With same XML and XSL-FO FOP1.0 works fine. But after upgrade to FOP2.4 ,
I can see below warning and exception when converting the xml to print doc for printing on the TCP/IP printer.
WARNING: The contents of fo:region-after on page 1 exceed the available area in the block-progression direction by 13483 millipoints. (No context info available) Exception:
java.lang.NullPointerException
at org.apache.fop.render.AbstractRenderer.renderMainReference(AbstractRenderer.java:527)
at org.apache.fop.render.AbstractRenderer.renderBodyRegion(AbstractRenderer.java:433)
at org.apache.fop.render.AbstractRenderer.renderRegionViewport(AbstractRenderer.java:380)
at org.apache.fop.render.AbstractRenderer.renderPageAreas(AbstractRenderer.java:345)
at org.apache.fop.render.java2d.Java2DRenderer.print(Java2DRenderer.java:1008)
at sun.print.RasterPrinterJob.printPage(RasterPrinterJob.java:2166)
at sun.print.RasterPrinterJob.print(RasterPrinterJob.java:1548)
at sun.print.Win32PrintJob.pageableJob(Win32PrintJob.java:576)
at sun.print.Win32PrintJob.print(Win32PrintJob.java:393)
at PrinterHandler.print(PrinterHandler.java:65)
at Test.main(Test.java:734)
This issue is not seen when used FOP 1.0. After upgrade to FOP2.0, I started observing this exception hence document doesn't get print. Refer the below code which i have used.
Additionally , I downloaded the FOP2.4 source and see the below snippets. So can any one suggest what shall i need to change in our code or in XSL-FO schema to make this work. Below API is from FOP2.4. I did compare with FOP1.0 and see lots of changes related pageindex.
from AbstractRenderer.java :
'''
protected void renderMainReference(MainReference mainReference) {
//Few sample code snippets from FOP where exception seen
if (flow != null) {
// if direction is right to left, then end is left edge,
// else end is right edge (for top-bottom/bottom-top block
// progression directions)
// binding edge is on left edge for odd pages and
// on right edge for even pages
** int pageIndex = currentPageViewport.getPageIndex(); **
//Crashes as currentPageViewport is null
//More codes are below
}
This below example is taken from apache fop-2.4-bin\fop-2.4\fop\examples\embedding\java\embedding\ . This program is combination of ExampleXML2FO.java and ExampleFO2JPSPrint.java . I am trying to print the doc to printer, but above nullpointerexception raised.Below is the complete code to reproduce this issue.
projectteam.xml
<?xml version="1.0" encoding="UTF-8"?>
<projectteam>
<projectname>The Killer Application</projectname>
<member>
<name>John Doe</name>
<function>lead</function>
<email>jon.doe@killerapp.fun</email>
</member>
</projectteam>
projectteam2fo.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format" exclude-result-prefixes="fo">
<xsl:output method="xml" version="1.0" omit-xml-declaration="no" indent="yes"/>
<xsl:param name="versionParam" select="'1.0'"/>
<!-- ========================= -->
<!-- root element: projectteam -->
<!-- ========================= -->
<xsl:template match="projectteam">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simpleA4" page-height="29.7cm" page-width="21cm" margin-top="2cm" margin-bottom="2cm" margin-left="2cm" margin-right="2cm">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simpleA4">
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="16pt" font-weight="bold" space-after="5mm">Project: <xsl:value-of select="projectname"/>
</fo:block>
<fo:block font-size="12pt" space-after="5mm">Version <xsl:value-of select="$versionParam"/>
</fo:block>
<fo:block font-size="10pt">
<fo:table table-layout="fixed" width="100%" border-collapse="separate">
<fo:table-column column-width="4cm"/>
<fo:table-column column-width="4cm"/>
<fo:table-column column-width="5cm"/>
<fo:table-body>
<xsl:apply-templates select="member"/>
</fo:table-body>
</fo:table>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<!-- ========================= -->
<!-- child element: member -->
<!-- ========================= -->
<xsl:template match="member">
<fo:table-row>
<xsl:if test="function = 'lead'">
<xsl:attribute name="font-weight">bold</xsl:attribute>
</xsl:if>
<fo:table-cell>
<fo:block>
<xsl:value-of select="name"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:template>
</xsl:stylesheet>
Test.java
//Java
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
//JAXP
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.TransformerException;
import javax.xml.transform.Source;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.render.print.PageableRenderer;
/**
* This class demonstrates the conversion of an XML file to an XSL-FO file
* using JAXP (XSLT).
*/
public class Test {
/**
* Converts an XML file to an XSL-FO file using JAXP (XSLT).
* @param xml the XML file
* @param xslt the stylesheet file
* @param fo the target XSL-FO file
* @throws IOException In case of an I/O problem
* @throws TransformerException In case of a XSL transformation problem
*/
public void convertXML2FO(File xml, File xslt, File fo)
throws IOException, TransformerException {
//Setup output
OutputStream out = new java.io.FileOutputStream(fo);
try {
//Setup XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(xslt));
//Setup input for XSLT transformation
Source src = new StreamSource(xml);
//Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new StreamResult(out);
//Start XSLT transformation and FOP processing
transformer.transform(src, res);
} finally {
out.close();
}
}
public static void printFO(File fo)
throws IOException, FOPException, TransformerException, PrintException {
// configure fopFactory as desired
final FopFactory FOP_FACTORY = FopFactory.newInstance(new File(".").toURI());
//Set up a custom user agent so we can supply our own renderer instance
FOUserAgent userAgent = FOP_FACTORY.newFOUserAgent();
PageableRenderer renderer = new PageableRenderer(userAgent);
userAgent.setRendererOverride(renderer);
// Construct FOP with desired output format
Fop fop = FOP_FACTORY.newFop(userAgent);
// Setup JAXP using identity transformer
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(); // identity transformer
// Setup input stream
Source src = new StreamSource(fo);
// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Start XSLT transformation and FOP processing
transformer.transform(src, res);
Doc doc = new SimpleDoc(renderer, DocFlavor.SERVICE_FORMATTED.PAGEABLE, null);
final PrintService printer = PrintServiceLookup.lookupDefaultPrintService();
final DocPrintJob printJob = printer.createPrintJob();
printJob.addPrintJobListener(null);
new PrinterHandler().print(doc);
}
/**
* Main method.
* @param args command-line arguments
*/
public static void main(String[] args) {
try {
System.out.println("FOP ExampleXML2FO\n");
System.out.println("Preparing...");
//Setup directories
File baseDir = new File(".");
File outDir = new File(baseDir, "out");
outDir.mkdirs();
//Setup input and output files
File xmlfile = new File(baseDir, "xml/xml/projectteam.xml");
File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl");
File fofile = new File(outDir, "ResultXML2FO.fo");
System.out.println("Input: XML (" + xmlfile + ")");
System.out.println("Stylesheet: " + xsltfile);
System.out.println("Output: XSL-FO (" + fofile + ")");
System.out.println();
System.out.println("Transforming...");
Test app = new Test();
app.convertXML2FO(xmlfile, xsltfile, fofile);
printFO(fofile);
System.out.println(fofile);
System.out.println("Success!");
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(-1);
}
}
}
PrintHandler.java
/**
* PrinterHandler.java
*/
import javax.print.Doc;
import javax.print.DocPrintJob;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.event.PrintJobEvent;
import javax.print.event.PrintJobListener;
import java.util.logging.Logger;
/**
* Class PrinterHandler sends a print job to the default printer and observes the printer register
* itself to the printer to inspect the state of the printer.
*
*/
public final class PrinterHandler implements PrintJobListener {
/** Logger. */
private final Logger mLogger = Logger.getLogger(PrinterHandler.class.getName());
/**
* Constructor.
*/
public PrinterHandler() {
}
/**
* Print the data contained in the Doc object.
* <p>
* The default printer configured in the operating system is used. If no default printer is
* found, the first printer in the list of configured printers is used.
*
* @param doc is a Doc object which contains the printable data.
* @return true if successfully printed.
*/
public boolean print( Doc doc) {
boolean success = true;
PrintService printer = PrintServiceLookup.lookupDefaultPrintService();
if (printer == null) {
final PrintService[] allPrinters =
PrintServiceLookup.lookupPrintServices(doc.getDocFlavor(), null);
if (allPrinters.length > 0) {
printer = allPrinters[0];
mLogger.info(printer.getName());
}
}
if (printer == null) {
mLogger.info( "no Printer");
} else {
final DocPrintJob printJob = printer.createPrintJob();
try {
mLogger.info("Printing document on " + printer.getName() + ".");
printJob.addPrintJobListener(this);
printJob.print(doc, null);
} catch (final Exception e) {
success = false;
System.out.println(e.getMessage());
mLogger.info("Detailed Print Problem");
e.printStackTrace();
System.out.println(e);
} finally {
printJob.removePrintJobListener(this);
}
}
return success;
}
/**
* Called to notify the client that data has been successfully transferred to the print
* service, and the client may free local resources allocated for that data.
*
* @param pje the job generating this event.
* @see javax.print.event.PrintJobListener
*/
@Override
public void printDataTransferCompleted(final PrintJobEvent pje) {
mLogger.info("Print Data Transfer Completed: " + pje.getPrintJob());
}
/**
* Called to notify the client that the job was canceled by a user or a program.
*
* @param pje the job generating this event.
* @see javax.print.event.PrintJobListener
*/
@Override
public void printJobCanceled(final PrintJobEvent pje) {
mLogger.info("Print Job Canceled : " + pje.getPrintJob());
}
/**
* Called to notify the client that the job completed successfully.
*
* @param pje the job generating this event.
* @see javax.print.event.PrintJobListener
*/
@Override
public void printJobCompleted(final PrintJobEvent pje) {
mLogger.info( "Print Job Completed : " + pje.getPrintJob());
}
/**
* Called to notify the client that the job failed to complete successfully and
* will have to be resubmitted.
*
* @param pje the job generating this event.
* @see javax.print.event.PrintJobListener
*/
@Override
public void printJobFailed(final PrintJobEvent pje) {
mLogger.info( "Print Job Failed : " + pje.getPrintJob());
}
/**
* Called to notify the client that no more events will be delivered.
*
* @param pje the job generating this event.
* @see javax.print.event.PrintJobListener
*/
@Override
public void printJobNoMoreEvents(final PrintJobEvent pje) {
mLogger.info( "Print Job No More Events: " + pje.getPrintJob());
}
/**
* Called to notify the client that an error has occurred that the user might be able to fix.
*
* @param pje the job generating this event.
* @see javax.print.event.PrintJobListener
*/
@Override
public void printJobRequiresAttention(final PrintJobEvent pje) {
mLogger.info("Print Job Requires Attention : " + pje.getPrintJob());
}
}
My suspect is that , there might be some schema changes require in XSL-FO. But I am not able to figure out the actual reason of this issue.
Looking for you expert opinion on this to resolve this issue.Thank you!