Tuesday, April 28, 2009

Creating PDFs Using Notes Java Agent

A new project hit my desk a few weeks ago. The project involves the enhancement of an existing Notes workflow application, adding on processes to the start and finish of the workflow process. One of the requirements is to create a PDF for archival as the final step. In order to save some money and learn some new techniques, I chose to look into using the Apache FOP project.

I learned a few things while building a proof of concept and wanted to share what I learned. At a high level, this approach will require some knowledge of Java agents and a little knowledge of XSL-FO. So if you're not already up to speed on these two areas, you might want to spend a little time with the following:

  • Java agents and the Notes Java back-end classes. The notes help has a pretty good reference, and if you know the LotusScript back-end classes, you pretty much already know the Java classes. Also note that Java is pretty version specific and the Apache FOP project requires 1.4.x or later. That means this solution only works on Lotus Domino 7 or newer.
  • You'll probably want to learn how to use Eclipse in your Java agent development. Although not necessary, it provides a lot of help organizing and importing your packages, and assisting with your coding so your method signatures are correct, etc.
  • Depending on how intricate your PDF formatting will be, you'll want to familiarize yourself with XSL-FO. Also, download the Apache FOP zipped source files and look at the example FO files for ideas.
  • Download and set up OpenLog from OpenNTF.org to help in your debugging and error handling. As always, you can use the Java Debug Console or system.out to the console and log.nsf, but OpenLog gives you a few more options such as including a document link to the document being worked on at the time of the log event or error event. (You can even debug from Eclipse if you know what you're doing.)

My original approach was to import the Jar files into the agent or a script library, but I ran into a few problems with this approach: even if you get your base directory lined up correctly for your classes to access the META-INF path, the Jars are too big to include and will throw a out of memory error. Although not ideal, you will need to put all the Jar files in the jvm/lib/ext directory of your Domino directory (or Notes directory if you're testing locally).

The rest is pretty straightforward:

  • My agent (download the sample NSF here) will access a Notes document and construct the FO as a string. The string is constructed from various fields in the document and formatted to conform to the XSL-FO standards. When complete, the string is passed into a transformer class. (If the XSL-FO is quite large or elaborate, you will probably want to use a StringBuffer: use the append method to build the XSL-FO; use the toString method to pass the resulting XSL-FO into the transformer.)
  • Use the example in the Basic Usage Pattern to write the FOP components of your Java agent.
  • The results are saved to a file on disk, which you will eventually want to deal with. In my case I'll save directly to the file system of another server using a UNC path. In the example you will see a file path in which you can specify where the resulting PDF is to be saved. If you would like to add the PDF as an attachment to a document use the embedObject method of the RichTextItem class. Depending on what you end up doing with these PDFs, you might find yourself with a pile of files. Cleaning up these files can be done with another LotusScript agent or with the java.io.File class delete() method in the same Java agent.
  • Because the agent is writing to the file system you will need to give it a runtime security level of 2, allowing restricted operations.

Regarding setup, for testing you can run it locally on your workstation. Download the FOP binaries at the Apache site and extract the jar files to your notes/jvm/lib/ext directory. Sign the database and give that ID manager access and double-check that ID can run unrestricted agents. Right-click the ApacheFOP agent and select Run. If everything goes well and you haven’t changed anything, there should be a file in your C:\Temp directory called myfile.pdf. Once you know its working, go ahead and start customizing things to suit your needs.

Note: The code uses the UNID of the Simple.fo document that is inside the nsf, so you can open that document up in your Notes client and modify the XSL to make it custom for you.

There's alot of different things you can do within the FO, different approaches with Notes to build the FO, and different ways to process the resulting PDF (attaching, emailing, etc.). Hopefully this open source solution gives you some new options when it comes to incorporating PDFs into your Notes applications.

3 comments:

Anonymous said...

Hey Ded Reckoning,

I'm getting this error while complie the agent ApacheFOP:

Package org.apache.fop.apps does not exit.

import org.apache.fop.apps.fop ;

I unzip the Apache FOP under:
C:\Program Files\IBM\Lotus Notes\jvm\lib\ext\fop-0.94

I did not modified your code. Pl. let me know.

Thanks,
Rharan

Mike Miller said...

@Rharan

All you need are the JAR files in jvm\lib\ext. Looks like they might be one directory below in "fop-0.94".

M.M.

Mikkel Heisterberg said...

Glad you got it working... :-)