PDF Generation within WebObjects
PDF Generation within WebObjects
- Subject: PDF Generation within WebObjects
- From: Zac Konopa <email@hidden>
- Date: Thu, 23 Mar 2006 12:11:02 -0800
Hey everyone,
I wrote to the list a few days ago about generating pdf files for
download from a WebObjects application. Well I've figured out a
solution and I thought I would post it along with some notes about
the process to help those who follow and perhaps get some feedback on
how to improve the process. Okay so here goes...
First you need to get a java library that will generate PDF's from
xsl-fo (this is an xml file in the "fo" format, fo stands for
Formatt Object or some such, it's simply xml description of a
document that will be parsed into PDF). I choose the Apache FOP
0.20.5 library. There is also the Apache .90 library, and iText, but
I don't know anything about either of those librarys. Just follow
the instructions in from Apache on how to install these libraries.
Ultimately you need to make sure that all the .jar files are in you
classpath.
Once you've got everything installed you can look at the application
itself. Now the approach I took was that when the user requested a
certain thing (ie a pdf report) instead of vending html from a
WOComponent we wanted to vend a PDF. To this end the WOComponent
will contain xml that will describe the document then we will
override the appendToResponse method of WOComponent to parse the
content of the response from xml into PDF using the librarys from
Apache's FOP, then substitute the PDF content for the xml, then
change the response header to PDF. The approach I took was to factor
out all this functionality into a separate class that extends
WOComponent, then make all my components that hold the actual xml
subclasses of this class. I called the superclass FO2PDFSerializer,
and here is it's content...
//
// FO2PDFSerializer.java: Class file
//
// Created by zac on 3/20/06
//
import com.webobjects.foundation.*;
import com.webobjects.appserver.*;
import com.webobjects.eocontrol.*;
import com.webobjects.eoaccess.*;
import org.apache.fop.apps.*;
import org.xml.sax.*;
import com.webobjects.appserver.*;
import java.io.*;
public class FO2PDFSerializer extends WOComponent {
private String _contentType = "text/fo-xml";//all subclasses
need to contain this type of content
public FO2PDFSerializer(WOContext context) {
super(context);
}
public void setContentType(String aType) {
_contentType = aType;
}
//this function will be used by the initializing component to
determine wether we want to see the actual xml or get the pdf
public String contentType() {
return _contentType;
}
//this function is the meat of the class
public void appendToResponse(WOResponse response, WOContext
context) {
super.appendToResponse(response, context);
// vend as PDF to response
if (contentType().equals("application/pdf")) {
response.setHeader("text/xml", "Content-Type");//set the
Content Type to xml
InputSource foInput = new InputSource(new
ByteArrayInputStream(response.contentString().getBytes()));//get the
content of the Component as bytes and convert to a ByteArray
ByteArrayOutputStream out = new ByteArrayOutputStream
();//initialize an output stream for the FOP driver
Driver driver = new Driver(foInput, out);//initialize a
Driver (member of the ApacheFOP) with input and output from above
driver.setLogger(null);//this can be used when tracking
down errors, but you'll have to figure out how to use it for yourself
driver.setRenderer(Driver.RENDER_PDF);//set the type of
document that you want from the Driver
//now run the driver
try {
driver.run();
} catch (Exception e) {
NSLog.out.appendln(e.getMessage());
}
//Convert the output to a class that can be used by WOResponse
NSData outData = new NSData(out.toByteArray());
//if you've actually got data, substitute it for the response
data and change the response Content Type
if(outData != null) {
response.setContent(outData);
response.setHeader("application/pdf", "Content-Type");
response.setHeader("attachement;filename=\"" +
"Test.pdf" + "\"", "Content-Disposition");//you can use this line to
set the filename if you want but it's not required
}
}
}
}
Okay that's the superclass. All your subclasses have to hold is the
actual xml data in the .wo source. This can be confusing because the
WebObjects builder won't inerperet the xml, it will only show you the
static text so most of the manipulation you do will have to be in the
source files. It is doable though.
And with that you're good! Any document that you want to vend as PDF
simply have the class extend this one, and when you call that
component from elsewhere in your app remember to set the content type
as "application/pdf".
It's good to keep in mind that the Apache FOP library can parse xml
into several different files and with minimal modification this class
could be modified to vend any of them.
Well good luck all. I'm outa here.
Zac
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden