SolvingClassLoaderProblems

From Protege Wiki
Revision as of 15:33, October 22, 2007 by Tredmond (talk | contribs) (New page: In order to apply the techniques of this section the developer will need to have the ability to capture and navigate the output of a run command and must be able to compile a knopflerfish ...)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

In order to apply the techniques of this section the developer will need to have the ability to capture and navigate the output of a run command and must be able to compile a knopflerfish distribution (ant knopflerfish). Given this 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:

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) <p> 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. <p> This should have been enough for me to figure out what happened because (at this time) the org.protege.editor.owl 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. <p> So I make a knopflerfish distribution. I then modify the props.xargs file to set

      -Dorg.knopflerfish.framework.debug.classloader=true.

In this mode knopflerfish spits out tons of output describing all its class loading work. I work backwards in the resulting output from the exception and find the following log messages: <p> ## DEBUG: BundleClassLoader(id=14,gen=0) Search for: org/apache/commons/lang/StringEscapeUtils.class ## DEBUG: BundleClassLoader(id=14,gen=0) Import search: org/apache/commons/lang/StringEscapeUtils.class from #8 ## DEBUG: BundleClassLoader(id=8,gen=0) Search for: org/apache/commons/lang/StringEscapeUtils.class ## DEBUG: BundleClassLoader(id=9,gen=0) Search for: org/protege/editor/core/ui/error/ErrorLog$ErrorLogEntry.class <p> I am not including any of the other messages (involving class loaders to present the error to me) because there is no good news after this. The first line <p> ## DEBUG: BundleClassLoader(id=14,gen=0) Search for: org/apache/commons/lang/StringEscapeUtils.class <p> says that the class loader with the identity 14 initially tries to load the StringEscapeUtils.class. So I need to figure out which class loader has the id 14. If I search forwards from the top of the log for the number14, I see the lines <p> ## DEBUG: BundleClassLoader(id=14,gen=0) Created new classloader Installed plugin The OWL API <p> This means that during the installation of the OWL API the class loader 14 was created. So it was the OWL API bundle (org.semanticweb.owlapi) that initially tried to load the StringEscapeUtils class. Just like it should have been. The next two lines <p> ## DEBUG: BundleClassLoader(id=14,gen=0) Import search: org/apache/commons/lang/StringEscapeUtils.class from #8 ## DEBUG: BundleClassLoader(id=8,gen=0) Search for: org/apache/commons/lang/StringEscapeUtils.class <p> says that the owl api bundle (#14) tries to get the definition of the StringEscapeUtils class from the bundle with the number 8. As before I find out which bundle has the id 8 by searching down from the top of the logs: <p> Installed: file:jars/protege/org.protege.common.jar (id#8) <p>

So the owl api bundle is delegating to org.protege.common just like I thought it should. At this point there is only one thing that could be wrong and I immediately go to check. In the manifest the Bundle-Classpath includes an entry lib/commons-lang.jar. This entry should be lib/commons-lang-2.2.jar. If I had trusted my logic better I would probably have saved myself some trouble but the knopflerfish debug statements allowed me to determine exactly what parts of my logic were right and what I did wrong.