LATEST VERSION: v0.1.0 - RELEASE NOTES
Pivotal Function Service v0.1.0

Java Functions

Page last updated:

This topic provides an overview of how to write Java functions for Pivotal Function Service (PFS).

Requirements

  • PFS has been installed and you have prepared a namespace.
  • The pfs CLI has been installed.
  • You have set REGISTRY and REGISTRY_USER environment variables.

    For GCR use gcr.io and your GCP Project ID.

    export REGISTRY=gcr.io
    export REGISTRY_USER=$(gcloud config get-value core/project)
    

    For the local registry used with Minikube or Docker Desktop, use registry name registry.pfs.svc.cluster.local:5000 and a dummy username.

    export REGISTRY=registry.pfs.svc.cluster.local:5000
    export REGISTRY_USER=testuser
    

How the Java Function Invoker Works

The Java function invoker is a Spring Boot application which will locate your function based on configuration settings, and invoke the function for each request.

PFS function support for the Java language relies on function code being written using interfaces like Function<T,R>, Supplier<T>, or Consumer<T> from the java.util.function package in the Java SE platform.

The implementation can be provided as a plain Java class or as part of a Spring Boot app.

When configuring the build for the Java project it is necessary to provide all required dependencies in the JAR file that is created. This can be done using Spring Boot’s build plugins for Maven and Gradle. For non-Boot projects you can use the Shade plugin for Maven or a Shadow plugin for Gradle.
Due to an issue with the buildpack it is currently not possible to use the Shade plugin for Maven.

For more in-depth coverage see the riff java-function-invoker.

A Simple Spring Boot Based Function

We recommend using the Spring Initializr to bootstrap your project. Select the Web and Cloud Function dependencies and generate your project with either Maven or Gradle for the build configuration. After you unzip the generated project you can modify the app and add a @Bean definition for your function.

Here we are adding the following uppercase function bean:

    @Bean
    public Function<String, String> uppercase() {
        return s -> s.toUpperCase();
    }

to our Spring Boot app:

src/main/java/functions/UppercaseApplication.java

package functions;

import java.util.function.Function;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class UppercaseApplication {

    @Bean
    public Function<String, String> uppercase() {
        return s -> s.toUpperCase();
    }

    public static void main(String[] args) {
        SpringApplication.run(UppercaseApplication.class, args);
    }
}

Commit your source to a Git repo once the function compiles and tests pass. The source for this function is also available in this sample repo on GitHub.

Use the pfs CLI to Run the Boot Function

Create the uppercase function by running the pfs CLI command below. You can replace the sample git-repo URL with your own.

pfs function create uppercase \
  --git-repo https://github.com/projectriff-samples/java-boot-uppercase.git \
  --image $REGISTRY/$REGISTRY_USER/uppercase \
  --verbose

The invoker attempts to detect the function from the function source. Since you have a single function declared with @Bean in the Spring Boot app, that is the function that is used. If you have multiple functions in the source then you must specify which one you want to use by providing a --handler flag for the pfs function create command.

You should now be able to invoke the function service with the pfs service invoke command:

pfs service invoke uppercase --text -- -w '\n' -d 'welcome to pfs'
curl 35.239.12.146/ -H 'Host: uppercase.default.example.com' -H 'Content-Type: text/plain' -w '\n' -d 'welcome to pfs'
WELCOME TO PFS

Finally, delete the function using the pfs service delete command:

pfs service delete uppercase

A Plain Java Function

For plain Java functions you have to provide your own Maven or Gradle build configuration. After you configure the build you can add a Java class that implements Function<String, String>:

src/main/java/functions/Hello.java

package functions;

import java.util.function.Function;

public class Hello implements Function<String, String> {

    public String apply(String name) {
        return "Hello " + name;
    }
}

Commit your source to a Git repo once the function compiles and tests pass. The source for this function is also available in this sample repo on GitHub.

Using the pfs CLI to Run the Plain Java Function

Create the hello function by running the pfs function create command below. You can replace the sample git-repo URL with your own. When using plain Java functions, you have to specify the function class name by providing a --handler flag.

pfs function create hello \
  --git-repo https://github.com/projectriff-samples/java-hello.git \
  --handler functions.Hello \
  --image $REGISTRY/$REGISTRY_USER/hello \
  --verbose

You should now be able to invoke the function service with the pfs service invoke command:

pfs service invoke hello --text -- -w '\n' -d 'PFS'
curl 35.232.242.167/ -H 'Host: hello.default.example.com' -H 'Content-Type: text/plain' -w '\n' -d PFS
Hello PFS

To clean up, for example after a failure, delete the function using the pfs service delete command:

pfs service delete hello

Creating a function from local source

This capability is currently only available when using Minikube or Docker Desktop with a local registry. It will be extended to work in other environments in a future release.

First you must prepare your environment for local builds by setting the PFS_BUILDER_IMAGE and PFS_PACKS_RUN_IMAGE environment variables. See Installing PFS on Minikube or on Docker Desktop for detailed instructions.

Setting these environment variables will affect both local and cluster builds. We suggest opening a new terminal window before changing to a different Kubernetes context.

Here we assume that you have created the pfs-local-path-env file in your download directory. Source the file with the environment settings using (if it is in a different location just change the path):

source ~/Downloads/pfs-local-path-env

To build a function from a local directory, use --local-path instead of --git-repo.

E.g. if you are in a directory that is a Java project like the hello example above:

pfs function create hello \
  --local-path .
  --handler functions.Hello \
  --image $REGISTRY/$REGISTRY_USER/hello \
  --verbose

To update the function and deploy a new revision:

pfs function update hello \
  --local-path .