You are currently browsing the Philipp Meier's weblog blog archives for November, 2004


trademarkshome

Use Jelly XLF:FO and FOP to print and generate PDF

Recently I described how to use XStream, XSLT and XSL:FO to generate PDF. The mapping from the objects to an xml tree is more difficult than it appears first because the object form a possibly cylclic graph wheres XML is a directed cyclic graph. The leads to the problem of how to map two object which are referencing eatch other (possible via other objects). XStream provides a way to replace the 2nd occurence of the object with a reference using XML ids but this makes the XSLT stylesheet very verbose. This is why i dropped the XSLT step in generating a XSL:FO document.

Instead I use jelly to generate a SAX stream which is fed into FOP. I will give a short code example (please note the use of a temporary dom because I got strange FOP exception about default fonts which I will investigate sometimes):

/**
* Apply a jelly script to the target object an emit sax events for the
* generated fop object.
*
* @todo this class does not depend on fop, adjust naming
* @todo do without temporary dom
*
* @created 17.11.2004 01:29:48
*/
public class JellyFOPSAXEmitter implements FOPSAXEmitter {
public void emitSAX(Object object, URL stylesheetURL,
Map parameters,
ContentHandler contentHandler) {
JellyContext context = new JellyContext();

context.setVariables(parameters);
context.setVariable(“root”, object);

try {
context.runScript(stylesheetURL, XMLOutput.createXMLOutput(System.out));
DOMBuilder tmpdom = new DOMBuilder(
DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());
context.runScript(stylesheetURL, new XMLOutput(tmpdom));
final Transformer transformer =
TransformerFactory.newInstance().newTransformer();
transformer.setErrorListener(new DefaultErrorHandler(new PrintWriter(System.err)));
final Result result = new SAXResult(contentHandler);
transformer.transform(new DOMSource(tmpdom.getRootNode()), result);
} catch (Exception e) {
throw new RuntimeException(“Error running jelly script ” + stylesheetURL, e);
}
/*
try {
xmlOutput.flush();
} catch (IOException e) {
throw new RuntimeException(“Error running jelly script ” + stylesheetURL, e);
}
*/
}
}

/**
* @created 16.11.2004 23:07:34
*/
public class FOPPrintManager implements PrintManager {
private final Log log = LogFactory.getLog(getClass());
private Map classAliases;

public FOPPrintManager(Map classAliases) {
this.classAliases = classAliases;
}

public void printObject(final Object object, final URL stylesheetURL,
Object configuration, final Map parameters) {
FOPSAXEmitter emitter;
Class emitterClass = null;
try {
if (classAliases.get(configuration) != null) {
emitterClass = Class.forName((String) classAliases.get(configuration));
} else {
emitterClass = Class.forName((String) configuration);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(“Emitter not found class ” + configuration, e);
}
try {
emitter = (FOPSAXEmitter) emitterClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(“Invalid emitter class ”
+ emitterClass.getName(), e);
} catch (IllegalAccessException e) {
throw new RuntimeException(“Invalid emitter class ”
+ emitterClass.getName(), e);
}
Driver driver;
driver = new Driver();
driver.setErrorDump(true);
driver.setLogger(new CommonsLogger(log));
Translator translator = new SecureResourceBundle(
driver.getClass().getResourceAsStream(
“/org/apache/fop/viewer/resources/messages.en”));
AWTRenderer renderer = new AWTRenderer(translator);
driver.setRenderer(renderer);
ContentHandler contentHandler = driver.getContentHandler();
//Make sure the XSL transformation’s result is piped through to FOP

driver.setLogger(new CommonsLogger(log));
emitter.emitSAX(object, stylesheetURL, parameters, contentHandler);
final JFrame frame = new PreviewDialog(renderer, translator);
frame.pack();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
}

}

Usage is like the following:

Map classAliases = new HashMap();
classAliases.put(“jelly”, JellyFOPSAXEmitter.class);
manager = new FOPPrintManager(mapping);
order = orderService.findOrderById(12345);
Map parameters = new HashMap();
parameters.put(“printColor”, true);
manager.printObject(order, new URL(“file:printOrder.jelly”), “jelly”, parameters);

Please note that this code is pasted from a life system and supports different FOPSaxEmitters to switch generation of the document using jelly or xslt or whatever. The FOP is first shown using the AWTRenderer but could be directly written to a pdf file.

guidelines

OGNL TableModel instead of BeanPropertyTableModel

Code Poet writes about a BeanPropertyTableModel which is an adater to use a list of object as a javax.swing.table.TableModel by acessing the properties with commons-beanutils.

I suppose to go further an use OGNL for a more powerful expression language. I only outline the implementation here:

class OGNLTableModel() {
  private List items;
  private Object[] compliedExpression;

 public OGNLTableModel(List items, String[] columnExpressions) {
        ognlExprs = new Object[columnExprs.length];
        for (int i = 0; i < columnExprs.length; i++) {
            try {
            String columnExpr = columnExprs[i];
                ognlExprs[i] = Ognl.parseExpression(columnExpr);
            } catch (ExpressionSyntaxException e) {
                throw new IllegalArgumentException(
                   "Error for property »" + columnExprs[i] 
                     + "« : »" + e + "«");
            } catch (OgnlException e) {
                throw new IllegalArgumentException(
                   "Error for property »" + columnExprs[i] 
                     + "« : »" + e + "«");
            }
        }
    }
    public Object getValueAt(int rowIndex, int columnIndex) {
        try {
            return Ognl.getValue(ognlExprs[columnIndex],
                items.get(rowIndex);
        } catch (OgnlException e) {
            return "Error for property »"
             + columnExprs[columnIndex] + "« : »" + e + "«";
        }
    }
}

The actual implementation I use can handle column names, I left to out to make the idea clear. Use it like this:

// example
List list = orderService.findAllCustomers();
TableModel tm = new OGNLTableModel(list,
     new String[]{"id", "firstname", "lastname", "orders.size",
                             "orders[orders.size].date});

Moved to wordpress

I moved my blog to WordPress because I changed the server and I didn’t like MT any more ;-)

* easy installation
* Support for MarkDown
* Easy plugin installation
* Nice admin interface
* Nice template, the one used on this page is based on Kubrick
* No site regeneration

feed
search

Bear