I've been using FOP to generate PDFs from the Tapestry application for
quite a few years. There's nothing specific to Tapestry, you just create a
"rendering service" which does all the processing for you. The only caveat
I remember is using Saxon instead of Xalan for running initial
transformation (it's *much* faster and has a lower memory footprint).

This is the entire code responsible for producing PDF:

// 1) create transformer
if (fopFactory == null) {
    fopFactory = FopFactory.newInstance();
    final URL fopConfigResource =
getClass().getClassLoader().getResource(FOP_CONFIG_URL);
    final URL fontsDirectoryResource =
getClass().getClassLoader().getResource("your/font/package");
    assert fopConfigResource != null && fontsDirectoryResource != null;
    fopFactory.setUserConfig(fopConfigResource.toExternalForm());
    
fopFactory.getFontManager().setFontBaseURL(fontsDirectoryResource.toExternalForm());
}

// use Saxon instead of Xalan
System.setProperty("javax.xml.transform.TransformerFactory",
"net.sf.saxon.TransformerFactoryImpl");
TransformerFactory transformerFactory = TransformerFactory.newInstance();

// register Saxon extension functions
TransformerFactoryImpl saxonFactory = (TransformerFactoryImpl)
transformerFactory;
Configuration configuration = saxonFactory.getConfiguration();
extensionFunctions.getAvailableFunctions(activeLocale).forEach(configuration::registerExtensionFunction);

// initialize transformer
Source template = new StreamSource(templateStream);
Transformer transformer = transformerFactory.newTransformer(template);

// 2) serialize object to xml
File tmpFile = File.createTempFile("fop", ".xml");
FileOutputStream marshallerOutputStream = new FileOutputStream(tmpFile);
JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass());
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(object, marshallerOutputStream);
marshallerOutputStream.close();
logger.info("marshaller result: {}, {} bytes", tmpFile, tmpFile.length());

// 3) perform transformation
FileInputStream fopInputStream = new FileInputStream(tmpFile);
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
foUserAgent.setProducer("producer name");
foUserAgent.setCreationDate(new Date());
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, outputStream);
Source xmlSource = new StreamSource(fopInputStream);
Result pdfResult = new SAXResult(fop.getDefaultHandler());
transformer.transform(xmlSource, pdfResult);
fopInputStream.close();
if (!tmpFile.delete())
    logger.warn("unable to remove temporary file {}", tmpFile);


There's basically nothing else. After processing, *outputStream* will
contain your PDF. Note that my example includes:

   - using custom fonts (you probably don't need this);
   - using custom extension functions for Saxon (you probably don't need
   this either).

Otherwise it's pretty much straightforward.


On Thu, Jan 27, 2022 at 9:19 AM Volker Lamp <volker.l...@gmail.com> wrote:

> Hello Tapestry users,
>
> Our Tapestry webapp needs to generate printable PDFs including user input.
> We are currently looking at using Apache FOP for that.
>
> Has anyone integrated FOP in their Tapestry webapp and perhaps a Tapestry
> module to share?
>
> Suggestions for other approaches are also welcome.
>
> Cheers,
>
> Volker
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
> For additional commands, e-mail: users-h...@tapestry.apache.org
>
>

-- 
Ilya Obshadko

Reply via email to