Difference between revisions of "SolvingClassLoaderProblems"

From Protege Wiki
Jump to: navigation, search
Line 1: Line 1:
I will describe how to debug class loader exceptions (if they cannot be easily figured out and they are giving you a headache).  So I recently saw the following exception:
+
I will describe how to debug class loader exceptions (if they cannot be easily figured out and they are giving you a headache).  Before starting, an important tip is the fact that class loader problems are often masked.  I usually have a good suspicion when this is the problem but it doesn't help that we don't know.  If you are not seeing a ClassNotFoundException or some like, put a breakpoint for ClassNotFoundException (which is what the class loader throws) and see what it turns up.  Ok now for my example.
 +
 
 +
 
 +
So I recently saw the following exception:
  
 
<pre>
 
<pre>

Revision as of 07:42, December 14, 2007

I will describe how to debug class loader exceptions (if they cannot be easily figured out and they are giving you a headache). Before starting, an important tip is the fact that class loader problems are often masked. I usually have a good suspicion when this is the problem but it doesn't help that we don't know. If you are not seeing a ClassNotFoundException or some like, put a breakpoint for ClassNotFoundException (which is what the class loader throws) and see what it turns up. Ok now for my example.


So I recently saw the following exception:

java.lang.NoClassDefFoundError: org/apache/commons/lang/StringEscapeUtils
        at org.coode.xml.XMLWriterImpl.writeEntities(XMLWriterImpl.java:207)
        at org.coode.xml.XMLWriterImpl.startDocument(XMLWriterImpl.java:221)
        at org.coode.owl.rdf.rdfxml.RDFXMLWriter.startDocument(RDFXMLWriter.java:135)
        at org.coode.owl.rdf.rdfxml.RDFXMLRenderer.render(RDFXMLRenderer.java:87)
        at org.coode.owl.rdf.rdfxml.RDFXMLOntologyStorer.storeOntology(RDFXMLOntologyStorer.java:56)
        at uk.ac.manchester.cs.owl.OWLOntologyManagerImpl.saveOntology(OWLOntologyManagerImpl.java:370)
        at org.protege.editor.owl.model.OWLModelManagerImpl.save(OWLModelManagerImpl.java:368)
        at org.protege.editor.owl.OWLEditorKit.handleSave(OWLEditorKit.java:185)
        at org.protege.editor.core.ProtegeManager.saveEditorKit(ProtegeManager.java:187)

In this case the exception was caused by a trivial stupid typo in the org.protege.common manifest but I was confused at the time and did not figure this out. So the first item of confusion here might be the question of which class loader is causing the problem. One might somehow think that this is being caused by the class loader for the org.protege.editor.owl bundle because, in some vague and undefined sense, this sequence of events seemed to be triggered in that bundle. But this is not how class loaders work. Actually the class loader that got into trouble (before delegation is taken into account) is the class loader for the org.coode.xml.XMLWriterImp class. This class loader is the org.semanticweb.owlapi bundle.

This should have been enough for me to figure out what happened because (at this time) the org.semanticweb.owlapi bundle imported the package org.apache.commons.lang and the org.protege.common bundle exportedthe package org.apache.commons.lang package. There were very few things that could go wrong at this point but I didn't see it and I began to doubt my reasoning.

To solve these types of problems I have created a bundle providing some servlets that debug class loading issues. The source for this bundle can be found in the svn repository

http://smi-protege/repos/protege/protege4/small-projects/org.protege.osgi.debug/trunk

and once it is checked out it can be built with ant dist. The result of ant dist will be a relatively minimal OSGi distribution in the directory build/dist/equinox which allows the org.protege.osgi.debug bundle to run. To use this with an equinox distribution copy the files

   javax.servlet_2.4.0.v200706111738.jar
   org.apache.commons.logging_1.0.4.v200706111724.jar
   org.eclipse.equinox.http.jetty_1.0.1.R33x_v20070816.jar
   org.eclipse.equinox.http.servlet_1.0.1.R33x_v20070816.jar
   org.eclipse.osgi.services_3.1.200.v20070605.jar
   org.mortbay.jetty_5.1.11.v200706111724.jar
   org.protege.osgi.debug.jar

into from the org.protege.osgi.debug distribution to the Protege 4 OWL editor's plugin directory. (Note the exclusion of the org.eclipse.osgi_3.3.1.R33x_v20070828.jar and org.eclipse.equinox.common_3.3.0.v20070426.jar files). Now when the OWL editor is started these bundles will automatically be loaded. One indicator that these bundles have been seen are the following messages on the console:

Oct 25, 2007 11:35:46 PM org.mortbay.http.HttpServer doStart
INFO: Version Jetty/5.1.x
Oct 25, 2007 11:35:46 PM org.mortbay.util.Container start
INFO: Started org.mortbay.jetty.servlet.ServletHandler@c7e176
Oct 25, 2007 11:35:46 PM org.mortbay.util.Container start
INFO: Started HttpContext[/,/]
Oct 25, 2007 11:35:46 PM org.mortbay.http.SocketListener start
INFO: Started SocketListener on 0.0.0.0:8080
Oct 25, 2007 11:35:46 PM org.mortbay.util.Container start
INFO: Started org.mortbay.http.HttpServer@787144

These message merely indicate that the http servlet code been initialized.

Now the rest is easy. If you go to the page

http://localhost:8080/debug/classloader

and enter the class org.apache.commons.lang.StringEscapeUtils we find that there is no bundle that can load this class. But the plan was that the org.protege.common bundle should have seen this class. This fact takes us directly to the typo in the classpath for org.protege.common in the org.protege.common MANIFEST.

Futher we can check the imports and exports by going to the page

  http://localhost:8080/debug/package

and selecting the org.semanticweb.owlapi bunde. We then see that this bundle imports the package org.apache.commons.lang from the org.protege.common bundle. This means that if org.protege.common can load the class

org.apache.commons.lang.StringEscapeUtils

then so should the org.semanticweb.owlapi bundle.