cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with ObjectMessage in Message Driven Bean

Former Member
0 Kudos

Hi everyone,

I have a problem whiling developing a MDB scenario with ObjectMesssage.

Scenario description:

A client sends a MapMessage to a MDB and waits for a reply. The MDB will process this MapMessage and creates several reply objects, which implement the java Serializable interface and are saved in an ArrayList.

At the end, the MDB will put the ArrayList into the ObjectMessage (ObjectMessage.setObject()) and sends the message back to the client.

For this scenario, three DCs are created --> 1. DC for client; 2. DC for MDB; 3. DC for the "reply object". The "reply object" DC is referenced in the client DC and MDB DC by using "Used DC".

In the Compile Time, there is no error about the "reply object". I could use the "reply object" in the client DC or in the MDB DC.

In the Run Time, the MDB DC can build the reply object instances and send them in the Object message. But I got exceptions on the client side:

com.sap.jms.client.message.ObjectMessage.getObject(ObjectMessage.java:114)

at com.sap.jms.protocol.message.MessageRequest.readBody(MessageRequest.java:408)

javax.jms.JMSException: null class

Exception was thrown while trying to load class: uwl.konplan.domino.provider.DominoItem with classloader: com.sap.engine.services.deploy.server.ApplicationLoade

Please give me some tips.

with best regards

Xiang

Accepted Solutions (0)

Answers (1)

Answers (1)

Former Member
0 Kudos

HI Xiang,

The exception is that your client cannot properly classload the objects you have sent (uwl.konplan.domino.provider.DominoItem).

I am not a big expert in the NWDI, but as far as I remember there were several type of DC dependancies -- Build time, Assembly time, Runtime

You would need a Runtime dependancy between the client and the reply object in order to allow runtime classloading.

HTH

Peter

Former Member
0 Kudos

Hi Peter,

First thanks a lot for your reply.

Actually I have already set the "Dependeny Type" as "Runtime(strong)" for the reply object in the client Used DC. But it did not work.

The problem is that, I didn't do this in the MDB DC. But it works in the MDB DC.

with best regards

Xiang

Former Member
0 Kudos

HI Xiang,

That sounds strange, can you do a little experiment to try to see if that is a problem in the JMS / MDB or a classloading issues due to some of the references. Somewhere in your code in the client try to instantiate manually the object. I.e.

DominoItem test = new DominoItem();

System.err.println("Success" + test);

Btw, can you provide more info - where is that client running from (servlet / EJB ?) also what server version you are using

Best Regards

Peter

Former Member
0 Kudos

Hi Peter,

I wrote the test codes in the client DC as you suggested and got the following error:

java.lang.NoClassDefFoundError: uwl/konplan/domino/dominoitem/DominoItem

The server vesion is: NetWeaver 7.00 SP7, Java version: 1.4.2_11-b06

The client is running as a Portal Modul (Portal Application Standalone), which will be called by the UWL service. It implements the "com.sap.netweaver.bc.uwl.connect.IProviderConnector" interface.

Best Regards

Xiang

Former Member
0 Kudos

Hi Peter,

I've defined the DominoItem DC in the "SharingReference" element in the portapp.xml of the client DC. The error "java.lang.NoClassDefFoundError: uwl/konplan/domino/dominoitem/DominoItem" is solved.

I can create instances of the DominoItem class in the client DC and in the MDB DC. But the JMSException is not solved.

I guess that the DominoItem class is still unknown to the JMS service. Because when I call the methode ObjectMessage.getObject(), the JMS service tries to de-serialize the DominoItem objects in its own context.

Best Regards

Xiang

Former Member
0 Kudos

Hi Xiang,

I am assuming you are calling a synchronous recveive -- receiver.receive() in order to get the object message sent back from the MDB In that case the current thread classloader will be used. As you can see from the exception :

uwl.konplan.domino.provider.DominoItem with classloader: com.sap.engine.services.deploy.server.ApplicationLoade

That is the ApplicationLoader not something from the JMS. So i strongly doubt JMS is the problem.

Two things that you can check further :

1) When a deserialization is involved it will try to deserialize the full object graph. I.e. if your dominoItem has a field with class FOO, than the getObject() call must be able to classload FOO. Please check if some classes should be added as well in that portapp.xml of yours

2) Make sure that you test to instantiate the DominoObject right before you call getObject() and not in some different thread and logic in your application. Just to be sure that you can really classload it.

HTH

Peter

Former Member
0 Kudos

Hi Peter,

appreciate for your new suggetions.

Actually I used the MessageListener to receive the reply messages. In the DominoItem class there are only String and Date variables to contain the information. In the onMessage() method I can also create instances of the DominoItem class.

In the debug mode, I noticed the message parameter of the methode onMessage(Message message) has already contained the "javax.jms.JMSException: null class" in the "messagePacket" property. It means the JMS service can not correctly interpret the incoming message or maybe it can not unterstand the DominoItem class when the MDB sends the message.

with kind regards

Xiang

Former Member
0 Kudos

Hi Xiang,

The problem is definetely on the receiving side, otherwise the message sending in the MDB would have failed..

Can you try the following, put the following code inside the onMessage, before you call getObject :

Thread.currentThread.setContextClassLoader(myDominoObject.getClass().getClassLoader());

Btw, usually it should be restored in a finally clause, but that's just for testing.

If even that's not eliminating the exception, can you leave an email address ? I might try to get you a contact person to deal faster with the problem.

Btw, setting MessageListeners manually as you do is not allowed according to the Java EE spec if done in the servlet \ EJB container.

HTH

Peter

Former Member
0 Kudos

Hi Peter,

Thanks a lot. Your suggestion works. But this solution is very dangerous. It should be only used for testing purpose.

But now we can tell that the problem is the JMS thread. Its classloader could not find the DominoItem class. Why? No idea.

Could you please give us some more tips to handle this problem?

best regards

Xiang

Former Member
0 Kudos

Hi Peter,

"setting MessageListeners manually as you do is not allowed according to the Java EE spec if done in the servlet \ EJB container. "

I don't understand what you mean here. Could you please give me more information?

Actually the client DC is a UWLConnector for SAP UWL service. The MessagerListener is located in this DC and registered to a tempory queue to receive the reply messages from the MDB DC.

with best regards

Xiang

Former Member
0 Kudos

HI Xiang,

It should be not the classloader of the JMS, but the cached classloader when your JMS connection has been created, now that we have pinpointed the problem you should verify that at the moment you call factory.createConnection() your classloader can load the DominoItem.

Btw, the MDB is within the same cluster, right ?

You have mentioning that you have a temporary destination and you set a message listener on top of it , out of curiosity -- do you create such destination after each message to the MDB ? How do you delete the temporary destination and close the listeners ?

Can't you use something like the javax.jms.QueueRequestor ?

Best Regards

Peter

Former Member
0 Kudos

Hi Peter,

I think the problem should be in the JMS service. I've already load the DominoItem before called factory.createConnection().

DominoItem tempItem = new DominoItem();

Category.APPLICATIONS.fatal(LOC, "DominoItem In Connector --> " + tempItem.getClass().getClassLoader());

tConnection = topicConnectionFactory.createTopicConnection();

qConnection = queueConnectionFactory.createQueueConnection();

The Client DC, MDB and JMS are located on the same cluster.

The temporary queue is created for receiving reply messages. I don't delete the temporary destination. Because in the JavaDoc I found the following:

"Creates a TemporaryQueue object. Its lifetime will be that of the QueueConnection unless it is deleted earlier."

with regards

Xiang

Former Member
0 Kudos

Hi Xiang,

Indeed the temporary destination and the message listener will be removed when the queueConnection is closed. However that raises the question as to when exactly you close the connecton ? You can't close it inside onMessage, you will get a deadlock since by spec and javadoc closing should wait for all message processing to finish. And if you leave it opened forever and just create new objects for each message, that would be a memory leak.

Btw, would you mind if I contact you by email so you can share some trace files \ sample source code what you invoke from the JMS and not post them here. Perhaps I can help you after I could see in more details what is going. But it's quite specific problem, I doubt anyone else is interested.

HTH

Peter

Former Member
0 Kudos

Hi Peter,

thanks for your reply.

I close the temporary destination in the client DC not inside the onMessage method. And the client DC will wait 30 seconds for the reply messages from the listener. After that, the connection will be closed.

My email is: xzhang@konplan.com

with best regards

Xiang

Former Member
0 Kudos

An SAP ticket is opened for this problem.

This thread will be closed.

Thanks a lot Peter.

Former Member
0 Kudos

Just a short summary of the whole problem -- at the moment it is not possible to use JMS ObjectMessages out of threads launched by the UWL. (The ContextClassLoader used by the JMS for classloading the object messages is not set to the application one by the UWL)

It will not be possible both for synchronous and asynchronous programming.