On Thu, Feb 19, 2009 at 09:46, Gert Vanthienen <[email protected]> wrote: > Guillaume, > > Nice work, looks like there were a few hard nuts to crack down the road... > > For the classloader question, wouldn't it be possible to somehow create OSGi > classloaders to implement the JBI classloading architecture as well. This > would deal with the problem and it would allow you to fine-tune OSGi and JBI > integration for e.g. a SU classloader afterwards as well?
Not sure if we can completely mimic the JBI classloading mechanism specified in the spec using OSGi classloaders. OSGi classloaders resolve classes in the following way: * boot classpath delegation * if the class has not been found and the class is in the java.* packages, throw CNFE * search static imports * search the bundle * search dynamic imports The JBI spec has the following ordering rules: * component classloader if self-first delegation * shared libraries * jbi classloader * component classloader if parent-first delegation In addition, java.* and javax.* must always be loaded from the jbi classloader first The only way I've been thinking of to do that would be to scan all jars in the component classpath for imported packages. If the delegation is parent-first, the components' bundle would import all those packages with an optional import (so that the bundle resolution won't fail). For shared libraries, using Require-Bundle could work. I guess one problem would be a component that uses Class.forName(). In such a case I don't think there is a way to delegate to the parents first. Though as we know all the classes in the component classloader, the search will either find a known class (inside the imported packages, then the bundle) or fail. So I think it may be possible through the use of bnd tool, lots of optional imports, Require-Bundle and Bundle-Classpath ... > If that's not a solution, I'd rather opt for the second solution -- go for > the simple solution of using the expanded files. I have a patch ready. I will commit it and investigate the first solution later. > Regards, > > Gert > > Guillaume Nodet wrote: >> >> Yesterday, I've been trying to deploy Ode in ServiceMix 4 and found >> some problems. >> >> The first one was the fact that Ode expects the transaction manager to >> implement the >> org.apache.geronimo.transaction.manager.RecoverableTransactionMaanger. >> In order to fix that one (SMX4-51), I've applied the patch attached >> partially (so that the spring proxy for the transaction manager >> actually implement the above interface) and enhanced the JBI URL >> handler to be able to customize the generated manifest header for the >> OSGi bundle created for the JBI component (SMX4NMR-93). Using a >> dynamic import on the above package (or I suppose a plain import) >> works. >> >> The second one was a ClassCastException on a SAX class. For some >> reason, the SAX classes loaded by the JBI component were loaded from >> the JRE instead of the stax-api OSGi bundle. The reason for that one >> is that the first parent of the classloader for the component was the >> system bundle instead of the classloader for the component's bundle. >> I haven't committed the changes yet, but will do it soon. >> >> The last one is caused by the classloader not being able to load >> classes and resources. The exceptions are thrown from the following >> code: >> >> processstoreimp...@24390 daemon, priority=5, in group 'main', status: >> 'RUNNING' >> at >> org.apache.felix.framework.URLHandlersBundleStreamHandler.openConnection(URLHandlersBundleStreamHandler.java:69) >> at java.net.URL.openConnection(URL.java:943) >> at >> sun.net.www.protocol.jar.JarURLConnection.<init>(JarURLConnection.java:64) >> at >> sun.net.www.protocol.jar.Handler.openConnection(Handler.java:24) >> at java.net.URL.openConnection(URL.java:943) >> at java.net.URL.openStream(URL.java:1,007) >> at >> java.lang.ClassLoader.getResourceAsStream(ClassLoader.java:1,216) >> at java.lang.Class.getResourceAsStream(Class.java:1,998) >> at >> org.apache.openjpa.conf.OpenJPAVersion.<clinit>(OpenJPAVersion.java:50) >> at >> org.apache.openjpa.kernel.AbstractBrokerFactory.getFactoryInitializationBanner(AbstractBrokerFactory.java:663) >> at >> org.apache.openjpa.kernel.AbstractBrokerFactory.makeReadOnly(AbstractBrokerFactory.java:616) >> at >> org.apache.openjpa.kernel.AbstractBrokerFactory.newBroker(AbstractBrokerFactory.java:183) >> at >> org.apache.openjpa.kernel.DelegatingBrokerFactory.newBroker(DelegatingBrokerFactory.java:142) >> at >> org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:192) >> at >> org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:145) >> at >> org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:56) >> at >> org.apache.ode.store.jpa.DbConfStoreConnectionFactory.getConnection(DbConfStoreConnectionFactory.java:49) >> at >> org.apache.ode.store.ProcessStoreImpl.getConnection(ProcessStoreImpl.java:549) >> at >> org.apache.ode.store.ProcessStoreImpl.access$300(ProcessStoreImpl.java:74) >> at >> org.apache.ode.store.ProcessStoreImpl$Callable.call(ProcessStoreImpl.java:698) >> at >> java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:269) >> at java.util.concurrent.FutureTask.run(FutureTask.java:123) >> at >> java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:650) >> at >> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:675) >> at java.lang.Thread.run(Thread.java:613) >> >> The reason is that the jbi classloader is create with bundle urls >> pointing to the libraries embedded in the component. >> For example: >> bundle://72.0:1/lib/openjpa-1.1.0.jar >> Those URLs are resolved correctly to locate resources, so we end up >> with urls like: >> >> >> jar:bundle://72.0:1/lib/openjpa-1.1.0.jar!/org/apache/openjpa/kernel/localizer.properties >> Now, the problem is that they fail to be opened at the above point in >> the code. THis is because Felix is trying to find on the stack trace >> a classloader which is of type >> org.apache.felix.framework.searchpolicy.ContentClassLoader (in the >> URLHandlers#getFrameworkContext() method). But there's none because >> all classes are loaded from the JBI component classloader instead of >> a felix classloader in this case. >> >> Anyway, I will try a few things: >> * when transforming the JBI artifact to an OSGi bundle, we could >> leverage the Bundle-Classpath osgi header to point to the embedded >> jars. However, I fear we won't be able to control JBI classloader >> self-first / parent-first delegation when doing so >> * the bundle content is extracted to a folder >> (data/jbi/<name>/install) as required by the JBI spec. We could point >> directly to those files instead of using URLs like bundle:// . >> >> Any other idea is welcome. >> >> > > -- Cheers, Guillaume Nodet ------------------------ Blog: http://gnodet.blogspot.com/ ------------------------ Open Source SOA http://fusesource.com
