Running Apache FOP in Docker
08 Jun 2020 • Christian Wahl
One of my interests is XML and with that interest, a tail of related technologies. Over the years I have spend a lot of time on XSL transforming “stuff”. From time to time I have also used Apache FOP, a tool for generating PDF files from XML using XSL formatting objects (XSL-FO). This tool require Java – like everything else – back then. But now, not so much. So, actually I don’t have Java installed.
The question is: how can I run FOP without all the hassle of installing Java? Here Docker comes to the rescue. From previous experiences with FOP I knew that I needed Sun/Oracle Java. I don’t know the details, but fortunately FOP version 2.5 can also run under OpenJDK. This made it even easier to get up and running.
Before getting into the details – this is the final Dockerfile:
FROM ubuntu
ENV PATH "$PATH:/usr/local/fop-2.5/fop"
RUN apt-get update
RUN apt-get install -y default-jre
RUN apt-get install -y wget
RUN wget http://ftp.download-by.net/apache/xmlgraphics/fop/binaries/fop-2.5-bin.tar.gz
RUN tar -xvzf fop-2.5-bin.tar.gz -C /usr/local
ENTRYPOINT ["fop"]
CMD ["-version"]
Details:
- The starting point is the latest Ubuntu image:
FROM ubuntu. I haven’t looked into other options. - To be able to call fop from the shell I need to add the path of the installation to the PATH environment variable:
ENV PATH "$PATH:/usr/local/fop-2.5/fop". I struggled a lot with this, adding the path to /etc/profile and ~/.bashrc, and running bothsource /etc/profileand. /etc/profileetc. and finally ended with this simple solution. - I need both Java and wget installed.
RUN apt-get updatewill download all the PPAs. And the runningRUN apt-get install -y default-jreandRUN apt-get install -y wget, both with the -y flag will install the two applications.default-jreis an alias for OpenJDK. - Now, I can download the files for fop:
RUN wget http://ftp.download-by.net/apache/xmlgraphics/fop/binaries/fop-2.5-bin.tar.gz. - And extract the tar.gz file into the
/usr/localdirectory:RUN tar -xvzf fop-2.5-bin.tar.gz -C /usr/local. - Finally I add fop as the entrypoint:
ENTRYPOINT ["fop"]and a default parameter:CMD ["-version"]to fop.
With the Docker file in place an image can be build:
$ docker build -t fop .
The container based on the image will just run as long as the process is running:
$ docker run -it --rm fop
Using Apache FOP
Just to give a practical (and short) example. This is the contents of helloworld.fo:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://www.w3.org/1999/XSL/Format">
<layout-master-set>
<simple-page-master
margin="10mm" page-width="210mm" page-height="297mm"
master-name="simple">
<region-body region-name="simple-body"
margin-bottom="20mm" margin-top="20mm" />
</simple-page-master>
</layout-master-set>
<page-sequence master-reference="simple">
<flow flow-name="simple-body">
<block>Hello World!</block>
</flow>
</page-sequence>
</root>
To generate a PDF file execute:
$ docker run --user $(id -u):$(id -g) -v $(pwd):/src -w /src -it --rm fop helloworld.fo helloworld.pdf
Where --user set the user to be you (instead of root), -v is mapping the current directory to /src, -w is setting the working directory to /src and fop helloworld.fo helloworld.pdf will generate a PDF file and save it in the working directory.