Failed to instantiate the JavaCallout Class

Hello Apigee Forum,

currently we are trying to deploy a global Resource for our JavaCallouts and it`s apparently not loading the class correctly.

When we upload the Resource using the REST Api, then we get the usual OK Response and also using the REST Api we are able to see the deployed Jar.

But when we use it in a Policy like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<JavaCallout async="false" continueOnError="false" enabled="true" name="QuotaUseAlertPolicy">
    <DisplayName>QuotaUseAlertPolicy</DisplayName>
    <Properties>
        <Property name="allowedCountVariableName">ratelimit.Quota-Limits.allowed.count</Property>
        <Property name="usedCountVariableName">ratelimit.Quota-Limits.used.count</Property>
    </Properties>
    <ClassName>de.allianz.apigateway.apigee.QuotaUseAlertPolicy</ClassName>
    <ResourceURL>java://apigee-java-callouts-fat.jar</ResourceURL>
</JavaCallout>

We get the following Error Message

Error in deployment for environment test.The revision is deployed, but traffic cannot flow. Failed to instantiate the JavaCallout Class de.allianz.apigateway.apigee.QuotaUseAlertPolicy

and from the log of the MessageProcessor

Apigee-Main-3 ERROR BOOTSTRAP - RuntimeConfigurationServiceImpl.dispatchToListeners() : RuntimeConfigurationServiceImpl.dispatchToListeners : Error occurred while dispatching the request DeployEvent{org anization='adag', application='dev-immchk_test-gw-immchk', applicationRevision='2', deploymentSpec=basepath=/;env=test;, deploymentID=null} to com.apigee.application.bootstrap.listeners.MessageProcessorBootstrapListener@37e6e38 d
com.apigee.kernel.exceptions.spi.UncheckedException: Failed to instantiate the JavaCallout Class de.allianz.apigateway.apigee.QuotaUseAlertPolicy
        at com.apigee.steps.javacallout.JavaCalloutStepDefinition.newInstance(JavaCalloutStepDefinition.java:89) ~[javacallout-1.0.0.jar:na]
        at com.apigee.messaging.runtime.StepDefinition.getStepDefinitionExecution(StepDefinition.java:230) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.runtime.Step.createExecutionInstance(Step.java:78) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.runtime.Step.handleAdd(Step.java:58) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.runtime.Flow.addStep(Flow.java:123) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.runtime.Flow.addSteps(Flow.java:115) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.runtime.Flow.handleAdd(Flow.java:93) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.runtime.Endpoint.addFlow(Endpoint.java:274) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.runtime.Endpoint.initPreFlow(Endpoint.java:147) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.runtime.Endpoint.handleAdd(Endpoint.java:81) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.runtime.ProxyEndpoint.handleAdd(ProxyEndpoint.java:70) ~[message-processor-1.0.0.jar:na]
        at com.apigee.entities.AbstractConfigurator.handleUpdate(AbstractConfigurator.java:125) ~[config-entities-1.0.0.jar:na]
        at com.apigee.messaging.runtime.Application.handleUpdate(Application.java:235) ~[message-processor-1.0.0.jar:na]
        at com.apigee.entities.AbstractConfigurator.loadXMLConfigurations(AbstractConfigurator.java:215) ~[config-entities-1.0.0.jar:na]
        at com.apigee.messaging.runtime.Application.sync(Application.java:598) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.runtime.Application.sync(Application.java:559) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.runtime.ApplicationManager.handleUpdate(ApplicationManager.java:119) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.runtime.Environment.handleUpdate(Environment.java:220) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.runtime.EnvironmentManager.propagateEvent(EnvironmentManager.java:176) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.runtime.EnvironmentManager.handleUpdate(EnvironmentManager.java:132) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.configuration.MessageProcessorServiceImpl.configure(MessageProcessorServiceImpl.java:623) ~[message-processor-1.0.0.jar:na]
        at com.apigee.application.bootstrap.listeners.MessageProcessorBootstrapListener.configureMessageProcessorService(MessageProcessorBootstrapListener.java:74) ~[application-bootstrap-1.0.0.jar:na]
        at com.apigee.application.bootstrap.listeners.MessageProcessorBootstrapListener.deploy(MessageProcessorBootstrapListener.java:32) ~[application-bootstrap-1.0.0.jar:na]
        at com.apigee.application.bootstrap.RuntimeConfigurationServiceImpl.dispatchToListeners(RuntimeConfigurationServiceImpl.java:571) [application-bootstrap-1.0.0.jar:na]
        at com.apigee.application.bootstrap.RuntimeConfigurationServiceImpl.deploy(RuntimeConfigurationServiceImpl.java:243) [application-bootstrap-1.0.0.jar:na]
        at com.apigee.application.bootstrap.RuntimeConfigurationRPCService.deployUsingInfos(RuntimeConfigurationRPCService.java:96) [application-bootstrap-1.0.0.jar:na]
        at com.apigee.application.bootstrap.RuntimeConfigurationRPCService.deploy(RuntimeConfigurationRPCService.java:76) [application-bootstrap-1.0.0.jar:na]
        at com.apigee.application.bootstrap.proto.RuntimeConfig_ConfigRPCService_BlockingSkeleton$1.run(RuntimeConfig_ConfigRPCService_BlockingSkeleton.java:38) [application-bootstrap-1.0.0.jar:na]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_151]
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_151]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_151]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_151]
        at java.lang.Thread.run(Thread.java:748) [na:1.8.0_151]
Caused by: java.lang.ClassNotFoundException: de.allianz.apigateway.apigee.QuotaUseAlertPolicy
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_151]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_151]
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) ~[na:1.8.0_151]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_151]
        at com.apigee.messaging.resource.JavaResourceClassLoader.loadClassSelfFirst(JavaResourceClassLoader.java:218) ~[message-processor-1.0.0.jar:na]
        at com.apigee.messaging.resource.JavaResourceClassLoader.loadClass(JavaResourceClassLoader.java:117) ~[message-processor-1.0.0.jar:na]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_151]
        at java.lang.Class.forName0(Native Method) ~[na:1.8.0_151]
        at java.lang.Class.forName(Class.java:348) ~[na:1.8.0_151]
        at com.apigee.steps.javacallout.JavaCalloutStepDefinition$CallOutWrapper.initialize(JavaCalloutStepDefinition.java:103) ~[javacallout-1.0.0.jar:na]
        at com.apigee.steps.javacallout.JavaCalloutStepDefinition$CallOutWrapper.<init>(JavaCalloutStepDefinition.java:99) ~[javacallout-1.0.0.jar:na]
        at com.apigee.steps.javacallout.JavaCalloutStepDefinition.newInstance(JavaCalloutStepDefinition.java:85) ~[javacallout-1.0.0.jar:na]
        ... 32 common frames omitted


We have also validated if the JAR is correctly build, using another Proxy but this time including directly the Script JAR in the policy.

In this case, the Proxy is correctly deployed and the JavaCallout is performed as expected.

Lastly, we tryed to delete the global resource JAR file, but that´s also not possible, because it is in use by the Proxies

{
 "code" : "events.EventHandlingFailure",
 "message" : "Resource is in use by [QuotaUseMailPolicy, SecurityTokenValidation, QuotaUseAlertPolicy]",
 "contexts" : [ ]
}

According to that, I would expect that the JAR is indeed loaded, but still we cannot get the Proxy to be deployed.

Is there anything that we should do after deploying a JAR using the REST Api?

PS: we have also restarted the MessageProcessors, without any luck.

Thank you very much in advance,

Oscar Pinilla

Solved Solved
0 2 856
1 ACCEPTED SOLUTION

Hello everybody,

I managed to solve the problem.

It´s important to upload the Resource using the following Headers:

var headers = {
		'Authorization' : 'Basic ' + Buffer.from(apigeeCredentials).toString('base64'),
		Accept: 'application/json',
	    'Content-Type': 'application/octet-stream;',
	    'Content-Length': Buffer.byteLength(multipartBody),
	    'Content-Disposition' : 'attachment',
	    'name' : fileName,
	    'filename' :  fileName
	};

If you use 'Content-Type' 'multipart/form-data' with boundary and 'Content-Disposition' 'form-data', the file will upload, apigee will mark the resource as accepted BUT it won´t start correctly (see the error mentioned earlier).

Apparently the boundaries are not correctly used to identify the start and end of the file, and therefore used as part of the actual file content.

If anyone is interested, I can also provide the working Node.js code to upload files to Apigee.

Regards,

Oscar Pinilla

View solution in original post

2 REPLIES 2

I also tryed with some ultra-simplified JavaCallout and the result is still the same.

Therefore, I don´t think the problem comes from the Java Class Code, but from the instantiation of the Global Resource in the Organisation.

public class ResponseUppercase implements Execution {


    @Override
    public ExecutionResult execute(final MessageContext messageContext, final ExecutionContext executionContext) {
        try {


            final Set<String> headers = messageContext.getMessage().getHeaderNames();


            for (final String header : headers) {
                final String h = messageContext.getMessage().getHeader(header).toUpperCase();
                messageContext.getMessage().setHeader(header, h);
            }


            // final String content = messageContext.getMessage().getContent();
            // messageContext.getMessage().setContent(content.toUpperCase());


            return ExecutionResult.SUCCESS;


        } catch (final Exception e) {
            messageContext.setVariable("java.error.status.code", 9999);
            messageContext.setVariable("java.error.reason.phrase", e.getMessage());
            messageContext.setVariable("java.error.header.Content-Type", "application/json");
            messageContext.setVariable("java.error.content", e.getStackTrace());


            return ExecutionResult.ABORT;
        }
    }
}

Hello everybody,

I managed to solve the problem.

It´s important to upload the Resource using the following Headers:

var headers = {
		'Authorization' : 'Basic ' + Buffer.from(apigeeCredentials).toString('base64'),
		Accept: 'application/json',
	    'Content-Type': 'application/octet-stream;',
	    'Content-Length': Buffer.byteLength(multipartBody),
	    'Content-Disposition' : 'attachment',
	    'name' : fileName,
	    'filename' :  fileName
	};

If you use 'Content-Type' 'multipart/form-data' with boundary and 'Content-Disposition' 'form-data', the file will upload, apigee will mark the resource as accepted BUT it won´t start correctly (see the error mentioned earlier).

Apparently the boundaries are not correctly used to identify the start and end of the file, and therefore used as part of the actual file content.

If anyone is interested, I can also provide the working Node.js code to upload files to Apigee.

Regards,

Oscar Pinilla