5 Replies Latest reply on Dec 17, 2014 11:52 AM by lincolnthree

    Furnace Class Loading Issue

    itewk

      I am attempting to use Forge/Furnace integration with eclipse to load my addon but I am running into class loading issues. It would seem that for some reason when a class from my Addon, WindupEngine, tries to load ApplicaitonContext the org.jboss.tools.forge.core.internal.furnace.CompositeFurnaceClassLoader is not being consulted. I have debugged it and CompositeFurnaceClassLoader#loadClass is never asked to load ApplicaitonContext. I don't know why this is, but I suspect this is the issue. Since ApplicaitonContext is in spring-context-3.1.0.RELEASE.jar which is included as a dependency in my addon. From the logs I know that my addon is being loaded, it is just for some reason it is not being consulted when trying to load this class and I do not know why.

       

      In case source is useful:

       

      The addon I am trying to load: https://github.com/windup/windup-legacy/tree/master/application/addon

      Eclipse plugin that loads the addon: windup-eclipse-plugin/plugins/org.jboss.tools.windup.runtime at forge · windup/windup-eclipse-plugin · GitHub

      IFurnaceRepositoryProvider implementation to load the Furnace repository with the addon: windup-eclipse-plugin/FurnaceRepositoryProvider.java at forge · windup/windup-eclipse-plugin · GitHub

      The service having class loading issues: windup-eclipse-plugin/WindupService.java at forge · windup/windup-eclipse-plugin · GitHub

      • #getWindupFactory - successfully uses Furnace to load the factory class
      • #getWindupEngine - fails at creating WindupEngine due to the class loading issue

       

      I am really not sure if I just have something not configured correctly or if this is some issue with Furnace/Forge. I have a fair bit of experience debugging Eclipse/OSGI class loading issues with plugins and their dependencies but I have no working knowledge of how Furnace/Forge works and thus while trying to debug I am at a lost as to what to be looking for.

       

      Any one with any ideas would be greatly appreciated.

       

      ModuleClassLoader[org.jboss.tools.windup.runtime_3.1.0.qualifier].loadClass(org.springframework.context.ApplicationContext)

      BundleLoader[org.jboss.tools.windup.runtime_3.1.0.qualifier].findClassInternal(org.springframework.context.ApplicationContext)

      BundleLoader[org.jboss.tools.windup.runtime_3.1.0.qualifier].findLocalClass(org.springframework.context.ApplicationContext)

      ModuleClassLoader[org.jboss.tools.windup.runtime_3.1.0.qualifier - /usr/share/eclipse/luna-sr1/eclipse/../../../../../home/ian/Projects/Windup/workspace/windup-eclipse-plugin/plugins/org.jboss.tools.windup.runtime].findClassImpl(org.springframework.context.ApplicationContext)

      ModuleClassLoader[org.jboss.tools.windup.runtime_3.1.0.qualifier - /usr/share/eclipse/luna-sr1/eclipse/../../../../../home/ian/Projects/Windup/workspace/windup-eclipse-plugin/plugins/org.jboss.tools.windup.runtime/lib/windup-legacy-app-addon.jar].findClassImpl(org.springframework.context.ApplicationContext)

      ModuleClassLoader[org.jboss.tools.windup.runtime_3.1.0.qualifier - /usr/share/eclipse/luna-sr1/eclipse/../../../../../home/ian/Projects/Windup/workspace/windup-eclipse-plugin/plugins/org.jboss.tools.windup.runtime/lib/windup-legacy-engine.jar].findClassImpl(org.springframework.context.ApplicationContext)

      ModuleClassLoader[org.jboss.tools.windup.runtime_3.1.0.qualifier - /usr/share/eclipse/luna-sr1/eclipse/../../../../../home/ian/Projects/Windup/workspace/windup-eclipse-plugin/plugins/org.jboss.tools.windup.runtime/lib/windup-legacy-metadata.jar].findClassImpl(org.springframework.context.ApplicationContext)

      ModuleClassLoader[org.jboss.tools.windup.runtime_3.1.0.qualifier - /usr/share/eclipse/luna-sr1/eclipse/../../../../../home/ian/Projects/Windup/workspace/windup-eclipse-plugin/plugins/org.jboss.tools.windup.runtime/lib/windup-legacy-reporting.jar].findClassImpl(org.springframework.context.ApplicationContext)

      ModuleClassLoader[org.jboss.tools.windup.runtime_3.1.0.qualifier - /usr/share/eclipse/luna-sr1/eclipse/../../../../../home/ian/Projects/Windup/workspace/windup-eclipse-plugin/plugins/org.jboss.tools.windup.runtime].findClassImpl(org.springframework.context.ApplicationContext)

      ModuleClassLoader[org.jboss.tools.windup.runtime_3.1.0.qualifier - /usr/share/eclipse/luna-sr1/eclipse/../../../../../home/ian/Projects/Windup/workspace/windup-eclipse-plugin/plugins/org.jboss.tools.windup.runtime/lib/windup-legacy-app-addon.jar].findClassImpl(org.springframework.context.ApplicationContext)

      ModuleClassLoader[org.jboss.tools.windup.runtime_3.1.0.qualifier - /usr/share/eclipse/luna-sr1/eclipse/../../../../../home/ian/Projects/Windup/workspace/windup-eclipse-plugin/plugins/org.jboss.tools.windup.runtime/lib/windup-legacy-engine.jar].findClassImpl(org.springframework.context.ApplicationContext)

      ModuleClassLoader[org.jboss.tools.windup.runtime_3.1.0.qualifier - /usr/share/eclipse/luna-sr1/eclipse/../../../../../home/ian/Projects/Windup/workspace/windup-eclipse-plugin/plugins/org.jboss.tools.windup.runtime/lib/windup-legacy-metadata.jar].findClassImpl(org.springframework.context.ApplicationContext)

      ModuleClassLoader[org.jboss.tools.windup.runtime_3.1.0.qualifier - /usr/share/eclipse/luna-sr1/eclipse/../../../../../home/ian/Projects/Windup/workspace/windup-eclipse-plugin/plugins/org.jboss.tools.windup.runtime/lib/windup-legacy-reporting.jar].findClassImpl(org.springframework.context.ApplicationContext)

      ModuleClassLoader[org.jboss.tools.windup.runtime_3.1.0.qualifier].loadClass(org.springframework.context.ApplicationContext) failed.

      java.lang.ClassNotFoundException: org.springframework.context.ApplicationContext cannot be found by org.jboss.tools.windup.runtime_3.1.0.qualifier

        at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:432)

        at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:345)

        at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:337)

        at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:160)

        at java.lang.ClassLoader.loadClass(ClassLoader.java:358)

        at java.lang.Class.getDeclaredMethods0(Native Method)

        at java.lang.Class.privateGetDeclaredMethods(Class.java:2531)

        at java.lang.Class.getDeclaredMethods(Class.java:1855)

        at org.jboss.forge.furnace.proxy.javassist.util.proxy.SecurityActions.getDeclaredMethods(SecurityActions.java:30)

        at org.jboss.forge.furnace.proxy.javassist.util.proxy.ProxyFactory.getMethods(ProxyFactory.java:1121)

        at org.jboss.forge.furnace.proxy.javassist.util.proxy.ProxyFactory.getMethods(ProxyFactory.java:1098)

        at org.jboss.forge.furnace.proxy.javassist.util.proxy.ProxyFactory.makeSortedMethodList(ProxyFactory.java:803)

        at org.jboss.forge.furnace.proxy.javassist.util.proxy.ProxyFactory.computeSignature(ProxyFactory.java:810)

        at org.jboss.forge.furnace.proxy.javassist.util.proxy.ProxyFactory.createClass(ProxyFactory.java:398)

        at org.jboss.forge.furnace.proxy.ClassLoaderAdapterCallback$3.call(ClassLoaderAdapterCallback.java:987)

        at org.jboss.forge.furnace.util.ClassLoaders.executeIn(ClassLoaders.java:42)

        at org.jboss.forge.furnace.proxy.ClassLoaderAdapterCallback.enhance(ClassLoaderAdapterCallback.java:900)

        at org.jboss.forge.furnace.proxy.ClassLoaderAdapterCallback.enhanceResult(ClassLoaderAdapterCallback.java:277)

        at org.jboss.forge.furnace.proxy.ClassLoaderAdapterCallback.access$200(ClassLoaderAdapterCallback.java:37)

        at org.jboss.forge.furnace.proxy.ClassLoaderAdapterCallback$2.call(ClassLoaderAdapterCallback.java:124)

        at org.jboss.forge.furnace.util.ClassLoaders.executeIn(ClassLoaders.java:42)

        at org.jboss.forge.furnace.proxy.ClassLoaderAdapterCallback.invoke(ClassLoaderAdapterCallback.java:96)

        at org.jboss.windup.WindupFactory_$$_javassist_7a5483bd-dd1d-470f-8ad4-58ae4916017f.createWindupEngine(WindupFactory_$$_javassist_7a5483bd-dd1d-470f-8ad4-58ae4916017f.java)

        at org.jboss.tools.windup.core.WindupService.getWindupEngine(WindupService.java:391)

        at org.jboss.tools.windup.core.WindupService.getWindupReportEngine(WindupService.java:412)

        at org.jboss.tools.windup.core.WindupService.generateReport(WindupService.java:250)

        at org.jboss.tools.windup.core.WindupService.generateReport(WindupService.java:186)

        at org.jboss.tools.windup.ui.internal.commands.GenerateWindupReportHandler$1.run(GenerateWindupReportHandler.java:78)

        at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)

        • 1. Re: Furnace Class Loading Issue
          lincolnthree

          Hey Ian,

           

          Dependent classes are loaded by the loader that loaded the current class (unless manually declared otherwise using ClassLoader.loadClass(). So if Class X uses Class Y directly (by referencing its type in the source code), class Y will be loaded from Class X's class-loader. Now, X's ClassLoader may still delegate to a different classloader, but ClassLoader X will be the first place that is checked, if I am not mistaken. The second place that is checked if it is not found there, is the Thread.getContextClassLoader().

           

          I hope this helps,

          Lincoln

          • 2. Re: Furnace Class Loading Issue
            itewk

            Lincoln,

             

            It helps a little. And I have a hunch as to what is going on but not sure how to fix it.

             

            In my runtime plugin which contains my addon, I also have to put the four jars that make up the API of windup in the /lib directory and add them to the class path of the plugin. If I do not do this then any plugin dependent on the runtime plugin has no way to compile against the API. But this means these four JARs are both on the runtime path of the OSGi bundle and in the Forge addon. The difference being in the forge addon the jars are there as well as all of their dependencies.Now when my plugin loads the WindupFactory it uses Furance to do so, so I assume it is grabbing the version from the addon, but I also have class references to things like WIndupEngine which maybe causing them to be loaded from the OSGi bundle libs rather then the addon, but I am unclear on this.

             

            I did try to no include the windup libs in the lib directory of the runtime plugin, and then used compile time only settings to get things to compile, but then at runtime eclipse complained it could not find reference to WIndupFactory.class to load it from Furnace.

             

            So I really don't know what to try from here. Any suggestions?

             

            Blue Skies,

            ~Ian

            • 3. Re: Furnace Class Loading Issue
              lincolnthree

              Addons don't have any knowledge of OSGi ClassLoaders (except the system classloader, and only select packages/types from that), so it's unlikely that anything is bleeding in.

               

              It is correct to place the API jars in your plugin's classpath/lib directory.

               

              On closer inspection of this exception, it appears that the Furnace ClassLoader adapter proxy is looking for the ApplicationContext.class in the Eclipse side of things (presumably to generate a proxy that implements this type), but the adapter is not finding ApplicationContext.class in the OSGi bundle. This means you are likely missing the Spring API jars in the Eclipse/OSGi plugin bundle. Is that correct? Try adding the Spring JAR that contains ApplicationContext.class to your bundle/plugin classpath.

               

              ~Lincoln

              • 4. Re: Furnace Class Loading Issue
                itewk

                Wouldn't including the spring API jar into the /lib directory of the plugin completely defeat the purpose of using forge/furance in the first place? I thought the point was so that I would not have to load all these dependency jars into the lib of the plugin. But maybe I am missing something.

                 

                What i was doing before was just placing windup and all of its dependency jars directly in the lib directory of the runtime plugin and everything worked. I thought by using forge/furance I would not have to do that any more and they could all be managed in the addon by forge.

                 

                If I start putting all the dependency Jars in the lib directory of the plugin then what benefit am I getting from the use of Forge/Furnace?

                 

                Or maybe I am just totally confused

                • 5. Re: Furnace Class Loading Issue
                  lincolnthree

                  It doesn't defeat the purpose. It's the same thing as separating an EJB into a Remote interface. You may have the Remote interface on your classpath, but that doesn't mean you have the implementation - that could be coming from somewhere completely different, even a different JVM - and you get handed a proxy instead of the real object.

                   

                  If you don't have the API with the .class objects on your classpath, you can't interact with them. OSGi does not delegate in any way to Furnace. As far as OSGi knows, Furnace doesn't exist, so you still need the types on your classpath.

                   

                  There are two classpaths that you shoudl care about:

                   

                  1. What Furnace sees and you don't. (Addons)

                  2. What you see and Furnace doesn't. (OSGi/Eclipse)

                   

                  What joins those two classpaths is the ClassLoaderAdapterCallback proxy, which handles adapting the types between the two world views. Any (non-built in) type that crosses the classloader boundary between the two worlds must be proxied. If that proxy extends, implements, or one of those types references a type (such as Spring's ApplicationContext.class), then that type must be available on the classpath or proxying will fail. That is what I believe happened in your scenario, and that is why I believe including the Spring API jar on the OSGi classpath should resolve the issue.