This blog post will explain how to run large Java applications on Apache OpenWhisk.
Java actions are deployed from JAR files containing application class files. External libraries can be used by bundling those dependencies into a fat JAR file. The JAR file must be less than the maximum action size of 48MB.
So, what if the application uses lots of external libraries and the JAR file is larger than 48MB? 🤔
Apache OpenWhisk’s support for custom Docker runtimes provides a workaround. In a previous blog post, we showed how this feature could be used with Python applications which rely on lots of external libraries.
Using the same approach with Java, a custom Java runtime can be created with additional libraries pre-installed. Those libraries do not need to be included in the application jar, which will just contain private class files. This should hopefully reduce the JAR file to under the action size limit.
Let’s walk through an example to show how this works….
Example Java Class using External Libraries
import com.google.gson.JsonObject;
import org.apache.commons.text.WordUtils;
public class Capitialize {
public static JsonObject main(JsonObject args) {
String name = args.getAsJsonPrimitive("message").getAsString();
JsonObject response = new JsonObject();
response.addProperty("capitalized", WordUtils.capitalize(name));
return response;
}
}
This example Java action capitalises sentences from the input event. It uses the Apache Commons Text library to handle [capitialisation](https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/WordUtils.html#capitalize(java.lang.String)) of input strings. This external library will be installed in the runtime, rather than bundled in the application JAR file.
Build Custom Java Runtime
- Clone the existing Apache OpenWhisk Java runtime repository.
git clone https://github.com/apache/incubator-openwhisk-runtime-java
- Edit the
core/java8/proxy/build.gradle
file and update thedependencies
configuration with extra dependencies needed in the runtime.
dependencies {
compile 'com.google.code.gson:gson:2.6.2'
compile 'org.apache.commons:commons-text:1.6' // <-- the additional library
}
Note: com.google.code.gson:gson:2.6.2
is used by the runtime to handle JSON encoding/decoding. Do not remove this dependency.
- Execute the following command to build the custom Docker image.
./gradlew core:java8:distDocker
Push Image To Docker Hub
If the build process succeeds, a local Docker image named java8action
should be available. This needs to be pushed to Docker Hub to allow Apache OpenWhisk to use it.
- Tag the custom image with a Docker Hub username.
docker tag java8action <DOCKERHUB_USERNAME>/java8action
- Push the tagged custom image to Docker Hub.
docker push <DOCKERHUB_USERNAME>/java8action
Create OpenWhisk Action With Custom Runtime
- Compile the Java source file.
javac Capitialize.java
- Create the application JAR from the class file.
jar cvf capitialize.jar Capitialize.class
- Create the Java action with the custom runtime.
wsk action create capitialize capitialize.jar --main Capitialize --docker <DOCKERHUB_USERNAME>/java8action
--main
is the class file name containing the action handler in the JAR file. --docker
is the Docker image name for the custom runtime.
Test it out!
- Execute the
capitialize
action with input text to returned capitalised sentences.
wsk action invoke capitialize -b -r -p message "this is a sentence"
If this works, the following JSON should be printed to the console.
{
"capitalized": "This Is A Sentence"
}
The external library has been used in the application without including it in the application JAR file! 💯💯💯
Conclusion
Apache OpenWhisk supports running Java applications using fat JARs, which bundle application source code and external dependencies. JAR files cannot be more than 48MB, which can be challenging when applications uses lots of external libraries.
If application source files and external libraries result in JAR files larger than this limit, Apache OpenWhisk’s support for custom Docker runtimes provide a solution for running large Java applications on the platform.
By building a custom Java runtime, extra libraries can be pre-installed in the runtime. These dependencies do not need to be included in the application JAR file, which reduces the file size to under the action size limit. 👍