ApacheFOP.Serverless
A ready to use serverless implementation of Apache FOP via Azure Functions. This provides a micro-service for dynamically rendering quality PDF binary outputs from XSL-FO source using Apache FOP. When combined with the ease and simplicity of Azure Functions this project is a powerful, efficient, and scalable PDF Reporting Service that generates high quality, true paged media, reports for any environment and any client technology (.Net, NodeJS/JavaScript, Ruby, Mobile iOS/Android, Powershell, even Windows/Mac apps, etc.)!
Install / Use
/learn @cajuncoding/ApacheFOP.ServerlessREADME
ApacheFOP.Serverless -- Quality PDF Rendering-as-a-service for any Environment!
ApacheFOP.Serverless is a ready to use server-less implementation of Apache FOP via Azure Functions. This provides an easy to use REST API micro-service for dynamically rendering quality PDF binary outputs from XSL-FO source using Apache FOP.
When combined with the ease and simplicity of Azure Functions this project is a powerful, efficient, and scalable PDF Reporting Service that generates high quality, true paged media, reports for any environment and any client technology (.Net, NodeJS/JavaScript, Ruby, Mobile iOS/Android, Powershell, even Windows/Mac apps, etc.)!
You should be able to pull this code down and be up and running quickly & easily with IntelliJ or VS Code (after installing pre-requisites), or even just clone the repo and deploy directly to your Azure Subscription via GitHub Actions with no local Java needed.
Give Star 🌟
If you like this project and/or use it the please give it a Star 🌟 (c'mon it's free, and it'll help others find the project)!
Buy me a Coffee ☕
I'm happy to share with the community, but if you find this useful (e.g for professional use), and are so inclinded, then I do love-me-some-coffee!
<a href="https://www.buymeacoffee.com/cajuncoding" target="_blank"> <img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"> </a>Updates / Change Log
Updated the project to v1.7 with the following:
- XXE Scripting Vulnerability Mitigation: Added secure processing features to XML parsing to mitigate XXE vulnerabilities as per OWASP recommendations.
- The rendering process is now using a fully streaming (SAX) pipeline that is secured (no XXE allowed) — NO DOM is built and NO identity transform hop is necessary anymore.
- Fix Thread safety issues with FopFactory initialization with improved locking to create the singleton to mitigate risk of race conditions across multiple concurrent requests.
- Implement support for dynamic re-initialization when potentially recoverable errors may occur and/or if FOP Factory corruption occurs (e.g. Font Cache corruption).
- Updated all maven dependencies to latest stable versions.
- Improve error handling for requests now identifying invalid/malformed XML requests as 400-BadRequest instead of Http 500-InternalServerError.
- Improve error logging when exceptions occur.
- Fix Error handling to safely handle and return exceptions as valid Json responses that are compliant with the ApacheFOP.Serverless C# client -- which looks for Json to extract the 'detailMessage' value.
- Fix issues with Azure Functions internal pipeline throwing ClassCastExceptions where RpcHttpDataTarget cannot be cast to class TypedData$Builder; resolved by the aforementioned error handling changes.
- Cleanup and fix non-critical items in the KeepWarm.fo source to minimize issues when rendering.
- Fix <default-page-settings> configuration value to correctly initialize US-Letter size as default.
Updated the project to v1.6 with the following:
- Updated Apache FOP to v2.11 (latest as of 2025-05-20).
- Update to now use Java Azure Functions v4 (v3 is fully deprecated by end of 2022).
- Updated Java to latest supported version Java v21 (Using Azul Zulu OpenJDK).
- Updated all other packages to latest stable versions.
- Upgraded project
apachefop-serverless-az-func.imlto IntelliJ 2025 Community. - Resolved bug/breaking issue with
ApacheFopJavaResourcesFileResolvernot being used in v2.11 when callingFopFactoryBuilder.setConfiguration()(as it was in FOP v2.6).- The new version of FOP upgraded from FOP v2.6 to v2.11 introduced a bug (breaking issue) where the
ResourceResolverinjected to the constrcutor ofFopFactoryBuilderis not honored resulting in embedded Fonts (java resources) no longer being resolved. - The custom resolver is lost when calling
FopFactoryBuilder.setConfiguration(), whereby the code now instantiates a default resource resover that is actually passed to theFontManagerinstead of the resource resolver we provided in the constructor. - This worked fine in Fop v2.6 (and maybe other versions).
- The resolution is to initialize
FopFactoryBuilderdifferently now by parsing the configuration directly from theStreamusingFopConfParserwhich allows us to provide theApacheFopJavaResourcesFileResolverinto it's constructor instead (that is then correctly honored).- We are then able to call
FopConfParsergetFopFactoryBuilder()to get the fully initializeFopFactoryBuilderfrom theFopConfParser. - Everything works as expected after that!
- We are then able to call
- The new version of FOP upgraded from FOP v2.6 to v2.11 introduced a bug (breaking issue) where the
Updated the project to v1.5 with the following:
- Add support to read the Accessibility flag correctly from ApacheFOP configuration as noted in the documentation; a bug exists where the value is not loaded so we manually support this now in a way that is fully compliant with the documentation.
- The original support from Azure Function configuration (environment variable) is still supported also.
- Several small code improvements for consistency.
- Additional debugging log added to better know if rendering process was completed (e.g. logs SUCCESS along with Pdf Byte Size).
Updated the project to v1.4 with the following:
- Added support for running, debugging, and deploying from within VS Code as well as IntelliJ IDEA.
- Both project types use folder context configuration, so all configuration files have now been included and checked into the Repository.
- This should make it easier to get up and running quickly with either IDE.
- Resolved a bug in the Font loading/path handling when running in Windows Host (due to existing font paths).
- Updated Microsoft's
azure-functions-maven-pluginto address various issues (esp. the need for a GUID in the deployment name which broke VS Code's ability to debug). - Pom.xml cleanup to eliminate various "Problems" flagged by VS Code's pom parsing (using M2Eclipse processor).
- Various small code cleanup items as noted in VS Code Java "Problems" tab.
Updated the project to v1.3 with the following:
- Added support for Azure Function configuration capability to enable Accessibility since Apache FOP
<accessibility>xml config element is not working as of v2.6.- Added an XslFO markup sample to test/demonstrate Accessibility in
resources/samples/WorkinWithAccessibilitySample.fo. - Updated KeepinItWarm.fo to run correctly when Accessibility is enabled.
- Added an XslFO markup sample to test/demonstrate Accessibility in
- Added in-memory caching of Java embedded resources that are resolved (e.g. Fonts) for performance.
- Code cleanup.
Updated the project to v1.2 with the following:
- Added support for Custom Font integration as Resource Files in the project and deployed with the JAR!
- This enables adding fonts easily by simply dropping them in the
resources/fontsfolder, and then registering them via configuration in theapache-fop-config.xmlaccording to Apache FOP Font Documentation. - Added a a couple sample (free) custom fonts and sample markup
resources/samples/WorkinWithFontsSample.foin the project.
- This enables adding fonts easily by simply dropping them in the
- Fixed bug in the render Event Log debug details returned in the Http Header whereby Apache FOP may send Unicode Characters but only ASCII are allowed; Unicode are now safely escaped into their respective Hex Codes so that the message is readable.
- Fixed issue in Maven build to enforce the clean stage so the artifact always contains the latest changes (e.g. especially physical resource file changes) when debugging.
- Some miscellaneous code cleanup.
Updated the project to v1.1 as it now incorporates:
- Upgraded the project to use Java v11 now as the latest long term supported (LTS) version for Azure Functions (aka Zulu Java v11)
- Previously was Java 8 (v1.8) (aka Zulu Java v8).
- Bumping the versions of all dependencies to the latest stable versions
- Bumping the Apache FOP version to v2.6 (just released in Jan 2021)
- Adding support for configuration Xml to fully configure ApacheFOP Factory by editing the `/src/main/resources/apache-fop-config.xml' as needed.
- The configuration will be bundled and deployed with the application.
- Now includes an existing
apache-fop-config.xmlfile which enables Font 'auto-detect' feature for much better Font support. - Removed dependency on
com.sun.deploy.net.HttpRequestimport as importing it no longer compiles on the latest versions of IntelliJ IDEA; little value was added by using only one constant that was needed: ACCEPT_ENCODING - All Heading and Content type constants are now self-contained so no additional dependencies are needed.
- This enabled removal of the dependency on com.sun.deploy.net.HttpRequest import as importing it no longer compiles on the latest versions of IntelliJ IDEA, and is a bad practice. Little value was added by using only 1 constant was needed, ACCEPT_ENCODING
- Notable cleanup & optimization of the Pom.xml
- Implemented a fix for a possilbe deployment risk when AppName and ResourceGroupName values are not unique with the azure-functions-maven-plugin
- As noted here: https://github.com/Azure/azure-functions-java-worker/issues/140
Technical Summary:
This project provides a REST API that recieves a POST body containing a well formed Xsl-FO Xml document (like these Apache FOP samples). The service will respond with the rendered Pdf binary (file bytes).
If an error occurs -- likely due to incorrect Xsl-FO syntax or structure -- then an Http 500 Response will be returned with a JSON payload containing details about the error. Fo
