0

I'm using ApacheFOP 1.0 to produce a PDF document in a Tomcat hosted OSGI bundle, when I run my code outside the bundle as a standalone application (on the same server) it works. But the same code running on tomcat fails with the IllegalArgumentException, on the line: transformer.transform(src, res); No further stack trace or information is output, and I get corrupted PDF file.

I did a google search and found someone who got a similar error message when using FOP in an applet, but that was fixed by including xalan.jar. I definitely have xalan.jar in the WAR file's classpath, and I also tried running the standalone application without xalan.jar, and it still worked, so my code doesn't actually use it.

I did a 'find / -name ' for the jar files used by FOP, to see if there are any others in tomcat that could be conflicting, but didn't find any.

What is interesting is that if I remove the image element from my source xsl file, then it all works. I define the image in the xsl with:

<fo:external-graphic src="/images/im.png"/>

If I comment out this line it works in tomcat. Problem is I need images in my PDF.

Code is below (I also needed to create a PDFRenderer useragent to workaround another problem, where I got the error: "Caused by: java.lang.UnsupportedOperationException: Don't know how to handle "application/pdf" as an output format. Neither an FOEventHandler, nor a Renderer could be found for this output format.."). Any advice greatly appreciated!

    FopFactory fopFactory = FopFactory.newInstance();


    FOUserAgent useragent = fopFactory.newFOUserAgent();
    PDFRenderer pdfrenderer = new PDFRenderer();
    pdfrenderer.setUserAgent(useragent);
    useragent.setRendererOverride(pdfrenderer);

    fopFactory.addElementMapping(new FOElementMapping());
    fopFactory.addElementMapping(new SVGElementMapping());
    fopFactory.addElementMapping(new BatikExtensionElementMapping());
    fopFactory.addElementMapping(new ExtensionElementMapping());
    fopFactory.addElementMapping(new XMPElementMapping());
    fopFactory.addElementMapping(new RDFElementMapping());
    fopFactory.addElementMapping(new PSExtensionElementMapping());

    fopFactory.addElementMapping(new AFPElementMapping());
    fopFactory.addElementMapping(new PSExtensionElementMapping());
    fopFactory.addElementMapping(new InternalElementMapping());
    fopFactory.addElementMapping(new OldExtensionElementMapping());
    fopFactory.addElementMapping(new PCLElementMapping());      

    try {
        // Step 3: Construct fop with desired output format
        Fop fop = null;
        try {
            fop = fopFactory.newFop(MimeConstants.MIME_PDF, useragent, outfile);
            //fop = fopFactory.newFop(MimeConstants.MIME_PDF,  outfile);
        } catch (FOPException e) {
            logger.log(Level.SEVERE, "Failed to create FOP object: " + e.getLocalizedMessage());
            e.printStackTrace();
            return null;
        }


        Source src = new StreamSource(new File(interimFile));
        // Resulting SAX events (the generated FO) must be piped through to FOP
        Result res = null;
        try {
            res = new SAXResult(fop.getDefaultHandler());
        } catch (FOPException e) {
            logger.log(Level.SEVERE, "Failed to setup pdf result file: " + e.getLocalizedMessage());
            e.printStackTrace();
            return null;
        }


        // Step 6: Start XSLT transformation and FOP processing
        try {
            transformer.transform(src, res);
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Failed to transform xsl to PDF " + e.getLocalizedMessage());
            e.printStackTrace();
            return null;
        }
IainS
  • 139
  • 1
  • 4
  • 9

2 Answers2

1

You will at least need the following jars in your bundle classpath (I use FOP 1.0):

  • commons-io
  • xml-apis-ext
  • fop
  • xmlgraphics-common
  • avalon-framework
  • batik-all

The lower 3 are specifically needed for image handling.

The jars are in the FOP distibution below lib.

0

How is FOP rendering the png file image? Perhaps it needs classes not visible to your bundle. Run with -verbose:class as a standalone application and note the classes it loads. You can then see if any are not visible to your bundle. For example, it may need some javax.* classes from the JRE which your bundle would need to import.

BJ Hargrave
  • 9,324
  • 1
  • 19
  • 27
  • Thanks, I did run the check, starting Tomcat with the same argument. Both loaded xml.jar and rt.jar, nothing else javax. Tomcat also loaded all the classes needed for FOP, but I did see an overlap with two versions of commons-logging (one for FOP, one for some other code) in the loading. Looking at the exception, I've found where it's raised in the FOP code: fop-1.0-src\fop-1.0\src\java\org\apache\fop\util\text\AdvancedMessageFormat.java: if (this.function == null) { throw new IllegalArgumentException("Unknown function: " + functionName); } – IainS Nov 24 '14 at 16:07
  • I was not asking about the jars used but rather the types used. Jars are just containers for types. If the FOP codes uses a type which is not properly imported, then the type can be visible when run as a standalone application from the classpath (since the classpath does not provide any modularity encapsulation) but not visible when run in a modular fashion like OSGi. – BJ Hargrave Nov 24 '14 at 17:38