Red Hat Bugzilla – Bug 1002481
SwitchYard Drools CEP no longer supports Exchange which leads to NPE
Last modified: 2014-06-16 19:48:02 EDT
I have a simple Drools service with a CEP rule listening on an entry point. From this rule I send an object to another service using channels. This leads to the following exception:
11:14:00,417 DEBUG [org.switchyard.internal.EventManager] (pool-1-thread-4) Observer threw exception on event class org.switchyard.runtime.event.ExchangeCompletionEvent: java.lang.NullPointerException
at org.switchyard.internal.EventManager.publish(EventManager.java:52) [switchyard-runtime-1.1.0.M1-redhat-1.jar:1.1.0.M1-redhat-1]
at org.switchyard.bus.camel.CamelExchange.sendInternal(CamelExchange.java:232) [switchyard-bus-camel-1.1.0.M1-redhat-1.jar:1.1.0.M1-redhat-1]
at org.switchyard.bus.camel.CamelExchange.send(CamelExchange.java:174) [switchyard-bus-camel-1.1.0.M1-redhat-1.jar:1.1.0.M1-redhat-1]
at org.switchyard.component.bean.ClientProxyBean$ClientProxyInvocationHandler.invoke(ClientProxyBean.java:311) [switchyard-component-bean-1.1.0.M1-redhat-1.jar:1.1.0.M1-redhat-1]
at com.sun.proxy.$Proxy194.heartBeat(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_25]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_25]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_25]
at java.lang.reflect.Method.invoke(Method.java:606) [rt.jar:1.7.0_25]
at org.jboss.weld.bean.proxy.AbstractBeanInstance.invoke(AbstractBeanInstance.java:45) [weld-core-1.1.13.Final-redhat-1.jar:1.1.13.Final-redhat-1]
at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:105) [weld-core-1.1.13.Final-redhat-1.jar:1.1.13.Final-redhat-1]
at org.jboss.weld.proxies.CEPService$1366014918$Proxy$_$$_WeldClientProxy.heartBeat(CEPService$1366014918$Proxy$_$$_WeldClientProxy.java) [weld-core-1.1.13.Final-redhat-1.jar:]
at org.jboss.soa.qa.drools.cep.CEPService$heartBeat.call(Unknown Source)
The code in SwitchYardBuilder tries to obtain provider Exchange.getProvider() which returns null. This is no wonder since the in the last build of SOA-P I was not able to set provider to Drools globals in my service.
Comments in SwitchYardBuilder.exchangeCompleted(ExchangeCompletionEvent event) indicates that this is just a statistics colletion. So this should be rewritten.
Created attachment 791675 [details]
I'm not clear on what's meant by this comment:
"This is no wonder since the in the last build of SOA-P I was not able to set provider to Drools globals in my service."
You should never have to set provider in application code. The provider is set by the runtime. I would like to view the reproducer, but xz is not recognized by the version of tar in OS X so another format (gz, zip, tar) would help me out a lot.
Created attachment 792182 [details]
Artifacts in different format
Unfortunatelly, I do not have a standalone reproducer at the moment. I can create one if needed. Attached are the important files.
By setting the provider I meant configuring it in JBDS in Rules Component, Properties, Implementation, Operations, Globals and adding exchange.provider.name. This way I wanted to set the service name in a global variable...
Thanks, I can view the artifacts now. How are you driving the test? I see there's a DroolsCEPServiceTest in switchyard.xml that's not included in the tar. A reproducer would help a lot, but just knowing what drives the test will help too.
Created attachment 792800 [details]
I just inject the service and call it. Attaching the test sources.
The Groovy test with Arquillian looks cool, but this is pretty far outside our normal test suite. At this stage, we need a test case which uses our own unit test framework or a deployable application that can be driven externally (either through a test client you provide or through a gateway binding like SOAP).
It does not do anything difficult, it just directly calls the service...
It will take me some time to create a standalone reproducer, so this is why I originally skipped it hoping the description is sufficient. Meanwhile, if you look at org.switchyard.admin.base.SwitchYardBuilder.exchangeCompleted you can see
Exchange exchange = event.getExchange();
QName serviceName = exchange.getProvider().getName();
The problem is that exchange is null.
How to run the reproducer:
0) Reconfigure sample-settings.xml to contain correct paths. You need full ER1 repo.
1) tests/parents/parent mvn -s sample-settings.xml package install -DskipTests
2) tests/qa mvn -s sample-settings.xml package install -DskipTests
2b) now you can import tests/switchyard/drools-cep-test to JBDS supposing you have appropriate Maven config in Eclipse (the same repositories and local repo are used)
3) tests/switchyard mvn -s sample-settings.xml package install -DskipTests
4) start SOA-P standalone-full.xml in out of the box config
5) tests/switchyard/drools-cep-test mvn -s sample-settings.xml integration-test
Created attachment 793122 [details]
I will try and run the reproducer as is, but this is pretty far away from a supported scenario in the product based on how Arquillian is being used with injection of a SY reference in the test application. The reason I wanted a standalone reproducer is that it eliminates any possible bootstrap/lifecycle issues when using Arquillian.
Re: the NPE, this has no impact on the actual message flow as the admin layer catches any exceptions when processing events so they do not interrupt the processing of messages. That's why the exception itself is printed at DEBUG - the scope of the failure here is that metrics could not be collected on the exchange.
Created attachment 793180 [details]
cepnull.zip - standalone reproducer w/o Arquillian
I went ahead and created a new standalone application to reproduce this using the artifacts provided. I added an SCA binding and introduced a remote test client to replace the use of reference injection in Arquillian. I am able to see the NPE in DEBUG output with this application, but I want to reiterate that this is not the root cause of the issue here. The following exception info from the message trace does point to something though:
CamelExceptionCaught : java.lang.IllegalStateException: Unable to find BeanManager. Please ensure that you configured the CDI implementation of your choice properly.
My suspicion here is that the class loader chain used for dispatch on the Drools channel is not being set correctly (or is being reset somewhere by Drools), which causes the CDI BeanManager lookup to fail. Kicking this over to David to debug deeper.
David - the attached cepnull.zip will allow you to reproduce. You should be able to test using a 1.0.0.Final or 1.1.0-SNAPSHOT build if you don't have a SOA-P 6 build around.
I was able to reproduce this with Keith's example. It is indeed the classloader used in the FireUntilHalt thread that is spawned which is incorrect, causing the BeanManager to not be found. I tested a fix that works. i.e.: After the fix, there is no more exception, and the demo application's AuditorCEPServiceBean is properly invoked. I will now create a jira and submit a pull request.
PS: This had absolutely nothing to do with "exchange" being available for use as a variable. So, this line in the switchyard.xml:
<rules:global from="exchange.serviceName.localPart" to="service"/>
should be removed, and these line in the RulesComponent.drl should be removed/modified as well:
global java.lang.String service
System.out.println("In service: CEPService(" + service + "), payload: " + message.getContent() + ", context: " + context);
David Ward <email@example.com> made a comment on jira SWITCHYARD-1689
(In reply to David Ward from comment #15)
> PS: This had absolutely nothing to do with "exchange" being available for
> use as a variable. So, this line in the switchyard.xml:
> <rules:global from="exchange.serviceName.localPart" to="service"/>
> should be removed, and these line in the RulesComponent.drl should be
> removed/modified as well:
> global java.lang.String service
> System.out.println("In service: CEPService(" + service + "), payload: " +
> message.getContent() + ", context: " + context);
Yes, it became clear too me later. Sorry for the misleading analysis...
Keith Babo <firstname.lastname@example.org> made a comment on jira SWITCHYARD-1689
Verified in ER7
Keith Babo <email@example.com> updated the status of jira SWITCHYARD-1689 to Closed