Creating PDF File on Google App Engine

As part of an application I’m working on, I’d like to create documents in PDF format. I’ve mentioned this before, but it wasn’t until last weekend that I actually got started implementing my solution. The solution consists of generating HTML documents, exporting them to Google Docs and finally, exporting that newly created document to a PDF. Sounds complicated, but it turns out it was actually fairly easy.

download an example project

The example application consists of three parts:

  • There’s an RPC servlet that reacts to the user’s input. It will first use Apache Velocity to create a HTML file based on a template. There are a few things to take care of when running Velocity on App Engine, but nothing showstopping as with many of the other PDF and template libraries. I’ve used Jurgen van de Kamp’s explanation and classes. It worked flawlessly.
  • Together with the creation of the HTML, the RPC servlet will also create a new Google Document and send the HTML to the document. You’ll need to fill in a Google Docs user and password before this part works. Because of Google’s well documented API’s, this is a breeze:
public DocumentListEntry createNewDocument(String title, String content) throws ServiceException {
	try {
		URL feedUrl = new URL("https://docs.google.com/feeds/default/private/full/");
		DocumentListEntry newEntry = new DocumentEntry();
		newEntry.setTitle(new PlainTextConstruct(title));
		newEntry = client().insert(feedUrl, newEntry);
			
		newEntry.setMediaSource(new MediaByteArraySource(content.getBytes(), "text/html"));
		newEntry = newEntry.updateMedia(true);
		return newEntry;
	} catch (MalformedURLException e) {
		throw new RuntimeException(e);
	} catch (IOException e) {
		throw new RuntimeException(e);
	}
}
  • The final part is a normal (not GWT RPC) servlet that exports the PDF from Google Docs and returns it. I had to use a second servlet because the RPC format is limited. Again this code is very compact:
public InputStream getPdfInputStream(DocumentListEntry document) throws ServiceException {
	String exportUrl = ((MediaContent)document.getContent()).getUri() + "&exportFormat=pdf";
	MediaContent mc = new MediaContent();
	mc.setUri(exportUrl);
	try {
		MediaSource ms = client().getMedia(mc);
		return ms.getInputStream();
	} catch (IOException e) {
		throw new RuntimeException(e);
	}
}

A few things to note:

  • I’ve only shown a few highlights, you should really download the code to see how little there is to get such a fairly complicated result.
  • I haven’t really thought too hard about architecture and stuff like exception handling. So you might want to do some tuning if you actually use the code.
  • For this project, I haven’t use Maven, I just used the Eclipse plugins too quickly generate an application. In fact, it worked so quick I’m considering dumping Maven. Maven has some serious advantages, but the number of hoops I have to jump through keeps increasing exponentially. Especially since Google doesn’t offer their own Maven repositories.

download an example project