Skip to content

Commit eedde2f

Browse files
committed
Fix issues introduced in upgrade from FOP v2.6 to v2.11 where the Resource Resolver injected to the constrcutor of FopFactoryBuilder is not honored and is lost when calling FopFactoryBuilder.setConfiguration(), whereby the default resource resover is actually passed to the FontManager instead of the one that was originally injected. This worked fine in Fop v2.6 (and maybe other versions). The resolution is to actually parse the configuration directly from the stream using FopConfParser directly (which allows us to inject the Resource Resolver that is then correctly honored), and then calling getFopFactoryBuilder() to get the fully initialize FopFactoryBuilder from the FopConfParser. Everything works as expected after that!
ALSO improved the default flow if there are any issues parsing the Configuration that ensures we still use our custom Resorce Resolver even if all other configuration Defaults are used; this was missing in the prior version of ApacheFop.Serverless.
1 parent 5bcba42 commit eedde2f

File tree

2 files changed

+56
-28
lines changed

2 files changed

+56
-28
lines changed

apachefop-serverless-az-func/src/main/java/com/cajuncoding/apachefop/serverless/apachefop/ApacheFopJavaResourcesFileResolver.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ protected InputStream tryFindJavaResourceWithCaching(URI uri) {
5757

5858
//Use cached results from our Concurrent HashMap cached data if possible!
5959
var resourceBytes = javaResourceFileCache.computeIfAbsent(uri, key -> {
60-
//Map the requested Uri to the base application path to determine it's relative path as a Resource!
60+
//Map the requested Uri to the base application path to determine its relative path as a Resource!
6161
try {
6262
var mappedPath = ResourceUtils.MapServerPath(requestPath);
6363

apachefop-serverless-az-func/src/main/java/com/cajuncoding/apachefop/serverless/apachefop/ApacheFopRenderer.java

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@
88
import org.apache.commons.io.IOUtils;
99
import org.apache.commons.lang3.StringUtils;
1010
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;
1312

1413
import javax.xml.transform.*;
1514
import javax.xml.transform.sax.SAXResult;
1615
import javax.xml.transform.stream.StreamSource;
1716
import java.io.*;
1817
import java.nio.charset.StandardCharsets;
1918
import java.text.MessageFormat;
19+
import java.util.logging.Level;
2020
import java.util.logging.Logger;
2121
import java.util.zip.GZIPOutputStream;
2222

@@ -109,45 +109,73 @@ protected synchronized void initApacheFopFactorySafely() {
109109

110110
//Attempt to initialize with Configuration loaded from Configuration XML Resource file...
111111
//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;
113113
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();
118148
}
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();
129149
}
130-
} catch (IOException | ConfigurationException e) {
150+
} catch (IOException e) {
131151
//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);
137153
}
138154

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...
140156
if (newFopFactory == null) {
141-
newFopFactory = FopFactory.newInstance(baseUri);
157+
var fopFactoryBuilder = new FopFactoryBuilder(baseUri, fopResourcesFileResolver);
158+
newFopFactory = fopFactoryBuilder.build();
142159
}
143160

144161
staticFopFactory = newFopFactory;
145162
}
146163
}
147164

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+
148177
protected void LogMessage(String message)
149178
{
150-
if(logger != null)
151-
logger.info(message);
179+
if(logger != null) logger.info(message);
152180
}
153181
}

0 commit comments

Comments
 (0)