How to create a Java callout

This page applies to Apigee and Apigee hybrid.

View Apigee Edge documentation.

What is a Java callout?

Apigee provides a range of policies that address common API management requirements such as security, data transformation, traffic management, and others.

However, there are some cases where your API requires custom behavior that is not implemented in a standard policy. In these cases, Apigee provides several options that enable you to script or code customized API behavior. One approach is to implement the desired behavior in Java.

Supported Java versions include: Oracle JDK 11 and OpenJDK 11.

How do I use Java code in a proxy?

A Java callout policy lets you call Java code from within an executing proxy flow. Your Java code needs to implement certain Apigee-specific Java interfaces that allow the code to interact with the executing proxy. For example, Java methods exist for getting and setting headers, query parameters, flow variables, and other entities within the current flow context of the proxy.

When should I use a Java callout?

Let's look at situations where Java callouts are useful, and situations where you should consider other approaches.

First, consider alternative approaches

Before using a Java callout, note that there may be alternative approaches that you can use instead. For example:

  • For lightweight operations, such as HTTP API calls to remote services, consider using the ServiceCallout policy. See Service Callout policy.
  • For relatively simple interactions with message content, such as modifying or extracting HTTP headers, parameters, or message content, you can use JavaScript or PythonScript policies.

What you can do in Java code

A Java callout supports these basic operations:

  • Examining or manipulating request or response messages
  • Getting and setting flow variables. You can use Java methods to access Apigee flow variables. If you want to access Key Value Map (KVM) information, use a KVM policy, assign KVM values to flow variables, and then you can access the flow variables from within the Java callout.
  • Calling external services
  • Raising faults
  • Manipulating error messages and status codes

What you cannot do in Java code

Most system calls are disallowed. You cannot:

  • Make internal file system reads or writes. This means that you cannot use any of the Java packages to read/write into internal file systems; however, you can make external remote calls.
  • Get information about the current process, the process list, or CPU/memory utilization on the machine.
  • Access the source code in expressions-1.0.0.jar and message-flow-1.0.0.jar.

Although some such calls may work, they are unsupported and liable to be actively disabled at any time. Avoid making such calls in your code.

Do not use or rely on Java libraries that are included with Apigee. Those libraries are for Apigee product functionality only, and there's no guarantee that a library will be available from release to release. If you use such libraries, use them in non-production demonstrations only.

Hello Java callout

Let's go through a basic hello world Java callout example. In this example, we create a simple proxy with a Java callout that returns a "hello world" response. The proxy can return one of two possible responses:

  • If you pass in a "username" header with a "name" value, the proxy returns:

    Hello, <name>!
    
  • If you omit the header, the proxy just returns:

    "Hello, Guest!"
    

Download the starter project

To make things simple, we have a basic project prepared for you on GitHub in the Apigee api-platform-samples repository.

  1. Download or clone api-platform-samples to your system. If you already have api-platform-samples on your system, do a pull to make sure you have the latest version.
  2. In a terminal or code editor of your choice, go to the api-platform-samples/doc-samples/java-hello project.

Write the Java code

  1. Open the Java source file: java-hello/callout/src/main/java/HelloJava.java. This file is a skeleton version of the main Java class that we will implement. The imported packages are required for Apigee Java Callout code. These classes provide methods that allow you to access the proxy execution context. We'll walk through the steps for compiling and deploying this code shortly.
    package com.apigeesample;
    
    import com.apigee.flow.execution.ExecutionContext;
    import com.apigee.flow.execution.ExecutionResult;
    import com.apigee.flow.execution.spi.Execution;
    import com.apigee.flow.message.MessageContext;
    
    
    public class HelloJava implements Execution {
    
            public ExecutionResult execute(MessageContext messageContext, ExecutionContext executionContext) {
    
                    try {
    
                            // Your code here.
    
                return ExecutionResult.SUCCESS;
    
                    } catch (Exception e) {
                            return ExecutionResult.ABORT;
                    }
            }
    
    }
    
  2. Replace the commented line // Your code here with the following code:

    String name = messageContext.getMessage().getHeader("username");
    
    if (name != null && name.length()>0) {
            messageContext.getMessage().setContent("Hello, " + name + "!");
            messageContext.getMessage().removeHeader("username");
    } else {
            messageContext.getMessage().setContent("Hello, Guest!");
    }
    
  3. Save the file.


Compile your code with Maven

  1. Be sure that you have Maven installed:

    mvn -version
    
  2. Install the required JAR dependencies in your local Maven repo using one of the following methods:
    • Add the following snippet to the pom.xml file to downoad the required JAR dependencies from Artifact Registry:
      <repositories>
        <repository>
          <id>artifact-registry</id>
          <url>https://us-maven.pkg.dev/apigee-release/apigee-java-callout-dependencies</url>
        </repository>
      </repositories>
      
      <dependencies>
        <dependency>
          <groupId>com.apigee.gateway.libraries</groupId>
          <artifactId>message-flow</artifactId>
          <version>1.0.0</version>
          <scope>compile</scope>
          <type>jar</type>
        </dependency>
        <dependency>
          <groupId>com.apigee.infra.libraries</groupId>
          <artifactId>expressions</artifactId>
          <version>1.0.0</version>
          <scope>compile</scope>
          <type>jar</type>
        </dependency>
      </dependencies>
    • Use the following curl calls to download the required JAR dependencies from Artifact Registry:
      curl "https://us-maven.pkg.dev/apigee-release/apigee-java-callout-dependencies/com/apigee/gateway/libraries/message-flow/1.0.0/message-flow-1.0.0.jar" -v -L -o message-flow-1.0-0.jar
              
      curl "https://us-maven.pkg.dev/apigee-release/apigee-java-callout-dependencies/com/apigee/infra/libraries/expressions/1.0.0/expressions-1.0.0.jar" -v -L -o expressions-1.0.0.jar
              
    • Execute the script java-hello/buildsetup.sh. This script downloads the required JAR dependencies from the Apigee GitHub repository.
  3. cd to the java-hello/callout directory.
  4. Execute Maven:

    mvn clean package
    
  5. If you wish, verify that the JAR file edge-custom-policy-java-hello.jar was copied to java-hello/apiproxy/resources/java. This is the required location for JAR files that you wish to deploy with a proxy.

Deploy and call the proxy

Follow these steps to deploy and test the API proxy:

  1. Change to the java-hello directory.
  2. Zip the API proxy bundle:
    zip apiproxy-bundle.zip -r apiproxy -x \*.\*~
    
  3. The simplest way to deploy the proxy is to bundle it in a zip file and upload the proxy bundle to an environment in your Apigee organization. See Creating an API proxy. Be sure to use the Upload Proxy Bundle option. See also Tips and tricks for uploading API proxy in a proxy bundle in the Apigee community.
  4. When the proxy is deployed, try calling it:
    curl  https://$HOSTNAME/java-hello -H "username:Will"
    

    Which returns "Hello, Will!

About the proxy

Let's quickly examine the policies used in this proxy. Pay attention to where the policies are positioned in the proxy flow and why.

The Assign message policy

An Assign message policy is attached to the ProxyEndpoint request flow. It copies the username header from the request and assigns it to the response. This operation allows the Java Callout policy, which is attached to the response flow, to access the username header and build a custom response body using the value of that header.

<AssignMessage async="false" continueOnError="false" enabled="true" name="CopyHeader">
    <DisplayName>CopyHeader</DisplayName>
    <Copy source="request">
        <Headers>
          <Header name="username"/>
        </Headers>
    </Copy>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

The Java callout policy

The Java callout policy is attached to the response flow. This is because the custom Java code makes changes to the response headers and message. The policy's ClassName element specifies the main class that is executed by the policy. The ResourceURL element is the name of the JAR file that you built and added to the resources/java directory of the proxy.

<JavaCallout name="hello-java">
    <ClassName>com.apigeesample.HelloJava</ClassName>
    <ResourceURL>java://edge-custom-policy-java-hello.jar</ResourceURL>
</JavaCallout>

What you need to know about Java callout

Important things to note about implementing a Java callout are:

  • Imports classes from the com.apigee.flow.execution and com.apigee.flow.message packages. These packages must be included in the JAR file that is packaged and deployed. You can upload your Java JAR through the Management UI proxy editor, or you can include it in the /resources/java directory in API proxies that you develop locally.
  • Implements the Execution interface. Any Java code that is executed within an API proxy must implement Execution.
  • A Java Callout policy contains no actual code. Instead, a Java Callout policy references a Java 'resource', which you must package in a JAR.
  • Package names to avoid: Do not use io.apigee or com.apigee as package names in Java Callouts. Those are reserved and used by other Apigee modules.
  • If your Java Callout relies on additional third-party libraries packaged as independent JAR files, then place those JAR files in the /resources/java directory as well to ensure that they are loaded correctly at runtime.
  • If there are multiple JARs, simply add them as additional resources. You do not need to modify the policy configuration to refer to additional JAR files. Putting them in /resources/java is sufficient.
  • For additional information on uploading Java JARs, see Resource files.