Skip to content

Commit aea44e3

Browse files
committed
- Fix several new issues with running locally via Visual Studio Code; has to remove ExtensionBundle from host.json to run as expected with Debugger successfully attaching!.
- Cleaned up settings.json - Added more robust support for loading configuration values from Xml and implemented support for Accessibility value from ApacheFOP Xml Config as described in the documentation (or via Az Func configuration as a Serverless unique ability).
1 parent 7ce2274 commit aea44e3

File tree

5 files changed

+132
-15
lines changed

5 files changed

+132
-15
lines changed

apachefop-serverless-az-func/.vscode/settings.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
"java.configuration.updateBuildConfiguration": "automatic",
88
"maven.view": "hierarchical",
99
"cSpell.words": [
10+
"apachefop",
1011
"Gzipped",
12+
"Keepin",
1113
"xslfo"
1214
]
1315
}
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"version": "2.0",
3-
"extensionBundle": {
4-
"id": "Microsoft.Azure.Functions.ExtensionBundle",
5-
"version": "[1.*, 2.0.0)"
6-
}
2+
"version": "2.0"//,
3+
// "extensionBundle": {
4+
// "id": "Microsoft.Azure.Functions.ExtensionBundle",
5+
// "version": "[1.*, 2.0.0)"
6+
// }
77
}

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

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,21 @@
33
import com.cajuncoding.apachefop.serverless.config.ApacheFopServerlessConfig;
44
import com.cajuncoding.apachefop.serverless.config.ApacheFopServerlessConstants;
55
import com.cajuncoding.apachefop.serverless.utils.ResourceUtils;
6+
import com.cajuncoding.apachefop.serverless.utils.XPathUtils;
7+
8+
import org.apache.commons.io.IOUtils;
9+
import org.apache.commons.lang3.StringUtils;
610
import org.apache.fop.apps.*;
711
import org.apache.fop.configuration.ConfigurationException;
812
import org.apache.fop.configuration.DefaultConfigurationBuilder;
13+
import org.xml.sax.SAXException;
914

15+
import javax.xml.parsers.ParserConfigurationException;
1016
import javax.xml.transform.*;
1117
import javax.xml.transform.sax.SAXResult;
1218
import javax.xml.transform.stream.StreamSource;
1319
import java.io.*;
20+
import java.nio.charset.StandardCharsets;
1421
import java.text.MessageFormat;
1522
import java.util.logging.Logger;
1623
import java.util.zip.GZIPOutputStream;
@@ -87,29 +94,40 @@ public ApacheFopRenderResult renderPdfResult(String xslFOSource, boolean gzipEna
8794
}
8895
}
8996

97+
98+
9099
protected synchronized void initApacheFopFactorySafely() {
91100
if(staticFopFactory == null) {
92101
var baseUri = new File(".").toURI();
93102
var configFilePath = ApacheFopServerlessConstants.ConfigXmlResourceName;
94103
FopFactory newFopFactory = null;
95104

96-
try (var configStream = ResourceUtils.loadResourceAsStream(configFilePath);) {
97-
if (configStream != null) {
105+
try {
106+
String configXmlText = ResourceUtils.loadResourceAsString(configFilePath);
107+
if (!StringUtils.isBlank(configXmlText)) {
98108

99109
//When Debugging log the full Configuration file...
100110
if(this.apacheFopConfig.isDebuggingEnabled()) {
101-
var configFileXmlText =ResourceUtils.loadResourceAsString(configFilePath);
102-
LogMessage("[DEBUG] ApacheFOP Configuration Xml:".concat(System.lineSeparator()).concat(configFileXmlText));
111+
LogMessage("[DEBUG] ApacheFOP Configuration Xml:".concat(System.lineSeparator()).concat(configXmlText));
103112
}
104113

105114
//Attempt to initialize with Configuration loaded from Configuration XML Resource file...
106-
var cfgBuilder = new DefaultConfigurationBuilder();
107-
var cfg = cfgBuilder.build(configStream);
108-
109-
var fopFactoryBuilder = new FopFactoryBuilder(baseUri, fopResourcesFileResolver).setConfiguration(cfg);
110-
115+
//NOTE: FOP Factory requires a Stream so we have to initialize a new Stream for it to load from!
116+
FopFactoryBuilder fopFactoryBuilder;
117+
try(var configXmlStream = IOUtils.toInputStream(configXmlText, StandardCharsets.UTF_8)) {
118+
var cfgBuilder = new DefaultConfigurationBuilder();
119+
var cfg = cfgBuilder.build(configXmlStream);
120+
121+
fopFactoryBuilder = new FopFactoryBuilder(baseUri, fopResourcesFileResolver).setConfiguration(cfg);
122+
}
111123
//Ensure Accessibility is programmatically set (default configuration is false)...
112-
//fopFactoryBuilder.setAccessibility(this.apacheFopConfig.isAccessibilityPdfRenderingEnabled());
124+
//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!
125+
// to work around this we read the value ourselves and also provide convenience support to simply set it in Azure Functions Configuration
126+
// and if either configuration value is true then it will be enabled.
127+
//NOTE: The XPathUtils is null safe so any issues in loading/parsing will simply result in null or default values...
128+
var configXml = XPathUtils.fromXml(configXmlText);
129+
var isAccessibilityEnabledInXmlConfig = configXml.evalXPathAsBoolean("//fop/accessibility", false);
130+
fopFactoryBuilder.setAccessibility(this.apacheFopConfig.isAccessibilityPdfRenderingEnabled() || isAccessibilityEnabledInXmlConfig);
113131

114132
newFopFactory = fopFactoryBuilder.build();
115133
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package com.cajuncoding.apachefop.serverless.utils;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
import java.io.StringReader;
6+
import java.nio.charset.StandardCharsets;
7+
8+
import javax.xml.parsers.DocumentBuilderFactory;
9+
import javax.xml.parsers.ParserConfigurationException;
10+
import javax.xml.xpath.XPath;
11+
import javax.xml.xpath.XPathExpressionException;
12+
import javax.xml.xpath.XPathFactory;
13+
14+
import org.apache.commons.io.IOUtils;
15+
import org.w3c.dom.Document;
16+
import org.xml.sax.InputSource;
17+
import org.xml.sax.SAXException;
18+
19+
public class XPathUtils {
20+
21+
public static XPathUtils fromXml(String xmlContent)
22+
{
23+
try (var xmlContentStream = IOUtils.toInputStream(xmlContent, StandardCharsets.UTF_8)) {
24+
return XPathUtils.fromXml(xmlContentStream);
25+
} catch (IOException e) {
26+
e.printStackTrace();
27+
}
28+
29+
return new XPathUtils(null);
30+
}
31+
32+
public static XPathUtils fromXml(InputStream xmlContentStream)
33+
{
34+
Document xmlDocument = null;
35+
try {
36+
xmlDocument = DocumentBuilderFactory.newInstance()
37+
.newDocumentBuilder()
38+
.parse(xmlContentStream);
39+
} catch (SAXException | IOException | ParserConfigurationException e) {
40+
e.printStackTrace();
41+
}
42+
43+
return new XPathUtils(xmlDocument);
44+
}
45+
46+
protected Document _xmlDoc;
47+
48+
public XPathUtils(Document xmlDoc)
49+
{
50+
_xmlDoc = xmlDoc;
51+
}
52+
53+
public Document getXmlDocument() {
54+
return _xmlDoc;
55+
}
56+
57+
public <T>T evalXPath(String xpath, Class<T> classType) throws XPathExpressionException
58+
{
59+
return evalXPathInternal(xpath, classType);
60+
}
61+
62+
public String evalXPathAsString(String xpath, String defaultIfNotFound) throws XPathExpressionException
63+
{
64+
try {
65+
var result = evalXPathInternal(xpath, String.class);
66+
return result != null ? result : defaultIfNotFound;
67+
} catch (XPathExpressionException e) {
68+
return defaultIfNotFound;
69+
}
70+
}
71+
72+
public boolean evalXPathAsBoolean(String xpath, boolean defaultIfNotFound)
73+
{
74+
try {
75+
var result = evalXPathInternal(xpath, Boolean.class);
76+
return (boolean)(result != null ? result : defaultIfNotFound);
77+
} catch (XPathExpressionException e) {
78+
return defaultIfNotFound;
79+
}
80+
}
81+
82+
public <T>T evalXPathInternal(String xpathCommand, Class<T> classType) throws XPathExpressionException
83+
{
84+
if(_xmlDoc == null)
85+
return null;
86+
87+
XPath xpath = XPathFactory.newInstance().newXPath();
88+
// //XPathExpression xpathExpression = xpathCompiler.compile(xpath);
89+
// var result = xpathExpression.evaluate(_xmlDoc, returnType);
90+
var result = xpath.evaluateExpression(xpathCommand, _xmlDoc, classType);
91+
return result;
92+
}
93+
}
94+

apachefop-serverless-az-func/src/main/resources/apache-fop-config.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
<!-- All fonts information that has been gathered as a result of "directory" or "auto-detect" font configurations will be cached for future rendering runs.-->
2424
<use-cache>true</use-cache>
2525

26+
<!-- Enable Accessibility as noted in Apache FOP Docs; NOTE: There is a Bug where this isn't loaded but we now manually support this! -->
27+
<accessibility>false</accessibility>
28+
2629
<renderers>
2730
<renderer mime="application/pdf">
2831
<!-- Enable this to turn on Accessibility Support...

0 commit comments

Comments
 (0)