/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import org.xml.sax.SAXException;

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.xmlgraphics.image.loader.spi.ImageImplRegistry;
import org.apache.xmlgraphics.image.loader.util.Penalty;
import org.apache.xmlgraphics.io.ResourceResolver;

import org.apache.fop.apps.io.InternalResourceResolver;
import org.apache.fop.apps.io.ResourceResolverFactory;
import org.apache.fop.fonts.FontManagerConfigurator;
import org.apache.fop.hyphenation.HyphenationTreeCache;
import org.apache.fop.hyphenation.Hyphenator;
import org.apache.fop.util.LogUtil;

Parses the FOP configuration file and returns a FopFactoryBuilder which builds a FopFactory.
/** * Parses the FOP configuration file and returns a {@link FopFactoryBuilder} which builds a * {@link FopFactory}. */
public class FopConfParser { private static final String PREFER_RENDERER = "prefer-renderer"; private final Log log = LogFactory.getLog(FopConfParser.class); private final FopFactoryBuilder fopFactoryBuilder;
Constructor that takes the FOP conf in the form of an InputStream. A default base URI must be given as a fall-back mechanism for URI resolution.
Params:
  • fopConfStream – the fop conf input stream
  • enviro – the profile of the FOP deployment environment
Throws:
  • SAXException – if a SAX error was thrown parsing the FOP conf
  • IOException – if an I/O error is thrown while parsing the FOP conf
/** * Constructor that takes the FOP conf in the form of an {@link InputStream}. A default base URI * must be given as a fall-back mechanism for URI resolution. * * @param fopConfStream the fop conf input stream * @param enviro the profile of the FOP deployment environment * @throws SAXException if a SAX error was thrown parsing the FOP conf * @throws IOException if an I/O error is thrown while parsing the FOP conf */
public FopConfParser(InputStream fopConfStream, EnvironmentProfile enviro) throws SAXException, IOException { this(fopConfStream, enviro.getDefaultBaseURI(), enviro); }
Constructor that takes the FOP conf in the form of an InputStream. A default base URI must be given as a fall-back mechanism for URI resolution.
Params:
  • fopConfStream – the fop conf input stream
  • defaultBaseURI – the default base URI
  • resourceResolver – the URI resolver
Throws:
  • SAXException – if a SAX error was thrown parsing the FOP conf
  • IOException – if an I/O error is thrown while parsing the FOP conf
/** * Constructor that takes the FOP conf in the form of an {@link InputStream}. A default base URI * must be given as a fall-back mechanism for URI resolution. * * @param fopConfStream the fop conf input stream * @param defaultBaseURI the default base URI * @param resourceResolver the URI resolver * @throws SAXException if a SAX error was thrown parsing the FOP conf * @throws IOException if an I/O error is thrown while parsing the FOP conf */
public FopConfParser(InputStream fopConfStream, URI defaultBaseURI, ResourceResolver resourceResolver) throws SAXException, IOException { this(fopConfStream, defaultBaseURI, EnvironmentalProfileFactory.createDefault(defaultBaseURI, resourceResolver)); }
Constructor that takes the FOP conf in the form of an InputStream. A default base URI must be given as a fall-back mechanism for URI resolution. The default URI resolvers is used.
Params:
  • fopConfStream – the fop conf input stream
  • defaultBaseURI – the default base URI
Throws:
  • SAXException – if a SAX error was thrown parsing the FOP conf
  • IOException – if an I/O error is thrown while parsing the FOP conf
/** * Constructor that takes the FOP conf in the form of an {@link InputStream}. A default base URI * must be given as a fall-back mechanism for URI resolution. The default URI resolvers is used. * * @param fopConfStream the fop conf input stream * @param defaultBaseURI the default base URI * @throws SAXException if a SAX error was thrown parsing the FOP conf * @throws IOException if an I/O error is thrown while parsing the FOP conf */
public FopConfParser(InputStream fopConfStream, URI defaultBaseURI) throws SAXException, IOException { this(fopConfStream, defaultBaseURI, ResourceResolverFactory.createDefaultResourceResolver()); }
Constructor that takes the FOP conf and uses the default URI resolver.
Params:
  • fopConfFile – the FOP conf file
Throws:
  • SAXException – if a SAX error was thrown parsing the FOP conf
  • IOException – if an I/O error is thrown while parsing the FOP conf
/** * Constructor that takes the FOP conf and uses the default URI resolver. * * @param fopConfFile the FOP conf file * @throws SAXException if a SAX error was thrown parsing the FOP conf * @throws IOException if an I/O error is thrown while parsing the FOP conf */
public FopConfParser(File fopConfFile) throws SAXException, IOException { this(fopConfFile, ResourceResolverFactory.createDefaultResourceResolver()); }
Constructor that takes the FOP conf and a default base URI and uses the default URI resolver.
Params:
  • fopConfFile – the FOP conf file
  • defaultBaseURI – the default base URI
Throws:
  • SAXException – if a SAX error was thrown parsing the FOP conf
  • IOException – if an I/O error is thrown while parsing the FOP conf
/** * Constructor that takes the FOP conf and a default base URI and uses the default URI resolver. * * @param fopConfFile the FOP conf file * @param defaultBaseURI the default base URI * @throws SAXException if a SAX error was thrown parsing the FOP conf * @throws IOException if an I/O error is thrown while parsing the FOP conf */
public FopConfParser(File fopConfFile, URI defaultBaseURI) throws SAXException, IOException { this(new FileInputStream(fopConfFile), fopConfFile.toURI(), EnvironmentalProfileFactory.createDefault(defaultBaseURI, ResourceResolverFactory.createDefaultResourceResolver())); }
Constructor that parses the FOP conf and uses the URI resolver given.
Params:
  • fopConfFile – the FOP conf file
  • resourceResolver – the URI resolver
Throws:
  • SAXException – if a SAX error was thrown parsing the FOP conf
  • IOException – if an I/O error is thrown while parsing the FOP conf
/** * Constructor that parses the FOP conf and uses the URI resolver given. * * @param fopConfFile the FOP conf file * @param resourceResolver the URI resolver * @throws SAXException if a SAX error was thrown parsing the FOP conf * @throws IOException if an I/O error is thrown while parsing the FOP conf */
public FopConfParser(File fopConfFile, ResourceResolver resourceResolver) throws SAXException, IOException { this(new FileInputStream(fopConfFile), fopConfFile.toURI(), resourceResolver); } public FopConfParser(InputStream fopConfStream, URI baseURI, EnvironmentProfile enviro) throws SAXException, IOException { DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder(); Configuration cfg; try { cfg = cfgBuilder.build(fopConfStream); } catch (ConfigurationException e) { throw new FOPException(e); } // The default base URI is taken from the directory in which the fopConf resides fopFactoryBuilder = new FopFactoryBuilder(enviro).setConfiguration(cfg); configure(baseURI, enviro.getResourceResolver(), cfg); } private void configure(final URI baseURI, final ResourceResolver resourceResolver, Configuration cfg) throws FOPException { if (log.isDebugEnabled()) { log.debug("Initializing FopFactory Configuration"); } // strict fo validation if (cfg.getChild("strict-validation", false) != null) { try { boolean strict = cfg.getChild("strict-validation").getValueAsBoolean(); fopFactoryBuilder.setStrictFOValidation(strict); } catch (ConfigurationException e) { LogUtil.handleException(log, e, false); } } boolean strict = false; if (cfg.getChild("strict-configuration", false) != null) { try { strict = cfg.getChild("strict-configuration").getValueAsBoolean(); fopFactoryBuilder.setStrictUserConfigValidation(strict); } catch (ConfigurationException e) { LogUtil.handleException(log, e, false); } } if (cfg.getChild("accessibility", false) != null) { try { fopFactoryBuilder.setAccessibility(cfg.getChild("accessibility").getValueAsBoolean()); } catch (ConfigurationException e) { LogUtil.handleException(log, e, false); } } // base definitions for relative path resolution if (cfg.getChild("base", false) != null) { try { URI confUri = InternalResourceResolver.getBaseURI(cfg.getChild("base").getValue(null)); fopFactoryBuilder.setBaseURI(baseURI.resolve(confUri)); } catch (URISyntaxException use) { LogUtil.handleException(log, use, strict); } } // renderer options if (cfg.getChild("source-resolution", false) != null) { float srcRes = cfg.getChild("source-resolution").getValueAsFloat( FopFactoryConfig.DEFAULT_SOURCE_RESOLUTION); fopFactoryBuilder.setSourceResolution(srcRes); if (log.isDebugEnabled()) { log.debug("source-resolution set to: " + srcRes + "dpi"); } } if (cfg.getChild("target-resolution", false) != null) { float targetRes = cfg.getChild("target-resolution").getValueAsFloat( FopFactoryConfig.DEFAULT_TARGET_RESOLUTION); fopFactoryBuilder.setTargetResolution(targetRes); if (log.isDebugEnabled()) { log.debug("target-resolution set to: " + targetRes + "dpi"); } } if (cfg.getChild("break-indent-inheritance", false) != null) { try { fopFactoryBuilder.setBreakIndentInheritanceOnReferenceAreaBoundary( cfg.getChild("break-indent-inheritance").getValueAsBoolean()); } catch (ConfigurationException e) { LogUtil.handleException(log, e, strict); } } Configuration pageConfig = cfg.getChild("default-page-settings"); if (pageConfig.getAttribute("height", null) != null) { String pageHeight = pageConfig.getAttribute("height", FopFactoryConfig.DEFAULT_PAGE_HEIGHT); fopFactoryBuilder.setPageHeight(pageHeight); if (log.isInfoEnabled()) { log.info("Default page-height set to: " + pageHeight); } } if (pageConfig.getAttribute("width", null) != null) { String pageWidth = pageConfig.getAttribute("width", FopFactoryConfig.DEFAULT_PAGE_WIDTH); fopFactoryBuilder.setPageWidth(pageWidth); if (log.isInfoEnabled()) { log.info("Default page-width set to: " + pageWidth); } } if (cfg.getChild("complex-scripts") != null) { Configuration csConfig = cfg.getChild("complex-scripts"); fopFactoryBuilder.setComplexScriptFeatures(!csConfig.getAttributeAsBoolean("disabled", false)); } setHyphenationBase(cfg, resourceResolver, baseURI, fopFactoryBuilder); setHyphPatNames(cfg, fopFactoryBuilder, strict); // prefer Renderer over IFDocumentHandler if (cfg.getChild(PREFER_RENDERER, false) != null) { try { fopFactoryBuilder.setPreferRenderer( cfg.getChild(PREFER_RENDERER).getValueAsBoolean()); } catch (ConfigurationException e) { LogUtil.handleException(log, e, strict); } } // configure font manager new FontManagerConfigurator(cfg, baseURI, fopFactoryBuilder.getBaseURI(), resourceResolver) .configure(fopFactoryBuilder.getFontManager(), strict); // configure image loader framework configureImageLoading(cfg.getChild("image-loading", false), strict); } private void setHyphenationBase(Configuration cfg, ResourceResolver resourceResolver, URI baseURI, FopFactoryBuilder fopFactoryBuilder) throws FOPException { if (cfg.getChild("hyphenation-base", false) != null) { try { URI fontBase = InternalResourceResolver.getBaseURI(cfg.getChild("hyphenation-base").getValue(null)); fopFactoryBuilder.setHyphenBaseResourceResolver( ResourceResolverFactory.createInternalResourceResolver( baseURI.resolve(fontBase), resourceResolver)); } catch (URISyntaxException use) { LogUtil.handleException(log, use, true); } } else { fopFactoryBuilder.setHyphenBaseResourceResolver( ResourceResolverFactory.createInternalResourceResolver( fopFactoryBuilder.getBaseURI(), resourceResolver)); } } private void setHyphPatNames(Configuration cfg, FopFactoryBuilder builder, boolean strict) throws FOPException { Configuration[] hyphPatConfig = cfg.getChildren("hyphenation-pattern"); if (hyphPatConfig.length != 0) { Map<String, String> hyphPatNames = new HashMap<String, String>(); for (Configuration aHyphPatConfig : hyphPatConfig) { String lang; String country; String filename; StringBuffer error = new StringBuffer(); String location = aHyphPatConfig.getLocation(); lang = aHyphPatConfig.getAttribute("lang", null); if (lang == null) { addError("The lang attribute of a hyphenation-pattern configuration" + " element must exist (" + location + ")", error); } else if (!lang.matches("[a-zA-Z]{2}")) { addError("The lang attribute of a hyphenation-pattern configuration" + " element must consist of exactly two letters (" + location + ")", error); } lang = lang.toLowerCase(Locale.getDefault()); country = aHyphPatConfig.getAttribute("country", null); if ("".equals(country)) { country = null; } if (country != null) { if (!country.matches("[a-zA-Z]{2}")) { addError("The country attribute of a hyphenation-pattern configuration" + " element must consist of exactly two letters (" + location + ")", error); } country = country.toUpperCase(Locale.getDefault()); } filename = aHyphPatConfig.getValue(null); if (filename == null) { addError("The value of a hyphenation-pattern configuration" + " element may not be empty (" + location + ")", error); } if (error.length() != 0) { LogUtil.handleError(log, error.toString(), strict); continue; } String llccKey = HyphenationTreeCache.constructLlccKey(lang, country); String extension = aHyphPatConfig.getAttribute("extension", null); if ("xml".equals(extension)) { hyphPatNames.put(llccKey, filename + Hyphenator.XMLTYPE); } else if ("hyp".equals(extension)) { hyphPatNames.put(llccKey, filename + Hyphenator.HYPTYPE); } else { hyphPatNames.put(llccKey, filename); } if (log.isDebugEnabled()) { log.debug("Using hyphenation pattern filename " + filename + " for lang=\"" + lang + "\"" + (country != null ? ", country=\"" + country + "\"" : "")); } } builder.setHyphPatNames(hyphPatNames); } } private static void addError(String message, StringBuffer error) { if (error.length() != 0) { error.append(". "); } error.append(message); } private void configureImageLoading(Configuration parent, boolean strict) throws FOPException { if (parent == null) { return; } ImageImplRegistry registry = fopFactoryBuilder.getImageManager().getRegistry(); Configuration[] penalties = parent.getChildren("penalty"); try { for (Configuration penaltyCfg : penalties) { String className = penaltyCfg.getAttribute("class"); String value = penaltyCfg.getAttribute("value"); Penalty p = null; if (value.toUpperCase(Locale.getDefault()).startsWith("INF")) { p = Penalty.INFINITE_PENALTY; } else { try { p = Penalty.toPenalty(Integer.parseInt(value)); } catch (NumberFormatException nfe) { LogUtil.handleException(log, nfe, strict); } } if (p != null) { registry.setAdditionalPenalty(className, p); } } } catch (ConfigurationException e) { LogUtil.handleException(log, e, strict); } }
Returns the FopFactoryBuilder.
Returns:the object for configuring the FopFactory
/** * Returns the {@link FopFactoryBuilder}. * * @return the object for configuring the {@link FopFactory} */
public FopFactoryBuilder getFopFactoryBuilder() { return fopFactoryBuilder; } }