APIGEE : Java Callout Issue

Hi @dchiesa1 ,

I am working on Java callout for invoking AWS lambda function from Apigee. I have written below java code and created Java project in Eclipse and exported project as runnable jar. That jar I am using in API proxies. But when I am testing API getting java error as below    

Java Code-

 

package com.example.lambda;

import java.nio.charset.Charset;
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.amazonaws.auth.AWSSessionCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicSessionCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.lambda.AWSLambda;
import com.amazonaws.services.lambda.AWSLambdaClientBuilder;
import com.amazonaws.services.lambda.model.InvocationType;
import com.amazonaws.services.lambda.model.InvokeRequest;
import com.amazonaws.services.lambda.model.InvokeResult;

public class awsinvoke implements Execution  {
	
	public ExecutionResult execute(MessageContext messageContext,ExecutionContext executionContext) {
		try {

		// final String AWS_ACCESS_KEY_ID = "ASIA3UK7JR6MLQBMGIXW";
		  //  final String AWS_SECRET_ACCESS_KEY = "L/W8VHOqj2dN4JPAe8CnF/u2sqNJwu/+KPJrLi2Q";
		    //final String AWS_SESSION_TOKEN = "FwoGZXIvYXdzENj//////////wEaDN4TpncmRFI83olJ9iKpAvf8qiqfYd0F6ifT8xz/D69S/QaSFTHEHww5Rz/scvanT9gkMIssiSdqm+R3uGS93bptUHw1OjJnr+hStsn+ZZF2YQfRkEJ3WlQhOW1rDbgDBHiLtfSMQrKfye2LrUnviDUWRKwBVotw6bIU9NXSP5SRvwHC7Cz//s3UqqPojA3/0l+SpYtBnfjInpiMV7ppgUosYc3y2u21mWlmKvkl1ZF3ZUSWlp4uAEQevMdVQTdQP2JYKejzDhZ+IUZ7nNJbP2Jx4hsT72yPYir0JeqpdvklbzzouYN3DcJLSW7U8Kxs1GnJphJP3VKK+xxrW2KTBJV2R/BJc0fsgCRBxsy3NbYiA7C3n/Pdik3NU+Xa37RYoNwSPpBCmJXcv9JwsSAugj+r9K9sHZ3OLyj6k5uaBjIqEjOV4jdAsIJehb62jLrGKgQoRg0yHiSjUg/gTmXnNmaOWhKI6bJ6pFI5";

		    //AWSCredentials credentials = new BasicAWSCredentials(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY);
			 // ARN
		    //String functionName = "arn:aws:lambda:us-east-1:799600643992:function:helloworldlambda";
		    
		    String AWS_SESSION_TOKEN = messageContext.getVariable("AWS_SESSION_TOKEN");
		    String AWS_SECRET_ACCESS_KEY = messageContext.getVariable("AWS_ACCESS_KEY_ID");
		    String AWS_ACCESS_KEY_ID = messageContext.getVariable("AWS_SECRET_ACCESS_KEY");
		    String functionName = messageContext.getVariable("functionName");
		    String regionname= messageContext.getVariable("regionname");
		    AWSSessionCredentials credentials = new BasicSessionCredentials(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY,AWS_SESSION_TOKEN);
		    

		    //This will convert object to JSON String
		    //String inputJSON = new Json().toJson(userActivity);

		    InvokeRequest lmbRequest = new InvokeRequest()
		           .withFunctionName(functionName);

		    lmbRequest.setInvocationType(InvocationType.RequestResponse);
		    Regions functionregion = Regions.US_EAST_1;
		    if(regionname=="us-west-2")
		    {
		    functionregion= Regions.US_WEST_2;
		    }
		    if(regionname=="us-east-2")
		    {
		    functionregion= Regions.US_EAST_2;
		    }

		    AWSLambda lambda = AWSLambdaClientBuilder.standard()
		            .withRegion(functionregion)
		            .withCredentials(new AWSStaticCredentialsProvider(credentials)).build();

		    InvokeResult lmbResult = lambda.invoke(lmbRequest);

		    String resultJSON = new String(lmbResult.getPayload().array(), Charset.forName("UTF-8"));

		    //System.out.println(resultJSON);
		    String resultstr = "lambda_response";
		    messageContext.setVariable(resultstr, "Result: " + resultJSON );
		    
		    return ExecutionResult.SUCCESS;
		}

	    

		catch (Exception e) {
		//String exc =  e.toString();
		//messageContext.getErrorMessage().setContent(exc);
		String varName = "mycallout_error";
		messageContext.setVariable(varName, "Exception: " + e.toString());
		      return ExecutionResult.ABORT;

		    }
	}
}

 

.Error-

{
    "fault": {
        "faultstring""Failed to execute JavaCallout. Could not initialize class com.amazonaws.services.lambda.AWSLambdaClientBuilder",
        "detail": {
            "errorcode""steps.javacallout.ExecutionError"
        }
    }
}
 
This java file referring aws sdk , that jars is present in in exported jar, and when I am running this jar in my local system through cmd its working fine but in Apigee its throwing error. Can you please help me on this.
 
 
jar.PNG

 

 

Solved Solved
0 8 659
1 ACCEPTED SOLUTION


My requirement is to invoke lamda function from api proxy. Signature part I have done and it's working fine.


"signature part I have done" means what exactly? Do you have a Java callout that creates a signature? does it work within Apigee? I understood from your prior posts that you have a Java class that produces the signature but that class does not function within Apigee as a callout. I thought that was the problem we were solving. Is this wrong?


And I believe to call any aws services we need to use aws sdk.


That is not correct. To call AWS services you can just send an HTTP request to the appropriate endpoint. You can use a Lambda function as an HTTP Target. Or the target of a ServiceCallout. The only tricky part is the authentication, the signature. The Java callout I shared with you produces the signature you need. I think a Java callout that relies on the AWS SDK will not work in Apigee. The JAR for the AWS SDK is too large for Apigee. I cannot solve that.  It won't work. The Java class you already have cannot be used within Apigee. Other people have had this problem. That is why I produced the smaller Java callout that simply creates the signature for AWS.

View solution in original post

8 REPLIES 8

 

Clearly, something is wrong with your 'fat' jar file.

Right now there are a couple of ways how things might go wrong way.

It would be complicated for us to replicate your build. A good first step could be for you to upload your jar somewhere so we can inspect it and see if we can spot the problem.

Hi ,

Is there any way I can share my jar. I am finding anything here to upload any file.

@pankajrai9026 This doesn't answer your question directly, but in case you didn't know, it's also possible to call an AWS Lambda function from Apigee using a JavaScript policy. See here for details.

If using a JavaScript policy is an option for you this may be a less complex approach.

1. There is already a Java callout that computes an AWS v4 Signature that is suitable for authenticating to AWS Lambda. find it here

2. I am not sure what the problem might be with your Java callout, but one problem I have seen with using the AWS SDK is that the resulting JAR is too large, and gets rejected by APigee. Another possible problem is a permissions error. The good news is you don't have to solve this mystery. You can just use the existing callout. 

Hi, 

My requirement is to invoke lamda function from api proxy. Signature part I have done and it's working fine. And I believe to call any aws services we need to use aws sdk. 

 

 


My requirement is to invoke lamda function from api proxy. Signature part I have done and it's working fine.


"signature part I have done" means what exactly? Do you have a Java callout that creates a signature? does it work within Apigee? I understood from your prior posts that you have a Java class that produces the signature but that class does not function within Apigee as a callout. I thought that was the problem we were solving. Is this wrong?


And I believe to call any aws services we need to use aws sdk.


That is not correct. To call AWS services you can just send an HTTP request to the appropriate endpoint. You can use a Lambda function as an HTTP Target. Or the target of a ServiceCallout. The only tricky part is the authentication, the signature. The Java callout I shared with you produces the signature you need. I think a Java callout that relies on the AWS SDK will not work in Apigee. The JAR for the AWS SDK is too large for Apigee. I cannot solve that.  It won't work. The Java class you already have cannot be used within Apigee. Other people have had this problem. That is why I produced the smaller Java callout that simply creates the signature for AWS.

When trying to use above jars for signing for lambda, I get below message:

{"message":"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details."}

 

<Property name="debug">true</Property>
<Property name="service">lambda</Property>
<Property name="endpoint">https://lambda.us-east-1.amazonaws.com</Property>
<Property name="region">us-east-1</Property>
<Property name="key">xx</Property>
<Property name="secret">xx</Property>
<Property name="message-variable-ref">lambdaCallout</Property>

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="AM-LambdaRequest">
<DisplayName>AM-LambdaRequest</DisplayName>
<Set>
<Verb>POST</Verb>
<Path/>
<Headers>
<Header name="content-type">application/json</Header>
</Headers>
<Payload>{}</Payload>
</Set>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="new" transport="http" type="request">lambdaCallout</AssignTo>
</AssignMessage>

 

 

Where is the rest of the configuration for the Java callout? I see a list of properties, but not the other configuration. If you are using the AWS v4 callout that we have been discussing above, the one available at this link ... there is no property the callout uses that is called "message-variable-ref". What is that thing? Is that intended to be the source property that is documented for the callout?

Are you trying to INVOKE a lambda function?  Your message said "for signing for lambda," but didn't elaborate of what that means. Are you trying to invoke a Lambda function?  I am not a Lambda expert, but I think there are two ways to invoke a Lambda function via HTTP:  using AWS API Gateway, and using Lambda function URLs. The hostname you showed in the callout configuration  doesn't look like a hostname that would work for either of them, I think.  Which are you intending to use?  Are you trying to invoke your own lambda function, or manage lambda functions from within Apigee?  Can you elaborate on what you are aiming to do? 

Also, I see your AssignMessage, it uses createNew='new' . I think you want that to be createNew='true' .

Remember when signing messages with the callout, it's important that you create the message (via AssignMessage) BEFORE the Java signature callout. Have you done that? The idea is, create the message, then use the callout to sign it, then send it. One possible policy sequence is: AssignMessage, AWS v4 Callout, ServiceCallout . This is all covered in the readme.