JavaCallout possible to pass data

Not applicable

Hi,

I want to write a utility using Java callout that takes request header name and encode/decode and set it in a variable...

Is it possible to send values to Java Calout?

Thanks in advance

1 9 3,266
9 REPLIES 9

Yes, it is possible to "pass values" to a Java callout. You can do it "implicitly" or "explicitly".

First, let's be clear that the Java Callout has available to it, at runtime, an object of type MessageContext. This object is documented; it has a number of exposed methods. An important one is getVariable(String). This allows the Java code to retrieve values of any variable in the message context, at runtime. Variables in the context hold the values for ... basically everything associated to the message. request headers, request content, the verb, the time-of-day, the results of policies that executed previously in the request (like client_id after a VerifyAccessToken), and so on.

There is a companion method setVariable(String, Object) that allows the Java code to write data into the MessageContext.

When I say "implicitly", what I mean is you can "hard code" some dependence within the Java code to always refer to a specific variable. For example you could design the code with a line like this:

String conversationId = 
   (String) msgCtxt.getVariable("request.header.conversation-id");

And what that does is retrieve the request header named "Conversation-Id". It will be null if there is no such header. Every time the callout runs, it will retrieve that variable. You can of course use any variable name there.... and implicitly the Java code will read the variables you specify.

OK, now what do I mean by "explicitly"? Well you can set properties on the Java callout in the policy configuration, and in doing so, tell the policy which variables to read. Check out this example:

<JavaCallout name="Java-HashCompute">
  <Properties>
    <Property name='debug'>true</Property>
    <Property name='apply-templates'>true</Property>
    <Property name='algorithm'>sha256</Property>
    <Property name='string-to-hash'>{request.content}</Property>
  </Properties>
  <ClassName>com.dinochiesa.edgecallouts.HashGeneratorCallout</ClassName>
  <ResourceURL>java://edge-callout-hash-1.0-SNAPSHOT.jar</ResourceURL>
</JavaCallout>

This is a real example of a callout that computes a Hash on "something". The Property elements there are available to the Callout at instantiation time. So when the callout starts up, it gets access to all those settings in the constructor. They are passed as a Map. Like this:

    private final Map properties;
    public HashGeneratorCallout(Map properties) {
        this.properties = properties;
    }

Then, when a request arrives, the callout will reference the Property named "string-to-hash", see that it refers to "request.content", and then call getVariable() on THAT. Maybe like this:

    private String getStringToHash(MessageContext msgCtxt) {
        String s = (String) this.properties.get("string-to-hash");
        if (s == null || s.equals("")) {
            // by default, get the content of the message (either request or response)
            return msgCtxt.getVariable("message.content");
        }
        if (isWrappedInCurlyBraces(s)) {
            return msgCtxt.getVariable(s.substring(1,s.length-1));
        }
        // it's not a variable reference; it's a fixed string
        return s;
    }

A good actual working example of this technique - relying on properties and the MessageContext - is available here. That code is open-source and Apache-licensed, so you should be able to freely borrow from it.

Whether you're using the "implicit" or hard-coded variable reference, or the "explicit" or property-driven variable references, it's the same mechanism... the callout is still using getVariable and setVariable. The difference is in configuration and re-usability.

Helpful?

@Dino

I have question on the line <Propertyname='string-to-hash'>{request.content}</Property>

My Callout looks like this

<Properties> <Property name="encrypt.utils.key">{timeoutKey}</Property> </Properties>

Where timeoutKey variable is retrieved from KVM. I have checked that value is being retrieved from KVM properly. But in the javacallout encrypt.utils.key is passed as "{timeoutKey}" not as a value of the variable timeoutKey. How can pass the value of timeoutKey to the callout constructor. My callout constructor looks like this.

public EncryptorCallout(Map<String, String> props){
        String key = props.get("encrypt.utils.key");
        o1.addProperty("key", key);
        if(null != key && key.length() == 16){
        ENCRYPTION_KEY = key;
        }
    }

Can you please help me on this?

yes, I can help you, but you must ask this question in a new question.

6135-ask-a-question.png

@Dino

I see you have used flow variables within the Properties configuration but as per this link in the docs, we can only specify literal string. Is that a docs issue ? I see your Java callout code has an else block that fetches the content from the message.content. But want to be sure if we need to update the docs. I have never used flow variables within Properties as I usually access them directly using messageContext.getVariable() method. But wanted your thoughts too

hi Sai

I'm not clear what you are asking.

the config I showed for the Java callout uses this:

<Property name='string-to-hash'>{request.content}</Property>

When the Java callout is instantiated, it receives the property with key "string-to-hash" and value "{request.content}". The Java callout itself includes intelligence to resolve this reference to a value.

I don't know what documentation you are referring to.

@Dino


Was referring to the note mentioned in the docs - https://docs.apigee.com/api-services/reference/java-callout-policy#Property

"You must specify a literal string value for each property; you cannot reference flow variables in this element"

So as per the docs, the value for string-to-hash will be "{request.content}" but not the actual value it holds as a flow variable

Confirmed, you cannot pass in variable through properties. This may have changed at some point, though. Need to use the other pattern, msgCtxt.getVariable etc.

correct. You can pass the NAME of a variable in properties, but to get the VALUE of the variable, your java code must call MessageContext.getVariable().