diff --git a/environments/jvm-jersey/.gitignore b/environments/jvm-jersey/.gitignore
new file mode 100644
index 00000000..809cc8f2
--- /dev/null
+++ b/environments/jvm-jersey/.gitignore
@@ -0,0 +1,2 @@
+target/
+bin/
diff --git a/environments/jvm-jersey/Dockerfile b/environments/jvm-jersey/Dockerfile
new file mode 100644
index 00000000..a4b04096
--- /dev/null
+++ b/environments/jvm-jersey/Dockerfile
@@ -0,0 +1,15 @@
+FROM maven:3.5-jdk-8 as BUILD
+WORKDIR /usr/src/myapp/
+
+# To reuse the build cache, here we split maven dependency
+# download and package into two RUN commands to avoid cache invalidation.
+COPY pom.xml .
+RUN mvn dependency:go-offline
+
+COPY src /usr/src/myapp/src/
+RUN mvn package
+
+FROM openjdk:8-jre-alpine
+COPY --from=BUILD /usr/src/myapp/target/env-jvm-jersey-0.0.1.jar /app.jar
+ENTRYPOINT java ${JVM_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar 8888
+EXPOSE 8888
diff --git a/environments/jvm-jersey/Dockerfile-11 b/environments/jvm-jersey/Dockerfile-11
new file mode 100644
index 00000000..37353798
--- /dev/null
+++ b/environments/jvm-jersey/Dockerfile-11
@@ -0,0 +1,15 @@
+FROM maven:3.6-jdk-11 as BUILD
+WORKDIR /usr/src/myapp/
+
+# To reuse the build cache, here we split maven dependency
+# download and package into two RUN commands to avoid cache invalidation.
+COPY pom.xml .
+RUN mvn dependency:go-offline
+
+COPY src /usr/src/myapp/src/
+RUN mvn package
+
+FROM openjdk:11-jre
+COPY --from=BUILD /usr/src/myapp/target/env-jvm-jersey-0.0.1.jar /app.jar
+ENTRYPOINT java ${JVM_OPTS} -Djava.security.egd=file:/dev/./urandom -jar /app.jar --server.port=8888
+EXPOSE 8888
diff --git a/environments/jvm-jersey/README.md b/environments/jvm-jersey/README.md
new file mode 100644
index 00000000..2a6278d9
--- /dev/null
+++ b/environments/jvm-jersey/README.md
@@ -0,0 +1,68 @@
+# Fission: Java and JVM-Jersey Environment
+
+This is the JVM (Jersey based) environment for Fission.
+
+It's a Docker image containing a OpenJDK8 runtime, along with a
+dynamic loader. A few dependencies are included in the
+pom.xml file.
+
+Unlike the other [JVM environment](../jvm) which is based on the Spring framework, this environment uses Jersey.
+
+Looking for ready-to-run examples? See the [JVM examples directory](../../examples/jvm-jersey).
+
+## Customizing this image
+
+To add package dependencies, edit pom.xml to add what you
+need, and rebuild this image (instructions below).
+
+## Rebuilding and pushing the image
+
+You'll need access to a Docker registry to push the image: you can
+sign up for Docker hub at hub.docker.com, or use registries from
+gcr.io, quay.io, etc. Let's assume you're using a docker hub account
+called USER. Build and push the image to the the registry:
+
+```
+ docker build -t USER/jvm-jersey-env . && docker push USER/jvm-jersey-env
+```
+
+You can also create environment image based on JVM 11 using Dockerfile-11 in this directory.
+
+## Using the image in fission
+
+You can add this customized image to fission with "fission env
+create":
+
+```
+ fission env create --name jvm --image USER/jvm-jersey-env
+```
+
+Or, if you already have an environment, you can update its image:
+
+```
+ fission env update --name jvm --image USER/jvm-jersey-env
+```
+
+After this, fission functions that have the env parameter set to the
+same environment name as this command will use this environment.
+
+## Web Server Framework
+
+JVM Jersey environment uses an embedded Jetty HTTP server by default, as can be seen in the pom.xml file.
+
+```
+
+ org.eclipse.jetty
+ jetty-server
+ 9.0.4.v20130625
+
+
+ org.eclipse.jetty
+ jetty-servlet
+ 9.0.4.v20130625
+
+```
+
+## Java and JVM builder
+
+There are two JVM environment builder based on OpenJDK8 and OpenJDK 11 and using Maven 3.5.4. The default build command runs `mvn clean package` and uses the target/*with-dependencies.jar file for function. The default build command can be overridden as long as the uber jar file is copied to ${DEPLOY_PKG}.
diff --git a/environments/jvm-jersey/builder/Dockerfile b/environments/jvm-jersey/builder/Dockerfile
new file mode 100644
index 00000000..24db019a
--- /dev/null
+++ b/environments/jvm-jersey/builder/Dockerfile
@@ -0,0 +1,48 @@
+## Fission builder base image
+ARG BUILDER_IMAGE=fission/builder:latest
+FROM ${BUILDER_IMAGE}
+
+## Section copied from the openjdk:8-jdk-alpine Dockerfile - (https://github.com/docker-library/openjdk/blob/47a6539cd18023dafb45db9013455136cc0bca07/8/jdk/alpine/Dockerfile)
+
+ENV LANG C.UTF-8
+RUN { \
+ echo '#!/bin/sh'; \
+ echo 'set -e'; \
+ echo; \
+ echo 'dirname "$(dirname "$(readlink -f "$(which javac || which java)")")"'; \
+ } > /usr/local/bin/docker-java-home \
+ && chmod +x /usr/local/bin/docker-java-home
+ENV JAVA_HOME /usr/lib/jvm/java-1.8-openjdk
+ENV PATH $PATH:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin
+
+ENV JAVA_VERSION 8u181
+## Use "fuzzy" version matching to pin the version to a major/minor release
+ENV JAVA_ALPINE_VERSION "~8"
+
+RUN set -x \
+ && apk add --no-cache \
+ openjdk8="$JAVA_ALPINE_VERSION" \
+ && [ "$JAVA_HOME" = "$(docker-java-home)" ]
+
+## Section copied from the Maven Dockerfile
+
+RUN apk add --no-cache curl tar bash procps
+
+ARG MAVEN_VERSION=3.5.4
+ARG USER_HOME_DIR="/root"
+ARG SHA=ce50b1c91364cb77efe3776f756a6d92b76d9038b0a0782f7d53acf1e997a14d
+ARG BASE_URL=https://apache.osuosl.org/maven/maven-3/${MAVEN_VERSION}/binaries
+
+RUN mkdir -p /usr/share/maven /usr/share/maven/ref \
+ && curl -fsSL -o /tmp/apache-maven.tar.gz ${BASE_URL}/apache-maven-${MAVEN_VERSION}-bin.tar.gz \
+ && echo "${SHA} /tmp/apache-maven.tar.gz" | sha256sum -c - \
+ && tar -xzf /tmp/apache-maven.tar.gz -C /usr/share/maven --strip-components=1 \
+ && rm -f /tmp/apache-maven.tar.gz \
+ && ln -s /usr/share/maven/bin/mvn /usr/bin/mvn
+
+ENV MAVEN_HOME /usr/share/maven
+ENV MAVEN_CONFIG "$USER_HOME_DIR/.m2"
+
+## Fission builder specific section
+ADD build.sh /usr/local/bin/build
+EXPOSE 8001
diff --git a/environments/jvm-jersey/builder/Dockerfile-11 b/environments/jvm-jersey/builder/Dockerfile-11
new file mode 100644
index 00000000..8849d9af
--- /dev/null
+++ b/environments/jvm-jersey/builder/Dockerfile-11
@@ -0,0 +1,43 @@
+## Fission builder base image
+ARG BUILDER_IMAGE=fission/builder:latest
+FROM ${BUILDER_IMAGE}
+
+## Section referred from the openjdk:8-jdk-alpine Dockerfile - (https://github.com/docker-library/openjdk/blob/47a6539cd18023dafb45db9013455136cc0bca07/8/jdk/alpine/Dockerfile)
+
+ENV LANG C.UTF-8
+RUN { \
+ echo '#!/bin/sh'; \
+ echo 'set -e'; \
+ echo; \
+ echo 'dirname "$(dirname "$(readlink -f "$(which javac || which java)")")"'; \
+ } > /usr/local/bin/docker-java-home \
+ && chmod +x /usr/local/bin/docker-java-home
+ENV JAVA_HOME /usr/lib/jvm/java-11-openjdk
+ENV PATH $PATH:/usr/lib/jvm/java-11-openjdk/jre/bin:/usr/lib/jvm/java-11-openjdk/bin
+
+RUN set -x \
+ && apk add --no-cache openjdk11 \
+ && [ "$JAVA_HOME" = "$(docker-java-home)" ]
+
+## Section copied from the Maven Dockerfile
+
+RUN apk add --no-cache curl tar bash procps
+
+ARG MAVEN_VERSION=3.5.4
+ARG USER_HOME_DIR="/root"
+ARG SHA=ce50b1c91364cb77efe3776f756a6d92b76d9038b0a0782f7d53acf1e997a14d
+ARG BASE_URL=https://apache.osuosl.org/maven/maven-3/${MAVEN_VERSION}/binaries
+
+RUN mkdir -p /usr/share/maven /usr/share/maven/ref \
+ && curl -fsSL -o /tmp/apache-maven.tar.gz ${BASE_URL}/apache-maven-${MAVEN_VERSION}-bin.tar.gz \
+ && echo "${SHA} /tmp/apache-maven.tar.gz" | sha256sum -c - \
+ && tar -xzf /tmp/apache-maven.tar.gz -C /usr/share/maven --strip-components=1 \
+ && rm -f /tmp/apache-maven.tar.gz \
+ && ln -s /usr/share/maven/bin/mvn /usr/bin/mvn
+
+ENV MAVEN_HOME /usr/share/maven
+ENV MAVEN_CONFIG "$USER_HOME_DIR/.m2"
+
+## Fission builder specific section
+ADD build.sh /usr/local/bin/build
+EXPOSE 8001
diff --git a/environments/jvm-jersey/builder/build.sh b/environments/jvm-jersey/builder/build.sh
new file mode 100755
index 00000000..bf167d59
--- /dev/null
+++ b/environments/jvm-jersey/builder/build.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+set -eou pipefail
+mvn clean package
+cp ${SRC_PKG}/target/*with-dependencies.jar ${DEPLOY_PKG}
\ No newline at end of file
diff --git a/environments/jvm-jersey/pom.xml b/environments/jvm-jersey/pom.xml
new file mode 100644
index 00000000..bdc79452
--- /dev/null
+++ b/environments/jvm-jersey/pom.xml
@@ -0,0 +1,86 @@
+
+
+ 4.0.0
+
+ io.fission
+ env-jvm-jersey
+ 0.0.1
+
+
+ 1.6
+ 1.6
+
+
+
+
+ io.fission
+ fission-jvm-jersey
+ 0.0.1
+
+
+ org.eclipse.jetty
+ jetty-server
+ 9.0.4.v20130625
+
+
+ org.eclipse.jetty
+ jetty-servlet
+ 9.0.4.v20130625
+
+
+ org.glassfish.jersey.containers
+ jersey-container-servlet-core
+ 2.0
+
+
+ org.glassfish.jersey.media
+ jersey-media-json-jackson
+ 2.0
+
+
+ javax.xml
+ jaxb-api
+ 2.1
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.1
+
+ ${java.source.level}
+ ${java.target.level}
+ UTF-8
+ true
+ true
+
+
+
+ maven-assembly-plugin
+
+
+
+ io.fission.Main
+
+
+
+ jar-with-dependencies
+
+ false
+
+
+
+ package
+
+ single
+
+
+
+
+
+
+
diff --git a/environments/jvm-jersey/src/main/java/io/fission/FunctionLoadRequest.java b/environments/jvm-jersey/src/main/java/io/fission/FunctionLoadRequest.java
new file mode 100644
index 00000000..02d3e65a
--- /dev/null
+++ b/environments/jvm-jersey/src/main/java/io/fission/FunctionLoadRequest.java
@@ -0,0 +1,35 @@
+package io.fission;
+
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class FunctionLoadRequest {
+
+ private String filepath;
+ private String functionName;
+ private String url;
+
+ String getFilepath() {
+ return filepath;
+ }
+
+ void setFilepath(String filepath) {
+ this.filepath = filepath;
+ }
+
+ String getUrl() {
+ return url;
+ }
+
+ void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getFunctionName() {
+ return functionName;
+ }
+
+ public void setFunctionName(String functionName) {
+ this.functionName = functionName;
+ }
+}
diff --git a/environments/jvm-jersey/src/main/java/io/fission/JerseyServer.java b/environments/jvm-jersey/src/main/java/io/fission/JerseyServer.java
new file mode 100644
index 00000000..492d0164
--- /dev/null
+++ b/environments/jvm-jersey/src/main/java/io/fission/JerseyServer.java
@@ -0,0 +1,147 @@
+package io.fission;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.container.ContainerRequestContext;
+
+import io.fission.Function;
+
+@Path("/")
+public class JerseyServer {
+
+ private static Function fn;
+
+ private static final int CLASS_LENGTH = 6;
+
+ private static Logger logger = Logger.getGlobal();
+
+ @GET
+ public Response home(@Context ContainerRequestContext request) {
+ return callUserFunction(request);
+ }
+
+ @POST
+ public Response homePost(@Context ContainerRequestContext request) {
+ return callUserFunction(request);
+ }
+
+ @PUT
+ public Response homePut(@Context ContainerRequestContext request) {
+ return callUserFunction(request);
+ }
+
+ @DELETE
+ public Response homeDelete(@Context ContainerRequestContext request) {
+ return callUserFunction(request);
+ }
+
+ @Path("v2/specialize")
+ @POST
+ public Response specialize(FunctionLoadRequest req) {
+
+ long startTime = System.nanoTime();
+ File file = new File(req.getFilepath());
+
+ if (!file.exists()) {
+ return Response.status(Response.Status.BAD_REQUEST).entity("/userfunc/usernot found").build();
+ }
+
+ String entryPoint = req.getFunctionName();
+ logger.log(Level.INFO, "Entrypoint class:" + entryPoint);
+ if (entryPoint == null) {
+ return Response.status(Response.Status.BAD_REQUEST).entity("Entrypoint class is missing in the JAR or the name is incorrect")
+ .build();
+ }
+
+ JarFile jarFile = null;
+ ClassLoader cl = null;
+ try {
+
+ jarFile = new JarFile(file);
+ Enumeration e = jarFile.entries();
+ URL[] urls = { new URL("jar:file:" + file + "!/") };
+
+ // TODO Check if the classloading can be improved for ex. use something like:
+ // Thread.currentThread().setContextClassLoader(cl);
+ if (this.getClass().getClassLoader() == null) {
+ cl = URLClassLoader.newInstance(urls);
+ } else {
+ cl = URLClassLoader.newInstance(urls, this.getClass().getClassLoader());
+ }
+
+ if (cl == null) {
+
+ return Response.status(Response.Status.BAD_REQUEST).entity("Failed to initialize the classloader")
+ .build();
+ }
+
+ // Load all dependent classes from libraries etc.
+ while (e.hasMoreElements()) {
+ JarEntry je = e.nextElement();
+ if (je.isDirectory() || !je.getName().endsWith(".class")) {
+ continue;
+ }
+ String className = je.getName().substring(0, je.getName().length() - CLASS_LENGTH);
+ className = className.replace('/', '.');
+ cl.loadClass(className);
+ }
+
+ // Instantiate the function class
+ fn = (Function) cl.loadClass(entryPoint).newInstance();
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ return Response.status(Response.Status.BAD_REQUEST).entity("Entrypoint class is missing in the function")
+ .build();
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ return Response.status(Response.Status.BAD_REQUEST).entity("Error loading Function or dependent class")
+ .build();
+ } catch (InstantiationException e) {
+ e.printStackTrace();
+ return Response.status(Response.Status.BAD_REQUEST)
+ .entity("Error creating a new instance of function class").build();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ return Response.status(Response.Status.BAD_REQUEST)
+ .entity("Error creating a new instance of function class").build();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return Response.status(Response.Status.BAD_REQUEST).entity("Error reading the JAR file").build();
+ } finally {
+ try {
+ jarFile.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return Response.status(Response.Status.BAD_REQUEST)
+ .entity("Error closing the file while loading the class").build();
+ }
+ }
+ long elapsedTime = System.nanoTime() - startTime;
+ logger.log(Level.INFO, "Specialize call done in: " + elapsedTime / 1000000 + " ms");
+ return Response.status(Response.Status.OK).entity("Done").build();
+ }
+
+ private Response callUserFunction(ContainerRequestContext httpRequest) {
+ if (fn == null) {
+ return Response.status(Response.Status.BAD_REQUEST).entity("Container not specialized").build();
+ } else {
+ return fn.call(httpRequest, null);
+ }
+ }
+}
diff --git a/environments/jvm-jersey/src/main/java/io/fission/Main.java b/environments/jvm-jersey/src/main/java/io/fission/Main.java
new file mode 100644
index 00000000..a3148f1c
--- /dev/null
+++ b/environments/jvm-jersey/src/main/java/io/fission/Main.java
@@ -0,0 +1,50 @@
+package io.fission;
+
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.glassfish.jersey.jackson.JacksonFeature;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.servlet.ServletContainer;
+
+public class Main {
+
+ private static final int DEFAULT_PORT = 8888;
+
+ private int serverPort;
+
+ public Main(int serverPort) throws Exception {
+ this.serverPort = serverPort;
+ Server server = configureServer();
+ server.start();
+ server.join();
+ }
+
+ private Server configureServer() {
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig.packages(JerseyServer.class.getPackage().getName());
+ resourceConfig.register(JacksonFeature.class);
+ ServletContainer servletContainer = new ServletContainer(resourceConfig);
+ ServletHolder sh = new ServletHolder(servletContainer);
+ Server server = new Server(serverPort);
+ ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
+ context.setContextPath("/");
+ context.addServlet(sh, "/*");
+ server.setHandler(context);
+ return server;
+ }
+
+ public static void main(String[] args) throws Exception {
+
+ int serverPort = DEFAULT_PORT;
+
+ if(args.length >= 1) {
+ try {
+ serverPort = Integer.parseInt(args[0]);
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ }
+ }
+ new Main(serverPort);
+ }
+}
diff --git a/examples/jvm-jersey/java/.gitignore b/examples/jvm-jersey/java/.gitignore
new file mode 100644
index 00000000..4c3f8757
--- /dev/null
+++ b/examples/jvm-jersey/java/.gitignore
@@ -0,0 +1,4 @@
+.project
+.settings
+.classpath
+target/
diff --git a/examples/jvm-jersey/java/README.md b/examples/jvm-jersey/java/README.md
new file mode 100644
index 00000000..1c9bf76e
--- /dev/null
+++ b/examples/jvm-jersey/java/README.md
@@ -0,0 +1,60 @@
+# Hello World in JVM/Java on Fission
+
+The `io.fission.HelloWorld.java` class is a very simple fission function that implements `io.fission.Function` and says "Hello, World!" .
+
+## Building and deploying using Fission
+
+Fission's builder can be used to create the binary artifact from source code. Create an environment with builder image and then create a package.
+
+```
+$ zip -r java-src-pkg.zip *
+$ fission env create --name java --image fission/jvm-env --version 2 --keeparchive --builder fission/jvm-builder
+$ fission package create --sourcearchive java-src-pkg.zip --env java
+java-src-pkg-zip-tvd0
+$ fission package info --name java-src-pkg-zip-tvd0
+Name: java-src-pkg-zip-tvd0
+Environment: java
+Status: succeeded
+Build Logs:
+[INFO] Scanning for projects...
+[INFO]
+[INFO] -----------------------< io.fission:hello-world >-----------------------
+[INFO] Building hello-world 1.0-SNAPSHOT
+[INFO] --------------------------------[ jar ]---------------------------------
+```
+
+Once package's status is `succeeded` then that package can be used to create and execute a function.
+
+```
+$ fission fn create --name hello --pkg java-src-pkg-zip-tvd0 --env java --entrypoint io.fission.HelloWorld
+$ fission fn test --name hello
+Hello World!
+```
+
+## Building locally and deploying with Fission
+
+You can build the jar file in one of the two ways below based on your setup:
+
+- You can use docker without the need to install JDK and Maven to build the jar file from source code:
+
+```bash
+$ bash -x ./build.sh
+
+```
+- If you have JDK and Maven installed, you can directly build the JAR file using command:
+
+```
+$ mvn clean package
+```
+
+Both of above steps will generate a target subdirectory which has the archive `target/hello-world-1.0-SNAPSHOT-jar-with-dependencies.jar` which will be used for creating function.
+
+- The archive created above will be used as a deploy package when creating the function.
+
+```
+$ fission env create --name jvm --image fission/jvm-env --version 2 --keeparchive=true
+$ fission fn create --name hello --deploy target/hello-world-1.0-SNAPSHOT-jar-with-dependencies.jar --env jvm --entrypoint io.fission.HelloWorld
+$ fission route create --function hello --url /hellop --method GET
+$ fission fn test --name hello
+Hello World!
+```
diff --git a/examples/jvm-jersey/java/build.sh b/examples/jvm-jersey/java/build.sh
new file mode 100755
index 00000000..abac4200
--- /dev/null
+++ b/examples/jvm-jersey/java/build.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# This script allows you to build the jar without needing Maven & JDK installed locally.
+# You need docker, as it uses a Docker image to build source code
+set -eou pipefail
+docker run -it --rm -v "$(pwd)":/usr/src/mymaven -w /usr/src/mymaven maven:3.5-jdk-8 mvn clean package
diff --git a/examples/jvm-jersey/java/pom.xml b/examples/jvm-jersey/java/pom.xml
new file mode 100644
index 00000000..efc5fdf0
--- /dev/null
+++ b/examples/jvm-jersey/java/pom.xml
@@ -0,0 +1,76 @@
+
+
+ 4.0.0
+ io.fission
+ jersey-hello-world
+ 0.0.1
+ jar
+
+ hello-world
+ http://maven.apache.org
+
+
+ UTF-8
+ 1.6
+ 1.6
+
+
+
+
+ io.fission
+ fission-jvm-jersey
+ 0.0.1
+ provided
+
+
+ javax.ws.rs
+ javax.ws.rs-api
+ 2.0
+ provided
+
+
+ org.glassfish.jersey.containers
+ jersey-container-servlet-core
+ 2.0
+ test
+
+
+ junit
+ junit
+ 4.13
+ test
+
+
+
+
+
+
+ maven-assembly-plugin
+
+
+ jar-with-dependencies
+
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.22.1
+
+ false
+
+
+
+
+
+
diff --git a/examples/jvm-jersey/java/specs/README b/examples/jvm-jersey/java/specs/README
new file mode 100644
index 00000000..1db3f9a5
--- /dev/null
+++ b/examples/jvm-jersey/java/specs/README
@@ -0,0 +1,42 @@
+
+Fission Specs
+=============
+
+This is a set of specifications for a Fission app. This includes functions,
+environments, and triggers; we collectively call these things "resources".
+
+How to use these specs
+----------------------
+
+These specs are handled with the 'fission spec' command. See 'fission spec --help'.
+
+'fission spec apply' will "apply" all resources specified in this directory to your
+cluster. That means it checks what resources exist on your cluster, what resources are
+specified in the specs directory, and reconciles the difference by creating, updating or
+deleting resources on the cluster.
+
+'fission spec apply' will also package up your source code (or compiled binaries) and
+upload the archives to the cluster if needed. It uses 'ArchiveUploadSpec' resources in
+this directory to figure out which files to archive.
+
+You can use 'fission spec apply --watch' to watch for file changes and continuously keep
+the cluster updated.
+
+You can add YAMLs to this directory by writing them manually, but it's easier to generate
+them. Use 'fission function create --spec' to generate a function spec,
+'fission environment create --spec' to generate an environment spec, and so on.
+
+You can edit any of the files in this directory, except 'fission-deployment-config.yaml',
+which contains a UID that you should never change. To apply your changes simply use
+'fission spec apply'.
+
+fission-deployment-config.yaml
+------------------------------
+
+fission-deployment-config.yaml contains a UID. This UID is what fission uses to correlate
+resources on the cluster to resources in this directory.
+
+All resources created by 'fission spec apply' are annotated with this UID. Resources on
+the cluster that are _not_ annotated with this UID are never modified or deleted by
+fission.
+
diff --git a/examples/jvm-jersey/java/specs/env-java.yaml b/examples/jvm-jersey/java/specs/env-java.yaml
new file mode 100644
index 00000000..78b2db7b
--- /dev/null
+++ b/examples/jvm-jersey/java/specs/env-java.yaml
@@ -0,0 +1,17 @@
+apiVersion: fission.io/v1
+kind: Environment
+metadata:
+ creationTimestamp: null
+ name: java-jersey
+ namespace: default
+spec:
+ builder:
+ command: build
+ image: fission/jvm-jersey-builder
+ imagepullsecret: ""
+ keeparchive: true
+ poolsize: 3
+ resources: {}
+ runtime:
+ image: fission/jvm-jersey-env
+ version: 2
diff --git a/examples/jvm-jersey/java/specs/fission-deployment-config.yaml b/examples/jvm-jersey/java/specs/fission-deployment-config.yaml
new file mode 100644
index 00000000..24e5e094
--- /dev/null
+++ b/examples/jvm-jersey/java/specs/fission-deployment-config.yaml
@@ -0,0 +1,7 @@
+# This file is generated by the 'fission spec init' command.
+# See the README in this directory for background and usage information.
+# Do not edit the UID below: that will break 'fission spec apply'
+apiVersion: fission.io/v1
+kind: DeploymentConfig
+name: java-jersey
+uid: 908a303a-bf23-4bae-a22c-b1db9a1f71a9
diff --git a/examples/jvm-jersey/java/specs/function-hello.yaml b/examples/jvm-jersey/java/specs/function-hello.yaml
new file mode 100644
index 00000000..9dd85f65
--- /dev/null
+++ b/examples/jvm-jersey/java/specs/function-hello.yaml
@@ -0,0 +1,27 @@
+apiVersion: fission.io/v1
+kind: Function
+metadata:
+ creationTimestamp: null
+ name: hello
+ namespace: default
+spec:
+ InvokeStrategy:
+ ExecutionStrategy:
+ ExecutorType: poolmgr
+ MaxScale: 0
+ MinScale: 0
+ SpecializationTimeout: 120
+ TargetCPUPercent: 0
+ StrategyType: execution
+ configmaps: null
+ environment:
+ name: java-jersey
+ namespace: default
+ functionTimeout: 60
+ package:
+ functionName: io.fission.HelloWorld
+ packageref:
+ name: hellojava
+ namespace: default
+ resources: {}
+ secrets: null
diff --git a/examples/jvm-jersey/java/specs/package-hellojava.yaml b/examples/jvm-jersey/java/specs/package-hellojava.yaml
new file mode 100644
index 00000000..f606e112
--- /dev/null
+++ b/examples/jvm-jersey/java/specs/package-hellojava.yaml
@@ -0,0 +1,26 @@
+include:
+- src
+- pom.xml
+kind: ArchiveUploadSpec
+name: src-URlE
+
+---
+apiVersion: fission.io/v1
+kind: Package
+metadata:
+ creationTimestamp: null
+ name: hellojavajersey
+ namespace: default
+spec:
+ deployment:
+ checksum: {}
+ environment:
+ name: java-jersey
+ namespace: default
+ source:
+ checksum: {}
+ type: url
+ url: archive://src-URlE
+status:
+ buildstatus: pending
+ lastUpdateTimestamp: "2020-01-29T09:43:56Z"
diff --git a/examples/jvm-jersey/java/src/main/java/io/fission/HelloWorld.java b/examples/jvm-jersey/java/src/main/java/io/fission/HelloWorld.java
new file mode 100644
index 00000000..29039300
--- /dev/null
+++ b/examples/jvm-jersey/java/src/main/java/io/fission/HelloWorld.java
@@ -0,0 +1,25 @@
+package io.fission;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.container.ContainerRequestContext;
+import io.fission.Function;
+import java.io.BufferedReader;
+import java.util.stream.Collectors;
+import java.io.InputStreamReader;
+
+public class HelloWorld implements Function {
+
+ public static final String RETURN_STRING = "Hello World!";
+
+ @Override
+ public Response call(ContainerRequestContext request, Context arg1) {
+ if(request.getMethod().equals("GET")) {
+ return Response.ok(RETURN_STRING).build();
+ }
+ else {
+ String body = new BufferedReader(new InputStreamReader(request.getEntityStream())).lines()
+ .parallel().collect(Collectors.joining("\n"));
+ return Response.ok("Echo: " + body).build();
+ }
+ }
+}
diff --git a/examples/jvm-jersey/java/src/test/java/io/fission/HelloWorldTest.java b/examples/jvm-jersey/java/src/test/java/io/fission/HelloWorldTest.java
new file mode 100644
index 00000000..907946d8
--- /dev/null
+++ b/examples/jvm-jersey/java/src/test/java/io/fission/HelloWorldTest.java
@@ -0,0 +1,25 @@
+package io.fission;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import org.glassfish.jersey.server.ContainerRequest;
+import javax.ws.rs.core.Response;
+import org.junit.Assert;
+import org.junit.Test;
+
+
+public class HelloWorldTest {
+
+ @Test
+ public void testResponse() {
+ HelloWorld hw = new HelloWorld();
+ ContainerRequest request = null;
+ try {
+ request = new ContainerRequest(new URI("http://example.com/"),new URI("/hello"),"GET",null,null);
+ } catch (URISyntaxException e) {
+ e.printStackTrace();
+ }
+ Response response = hw.call(request, null);
+ Assert.assertTrue(response.getEntity().toString().equals(HelloWorld.RETURN_STRING));
+ }
+}
diff --git a/hack/release-build.sh b/hack/release-build.sh
index 3ca96028..3b69a2ae 100755
--- a/hack/release-build.sh
+++ b/hack/release-build.sh
@@ -148,6 +148,8 @@ build_all_envs() {
build_env_image "$version" "python" "python-env" "2.7"
build_env_image "$version" "ruby" "ruby-env" ""
build_env_image "$version" "jvm" "jvm-env" ""
+ build_env_image "$version" "jvm-jersey" "jvm-jersey-env" ""
+ build_env_image "$version" "jvm-jersey" "jvm-jersey-env" "11"
build_env_image "$version" "tensorflow-serving" "tensorflow-serving-env" ""
}
@@ -180,19 +182,20 @@ build_all_env_builders() {
local version=$1
# call with version, env dir, image name base, image name variant
- build_env_builder_image "$version" "python" "python-builder" ""
- build_env_builder_image "$version" "binary" "binary-builder" ""
- build_env_builder_image "$version" "go" "go-builder" ""
- build_env_builder_image "$version" "go" "go-builder" "1.11.4"
- build_env_builder_image "$version" "go" "go-builder" "1.12"
- build_env_builder_image "$version" "go" "go-builder" "1.13"
- build_env_builder_image "$version" "go" "go-builder" "1.14"
- build_env_builder_image "$version" "jvm" "jvm-builder" ""
- build_env_builder_image "$version" "nodejs" "node-builder" ""
- build_env_builder_image "$version" "nodejs" "node-builder" "12.16"
- build_env_builder_image "$version" "php7" "php-builder" ""
- build_env_builder_image "$version" "ruby" "ruby-builder" ""
- build_env_builder_image "$version" "dotnet20" "dotnet20-builder" ""
+ build_env_builder_image "$version" "python" "python-builder" ""
+ build_env_builder_image "$version" "binary" "binary-builder" ""
+ build_env_builder_image "$version" "go" "go-builder" ""
+ build_env_builder_image "$version" "go" "go-builder" "1.11.4"
+ build_env_builder_image "$version" "go" "go-builder" "1.12"
+ build_env_builder_image "$version" "go" "go-builder" "1.13"
+ build_env_builder_image "$version" "go" "go-builder" "1.14"
+ build_env_builder_image "$version" "jvm" "jvm-builder" ""
+ build_env_builder_image "$version" "jvm-jersey" "jvm-jersey-builder" ""
+ build_env_builder_image "$version" "jvm-jersey" "jvm-jersey-builder" "11"
+ build_env_builder_image "$version" "nodejs" "node-builder" ""
+ build_env_builder_image "$version" "php7" "php-builder" ""
+ build_env_builder_image "$version" "ruby" "ruby-builder" ""
+ build_env_builder_image "$version" "dotnet20" "dotnet20-builder" ""
}
build_charts() {
diff --git a/hack/release.sh b/hack/release.sh
index f20948b5..406668a7 100755
--- a/hack/release.sh
+++ b/hack/release.sh
@@ -89,6 +89,8 @@ push_all_envs() {
push_env_image "$version" "python" "python-env" "2.7"
push_env_image "$version" "ruby" "ruby-env" ""
push_env_image "$version" "jvm" "jvm-env" ""
+ push_env_image "$version" "jvm-jersey" "jvm-jersey-env" ""
+ push_env_image "$version" "jvm-jersey" "jvm-jersey-env" "11"
push_env_image "$version" "tensorflow-serving" "tensorflow-serving-env" ""
}
@@ -117,18 +119,20 @@ push_all_env_builders() {
local version=$1
# call with version, env dir, image name base, image name variant
- push_env_builder_image "$version" "python" "python-builder" ""
- push_env_builder_image "$version" "binary" "binary-builder" ""
- push_env_builder_image "$version" "go" "go-builder" ""
- push_env_builder_image "$version" "go" "go-builder" "1.11.4"
- push_env_builder_image "$version" "go" "go-builder" "1.12"
- push_env_builder_image "$version" "go" "go-builder" "1.13"
- push_env_builder_image "$version" "go" "go-builder" "1.14"
- push_env_builder_image "$version" "jvm" "jvm-builder" ""
- push_env_builder_image "$version" "nodejs" "node-builder" ""
- push_env_builder_image "$version" "ruby" "ruby-builder" ""
- push_env_builder_image "$version" "dotnet20" "dotnet20-builder" ""
- push_env_builder_image "$version" "php7" "php-builder" ""
+ push_env_builder_image "$version" "python" "python-builder" ""
+ push_env_builder_image "$version" "binary" "binary-builder" ""
+ push_env_builder_image "$version" "go" "go-builder" ""
+ push_env_builder_image "$version" "go" "go-builder" "1.11.4"
+ push_env_builder_image "$version" "go" "go-builder" "1.12"
+ push_env_builder_image "$version" "go" "go-builder" "1.13"
+ push_env_builder_image "$version" "go" "go-builder" "1.14"
+ push_env_builder_image "$version" "jvm" "jvm-builder" ""
+ push_env_builder_image "$version" "jvm-jersey" "jvm-jersey-builder" ""
+ push_env_builder_image "$version" "jvm-jersey" "jvm-jersey-builder" "11"
+ push_env_builder_image "$version" "nodejs" "node-builder" ""
+ push_env_builder_image "$version" "ruby" "ruby-builder" ""
+ push_env_builder_image "$version" "dotnet20" "dotnet20-builder" ""
+ push_env_builder_image "$version" "php7" "php-builder" ""
}
# Push pre-upgrade-checks image
diff --git a/test/build.sh b/test/build.sh
index 15cc534a..373db855 100755
--- a/test/build.sh
+++ b/test/build.sh
@@ -29,12 +29,14 @@ build_and_push_builder $BUILDER_IMAGE:$TAG $REPO/go-mod-image-cache
build_and_push_env_runtime python $REPO/python-env:$TAG ""
build_and_push_env_runtime jvm $REPO/jvm-env:$TAG ""
+build_and_push_env_runtime jvm-jersey $REPO/jvm-jersey-env:$TAG ""
build_and_push_env_runtime go $REPO/go-env:$TAG "1.12"
build_and_push_env_runtime nodejs $REPO/node-env:$TAG "12.16"
build_and_push_env_runtime tensorflow-serving $REPO/tensorflow-serving-env:$TAG ""
build_and_push_env_builder python $REPO/python-env-builder:$TAG $BUILDER_IMAGE:$TAG ""
build_and_push_env_builder jvm $REPO/jvm-env-builder:$TAG $BUILDER_IMAGE:$TAG ""
+build_and_push_env_builder jvm-jersey $REPO/jvm-jersey-env-builder:$TAG $BUILDER_IMAGE:$TAG ""
build_and_push_env_builder go $REPO/go-env-builder:$TAG $BUILDER_IMAGE:$TAG "1.12"
build_and_push_env_builder nodejs $REPO/node-env-builder:$TAG $BUILDER_IMAGE:$TAG "12.16"
diff --git a/test/test_utils.sh b/test/test_utils.sh
index 3e17d74e..c0f96ed6 100755
--- a/test/test_utils.sh
+++ b/test/test_utils.sh
@@ -505,6 +505,7 @@ run_all_tests() {
export GO_RUNTIME_IMAGE=gcr.io/$GKE_PROJECT_NAME/go-env:${imageTag}
export GO_BUILDER_IMAGE=gcr.io/$GKE_PROJECT_NAME/go-env-builder:${imageTag}
export JVM_RUNTIME_IMAGE=gcr.io/$GKE_PROJECT_NAME/jvm-env:${imageTag}
+ export JVM_JERSEY_RUNTIME_IMAGE=gcr.io/$GKE_PROJECT_NAME/jvm-jersey-env:${imageTag}
export JVM_BUILDER_IMAGE=gcr.io/$GKE_PROJECT_NAME/jvm-env-builder:${imageTag}
export NODE_RUNTIME_IMAGE=gcr.io/$GKE_PROJECT_NAME/node-env:${imageTag}
export NODE_BUILDER_IMAGE=gcr.io/$GKE_PROJECT_NAME/node-env-builder:${imageTag}
diff --git a/test/tests/test_environments/test_jvm_jersey_env.sh b/test/tests/test_environments/test_jvm_jersey_env.sh
new file mode 100755
index 00000000..4b267fbc
--- /dev/null
+++ b/test/tests/test_environments/test_jvm_jersey_env.sh
@@ -0,0 +1,186 @@
+#!/bin/bash
+
+
+
+set -euo pipefail
+source $(dirname $0)/../../utils.sh
+
+TEST_ID=$(generate_test_id)
+echo "TEST_ID = $TEST_ID"
+
+ROOT=$(dirname $0)/../../..
+
+env=jvm-$TEST_ID
+fn_n=jvm-hello-n-$TEST_ID
+fn_p=jvm-hello-p-$TEST_ID
+fn_n_p=jvm-hello-n-post-$TEST_ID
+
+xmlBody=$(cat <<-END
+
+
+
+ Gambardella, Matthew
+ XML Developer's Guide
+ Computer
+ 44.95
+ 2000-10-01
+ An in-depth look at creating applications
+ with XML.
+
+
+ Ralls, Kim
+ Midnight Rain
+ Fantasy
+ 5.95
+ 2000-12-16
+ A former architect battles corporate zombies,
+ an evil sorceress, and her own childhood to become queen
+ of the world.
+
+
+ Corets, Eva
+ Maeve Ascendant
+ Fantasy
+ 5.95
+ 2000-11-17
+ After the collapse of a nanotechnology
+ society in England, the young survivors lay the
+ foundation for a new society.
+
+
+ Corets, Eva
+ Oberon's Legacy
+ Fantasy
+ 5.95
+ 2001-03-10
+ In post-apocalypse England, the mysterious
+ agent known only as Oberon helps to create a new life
+ for the inhabitants of London. Sequel to Maeve
+ Ascendant.
+
+
+ Corets, Eva
+ The Sundered Grail
+ Fantasy
+ 5.95
+ 2001-09-10
+ The two daughters of Maeve, half-sisters,
+ battle one another for control of England. Sequel to
+ Oberon's Legacy.
+
+
+ Randall, Cynthia
+ Lover Birds
+ Romance
+ 4.95
+ 2000-09-02
+ When Carla meets Paul at an ornithology
+ conference, tempers fly as feathers get ruffled.
+
+
+ Thurman, Paula
+ Splish Splash
+ Romance
+ 4.95
+ 2000-11-02
+ A deep sea diver finds true love twenty
+ thousand leagues beneath the sea.
+
+
+ Knorr, Stefan
+ Creepy Crawlies
+ Horror
+ 4.95
+ 2000-12-06
+ An anthology of horror stories about roaches,
+ centipedes, scorpions and other insects.
+
+
+ Kress, Peter
+ Paradox Lost
+ Science Fiction
+ 6.95
+ 2000-11-02
+ After an inadvertant trip through a Heisenberg
+ Uncertainty Device, James Salway discovers the problems
+ of being quantum.
+
+
+ O'Brien, Tim
+ Microsoft .NET: The Programming Bible
+ Computer
+ 36.95
+ 2000-12-09
+ Microsoft's .NET initiative is explored in
+ detail in this deep programmer's reference.
+
+
+ O'Brien, Tim
+ MSXML3: A Comprehensive Guide
+ Computer
+ 36.95
+ 2000-12-01
+ The Microsoft MSXML3 parser is covered in
+ detail, with attention to XML DOM interfaces, XSLT processing,
+ SAX and more.
+
+
+ Galos, Mike
+ Visual Studio 7: A Comprehensive Guide
+ Computer
+ 49.95
+ 2001-04-16
+ Microsoft Visual Studio 7 is explored in depth,
+ looking at how Visual Basic, Visual C++, C#, and ASP+ are
+ integrated into a comprehensive development
+ environment.
+
+
+END
+)
+
+cleanup() {
+ clean_resource_by_id $TEST_ID
+}
+
+if [ -z "${TEST_NOCLEANUP:-}" ]; then
+ trap cleanup EXIT
+else
+ log "TEST_NOCLEANUP is set; not cleaning up test artifacts afterwards."
+fi
+
+cd $ROOT/examples/jvm-jersey/java
+
+log "Creating the jar from application"
+#Using Docker to build Jar so that maven & other Java dependencies are not needed on CI server
+docker run --rm -v "$(pwd)":/usr/src/mymaven -w /usr/src/mymaven maven:3.5-jdk-8 mvn clean package -q
+
+log "Creating environment for Java"
+fission env create --name $env --image $JVM_JERSEY_RUNTIME_IMAGE --version 2 --keeparchive=true
+
+log "Creating pool manager & new deployment function for Java"
+fission fn create --name $fn_p --deploy target/jersey-hello-world-0.0.1-jar-with-dependencies.jar --env $env --entrypoint io.fission.HelloWorld
+fission fn create --name $fn_n --deploy target/jersey-hello-world-0.0.1-jar-with-dependencies.jar --env $env --executortype newdeploy --entrypoint io.fission.HelloWorld
+
+log "Creating route for pool manager function"
+fission route create --name $fn_p --function $fn_p --url /$fn_p --method GET
+
+log "Creating route for new deployment function"
+fission route create --name $fn_n --function $fn_n --url /$fn_n --method GET
+
+log "Creating post route for new deployment function"
+fission route create --name $fn_n_p --function $fn_n --url /$fn_n_p --method POST
+
+log "Waiting for router & pools to catch up"
+sleep 10
+
+log "Testing pool manager function"
+timeout 60 bash -c "test_fn $fn_p Hello"
+
+log "Testing new deployment function"
+timeout 60 bash -c "test_fn $fn_n Hello"
+
+log "Testing new deployment function for XML POST request"
+timeout 60 bash -c "test_post_route $fn_n_p \"$xmlBody\" \"Echo: $xmlBody\""
+
+log "Test PASSED"
diff --git a/test/utils.sh b/test/utils.sh
index d6ead6f8..0532afc3 100755
--- a/test/utils.sh
+++ b/test/utils.sh
@@ -186,6 +186,7 @@ export PYTHON_BUILDER_IMAGE=${PYTHON_BUILDER_IMAGE:-fission/python-builder}
export GO_RUNTIME_IMAGE=${GO_RUNTIME_IMAGE:-fission/go-env-1.12}
export GO_BUILDER_IMAGE=${GO_BUILDER_IMAGE:-fission/go-builder-1.12}
export JVM_RUNTIME_IMAGE=${JVM_RUNTIME_IMAGE:-fission/jvm-env}
+export JVM_JERSEY_RUNTIME_IMAGE=${JVM_JERSEY_RUNTIME_IMAGE:-fission/jvm-jersey-env}
export JVM_BUILDER_IMAGE=${JVM_BUILDER_IMAGE:-fission/jvm-builder}
export NODE_RUNTIME_IMAGE=${NODE_RUNTIME_IMAGE:-fission/node-env}
export NODE_BUILDER_IMAGE=${NODE_BUILDER_IMAGE:-fission/node-env-builder}