Access Keys:
Skip to content (Access Key - 0)









Introduction

This document identifies classloading problems that may arise in JAIN SLEE using Rhino, their common causes and how problems can be diagnosed.

First, an explanation of why classloading can be an issue in JAIN SLEE is given. The document then describes the classloader structure used by Rhino for deployed components. Next, a brief description of the types of classloading errors often seen is provided along with their common causes. Detailed explanations are then given on how the classloader debugging information generated by Rhino can be interpreted and used to pinpoint the specific cause of a problem. Finally some approaches to diagnosing the different types of problems are suggested.

What Makes Classloading an Issue in JAIN SLEE?

There are seven different types of deployable component defined by JAIN SLEE 1.1: libraries, SBBs, services, event types, resource adaptor types, resource adaptors, and profile specifications. SLEE allows each type of component to depend on other components of certain types, leading to a directed graph structure where nodes represent components and arcs represent dependencies. Cycles may be present, such as where a parent and child SBB mutually depend on each other, but these are generally limited by the types of component dependencies SLEE allows. For example a resource adaptor type can depend on an event type, but an event type cannot depend on a resource adaptor type. Therefore a cyclic dependency between a resource adaptor type and an event type can never occur.

The following figure illustrates a typical dependency graph for a number of deployed components.

In this example we see a service containing two SBBs. The root SBB depends on a resource adaptor type, which in turn depends on some event types that themselves depend on a library. The root SBB also depends on a profile specification, which is also used by the child SBB that the root SBB depends on. The child SBB has a cyclic dependency back to its parent, and also depends on a second profile specification. Finally, a resource adaptor depends on the resource adaptor type used by the root SBB.

A notable classloader issue becomes apparant when a dependency graph such as the above is considered. It is possible for a component to depend on other components which have no common ancestor. For example, the profile specification and the resource adaptor type that the root SBB in the figure above depends on have no ancestor component in common. There are a number of possible implementation choices to deal with this issue:

  • Load all classes for all components in a single classloader. This option would be good enough for a development environment where the SLEE can be restarted and reloaded with new deployable units whenever required. However it is unsatisfactory for a production platform as it precludes the ability to have mulitple versions of the same class deployed at the same time and therefore online upgrade of components becomes extremely difficult.
  • Create a new classloader, independent from all other similarly created classloaders, for each service or resource adaptor installed in the SLEE. While this would allow each service and resource adaptor to operate within their own flat classloader structure, it would make communication between the components almost impossible due to multiple copies of the common classes being loaded by the different classloaders.
  • Use a custom "multi-parent" classloader that allows independent classloader hierarchies to be brought together. This is the option implemented in Rhino, and ensures that only one instance of each class included in each component jar is loaded by the JVM.

A second, minor, issue is how to deal with cyclic dependencies. As it makes no sense to create a cyclic classloader structure the only remaining option is to ensure that the all the classes for components with cyclic dependencies are loaded by the same classloader.

Visualisation of SLEE component dependencies in Rhino

The dependency-graph command line utility in the rhino/client/bin directory can show the dependencies between SLEE components in a running SLEE. (Requires Graphviz to generate images).

Potential Classloader-Related Errors

The most common exceptions seen due to classloader problems, likely causes, and probable solutions are as follows:

Exception / Error Problem Likely Cause Possible Solution
ClassNotFoundException An explicit attempt to load class XYZ using ClassLoader.loadClass or Class.forName failed because the class could not be found. If class XYZ can't be found even though the class appears in the component jar where you think it should be, most likely the class trying to load XYZ was loaded from an ancestor component and therefore the classloader of that class has no visibility to XYZ. Move or add XYZ to the component jar containing the class trying to load it, or modify the classloading code so that you can specify a different classloader to use.
NoClassDefFoundError An implicit attempt to load class XYZ failed because the class could not be found. Implicit classloading attempts are made by the JVM to resolve class dependency relationships. A class that depends on XYZ was loaded from an ancestor component, and that component does not include XYZ. Move or add XYZ to the component jar containing the class that depends on it.
ClassCastException A particular object can't be cast to class XYZ even though the object implements or extends XYZ. Two instances of XYZ have been loaded by the JVM in different classloaders. The object you have implements or extends one instance of the XYZ class, and you're trying to cast it to the second instance of the class. There are two cases where this could occur:
  1. XYZ exists in multiple component jars which have no common ancestor component, but there is some other component that depends on these component jars. For example class XYZ exists in two different profile specifications defined in separate component jars, and an SBB uses both profile specifications.
  2. XYZ exists in multiple component jars whose classes may communicate with each other, but are not directly related by a component dependency. For example class XYZ exists in a resource adaptor and an SBB, and the resource adaptor and SBB communicate with each other via events and the resource adaptor interface.
For case (1), move XYZ into a library and have the components which require the class depend on the library. This ensures only one instance of the class will be loaded for all components that depend either directory or indirectly on the library.
 
For case (2), class XYZ should be moved into the resource adaptor type component (or possibly higher in the dependency graph as required) that both the resource adaptor and SBB share a dependency on. This ensures the components share the class definition of XYZ.
IncompatibleClassChangeError or other LinkageError A class' definition has unexpectedly changed. This error is quite rare but is generally caused by the same problems as that which leads to ClassCastExceptions but manifests during an implicit classloading operation. (In constrast a ClassCastException occurs when code is running in which the class definitions have already been loaded.) Problem resolution is the same as that for the ClassCastException.

Generally speaking, all classloader problems stem from the presence of multiple instances of a class being loadable by the JVM at different codepoints within a set of related components. In order to be completely safe from classloader problems, any class used by the set of SBBs in a service, and the profile specifications, resource adaptor types, event types, and libraries the SBBs depend on, must be loaded at most once within the classloader hierarchy used by the service.

Debugging Classloader Problems in Rhino

Determining exactly why a classloader error occurs and finding the correct solution to the problem can often require some detailed analysis of how classes have been loaded by the JVM. Rhino is capable of generating comprehensive debugging information to aid in diagnosing possible classloader related problems. This debugging information includes information on:

  • the classloaders created by Rhino for each installed component, the jar URLs accessed by each classloader, and the parent classloaders used
  • attempts by a classloader to find a class or resource, and the outcome of each attempt

Enabling Classloader Debugging

To enable classloader debugging, set the "rhino.classloaders" log key to DEBUG level using rhino-console or some other management tool. The console command to do this is as follows:

setloglevel rhino.classloaders debug

Due to the overhead incurred by this debugging information Rhino decides at the time it creates a classloader whether to create a standard classloader or a classloader that generates debug output. Therefore if the components for which classloader debug information is required are already deployed then a Rhino restart will be required after setting the rhino.classloaders log key to DEBUG level in order that the components are reloaded in Rhino using the classloaders that generate debug information.

Debug Messages on Classloader Creation

Whenever Rhino creates a classloader for a component it will output the details of the classloader to the log. All classloaders have a type - either URL or Multiparent - and a sequential ID which together uniquely identify the classloader. URL classloaders will list the URLs that the classloader is using and the parent classloader. A multiparent classloader will list any URLs directly accessible to it for classloading, its parent classloaders as well as a "default" parent classloader, typically the system classloader, which is used as a fallback if none of the other parent classloaders can successfully load a particular class.

The following examples illustrate some basic classloader creation logs:

2008-01-16 17:28:55.462  INFO   [rhino.state.deployment]  Installing library: LibraryID[name=JSIP,vendor=javax.sip,version=1.2]
2008-01-16 17:28:55.462  DEBUG  [rhino.classloaders]  Created new [13] TracingURLClassLoader
        url     file:/home/rhino/rhino/work/deployments/unit1200457735268/jsip-library-1.2.jar
        parent  Log4jClassLoader

In the example above, a new URL classloader with ID [13] is created as a result of installing the "JSIP" library. The classloader references a single jar URL containing the JAIN SIP 1.2 classes. By default libraries are provided with access to the log4j classes included with Rhino and as such the classloader that can load the log4j classes is used as the library classloader's parent classloader.

2008-01-16 17:28:57.060  INFO   [rhino.state.deployment]  Installing library: LibraryID[name=JSIP RA Type Classes,vendor=net.java.slee,version=1.2]
2008-01-16 17:28:57.062  DEBUG  [rhino.classloaders]  Created new [1] TracingMultiparentClassLoader
        parent  Log4jClassLoader
        parent  [13] TracingURLClassLoader
        def-parent      sun.misc.Launcher$AppClassLoader@47858e
2008-01-16 17:28:57.063  DEBUG  [rhino.classloaders]  Created new [16] TracingURLClassLoader
        url     file:/home/rhino/rhino/work/deployments/unit1200457735608/jsip-ratype-classes-1.2.jar
        parent  [1] TracingMultiparentClassLoader

In the example above, the "JSIP RA Type Classes" library is being installed. As a result a multiparent classloader with ID [1] is created. As the library depends on the "JSIP" library above, the multiparent classloader has the classloader created for the "JSIP" library as one of its parent classloaders. Again the log4j classloader is also included by default as an additional parent classloader. A URL classloader with ID [16] is also created with the multiparent classloader as its parent. The URL of the jar containing the classes for the library is included in the URL classloader.

It should be noted that Rhino creates classloaders at two distinct points while installing a deployable unit: firstly during component verification phase and secondly during cluster-wide deployment of the component.

Component Verification Classloader

Component verification only occurs on the Rhino node performing the management command to install the deployable unit. During this phase a single URL classloader is created for each component jar being installed in order to load and verify the classes and interfaces specified by the components defined in the component jar. This classloader includes the jar URLs of all dependent components in one flat structure.

This phase is clearly distinguishable by a "Verifying ..." information log message output by the node before the classloader is created. For example:

2008-01-16 17:28:55.856  INFO   [rhino.management.deployment]  Verifying event type component definitions in jsip-events-1.2.jar
2008-01-16 17:28:55.906  DEBUG  [rhino.classloaders]  Created new [14] TracingURLClassLoader
	url	file:/home/rhino/rhino/work/deployments/unit1200457735608/jsip-ratype-classes-1.2.jar
	url	file:/home/rhino/rhino/work/deployments/unit1200457735268/jsip-library-1.2.jar
	url	file:/home/rhino/rhino/work/deployments/unit1200457735608/jsip-events-1.2.jar
	parent	sun.misc.Launcher$AppClassLoader@47858e

Classloaders created during component verification are discarded by Rhino after the verification phase has completed. Therefore the classloaders created during this phase, and any classes loaded by them, are generally safe to ignore during classloader problem analysis.

Component Deployment Classloader

During the final component deployment phase, details of the component deployment are broadcast across the cluster. Each Rhino cluster node creates an appropriate set of classloaders for the new components. If the components depend on previously installed components, the classloaders created for those components will be used as parent classloaders in order to satisfy the class dependencies.

The installation phase can be identified by an "Installing ..." information log message output by the node before the classloaders are created. For example:

2008-01-16 17:28:55.462  INFO   [rhino.state.deployment]  Installing library: LibraryID[name=JSIP,vendor=javax.sip,version=1.2]
2008-01-16 17:28:55.462  DEBUG  [rhino.classloaders]  Created new [13] TracingURLClassLoader
        url     file:/home/rhino/rhino/work/deployments/unit1200457735268/jsip-library-1.2.jar
        parent  Log4jClassLoader

The classloaders created during the installation phase are the ones we need to be concerned with when diagnosing classloader problems.

Interpreting Classloader Output

Generic Classloading Algorithm

The classloading algorithm used by the JVM can be generalised by this algorithm:

public Class loadClass(String name) throws ClassNotFoundException {
    if (a class with given name already loaded) return the class
    try {
        if (parentClassloader != null) {
            // delegate to parent classloader first
            return parentClassloader.loadClass(name)
        }
        else {
            // or if we have no parent, use the system classloader
            return systemClassloader.loadClass(name);
        }
    }
    catch (ClassNotFoundException e) {
        // if the class couldn't be loaded by our parent classloader,
        // attempt to find it ourselves
        return findClass(name);
    }
}

protected class findClass(String name) throws ClassNotFoundException {
    // implementation depends on the classloader
    // e.g. a URLClassLoader will attempt to read jars from the URLs it is provided with
}

The debugging classloaders provided with Rhino override the findClass method to output debugging information. Since a parent classloader's findClass method is invoked before the child's, debug output from a parent classloader's findClass method always preceeds that from the child.

Classloader Entry and Exit

Rhino's debugging classloaders generate a log message on entry to and exit from the findClass method. The entry message is always the same and identifies the class that needs to be found. The exit message depends on whether or not the class could be found.

Entry and exit from a URL classloader that can successfully find a class is shown below:

2008-01-16 17:28:57.098  DEBUG  [rhino.classloaders]  [13] TracingURLClassLoader: findClass( javax.sip.RequestEvent )
...
2008-01-16 17:28:57.099  DEBUG  [rhino.classloaders]  [13] TracingURLClassLoader: findClass( javax.sip.RequestEvent )
 =class javax.sip.RequestEvent, classloader=[13] TracingURLClassLoader

Similary for a multiparent classloader:

2008-01-16 17:28:57.097  DEBUG  [rhino.classloaders]  [1] TracingMultiparentClassLoader: findClass(javax.sip.RequestEvent)
...
2008-01-16 17:28:57.099  DEBUG  [rhino.classloaders]  [1] TracingMultiparentClassLoader: class javax.sip.RequestEvent found, class loaded by [13] TracingURLClassLoader

A URL classloader that cannot find a class will output a message indicating so. This message will always immediately follow the request to find the class since there are no intervening actions possible.

2008-01-16 17:28:57.160  DEBUG  [rhino.classloaders]  [13] TracingURLClassLoader: findClass( net.java.slee.resource.sip.DialogTimeoutEvent )
2008-01-16 17:28:57.160  DEBUG  [rhino.classloaders]  [13] TracingURLClassLoader: class net.java.slee.resource.sip.DialogTimeoutEvent not found

A multiparent classloader will provide information about each of the parent classloaders it tries, ultimately delegating to its superclass to try to find the class if all else fails. The entry and exit messages from a multiparent classloader that fails to find a class is shown below:

2008-01-16 17:28:57.160  DEBUG  [rhino.classloaders]  [1] TracingMultiparentClassLoader: findClass(net.java.slee.resource.sip.DialogTimeoutEvent)
...
2008-01-16 17:28:57.161  DEBUG  [rhino.classloaders]  [1] TracingMultiparentClassLoader: class net.java.slee.resource.sip.DialogTimeoutEvent not found by superclass

Interpreting Multiparent Classloader Output

A multiparent classloader invokes the loadClass method in turn on each of its parent classloaders. This can lead to some confusing log sequences. For instance, consider the following:

2008-01-16 17:29:01.865  DEBUG  [rhino.classloaders]  Created new [4] TracingMultiparentClassLoader
        parent  [21] TracingURLClassLoader
        parent  [24] TracingURLClassLoader
        parent  [17] TracingURLClassLoader
        def-parent      sun.misc.Launcher$AppClassLoader@47858e
2008-01-16 17:29:01.866  DEBUG  [rhino.classloaders]  Created new [25] TracingURLClassLoader
        url     file:/home/rhino/rhino/work/deployments/unit1200457739598/ocsip-resource-adaptor-type-2.0.jar
        parent  [4] TracingMultiparentClassLoader
...
2008-01-16 17:29:01.866  DEBUG  [rhino.classloaders]  Created new [26] TracingURLClassLoader
        url     file:/home/rhino/rhino/sdk-trunk/work/deployments/unit1200457739598/unit1200457739598.ocsip-resource-adaptor-type-2.0.jar.OCSIP_OpenCloud_2_0.ACIFactory.jar
        parent  [25] TracingURLClassLoader
...
2008-01-16 17:29:02.943  DEBUG  [rhino.classloaders]  Created new [5] TracingMultiparentClassLoader
        parent  Log4jClassLoader
        parent  [25] TracingURLClassLoader
        parent  [18] TracingURLClassLoader
        def-parent      sun.misc.Launcher$AppClassLoader@47858e
...

2008-01-16 17:29:03.420  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: findClass(com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor)
2008-01-16 17:29:03.420  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: trying parent Log4jClassLoader for class com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor
2008-01-16 17:29:03.420  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: class com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor not found by parent Log4jClassLoader
2008-01-16 17:29:03.420  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: trying parent [25] TracingURLClassLoader for class com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor
2008-01-16 17:29:03.420  DEBUG  [rhino.classloaders]  [4] TracingMultiparentClassLoader: findClass(com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor)
2008-01-16 17:29:03.421  DEBUG  [rhino.classloaders]  [4] TracingMultiparentClassLoader: trying parent [21] TracingURLClassLoader for class com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor
2008-01-16 17:29:03.421  DEBUG  [rhino.classloaders]  [3] TracingMultiparentClassLoader: findClass(com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor)
2008-01-16 17:29:03.421  DEBUG  [rhino.classloaders]  [3] TracingMultiparentClassLoader: trying parent [16] TracingURLClassLoader for class com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor
...

What happens here is:

  1. Multiparent [5] is asked to find the FTSipResourceAdaptor class
  2. Multiparent [5] initially tries its first parent classloader, the log4j classloader. This classloader fails to find the class
  3. Multiparent [5] then tries its second parent classloader, the URL [25] classloader
  4. Since a multiparent classloader invokes the loadClass method on its parents, rather than the findClass method of the URL [25] classloader being invoked, loadClass delegates to the parent classloader - Multiparent [4] - which further delegates to its parent, the system classloader
  5. The system classloader fails to load the class, so execution returns to loadClass in Multiparent [4], which invokes the findClass method to give the opportunity for Multiparent [4] to try to find the class
  6. Multiparent [4] initially tries its first parent classloader, URL [21], and the same process as in steps 4-5 are repeated.

The rest of the log messages on the way back out the stack are generally self-explanatory:

2008-01-16 17:29:03.427  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: class com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor not found by parent [25] TracingURLClassLoader
2008-01-16 17:29:03.427  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: trying parent [18] TracingURLClassLoader for class com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor
...
2008-01-16 17:29:03.438  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: class com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor not found by parent [18] TracingURLClassLoader
2008-01-16 17:29:03.438  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: class com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor not found by multi-parents, 
  delegating to URLClassLoader superclass to try urls and default parent classloader
2008-01-16 17:29:03.438  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: class com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor not found by superclass

One can see a similar process in the case that a class is found:

2008-01-16 17:29:03.787  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: findClass(javax.sip.SipListener)
2008-01-16 17:29:03.787  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: trying parent Log4jClassLoader for class javax.sip.SipListener
2008-01-16 17:29:03.787  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: class javax.sip.SipListener not found by parent Log4jClassLoader
2008-01-16 17:29:03.787  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: trying parent [25] TracingURLClassLoader for class javax.sip.SipListener
2008-01-16 17:29:03.787  DEBUG  [rhino.classloaders]  [4] TracingMultiparentClassLoader: findClass(javax.sip.SipListener)
2008-01-16 17:29:03.787  DEBUG  [rhino.classloaders]  [4] TracingMultiparentClassLoader: trying parent [21] TracingURLClassLoader for class javax.sip.SipListener
2008-01-16 17:29:03.787  DEBUG  [rhino.classloaders]  [3] TracingMultiparentClassLoader: findClass(javax.sip.SipListener)
2008-01-16 17:29:03.787  DEBUG  [rhino.classloaders]  [3] TracingMultiparentClassLoader: trying parent [16] TracingURLClassLoader for class javax.sip.SipListener
2008-01-16 17:29:03.788  DEBUG  [rhino.classloaders]  [1] TracingMultiparentClassLoader: findClass(javax.sip.SipListener)
2008-01-16 17:29:03.788  DEBUG  [rhino.classloaders]  [1] TracingMultiparentClassLoader: trying parent Log4jClassLoader for class javax.sip.SipListener
2008-01-16 17:29:03.788  DEBUG  [rhino.classloaders]  [1] TracingMultiparentClassLoader: class javax.sip.SipListener not found by parent Log4jClassLoader
2008-01-16 17:29:03.788  DEBUG  [rhino.classloaders]  [1] TracingMultiparentClassLoader: trying parent [13] TracingURLClassLoader for class javax.sip.SipListener
2008-01-16 17:29:03.788  DEBUG  [rhino.classloaders]  [13] TracingURLClassLoader: findClass( javax.sip.SipListener )
2008-01-16 17:29:03.788  DEBUG  [rhino.classloaders]  [13] TracingURLClassLoader: findClass( javax.sip.SipListener )=interface javax.sip.SipListener, classloader=[13] TracingURLClassLoader
2008-01-16 17:29:03.789  DEBUG  [rhino.classloaders]  [1] TracingMultiparentClassLoader: class javax.sip.SipListener found, class loaded by [13] TracingURLClassLoader
2008-01-16 17:29:03.789  DEBUG  [rhino.classloaders]  [3] TracingMultiparentClassLoader: class javax.sip.SipListener found, class loaded by [13] TracingURLClassLoader
2008-01-16 17:29:03.789  DEBUG  [rhino.classloaders]  [4] TracingMultiparentClassLoader: class javax.sip.SipListener found, class loaded by [13] TracingURLClassLoader
2008-01-16 17:29:03.789  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: class javax.sip.SipListener found, class loaded by [13] TracingURLClassLoader

Interpreting URL Classloader Output

Note: This section also applies to a multiparent classloader created with a list of URLs, and where the classloader has delegated to its superclass to try to find a class.

There are three possible variations in URL classloader output. The first is if a class cannot be found by the classloader, and results in a log message to that effect immediately following the findClass request, as previously mentioned above:

2008-01-16 17:28:57.160  DEBUG  [rhino.classloaders]  [13] TracingURLClassLoader: findClass( net.java.slee.resource.sip.DialogTimeoutEvent )
2008-01-16 17:28:57.160  DEBUG  [rhino.classloaders]  [13] TracingURLClassLoader: class net.java.slee.resource.sip.DialogTimeoutEvent not found

The remaining two variations occur when a URL classloader successfully finds a class. In one case, the class has no immediate dependent classes that also need to be loaded by the classloader, and findClass returns immediately:

2008-01-16 17:28:57.098  DEBUG  [rhino.classloaders]   <StageWorker/GroupRMI/2> [13] TracingURLClassLoader: findClass( javax.sip.RequestEvent )
2008-01-16 17:28:57.099  DEBUG  [rhino.classloaders]   <StageWorker/GroupRMI/2> [13] TracingURLClassLoader: findClass( javax.sip.RequestEvent )
  =class javax.sip.RequestEvent, classloader=[13] TracingURLClassLoader

In the second case, one or more dependent classes must also be loaded before the class being found can be returned to the caller. For example, if class XYZ extends class ABC and a URL classloader is asked to find XYZ, when the classloader reads the class definition for XYZ it will recognise that XYZ extends ABC, and so will attempt to obtain access to the class definition of ABC in order to resolve XYZ.

What this looks like in the log is an invocation of findClass on a URL classloader being immediately following by another invocation of findClass on one of the URL classloader's ancestor classloaders. For example:

2008-01-16 17:29:03.438  DEBUG  [rhino.classloaders]  [29] TracingURLClassLoader: findClass( com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor )
2008-01-16 17:29:03.439  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: findClass(com.opencloud.slee.resources.sip.ra.DialogAwareSipResourceAdaptor)

In this case classloader URL [29] has successfully found the FTSipResourceAdaptor class. This class depends on the DialogAwareSipResourceAdaptor class. As a result the URL [29] classloader needs to load or obtain access to the DialogAwareSipResourceAdaptor class also. It follows the regular loadClass algorithm to do this, therefore the parent classloaders get an opportunity to find the class first.

Following this through a bit more:

2008-01-16 17:29:03.465  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: class com.opencloud.slee.resources.sip.ra.DialogAwareSipResourceAdaptor not found by superclass
2008-01-16 17:29:03.465  DEBUG  [rhino.classloaders]  [29] TracingURLClassLoader: findClass( com.opencloud.slee.resources.sip.ra.DialogAwareSipResourceAdaptor )
2008-01-16 17:29:03.466  DEBUG  [rhino.classloaders]  [5] TracingMultiparentClassLoader: findClass(com.opencloud.slee.resources.sip.ra.SipResourceAdaptor)

Multiparent [5] fails to locate the DialogAwareSipResourceAdaptor class. The URL [29] classloader however can locate the class, evident by it immediately trying to load the SipResourceAdaptor class which DialogAwareSipResourceAdaptor depends on.

The theories above are proven when we eventually see these log messages as the findClass methods return:

2008-01-16 17:29:03.493  DEBUG  [rhino.classloaders]  [29] TracingURLClassLoader: findClass( com.opencloud.slee.resources.sip.ra.SipResourceAdaptor )
  =class com.opencloud.slee.resources.sip.ra.SipResourceAdaptor, classloader=[29] TracingURLClassLoader
2008-01-16 17:29:03.494  DEBUG  [rhino.classloaders]  [29] TracingURLClassLoader: findClass( com.opencloud.slee.resources.sip.ra.DialogAwareSipResourceAdaptor )
  =class com.opencloud.slee.resources.sip.ra.DialogAwareSipResourceAdaptor, classloader=[29] TracingURLClassLoader
2008-01-16 17:29:03.494  DEBUG  [rhino.classloaders]  [29] TracingURLClassLoader: findClass( com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor )
  =class com.opencloud.slee.resources.sip.ra.FTSipResourceAdaptor, classloader=[29] TracingURLClassLoader

Essentially everything that happens between a matched pair of findClass entry and exit log messages for a particular class in a given classloader are the classloader actions taken as a result of attempting to resolve the runtime definition of the class.

Suggested Diagnostic Approaches

Diagnosing ClassNotFoundExceptions or NoClassDefFoundErrors

Problem: Class XYZ cannot be found.

Search the log for the last occurrence of "findClass( XYZ )" before the exception or error occurred. This is the classloader that was initially attempting to load the class. Check the log to see what this classloader was created for. Is it the component you expect?

Search the log for the first occurrence of "findClass( XYZ )" (ignoring any classloaders used during the component verification phase). If that line is immediately preceeded by another "findClass" log message for class ABC then class XYZ is a dependent class of ABC. The classloader specified in the "findClass( ABC )" log message was able to locate class ABC and therefore is also expected to be able to find class XYZ. Check the log to see what this classloader was created for. Is it the component you expect?

In some cases you may need to traverse through a number of dependencies before fully understanding why a class was loaded from a particular location.

Diagnosing ClassCastExceptions, IncompatibleClassChangeErrors, or other LinkageErrors

Problem: An attempt to cast an object to class XYZ fails.

Search the logs for occurrences where class XYZ has been found by a classloader (ignoring any classloaders used during the component verification phase). Take note of the classloaders that the class was loaded from then check the logs to see what components these classloaders relate to. Class XYZ and all its dependencies will need to be moved to a component that is a common ancestor of all components that require the class.

Adaptavist Theme Builder Powered by Atlassian Confluence