Skip to content

Intermittent, random errors fulfilling PDFs using iText and Lucee

We had been getting intermittent, unreproduceable (or so I thought!) errors when fulfilling PDF documents on our website, which runs the Lucee server software on a Windows box.

Our fulfilment process (for each product purchased) involves watermarking a master PDF to create a customised version of that PDF. This is part of our “social DRM” strategy to avoid re-use of PDF documents purchased for a single purpose.

The errors that we were seeing were:

  • javax.xml.parsers.DocumentBuilderFactory cannot be created
  • PDF startxref not found

It boiled down, it seems, to our inability to close a file handle of one of the intermediate PDFs when watermarking. Upon further examination, I Googled and found this obscure Lucee forum thread which detailed a problem with a missing file in Lucee’s tmpdir (temporary folder).

The solution appeared to be to change Java’s tmpdir using the Lucee Service Control app to add an additional parameter: -Djava.io.tmpdir=<whatever>. However, I looked at our Service Control and saw that it was already defined.

Therefore, it appeared that it wasn’t actually Windows clearing out necessary files (as the thread indicated) but it might have been Java doing some housekeeping.

I looked a little further and found a file called com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl in Lucee’s temp folder (defined by tmpdir). With a little experimentation, it seems that if that file disappeared (was deleted), then the DocumentBuilderFactory error was thrown. If the file was then restored (undeleted), the error was no longer thrown.

I looked at the file and saw that the entire contents were just

com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl

with no line break at the end. It seemed to be a reference of some sort, but in any case it just appeared that the file needed to be there, with those exact contents.

I thought around the problem for a while and realised that all I needed to do was to make sure that the file existed (with the right contents) at the point I opened the original master PDF. So, all I needed to do was add a bit of code that checked to see if the file existed, and if it didn’t, I just needed to recreate it.

Here’s the code (which was wrapped in a function):

<cfset local.tmp_folder = server.system.properties["java.io.tmpdir"]>

<cfset local.filename = "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl">

<cfset local.contents = "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl">

<cfset local.filepath = "#local.tmp_folder#\#local.filename#">

<cfif NOT fileExists(local.filepath)>
  <cffile action="write" file="#local.filepath#" output="#local.contents#" addnewline="false">
</cfif>

Time will tell if the solution works for a long period. I’d be satisfied if I never saw the errors again, frankly, so here’s hoping! 🙂

Published incfml