]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Stricter user config file validation.
authorVincent Hennebert <vhennebert@apache.org>
Wed, 14 Feb 2007 14:24:36 +0000 (14:24 +0000)
committerVincent Hennebert <vhennebert@apache.org>
Wed, 14 Feb 2007 14:24:36 +0000 (14:24 +0000)
Add a configuration parameter (strict-configuration), enabled by default, which makes FOP throw an exception instead of logging an error when a problem occurs.
Invalid resource paths should be catched now. Fixes bug #40120.
Submitted by: Adrian Cumiskey (fop-dev AT cumiskey DOT com)

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@507539 13f79535-47bb-0310-9956-ffa450edef68

31 files changed:
build.xml
src/documentation/content/xdocs/trunk/configuration.xml
src/foschema/fop-configuration.xsd
src/java/org/apache/fop/apps/FOURIResolver.java
src/java/org/apache/fop/apps/FOUserAgent.java
src/java/org/apache/fop/apps/FopFactory.java
src/java/org/apache/fop/fonts/FontSetup.java
src/java/org/apache/fop/render/AbstractRenderer.java
src/java/org/apache/fop/render/PrintRenderer.java
src/java/org/apache/fop/render/RendererFactory.java
src/java/org/apache/fop/render/pdf/PDFRenderer.java
src/java/org/apache/fop/render/ps/PSRenderer.java
src/java/org/apache/fop/render/xml/XMLRenderer.java
status.xml
test/config/test_embedurl_bad.xconf [new file with mode: 0644]
test/config/test_embedurl_malformed.xconf [new file with mode: 0644]
test/config/test_fontattributes_missing.xconf [new file with mode: 0644]
test/config/test_fontbase_bad.xconf [new file with mode: 0644]
test/config/test_fonttripletattribute_missing.xconf [new file with mode: 0644]
test/config/test_metricsurl_bad.xconf [new file with mode: 0644]
test/config/test_metricsurl_malformed.xconf [new file with mode: 0644]
test/java/org/apache/fop/config/BaseUserConfigTestCase.java [new file with mode: 0644]
test/java/org/apache/fop/config/EmbedUrlBadTestCase.java [new file with mode: 0644]
test/java/org/apache/fop/config/EmbedUrlMalformedTestCase.java [new file with mode: 0644]
test/java/org/apache/fop/config/FontAttributesMissingTestCase.java [new file with mode: 0644]
test/java/org/apache/fop/config/FontBaseBadTestCase.java [new file with mode: 0644]
test/java/org/apache/fop/config/FontTripletAttributeMissingTestCase.java [new file with mode: 0644]
test/java/org/apache/fop/config/MetricsUrlBadTestCase.java [new file with mode: 0644]
test/java/org/apache/fop/config/MetricsUrlMalformedTestCase.java [new file with mode: 0644]
test/java/org/apache/fop/config/UserConfigTestSuite.java [new file with mode: 0644]
test/java/org/apache/fop/render/pdf/BasePDFTestCase.java

index 60d6537ae3007d73ea971ec0f468595fbe2cbd26..cbb4276b671392fce71fff47fa1c4fe25812224e 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -776,6 +776,7 @@ list of possible build targets.
       <formatter type="xml" usefile="true"/>
       <classpath>
         <pathelement location="${build.dir}/test-classes"/>
+        <path refid="libs-build-classpath"/>
         <fileset dir="build">
           <include name="fop-transcoder-allinone.jar"/>
         </fileset>
@@ -789,6 +790,24 @@ list of possible build targets.
     </junit>
   </target>
 
+  <target name="junit-userconfig" depends="junit-compile" if="junit.present" description="Runs FOP's user config JUnit tests">
+    <echo message="Running user config tests"/>
+    <junit dir="${basedir}" haltonfailure="${junit.haltonfailure}" fork="${junit.fork}" errorproperty="fop.junit.error" failureproperty="fop.junit.failure">
+      <sysproperty key="basedir" value="${basedir}"/>
+      <sysproperty key="jawa.awt.headless" value="true"/>
+      <sysproperty key="fop.layoutengine.disabled" value="${layoutengine.disabled}"/>
+      <sysproperty key="fop.layoutengine.testset" value="standard"/>
+      <formatter type="brief" usefile="false"/>
+      <formatter type="plain" usefile="true"/>
+      <formatter type="xml" usefile="true"/>
+      <classpath>
+        <pathelement location="${build.dir}/test-classes"/>
+        <path refid="libs-run-classpath"/>
+      </classpath>
+      <test name="org.apache.fop.config.UserConfigTestSuite" todir="${junit.reports.dir}" outfile="TEST-userconfig"/>
+    </junit>
+  </target>
+
   <target name="junit-basic" depends="junit-compile" description="Runs FOP's JUnit basic tests" if="junit.present">
     <echo message="Running basic functionality tests for fop.jar"/>
     <junit dir="${basedir}" haltonfailure="${junit.haltonfailure}" fork="${junit.fork}" errorproperty="fop.junit.error" failureproperty="fop.junit.failure">
@@ -924,7 +943,7 @@ list of possible build targets.
     </junit>
   </target>
 
-  <target name="junit" depends="junit-basic, junit-transcoder, junit-text-linebreak, junit-layout, junit-fotree, junit-intermediate-format" description="Runs all of FOP's JUnit tests" if="junit.present">
+  <target name="junit" depends="junit-userconfig, junit-basic, junit-transcoder, junit-text-linebreak, junit-layout, junit-fotree, junit-intermediate-format" description="Runs all of FOP's JUnit tests" if="junit.present">
     <fail>
       <condition>
         <or>
index c40a64de5f713b55c9ad37ad54e0cfc80edd1b01..7032379cafcdc1c22bbc470110b530fb17c6038d 100644 (file)
       <tr>
         <th>Element</th>
         <th>Data Type (for the value)</th>
+        <th>Description</th>
         <th>Default Value</th>
       </tr>
       <tr>
         <td>base</td>
         <td>URL or directory</td>
         <td>Specifies the base URL based on which relative URL will be resolved.</td>
+        <td>current directory</td>
       </tr>
       <tr>
         <td>font-base</td>
         <td>URL or directory</td>
         <td>Specifies the base URL based on which relative font URLs will be resolved.
-        If not specified defaults to the base URL above.
         </td>
+       <td>base URL/directory (above)</td>
       </tr>
       <tr>
         <td>hyphenation-base</td>
@@ -85,6 +87,7 @@
         files will be resolved. If not specified, support for user-supplied hyphenation 
         patterns remains disabled.
         </td>
+        <td>disabled</td>
       </tr>
       <tr>
         <td>source-resolution</td>
@@ -93,6 +96,7 @@
           Resolution in dpi (dots per inch) which is used internally to determine the pixel 
           size for SVG images and bitmap images without resolution information.
         </td>
+        <td>72 dpi</td>
       </tr>
       <tr>
         <td>target-resolution</td>
           images generated by bitmap renderers (such as the TIFF renderer) and by bitmaps
           generated by Apache Batik for filter effects and such.
         </td>
+        <td>72 dpi</td>
+      </tr>
+      <tr>
+        <td>strict-configuration</td>
+        <td>Boolean (true, false)</td>
+        <td>
+         Setting this option to 'true' will cause FOP to strictly verify the contents of the
+         FOP configuration file to ensure that defined resources (such as fonts and base
+         URLs/directories) are valid and available to FOP.  Any errors found will cause FOP to
+         immediately raise an exception.</td>
+        <td>false</td>
       </tr>
       <tr>
         <td>strict-validation</td>
           Setting this option to 'false' causes FOP to be more forgiving about XSL-FO validity, 
           for example, you're allowed to specify a border on a region-body which is supported 
           by some FO implementations but is non-standard. Note that such a border would 
-          currently have no effect in Apache FOP.</td>
+         currently have no effect in Apache FOP.</td>
+        <td>true</td>
       </tr>
       <tr>
         <td>break-indent-inheritance</td>
           the desired behaviour and because the behaviour among the commercial implementations
           varies. The default for this option (i.e. false) is to behave exactly like the 
           specification describes.</td>
+        <td>false</td>
       </tr>
       <tr>
         <td>default-page-settings</td>
           Specifies the default width and height of a page if "auto" is specified 
           for either or both values. Use "height" and "width" attributes on the 
           default-page-settings element to specify the two values.</td>
+        <td>"height" 11 inches, "width" 8.26 inches</td>
       </tr>
       <tr>
         <td>renderers</td>
         <td>(see text below)</td>
         <td>Contains the configuration for each renderer. See below.</td>
+       <td>N/A</td>
       </tr>
     </table>
     <p>
     <source><![CDATA[
 <fop version="1.0">
 
+  <!-- Strict user configuration -->
+  <strict-configuration>true</strict-configuration>
+
+  <!-- Strict FO validation -->
+  <strict-validation>true</strict-validation>
+
   <!-- Base URL for resolving relative URLs -->
   <base>./</base>
 
index c5a12d27f0c427d249f2f77d5ecacd7b28f632e6..ad959f9473065071d6ff96ade09ad840bfffa7ba 100644 (file)
@@ -38,6 +38,7 @@
           type="xsd:positiveInteger" minOccurs="0">
         </xsd:element>
         <xsd:element name="strict-validation" type="xsd:boolean" minOccurs="0"></xsd:element>
+        <xsd:element name="strict-configuration" type="xsd:boolean" minOccurs="0"></xsd:element>
         <xsd:element name="break-indent-inheritance"
           type="xsd:boolean" minOccurs="0">
         </xsd:element>
index 925cd62f822122a30d0c35c9304e45b56792c6ea..db0cae75e2658d8da2d04b7f7b4c57db45ad87fd 100644 (file)
@@ -84,7 +84,7 @@ public class FOURIResolver
             try {
                 absoluteURL = f.toURL();
             } catch (MalformedURLException mfue) {
-                log.error("Could not convert filename to URL: " + mfue.getMessage(), mfue); 
+                log.error("Could not convert filename to URL: " + mfue.getMessage()); 
             }
         } else {
             URL baseURL = toBaseURL(base);
@@ -98,7 +98,7 @@ public class FOURIResolver
                         // the href contains only a path then file: is assumed
                         absoluteURL = new URL("file:" + href);
                     } catch (MalformedURLException mfue) {
-                        log.error("Error with URL '" + href + "': " + mue.getMessage(), mue);
+                        log.error("Error with URL '" + href + "': " + mue.getMessage());
                         return null;
                     }
                 }
@@ -137,7 +137,7 @@ public class FOURIResolver
                     }
                     absoluteURL = new URL(baseURL, href);
                 } catch (MalformedURLException mfue) {
-                    log.error("Error with URL '" + href + "': " + mfue.getMessage(), mfue);
+                    log.error("Error with URL '" + href + "': " + mfue.getMessage());
                     return null;
                 }
             }
@@ -155,7 +155,7 @@ public class FOURIResolver
             //Note: This is on "debug" level since the caller is supposed to handle this
             log.debug("File not found: " + effURL);
         } catch (java.io.IOException ioe) {
-            log.error("Error with opening URL '" + href + "': " + ioe.getMessage(), ioe);
+            log.error("Error with opening URL '" + href + "': " + ioe.getMessage());
         }
         return null;
     }
index 63a3859ac67220fb1c6678abcdf449c85560fcae..f15ddcc31dffac61af9d8a71c004934d6ac8cb1d 100644 (file)
@@ -27,10 +27,6 @@ import javax.xml.transform.Source;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.URIResolver;
 
-// avalon configuration
-import org.apache.avalon.framework.configuration.Configuration;
-import org.apache.avalon.framework.configuration.ConfigurationException;
-
 // commons logging
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -67,7 +63,7 @@ import org.apache.fop.render.pdf.PDFRenderer;
 public class FOUserAgent {
 
     /** Defines the default target resolution (72dpi) for FOP */
-    public static final float DEFAULT_TARGET_RESOLUTION = 72.0f; //dpi
+    public static final float DEFAULT_TARGET_RESOLUTION = FopFactory.DEFAULT_TARGET_RESOLUTION;
 
     private static Log log = LogFactory.getLog("FOP");
 
@@ -109,11 +105,12 @@ public class FOUserAgent {
     
     /**
      * Default constructor
+     * @throws FOPException 
      * @see org.apache.fop.apps.FopFactory
      * @deprecated Provided for compatibility only. Please use the methods from 
      *             FopFactory to construct FOUserAgent instances!
      */
-    public FOUserAgent() {
+    public FOUserAgent() throws FOPException {
         this(FopFactory.newInstance());
     }
     
@@ -128,9 +125,8 @@ public class FOUserAgent {
             throw new NullPointerException("The factory parameter must not be null");
         }
         this.factory = factory;
-        if (factory.getUserConfig() != null) {
-            configure(factory.getUserConfig());
-        }
+        setBaseURL(factory.getBaseURL());
+        setTargetResolution(factory.getTargetResolution());
     }
     
     /** @return the associated FopFactory instance */
@@ -278,55 +274,7 @@ public class FOUserAgent {
     public Map getRendererOptions() {
         return rendererOptions;
     }
-
-    /**
-     * Configures the FOUserAgent through the factory's configuration.
-     * @param cfg Avalon Configuration Object
-     * @see org.apache.avalon.framework.configuration.Configurable
-     */
-    protected void configure(Configuration cfg) {
-        setBaseURL(FopFactory.getBaseURLfromConfig(cfg, "base"));
-        if (cfg.getChild("target-resolution", false) != null) {
-            this.targetResolution 
-                = cfg.getChild("target-resolution").getValueAsFloat(
-                        DEFAULT_TARGET_RESOLUTION);
-            log.info("Target resolution set to: " + targetResolution 
-                    + "dpi (px2mm=" + getTargetPixelUnitToMillimeter() + ")");
-        }
-    }
     
-    /**
-     * Returns the configuration subtree for a specific renderer.
-     * @param mimeType MIME type of the renderer
-     * @return the requested configuration subtree, null if there's no configuration
-     */
-    public Configuration getUserRendererConfig(String mimeType) {
-
-        Configuration cfg = getFactory().getUserConfig();
-        if (cfg == null || mimeType == null) {
-            return null;
-        }
-
-        Configuration userRendererConfig = null;
-
-        Configuration[] cfgs
-            = cfg.getChild("renderers").getChildren("renderer");
-        for (int i = 0; i < cfgs.length; ++i) {
-            Configuration child = cfgs[i];
-            try {
-                if (child.getAttribute("mime").equals(mimeType)) {
-                    userRendererConfig = child;
-                    break;
-                }
-            } catch (ConfigurationException e) {
-                // silently pass over configurations without mime type
-            }
-        }
-        log.debug((userRendererConfig == null ? "No u" : "U")
-                  + "ser configuration found for MIME type " + mimeType);
-        return userRendererConfig;
-    }
-
     /**
      * Sets the base URL.
      * @param baseURL base URL
@@ -460,8 +408,20 @@ public class FOUserAgent {
      * bitmap images generated by filter effects in Apache Batik.
      * @param dpi resolution in dpi
      */
-    public void setTargetResolution(int dpi) {
+    public void setTargetResolution(float dpi) {
         this.targetResolution = dpi;
+        log.info("target-resolution set to: " + targetResolution 
+                + "dpi (px2mm=" + getTargetPixelUnitToMillimeter() + ")");
+    }
+
+    /**
+     * 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.
+     * @param dpi resolution in dpi
+     */
+    public void setTargetResolution(int dpi) {
+        setTargetResolution((float)dpi);
     }
     
     // ---------------------------------------------- environment-level stuff
@@ -470,7 +430,7 @@ public class FOUserAgent {
     /** @return the font base URL */
     public String getFontBaseURL() {
         String fontBaseURL = getFactory().getFontBaseURL(); 
-        return fontBaseURL != null ? fontBaseURL : this.baseURL;
+        return fontBaseURL != null ? fontBaseURL : getBaseURL();
     }
 
     /**
@@ -541,6 +501,5 @@ public class FOUserAgent {
     public XMLHandlerRegistry getXMLHandlerRegistry() {
         return getFactory().getXMLHandlerRegistry();
     }
-
 }
 
index 363d680590a621ec486f9596e8753eafc781fe56..f7a3bd251348606ec05dbde016d53886cc4edc1e 100644 (file)
@@ -55,18 +55,33 @@ import org.apache.fop.render.XMLHandlerRegistry;
 import org.apache.fop.util.ContentHandlerFactoryRegistry;
 
 /**
- * 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.
+ * 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 target resolution (72dpi) for FOP */
+    public static final float DEFAULT_TARGET_RESOLUTION = 72.0f; //dpi
 
     /** 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";
+    
+    /** Defines if FOP should use strict validation for FO and user config */
+    private static final boolean DEFAULT_STRICT_FO_VALIDATION = true;
+
+    /** Defines if FOP should validate the user config strictly */
+    private static final boolean DEFAULT_STRICT_USERCONFIG_VALIDATION = true;
+    
+    /** Defines if FOP should use an alternative rule to determine text indents */
+    private static final boolean DEFAULT_BREAK_INDENT_INHERITANCE = false;
 
     /** logger instance */
     private static Log log = LogFactory.getLog(FopFactory.class);
@@ -86,6 +101,7 @@ public class FopFactory {
     
     /** Our default resolver if none is set */
     private URIResolver foURIResolver = new FOURIResolver();
+    
     /** A user settable URI Resolver */
     private URIResolver uriResolver = null;
 
@@ -97,27 +113,50 @@ public class FopFactory {
     /** user configuration */
     private Configuration userConfig = null;
 
-    /** The base URL for all font URL resolutions */
+    /**
+     *  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;
-    
+
+    /** The base URL for all hyphen URL resolutions. */
+    private String hyphenBaseURL;
+
     /**
      * 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.   
+     * ability for FOP to halt on all content model violations if desired.
      */ 
-    private boolean strictValidation = true;
+    private boolean strictFOValidation = DEFAULT_STRICT_FO_VALIDATION;
 
+    /**
+     * FOP will validate the contents of the user configuration strictly
+     * (e.g. base-urls and font urls/paths).
+     */
+    private boolean strictUserConfigValidation = DEFAULT_STRICT_USERCONFIG_VALIDATION;
+    
     /** 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;
+
+    /** Target resolution in dpi */
+    private float targetResolution = DEFAULT_TARGET_RESOLUTION;
+
+    /** Page height */
     private String pageHeight = DEFAULT_PAGE_HEIGHT;
+    
+    /** Page width */
     private String pageWidth = DEFAULT_PAGE_WIDTH;
 
     /** @see #setBreakIndentInheritanceOnReferenceAreaBoundary(boolean) */
-    private boolean breakIndentInheritanceOnReferenceAreaBoundary = false;
+    private boolean breakIndentInheritanceOnReferenceAreaBoundary
+        = DEFAULT_BREAK_INDENT_INHERITANCE;
 
     /** Optional overriding LayoutManagerMaker */
     private LayoutManagerMaker lmMakerOverride = null;
@@ -149,6 +188,7 @@ public class FopFactory {
      * 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
+     * @throws FOPException 
      */
     public FOUserAgent newFOUserAgent() {
         FOUserAgent userAgent = new FOUserAgent(this);
@@ -295,6 +335,22 @@ public class FopFactory {
         return this.lmMakerOverride;
     }
 
+    /**
+     * Sets the base URL.
+     * @param baseURL base URL
+     */
+    void setBaseURL(String baseURL) {
+        this.baseURL = baseURL;
+    }
+
+    /**
+     * Returns the base URL.
+     * @return the base URL
+     */
+    public String getBaseURL() {
+        return this.baseURL;
+    }
+
     /**
      * Sets the font base URL.
      * @param fontBaseURL font base URL
@@ -308,6 +364,26 @@ public class FopFactory {
         return this.fontBaseURL;
     }
 
+    /** @return the hyphen base URL */
+    public String getHyphenBaseURL() {
+        return hyphenBaseURL;
+    }
+
+    /**
+     * Sets the hyphen base URL.
+     * @param hyphenBaseURL hythen base URL
+     */
+    public void setHyphenBaseURL(final String hyphenBaseURL) {
+        if (hyphenBaseURL != null) {
+            this.hyphResolver = new HyphenationTreeResolver() {
+                public Source resolve(String href) {
+                    return resolveURI(href, hyphenBaseURL);
+                }
+            };
+        }
+        this.hyphenBaseURL = hyphenBaseURL;
+    }
+
     /**
      * 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. 
@@ -336,7 +412,7 @@ public class FopFactory {
      * @param validateStrictly true to turn on strict validation
      */
     public void setStrictValidation(boolean validateStrictly) {
-        this.strictValidation = validateStrictly;
+        this.strictFOValidation = validateStrictly;
     }
 
     /**
@@ -344,7 +420,7 @@ public class FopFactory {
      * @return true of strict validation turned on, false otherwise
      */
     public boolean validateStrictly() {
-        return strictValidation;
+        return strictFOValidation;
     }
 
     /**
@@ -399,14 +475,49 @@ public class FopFactory {
     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) {
+    public void setSourceResolution(float dpi) {
         this.sourceResolution = dpi;
+        log.info("source-resolution set to: " + sourceResolution 
+                + "dpi (px2mm=" + getSourcePixelUnitToMillimeter() + ")");
+    }
+
+    /** @return the resolution for resolution-dependant output */
+    public float getTargetResolution() {
+        return this.targetResolution;
+    }
+
+    /**
+     * Returns the conversion factor from pixel units to millimeters. This
+     * depends on the desired target resolution.
+     * @return float conversion factor
+     * @see #getTargetResolution()
+     */
+    public float getTargetPixelUnitToMillimeter() {
+        return 25.4f / 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 setTargetResolution(float dpi) {
+        this.targetResolution = dpi;
+    }
+
+    /**
+     * 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) {
+        setSourceResolution((float)dpi);
     }
     
     /**
@@ -427,6 +538,7 @@ public class FopFactory {
      */
     public void setPageHeight(String pageHeight) {
         this.pageHeight = pageHeight;
+        log.info("Default page-height set to: " + pageHeight);
     }
     
     /**
@@ -447,6 +559,7 @@ public class FopFactory {
      */
     public void setPageWidth(String pageWidth) {
         this.pageWidth = pageWidth;
+        log.info("Default page-width set to: " + pageWidth);
     }
     
     /**
@@ -491,14 +604,12 @@ public class FopFactory {
      * @throws IOException if an I/O error occurs
      * @throws SAXException if a parsing error occurs
      */
-    public void setUserConfig(File userConfigFile)
-                throws SAXException, IOException {
+    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());
+        } catch (ConfigurationException e) {
+            throw new FOPException(e);
         }
     }
     
@@ -508,28 +619,26 @@ public class FopFactory {
      * @throws IOException if an I/O error occurs
      * @throws SAXException if a parsing error occurs
      */
-    public void setUserConfig(String uri)
-                throws SAXException, IOException {
+    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());
+        } catch (ConfigurationException e) {
+            throw new FOPException(e);
         }
     }
     
     /**
      * Set the user configuration.
      * @param userConfig configuration
+     * @throws FOPException if a configuration problem occurs 
      */
-    public void setUserConfig(Configuration userConfig) {
+    public void setUserConfig(Configuration userConfig) throws FOPException {
         this.userConfig = userConfig;
         try {
-            initUserConfig();
-        } catch (ConfigurationException cfge) {
-            log.error("Error initializing factory configuration: "
-                    + cfge.getMessage());
+            configure(userConfig);
+        } catch (ConfigurationException e) {            
+            throw new FOPException(e);
         }
     }
 
@@ -540,47 +649,105 @@ public class FopFactory {
     public Configuration getUserConfig() {
         return userConfig;
     }
-    
+
+    /**
+     * Returns the configuration subtree for a specific renderer.
+     * @param mimeType MIME type of the renderer
+     * @return the requested configuration subtree, null if there's no configuration
+     */
+    public Configuration getUserRendererConfig(String mimeType) {
+        if (userConfig == null || mimeType == null) {
+            return null;
+        }
+        
+        Configuration userRendererConfig = null;
+
+        Configuration[] cfgs
+            = userConfig.getChild("renderers").getChildren("renderer");
+        for (int i = 0; i < cfgs.length; ++i) {
+            Configuration child = cfgs[i];
+            try {
+                if (child.getAttribute("mime").equals(mimeType)) {
+                    userRendererConfig = child;
+                    break;
+                }
+            } catch (ConfigurationException e) {
+                // silently pass over configurations without mime type
+            }
+        }
+        log.debug((userRendererConfig == null ? "No u" : "U")
+                  + "ser configuration found for MIME type " + mimeType);
+        return userRendererConfig;
+    }
+
     /**
      * 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
+     * Configures the FopFactory.
+     * @param cfg Avalon Configuration Object
+     * @see org.apache.avalon.framework.configuration.Configurable
      */
-    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);
+    public void configure(Configuration cfg) throws ConfigurationException {        
+        log.info("Initializing FopFactory Configuration");        
+        
+        if (cfg.getChild("strict-configuration", false) != null) {
+            this.strictUserConfigValidation
+                    = cfg.getChild("strict-configuration").getValueAsBoolean();
+        }
+        if (cfg.getChild("strict-validation", false) != null) {
+            this.strictFOValidation = cfg.getChild("strict-validation").getValueAsBoolean();
+        }
+        if (cfg.getChild("base", false) != null) {
+            try {
+                setBaseURL(getBaseURLfromConfig(cfg, "base"));
+            } catch (ConfigurationException e) {
+                if (strictUserConfigValidation) {
+                    throw e;
                 }
-            };
+                log.error(e.getMessage());
+            }
         }
-        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 (cfg.getChild("font-base", false) != null) {
+            try {
+                setFontBaseURL(getBaseURLfromConfig(cfg, "font-base"));
+            } catch (ConfigurationException e) {
+                if (strictUserConfigValidation) {
+                    throw e;
+                }
+                log.error(e.getMessage());
+            }
         }
-        if (userConfig.getChild("strict-validation", false) != null) {
-            this.strictValidation = userConfig.getChild("strict-validation").getValueAsBoolean();
+        if (cfg.getChild("hyphenation-base", false) != null) {
+            try {
+                setHyphenBaseURL(getBaseURLfromConfig(cfg, "hyphenation-base"));
+            } catch (ConfigurationException e) {
+                if (strictUserConfigValidation) {
+                    throw e;
+                }
+                log.error(e.getMessage());
+            }
+        }
+        if (cfg.getChild("source-resolution", false) != null) {
+            setSourceResolution(
+                    cfg.getChild("source-resolution").getValueAsFloat(DEFAULT_SOURCE_RESOLUTION));
         }
-        if (userConfig.getChild("break-indent-inheritance", false) != null) {
-            this.breakIndentInheritanceOnReferenceAreaBoundary 
-                = userConfig.getChild("break-indent-inheritance").getValueAsBoolean();
+        if (cfg.getChild("target-resolution", false) != null) {
+            setTargetResolution(
+                    cfg.getChild("target-resolution").getValueAsFloat(DEFAULT_TARGET_RESOLUTION));
         }
-        Configuration pageConfig = userConfig.getChild("default-page-settings");
+        if (cfg.getChild("break-indent-inheritance", false) != null) {
+            setBreakIndentInheritanceOnReferenceAreaBoundary(
+                    cfg.getChild("break-indent-inheritance").getValueAsBoolean());
+        }        
+        Configuration pageConfig = cfg.getChild("default-page-settings");
         if (pageConfig.getAttribute("height", null) != null) {
-            setPageHeight(pageConfig.getAttribute("height"));
-            log.info("Default page-height set to: " + pageHeight);
+            setPageHeight(pageConfig.getAttribute("height", DEFAULT_PAGE_HEIGHT));
         }
         if (pageConfig.getAttribute("width", null) != null) {
-            setPageWidth(pageConfig.getAttribute("width"));
-            log.info("Default page-width set to: " + pageWidth);
+            setPageWidth(pageConfig.getAttribute("width", DEFAULT_PAGE_WIDTH));
         }
     }
 
@@ -589,26 +756,53 @@ public class FopFactory {
      * @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) {
+     * @throws ConfigurationException 
+     */    
+    public static String getBaseURLfromConfig(Configuration cfg, String name)
+    throws ConfigurationException {
         if (cfg.getChild(name, false) != null) {
             try {
-                String cfgBaseDir = cfg.getChild(name).getValue(null);
-                if (cfgBaseDir != null) {
-                    File dir = new File(cfgBaseDir);
+                String cfgBasePath = cfg.getChild(name).getValue(null);
+                if (cfgBasePath != null) {
+                    // Is the path a dirname?
+                    File dir = new File(cfgBasePath);
+//                    if (!dir.exists()) {
+//                        throw new ConfigurationException("Base URL '" + name
+//                                + "' references non-existent resource '"
+//                                + cfgBasePath + "'");
+//                    } else if (dir.isDirectory()) {
                     if (dir.isDirectory()) {
-                        cfgBaseDir = dir.toURL().toExternalForm(); 
+                        // Yes, convert it into a URL
+                        cfgBasePath = dir.toURL().toExternalForm(); 
                     }
+                    // Otherwise, this is already a URL
                 }
-                log.info(name + " set to: " + cfgBaseDir);
-                return cfgBaseDir;
+                log.info(name + " set to: " + cfgBasePath);
+                return cfgBasePath;
             } catch (MalformedURLException mue) {
-                log.error("Base URL in user config is malformed!");
+                throw new ConfigurationException("Base URL '" + name
+                        + "' in user config is malformed!");
             }
         }
         return null;
     }
 
+    /**
+     * Is the user configuration to be validated?
+     * @param strictUserConfigValidation strict user config validation
+     */
+    public void setStrictUserConfigValidation(boolean strictUserConfigValidation) {
+        this.strictUserConfigValidation = strictUserConfigValidation;
+    }
+
+    /**
+     * Is the user configuration to be validated?
+     * @return if the user configuration should be validated
+     */
+    public boolean validateUserConfigStrictly() {
+        return this.strictUserConfigValidation;
+    }
+
     //------------------------------------------- URI resolution
 
     /**
@@ -700,5 +894,4 @@ public class FopFactory {
         }
         return colorSpace;
     }
-    
 }
index 3362ce334147347da08181e93a9f6b09105b6529..bd3e81d4f1321a08b9d94bddd963c9a88ab1a07c 100644 (file)
@@ -34,6 +34,7 @@ import org.apache.fop.fonts.base14.CourierOblique;
 import org.apache.fop.fonts.base14.CourierBoldOblique;
 import org.apache.fop.fonts.base14.Symbol;
 import org.apache.fop.fonts.base14.ZapfDingbats;
+import org.apache.fop.render.PrintRenderer;
 
 // commons logging
 import org.apache.commons.logging.Log;
@@ -247,46 +248,130 @@ public class FontSetup {
             
         };
     }
+   
     /**
      * Builds a list of EmbedFontInfo objects for use with the setup() method.
+     * 
      * @param cfg Configuration object
+     * @param renderer calling Renderer object
      * @return List the newly created list of fonts
      * @throws ConfigurationException if something's wrong with the config data
      */
-    public static List buildFontListFromConfiguration(Configuration cfg)
+    public static List buildFontListFromConfiguration(Configuration cfg, PrintRenderer renderer)
             throws ConfigurationException {
         List fontList = new java.util.ArrayList();
-        Configuration[] font = cfg.getChild("fonts").getChildren("font");
-        for (int i = 0; i < font.length; i++) {
-            Configuration[] triple = font[i].getChildren("font-triplet");
-            List tripleList = new java.util.ArrayList();
-            for (int j = 0; j < triple.length; j++) {
-                int weight = FontUtil.parseCSS2FontWeight(triple[j].getAttribute("weight"));
-                tripleList.add(FontInfo.createFontKey(triple[j].getAttribute("name"),
-                                               triple[j].getAttribute("style"),
-                                               weight));
-            }
-
-            EmbedFontInfo efi;
-            efi = new EmbedFontInfo(font[i].getAttribute("metrics-url", null),
-                                    font[i].getAttributeAsBoolean("kerning", false),
-                                    tripleList, font[i].getAttribute("embed-url", null));
-
-            if (log.isDebugEnabled()) {
-                log.debug("Adding font " + efi.getEmbedFile()
-                          + ", metric file " + efi.getMetricsFile());
-                for (int j = 0; j < tripleList.size(); ++j) {
-                    FontTriplet triplet = (FontTriplet) tripleList.get(j);
-                    log.debug("Font triplet "
-                              + triplet.getName() + ", "
-                              + triplet.getStyle() + ", "
-                              + triplet.getWeight());
+               
+        FontResolver fontResolver = renderer.getFontResolver();
+        if (fontResolver == null) {
+            //Ensure that we have minimal font resolution capabilities
+            fontResolver = FontSetup.createMinimalFontResolver();
+        }
+       
+        boolean strict
+            = renderer.getUserAgent().getFactory().validateUserConfigStrictly();
+        
+        Configuration[] fonts = cfg.getChildren("fonts");
+        for (int f = 0; f < fonts.length; f++) {
+                
+            Configuration[] font = fonts[f].getChildren("font");
+            for (int i = 0; i < font.length; i++) {
+    
+                String metricsUrl = font[i].getAttribute("metrics-url", null);
+                String embedUrl = font[i].getAttribute("embed-url", null);
+    
+                if (metricsUrl == null && embedUrl == null) {
+                    if (strict) {
+                        throw new ConfigurationException(
+                                "Font configuration without metric-url or embed-url");
+                    }
+                    log.error("Font configuration without metric-url or embed-url");
+                    continue;
+                }
+                
+                if (metricsUrl != null && fontResolver.resolve(metricsUrl) == null) {
+                    if (strict) {
+                        throw new ConfigurationException("Failed to resolve font metric-url '"
+                            + metricsUrl + "'");                    
+                    }
+                    log.error("Failed to resolve font metric-url '" + metricsUrl + "'");
+                    continue;
+                }
+                
+                if (embedUrl != null && fontResolver.resolve(embedUrl) == null) {
+                    if (strict) {
+                        throw new ConfigurationException("Failed to resolve font with embed-url '"
+                                + embedUrl + "'");
+                    }
+                    log.error("Failed to resolve font with embed-url '" + embedUrl + "'");
+                    continue;
+                }
+            
+                boolean useKerning = font[i].getAttributeAsBoolean("kerning", false);
+    
+                Configuration[] triple = font[i].getChildren("font-triplet");
+                List tripleList = new java.util.ArrayList();
+                for (int j = 0; j < triple.length; j++) {
+                    String name = triple[j].getAttribute("name");
+                    if (name == null) {
+                        if (strict) {
+                            throw new ConfigurationException("font-triplet without name");
+                        }
+                        log.error("font-triplet without name");
+                        continue;
+                    }
+                    
+                    String weightStr = triple[j].getAttribute("weight");
+                    if (weightStr == null) {
+                        if (strict) {
+                            throw new ConfigurationException("font-triplet without weight");
+                        }
+                        log.error("font-triplet without weight");
+                        continue;
+                    }
+                    int weight = FontUtil.parseCSS2FontWeight(weightStr);
+    
+                    String style = triple[j].getAttribute("style");
+                    if (style == null) {
+                        if (strict) {
+                            throw new ConfigurationException("font-triplet without style");
+                        }
+                        log.error("font-triplet without style");
+                        continue;
+                    }
+                    
+                    tripleList.add(FontInfo.createFontKey(name,
+                            style, weight));
+                }
+    
+                EmbedFontInfo configFontInfo = new EmbedFontInfo(metricsUrl, 
+                        useKerning, tripleList, embedUrl);
+                
+                if (log.isDebugEnabled()) {
+                    log.debug("Adding font " + configFontInfo.getEmbedFile()
+                            + ", metric file " + configFontInfo.getMetricsFile());
+                    for (int j = 0; j < tripleList.size(); ++j) {
+                        FontTriplet triplet = (FontTriplet) tripleList.get(j);
+                        log.debug("Font triplet "
+                                    + triplet.getName() + ", "
+                                    + triplet.getStyle() + ", "
+                                    + triplet.getWeight());
+                    }
                 }
+                fontList.add(configFontInfo);
             }
-
-            fontList.add(efi);
         }
         return fontList;
+    }    
+
+    /**
+     * Builds a list of EmbedFontInfo objects for use with the setup() method.
+     * 
+     * @param cfg Configuration object
+     * @return List the newly created list of fonts
+     * @throws ConfigurationException if something's wrong with the config data
+     */
+    public static List buildFontListFromConfiguration(Configuration cfg)
+    throws ConfigurationException {
+        return buildFontListFromConfiguration(cfg, null);
     }
 }
-
index 562666bdcae922323b398031636a062bd5d60f57..91cfe7bfa2ab484e5b7b51255aafb2b68cf998ab 100644 (file)
@@ -88,7 +88,7 @@ public abstract class AbstractRenderer
     /**
      * user agent
      */
-    protected FOUserAgent userAgent;
+    protected FOUserAgent userAgent = null;
 
     /**
      * block progression position
@@ -135,6 +135,13 @@ public abstract class AbstractRenderer
         userAgent = agent;
     }
 
+    /**
+     *  @see org.apache.fop.render.Renderer#getUserAgent()
+     */
+    public FOUserAgent getUserAgent() {
+        return userAgent;
+    }
+
     /** @see org.apache.fop.render.Renderer#startRenderer(OutputStream) */
     public void startRenderer(OutputStream outputStream)
         throws IOException { }
@@ -845,7 +852,7 @@ public abstract class AbstractRenderer
         if (handler != null) {
             try {
                 //Optional XML handler configuration
-                Configuration cfg = userAgent.getUserRendererConfig(getMimeType());
+                Configuration cfg = userAgent.getFactory().getUserRendererConfig(getMimeType());
                 if (cfg != null) {
                     cfg = getHandlerConfig(cfg, namespace);
                     if (cfg != null) {
index ddb335564f8832ab96b0add0edcceba9c91668d6..6a3cdf2c68d773cd559c9ff7213c1b2e3bcf82fa 100644 (file)
@@ -41,9 +41,12 @@ public abstract class PrintRenderer extends AbstractRenderer {
     /** Font configuration */
     protected FontInfo fontInfo;
 
+    /** Font resolver */
+    protected FontResolver fontResolver = null;
+
     /** list of fonts */
     protected List fontList = null;
-
+    
     /**
      * Set up the font info
      *
@@ -51,8 +54,7 @@ public abstract class PrintRenderer extends AbstractRenderer {
      */
     public void setupFontInfo(FontInfo inFontInfo) {
         this.fontInfo = inFontInfo;
-        FontResolver resolver = new DefaultFontResolver(userAgent);
-        FontSetup.setup(fontInfo, fontList, resolver, 
+        FontSetup.setup(fontInfo, fontList, fontResolver, 
                 userAgent.getFactory().isBase14KerningEnabled());
     }
 
@@ -147,5 +149,16 @@ public abstract class PrintRenderer extends AbstractRenderer {
         
         renderXML(context, doc, ns);
     }
-    
+
+    /**
+     * Get FontResolver
+     *
+     * @return FontResolver
+     */
+    public FontResolver getFontResolver() {
+        if (this.fontResolver == null) {
+            this.fontResolver = new DefaultFontResolver(super.userAgent);
+        }
+        return this.fontResolver;
+    }
 }
index 8c35ec65a9e8d348bb96748df0b650b6b155d1c3..4d3f3a12cb8e758d7630701313262e10309fa1db 100644 (file)
@@ -189,7 +189,7 @@ public class RendererFactory {
             Configuration userRendererConfig = null;
             if (mimeType != null) {
                 userRendererConfig
-                    = userAgent.getUserRendererConfig(mimeType);
+                    = userAgent.getFactory().getUserRendererConfig(mimeType);
             }
             if (userRendererConfig != null) {
                 try {
index 966aef2e53d2009a1a511b27402dc25b9d133af6..481ce844cf282df4c308f53adda6f31c0a8a7f45 100644 (file)
@@ -243,7 +243,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
         this.filterMap = PDFFilterList.buildFilterMapFromConfiguration(cfg);
 
         //Font configuration
-        List cfgFonts = FontSetup.buildFontListFromConfiguration(cfg);
+        List cfgFonts = FontSetup.buildFontListFromConfiguration(cfg, this);
         if (this.fontList == null) {
             this.fontList = cfgFonts;
         } else {
index 75c3817f19ecc553b6147f9cdb4e7ecdcda6e503..6553f06b69c653406cbb3f4878553dc85583e8c2 100644 (file)
@@ -129,7 +129,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda
         this.autoRotateLandscape = cfg.getChild("auto-rotate-landscape").getValueAsBoolean(false);
 
         //Font configuration
-        List cfgFonts = FontSetup.buildFontListFromConfiguration(cfg);
+        List cfgFonts = FontSetup.buildFontListFromConfiguration(cfg, this);
         if (this.fontList == null) {
             this.fontList = cfgFonts;
         } else {
index c1f85be87f630ae858483781f6269e1d0b826e9d..857847e10a061399eb7e05392a5fb678da8f7d7d 100644 (file)
@@ -145,7 +145,7 @@ public class XMLRenderer extends PrintRenderer {
     public void configure(Configuration cfg) throws ConfigurationException {
         super.configure(cfg);
         //Font configuration
-        List cfgFonts = FontSetup.buildFontListFromConfiguration(cfg);
+        List cfgFonts = FontSetup.buildFontListFromConfiguration(cfg, this);
         if (this.fontList == null) {
             this.fontList = cfgFonts;
         } else {
index 4a4ffabaec85caff2d97ad49b2f984e9f1866185..f7e330aec36e4c3b346f0a50c6a107789d1be963 100644 (file)
@@ -28,6 +28,9 @@
 
   <changes>
     <release version="FOP Trunk">
+      <action context="Code" dev="VH" type="fix" fixes-bug="40120" due-to="Adrian Cumiskey">
+        Stricter FOP user configuration checking
+      </action>
       <action context="Code" dev="AD" type="fix" fixes-bug="41572" due-to="Erwin Tratar">
         Fix parsing 'url(...)' when the URL itself contains a bracketed part.
       </action>
diff --git a/test/config/test_embedurl_bad.xconf b/test/config/test_embedurl_bad.xconf
new file mode 100644 (file)
index 0000000..3636454
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<fop version="1.0">
+  <!-- Strict configuration On -->
+  <strict-configuration>true</strict-configuration>
+
+  <!-- Base URL for resolving relative URLs -->
+  <base>./</base>
+
+  <!-- Font Base URL for resolving relative font URLs -->
+  <font-base>./</font-base>
+  
+  <renderers>
+    <renderer mime="application/pdf">
+      <fonts>
+               <!-- this font has an embed-url that does not exist on filesystem -->
+               <font metrics-url="test/resources/fonts/glb12.ttf.xml" embed-url="test/resources/fonts/doesnotexist.ttf">
+          <font-triplet name="Gladiator-Ansi" style="normal" weight="normal"/>
+        </font>
+      </fonts>
+    </renderer>
+  </renderers>
+</fop>
diff --git a/test/config/test_embedurl_malformed.xconf b/test/config/test_embedurl_malformed.xconf
new file mode 100644 (file)
index 0000000..b11d086
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<fop version="1.0">
+  <!-- Strict configuration On -->
+  <strict-configuration>true</strict-configuration>
+
+  <!-- Base URL for resolving relative URLs -->
+  <base>./</base>
+
+  <!-- Font Base URL for resolving relative font URLs -->
+  <font-base>./</font-base>
+  
+  <renderers>
+    <renderer mime="application/pdf">
+      <fonts>
+               <!-- this font has a malformed embed-url -->
+               <font metrics-url="test/resources/fonts/glb12.ttf.xml" embed-url="badprotocol:test/resources/fonts/glb12.ttf">
+          <font-triplet name="Gladiator-Ansi" style="normal" weight="normal"/>
+        </font>
+      </fonts>
+    </renderer>
+  </renderers>
+</fop>
diff --git a/test/config/test_fontattributes_missing.xconf b/test/config/test_fontattributes_missing.xconf
new file mode 100644 (file)
index 0000000..f186d80
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<fop version="1.0">
+  <!-- Strict configuration On -->
+  <strict-configuration>true</strict-configuration>
+
+  <!-- Base URL for resolving relative URLs -->
+  <base>./</base>
+
+  <!-- Font Base URL for resolving relative font URLs -->
+  <font-base>./</font-base>
+  
+  <renderers>
+    <renderer mime="application/pdf">
+      <fonts>
+               <!-- this font is without a metrics-url -->
+               <font>
+          <font-triplet name="Gladiator" style="normal" weight="normal"/>
+        </font>
+      </fonts>
+    </renderer>
+  </renderers>
+</fop>
diff --git a/test/config/test_fontbase_bad.xconf b/test/config/test_fontbase_bad.xconf
new file mode 100644 (file)
index 0000000..850f343
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<fop version="1.0">
+  <!-- Strict configuration On -->
+  <strict-configuration>true</strict-configuration>
+
+  <!-- Base URL for resolving relative URLs -->
+  <base>./</base>
+
+  <!-- Font Base URL for resolving relative font URLs -->
+  <font-base>./doesnotexist/</font-base>
+  
+  <renderers>
+    <renderer mime="application/pdf">
+      <fonts>
+               <!-- this font is with a relative metrics-url
+                    so should call upon the bad font-base -->
+        <font metrics-url="test/resources/fonts/glb12.ttf.xml" embed-url="test/resources/fonts/glb12.ttf">
+          <font-triplet name="Gladiator" style="normal" weight="normal"/>
+        </font>
+      </fonts>
+    </renderer>
+  </renderers>
+</fop>
diff --git a/test/config/test_fonttripletattribute_missing.xconf b/test/config/test_fonttripletattribute_missing.xconf
new file mode 100644 (file)
index 0000000..4e13874
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<fop version="1.0">
+  <!-- Strict configuration On -->
+  <strict-configuration>true</strict-configuration>
+
+  <!-- Base URL for resolving relative URLs -->
+  <base>./</base>
+
+  <!-- Font Base URL for resolving relative font URLs -->
+  <font-base>./</font-base>
+  
+  <renderers>
+    <renderer mime="application/pdf">
+      <fonts>
+        <font metrics-url="test/resources/fonts/glb12.ttf.xml">
+                 <!-- this font-triplet has a missing style attribute -->           
+          <font-triplet name="Gladiator" weight="normal"/>
+        </font>
+      </fonts>
+    </renderer>
+  </renderers>
+</fop>
diff --git a/test/config/test_metricsurl_bad.xconf b/test/config/test_metricsurl_bad.xconf
new file mode 100644 (file)
index 0000000..a792834
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<fop version="1.0">
+  <!-- Strict configuration On -->
+  <strict-configuration>true</strict-configuration>
+
+  <!-- Base URL for resolving relative URLs -->
+  <base>./</base>
+
+  <!-- Font Base URL for resolving relative font URLs -->
+  <font-base>./</font-base>
+  
+  <renderers>
+    <renderer mime="application/pdf">
+      <fonts>
+               <!-- this font has a metrics-url that does not exist on filesystem -->
+        <font metrics-url="test/resources/fonts/doesnotexist.ttf.ansi.xml">
+          <font-triplet name="Gladiator-Ansi" style="normal" weight="normal"/>
+        </font>
+      </fonts>
+    </renderer>
+  </renderers>
+</fop>
diff --git a/test/config/test_metricsurl_malformed.xconf b/test/config/test_metricsurl_malformed.xconf
new file mode 100644 (file)
index 0000000..7dc6dac
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<fop version="1.0">
+  <!-- Strict configuration On -->
+  <strict-configuration>true</strict-configuration>
+
+  <!-- Base URL for resolving relative URLs -->
+  <base>./</base>
+
+  <!-- Font Base URL for resolving relative font URLs -->
+  <font-base>./</font-base>
+  
+  <renderers>
+    <renderer mime="application/pdf">
+      <fonts>
+               <!-- this font has a malformed metrics-url -->
+        <font metrics-url="badprotocol:test/resources/fonts/glb12.ttf.xml">
+          <font-triplet name="Gladiator" style="normal" weight="normal"/>
+        </font>
+      </fonts>
+    </renderer>
+  </renderers>
+</fop>
diff --git a/test/java/org/apache/fop/config/BaseUserConfigTestCase.java b/test/java/org/apache/fop/config/BaseUserConfigTestCase.java
new file mode 100644 (file)
index 0000000..3a97f43
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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.config;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+
+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.apps.FOPException;
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.render.pdf.BasePDFTestCase;
+import org.xml.sax.SAXException;
+
+/**
+ * Basic runtime test for FOP's font configuration. It is used to verify that 
+ * nothing obvious is broken after compiling.
+ */
+public abstract class BaseUserConfigTestCase extends BasePDFTestCase {
+
+    protected static DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
+
+    /** logging instance */
+    protected Log log = LogFactory.getLog(BaseUserConfigTestCase.class);
+
+
+    /**
+     * @see junit.framework.TestCase#TestCase(String)
+     */
+    public BaseUserConfigTestCase(String name) {
+        super(name);
+    }
+
+    /**
+     * @see org.apache.fop.render.pdf.BasePDFTestCase#init()
+     */
+    protected void init() {
+        // do nothing
+    }
+
+    /**
+     * Test using a standard FOP font
+     * @throws Exception checkstyle wants a comment here, even a silly one
+     */
+    public void testUserConfig() throws Exception {
+        try {
+            fopFactory.setUserConfig(getUserConfig());        
+            final File baseDir = getBaseDir();
+            final String fontFOFilePath = getFontFOFilePath();
+            File foFile = new File(baseDir, fontFOFilePath);
+            final boolean dumpOutput = false;
+            FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
+            convertFO(foFile, foUserAgent, dumpOutput);
+            fail( getName() + ": Expected Configuration Exception" );
+        } catch (FOPException e) {
+            // this *should* happen!
+        } catch (Exception e) {
+            fail( getName() + ": Expected FOPException but got: " + e.getMessage() );
+        }
+    }
+
+
+    /**
+     * get test FOP config File
+     * @return fo test filepath
+     */
+    protected String getFontFOFilePath() {
+        return "test/xml/bugtests/font.fo";
+    }
+
+    /**
+     * get test FOP Configuration
+     * @return fo test filepath
+     * @throws IOException 
+     * @throws SAXException 
+     * @throws ConfigurationException 
+     */
+    protected Configuration getUserConfig(String configString)
+            throws ConfigurationException, SAXException, IOException {
+        return cfgBuilder.build(new ByteArrayInputStream(configString.getBytes()));
+    }
+
+    /**
+     * get test FOP Configuration
+     * @return fo test filepath
+     * @throws IOException 
+     * @throws SAXException 
+     * @throws ConfigurationException 
+     */
+    protected Configuration getUserConfig()
+            throws ConfigurationException, SAXException, IOException {
+        return cfgBuilder.buildFromFile(getUserConfigFile());
+    }
+    
+    /** get base config directory */
+    protected String getBaseConfigDir() {
+        return "test/config";
+    }
+    
+    /**
+     * @return user config File
+     */
+    protected abstract File getUserConfigFile();
+}
diff --git a/test/java/org/apache/fop/config/EmbedUrlBadTestCase.java b/test/java/org/apache/fop/config/EmbedUrlBadTestCase.java
new file mode 100644 (file)
index 0000000..2934004
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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.config;
+
+import java.io.File;
+
+// 
+/**
+ * this font has an embed-url that does not exist on filesystem.
+ */
+public class EmbedUrlBadTestCase extends BaseUserConfigTestCase {
+
+    public EmbedUrlBadTestCase(String name) {
+        super(name);
+    }
+
+    protected File getUserConfigFile() {
+        return new File( getBaseConfigDir() + "/test_embedurl_bad.xconf");
+    }
+    
+    public String getName() {
+        return "test_embedurl_bad.xconf";
+    }
+}
diff --git a/test/java/org/apache/fop/config/EmbedUrlMalformedTestCase.java b/test/java/org/apache/fop/config/EmbedUrlMalformedTestCase.java
new file mode 100644 (file)
index 0000000..ab622fd
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.config;
+
+import java.io.File;
+
+// this font has a malformed embed-url
+public class EmbedUrlMalformedTestCase extends BaseUserConfigTestCase {
+
+    public EmbedUrlMalformedTestCase(String name) {
+        super(name);
+    }
+
+    protected File getUserConfigFile() {
+        return new File( getBaseConfigDir() + "/test_embedurl_malformed.xconf");
+    }
+    
+    public String getName() {
+        return "test_embedurl_malformed.xconf";
+    }
+}
diff --git a/test/java/org/apache/fop/config/FontAttributesMissingTestCase.java b/test/java/org/apache/fop/config/FontAttributesMissingTestCase.java
new file mode 100644 (file)
index 0000000..fc5b10a
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.config;
+
+import java.io.File;
+
+// this font is without a metrics-url or an embed-url
+public class FontAttributesMissingTestCase extends BaseUserConfigTestCase {
+
+    public FontAttributesMissingTestCase(String name) {
+        super(name);
+    }
+
+    protected File getUserConfigFile() {
+        return new File( getBaseConfigDir() + "/test_fontattributes_missing.xconf");
+    }
+    
+    public String getName() {
+        return "test_fontattributes_missing.xconf";
+    }
+}
diff --git a/test/java/org/apache/fop/config/FontBaseBadTestCase.java b/test/java/org/apache/fop/config/FontBaseBadTestCase.java
new file mode 100644 (file)
index 0000000..d22670d
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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.config;
+
+import java.io.File;
+
+// this font base does not exist and a relative font path is used
+public class FontBaseBadTestCase extends BaseUserConfigTestCase {
+
+    public FontBaseBadTestCase(String name) {
+        super(name);
+    }
+
+    /**
+     * @see org.apache.fop.config.BaseUserConfigTestCase#getUserConfigFile()
+     */
+    protected File getUserConfigFile() {
+        return new File( getBaseConfigDir() + "/test_fontbase_bad.xconf");
+    }
+    
+    /**
+     * @return configuration filename
+     */
+    public String getName() {
+        return "test_fontbase_bad.xconf";
+    }
+}
diff --git a/test/java/org/apache/fop/config/FontTripletAttributeMissingTestCase.java b/test/java/org/apache/fop/config/FontTripletAttributeMissingTestCase.java
new file mode 100644 (file)
index 0000000..c321926
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.config;
+
+import java.io.File;
+
+// this font has an embed-url that does not exist on filesystem
+public class FontTripletAttributeMissingTestCase extends BaseUserConfigTestCase {
+
+    public FontTripletAttributeMissingTestCase(String name) {
+        super(name);
+    }
+
+    protected File getUserConfigFile() {
+        return new File( getBaseConfigDir() + "/test_fonttripletattribute_missing.xconf");
+    }
+    
+    public String getName() {
+        return "test_fonttripletattribute_missing.xconf";
+    }
+}
diff --git a/test/java/org/apache/fop/config/MetricsUrlBadTestCase.java b/test/java/org/apache/fop/config/MetricsUrlBadTestCase.java
new file mode 100644 (file)
index 0000000..80f7e28
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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.config;
+
+import java.io.File;
+
+// this font has a metrics-url that does not exist on filesystem
+public class MetricsUrlBadTestCase extends BaseUserConfigTestCase {
+
+    /**
+     * @see junit.framework.TestCase#TestCase(String)
+     */
+    public MetricsUrlBadTestCase(String name) {
+        super(name);
+    }
+
+    /**
+     * @see org.apache.fop.config.BaseUserConfigTestCase#getUserConfigFile()
+     */
+    protected File getUserConfigFile() {
+        return new File( getBaseConfigDir() + "/test_metricsurl_bad.xconf");
+    }
+    
+    public String getName() {
+        return "test_metricsurl_bad.xconf";
+    }
+}
diff --git a/test/java/org/apache/fop/config/MetricsUrlMalformedTestCase.java b/test/java/org/apache/fop/config/MetricsUrlMalformedTestCase.java
new file mode 100644 (file)
index 0000000..6b623e0
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.config;
+
+import java.io.File;
+
+// this font has a malformed metrics-url
+public class MetricsUrlMalformedTestCase extends BaseUserConfigTestCase {
+
+    public MetricsUrlMalformedTestCase(String name) {
+        super(name);
+    }
+
+    protected File getUserConfigFile() {
+        return new File( getBaseConfigDir() + "/test_metricsurl_malformed.xconf");
+    }
+    
+    public String getName() {
+        return "test_metricsurl_malformed.xconf";
+    }
+}
diff --git a/test/java/org/apache/fop/config/UserConfigTestSuite.java b/test/java/org/apache/fop/config/UserConfigTestSuite.java
new file mode 100644 (file)
index 0000000..ab612d0
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.config;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Test suite for font configuration.
+ */
+public class UserConfigTestSuite {
+
+    /**
+     * Builds the test suite
+     * @return the test suite
+     */
+    public static Test suite() {
+        TestSuite suite = new TestSuite(
+            "Basic functionality test suite for user configuration");
+        //$JUnit-BEGIN$
+        suite.addTest(new TestSuite(FontBaseBadTestCase.class));
+        suite.addTest(new TestSuite(FontAttributesMissingTestCase.class));
+        suite.addTest(new TestSuite(FontTripletAttributeMissingTestCase.class));
+        suite.addTest(new TestSuite(MetricsUrlBadTestCase.class));
+        suite.addTest(new TestSuite(EmbedUrlBadTestCase.class));
+        suite.addTest(new TestSuite(MetricsUrlMalformedTestCase.class));
+        suite.addTest(new TestSuite(EmbedUrlMalformedTestCase.class));
+        //$JUnit-END$
+        return suite;
+    }
+
+}
index 54e2ba9d81fb0eeace9641c0cce050181f2cece9..3e399e064ee66dc3cd294894102f80084c2a429b 100644 (file)
@@ -29,17 +29,16 @@ import javax.xml.transform.stream.StreamSource;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.fop.AbstractFOPTestCase;
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.apps.Fop;
 import org.apache.fop.apps.FopFactory;
 import org.apache.fop.apps.MimeConstants;
 
-import junit.framework.TestCase;
-
 /**
  * Base class for automated tests that create PDF files
  */
-public class BasePDFTestCase extends TestCase {
+public class BasePDFTestCase extends AbstractFOPTestCase {
 
     /** the FopFactory */
     protected final FopFactory fopFactory = FopFactory.newInstance();
@@ -53,7 +52,13 @@ public class BasePDFTestCase extends TestCase {
      */
     protected BasePDFTestCase(String name) {
         super(name);
+        init();
+    }
 
+    /**
+     * initalizes the test
+     */
+    protected void init() {
         final File uc = getUserConfigFile();
 
         try {