Skip to content

Commit

Permalink
Merge pull request #7 from cajuncoding/feature/add_support_to_load_ac…
Browse files Browse the repository at this point in the history
…cessibility_from_xml_or_az_func_config

Feature/add support to load accessibility from xml or az func config
  • Loading branch information
cajuncoding authored Aug 11, 2022
2 parents 7ce2274 + f8d07f8 commit 479220a
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 24 deletions.
2 changes: 2 additions & 0 deletions apachefop-serverless-az-func/.vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"java.configuration.updateBuildConfiguration": "automatic",
"maven.view": "hierarchical",
"cSpell.words": [
"apachefop",
"Gzipped",
"Keepin",
"xslfo"
]
}
10 changes: 5 additions & 5 deletions apachefop-serverless-az-func/host.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
"version": "2.0"//,
// "extensionBundle": {
// "id": "Microsoft.Azure.Functions.ExtensionBundle",
// "version": "[1.*, 2.0.0)"
// }
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class ApacheFopRenderResult {
private final ApacheFopEventListener eventListener;

public ApacheFopRenderResult(byte[] pdfBytes, ApacheFopEventListener eventListener) {
this.pdfBytes = pdfBytes;
this.pdfBytes = pdfBytes != null ? pdfBytes : new byte[0];
this.eventListener = eventListener;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
import com.cajuncoding.apachefop.serverless.config.ApacheFopServerlessConfig;
import com.cajuncoding.apachefop.serverless.config.ApacheFopServerlessConstants;
import com.cajuncoding.apachefop.serverless.utils.ResourceUtils;
import com.cajuncoding.apachefop.serverless.utils.XPathUtils;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.fop.apps.*;
import org.apache.fop.configuration.ConfigurationException;
import org.apache.fop.configuration.DefaultConfigurationBuilder;
Expand All @@ -11,6 +15,7 @@
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.logging.Logger;
import java.util.zip.GZIPOutputStream;
Expand Down Expand Up @@ -93,23 +98,32 @@ protected synchronized void initApacheFopFactorySafely() {
var configFilePath = ApacheFopServerlessConstants.ConfigXmlResourceName;
FopFactory newFopFactory = null;

try (var configStream = ResourceUtils.loadResourceAsStream(configFilePath);) {
if (configStream != null) {
try {
String configXmlText = ResourceUtils.loadResourceAsString(configFilePath);
if (StringUtils.isNotBlank(configXmlText)) {

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

//Attempt to initialize with Configuration loaded from Configuration XML Resource file...
var cfgBuilder = new DefaultConfigurationBuilder();
var cfg = cfgBuilder.build(configStream);

var fopFactoryBuilder = new FopFactoryBuilder(baseUri, fopResourcesFileResolver).setConfiguration(cfg);

//NOTE: FOP Factory requires a Stream so we have to initialize a new Stream for it to load from!
FopFactoryBuilder fopFactoryBuilder;
try(var configXmlStream = IOUtils.toInputStream(configXmlText, StandardCharsets.UTF_8)) {
var cfgBuilder = new DefaultConfigurationBuilder();
var cfg = cfgBuilder.build(configXmlStream);

fopFactoryBuilder = new FopFactoryBuilder(baseUri, fopResourcesFileResolver).setConfiguration(cfg);
}
//Ensure Accessibility is programmatically set (default configuration is false)...
//fopFactoryBuilder.setAccessibility(this.apacheFopConfig.isAccessibilityPdfRenderingEnabled());
//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!
// to work around this we read the value ourselves and also provide convenience support to simply set it in Azure Functions Configuration
// and if either configuration value is true then it will be enabled.
//NOTE: The XPathUtils is null safe so any issues in loading/parsing will simply result in null or default values...
var configXml = XPathUtils.fromXml(configXmlText);
var isAccessibilityEnabledInXmlConfig = configXml.evalXPathAsBoolean("//fop/accessibility", false);
fopFactoryBuilder.setAccessibility(this.apacheFopConfig.isAccessibilityPdfRenderingEnabled() || isAccessibilityEnabledInXmlConfig);

newFopFactory = fopFactoryBuilder.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ protected void readRequestQueryParamsConfig(Map<String, String> queryParams) {

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

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ public static String getCurrentW3cDateTime() {
return currentW3cDateTime;
}

public static boolean isNullOrWhiteSpace(String value) {
return value == null || value.isBlank();
}

/**
* Truncates a string to the number of characters that fit in X bytes avoiding multi byte characters being cut in
* half at the cut off point. Also handles surrogate pairs where 2 characters in the string is actually one literal
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.cajuncoding.apachefop.serverless.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.io.IOUtils;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class XPathUtils {

public static XPathUtils fromXml(String xmlContent)
{
try (var xmlContentStream = IOUtils.toInputStream(xmlContent, StandardCharsets.UTF_8)) {
return XPathUtils.fromXml(xmlContentStream);
} catch (IOException e) {
e.printStackTrace();
}

return new XPathUtils(null);
}

public static XPathUtils fromXml(InputStream xmlContentStream)
{
Document xmlDocument = null;
try {
xmlDocument = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(xmlContentStream);
} catch (SAXException | IOException | ParserConfigurationException e) {
e.printStackTrace();
}

return new XPathUtils(xmlDocument);
}

protected Document _xmlDoc;

public XPathUtils(Document xmlDoc)
{
_xmlDoc = xmlDoc;
}

public Document getXmlDocument() {
return _xmlDoc;
}

public <T>T evalXPath(String xpath, Class<T> classType) throws XPathExpressionException
{
return evalXPathInternal(xpath, classType);
}

public String evalXPathAsString(String xpath, String defaultIfNotFound) throws XPathExpressionException
{
try {
var result = evalXPathInternal(xpath, String.class);
return result != null ? result : defaultIfNotFound;
} catch (XPathExpressionException e) {
return defaultIfNotFound;
}
}

public boolean evalXPathAsBoolean(String xpath, boolean defaultIfNotFound)
{
try {
var result = evalXPathInternal(xpath, Boolean.class);
return (boolean)(result != null ? result : defaultIfNotFound);
} catch (XPathExpressionException e) {
return defaultIfNotFound;
}
}

public <T>T evalXPathInternal(String xpathCommand, Class<T> classType) throws XPathExpressionException
{
if(_xmlDoc == null)
return null;

XPath xpath = XPathFactory.newInstance().newXPath();
// //XPathExpression xpathExpression = xpathCompiler.compile(xpath);
// var result = xpathExpression.evaluate(_xmlDoc, returnType);
var result = xpath.evaluateExpression(xpathCommand, _xmlDoc, classType);
return result;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ protected <TRequest> HttpResponseMessage ExecuteRequestInternal(
//Execute the transformation of the XSL-FO source content to Binary PDF format...
var pdfRenderResult = fopHelper.renderPdfResult(xslFOBodyContent, config.isGzipResponseEnabled());

//Add some contextual Logging so we can know if the PDF bytes were rendered...
logger.info(MessageFormat.format("[SUCCESS] Successfully Rendered PDF with [{0}] bytes.", pdfRenderResult.getPdfBytes().length));

//Render the PDF Response (or EventLog Dump if specified)...
var response = config.isEventLogDumpModeEnabled()
? responseBuilder.BuildEventLogDumpResponse(pdfRenderResult, config)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.cajuncoding.apachefop.serverless.web;

import com.cajuncoding.apachefop.serverless.http.HttpEncodings;
import com.cajuncoding.apachefop.serverless.utils.TextUtils;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;

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

protected String sanitizeTextForHttpHeader(String value, String encoding) throws UnsupportedEncodingException {
if(TextUtils.isNullOrWhiteSpace(value))
if(StringUtils.isBlank(value))
return value;

if(encoding != null && encoding != HttpEncodings.IDENTITY_ENCODING)
if(StringUtils.isNotBlank(encoding) && !encoding.equalsIgnoreCase(HttpEncodings.IDENTITY_ENCODING))
return value;

//BBernard - 09/29/2021
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
<!-- All fonts information that has been gathered as a result of "directory" or "auto-detect" font configurations will be cached for future rendering runs.-->
<use-cache>true</use-cache>

<!-- Enable Accessibility as noted in Apache FOP Docs; NOTE: There is a Bug where this isn't loaded but we now manually support this! -->
<accessibility>false</accessibility>

<renderers>
<renderer mime="application/pdf">
<!-- Enable this to turn on Accessibility Support...
Expand Down

0 comments on commit 479220a

Please sign in to comment.