Openwings Home
Introduction
Search
In the News
Frequently Asked Questions
Registration
Open Forum
Openwings Tutorial
Bug Database
Openwings API
Download
Expert Teams
Process Management Office
Projects
Links
Terms of Use
Comment on this bug

05798:

ClassNotFoundExceptions when mobile code uses Component Services

Category: Component
Status: Closed

Severity: MEDIUM
Reported against release: 0.9
Fixed in release: 0.9.1

PROBLEM:

A user reported the following stack trace in a client program that used 
a service:

javax.jms.MessageFormatException: 
com.gd.openwings.connector.asynchronous.openjms.SerializableMethod
	at org.exolab.jms.message.ObjectMessageImpl.getObject(Unknown 
Source)
	at 
com.gd.openwings.connector.asynchronous.openjms.broadcast.BroadcastConne
ctorSubscriberProxyImpl.onMessag
		(BroadcastConnectorSubscriberProxyImpl.java:289)
	at org.exolab.jms.client.JmsMessageConsumer.onMessage(Unknown 
Source)
	at org.exolab.jms.client.JmsSession.execute(Unknown Source) 
	at org.exolab.jms.client.JmsSession.onMessage(Unknown Source)
	at org.exolab.jms.client.rmi.RmiJmsSessionStub.onMessage
(Unknown Source)
	at java.lang.reflect.Method.invoke(Native Method) 
	at sun.rmi.server.UnicastServerRef.dispatch
(UnicastServerRef.java:241)
	at sun.rmi.transport.Transport$1.run(Transport.java:152)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.Transport.serviceCall(Transport.java:148)
	at sun.rmi.transport.tcp.TCPTransport.handleMessages
(TCPTransport.java:465) 
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run
(TCPTransport.java:706)

Apparently the implementation of the service was a smart proxy that 
used Component Services (and an OpenJMS asynchronous connector) to 
subscribe to some message interface. These error messages would occur 
whenever the smart proxy received a message.

ANALYSIS:

Quick background: Service implementations can either be the UserProxy 
side of an Openwings connector, or any Serializable object that 
implements the service interface - aka "smart proxy".

Some users have written smart proxies that implement services mostly or 
even completely on the client side. Some of these smart proxies 
actually use Component Services to do other service interactions behind 
the scenes. 

Analysis: the exception shown in the problem description is actually a 
JMSException wrapping a ClassNotFoundException (or 
NoClassDefFoundError). Here's a few steps that describe what is 
happening:

- The service (smart proxy) is discovered by the client. Because of how 
Java RMI works, the smart proxy class is actually loaded in its own 
URLClassLoader. 

- When the smart proxy's connect() method is called by Component 
Services, the smart proxy makes a call back in to Component Services - 
Component.subscribeService() on some messaging interface. 

- Behind the scenes, Component Services distributes the object (just 
like calling Component.distributeObject(). This causes the OpenJMS 
connector for the messaging interface to be loaded, and the 
SubscriberProxy is instantiated.

- When the SubscriberProxy is instantiated, what actually happens is an 
RMI exportObject() call (since we're using the RMI-based version of 
OpenJMS), which creates a RMI thread that listens on a socket. Because 
this call occurs from a thread initiated by Component Services, the RMI 
thread has the same context ClassLoader that Component Services (and 
the rest of the program has).

- When a message comes in via the JMS connector, the connector attempts 
to unmarshal the arguments. However, the context class loader for the 
thread is the main program's classloader, and not the smart proxy's 
classloader so the classes representing any types on the message must 
be on the main program classpath. If a class is not on the main program 
classpath, a ClassNotFoundException will be thrown, and this will be 
wrapped in a JMSException by the OpenJMS connector.

Note that this problem could also occur if a smart proxy calls 
Component.distributeObject() and provides the distributed object as a 
service, or passes the distributed object to another program directly. 

The suggested solution is to modify the implementation of 
Component.distributeObject(). When an object is distributed, it's class 
should be mapped to a ClassLoader. If this ClassLoader is not the 
context ClassLoader, it should be set as the context ClassLoader 
temporarily while the object is being distributed, then the original 
context ClassLoader should be replaced. In this way, any threads 
created by distributing the object will have the correct context 
ClassLoader, since threads inherit their parent thread's context 
ClassLoader at creation.

back to top

home | vision | search | in the news | faq | registration | open forum | tutorial | bug database
 API | download | expert teams | process management office | projects | links | terms of use

© Copyright 2001-2006 General Dynamics C4 Systems. All rights reserved.