/* $Id$ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. * For details on use and redistribution please refer to the * LICENSE file included with these sources. */ package org.apache.fop.apps; // FOP import org.apache.fop.fo.FOTreeBuilder; import org.apache.fop.fo.ElementMapping; import org.apache.fop.fo.PropertyListMapping; import org.apache.fop.layout.AreaTree; import org.apache.fop.layout.FontInfo; import org.apache.fop.render.Renderer; import org.apache.fop.messaging.MessageHandler; import org.apache.fop.configuration.ConfigurationReader; import org.apache.fop.configuration.Configuration; import org.apache.fop.tools.DocumentInputSource; import org.apache.fop.tools.DocumentReader; import org.apache.fop.system.BufferManager; // DOM import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Attr; // SAX import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; // Java import java.io.*; /** * Primary class that drives overall FOP process. *

* The simplest way to use this is to instantiate it with the * InputSource and OutputStream, then set the renderer desired, and * calling run(); *

* Here is an example use of Driver which outputs PDF: * *

 *   Driver driver = new Driver(new InputSource (args[0]),
 *                              new FileOutputStream(args[1]));
 *   driver.setRenderer(RENDER_PDF);
 *   driver.run();
 * 
* If neccessary, calling classes can call into the lower level * methods to setup and * render. Methods can be called to set the * Renderer to use, the (possibly multiple) ElementMapping(s) to * use and the OutputStream to use to output the results of the * rendering (where applicable). In the case of the Renderer and * ElementMapping(s), the Driver may be supplied either with the * object itself, or the name of the class, in which case Driver will * instantiate the class itself. The advantage of the latter is it * enables runtime determination of Renderer and ElementMapping(s). *

* Once the Driver is set up, the buildFOTree method * is called. Depending on whether DOM or SAX is being used, the * invocation of the method is either buildFOTree(Document) or * buildFOTree(Parser, InputSource) respectively. *

* A third possibility may be used to build the FO Tree, namely * calling getContentHandler() and firing the SAX events yourself. *

* Once the FO Tree is built, the format() and render() methods may be * called in that order. *

* Here is an example use of Driver which outputs to AWT: * *

 *   Driver driver = new Driver();
 *   driver.setRenderer(new org.apache.fop.render.awt.AWTRenderer(translator));
 *   driver.buildFOTree(parser, fileInputSource(args[0]));
 *   driver.format();
 *   driver.render();
 * 
*/ public class Driver { /** Render to PDF. OutputStream must be set */ public static final int RENDER_PDF = 1; /** Render to a GUI window. No OutputStream neccessary */ public static final int RENDER_AWT = 2; /** Render to MIF. OutputStream must be set */ public static final int RENDER_MIF = 3; /** Render to XML. OutputStream must be set */ public static final int RENDER_XML = 4; /** Render to PRINT. No OutputStream neccessary */ public static final int RENDER_PRINT = 5; /** Render to PCL. OutputStream must be set */ public static final int RENDER_PCL = 6; /** Render to Postscript. OutputStream must be set */ public static final int RENDER_PS = 7; /** Render to Text. OutputStream must be set */ public static final int RENDER_TXT = 8; /** the FO tree builder */ private FOTreeBuilder _treeBuilder; /** the area tree that is the result of formatting the FO tree */ private AreaTree _areaTree; /** the renderer to use to output the area tree */ private Renderer _renderer; /** the source of the FO file */ private InputSource _source; /** the stream to use to output the results of the renderer */ private OutputStream _stream; /** The XML parser to use when building the FO tree */ private XMLReader _reader; /** If true, full error stacks are reported */ private boolean _errorDump = false; /** the system resources that FOP will use */ private BufferManager _bufferManager; /** create a new Driver */ public Driver() { _stream = null; _bufferManager = new BufferManager(); _treeBuilder = new FOTreeBuilder(); _treeBuilder.setBufferManager(_bufferManager); setupDefaultMappings(); } public Driver(InputSource source, OutputStream stream) { this(); _source = source; _stream = stream; } /** * Resets the Driver so it can be reused. Property and element * mappings are reset to defaults. * The output stream is cleared. The renderer is cleared. */ public synchronized void reset() { _areaTree = null; _treeBuilder.reset(); } public boolean hasData() { return(_treeBuilder.hasData()); } /** * Set the error dump option * @param dump if true, full stacks will be reported to the error log */ public void setErrorDump(boolean dump) { _errorDump = dump; } /** * Set the OutputStream to use to output the result of the Renderer * (if applicable) * @param stream the stream to output the result of rendering to * */ public void setOutputStream(OutputStream stream) { _stream = stream; } /** * Set the source for the FO document. This can be a normal SAX * InputSource, or an DocumentInputSource containing a DOM document. * @see DocumentInputSource */ public void setInputSource(InputSource source) { _source = source; } /** * Sets the reader used when reading in the source. If not set, * this defaults to a basic SAX parser. */ public void setXMLReader(XMLReader reader) { _reader = reader; } /** * Sets all the element and property list mappings to their default values. * */ public void setupDefaultMappings() { addElementMapping("org.apache.fop.fo.StandardElementMapping"); addPropertyList ("org.apache.fop.fo.StandardPropertyListMapping"); addElementMapping("org.apache.fop.svg.SVGElementMapping"); addPropertyList ("org.apache.fop.svg.SVGPropertyListMapping"); addElementMapping("org.apache.fop.extensions.ExtensionElementMapping"); addPropertyList ("org.apache.fop.extensions.ExtensionPropertyListMapping"); } /** * Set the rendering type to use. Must be one of * * @param renderer the type of renderer to use */ public void setRenderer(int renderer) throws IllegalArgumentException { switch (renderer) { case RENDER_PDF: setRenderer(new org.apache.fop.render.pdf.PDFRenderer()); break; case RENDER_AWT: throw new IllegalArgumentException("Use renderer form of setRenderer() for AWT"); case RENDER_PRINT: throw new IllegalArgumentException("Use renderer form of setRenderer() for PRINT"); case RENDER_PCL: setRenderer(new org.apache.fop.render.pcl.PCLRenderer()); break; case RENDER_PS: setRenderer(new org.apache.fop.render.ps.PSRenderer()); break; case RENDER_TXT: setRenderer(new org.apache.fop.render.txt.TXTRenderer()); break; case RENDER_MIF: setRenderer(new org.apache.fop.render.mif.MIFRenderer()); break; case RENDER_XML: setRenderer(new org.apache.fop.render.xml.XMLRenderer()); break; default: throw new IllegalArgumentException("Unknown renderer type"); } } /** * Set the Renderer to use * @param renderer the renderer instance to use */ public void setRenderer(Renderer renderer) { _renderer = renderer; } public Renderer getRenderer() { return _renderer; } /** * @deprecated use renderer.setProducer(version) + setRenderer(renderer) or just setRenderer(renderer_type) which will use the default producer string. * @see #setRenderer(int) * @see #setRenderer(Renderer) */ public void setRenderer(String rendererClassName, String version) { setRenderer(rendererClassName); } /** * Set the class name of the Renderer to use as well as the * producer string for those renderers that can make use of it. * @param rendererClassName classname of the renderer to use such as * "org.apache.fop.render.pdf.PDFRenderer" * @exception IllegalArgumentException if the classname was invalid. * @see #setRenderer(int) */ public void setRenderer(String rendererClassName) throws IllegalArgumentException { try { _renderer = (Renderer) Class.forName( rendererClassName).newInstance(); _renderer.setProducer(Version.getVersion()); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Could not find " + rendererClassName); } catch (InstantiationException e) { throw new IllegalArgumentException( "Could not instantiate " + rendererClassName); } catch (IllegalAccessException e) { throw new IllegalArgumentException("Could not access " + rendererClassName); } catch (ClassCastException e) { throw new IllegalArgumentException(rendererClassName + " is not a renderer"); } } /** * Add the given element mapping. * An element mapping maps element names to Java classes. * * @param mapping the element mappingto add */ public void addElementMapping(ElementMapping mapping) { mapping.addToBuilder(_treeBuilder); } /** * add the element mapping with the given class name */ public void addElementMapping(String mappingClassName) throws IllegalArgumentException { try { ElementMapping mapping = (ElementMapping) Class.forName( mappingClassName).newInstance(); addElementMapping(mapping); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Could not find " + mappingClassName); } catch (InstantiationException e) { throw new IllegalArgumentException( "Could not instantiate " + mappingClassName); } catch (IllegalAccessException e) { throw new IllegalArgumentException("Could not access " + mappingClassName); } catch (ClassCastException e) { throw new IllegalArgumentException(mappingClassName + " is not an ElementMapping"); } } /** * Add the PropertyListMapping. */ public void addPropertyList(PropertyListMapping mapping) { mapping.addToBuilder(_treeBuilder); } /** * Add the PropertyListMapping with the given class name. */ public void addPropertyList(String listClassName) throws IllegalArgumentException { try { PropertyListMapping mapping = (PropertyListMapping) Class.forName( listClassName).newInstance(); addPropertyList(mapping); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Could not find " + listClassName); } catch (InstantiationException e) { throw new IllegalArgumentException( "Could not instantiate " + listClassName); } catch (IllegalAccessException e) { throw new IllegalArgumentException("Could not access " + listClassName); } catch (ClassCastException e) { throw new IllegalArgumentException(listClassName + " is not an ElementMapping"); } } /** * Returns the tree builder (a SAX ContentHandler). * * Used in situations where SAX is used but not via a FOP-invoked * SAX parser. A good example is an XSLT engine that fires SAX * events but isn't a SAX Parser itself. */ public ContentHandler getContentHandler() { return _treeBuilder; } /** * Build the formatting object tree using the given SAX Parser and * SAX InputSource */ public synchronized void buildFOTree(XMLReader parser, InputSource source) throws FOPException { parser.setContentHandler(_treeBuilder); try { parser.parse(source); } catch (SAXException e) { if (e.getException() instanceof FOPException) { throw (FOPException) e.getException(); } else { throw new FOPException(e); } } catch (IOException e) { throw new FOPException(e); } } /** * Build the formatting object tree using the given DOM Document */ public synchronized void buildFOTree(Document document) throws FOPException { try { DocumentInputSource source = new DocumentInputSource(document); DocumentReader reader = new DocumentReader(); reader.setContentHandler(_treeBuilder); reader.parse(source); } catch (SAXException e) { throw new FOPException(e); } catch (IOException e) { throw new FOPException(e); } } /** * Dumps an error */ public void dumpError(Exception e) { if (_errorDump) { if (e instanceof SAXException) { e.printStackTrace(); if (((SAXException) e).getException() != null) { ((SAXException) e).getException().printStackTrace(); } } else if (e instanceof FOPException) { e.printStackTrace(); if (((FOPException) e).getException() != null) { ((FOPException) e).getException().printStackTrace(); } } else { e.printStackTrace(); } } } /* Set up the system buffers */ public void setBufferFile(File bufferFile) { this._bufferManager.addBufferFile(bufferFile); } /** * format the formatting object tree into an area tree */ public synchronized void format() throws FOPException { FontInfo fontInfo = new FontInfo(); _renderer.setupFontInfo(fontInfo); _areaTree = new AreaTree(); _areaTree.setFontInfo(fontInfo); _treeBuilder.format(_areaTree); } /** * render the area tree to the output form */ public synchronized void render() throws IOException, FOPException { _renderer.render(_areaTree, _stream); } /** * Runs the formatting and renderering process using the previously set * inputsource and outputstream */ public synchronized void run() throws IOException, FOPException { if (_renderer == null) { setRenderer(RENDER_PDF); } if (_source == null) { throw new FOPException("InputSource is not set."); } if (_reader == null) { if (!(_source instanceof DocumentInputSource)) { _reader = ConfigurationReader.createParser(); } } if (_source instanceof DocumentInputSource) { buildFOTree(((DocumentInputSource)_source).getDocument()); } else { buildFOTree(_reader, _source); } format(); render(); } }