|
8 | 8 | import org.apache.commons.io.IOUtils; |
9 | 9 | import org.apache.commons.lang3.StringUtils; |
10 | 10 | import org.apache.fop.apps.*; |
11 | | -import org.apache.fop.configuration.ConfigurationException; |
12 | | -import org.apache.fop.configuration.DefaultConfigurationBuilder; |
| 11 | +import org.xml.sax.SAXException; |
13 | 12 |
|
14 | 13 | import javax.xml.transform.*; |
15 | 14 | import javax.xml.transform.sax.SAXResult; |
16 | 15 | import javax.xml.transform.stream.StreamSource; |
17 | 16 | import java.io.*; |
18 | 17 | import java.nio.charset.StandardCharsets; |
19 | 18 | import java.text.MessageFormat; |
| 19 | +import java.util.logging.Level; |
20 | 20 | import java.util.logging.Logger; |
21 | 21 | import java.util.zip.GZIPOutputStream; |
22 | 22 |
|
@@ -109,45 +109,73 @@ protected synchronized void initApacheFopFactorySafely() { |
109 | 109 |
|
110 | 110 | //Attempt to initialize with Configuration loaded from Configuration XML Resource file... |
111 | 111 | //NOTE: FOP Factory requires a Stream so we have to initialize a new Stream for it to load from! |
112 | | - FopFactoryBuilder fopFactoryBuilder; |
| 112 | + FopFactoryBuilder fopFactoryBuilder = null; |
113 | 113 | try(var configXmlStream = IOUtils.toInputStream(configXmlText, StandardCharsets.UTF_8)) { |
114 | | - var cfgBuilder = new DefaultConfigurationBuilder(); |
115 | | - var cfg = cfgBuilder.build(configXmlStream); |
116 | | - |
117 | | - fopFactoryBuilder = new FopFactoryBuilder(baseUri, fopResourcesFileResolver).setConfiguration(cfg); |
| 114 | + //BUG: |
| 115 | + // Changes somewhere since FOP v2.6 (the last version before jumping to now FOP v2.11) caused |
| 116 | + // a new bug whereby calling the FopFactoryBuilder.setConfiguration() would correctly load & |
| 117 | + // parse the config Xml, but NOT honor the original ResourceResolver, originally passed |
| 118 | + // into the constructor for the FopFactoryBuilder, and instead calls the |
| 119 | + // ResourceResolverFactory.createDefaultResourceResolver() which loses the resolver context |
| 120 | + // for the FontManager! |
| 121 | + //RESOLUTION: |
| 122 | + // However, we can work around this by simply newing up the FopConfParser directly, and then |
| 123 | + // retrieving the FopFactoryBuilder from it, this honors the Resource Resolver we pass |
| 124 | + // into the constructor of the FopConfParser, and everything works as expected! |
| 125 | + // The main impact is that now we are exposed to a possible SAXException that we must now handle. |
| 126 | + //var cfgBuilder = new DefaultConfigurationBuilder(); |
| 127 | + //var cfg = cfgBuilder.build(configXmlStream); |
| 128 | + //fopFactoryBuilder = new FopFactoryBuilder(baseUri, fopResourcesFileResolver).setConfiguration(cfg); |
| 129 | + var fopConfigParser = new FopConfParser(configXmlStream, baseUri, fopResourcesFileResolver); |
| 130 | + fopFactoryBuilder = fopConfigParser.getFopFactoryBuilder(); |
| 131 | + |
| 132 | + } catch (SAXException e) { |
| 133 | + //DO NOTHING if Configuration is Invalid; log info. for troubleshooting. |
| 134 | + logUnexpectedException(configFilePath, e); |
| 135 | + } |
| 136 | + |
| 137 | + if(fopFactoryBuilder != null) { |
| 138 | + //Ensure Accessibility is programmatically set (default configuration is false)... |
| 139 | + //NOTE: There appears to be a bug in ApacheFOP code or documentation whereby it does not load the value from Xml as defined in the Docs! |
| 140 | + // to work around this we read the value ourselves and also provide convenience support to simply set it in Azure Functions Configuration |
| 141 | + // and if either configuration value is true then it will be enabled. |
| 142 | + //NOTE: The XPathUtils is null safe so any issues in loading/parsing will simply result in null or default values... |
| 143 | + var configXml = XPathUtils.fromXml(configXmlText); |
| 144 | + var isAccessibilityEnabledInXmlConfig = configXml.evalXPathAsBoolean("//fop/accessibility", false); |
| 145 | + fopFactoryBuilder.setAccessibility(this.apacheFopConfig.isAccessibilityPdfRenderingEnabled() || isAccessibilityEnabledInXmlConfig); |
| 146 | + |
| 147 | + newFopFactory = fopFactoryBuilder.build(); |
118 | 148 | } |
119 | | - //Ensure Accessibility is programmatically set (default configuration is false)... |
120 | | - //NOTE: There appears to be a bug in ApacheFOP code or documentation whereby it does not load the value from Xml as defined in the Docs! |
121 | | - // to work around this we read the value ourselves and also provide convenience support to simply set it in Azure Functions Configuration |
122 | | - // and if either configuration value is true then it will be enabled. |
123 | | - //NOTE: The XPathUtils is null safe so any issues in loading/parsing will simply result in null or default values... |
124 | | - var configXml = XPathUtils.fromXml(configXmlText); |
125 | | - var isAccessibilityEnabledInXmlConfig = configXml.evalXPathAsBoolean("//fop/accessibility", false); |
126 | | - fopFactoryBuilder.setAccessibility(this.apacheFopConfig.isAccessibilityPdfRenderingEnabled() || isAccessibilityEnabledInXmlConfig); |
127 | | - |
128 | | - newFopFactory = fopFactoryBuilder.build(); |
129 | 149 | } |
130 | | - } catch (IOException | ConfigurationException e) { |
| 150 | + } catch (IOException e) { |
131 | 151 | //DO NOTHING if Configuration is Invalid; log info. for troubleshooting. |
132 | | - System.out.println(MessageFormat.format( |
133 | | - "An Exception occurred loading the Configuration file [{0}]; {1}", |
134 | | - configFilePath, |
135 | | - e.getMessage() |
136 | | - )); |
| 152 | + logUnexpectedException(configFilePath, e); |
137 | 153 | } |
138 | 154 |
|
139 | | - //Safely Initialize will All DEFAULTS if not loaded with Configuration... |
| 155 | + //If not loaded with Configuration we still safely Initialize will All DEFAULTS, as well as our custom Resource Resolver... |
140 | 156 | if (newFopFactory == null) { |
141 | | - newFopFactory = FopFactory.newInstance(baseUri); |
| 157 | + var fopFactoryBuilder = new FopFactoryBuilder(baseUri, fopResourcesFileResolver); |
| 158 | + newFopFactory = fopFactoryBuilder.build(); |
142 | 159 | } |
143 | 160 |
|
144 | 161 | staticFopFactory = newFopFactory; |
145 | 162 | } |
146 | 163 | } |
147 | 164 |
|
| 165 | + private void logUnexpectedException(String configFilePath, Exception exc) |
| 166 | + { |
| 167 | + var message = MessageFormat.format( |
| 168 | + "An Exception occurred loading the Configuration file [{0}]; {1}", |
| 169 | + configFilePath, |
| 170 | + exc.getMessage() |
| 171 | + ); |
| 172 | + |
| 173 | + System.out.println(message); |
| 174 | + if(logger != null) logger.log(Level.SEVERE, message, exc); |
| 175 | + } |
| 176 | + |
148 | 177 | protected void LogMessage(String message) |
149 | 178 | { |
150 | | - if(logger != null) |
151 | | - logger.info(message); |
| 179 | + if(logger != null) logger.info(message); |
152 | 180 | } |
153 | 181 | } |
0 commit comments