diff options
Diffstat (limited to 'src/java/org/apache/fop')
27 files changed, 1005 insertions, 621 deletions
diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java index e7686e65f..9a052b155 100644 --- a/src/java/org/apache/fop/apps/FOUserAgent.java +++ b/src/java/org/apache/fop/apps/FOUserAgent.java @@ -20,10 +20,7 @@ package org.apache.fop.apps; // Java import java.io.File; -import java.net.URL; -import java.net.MalformedURLException; import java.util.Date; -import java.util.List; import java.util.Map; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; @@ -39,19 +36,17 @@ import org.apache.commons.logging.LogFactory; // FOP import org.apache.fop.Version; -import org.apache.fop.fo.ElementMapping; import org.apache.fop.fo.FOEventHandler; -import org.apache.fop.hyphenation.HyphenationTreeResolver; -import org.apache.fop.layoutmgr.LayoutManagerMaker; import org.apache.fop.pdf.PDFEncryptionParams; import org.apache.fop.render.Renderer; import org.apache.fop.render.RendererFactory; import org.apache.fop.render.XMLHandlerRegistry; +import org.apache.fop.render.pdf.PDFRenderer; /** - * The User Agent for fo. - * This user agent is used by the processing to obtain user configurable - * options. + * This is the user agent for FOP. + * It is the entity through which you can interact with the XSL-FO processing and is + * used by the processing to obtain user configurable options. * <p> * Renderer specific extensions (that do not produce normal areas on * the output) will be done like so: @@ -70,65 +65,25 @@ import org.apache.fop.render.XMLHandlerRegistry; */ public class FOUserAgent { - /** Defines the default source resolution (72dpi) for FOP */ - public static final float DEFAULT_SOURCE_RESOLUTION = 72.0f; //dpi /** Defines the default target resolution (72dpi) for FOP */ public static final float DEFAULT_TARGET_RESOLUTION = 72.0f; //dpi - /** Defines the default page-height */ - public static final String DEFAULT_PAGE_HEIGHT = "11in"; - /** Defines the default page-width */ - public static final String DEFAULT_PAGE_WIDTH = "8.26in"; - - /** Factory for Renderers and FOEventHandlers */ - private RendererFactory rendererFactory = new RendererFactory(); - - /** Registry for XML handlers */ - private XMLHandlerRegistry xmlHandlers = new XMLHandlerRegistry(); - - /** The resolver for user-supplied hyphenation patterns */ - private HyphenationTreeResolver hyphResolver; + + private static Log log = LogFactory.getLog("FOP"); + + private FopFactory factory; /** The base URL for all URL resolutions, especially for external-graphics */ private String baseURL; - /** The base URL for all font URL resolutions */ - private String fontBaseURL; - /** A user settable URI Resolver */ private URIResolver uriResolver = null; - /** Our default resolver if none is set */ - private URIResolver foURIResolver = new FOURIResolver(); - private PDFEncryptionParams pdfEncryptionParams; - private float sourceResolution = DEFAULT_SOURCE_RESOLUTION; private float targetResolution = DEFAULT_TARGET_RESOLUTION; - private String pageHeight = DEFAULT_PAGE_HEIGHT; - private String pageWidth = DEFAULT_PAGE_WIDTH; private Map rendererOptions = new java.util.HashMap(); private File outputFile = null; private Renderer rendererOverride = null; private FOEventHandler foEventHandlerOverride = null; - private LayoutManagerMaker lmMakerOverride = null; - /* user configuration */ - private Configuration userConfig = null; - private Log log = LogFactory.getLog("FOP"); - - /* FOP has the ability, for some FO's, to continue processing even if the - * input XSL violates that FO's content model. This is the default - * behavior for FOP. However, this flag, if set, provides the user the - * ability for FOP to halt on all content model violations if desired. - */ - private boolean strictValidation = true; - /** @see #setBreakIndentInheritanceOnReferenceAreaBoundary(boolean) */ - private boolean breakIndentInheritanceOnReferenceAreaBoundary = false; - - /** Allows enabling kerning on the base 14 fonts, default is false */ - private boolean enableBase14Kerning = false; - - /* Additional fo.ElementMapping subclasses set by user */ - private List additionalElementMappings = null; - /** Producer: Metadata element for the system/software that produces * the document. (Some renderers can store this in the document.) */ @@ -152,24 +107,43 @@ public class FOUserAgent { protected String keywords = null; /** - * Add the element mapping with the given class name. - * @param elementMapping the class name representing the element mapping. + * Default constructor + * @see org.apache.fop.apps.FopFactory + * @deprecated Provided for compatibility only. Please use the methods from + * FopFactory to construct FOUserAgent instances! */ - public void addElementMapping(ElementMapping elementMapping) { - if (additionalElementMappings == null) { - additionalElementMappings = new java.util.ArrayList(); - } - additionalElementMappings.add(elementMapping); + public FOUserAgent() { + this(FopFactory.newInstance()); } - + /** - * Returns the List of user-added ElementMapping class names - * @return List of Strings holding ElementMapping names. + * Main constructor. <b>This constructor should not be called directly. Please use the + * methods from FopFactory to construct FOUserAgent instances!</b> + * @param factory the factory that provides environment-level information + * @see org.apache.fop.apps.FopFactory */ - public List getAdditionalElementMappings() { - return additionalElementMappings; + public FOUserAgent(FopFactory factory) { + if (factory == null) { + throw new NullPointerException("The factory parameter must not be null"); + } + this.factory = factory; + try { + if (factory.getUserConfig() != null) { + configure(factory.getUserConfig()); + } + } catch (ConfigurationException cfge) { + log.error("Error while initializing the user asgent: " + + cfge.getMessage()); + } } - + + /** @return the associated FopFactory instance */ + public FopFactory getFactory() { + return this.factory; + } + + // ---------------------------------------------- rendering-run dependent stuff + /** * Sets an explicit renderer to use which overrides the one defined by the * render type setting. @@ -205,78 +179,6 @@ public class FOUserAgent { } /** - * Activates strict XSL content model validation for FOP - * Default is false (FOP will continue processing where it can) - * @param validateStrictly true to turn on strict validation - */ - public void setStrictValidation(boolean validateStrictly) { - this.strictValidation = validateStrictly; - } - - /** - * Returns whether FOP is strictly validating input XSL - * @return true of strict validation turned on, false otherwise - */ - public boolean validateStrictly() { - return strictValidation; - } - - /** - * @return true if the indent inheritance should be broken when crossing reference area - * boundaries (for more info, see the javadoc for the relative member variable) - */ - public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() { - return breakIndentInheritanceOnReferenceAreaBoundary; - } - - /** - * Controls whether to enable a feature that breaks indent inheritance when crossing - * reference area boundaries. - * <p> - * This flag controls whether FOP will enable special code that breaks property - * inheritance for start-indent and end-indent when the evaluation of the inherited - * value would cross a reference area. This is described under - * http://wiki.apache.org/xmlgraphics-fop/IndentInheritance as is intended to - * improve interoperability with commercial FO implementations and to produce - * results that are more in line with the expectation of unexperienced FO users. - * Note: Enabling this features violates the XSL specification! - * @param value true to enable the feature - */ - public void setBreakIndentInheritanceOnReferenceAreaBoundary(boolean value) { - this.breakIndentInheritanceOnReferenceAreaBoundary = value; - } - - /** @return true if kerning on base 14 fonts is enabled */ - public boolean isBase14KerningEnabled() { - return this.enableBase14Kerning; - } - - /** - * Controls whether kerning is activated on base 14 fonts. - * @param value true if kerning should be activated - */ - public void setBase14KerningEnabled(boolean value) { - this.enableBase14Kerning = value; - } - - /** - * Sets an explicit LayoutManagerMaker instance which overrides the one - * defined by the AreaTreeHandler. - * @param lmMaker the LayoutManagerMaker instance - */ - public void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker) { - this.lmMakerOverride = lmMaker; - } - - /** - * Returns the overriding LayoutManagerMaker instance, if any. - * @return the overriding LayoutManagerMaker or null - */ - public LayoutManagerMaker getLayoutManagerMakerOverride() { - return this.lmMakerOverride; - } - - /** * Sets the producer of the document. * @param producer source of document */ @@ -382,95 +284,18 @@ public class FOUserAgent { } /** - * Set the user configuration. - * @param userConfig configuration - */ - public void setUserConfig(Configuration userConfig) { - this.userConfig = userConfig; - try { - initUserConfig(); - } catch (ConfigurationException cfge) { - log.error("Error initializing User Agent configuration: " - + cfge.getMessage()); - } - } - - /** - * Get the user configuration. - * @return the user configuration + * Configures the FOUserAgent through the factory's configuration. + * @see org.apache.avalon.framework.configuration.Configurable */ - public Configuration getUserConfig() { - return userConfig; - } - - /** - * Initializes user agent settings from the user configuration - * file, if present: baseURL, resolution, default page size,... - * - * @throws ConfigurationException when there is an entry that - * misses the required attribute - */ - public void initUserConfig() throws ConfigurationException { - log.debug("Initializing User Agent Configuration"); - setBaseURL(getBaseURLfromConfig("base")); - setFontBaseURL(getBaseURLfromConfig("font-base")); - final String hyphBase = getBaseURLfromConfig("hyphenation-base"); - if (hyphBase != null) { - this.hyphResolver = new HyphenationTreeResolver() { - public Source resolve(String href) { - return resolveURI(href, hyphBase); - } - }; - } - if (userConfig.getChild("source-resolution", false) != null) { - this.sourceResolution - = userConfig.getChild("source-resolution").getValueAsFloat( - DEFAULT_SOURCE_RESOLUTION); - log.info("Source resolution set to: " + sourceResolution - + "dpi (px2mm=" + getSourcePixelUnitToMillimeter() + ")"); - } - if (userConfig.getChild("target-resolution", false) != null) { + protected void configure(Configuration cfg) throws ConfigurationException { + setBaseURL(FopFactory.getBaseURLfromConfig(cfg, "base")); + if (cfg.getChild("target-resolution", false) != null) { this.targetResolution - = userConfig.getChild("target-resolution").getValueAsFloat( + = cfg.getChild("target-resolution").getValueAsFloat( DEFAULT_TARGET_RESOLUTION); log.info("Target resolution set to: " + targetResolution + "dpi (px2mm=" + getTargetPixelUnitToMillimeter() + ")"); } - if (userConfig.getChild("strict-validation", false) != null) { - this.strictValidation = userConfig.getChild("strict-validation").getValueAsBoolean(); - } - if (userConfig.getChild("break-indent-inheritance", false) != null) { - this.breakIndentInheritanceOnReferenceAreaBoundary - = userConfig.getChild("break-indent-inheritance").getValueAsBoolean(); - } - Configuration pageConfig = userConfig.getChild("default-page-settings"); - if (pageConfig.getAttribute("height", null) != null) { - setPageHeight(pageConfig.getAttribute("height")); - log.info("Default page-height set to: " + pageHeight); - } - if (pageConfig.getAttribute("width", null) != null) { - setPageWidth(pageConfig.getAttribute("width")); - log.info("Default page-width set to: " + pageWidth); - } - } - - private String getBaseURLfromConfig(String name) { - if (userConfig.getChild(name, false) != null) { - try { - String cfgBaseDir = userConfig.getChild(name).getValue(null); - if (cfgBaseDir != null) { - File dir = new File(cfgBaseDir); - if (dir.isDirectory()) { - cfgBaseDir = dir.toURL().toExternalForm(); - } - } - log.info(name + " set to: " + cfgBaseDir); - return cfgBaseDir; - } catch (MalformedURLException mue) { - log.error("Base URL in user config is malformed!"); - } - } - return null; } /** @@ -478,21 +303,22 @@ public class FOUserAgent { * @param mimeType MIME type of the renderer * @return the requested configuration subtree, null if there's no configuration */ - public Configuration getUserRendererConfig (String mimeType) { + public Configuration getUserRendererConfig(String mimeType) { - if (userConfig == null || mimeType == null) { + Configuration cfg = getFactory().getUserConfig(); + if (cfg == null || mimeType == null) { return null; } Configuration userRendererConfig = null; Configuration[] cfgs - = userConfig.getChild("renderers").getChildren("renderer"); + = cfg.getChild("renderers").getChildren("renderer"); for (int i = 0; i < cfgs.length; ++i) { - Configuration cfg = cfgs[i]; + Configuration child = cfgs[i]; try { - if (cfg.getAttribute("mime").equals(mimeType)) { - userRendererConfig = cfg; + if (child.getAttribute("mime").equals(mimeType)) { + userRendererConfig = child; break; } } catch (ConfigurationException e) { @@ -521,27 +347,11 @@ public class FOUserAgent { } /** - * Sets the font base URL. - * @param fontBaseURL font base URL - */ - public void setFontBaseURL(String fontBaseURL) { - this.fontBaseURL = fontBaseURL; - } - - /** - * Returns the font base URL. - * @return the font base URL - */ - public String getFontBaseURL() { - return this.fontBaseURL != null ? this.fontBaseURL : this.baseURL; - } - - /** * Sets the URI Resolver. - * @param uriResolver the new URI resolver + * @param resolver the new URI resolver */ - public void setURIResolver(URIResolver uriResolver) { - this.uriResolver = uriResolver; + public void setURIResolver(URIResolver resolver) { + this.uriResolver = resolver; } /** @@ -555,18 +365,23 @@ public class FOUserAgent { /** * Returns the parameters for PDF encryption. * @return the PDF encryption parameters, null if not applicable + * @deprecated Use (PDFEncryptionParams)getRendererOptions().get("encryption-params") + * instead. */ public PDFEncryptionParams getPDFEncryptionParams() { - return pdfEncryptionParams; + return (PDFEncryptionParams)getRendererOptions().get(PDFRenderer.ENCRYPTION_PARAMS); } /** * Sets the parameters for PDF encryption. * @param pdfEncryptionParams the PDF encryption parameters, null to * disable PDF encryption + * @deprecated Use getRendererOptions().put("encryption-params", + * new PDFEncryptionParams(..)) instead or set every parameter separately: + * getRendererOptions().put("noprint", Boolean.TRUE). */ public void setPDFEncryptionParams(PDFEncryptionParams pdfEncryptionParams) { - this.pdfEncryptionParams = pdfEncryptionParams; + getRendererOptions().put(PDFRenderer.ENCRYPTION_PARAMS, pdfEncryptionParams); } @@ -588,27 +403,23 @@ public class FOUserAgent { * Will use the configured resolver and if not successful fall back * to the default resolver. * @param uri URI to access - * @param baseURL the base url to resolve against + * @param base the base URI to resolve against * @return A {@link javax.xml.transform.Source} object, or null if the URI * cannot be resolved. * @see org.apache.fop.apps.FOURIResolver */ - public Source resolveURI(String uri, String baseURL) { + public Source resolveURI(String uri, String base) { Source source = null; if (uriResolver != null) { try { - source = uriResolver.resolve(uri, baseURL); + source = uriResolver.resolve(uri, base); } catch (TransformerException te) { log.error("Attempt to resolve URI '" + uri + "' failed: ", te); } } if (source == null) { - // URI Resolver not configured or returned null, use default resolver - try { - source = foURIResolver.resolve(uri, baseURL); - } catch (TransformerException te) { - log.error("Attempt to resolve URI '" + uri + "' failed: ", te); - } + // URI Resolver not configured or returned null, use default resolver from the factory + source = getFactory().resolveURI(uri, base); } return source; } @@ -631,44 +442,20 @@ public class FOUserAgent { /** * Returns the conversion factor from pixel units to millimeters. This - * depends on the desired source resolution. - * @return float conversion factor - * @see getSourceResolution() - */ - public float getSourcePixelUnitToMillimeter() { - return 25.4f / this.sourceResolution; - } - - /** - * Returns the conversion factor from pixel units to millimeters. This * depends on the desired target resolution. * @return float conversion factor - * @see getTargetResolution() + * @see #getTargetResolution() */ public float getTargetPixelUnitToMillimeter() { return 25.4f / this.targetResolution; } - /** @return the resolution for resolution-dependant input */ - public float getSourceResolution() { - return this.sourceResolution; - } - /** @return the resolution for resolution-dependant output */ public float getTargetResolution() { return this.targetResolution; } /** - * Sets the source resolution in dpi. This value is used to interpret the pixel size - * of source documents like SVG images and bitmap images without resolution information. - * @param dpi resolution in dpi - */ - public void setSourceResolution(int dpi) { - this.sourceResolution = dpi; - } - - /** * Sets the target resolution in dpi. This value defines the target resolution of * bitmap images generated by the bitmap renderers (such as the TIFF renderer) and of * bitmap images generated by filter effects in Apache Batik. @@ -678,24 +465,39 @@ public class FOUserAgent { this.targetResolution = dpi; } + // ---------------------------------------------- environment-level stuff + // (convenience access to FopFactory methods) + + /** @return the font base URL */ + public String getFontBaseURL() { + String fontBaseURL = getFactory().getFontBaseURL(); + return fontBaseURL != null ? fontBaseURL : this.baseURL; + } + /** - * Gets the default page-height to use as fallback, - * in case page-height="auto" - * - * @return the page-height, as a String + * Returns the conversion factor from pixel units to millimeters. This + * depends on the desired source resolution. + * @return float conversion factor + * @see #getSourceResolution() */ - public String getPageHeight() { - return this.pageHeight; + public float getSourcePixelUnitToMillimeter() { + return getFactory().getSourcePixelUnitToMillimeter(); } + /** @return the resolution for resolution-dependant input */ + public float getSourceResolution() { + return getFactory().getSourceResolution(); + } + /** - * Sets the page-height to use as fallback, in case - * page-height="auto" + * Gets the default page-height to use as fallback, + * in case page-height="auto" * - * @param pageHeight page-height as a String + * @return the page-height, as a String + * @see FopFactory#getPageHeight() */ - public void setPageHeight(String pageHeight) { - this.pageHeight = pageHeight; + public String getPageHeight() { + return getFactory().getPageHeight(); } /** @@ -703,48 +505,43 @@ public class FOUserAgent { * in case page-width="auto" * * @return the page-width, as a String + * @see FopFactory#getPageWidth() */ public String getPageWidth() { - return this.pageWidth; + return getFactory().getPageWidth(); } /** - * Sets the page-width to use as fallback, in case - * page-width="auto" - * - * @param pageWidth page-width as a String + * Returns whether FOP is strictly validating input XSL + * @return true of strict validation turned on, false otherwise + * @see FopFactory#validateStrictly() */ - public void setPageWidth(String pageWidth) { - this.pageWidth = pageWidth; + public boolean validateStrictly() { + return getFactory().validateStrictly(); } - + /** - * If to create hot links to footnotes and before floats. - * @return True if hot links should be created + * @return true if the indent inheritance should be broken when crossing reference area + * boundaries (for more info, see the javadoc for the relative member variable) + * @see FopFactory#isBreakIndentInheritanceOnReferenceAreaBoundary() */ - /* TODO This method is never referenced! - public boolean linkToFootnotes() { - return true; - }*/ + public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() { + return getFactory().isBreakIndentInheritanceOnReferenceAreaBoundary(); + } /** * @return the RendererFactory */ public RendererFactory getRendererFactory() { - return this.rendererFactory; + return getFactory().getRendererFactory(); } /** * @return the XML handler registry */ public XMLHandlerRegistry getXMLHandlerRegistry() { - return this.xmlHandlers; + return getFactory().getXMLHandlerRegistry(); } - /** @return the HyphenationTreeResolver for resolving user-supplied hyphenation patterns. */ - public HyphenationTreeResolver getHyphenationTreeResolver() { - return this.hyphResolver; - } - } diff --git a/src/java/org/apache/fop/apps/Fop.java b/src/java/org/apache/fop/apps/Fop.java index 720d78644..574a17350 100644 --- a/src/java/org/apache/fop/apps/Fop.java +++ b/src/java/org/apache/fop/apps/Fop.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,6 @@ import java.io.OutputStream; import org.xml.sax.helpers.DefaultHandler; // FOP -import org.apache.fop.fo.Constants; import org.apache.fop.fo.FOTreeBuilder; /** @@ -45,7 +44,7 @@ import org.apache.fop.fo.FOTreeBuilder; * At the moment, it is recommended not to reuse an instance of this * class for more than one rendering run. */ -public class Fop implements Constants { +public class Fop { // desired output format: MIME type such as "application/pdf", "application/postscript" etc. private String outputFormat = null; @@ -64,23 +63,54 @@ public class Fop implements Constants { * output format (ex. "application/pdf" for PDF). * @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). * @param ua FOUserAgent object + * @param stream the output stream + * @throws FOPException if setting up the DefaultHandler fails + * @deprecated End-users should use {@link FopFactory#newFop(String, FOUserAgent, OutputStream)} + * instead! This constructor will become invisible with FOP 1.0. + */ + public Fop(String outputFormat, FOUserAgent ua, OutputStream stream) throws FOPException { + this.outputFormat = outputFormat; + + foUserAgent = ua; + if (foUserAgent == null) { + foUserAgent = FopFactory.newInstance().newFOUserAgent(); + } + + this.stream = stream; + + createDefaultHandler(); + } + + /** + * Constructor for use with already-created FOUserAgents. It uses MIME types to select the + * output format (ex. "application/pdf" for PDF). + * @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). + * @param ua FOUserAgent object + * @throws FOPException if setting up the DefaultHandler fails + * @deprecated End-users should use {@link FopFactory#newFop(String, FOUserAgent)} instead! + * This constructor will become invisible with FOP 1.0. */ - public Fop(String outputFormat, FOUserAgent ua) { + public Fop(String outputFormat, FOUserAgent ua) throws FOPException { this.outputFormat = outputFormat; foUserAgent = ua; if (foUserAgent == null) { - foUserAgent = new FOUserAgent(); + foUserAgent = FopFactory.newInstance().newFOUserAgent(); } + + createDefaultHandler(); } /** * Constructor for FOP with a default FOUserAgent. It uses MIME types to select the * output format (ex. "application/pdf" for PDF). * @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). + * @deprecated End-users should use {@link FopFactory#newFop(String)} instead! + * This constructor will become invisible with FOP 1.0. */ public Fop(String outputFormat) { - this(outputFormat, null); + this.outputFormat = outputFormat; + foUserAgent = FopFactory.newInstance().newFOUserAgent(); } /** @@ -95,25 +125,36 @@ public class Fop implements Constants { * Set the OutputStream to use to output the result of the Render * (if applicable) * @param stream the stream to output the result of rendering to + * @deprecated Use one of the factory methods on {@link FopFactory} with an OutputStream + * parameter instead. This method will be removed with FOP 1.0. */ public void setOutputStream(OutputStream stream) { this.stream = stream; } /** - * Returns a DefaultHandler object used to generate the document. + * Creates a DefaultHandler object used to generate the document. * Note this object implements the ContentHandler interface. * For processing with a Transformer object, this DefaultHandler object * can be used in the SAXResult constructor. * Alternatively, for processing with a SAXParser, this object can be * used as the DefaultHandler argument to its parse() methods. * - * @return a SAX DefaultHandler for handling the SAX events. + * @throws FOPException if setting up the DefaultHandler fails + */ + private void createDefaultHandler() throws FOPException { + this.foTreeBuilder = new FOTreeBuilder(outputFormat, foUserAgent, stream); + } + + /** + * Returns the DefaultHandler object used to generate the document. + * Checking for null and the exception is only for the deprecated constructor. + * @return the SAX DefaultHandler for handling the SAX events. * @throws FOPException if setting up the DefaultHandler fails */ public DefaultHandler getDefaultHandler() throws FOPException { if (foTreeBuilder == null) { - this.foTreeBuilder = new FOTreeBuilder(outputFormat, foUserAgent, stream); + createDefaultHandler(); } return this.foTreeBuilder; } @@ -140,6 +181,7 @@ public class Fop implements Constants { * Get the version of FOP * @return the version string * @deprecated Use {@link org.apache.fop.Version#getVersion()} instead! + * This method will be removed with FOP 1.0. */ public static String getVersion() { return org.apache.fop.Version.getVersion(); diff --git a/src/java/org/apache/fop/apps/FopFactory.java b/src/java/org/apache/fop/apps/FopFactory.java new file mode 100644 index 000000000..832004195 --- /dev/null +++ b/src/java/org/apache/fop/apps/FopFactory.java @@ -0,0 +1,608 @@ +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.apps; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.util.List; + +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; +import javax.xml.transform.URIResolver; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.fo.ElementMapping; +import org.apache.fop.fo.ElementMappingRegistry; +import org.apache.fop.hyphenation.HyphenationTreeResolver; +import org.apache.fop.image.ImageFactory; +import org.apache.fop.layoutmgr.LayoutManagerMaker; +import org.apache.fop.render.RendererFactory; +import org.apache.fop.render.XMLHandlerRegistry; +import org.apache.fop.util.ContentHandlerFactoryRegistry; +import org.xml.sax.SAXException; + +/** + * Factory class which instantiates new Fop and FOUserAgent instances. This class also holds + * environmental information and configuration used by FOP. Information that may potentially be + * different for each rendering run can be found and managed in the FOUserAgent. + */ +public class FopFactory { + + /** Defines the default source resolution (72dpi) for FOP */ + private static final float DEFAULT_SOURCE_RESOLUTION = 72.0f; //dpi + /** Defines the default page-height */ + private static final String DEFAULT_PAGE_HEIGHT = "11in"; + /** Defines the default page-width */ + private static final String DEFAULT_PAGE_WIDTH = "8.26in"; + + /** logger instance */ + private static Log log = LogFactory.getLog(FopFactory.class); + + /** Factory for Renderers and FOEventHandlers */ + private RendererFactory rendererFactory = new RendererFactory(); + + /** Registry for XML handlers */ + private XMLHandlerRegistry xmlHandlers = new XMLHandlerRegistry(); + + /** The registry for ElementMapping instances */ + private ElementMappingRegistry elementMappingRegistry; + + /** The registry for ContentHandlerFactory instance */ + private ContentHandlerFactoryRegistry contentHandlerFactoryRegistry + = new ContentHandlerFactoryRegistry(); + + /** Our default resolver if none is set */ + private URIResolver foURIResolver = new FOURIResolver(); + /** A user settable URI Resolver */ + private URIResolver uriResolver = null; + + /** The resolver for user-supplied hyphenation patterns */ + private HyphenationTreeResolver hyphResolver; + + private ImageFactory imageFactory = new ImageFactory(); + + /** user configuration */ + private Configuration userConfig = null; + + /** The base URL for all font URL resolutions */ + private String fontBaseURL; + + /** + * FOP has the ability, for some FO's, to continue processing even if the + * input XSL violates that FO's content model. This is the default + * behavior for FOP. However, this flag, if set, provides the user the + * ability for FOP to halt on all content model violations if desired. + */ + private boolean strictValidation = true; + + /** Allows enabling kerning on the base 14 fonts, default is false */ + private boolean enableBase14Kerning = false; + + /** Source resolution in dpi */ + private float sourceResolution = DEFAULT_SOURCE_RESOLUTION; + private String pageHeight = DEFAULT_PAGE_HEIGHT; + private String pageWidth = DEFAULT_PAGE_WIDTH; + + /** @see #setBreakIndentInheritanceOnReferenceAreaBoundary(boolean) */ + private boolean breakIndentInheritanceOnReferenceAreaBoundary = false; + + /** Additional fo.ElementMapping subclasses set by user */ + private List additionalElementMappings = null; + + /** Optional overriding LayoutManagerMaker */ + private LayoutManagerMaker lmMakerOverride = null; + + /** + * Main constructor. + */ + protected FopFactory() { + this.elementMappingRegistry = new ElementMappingRegistry(this); + } + + /** + * Returns a new FopFactory instance. + * @return the requested FopFactory instance. + */ + public static FopFactory newInstance() { + return new FopFactory(); + } + + /** + * Returns a new FOUserAgent instance. Use the FOUserAgent to configure special values that + * are particular to a rendering run. Don't reuse instances over multiple rendering runs but + * instead create a new one each time and reuse the FopFactory. + * @return the newly created FOUserAgent instance initialized with default values + */ + public FOUserAgent newFOUserAgent() { + FOUserAgent userAgent = new FOUserAgent(this); + return userAgent; + } + + /** + * Returns a new {@link Fop} instance. FOP will be configured with a default user agent + * instance. + * <p> + * MIME types are used to select the output format (ex. "application/pdf" for PDF). You can + * use the constants defined in {@link MimeConstants}. + * @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). + * @return the new Fop instance + * @throws FOPException when the constructor fails + */ + public Fop newFop(String outputFormat) throws FOPException { + return new Fop(outputFormat, newFOUserAgent()); + } + + /** + * Returns a new {@link Fop} instance. Use this factory method if you want to configure this + * very rendering run, i.e. if you want to set some metadata like the title and author of the + * document you want to render. In that case, create a new {@link FOUserAgent} + * instance using {@link #newFOUserAgent()}. + * <p> + * MIME types are used to select the output format (ex. "application/pdf" for PDF). You can + * use the constants defined in {@link MimeConstants}. + * @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). + * @param userAgent the user agent that will be used to control the rendering run + * @return the new Fop instance + * @throws FOPException when the constructor fails + */ + public Fop newFop(String outputFormat, FOUserAgent userAgent) throws FOPException { + if (userAgent == null) { + throw new NullPointerException("The userAgent parameter must not be null!"); + } + return new Fop(outputFormat, userAgent); + } + + /** + * Returns a new {@link Fop} instance. FOP will be configured with a default user agent + * instance. Use this factory method if your output type requires an output stream. + * <p> + * MIME types are used to select the output format (ex. "application/pdf" for PDF). You can + * use the constants defined in {@link MimeConstants}. + * @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). + * @param stream the output stream + * @return the new Fop instance + * @throws FOPException when the constructor fails + */ + public Fop newFop(String outputFormat, OutputStream stream) throws FOPException { + return new Fop(outputFormat, newFOUserAgent(), stream); + } + + /** + * Returns a new {@link Fop} instance. Use this factory method if your output type + * requires an output stream and you want to configure this very rendering run, + * i.e. if you want to set some metadata like the title and author of the document + * you want to render. In that case, create a new {@link FOUserAgent} instance + * using {@link #newFOUserAgent()}. + * <p> + * MIME types are used to select the output format (ex. "application/pdf" for PDF). You can + * use the constants defined in {@link MimeConstants}. + * @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). + * @param userAgent the user agent that will be used to control the rendering run + * @param stream the output stream + * @return the new Fop instance + * @throws FOPException when the constructor fails + */ + public Fop newFop(String outputFormat, FOUserAgent userAgent, OutputStream stream) + throws FOPException { + if (userAgent == null) { + throw new NullPointerException("The userAgent parameter must not be null!"); + } + return new Fop(outputFormat, userAgent, stream); + } + + /** + * Returns a new {@link Fop} instance. Use this factory method if you want to supply your + * own {@link org.apache.fop.render.Renderer Renderer} or + * {@link org.apache.fop.fo.FOEventHandler FOEventHandler} + * instance instead of the default ones created internally by FOP. + * @param userAgent the user agent that will be used to control the rendering run + * @return the new Fop instance + * @throws FOPException when the constructor fails + */ + public Fop newFop(FOUserAgent userAgent) throws FOPException { + if (userAgent.getRendererOverride() == null + && userAgent.getFOEventHandlerOverride() == null) { + throw new IllegalStateException("Either the overriding renderer or the overriding" + + " FOEventHandler must be set when this factory method is used!"); + } + return newFop(null, userAgent); + } + + /** @return the RendererFactory */ + public RendererFactory getRendererFactory() { + return this.rendererFactory; + } + + /** @return the XML handler registry */ + public XMLHandlerRegistry getXMLHandlerRegistry() { + return this.xmlHandlers; + } + + /** @return the element mapping registry */ + public ElementMappingRegistry getElementMappingRegistry() { + return this.elementMappingRegistry; + } + + /** @return the content handler factory registry */ + public ContentHandlerFactoryRegistry getContentHandlerFactoryRegistry() { + return this.contentHandlerFactoryRegistry; + } + + /** @return the image factory */ + public ImageFactory getImageFactory() { + return this.imageFactory; + } + + /** + * Add the element mapping with the given class name. + * @param elementMapping the class name representing the element mapping. + */ + public void addElementMapping(ElementMapping elementMapping) { + if (additionalElementMappings == null) { + additionalElementMappings = new java.util.ArrayList(); + } + additionalElementMappings.add(elementMapping); + } + + /** + * Returns the List of user-added ElementMapping class names + * @return List of Strings holding ElementMapping names. + */ + public List getAdditionalElementMappings() { + return additionalElementMappings; + } + + /** + * Sets an explicit LayoutManagerMaker instance which overrides the one + * defined by the AreaTreeHandler. + * @param lmMaker the LayoutManagerMaker instance + */ + public void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker) { + this.lmMakerOverride = lmMaker; + } + + /** + * Returns the overriding LayoutManagerMaker instance, if any. + * @return the overriding LayoutManagerMaker or null + */ + public LayoutManagerMaker getLayoutManagerMakerOverride() { + return this.lmMakerOverride; + } + + /** + * Sets the font base URL. + * @param fontBaseURL font base URL + */ + public void setFontBaseURL(String fontBaseURL) { + this.fontBaseURL = fontBaseURL; + } + + /** @return the font base URL */ + public String getFontBaseURL() { + return this.fontBaseURL; + } + + /** + * Sets the URI Resolver. It is used for resolving factory-level URIs like hyphenation + * patterns and as backup for URI resolution performed during a rendering run. + * @param resolver the new URI resolver + */ + public void setURIResolver(URIResolver resolver) { + this.uriResolver = resolver; + } + + /** + * Returns the URI Resolver. + * @return the URI Resolver + */ + public URIResolver getURIResolver() { + return this.uriResolver; + } + + /** @return the HyphenationTreeResolver for resolving user-supplied hyphenation patterns. */ + public HyphenationTreeResolver getHyphenationTreeResolver() { + return this.hyphResolver; + } + + /** + * Activates strict XSL content model validation for FOP + * Default is false (FOP will continue processing where it can) + * @param validateStrictly true to turn on strict validation + */ + public void setStrictValidation(boolean validateStrictly) { + this.strictValidation = validateStrictly; + } + + /** + * Returns whether FOP is strictly validating input XSL + * @return true of strict validation turned on, false otherwise + */ + public boolean validateStrictly() { + return strictValidation; + } + + /** + * @return true if the indent inheritance should be broken when crossing reference area + * boundaries (for more info, see the javadoc for the relative member variable) + */ + public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() { + return breakIndentInheritanceOnReferenceAreaBoundary; + } + + /** + * Controls whether to enable a feature that breaks indent inheritance when crossing + * reference area boundaries. + * <p> + * This flag controls whether FOP will enable special code that breaks property + * inheritance for start-indent and end-indent when the evaluation of the inherited + * value would cross a reference area. This is described under + * http://wiki.apache.org/xmlgraphics-fop/IndentInheritance as is intended to + * improve interoperability with commercial FO implementations and to produce + * results that are more in line with the expectation of unexperienced FO users. + * Note: Enabling this features violates the XSL specification! + * @param value true to enable the feature + */ + public void setBreakIndentInheritanceOnReferenceAreaBoundary(boolean value) { + this.breakIndentInheritanceOnReferenceAreaBoundary = value; + } + + /** @return true if kerning on base 14 fonts is enabled */ + public boolean isBase14KerningEnabled() { + return this.enableBase14Kerning; + } + + /** + * Controls whether kerning is activated on base 14 fonts. + * @param value true if kerning should be activated + */ + public void setBase14KerningEnabled(boolean value) { + this.enableBase14Kerning = value; + } + + /** @return the resolution for resolution-dependant input */ + public float getSourceResolution() { + return this.sourceResolution; + } + + /** + * Returns the conversion factor from pixel units to millimeters. This + * depends on the desired source resolution. + * @return float conversion factor + * @see #getSourceResolution() + */ + public float getSourcePixelUnitToMillimeter() { + return 25.4f / getSourceResolution(); + } + + /** + * Sets the source resolution in dpi. This value is used to interpret the pixel size + * of source documents like SVG images and bitmap images without resolution information. + * @param dpi resolution in dpi + */ + public void setSourceResolution(int dpi) { + this.sourceResolution = dpi; + } + + /** + * Gets the default page-height to use as fallback, + * in case page-height="auto" + * + * @return the page-height, as a String + */ + public String getPageHeight() { + return this.pageHeight; + } + + /** + * Sets the page-height to use as fallback, in case + * page-height="auto" + * + * @param pageHeight page-height as a String + */ + public void setPageHeight(String pageHeight) { + this.pageHeight = pageHeight; + } + + /** + * Gets the default page-width to use as fallback, + * in case page-width="auto" + * + * @return the page-width, as a String + */ + public String getPageWidth() { + return this.pageWidth; + } + + /** + * Sets the page-width to use as fallback, in case + * page-width="auto" + * + * @param pageWidth page-width as a String + */ + public void setPageWidth(String pageWidth) { + this.pageWidth = pageWidth; + } + + //------------------------------------------- Configuration stuff + + /** + * Set the user configuration. + * @param userConfigFile the configuration file + * @throws IOException if an I/O error occurs + * @throws SAXException if a parsing error occurs + */ + public void setUserConfig(File userConfigFile) + throws SAXException, IOException { + try { + DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder(); + setUserConfig(cfgBuilder.buildFromFile(userConfigFile)); + } catch (ConfigurationException cfge) { + log.error("Error loading configuration: " + + cfge.getMessage()); + } + } + + /** + * Set the user configuration from an URI. + * @param uri the URI to the configuration file + * @throws IOException if an I/O error occurs + * @throws SAXException if a parsing error occurs + */ + public void setUserConfig(String uri) + throws SAXException, IOException { + try { + DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder(); + setUserConfig(cfgBuilder.build(uri)); + } catch (ConfigurationException cfge) { + log.error("Error loading configuration: " + + cfge.getMessage()); + } + } + + /** + * Set the user configuration. + * @param userConfig configuration + */ + public void setUserConfig(Configuration userConfig) { + this.userConfig = userConfig; + try { + initUserConfig(); + } catch (ConfigurationException cfge) { + log.error("Error initializing factory configuration: " + + cfge.getMessage()); + } + } + + /** + * Get the user configuration. + * @return the user configuration + */ + public Configuration getUserConfig() { + return userConfig; + } + + /** + * Initializes user agent settings from the user configuration + * file, if present: baseURL, resolution, default page size,... + * + * @throws ConfigurationException when there is an entry that + * misses the required attribute + */ + public void initUserConfig() throws ConfigurationException { + log.debug("Initializing User Agent Configuration"); + setFontBaseURL(getBaseURLfromConfig(userConfig, "font-base")); + final String hyphBase = getBaseURLfromConfig(userConfig, "hyphenation-base"); + if (hyphBase != null) { + this.hyphResolver = new HyphenationTreeResolver() { + public Source resolve(String href) { + return resolveURI(href, hyphBase); + } + }; + } + if (userConfig.getChild("source-resolution", false) != null) { + this.sourceResolution + = userConfig.getChild("source-resolution").getValueAsFloat( + DEFAULT_SOURCE_RESOLUTION); + log.info("Source resolution set to: " + sourceResolution + + "dpi (px2mm=" + getSourcePixelUnitToMillimeter() + ")"); + } + if (userConfig.getChild("strict-validation", false) != null) { + this.strictValidation = userConfig.getChild("strict-validation").getValueAsBoolean(); + } + if (userConfig.getChild("break-indent-inheritance", false) != null) { + this.breakIndentInheritanceOnReferenceAreaBoundary + = userConfig.getChild("break-indent-inheritance").getValueAsBoolean(); + } + Configuration pageConfig = userConfig.getChild("default-page-settings"); + if (pageConfig.getAttribute("height", null) != null) { + setPageHeight(pageConfig.getAttribute("height")); + log.info("Default page-height set to: " + pageHeight); + } + if (pageConfig.getAttribute("width", null) != null) { + setPageWidth(pageConfig.getAttribute("width")); + log.info("Default page-width set to: " + pageWidth); + } + } + + /** + * Retrieves and verifies a base URL. + * @param cfg The Configuration object to retrieve the base URL from + * @param name the element name for the base URL + * @return the requested base URL or null if not available + */ + public static String getBaseURLfromConfig(Configuration cfg, String name) { + if (cfg.getChild(name, false) != null) { + try { + String cfgBaseDir = cfg.getChild(name).getValue(null); + if (cfgBaseDir != null) { + File dir = new File(cfgBaseDir); + if (dir.isDirectory()) { + cfgBaseDir = dir.toURL().toExternalForm(); + } + } + log.info(name + " set to: " + cfgBaseDir); + return cfgBaseDir; + } catch (MalformedURLException mue) { + log.error("Base URL in user config is malformed!"); + } + } + return null; + } + + //------------------------------------------- URI resolution + + /** + * Attempts to resolve the given URI. + * Will use the configured resolver and if not successful fall back + * to the default resolver. + * @param uri URI to access + * @param base the base URI to resolve against + * @return A {@link javax.xml.transform.Source} object, or null if the URI + * cannot be resolved. + * @see org.apache.fop.apps.FOURIResolver + */ + public Source resolveURI(String uri, String base) { + Source source = null; + if (uriResolver != null) { + try { + source = uriResolver.resolve(uri, base); + } catch (TransformerException te) { + log.error("Attempt to resolve URI '" + uri + "' failed: ", te); + } + } + if (source == null) { + // URI Resolver not configured or returned null, use default resolver + try { + source = foURIResolver.resolve(uri, base); + } catch (TransformerException te) { + log.error("Attempt to resolve URI '" + uri + "' failed: ", te); + } + } + return source; + } + + + +} diff --git a/src/java/org/apache/fop/area/AreaTreeHandler.java b/src/java/org/apache/fop/area/AreaTreeHandler.java index dfe2e7fa3..82a4ba234 100644 --- a/src/java/org/apache/fop/area/AreaTreeHandler.java +++ b/src/java/org/apache/fop/area/AreaTreeHandler.java @@ -116,7 +116,7 @@ public class AreaTreeHandler extends FOEventHandler { setupModel(userAgent, outputFormat, stream); - lmMaker = userAgent.getLayoutManagerMakerOverride(); + lmMaker = userAgent.getFactory().getLayoutManagerMakerOverride(); if (lmMaker == null) { lmMaker = new LayoutManagerMapping(); } diff --git a/src/java/org/apache/fop/area/AreaTreeParser.java b/src/java/org/apache/fop/area/AreaTreeParser.java index e3a291eee..251b4a687 100644 --- a/src/java/org/apache/fop/area/AreaTreeParser.java +++ b/src/java/org/apache/fop/area/AreaTreeParser.java @@ -108,8 +108,8 @@ public class AreaTreeParser { * @return the ContentHandler instance to receive the SAX stream from the area tree XML */ public ContentHandler getContentHandler(AreaTreeModel treeModel, FOUserAgent userAgent) { - //TODO Retrieve this instance from the environment class once it has been created. - ElementMappingRegistry elementMappingRegistry = new ElementMappingRegistry(userAgent); + ElementMappingRegistry elementMappingRegistry + = userAgent.getFactory().getElementMappingRegistry(); return new Handler(treeModel, userAgent, elementMappingRegistry); } @@ -252,8 +252,9 @@ public class AreaTreeParser { handled = false; } } else { - ContentHandlerFactory factory - = ContentHandlerFactoryRegistry.getInstance().getFactory(uri); + ContentHandlerFactoryRegistry registry + = userAgent.getFactory().getContentHandlerFactoryRegistry(); + ContentHandlerFactory factory = registry.getFactory(uri); if (factory != null) { delegate = factory.createContentHandler(); delegateStack.push(qName); @@ -936,7 +937,7 @@ public class AreaTreeParser { if (url != null) { bkg.setURL(url); - ImageFactory fact = ImageFactory.getInstance(); + ImageFactory fact = userAgent.getFactory().getImageFactory(); FopImage img = fact.getImage(url, userAgent); if (img == null) { log.error("Background image not available: " + url); diff --git a/src/java/org/apache/fop/cli/AreaTreeInputHandler.java b/src/java/org/apache/fop/cli/AreaTreeInputHandler.java index a8e83c87f..c4f0c5395 100644 --- a/src/java/org/apache/fop/cli/AreaTreeInputHandler.java +++ b/src/java/org/apache/fop/cli/AreaTreeInputHandler.java @@ -61,10 +61,6 @@ public class AreaTreeInputHandler extends InputHandler { public void renderTo(FOUserAgent userAgent, String outputFormat, OutputStream out) throws FOPException { FontInfo fontInfo = new FontInfo(); - FOUserAgent effUserAgent = userAgent; - if (effUserAgent == null) { - effUserAgent = new FOUserAgent(); - } AreaTreeModel treeModel = new RenderPagesModel(userAgent, outputFormat, fontInfo, out); diff --git a/src/java/org/apache/fop/cli/CommandLineOptions.java b/src/java/org/apache/fop/cli/CommandLineOptions.java index c90be81cb..efa3daa18 100644 --- a/src/java/org/apache/fop/cli/CommandLineOptions.java +++ b/src/java/org/apache/fop/cli/CommandLineOptions.java @@ -28,11 +28,13 @@ import java.util.Vector; import org.apache.fop.Version; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.FopFactory; import org.apache.fop.apps.MimeConstants; import org.apache.fop.pdf.PDFEncryptionManager; import org.apache.fop.pdf.PDFEncryptionParams; import org.apache.fop.render.awt.AWTRenderer; import org.apache.fop.render.Renderer; +import org.apache.fop.render.pdf.PDFRenderer; import org.apache.fop.render.xml.XMLRenderer; import org.apache.fop.util.CommandLineLogger; @@ -41,14 +43,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; // SAX -import org.xml.sax.XMLReader; import org.xml.sax.SAXException; -import javax.xml.parsers.SAXParserFactory; - -// avalon configuration -import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; /** * Options parses the commandline arguments @@ -92,6 +87,7 @@ public class CommandLineOptions { /* output mode */ private String outputmode = null; + private FopFactory factory = FopFactory.newInstance(); private FOUserAgent foUserAgent; private InputHandler inputHandler; @@ -130,7 +126,7 @@ public class CommandLineOptions { throws FOPException, IOException { boolean optionsParsed = true; - foUserAgent = new FOUserAgent(); + foUserAgent = factory.newFOUserAgent(); try { optionsParsed = parseOptions(args); @@ -217,7 +213,7 @@ public class CommandLineOptions { } else if (args[i].equals("-d")) { setLogOption("debug", "debug"); } else if (args[i].equals("-r")) { - foUserAgent.setStrictValidation(false); + factory.setStrictValidation(false); } else if (args[i].equals("-dpi")) { i = i + parseResolution(args, i); } else if (args[i].equals("-q") || args[i].equals("--quiet")) { @@ -571,14 +567,17 @@ public class CommandLineOptions { } private PDFEncryptionParams getPDFEncryptionParams() throws FOPException { - if (foUserAgent.getPDFEncryptionParams() == null) { + PDFEncryptionParams params = (PDFEncryptionParams)foUserAgent.getRendererOptions().get( + PDFRenderer.ENCRYPTION_PARAMS); + if (params == null) { if (!PDFEncryptionManager.checkAvailableAlgorithms()) { throw new FOPException("PDF encryption requested but it is not available." + " Please make sure MD5 and RC4 algorithms are available."); } - foUserAgent.setPDFEncryptionParams(new PDFEncryptionParams()); + params = new PDFEncryptionParams(); + foUserAgent.getRendererOptions().put(PDFRenderer.ENCRYPTION_PARAMS, params); } - return foUserAgent.getPDFEncryptionParams(); + return params; } private int parsePDFOwnerPassword(String[] args, int i) throws FOPException { @@ -726,18 +725,11 @@ public class CommandLineOptions { if (userConfigFile == null) { return; } - XMLReader parser = createParser(); - DefaultConfigurationBuilder configBuilder - = new DefaultConfigurationBuilder(parser); - Configuration userConfig = null; try { - userConfig = configBuilder.buildFromFile(userConfigFile); + factory.setUserConfig(userConfigFile); } catch (SAXException e) { throw new FOPException(e); - } catch (ConfigurationException e) { - throw new FOPException(e); } - foUserAgent.setUserConfig(userConfig); } /** @@ -978,20 +970,5 @@ public class CommandLineOptions { } } - /** - * Creates <code>XMLReader</code> object using default - * <code>SAXParserFactory</code> - * @return the created <code>XMLReader</code> - * @throws FOPException if the parser couldn't be created or configured for proper operation. - */ - private XMLReader createParser() throws FOPException { - try { - SAXParserFactory factory = SAXParserFactory.newInstance(); - factory.setNamespaceAware(true); - return factory.newSAXParser().getXMLReader(); - } catch (Exception e) { - throw new FOPException("Couldn't create XMLReader", e); - } - } } diff --git a/src/java/org/apache/fop/cli/InputHandler.java b/src/java/org/apache/fop/cli/InputHandler.java index 554f5d572..13d756ada 100644 --- a/src/java/org/apache/fop/cli/InputHandler.java +++ b/src/java/org/apache/fop/cli/InputHandler.java @@ -39,6 +39,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.Fop; +import org.apache.fop.apps.FopFactory; import org.apache.fop.render.awt.viewer.Renderable; /** @@ -85,10 +86,13 @@ public class InputHandler implements ErrorListener, Renderable { */ public void renderTo(FOUserAgent userAgent, String outputFormat, OutputStream out) throws FOPException { - - Fop fop = new Fop(outputFormat, userAgent); + + FopFactory factory = userAgent.getFactory(); + Fop fop; if (out != null) { - fop.setOutputStream(out); + fop = factory.newFop(outputFormat, userAgent, out); + } else { + fop = factory.newFop(outputFormat, userAgent); } // if base URL was not explicitly set in FOUserAgent, obtain here diff --git a/src/java/org/apache/fop/fo/ElementMappingRegistry.java b/src/java/org/apache/fop/fo/ElementMappingRegistry.java index 6cdfbb473..787d17b48 100644 --- a/src/java/org/apache/fop/fo/ElementMappingRegistry.java +++ b/src/java/org/apache/fop/fo/ElementMappingRegistry.java @@ -25,7 +25,7 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.apps.FOPException; -import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.FopFactory; import org.apache.fop.fo.ElementMapping.Maker; import org.apache.fop.util.Service; import org.w3c.dom.DOMImplementation; @@ -54,14 +54,14 @@ public class ElementMappingRegistry { /** * Main constructor. Adds all default element mapping as well as detects ElementMapping * through the Service discovery. - * @param userAgent the user agent + * @param factory the Fop Factory */ - public ElementMappingRegistry(FOUserAgent userAgent) { + public ElementMappingRegistry(FopFactory factory) { // Add standard element mappings setupDefaultMappings(); // add additional ElementMappings defined within FOUserAgent - List addlEMs = userAgent.getAdditionalElementMappings(); + List addlEMs = factory.getAdditionalElementMappings(); if (addlEMs != null) { for (int i = 0; i < addlEMs.size(); i++) { diff --git a/src/java/org/apache/fop/fo/FOTreeBuilder.java b/src/java/org/apache/fop/fo/FOTreeBuilder.java index d5d03b7b7..2711bd169 100644 --- a/src/java/org/apache/fop/fo/FOTreeBuilder.java +++ b/src/java/org/apache/fop/fo/FOTreeBuilder.java @@ -52,9 +52,7 @@ public class FOTreeBuilder extends DefaultHandler { /** The registry for ElementMapping instances */ protected ElementMappingRegistry elementMappingRegistry; - //TODO Remove the ElementMappingRegistry from here and move it to a new environmental class - //FOTreeBuilder should be a "one-use" component. - + /** * The root of the formatting object tree */ @@ -93,7 +91,7 @@ public class FOTreeBuilder extends DefaultHandler { OutputStream stream) throws FOPException { this.userAgent = foUserAgent; - + this.elementMappingRegistry = userAgent.getFactory().getElementMappingRegistry(); //This creates either an AreaTreeHandler and ultimately a Renderer, or //one of the RTF-, MIF- etc. Handlers. foEventHandler = foUserAgent.getRendererFactory().createFOEventHandler( @@ -103,8 +101,6 @@ public class FOTreeBuilder extends DefaultHandler { return new StaticPropertyList(fobj, parentPropertyList); } }); - - this.elementMappingRegistry = new ElementMappingRegistry(foUserAgent); } /** @@ -174,7 +170,8 @@ public class FOTreeBuilder extends DefaultHandler { foEventHandler.endDocument(); //Notify the image factory that this user agent has expired. - ImageFactory.getInstance().removeContext(this.userAgent); + ImageFactory imageFactory = userAgent.getFactory().getImageFactory(); + imageFactory.removeContext(this.userAgent); } /** diff --git a/src/java/org/apache/fop/fo/flow/ExternalGraphic.java b/src/java/org/apache/fop/fo/flow/ExternalGraphic.java index 35bd47360..d80cbe868 100644 --- a/src/java/org/apache/fop/fo/flow/ExternalGraphic.java +++ b/src/java/org/apache/fop/fo/flow/ExternalGraphic.java @@ -19,6 +19,7 @@ package org.apache.fop.fo.flow; import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; import org.apache.fop.fo.FONode; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; @@ -60,8 +61,9 @@ public class ExternalGraphic extends AbstractGraphics { //Additional processing: preload image url = ImageFactory.getURL(getSrc()); - ImageFactory fact = ImageFactory.getInstance(); - fopimage = fact.getImage(url, getUserAgent()); + FOUserAgent userAgent = getUserAgent(); + ImageFactory fact = userAgent.getFactory().getImageFactory(); + fopimage = fact.getImage(url, userAgent); if (fopimage == null) { getLogger().error("Image not available: " + getSrc()); } else { diff --git a/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java b/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java index 83214a5ab..54501d91c 100755 --- a/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java +++ b/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java @@ -18,6 +18,7 @@ package org.apache.fop.fo.properties; +import org.apache.fop.apps.FOUserAgent; import org.apache.fop.datatypes.ColorType; import org.apache.fop.datatypes.Length; import org.apache.fop.datatypes.PercentBaseContext; @@ -158,8 +159,9 @@ public class CommonBorderPaddingBackground implements Cloneable { //Additional processing: preload image String url = ImageFactory.getURL(backgroundImage); - ImageFactory fact = ImageFactory.getInstance(); - fopimage = fact.getImage(url, fobj.getUserAgent()); + FOUserAgent userAgent = fobj.getUserAgent(); + ImageFactory fact = userAgent.getFactory().getImageFactory(); + fopimage = fact.getImage(url, userAgent); if (fopimage == null) { fobj.getLogger().error("Background image not available: " + backgroundImage); } else { diff --git a/src/java/org/apache/fop/image/ImageFactory.java b/src/java/org/apache/fop/image/ImageFactory.java index e41ceb858..ce559b360 100644 --- a/src/java/org/apache/fop/image/ImageFactory.java +++ b/src/java/org/apache/fop/image/ImageFactory.java @@ -50,13 +50,14 @@ public final class ImageFactory { */ protected static Log log = LogFactory.getLog(FopImage.class); - private static ImageFactory factory = new ImageFactory(); - private HashMap imageMimeTypes = new HashMap(); private ImageCache cache = new ContextImageCache(true); - private ImageFactory() { + /** + * Main constructor for the ImageFactory. + */ + public ImageFactory() { /* @todo The mappings set up below of image mime types to implementing * classes should be made externally configurable */ @@ -124,15 +125,6 @@ public final class ImageFactory { } /** - * Get static image factory instance. - * - * @return the image factory instance - */ - public static ImageFactory getInstance() { - return factory; - } - - /** * Get the url string from a wrapped url. * * @param href the input wrapped url diff --git a/src/java/org/apache/fop/image/ImageLoader.java b/src/java/org/apache/fop/image/ImageLoader.java index ad22c6c2b..f26088a01 100644 --- a/src/java/org/apache/fop/image/ImageLoader.java +++ b/src/java/org/apache/fop/image/ImageLoader.java @@ -51,7 +51,8 @@ class ImageLoader { if (!valid || image != null) { return image; } - image = ImageFactory.getInstance().loadImage(url, userAgent); + ImageFactory imageFactory = userAgent.getFactory().getImageFactory(); + image = imageFactory.loadImage(url, userAgent); if (image == null) { cache.invalidateImage(url, userAgent); valid = false; diff --git a/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java index a0e198ad5..4bc66adfb 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,7 +37,6 @@ import java.util.List; import java.util.LinkedList; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.layoutmgr.inline.AlignmentContext; -import org.apache.fop.layoutmgr.inline.LeafNodeLayoutManager.AreaInfo; /** * LayoutManager for the fo:character formatting object @@ -146,7 +145,7 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager { /** @see InlineLevelLayoutManager#getWordChars(StringBuffer, Position) */ public void getWordChars(StringBuffer sbChars, Position bp) { sbChars.append - (((org.apache.fop.area.inline.Character) curArea).getChar()); + (((org.apache.fop.area.inline.TextArea) curArea).getText()); } /** @see InlineLevelLayoutManager#hyphenate(Position, HyphContext) */ diff --git a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java index 73c0de905..ef84d1c73 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java @@ -1520,11 +1520,11 @@ public class LineLayoutManager extends InlineStackingLayoutManager // on an inline or wrapper below the block level. Hyphenation hyph = Hyphenator.hyphenate(hyphenationProperties.language, - hyphenationProperties.country, - getFObj().getUserAgent().getHyphenationTreeResolver(), - sbChars.toString(), - hyphenationProperties.hyphenationRemainCharacterCount, - hyphenationProperties.hyphenationPushCharacterCount); + hyphenationProperties.country, + getFObj().getUserAgent().getFactory().getHyphenationTreeResolver(), + sbChars.toString(), + hyphenationProperties.hyphenationRemainCharacterCount, + hyphenationProperties.hyphenationPushCharacterCount); // They hyph structure contains the information we need // Now start from prev: reset to that position, ask that LM to get // a Position for the first hyphenation offset. If the offset isn't in diff --git a/src/java/org/apache/fop/render/PrintRenderer.java b/src/java/org/apache/fop/render/PrintRenderer.java index 4de65e561..873879fe1 100644 --- a/src/java/org/apache/fop/render/PrintRenderer.java +++ b/src/java/org/apache/fop/render/PrintRenderer.java @@ -48,7 +48,8 @@ public abstract class PrintRenderer extends AbstractRenderer { public void setupFontInfo(FontInfo inFontInfo) { this.fontInfo = inFontInfo; FontResolver resolver = new DefaultFontResolver(userAgent); - FontSetup.setup(fontInfo, fontList, resolver, userAgent.isBase14KerningEnabled()); + FontSetup.setup(fontInfo, fontList, resolver, + userAgent.getFactory().isBase14KerningEnabled()); } /** diff --git a/src/java/org/apache/fop/render/RendererFactory.java b/src/java/org/apache/fop/render/RendererFactory.java index c6d4f479e..4108043bf 100644 --- a/src/java/org/apache/fop/render/RendererFactory.java +++ b/src/java/org/apache/fop/render/RendererFactory.java @@ -229,7 +229,7 @@ public class RendererFactory { if (out == null && userAgent.getRendererOverride() == null && rendMaker.needsOutputStream()) { - throw new IllegalStateException( + throw new FOPException( "OutputStream has not been set"); } //Found a Renderer so we need to construct an AreaTreeHandler. diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java index 1dfc1b429..31e0a2bc4 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java +++ b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java @@ -1030,7 +1030,7 @@ public abstract class Java2DRenderer extends AbstractRenderer implements Printab int y = currentBPPosition; String url = ImageFactory.getURL(pUrl); - ImageFactory fact = ImageFactory.getInstance(); + ImageFactory fact = userAgent.getFactory().getImageFactory(); FopImage fopimage = fact.getImage(url, userAgent); if (fopimage == null) { diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index 1a2994145..68e9aa022 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -67,6 +67,7 @@ import org.apache.fop.pdf.PDFAnnotList; import org.apache.fop.pdf.PDFColor; import org.apache.fop.pdf.PDFDocument; import org.apache.fop.pdf.PDFEncryptionManager; +import org.apache.fop.pdf.PDFEncryptionParams; import org.apache.fop.pdf.PDFFilterList; import org.apache.fop.pdf.PDFInfo; import org.apache.fop.pdf.PDFLink; @@ -111,6 +112,20 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { */ public static final String MIME_TYPE = MimeConstants.MIME_PDF; + /** PDF encryption parameter: all parameters as object, datatype: PDFEncryptionParams */ + public static final String ENCRYPTION_PARAMS = "encryption-params"; + /** PDF encryption parameter: user password, datatype: String */ + public static final String USER_PASSWORD = "user-password"; + /** PDF encryption parameter: owner password, datatype: String */ + public static final String OWNER_PASSWORD = "owner-password"; + /** PDF encryption parameter: Forbids printing, datatype: Boolean or "true"/"false" */ + public static final String NO_PRINT = "noprint"; + /** PDF encryption parameter: Forbids copying content, datatype: Boolean or "true"/"false" */ + public static final String NO_COPY_CONTENT = "nocopy"; + /** PDF encryption parameter: Forbids editing content, datatype: Boolean or "true"/"false" */ + public static final String NO_EDIT_CONTENT = "noedit"; + /** PDF encryption parameter: Forbids annotations, datatype: Boolean or "true"/"false" */ + public static final String NO_ANNOTATIONS = "noannotations"; /** Rendering Options key for the PDF/A mode. */ public static final String PDF_A_MODE = "pdf-a-mode"; @@ -167,6 +182,9 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { */ protected PDFPage currentPage; + /** the (optional) encryption parameters */ + protected PDFEncryptionParams encryptionParams; + /** The current Transform */ protected AffineTransform currentBasicTransform; @@ -245,11 +263,70 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { } } + private boolean booleanValueOf(Object obj) { + if (obj instanceof Boolean) { + return ((Boolean)obj).booleanValue(); + } else if (obj instanceof String) { + return Boolean.valueOf((String)obj).booleanValue(); + } else { + throw new IllegalArgumentException("Boolean or \"true\" or \"false\" expected."); + } + } + /** * @see org.apache.fop.render.Renderer#setUserAgent(FOUserAgent) */ public void setUserAgent(FOUserAgent agent) { super.setUserAgent(agent); + PDFEncryptionParams params + = (PDFEncryptionParams)agent.getRendererOptions().get(ENCRYPTION_PARAMS); + if (params != null) { + this.encryptionParams = params; //overwrite if available + } + String pwd; + pwd = (String)agent.getRendererOptions().get(USER_PASSWORD); + if (pwd != null) { + if (encryptionParams == null) { + this.encryptionParams = new PDFEncryptionParams(); + } + this.encryptionParams.setUserPassword(pwd); + } + pwd = (String)agent.getRendererOptions().get(OWNER_PASSWORD); + if (pwd != null) { + if (encryptionParams == null) { + this.encryptionParams = new PDFEncryptionParams(); + } + this.encryptionParams.setOwnerPassword(pwd); + } + Object setting; + setting = agent.getRendererOptions().get(NO_PRINT); + if (setting != null) { + if (encryptionParams == null) { + this.encryptionParams = new PDFEncryptionParams(); + } + this.encryptionParams.setAllowPrint(!booleanValueOf(setting)); + } + setting = agent.getRendererOptions().get(NO_COPY_CONTENT); + if (setting != null) { + if (encryptionParams == null) { + this.encryptionParams = new PDFEncryptionParams(); + } + this.encryptionParams.setAllowCopyContent(!booleanValueOf(setting)); + } + setting = agent.getRendererOptions().get(NO_EDIT_CONTENT); + if (setting != null) { + if (encryptionParams == null) { + this.encryptionParams = new PDFEncryptionParams(); + } + this.encryptionParams.setAllowEditContent(!booleanValueOf(setting)); + } + setting = agent.getRendererOptions().get(NO_ANNOTATIONS); + if (setting != null) { + if (encryptionParams == null) { + this.encryptionParams = new PDFEncryptionParams(); + } + this.encryptionParams.setAllowEditAnnotations(!booleanValueOf(setting)); + } String s = (String)agent.getRendererOptions().get(PDF_A_MODE); if (s != null) { this.pdfAMode = PDFAMode.valueOf(s); @@ -276,8 +353,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { this.pdfDoc.outputHeader(stream); //Setup encryption if necessary - PDFEncryptionManager.setupPDFEncryption( - userAgent.getPDFEncryptionParams(), this.pdfDoc); + PDFEncryptionManager.setupPDFEncryption(encryptionParams, this.pdfDoc); } /** @@ -1213,7 +1289,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { } url = ImageFactory.getURL(url); - ImageFactory fact = ImageFactory.getInstance(); + ImageFactory fact = userAgent.getFactory().getImageFactory(); FopImage fopimage = fact.getImage(url, userAgent); if (fopimage == null) { return; diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java index 52e7c7bcb..dab429a13 100644 --- a/src/java/org/apache/fop/render/ps/PSRenderer.java +++ b/src/java/org/apache/fop/render/ps/PSRenderer.java @@ -279,7 +279,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda protected void drawImage(String url, Rectangle2D pos) { endTextObject(); url = ImageFactory.getURL(url); - ImageFactory fact = ImageFactory.getInstance(); + ImageFactory fact = userAgent.getFactory().getImageFactory(); FopImage fopimage = fact.getImage(url, userAgent); if (fopimage == null) { return; diff --git a/src/java/org/apache/fop/render/rtf/RTFHandler.java b/src/java/org/apache/fop/render/rtf/RTFHandler.java index 6c99ab4fe..ed33cf9df 100644 --- a/src/java/org/apache/fop/render/rtf/RTFHandler.java +++ b/src/java/org/apache/fop/render/rtf/RTFHandler.java @@ -1121,8 +1121,9 @@ public class RTFHandler extends FOEventHandler { String url = eg.getURL(); //set image data - ImageFactory fact = ImageFactory.getInstance(); - FopImage fopimage = fact.getImage(url, eg.getUserAgent()); + FOUserAgent userAgent = eg.getUserAgent(); + ImageFactory fact = userAgent.getFactory().getImageFactory(); + FopImage fopimage = fact.getImage(url, userAgent); if (fopimage == null) { log.error("Image could not be found: " + url); return; diff --git a/src/java/org/apache/fop/servlet/FopPrintServlet.java b/src/java/org/apache/fop/servlet/FopPrintServlet.java index 8ac980ccd..6b3268572 100644 --- a/src/java/org/apache/fop/servlet/FopPrintServlet.java +++ b/src/java/org/apache/fop/servlet/FopPrintServlet.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,25 +18,18 @@ package org.apache.fop.servlet; -import java.io.File; -import java.io.InputStream; +import java.io.IOException; import java.io.PrintWriter; -// JAXP -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerException; import javax.xml.transform.Result; import javax.xml.transform.Source; -import javax.xml.transform.URIResolver; import javax.xml.transform.sax.SAXResult; -import javax.xml.transform.stream.StreamSource; -// XML -import org.apache.commons.logging.impl.SimpleLog; +import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.Fop; import org.apache.fop.apps.MimeConstants; @@ -58,164 +51,49 @@ import org.apache.fop.apps.MimeConstants; * Example URL: http://servername/fop/servlet/FopPrintServlet?fo=readme.fo * <br/> * Example URL: http://servername/fop/servlet/FopPrintServlet?xml=data.xml&xsl=format.xsl - * - * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a> + * <br/> + * <b>Note:</b> This servlet is derived from FopServlet. Most methods are inherited from the + * superclass. Only the differences to the base class are necessary. + * + * @author <a href="mailto:fop-dev@xmlgraphics.apache.org">Apache FOP Development Team</a> * @version $Id$ - * (todo) Doesn't work since there's no AWTRenderer at the moment. Revisit when - * available. - * (todo) Ev. add caching mechanism for Templates objects */ -public class FopPrintServlet extends HttpServlet { - - /** Name of the parameter used for the XSL-FO file */ - protected static final String FO_REQUEST_PARAM = "fo"; - /** Name of the parameter used for the XML file */ - protected static final String XML_REQUEST_PARAM = "xml"; - /** Name of the parameter used for the XSLT file */ - protected static final String XSLT_REQUEST_PARAM = "xslt"; - - /** Logger to give to FOP */ - protected SimpleLog log = null; - - /** The TransformerFactory to use to create Transformer instances */ - protected TransformerFactory transFactory = null; - /** URIResolver for use by this servlet */ - protected URIResolver uriResolver; - - /** - * @see javax.servlet.GenericServlet#init() - */ - public void init() throws ServletException { - this.log = new SimpleLog("FOP/Print Servlet"); - log.setLevel(SimpleLog.LOG_LEVEL_WARN); - this.uriResolver = new ServletContextURIResolver(getServletContext()); - this.transFactory = TransformerFactory.newInstance(); - this.transFactory.setURIResolver(this.uriResolver); - } - - /** - * @see javax.servlet.http.HttpServlet#doGet(HttpServletRequest, HttpServletResponse) - */ - public void doGet(HttpServletRequest request, - HttpServletResponse response) throws ServletException { - if (log == null) { - log = new SimpleLog("FOP/Print Servlet"); - log.setLevel(SimpleLog.LOG_LEVEL_WARN); - } - - try { - String foParam = request.getParameter(FO_REQUEST_PARAM); - String xmlParam = request.getParameter(XML_REQUEST_PARAM); - String xsltParam = request.getParameter(XSLT_REQUEST_PARAM); - - if (foParam != null) { - InputStream file = new java.io.FileInputStream(foParam); - renderFO(file, response); - } else if ((xmlParam != null) && (xsltParam != null)) { - renderXML(new File(xmlParam), new File(xsltParam), response); - } else { - response.setContentType("text/html"); - - PrintWriter out = response.getWriter(); - out.println("<html><title>Error</title>\n" - + "<body><h1>FopServlet Error</h1>\n" - + "<h3>No 'fo' or 'xml/xsl' " - + "request param given.</h3></body>\n</html>"); - } - } catch (ServletException ex) { - throw ex; - } catch (Exception ex) { - throw new ServletException(ex); - } - } - - /** - * Renders an FO inputsource to the default printer. - * @param foFile The XSL-FO file - * @param response Response to write to - * @throws ServletException In case of a problem - */ - public void renderFO(InputStream foFile, - HttpServletResponse response) throws ServletException { - try { - Fop fop = new Fop(MimeConstants.MIME_FOP_PRINT, getFOUserAgent()); - - // Setup JAXP - TransformerFactory factory = TransformerFactory.newInstance(); - Transformer transformer = factory.newTransformer(); //identity transformer - transformer.setURIResolver(this.uriResolver); - - // Setup input for XSLT transformation - Source src = new StreamSource(foFile); - - // 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); - - reportOK (response); - } catch (Exception ex) { - throw new ServletException(ex); - } - } +public class FopPrintServlet extends FopServlet { /** - * Renders an FO generated using an XML and a stylesheet to the default printer. - * @param xmlfile XML file object - * @param xsltfile XSLT stylesheet - * @param response HTTP response object - * @throws ServletException In case of a problem + * @see org.apache.fop.servlet.FopServlet#render(javax.xml.transform.Source, + * javax.xml.transform.Transformer, javax.servlet.http.HttpServletResponse) */ - public void renderXML(File xmlfile, File xsltfile, - HttpServletResponse response) throws ServletException { - try { - Fop fop = new Fop(MimeConstants.MIME_FOP_PRINT, getFOUserAgent()); + protected void render(Source src, Transformer transformer, HttpServletResponse response) + throws FOPException, TransformerException, IOException { - // Setup XSLT - TransformerFactory factory = TransformerFactory.newInstance(); - Transformer transformer = factory.newTransformer(new StreamSource(xsltfile)); - transformer.setURIResolver(this.uriResolver); - - // Setup input for XSLT transformation - Source src = new StreamSource(xmlfile); + FOUserAgent foUserAgent = getFOUserAgent(); - // 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); - - reportOK (response); - } catch (Exception ex) { - throw new ServletException(ex); - } + //Setup FOP + Fop fop = fopFactory.newFop(MimeConstants.MIME_FOP_PRINT, foUserAgent); + + //Make sure the XSL transformation's result is piped through to FOP + Result res = new SAXResult(fop.getDefaultHandler()); + + //Start the transformation and rendering process + transformer.transform(src, res); + + //Return the result + reportOK(response); } // private helper, tell (browser) user that file printed - private void reportOK(HttpServletResponse response) - throws ServletException { + private void reportOK(HttpServletResponse response) throws IOException { String sMsg = "<html><title>Success</title>\n" + "<body><h1>FopPrintServlet: </h1>" - + "<h3>The requested data was printed</h3></body></html>"; + + "<h3>The requested data was printed to the default printer.</h3></body></html>"; response.setContentType("text/html"); response.setContentLength(sMsg.length()); - try { - PrintWriter out = response.getWriter(); - out.println(sMsg); - out.flush(); - } catch (Exception ex) { - throw new ServletException(ex); - } - } - - /** @return a new FOUserAgent for FOP */ - protected FOUserAgent getFOUserAgent() { - FOUserAgent userAgent = new FOUserAgent(); - userAgent.setURIResolver(this.uriResolver); - return userAgent; + PrintWriter out = response.getWriter(); + out.println(sMsg); + out.flush(); } } diff --git a/src/java/org/apache/fop/servlet/FopServlet.java b/src/java/org/apache/fop/servlet/FopServlet.java index cd1d23014..241c99319 100644 --- a/src/java/org/apache/fop/servlet/FopServlet.java +++ b/src/java/org/apache/fop/servlet/FopServlet.java @@ -19,6 +19,7 @@ package org.apache.fop.servlet; import java.io.File; +import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; @@ -37,10 +38,10 @@ import javax.xml.transform.stream.StreamSource; import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.commons.logging.impl.SimpleLog; -//FOP import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.Fop; import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FopFactory; import org.apache.fop.apps.MimeConstants; /** @@ -63,7 +64,7 @@ import org.apache.fop.apps.MimeConstants; * For this to work with Internet Explorer, you might need to append "&ext=.pdf" * to the URL. * - * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a> + * @author <a href="mailto:fop-dev@xmlgraphics.apache.org">Apache FOP Development Team</a> * @version $Id$ * (todo) Ev. add caching mechanism for Templates objects */ @@ -78,8 +79,10 @@ public class FopServlet extends HttpServlet { /** Logger to give to FOP */ protected SimpleLog log = null; - /** The TransformerFactory to use to create Transformer instances */ + /** The TransformerFactory used to create Transformer instances */ protected TransformerFactory transFactory = null; + /** The FopFactory used to create Fop instances */ + protected FopFactory fopFactory = null; /** URIResolver for use by this servlet */ protected URIResolver uriResolver; @@ -92,6 +95,18 @@ public class FopServlet extends HttpServlet { this.uriResolver = new ServletContextURIResolver(getServletContext()); this.transFactory = TransformerFactory.newInstance(); this.transFactory.setURIResolver(this.uriResolver); + //Configure FopFactory as desired + this.fopFactory = FopFactory.newInstance(); + this.fopFactory.setURIResolver(this.uriResolver); + configureFopFactory(); + } + + /** + * This method is called right after the FopFactory is instantiated and can be overridden + * by subclasses to perform additional configuration. + */ + protected void configureFopFactory() { + //Subclass and override this method to perform additional configuration } /** @@ -106,26 +121,17 @@ public class FopServlet extends HttpServlet { String xsltParam = request.getParameter(XSLT_REQUEST_PARAM); //Analyze parameters and decide with method to use - byte[] content = null; if (foParam != null) { - content = renderFO(foParam); + renderFO(foParam, response); } else if ((xmlParam != null) && (xsltParam != null)) { - content = renderXML(xmlParam, xsltParam); + renderXML(xmlParam, xsltParam, response); } else { + response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html><head><title>Error</title></head>\n" + "<body><h1>FopServlet Error</h1><h3>No 'fo' " + "request param given.</body></html>"); } - - if (content != null) { - //Send the result back to the client - response.setContentType("application/pdf"); - response.setContentLength(content.length); - response.getOutputStream().write(content); - response.getOutputStream().flush(); - } - } catch (Exception ex) { throw new ServletException(ex); } @@ -140,18 +146,27 @@ public class FopServlet extends HttpServlet { return new StreamSource(new File(param)); } + private void sendPDF(byte[] content, HttpServletResponse response) throws IOException { + //Send the result back to the client + response.setContentType("application/pdf"); + response.setContentLength(content.length); + response.getOutputStream().write(content); + response.getOutputStream().flush(); + } + /** * Renders an XSL-FO file into a PDF file. The PDF is written to a byte * array that is returned as the method's result. * @param fo the XSL-FO file - * @return byte[] the rendered PDF file + * @param response HTTP response object * @throws FOPException If an error occurs during the rendering of the * XSL-FO * @throws TransformerException If an error occurs while parsing the input * file + * @throws IOException In case of an I/O problem */ - protected byte[] renderFO(String fo) - throws FOPException, TransformerException { + protected void renderFO(String fo, HttpServletResponse response) + throws FOPException, TransformerException, IOException { //Setup source Source foSrc = convertString2Source(fo); @@ -161,7 +176,7 @@ public class FopServlet extends HttpServlet { transformer.setURIResolver(this.uriResolver); //Start transformation and rendering process - return render(foSrc, transformer); + render(foSrc, transformer, response); } /** @@ -170,14 +185,15 @@ public class FopServlet extends HttpServlet { * that is returned as the method's result. * @param xml the XML file * @param xslt the XSLT file - * @return byte[] the rendered PDF file + * @param response HTTP response object * @throws FOPException If an error occurs during the rendering of the * XSL-FO * @throws TransformerException If an error occurs during XSL * transformation + * @throws IOException In case of an I/O problem */ - protected byte[] renderXML(String xml, String xslt) - throws FOPException, TransformerException { + protected void renderXML(String xml, String xslt, HttpServletResponse response) + throws FOPException, TransformerException, IOException { //Setup sources Source xmlSrc = convertString2Source(xml); @@ -188,7 +204,7 @@ public class FopServlet extends HttpServlet { transformer.setURIResolver(this.uriResolver); //Start transformation and rendering process - return render(xmlSrc, transformer); + render(xmlSrc, transformer, response); } /** @@ -199,21 +215,23 @@ public class FopServlet extends HttpServlet { * returned as the method's result. * @param src Input XML or XSL-FO * @param transformer Transformer to use for optional transformation - * @return byte[] the rendered PDF file + * @param response HTTP response object * @throws FOPException If an error occurs during the rendering of the * XSL-FO * @throws TransformerException If an error occurs during XSL * transformation + * @throws IOException In case of an I/O problem */ - protected byte[] render(Source src, Transformer transformer) - throws FOPException, TransformerException { + protected void render(Source src, Transformer transformer, HttpServletResponse response) + throws FOPException, TransformerException, IOException { - //Setup FOP - Fop fop = new Fop(MimeConstants.MIME_PDF, getFOUserAgent()); + FOUserAgent foUserAgent = getFOUserAgent(); //Setup output ByteArrayOutputStream out = new ByteArrayOutputStream(); - fop.setOutputStream(out); + + //Setup FOP + Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out); //Make sure the XSL transformation's result is piped through to FOP Result res = new SAXResult(fop.getDefaultHandler()); @@ -222,13 +240,13 @@ public class FopServlet extends HttpServlet { transformer.transform(src, res); //Return the result - return out.toByteArray(); + sendPDF(out.toByteArray(), response); } /** @return a new FOUserAgent for FOP */ protected FOUserAgent getFOUserAgent() { - FOUserAgent userAgent = new FOUserAgent(); - userAgent.setURIResolver(this.uriResolver); + FOUserAgent userAgent = fopFactory.newFOUserAgent(); + //Configure foUserAgent as desired return userAgent; } diff --git a/src/java/org/apache/fop/tools/TestConverter.java b/src/java/org/apache/fop/tools/TestConverter.java index 6d4800a86..ff0da6eec 100644 --- a/src/java/org/apache/fop/tools/TestConverter.java +++ b/src/java/org/apache/fop/tools/TestConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; -import org.apache.fop.apps.Fop; +import org.apache.fop.apps.FopFactory; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; import org.apache.fop.cli.InputHandler; @@ -48,6 +48,9 @@ import org.apache.commons.logging.impl.SimpleLog; */ public class TestConverter { + // configure fopFactory as desired + private FopFactory fopFactory = FopFactory.newInstance(); + private boolean failOnly = false; private String outputFormat = MimeConstants.MIME_FOP_AREA_TREE; private File destdir; @@ -284,7 +287,7 @@ public class TestConverter { + xsl), null); } - FOUserAgent userAgent = new FOUserAgent(); + FOUserAgent userAgent = fopFactory.newFOUserAgent(); userAgent.setBaseURL(baseURL); userAgent.getRendererOptions().put("fineDetail", new Boolean(false)); diff --git a/src/java/org/apache/fop/tools/anttasks/Fop.java b/src/java/org/apache/fop/tools/anttasks/Fop.java index 1096feb5a..09caa848a 100644 --- a/src/java/org/apache/fop/tools/anttasks/Fop.java +++ b/src/java/org/apache/fop/tools/anttasks/Fop.java @@ -37,6 +37,7 @@ import java.util.List; // FOP import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.FopFactory; import org.apache.fop.apps.MimeConstants; import org.apache.fop.cli.InputHandler; @@ -306,6 +307,9 @@ public class Fop extends Task { class FOPTaskStarter { + // configure fopFactory as desired + private FopFactory fopFactory = FopFactory.newInstance(); + private Fop task; private String baseURL = null; @@ -555,11 +559,8 @@ class FOPTaskStarter { boolean success = false; try { - FOUserAgent userAgent = new FOUserAgent(); + FOUserAgent userAgent = fopFactory.newFOUserAgent(); userAgent.setBaseURL(this.baseURL); - if (userConfig != null) { - userAgent.setUserConfig(userConfig); - } inputHandler.renderTo(userAgent, outputFormat, out); success = true; } catch (Exception ex) { diff --git a/src/java/org/apache/fop/util/ContentHandlerFactoryRegistry.java b/src/java/org/apache/fop/util/ContentHandlerFactoryRegistry.java index 68e215b45..5fd68fd2b 100644 --- a/src/java/org/apache/fop/util/ContentHandlerFactoryRegistry.java +++ b/src/java/org/apache/fop/util/ContentHandlerFactoryRegistry.java @@ -36,22 +36,10 @@ public class ContentHandlerFactoryRegistry { /** the logger */ private static Log log = LogFactory.getLog(ContentHandlerFactoryRegistry.class); - private static ContentHandlerFactoryRegistry instance; - /** Map from namespace URIs to ContentHandlerFactories */ private Map factories = new java.util.HashMap(); /** - * @return a singleton instance of the ContentHandlerFactoryRegistry. - */ - public static ContentHandlerFactoryRegistry getInstance() { - if (instance == null) { - instance = new ContentHandlerFactoryRegistry(); - } - return instance; - } - - /** * Default constructor. */ public ContentHandlerFactoryRegistry() { |