The Codelab walks you through the experience of creating an Edge Java Callout for end-to-end experience using Eclipse as an IDE.

Prerequisites

How will you use this tutorial?

Only read through it Read it and complete the exercises

How would you rate your experience with Google Cloud Platform?

Novice Intermediate Proficient

The repository contains Edge .jar file we need to compile and test our Java Callout.

https://github.com/apigee/api-platform-samples/tree/master/doc-samples/java-cookbook/lib

1. Copy expressions-1.0.0.jar and message-flow-1.0.0.jar to ~/projects/json-sanitizer-policy/edge-jar-library

2. Install local copies of Edge dependencies

mvn install:install-file \
   -Dfile=expressions-1.0.0.jar \
   -DgroupId=com.apigee \
   -DartifactId=expressions \
   -Dversion=1.0.0 \
   -Dpackaging=jar \
   -DgeneratePom=true

mvn install:install-file \
   -Dfile=message-flow-1.0.0.jar \
   -DgroupId=com.apigee \
   -DartifactId=message-flow \
   -Dversion=1.0.0 \
   -Dpackaging=jar \
   -DgeneratePom=true

1. Generate a Java project

mvn archetype:generate -DgroupId=com.apigee \
-DartifactId=json-sanitizer-callout  \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false

2. In the generated pom.xml file, for junit dependency, change JUnit version from 3.8.1 to 4.12

Change version from 1.0-SNAPSHOT to 1.0.

3. Add Edge dependencies

<dependency>
        <groupId>com.apigee</groupId>
        <artifactId>expressions</artifactId>
        <version>1.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.apigee</groupId>
        <artifactId>message-flow</artifactId>
        <version>1.0.0</version>
        <scope>provided</scope>
    </dependency>

4. Add json-sanitizer dependency.

Go to https://search.maven.org/#artifactdetails%7Ccom.mikesamuel%7Cjson-sanitizer%7C1.1%7Cjar and copy Apache Maven section of the Dependency Information to the pom.xml file

    <dependency>
        <groupId>com.mikesamuel</groupId>
        <artifactId>json-sanitizer</artifactId>
        <version>1.1</version>
    </dependency>

5. Add jmockit dependency for junit tests.

    <dependency>
            <groupId>org.jmockit</groupId>
            <artifactId>jmockit</artifactId>
            <version>1.36</version>
            <scope>test</scope>
    </dependency>

1. Launch Eclipse.

2. Select File/Import...

3. Select Maven/Existing Maven Project.

4. In the Import Maven Projects dialog, Maven Projects step, browse to the Root Directory.

~/projects/json-sanitizer-policy/json-sanitizer-callout

Select folder, click Open button.

5. Press Finish button to import the project.

1. Right-click App.java class in the src/main/java/com.apigee package and select Delete.

2. Right-click src/main/java source folder and select New/Class

Change Package Name to: com.apigee.jsonsanitizer

Class name to: JsonSanitizerCallout

3. Click on Add... button on the right of Interfaces list. Select Execution from com.apigee.flow.execution.spi package.

4. Press Finish.

5. Type in the code of the JsonSanitizerCallout execute() method implementation.

package com.apigee.jsonsanitizer;
package com.apigee.jsonsanitizer;

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;
import com.google.json.JsonSanitizer;

public class JsonSanitizerCallout implements Execution {

    public ExecutionResult execute(MessageContext messageContext, ExecutionContext executionContext) {


        try{
                        String contentType = messageContext.getMessage().getHeader("Content-Type");
                        if( !(contentType  == null) && contentType.toLowerCase().endsWith("json") ){
                        String request = messageContext.getMessage().getContent();
        
                                        String json = JsonSanitizer.sanitize(request);

                        messageContext.getMessage().setContent(json);
                                        messageContext.getRequestMessage().setHeader("Content-Length", json.length());
                        }
                return  ExecutionResult.SUCCESS;
        }catch( Exception e ){
                return  ExecutionResult.ABORT;
        }

    }
}

1. Right-click AppTest.java class in the src/test/java/com.apigee package and select Delete.

2. Right-click src/test/java source folder and select New/Class

Change Package Name to: com.apigee.jsonsanitizer

Class name to: JsonSanitizerCalloutTest

3. Press Finish.

4. Type in the code of the JUnit callout test class.

package com.apigee.jsonsanitizer;

import static org.junit.Assert.*;

import java.util.HashMap;
import java.util.Map;

import mockit.Mock;
import mockit.MockUp;

import org.junit.Before;
import org.junit.Test;

import com.apigee.flow.execution.ExecutionContext;
import com.apigee.flow.message.MessageContext;

public class JsonSanitizerCalloutTest {

        
        MessageContext messageContext;
        ExecutionContext executionContext;
        
        @Before
        public void testSetup(){
                messageContext = new MockUp<MessageContext>() {
                        private Map<String,Object> variables;
                        
                        public void $init(){
                                getVariables();
                        }
                        
                        private Map<String,Object> getVariables(){
                                if( variables == null){
                                        variables = new HashMap<String,Object>();
                                }
                                return variables;
                        }
                        
                        @Mock
                        public Object getVariable(final String name){
                                return getVariables().get(name);
                        }
                        
                        @Mock
                        public boolean setVariable(final String name, final Object value){
                                getVariables().put(name, value);
                                return true;
                        }
                }.getMockInstance();
                
                executionContext = new MockUp<ExecutionContext>(){}.getMockInstance();
        }
        
        @Test
        public void sanitizeMessageContent(){
                messageContext.setVariable("message.content",  "{\r\n" + 
                                "        \"header\":{\r\n" + 
                                "                \"version\":\"1.0\",\r\n" + 
                                "                \"serviceName\":\"IPPEligibility\",\r\n" + 
                                "                \"timestamp\":\"2016-05-29 09:39:16\",\r\n" + 
                                "                \"uniqueRefNo\":\"12<1212\",\r\n" + 
                                "                \"orgID\":\"EBI\"\r\n" + 
                                "        },\r\n" + 
                                "    \"ippEligibilityReq\":: {\r\n" + 
                                "        \"creditCardNo\": \"fAFopAArD+6BXMzQqk+yI9d3V2bX77vbiFqF3jckNNY=\",\r\n" + 
                                "        \"merchantId\": \"31442\",\r\n" + 
                                "        \"amount\": \"1000\"\r\n" + 
                                "    }\r\n" + 
                                "}\r\n" + 
                                "");
                
                JsonSanitizerCallout callout = new JsonSanitizerCallout();
                
                callout.execute(messageContext, executionContext);
                
                assertEquals(3,4);
        }
}

5. Right-click project and select Run As/JUnit Test

1. In the pom.xml file add section to package the jar file with dependencies

        <build>
                <finalName>${artifactId}-${version}</finalName>
                <plugins>
                        <plugin>
                                <artifactId>maven-assembly-plugin</artifactId>
                                <version>2.6</version>
                                <configuration>
                                        <descriptorRefs>
                                                <descriptorRef>jar-with-dependencies</descriptorRef>
                                        </descriptorRefs>
                                        <appendAssemblyId>false</appendAssemblyId>
                                </configuration>
                                <executions>
                                        <execution>
                                                <id>make-assembly</id>
                                                <phase>package</phase>
                                                <goals>
                                                        <goal>single</goal>
                                                </goals>
                                        </execution>
                                </executions>
                        </plugin>
                </plugins>
        </build>

2. Right-click the project and choose Run As/Maven Build...

3. Give it a nice name: json-sanitizer-callout package.

4. Enter package as a goal into the Goals field.

5. Press Run.

The resultant .jar file will be generated and placed in the project target directory.

Define No Target Proxy

1. In APIs/API Proxies, select + API Proxy button.

2. In the Build Proxy wizard, select proxy type No Target Radio button. Press Next.

3. Enter json-sanitizer Proxy Name field value in the DETAILS. Click Next

4. In the SECURITY page of the wizard, chose Pass through (none) radio-button option. Click Next

1. In the VIRTUAL HOSTS, make sure that default vhost is selected.

2. In the BUILD page of the wizard, make sure that the proxy is deployed into the test environment.

3. Click Build and Deploy button.

The proxy will be generated, uploaded, and deployed to the test env.

4. Click on the json-sanitizer link to open the editor.

Add Echo Assign Message Policy

1. Activate DEVELOP tab of the proxy editor.

2. In the Navigator view, select the PostFlow item of the default proxy in the Proxy Endpoints section.

3. Click on the + Step button on the left side of the Flow: PostFlow diagrammer below RESPONSE arrow.

4. In the Add Step dialog, select Assign Message policy in the MEDIATION section.

5. Populate Display Name and Name fields as AssignMessage.Echo.

Click Add.

6. Define the AssignMessage.Echo policy as:

<AssignMessage async="false" continueOnError="false" enabled="true" name="AssignMessage.Echo">
    <DisplayName>AssignMessage.Echo</DisplayName>
    <Copy source="request"/>
    <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

7. Click Save button to save and deploy the proxy.

1. In the PostMan, execute POST request to the http://apigee-cs-test.apigee.net/json-sanitizer endpoint passing the application/json body:

{"xx":"<script>alert(1)</script>", "yy": 'yyy',"ar":[0,,2]}

It will return the same body, i.e., echo the request into response.

{"xx":"<script>alert(1)</script>", "yy": 'yyy',"ar":[0,,2]}

1. In the DEVELOP tab of the editor, select PreFlow of the default Proxy Endpoint.

2. Click on the + Step button on the right of the Flow: PreFlow editor above REQUEST arrow.

3. In the Add Step dialog, select Java Callout from the EXTENSION section. Give it a JavaCallout.JSONSanitizer name and display name.

4. Click on Choose File button and select json-sanitizer-callout-1.0.jar file. The Script Name field fill be automatically populated by the .jar file name.

Click Add.

5. In the opened JavaCallout.JSONSanitizer policy editor, enter correct class name that implements Execution.execute() interface method.

ResourceURL: json-sanitizer-callout-1.0.jar

ClassName: com.apigee.jsonsanitizer.JsonSanitizerCallout

6. Click on Save button to save and deploy the proxy.

1. Execute the POST request to the proxy endpoint http://apigee-cs-test.apigee.net/json-sanitizer

Pre-policy invocation Body:

{"xx":"<script>alert(1)</script>", "yy": 'yyy',"ar":[0,,2]}

This time the result will look differently, as OWASP json-sanitizer will sanitize and secure the JSON datagram in the request body.

Post-policy invocation Body:

{"xx":"
<script>alert(1)<\/script>", "yy": "yyy","ar":[0,null,2]}

Unless your Java Callout contains a couple of lines, it is good to be able to debug it. Mocking permits you conveniently debug most if not all code with your local development environment. Saying that, it is important to be able to debug a callout in context of a real Message Processor. Java remote debugging facility permits you to do this. Of course, you need an access to an OPDK environment to be able to reconfigure Message Processor JVM process. Usually, All-In-One installation of Edge provides perfect isolated development environment.

Turning On JVM Debug Mode

1. On an MP node, add debug_port=8000 by editing or creating message-processor.properties file

# vi /opt/apigee/customer/application message-processor.properties

debug_port=8000

2. Restart MP component

apigee-service edge-message-processor restart

3. Verify that debug setting is activated. Look for the -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,a

ddress=8000 signature.

# ps -eaf|grep 8000

apigee    4224     1  0 07:30 ?        00:04:23 /usr/lib/jvm/jre/bin/java -classpath /opt............var/log/edge-message-processor -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,a
ddress=8000 com.apigee.kernel.MicroKernel

This setting provides you with an ability to attach and detach to a process under debugging at any point of time.

Setting up Debugging Configuration

1. In the Eclipse, select Run/Debug Configurations... menu item.

2. In the left-side pane, select Remote Java Application line.

3. Right-click it and choose New Configuration context-menu item.

4. Enter java-sanitizer-callout as Name.

5. Click on Browse... button in the Project section and select java-sanitizer-callout project.

6. In the Connection Properties section enter IP address of your MP node and port 8000.

7. Click Apply and Close.

Remote Debugging Session

1. In the JsonSanitizerCallout.java file, double-click on line 22 gutter to flip a breakpoint.

2. Select Run/Debug Configuration... menu item.

3. Select Remote Java Application/java-sanitizer-callout configuration at the left side of the dialog.

4. Click Debug button to initiate remote debug session.

The Eclipse will switch to the Debug Perspective and attach itself to the running Message Processor instance. You will see all threads of MP's JVM.

5. Initiate an http request to the json-sanitizer proxy.

You are stopped at the breakpoint and can inspect any variables of the current state.

6. Click at the Step Into (F5), Step Over(F6), or Resume (F8) button to continue execution.

7. The request processing is continued as appropriate.

8. Select Run/Disconnect menu item to detach the remote debugger from the live process.

1. Execute a POST request in Postman to deploy .jar file of Java Callout policy using Management API

https://api.enterprise.apigee.com/v1/o/apigee-cs/resourcefiles?name=json-sanitizer-callout-1.0.jar&type=java

2. To check, send the GET request to return the contents of org-level resource files collection, by calling URL

https://api.enterprise.apigee.com/v1/o/apigee-cs/resourcefiles