Skip to content

Commit 479220a

Browse files
authored
Merge pull request #7 from cajuncoding/feature/add_support_to_load_accessibility_from_xml_or_az_func_config
Feature/add support to load accessibility from xml or az func config
2 parents 7ce2274 + f8d07f8 commit 479220a

File tree

10 files changed

+137
-24
lines changed

10 files changed

+137
-24
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/ApacheFopRenderResult.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ public class ApacheFopRenderResult {
77
private final ApacheFopEventListener eventListener;
88

99
public ApacheFopRenderResult(byte[] pdfBytes, ApacheFopEventListener eventListener) {
10-
this.pdfBytes = pdfBytes;
10+
this.pdfBytes = pdfBytes != null ? pdfBytes : new byte[0];
1111
this.eventListener = eventListener;
1212
}
1313

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

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
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;
@@ -11,6 +15,7 @@
1115
import javax.xml.transform.sax.SAXResult;
1216
import javax.xml.transform.stream.StreamSource;
1317
import java.io.*;
18+
import java.nio.charset.StandardCharsets;
1419
import java.text.MessageFormat;
1520
import java.util.logging.Logger;
1621
import java.util.zip.GZIPOutputStream;
@@ -93,23 +98,32 @@ protected synchronized void initApacheFopFactorySafely() {
9398
var configFilePath = ApacheFopServerlessConstants.ConfigXmlResourceName;
9499
FopFactory newFopFactory = null;
95100

96-
try (var configStream = ResourceUtils.loadResourceAsStream(configFilePath);) {
97-
if (configStream != null) {
101+
try {
102+
String configXmlText = ResourceUtils.loadResourceAsString(configFilePath);
103+
if (StringUtils.isNotBlank(configXmlText)) {
98104

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

105110
//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-
111+
//NOTE: FOP Factory requires a Stream so we have to initialize a new Stream for it to load from!
112+
FopFactoryBuilder fopFactoryBuilder;
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);
118+
}
111119
//Ensure Accessibility is programmatically set (default configuration is false)...
112-
//fopFactoryBuilder.setAccessibility(this.apacheFopConfig.isAccessibilityPdfRenderingEnabled());
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);
113127

114128
newFopFactory = fopFactoryBuilder.build();
115129
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ protected void readRequestQueryParamsConfig(Map<String, String> queryParams) {
8383

8484
//Determine if Event Log Dump mode is enabled (vs PDF Binary return).
8585
this.eventLogDumpModeEnabled = BooleanUtils.toBoolean(
86-
queryParams.getOrDefault(ApacheFopServerlessQueryParams.EventLogDump, null)
86+
queryParams.getOrDefault(ApacheFopServerlessQueryParams.EventLogDump, null)
8787
);
8888

8989
}

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@ public static String getCurrentW3cDateTime() {
1818
return currentW3cDateTime;
1919
}
2020

21-
public static boolean isNullOrWhiteSpace(String value) {
22-
return value == null || value.isBlank();
23-
}
24-
2521
/**
2622
* Truncates a string to the number of characters that fit in X bytes avoiding multi byte characters being cut in
2723
* half at the cut off point. Also handles surrogate pairs where 2 characters in the string is actually one literal
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/java/com/cajuncoding/apachefop/serverless/web/ApacheFopServerlessFunctionExecutor.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ protected <TRequest> HttpResponseMessage ExecuteRequestInternal(
9292
//Execute the transformation of the XSL-FO source content to Binary PDF format...
9393
var pdfRenderResult = fopHelper.renderPdfResult(xslFOBodyContent, config.isGzipResponseEnabled());
9494

95+
//Add some contextual Logging so we can know if the PDF bytes were rendered...
96+
logger.info(MessageFormat.format("[SUCCESS] Successfully Rendered PDF with [{0}] bytes.", pdfRenderResult.getPdfBytes().length));
97+
9598
//Render the PDF Response (or EventLog Dump if specified)...
9699
var response = config.isEventLogDumpModeEnabled()
97100
? responseBuilder.BuildEventLogDumpResponse(pdfRenderResult, config)

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package com.cajuncoding.apachefop.serverless.web;
22

33
import com.cajuncoding.apachefop.serverless.http.HttpEncodings;
4-
import com.cajuncoding.apachefop.serverless.utils.TextUtils;
4+
5+
import org.apache.commons.lang3.StringUtils;
56
import org.apache.commons.text.StringEscapeUtils;
67

78
import java.io.UnsupportedEncodingException;
@@ -19,10 +20,10 @@ public SafeHeader(String value, String encoding) throws UnsupportedEncodingExcep
1920
public String getValue() { return value; }
2021

2122
protected String sanitizeTextForHttpHeader(String value, String encoding) throws UnsupportedEncodingException {
22-
if(TextUtils.isNullOrWhiteSpace(value))
23+
if(StringUtils.isBlank(value))
2324
return value;
2425

25-
if(encoding != null && encoding != HttpEncodings.IDENTITY_ENCODING)
26+
if(StringUtils.isNotBlank(encoding) && !encoding.equalsIgnoreCase(HttpEncodings.IDENTITY_ENCODING))
2627
return value;
2728

2829
//BBernard - 09/29/2021

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)