on 07-25-2007 9:01 AM
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
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
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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
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
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
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
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
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
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
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
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
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
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
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.
User | Count |
---|---|
87 | |
10 | |
10 | |
9 | |
7 | |
6 | |
6 | |
5 | |
4 | |
3 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.