Ok, so far I successfully implemented a PDF generation test web application (vaadin) after getting over many problems with Apache FOP 2.2. Record my progress here:
URL fo = getClass().getClassLoader().getResource("/static/topdf.fo");String path = fo.getFile().substring(0, fo.getFile().lastIndexOf('/'));......base = new URI(fo.getProtocol() + "://" + fo.getHost() + path+"/"); // -- this works// base = new URI(fo.getProtocol() + "://" + fo.getHost() + path); -- this does not work......fopFactory = FopFactory.newInstance(base, stream);baseUri = base.toASCIIString();
........
HashMap model = new HashMap();
model.put("baseurl", baseUri);
model.put("basefonturl", baseUri+"fonts/");
model.put("basefontdir", base.getPath()+"/fonts/");
.... <fo:external-graphic src="url(vfs:///home/bing/opt/wildfly-10.1.0.Final/standalone/deployments/V8Experiment-1.0-SNAPSHOT.war/WEB-INF/classes/static/img/miso.png)"></fo:external-graphic> <fo:external-graphic src="vfs:///home/bing/opt/wildfly-10.1.0.Final/standalone/deployments/V8Experiment-1.0-SNAPSHOT.war/WEB-INF/classes/static/img/miso.png"></fo:external-graphic> <fo:external-graphic src="url(img/miso.png)"></fo:external-graphic> <fo:external-graphic src="img/miso.png"></fo:external-graphic> PipedOutputStream out = new PipedOutputStream();InputStream in = new PipedInputStream(out);
new Thread(() -> {
try {
transformer.transform(src, result);
} catch (TransformerException e) {
e.printStackTrace();
}
;
// Clean-up, anyway
try {
out.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}).start();
return in;
Complete code: it's ugly but it's just a test
package com.bing.V8Experiment.views;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStream;import java.io.PipedInputStream;import java.io.PipedOutputStream;import java.net.URI;import java.net.URISyntaxException;import java.net.URL;import java.util.HashMap;import javax.xml.transform.Result;import javax.xml.transform.Source;import javax.xml.transform.Transformer;import javax.xml.transform.TransformerException;import javax.xml.transform.TransformerFactory;import javax.xml.transform.sax.SAXResult;import javax.xml.transform.stream.StreamSource;import com.github.jknack.handlebars.Handlebars;import com.github.jknack.handlebars.Template;import com.vaadin.server.FileDownloader;import com.vaadin.server.StreamResource;import com.vaadin.ui.Button;import com.vaadin.ui.Label;import com.vaadin.ui.Notification;import com.vaadin.ui.TextArea;import com.vaadin.ui.VerticalLayout;import org.apache.fop.apps.FopFactory;import org.apache.fop.apps.FopFactoryBuilder;import org.apache.avalon.framework.configuration.Configuration;import org.apache.avalon.framework.configuration.DefaultConfiguration;import org.apache.fop.apps.FOUserAgent;import org.apache.fop.apps.Fop;import org.apache.fop.apps.MimeConstants;import org.apache.fop.cli.CommandLineOptions;import org.apache.fop.fonts.DefaultFontConfig;import org.xml.sax.SAXException;public class PDFDownload extends VerticalLayout {public PDFDownload() throws SAXException, IOException {
// preparing the URL and base
URL fo = getClass().getClassLoader().getResource("/static/topdf.fo");
// My implementation of PDF generator
PDFStreamSource pdfsrc = new PDFStreamSource(fo);
StreamResource res = new StreamResource(pdfsrc, "Test.pdf");
// preparing the button
Button act = new Button("Generate some PDF");
FileDownloader fd = new FileDownloader(res);
fd.extend(act);
act.addClickListener(e -> {
PDFDownload.this.addComponent(new Label("We are generating the PDF for you, download should start in a while"));
});
TextArea foCfg = new TextArea("FO Configuration");
foCfg.setHeight("400px");
foCfg.setWidth("100%");
foCfg.setValue(pdfsrc.foCfgStr);
this.addComponents(
new Label("FO URL:" + fo.toExternalForm()),
new Label("Base URL: "+pdfsrc.baseUri),
foCfg,
act);
}
}class PDFStreamSource implements StreamResource.StreamSource {private URL fo;
private URI base;
FopFactoryBuilder builder;
FopFactory fopFactory;
String baseUri;
String foCfgStr;
public PDFStreamSource(URL fo) {
this.fo = fo;
String path = fo.getFile().substring(0, fo.getFile().lastIndexOf('/'));
try {
base = new URI(fo.getProtocol() + "://" + fo.getHost() + path+"/"); // -- this works
// base = new URI(fo.getProtocol() + "://" + fo.getHost() + path); -- this does not work
} catch (URISyntaxException e1) {
e1.printStackTrace();
return;
}
baseUri = base.toASCIIString(); // for showing the uri on interface
// Step 0: construct a configuration file with Handlebar
Handlebars hbr = new Handlebars();
Template foCfg;
HashMap model = new HashMap();
model.put("baseurl", baseUri);
model.put("basefonturl", baseUri+"fonts/");
model.put("basefontdir", base.getPath()+"fonts/");
// DefaultFontConfig df;
try {
foCfg = hbr.compile("static/fop");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
foCfgStr = "Failed to generate foCfgStr";
return;
}
try {
foCfgStr = foCfg.apply(model);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Step 1: Construct a FopFactory by specifying a reference to
// the configuration file
// (reuse if you plan to render multiple documents!)
InputStream stream = new ByteArrayInputStream(foCfgStr.getBytes());
try {
fopFactory = FopFactory.newInstance(base, stream);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
};
@Override
public InputStream getStream() {
try {
// Step 2: Set up output stream.
PipedOutputStream out = new PipedOutputStream();
InputStream in = new PipedInputStream(out);
// Step 3: Construct fop with desired output format
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out);
System.err.println("User agent URI:"+fop.getUserAgent().getResourceResolver().getBaseURI().toASCIIString());
System.err.println("Factory font manager resource resolver baseUri:"+fopFactory.getFontManager().getResourceResolver().getBaseURI().toASCIIString());
// Step 4: Setup JAXP using identity transformer
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(); // identity
// transformer
// Step 5: Setup input and output for XSLT transformation
// Setup input stream
Source src = new StreamSource(fo.openStream());
// Resulting SAX events (the generated FO) must be piped
// through to FOP
Result result = new SAXResult(fop.getDefaultHandler());
// Step 6: Start XSLT transformation and FOP processing
new Thread(() -> {
try {
transformer.transform(src, result);
} catch (TransformerException e) {
e.printStackTrace();
}
;
// Clean-up, anyway
try {
out.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}).start();
return in;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}Finally generated FOP configuration:
<?xml version="1.0"?><fop version="1.0"> <!-- Strict user configuration --> <strict-configuration>true</strict-configuration> <!-- Strict FO validation --> <strict-validation>false</strict-validation> <!-- Base URL for resolving relative URLs --> <base>vfs:///home/bing/opt/wildfly-10.1.0.Final/standalone/deployments/V8Experiment-1.0-SNAPSHOT.war/WEB-INF/classes/static/</base> <!-- Font Base URL for resolving relative font URLs --> <font-base>vfs:///home/bing/opt/wildfly-10.1.0.Final/standalone/deployments/V8Experiment-1.0-SNAPSHOT.war/WEB-INF/classes/static/fonts/</font-base> <!-- Source resolution in dpi (dots/pixels per inch) for determining the size of pixels in SVG and bitmap images, default: 72dpi --> <source-resolution>72</source-resolution> <!-- Target resolution in dpi (dots/pixels per inch) for specifying the target resolution for generated bitmaps, default: 72dpi --> <target-resolution>72</target-resolution> <!-- default page-height and page-width, in case value is specified as auto --> <default-page-settings height="11in" width="8.26in"/> <!-- Use file name nl_Bel instead of the default nl_BE --> <hyphenation-pattern lang="nl" country="BE">nl_Bel</hyphenation-pattern> <!-- or for xml file --> <hyphenation-pattern lang="fr" extension="xml">lang/fr.xml</hyphenation-pattern> <!-- or for binary file --> <hyphenation-pattern lang="fr" extension="hyp">lang/fr.hyp</hyphenation-pattern> <renderers> <renderer mime="application/pdf">
<fonts>
<!-- register all the fonts found in a directory -->
<directory>/home/bing/opt/wildfly-10.1.0.Final/standalone/deployments/V8Experiment-1.0-SNAPSHOT.war/WEB-INF/classes/static/fonts/</directory>
<!-- automatically detect operating system installed fonts -->
<!-- auto-detect/ -->
</fonts>
</renderer>
</renderers></fop>