GraalVM support

Table of Contents

Introduction

Tomcat supports using the GraalVM/Mandrel Native Image tool to produce a native binary including the container. This documentation page describes the build process of such an image.

Setup

The native image tool is much easier to use with single JARs, as a result the process will use the Maven shade plugin JAR packaging (fat JAR). The idea is to produce a single JAR that contains all necessary classes from Tomcat, the webapps and all additional dependencies. Although Tomcat has received compatibility fixes to support native images, any library may not be compatible and may require replacement code (the GraalVM documentation has more details about this). Download and install GraalVM or Mandrel. If using GraalVM, the first step is then to add the Native Image tool. export JAVA_HOME=/absolute...path...to/graalvm-ce-javaX-x.y.z cd $JAVA_HOME/bin ./gu install native-image export JAVA_HOME=/absolute...path...to/mandrel-javaXX-platform-x.x.x.x/mandrelJDK Mandrel already includes the Native Image tool ready to use, so this step can be skipped. Only JAVA_HOME must be set to the folder which contains the bin folder with the JVM binaries, such as: Download the Tomcat Stuffed module from https://github.com/apache/tomcat/tree/master/modules/stuffed and place all the files in a folder stuffed in this documentation. export TOMCAT_STUFFED=/absolute...path...to/stuffed The build process now requires both Ant and Maven.

Packaging and Building

Inside the tomcat-stuffed folder, the directory structure is the same as for regular Tomcat. The main configuration files are placed in the conf folder, and if using the default server.xml the webapps are placed in the webapps folder. The first step is to build the fat Tomcat JAR with all dependencies. Any JSP in the webapp must all be precompiled and packaged. cd $TOMCAT_STUFFED mvn package ant -Dwebapp.name=somewebapp -f webapp-jspc.ant.xml mvn package Dependencies for the webapp should now be added to the main pom.xml, following with building the complete fat JAR. As it is best to avoid using reflection whenever possible with Ahead of Time compilation, it can be a good idea to generate and compile Tomcat Embedded code out of the main server.xml configuration as well as the context.xml files used to configure the contexts. $JAVA_HOME/bin/java\ -Dcatalina.base=. -Djava.util.logging.config.file=conf/logging.properties\ -jar target/tomcat-stuffed-1.0.jar --catalina -generateCode src/main/java mvn package --catalina -useGeneratedCode arguments are added to the command lines. If this was not the case, they should be removed. The rest of the process described here will assume this step was done and thearguments are added to the command lines. If this was not the case, they should be removed.

Native image configuration

Native images do not support any form of dynamic classloading or reflection unless it is defined explicitly in descriptors. Generating them uses a tracing agent from the GraalVM, and needs additional manual configuration in some cases. Run the GraalVM substrate VM using the trace agent: $JAVA_HOME/bin/java\ -agentlib:native-image-agent=config-output-dir=$TOMCAT_STUFFED/target/\ -Dorg.graalvm.nativeimage.imagecode=agent\ -Dcatalina.base=. -Djava.util.logging.config.file=conf/logging.properties\ -jar target/tomcat-stuffed-1.0.jar --catalina -useGeneratedCode Now all paths from the webapp that lead to dynamic classloading (ex: Servlet access, websockets, etc) need to be accessed using a script that will exercise the webapp. Servlets may be loaded on startup instead of needing an actual access. Listeners may also be used to load additional classes on startup. The descriptors have now been generated in the agent output directory. At this point, further configuration must be made to add items that are not traced, including: base interfaces, resource bundles, BeanInfo based reflection, etc. Please refer to the Graal documentation for more information on this process.

Building the native image

If everything has been done properly, the native image can now be built using the native-image tool. $JAVA_HOME/bin/native-image --no-server\ --allow-incomplete-classpath --enable-https\ --initialize-at-build-time=org.eclipse.jdt,org.apache.el.parser.SimpleNode,javax.servlet.jsp.JspFactory,org.apache.jasper.servlet.JasperInitializer,org.apache.jasper.runtime.JspFactoryImpl\ -H:+JNI -H:+ReportUnsupportedElementsAtRuntime\ -H:+ReportExceptionStackTraces -H:EnableURLProtocols=http,https,jar,jrt\ -H:ConfigurationFileDirectories=$TOMCAT_STUFFED/target/\ -H:ReflectionConfigurationFiles=$TOMCAT_STUFFED/tomcat-reflection.json\ -H:ResourceConfigurationFiles=$TOMCAT_STUFFED/tomcat-resource.json\ -H:JNIConfigurationFiles=$TOMCAT_STUFFED/tomcat-jni.json\ -jar $TOMCAT_STUFFED/target/tomcat-stuffed-1.0.jar --static parameter enables static linking of glibc, zlib and libstd++ in the generated binary. The additionalparameter enables static linking of glibc, zlib and libstd++ in the generated binary. Running the native image is then: ./tomcat-stuffed-1.0 -Dcatalina.base=. -Djava.util.logging.config.file=conf/logging.properties --catalina -useGeneratedCode

Compatibility