JMS resource adapter and classloading
cheaway Jun 10, 2011 5:37 AMHi,
I wrote a jms resource adapter that connects to any queue or topic on any server, be it remote or local. My MDBs define host, port and other relevant connection information and they can connect to that queue.
If I receive a message on the queue, the adapter is properly creating the message endpoint and passing the message on to the MDB. However, when I cast the message to my own message type (let's say 'MyMessage'), I get the following exception:
{code}
2011-06-10 10:48:39,917 WARN [com.three.MyListenerImpl] (imqConsumerReader-0-6916737897836249856-0) Retrieved a message we cannot handle: '
Class: com.sun.messaging.jmq.jmsclient.ObjectMessageImpl
getJMSMessageID(): ID:394384-192.168.30.63(8e:ca:b3:7b:d5:db)-1-1307695719913
getJMSTimestamp(): 1307695719913
getJMSCorrelationID(): null
JMSReplyTo: null
JMSDestination: my_topic
getJMSDeliveryMode(): PERSISTENT
getJMSRedelivered(): false
getJMSType(): null
getJMSExpiration(): 0
getJMSPriority(): 4
Properties: null' because: [C4015]: Deserialize message failed. - cause: java.lang.ClassNotFoundException: com.one.MyMessage from BaseClassLoader@53b5e629{VFSClassLoaderPolicy@4b19b8ae{
[snip]
}
at com.sun.messaging.jmq.jmsclient.ObjectMessageImpl.getObject(ObjectMessageImpl.java:215)
at com.three.MyListenerImpl.onMessage(MyListener.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jboss.aop.joinpoint.MethodInvocation.invokeTarget(MethodInvocation.java:122)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:111)
at org.jboss.ejb3.EJBContainerInvocationWrapper.invokeNext(EJBContainerInvocationWrapper.java:69)
at org.jboss.ejb3.interceptors.aop.InterceptorSequencer.invoke(InterceptorSequencer.java:73)
at org.jboss.ejb3.interceptors.aop.InterceptorSequencer.aroundInvoke(InterceptorSequencer.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jboss.aop.advice.PerJoinpointAdvice.invoke(PerJoinpointAdvice.java:174)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.interceptors.aop.InvocationContextInterceptor.fillMethod(InvocationContextInterceptor.java:72)
at org.jboss.aop.advice.org.jboss.ejb3.interceptors.aop.InvocationContextInterceptor_z_fillMethod_1789250033.invoke(InvocationContextInterceptor_z_fillMethod_1789250033.java)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.interceptors.aop.InvocationContextInterceptor.setup(InvocationContextInterceptor.java:88)
at org.jboss.aop.advice.org.jboss.ejb3.interceptors.aop.InvocationContextInterceptor_z_setup_1789250033.invoke(InvocationContextInterceptor_z_setup_1789250033.java)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:62)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor.invoke(TransactionScopedEntityManagerInterceptor.java:56)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.AllowedOperationsInterceptor.invoke(AllowedOperationsInterceptor.java:47)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.tx.NullInterceptor.invoke(NullInterceptor.java:42)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:68)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.aspects.tx.TxPolicy.invokeInCallerTx(TxPolicy.java:126)
at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:194)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.tx.NullInterceptor.invoke(NullInterceptor.java:42)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.security.Ejb3AuthenticationInterceptorv2.invoke(Ejb3AuthenticationInterceptorv2.java:80)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.BlockContainerShutdownInterceptor.invoke(BlockContainerShutdownInterceptor.java:67)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.aspects.currentinvocation.CurrentInvocationInterceptor.invoke(CurrentInvocationInterceptor.java:67)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.mdb.MessagingContainer.localInvoke(MessagingContainer.java:282)
at org.jboss.ejb3.mdb.inflow.MessageInflowLocalProxy.delivery(MessageInflowLocalProxy.java:270)
at org.jboss.ejb3.mdb.inflow.MessageInflowLocalProxy.invoke(MessageInflowLocalProxy.java:140)
at $Proxy780.onMessage(Unknown Source)
at com.two.MyMessageListener.onMessage(MyMessageListener.java:48)
at com.sun.messaging.jmq.jmsclient.MessageConsumerImpl.deliverAndAcknowledge(MessageConsumerImpl.java:338)
at com.sun.messaging.jmq.jmsclient.MessageConsumerImpl.onMessage(MessageConsumerImpl.java:273)
at com.sun.messaging.jmq.jmsclient.SessionReader.deliver(SessionReader.java:113)
at com.sun.messaging.jmq.jmsclient.ConsumerReader.run(ConsumerReader.java:186)
at java.lang.Thread.run(Thread.java:662)
{code}
Now, this all works if I deploy the application containing the MDBs in the same classloader as the resource adapter - namely the default classloader. But if I do that, the classloaders get linked and undeploying the ear messes up the classloading and I get lots of exceptions and JBoss freezes so that I have to restart.
I do not understand why the resource adapter creates the message endpoint using the correct classloader but then loads the depending classes in its own classloader. Is there a way to make the call remote, so that I can force the MDB to load the message in its own classloader?
Or what is the appropriate way to fix this?
By the way, I am using JBoss 5.1.
Thanks for your help,
Che