1 2 Previous Next 17 Replies Latest reply on Jul 24, 2013 9:19 AM by lincolnthree

    How to debug ClassNotFoundExceptions for Forge JARs?

    lennartj

      Hello there,

       

      I have a project which successfully creates a plugin, and verifies its operation within a unit test.

      When installing the plugin using forge source-plugin, an exception occurs and is clearly shown in the ~/.forge/runtime.log.

      The ultimate cause is shown below:

       

      Caused by: java.lang.ClassNotFoundException: org.jboss.forge.maven.plugins.Configuration from

      [Module "se.jguru.nazgul.forge.factory.impl.nazgul.nazgul-forge-factory-impl-nazgul.dependencies:1.0.0-SNAPSHOT-7a50e966-1b44-4c16-9a67-9d016be21aa8"

      from local module loader @22006edb

      (roots:

           /usr/local/share/forge/modules,

           /Users/lj/.forge/plugins,

           /Users/lj/Development/Projects/Nazgul/nazgul_forge/factory/factory-impl-nazgul)]

       

       

      I am at a loss here, since I got the impression that the forge-maven-api should be accessible.

      How can I proceed in the debugging?

      The project is small, and located in https://github.com/lennartj/nazgul_forge.git if anyone wants to take a look.

       

      Facts

       

      The Configuration class highlighted above is defined within the dependency org.jboss.forge:forge-maven-api:1.3.2.Final, which is

      1. included in the forge distribution and found under /usr/local/share/forge/modules - which is claimed to be searched by Forge in the log above, and
      2. referenced in provided scope within the plugin's project maven pom:

       

          <dependency>

            <groupId>org.jboss.forge</groupId>

            <artifactId>forge-maven-api</artifactId>

            <version>1.3.2.Final</version>

            <scope>provided</scope>

          </dependency>

       

       

      I checked the ~/.forge/plugins/.../[my plugin]/modules.xml which looks OK:

       

      <?xml version="1.0" encoding="UTF-8" standalone="no"?>

      <module xmlns="urn:jboss:module:1.0" name="se.jguru.nazgul.forge.factory.impl.nazgul.nazgul-forge-factory-impl-nazgul" slot="1.0.0-SNAPSHOT-7a50e966-1b44-4c16-9a67-9d016be21aa8">

        <resources>

         <resource-root path="nazgul-forge-factory-impl-nazgul.jar"/>

        </resources>

        <dependencies>

         <module name="se.jguru.nazgul.forge.factory.impl.nazgul.nazgul-forge-factory-impl-nazgul.dependencies" slot="1.0.0-SNAPSHOT-7a50e966-1b44-4c16-9a67-9d016be21aa8"/>

          <module name="org.jboss.forge.javaee.api" services="import"/>

          <module name="org.jboss.forge.maven.api" services="import"/>

          <module name="org.jboss.forge.scaffold.api" services="import"/>

          <module name="org.jboss.forge.scaffoldx.api" services="import"/>

          <module name="org.jboss.forge.shell.api" services="import"/>

          <module name="org.jboss.seam.render" services="import"/>

          <module name="javax.api"/>

        </dependencies>

      </module>

        • 1. Re: How to debug ClassNotFoundExceptions for Forge JARs?
          gastaldi

          Hi Lennart,

           

          Your projects looks allright. Perhaps this error may be caused by an unexpected scenario for the forge source-plugin, which afaik relies on a single artifact produced by the build.

          Have you tried splitting your repository in different repositories and having a separate repository for the plugin sources ?

          • 2. Re: How to debug ClassNotFoundExceptions for Forge JARs?
            lennartj

            Hello George,

             

            I'm not certain I understand you correctly here.

             

            The plugin is created in a multi-project build, that is true - but the unit test which runs the plugin works:

             

            ***SUCCESS*** Created project [foobar] structure in new working directory [/var/folders/n7/9gpdkfcd5mjc1b46_j1c4j7h0000gn/T/abstractshelltest5314697553657889629.tmp/foobar]

            Wrote /var/folders/n7/9gpdkfcd5mjc1b46_j1c4j7h0000gn/T/abstractshelltest5314697553657889629.tmp/foobar

            Wrote /var/folders/n7/9gpdkfcd5mjc1b46_j1c4j7h0000gn/T/abstractshelltest5314697553657889629.tmp/foobar/pom.xml

            Wrote /var/folders/n7/9gpdkfcd5mjc1b46_j1c4j7h0000gn/T/abstractshelltest5314697553657889629.tmp/foobar/poms

            Wrote /var/folders/n7/9gpdkfcd5mjc1b46_j1c4j7h0000gn/T/abstractshelltest5314697553657889629.tmp/foobar/poms/pom.xml

            Wrote /var/folders/n7/9gpdkfcd5mjc1b46_j1c4j7h0000gn/T/abstractshelltest5314697553657889629.tmp/foobar/poms/foobar-parent

            Wrote /var/folders/n7/9gpdkfcd5mjc1b46_j1c4j7h0000gn/T/abstractshelltest5314697553657889629.tmp/foobar/poms/foobar-parent/pom.xml

            Wrote /var/folders/n7/9gpdkfcd5mjc1b46_j1c4j7h0000gn/T/abstractshelltest5314697553657889629.tmp/foobar/poms/foobar-api-parent

            Wrote /var/folders/n7/9gpdkfcd5mjc1b46_j1c4j7h0000gn/T/abstractshelltest5314697553657889629.tmp/foobar/poms/foobar-api-parent/pom.xml

            Wrote /var/folders/n7/9gpdkfcd5mjc1b46_j1c4j7h0000gn/T/abstractshelltest5314697553657889629.tmp/foobar/poms/foobar-model-parent

            Wrote /var/folders/n7/9gpdkfcd5mjc1b46_j1c4j7h0000gn/T/abstractshelltest5314697553657889629.tmp/foobar/poms/foobar-model-parent/pom.xml

             

            Moreover, it seems that the dependencies folder under ~/.forge/plugins/se/..../[myplugin]/dependencies/ are correctly calculated.

             

            By "having a separate repository for the plugin sources", do you mean that I should avoid using a multi-module reactor build for the Forge plugin?

            Or am I missing your point entirely? 

             

            On a side note, where can I find the source plugin you refer to - just to peek around to see how it performs its classloading?

            Note that this plugin only creates reactor and parent POM projects; no java sources are generated here.

            • 3. Re: How to debug ClassNotFoundExceptions for Forge JARs?
              gastaldi

              Yes, that is exactly what I meant. :)

               

              I am not totally sure if the forge plugin is aware of multi-module builds.

              Could you please file a JIRA issue and reference this Forum message?

              If you could debug the ForgePlugin behavior to understand what is truly happening it would be much easier also.

               

              Best Regards,

               

              George

              1 of 1 people found this helpful
              • 4. Re: How to debug ClassNotFoundExceptions for Forge JARs?
                lennartj

                A problem, though, is that the ClassNotFoundException is thrown when looking for a JBoss Forge provided-scope dependency (i.e. the forge-maven-api) rather than any of the local reactor projects.

                • 5. Re: How to debug ClassNotFoundExceptions for Forge JARs?
                  lennartj

                  Added more debugging information on the https://issues.jboss.org/browse/FORGE-980 issue.

                  It seems that the ClassLoader responsible for loading the Forge Plugin cannot see some of its dependencies during construction.

                  • 6. Re: How to debug ClassNotFoundExceptions for Forge JARs?
                    lennartj

                    OK.. Added some decently complete debug printouts for classloading in a JBoss Forge plugin to the FORGE-980 issue.

                    It seems that classloading within Forge is either done through some completely different semantics than normally (i.e. two classloaders

                    exist on the base level - the Thread.currentThread().getContextClassLoader() one and the getClass().getClassLoader() one), or

                    the classloading implemented in JBoss Forge is broken.

                     

                    I'll take a look at the source in a few hours. Meanwhile, please check if you believe that I found the cause of the problem WRT the classloading

                    as described in FORGE-980.

                    • 7. Re: How to debug ClassNotFoundExceptions for Forge JARs?
                      lincolnthree

                      Sorry for coming into this discussion late. I believe you have stumbled across a case where the plugin itself is composed of three separate modules (as your maven structure appears to specify). However, this means that your sub-modules will be considered a "dependency" of the main plugin JAR, and will go into the dependency module classloader. Classes/JARs loaded from the Dependency module classloader do not have access to any forge internal classes (they may only see themselves.)

                       

                      Have you tried using the "dependencies-as-resource-root" configuration option to move the dependencies into the main plugin classloader?

                       

                      http://forge.jboss.org/docs/plugin_development/reference-libraries.html

                       

                      Modular ClassLoading is being implemented properly in Forge 2, so yes, while things are a bit funky in F1, we know about the issues and are working on fixing them

                       

                      I hope this helps.

                      ~Lincoln

                      • 8. Re: How to debug ClassNotFoundExceptions for Forge JARs?
                        lennartj

                        Hello there, Lincoln.

                         

                        I can get the implementation to work using the dependencies-as-resource-root settings, provided

                        I repeat all upstream maven dependencies within the maven project holding the plugin.

                        This is certainly doable, although probably rather confusing for most Maven-savvy

                        developers. I would therefore recommend amending the documentation on the JBoss Forge

                        site - a few further instructions would certainly have been of use for me.

                         

                        I sent a pull-request on the site documentation for this issue; made a stab at explaining

                        what needs to be done by a developer fluent in Maven but not in Forge.

                         

                         

                        The other - better - alternative would likely be to set the pathFilter of the

                        NativeLibraryResourceLoader used to load the dependencies on the active Forge module

                        to "ACCEPT" instead of "REJECT". The first screenshot of the FORGE-980 issue has this

                        settings property highlighted. So .. where is this property set?

                         

                         

                        A question here: Did you experience some other kinds of problems earlier on which led you

                        to configure the pathFilter to "REJECT" by default?

                         

                        It may very well be something I cannot  see, or fail to understand presently... but I have

                        searched a little throughout the 1.3.X  branch after ModuleLoader code, and found the only

                        references being in Bootstrap and within the "ModularPluginLoader.java" file.

                        The latter seems to be within a research state at the moment, unless I have missed something.

                         

                        ... which is quite possible...

                        • 9. Re: How to debug ClassNotFoundExceptions for Forge JARs?
                          lennartj

                          Hello again,

                           

                          I have updated the build for the multi-module and Forge 1.3.2.Final-compliant Plugin to create a new project, in the https://github.com/lennartj/nazgul_forge.git github repository.

                          This could serve as an example for how to construct multi-module forge plugins - unless you find something fundamentally broken in my approach or design.

                           

                          While the main point is to facilitate simple setup of a project structure, simply learning the JBoss Forge API and approach has been valid.

                          However, I have two observations:

                           

                          1. While the JBoss Forge APIs are elegant, they are sometimes incredibly verbose - in fact, they even surpass XML at times (see below for an example of a decently short maven plugin configuration).
                          2. The recursive/stack-like mindset of using createConfigurationElement() and getParentElement() for creating configuration to a plugin is not exactly intuitive, and could do with an example to simplify usage and understanding. (See below for an example). Could one perhaps simplify the entire approach with an "add this XML string as configuration"-method? Something along the lines of setConfig("<configuration><artifacts>...") is likely simpler to use. The XML Parsing section could likely use an example to provide plugin configuration from a Node approach, as indicated at the end of page http://forge.jboss.org/docs/plugin_development/important-apis.html.

                           

                          XML

                          <plugin>

                                          <artifactId>maven-dependency-plugin</artifactId>

                                          <executions>

                                              <execution>

                                                  <id>copyJpaRuntime</id>

                                                  <phase>process-resources</phase>

                                                  <goals>

                                                      <goal>copy</goal>

                                                  </goals>

                                                  <configuration>

                                                      <artifactItems>

                                                          <artifactItem>

                                                              <groupId>org.apache.openjpa</groupId>

                                                              <artifactId>openjpa</artifactId>

                                                              <version>${openjpa.version}</version>

                                                              <outputDirectory>${project.build.directory}</outputDirectory>

                                                              <destFileName>openjpa.jar</destFileName>

                                                          </artifactItem>

                                                      </artifactItems>

                                                  </configuration>

                                              </execution>

                                          </executions>

                                      </plugin>

                           

                           

                          JBoss Forge equivalent

                          private static final MavenPluginBuilder PLUGINSPEC_DEPENDENCY_PLUGIN_COPYOPENJPA =

                                      MavenPluginBuilder.create()

                                              .setDependency(DependencyBuilder.create()

                                                      .setGroupId("org.apache.maven.plugins")

                                                      .setArtifactId("maven-dependency-plugin"))

                                              .addExecution(ExecutionBuilder.create()

                                                      .addGoal("copy")

                                                      .setId("copyJpaRuntime")

                                                      .setPhase("process-resources")

                                                      .setConfig(ConfigurationBuilder.create()

                                                              .createConfigurationElement("artifactItems")

                                                              .createConfigurationElement("artifactItem")

                                                              .addChild("groupId").setText("org.apache.openjpa").getParentElement()

                                                              .addChild("artifactId").setText("openjpa").getParentElement()

                                                              .addChild("version").setText("${openjpa.version}").getParentElement()

                                                              .addChild("outputDirectory").setText("${project.build.directory}").getParentElement()

                                                              .addChild("destFileName").setText("openjpa.jar").getParentElement()

                                                              .getParentElement()

                                                              .getParentPluginConfig()));

                          • 10. Re: How to debug ClassNotFoundExceptions for Forge JARs?
                            lincolnthree

                            Yeah, I have to admit that this is pretty verbose. It would be nice just to be able to set plain XML into the configuration. Would you care to open a JIRA issue on this?

                             

                            https://issues.jboss.org/browse/FORGE

                             

                            It might be a while until we get to this, since what is there technically works fine, but if you'd like to send a patch with tests (as a pull request) we can make sure it gets in faster!

                             

                            Regarding the example of multi-module projects - I think that's a good idea, we whould probably reference this in the documentation. Would you care to add a section about this to the forge documentation?

                             

                            BTW. The Nazgul framework looks really interesting! I assume it's more back-end service oriented?

                             

                            Do you plan to add your plugin to the central plugin index? (See docs.)

                             

                            Thanks again for all of your contributions!

                            • 11. Re: How to debug ClassNotFoundExceptions for Forge JARs?
                              lennartj

                              Hello there,

                               

                              All right; will open a JIRA for the "plain XML to Configuration element" setter method.

                              Also - while I like the Builder pattern in general, I believe that the most compelling reason for suggesting a "plain XML" approach is one of usability - more specifically being able to use the same paradigm when learning to configure a Maven plugin as when configuring a JBoss Forge plugin configuration.

                               

                              Fair - I will add a section on multi-module JBoss Forge projects into the documentation.

                              Could you, meanwhile, document the configuration builder? Specifically, the difference between createConfigurationElement, setChild and addChild.

                              These methods occur in a few of the JBoss Forge builders - and the difference between createX, setX and addX can be subtle... which indicates an explanation can be appropriate.

                               

                              To answer your question - the Nazgul Framework is a set of patterns and best practises for devloping Maven projects.

                              It actually has little or nothing to do with back-end or services, although the patterns can certainly be used within a JEE or OSGi world.

                              What is currently missing (big time!) is a good means of getting started - and I basically chose between JBoss Forge and creating a small standalone Jar to do the job.

                              While the standalone JAR has the advantage of sporting a non-Eclipse GUI, I believe that Forge is certanly the better option here.

                               

                               

                              • 12. Re: How to debug ClassNotFoundExceptions for Forge JARs?
                                lennartj

                                Okies. Created a Github pull request for the 1.3.3.Final Forge version.

                                This implies a stable (POM version-wise) release of all projects in the reactor.

                                 

                                However... presumably you would want a stable Maven release within each

                                Forge compatibility branch (such as 1.3.4.Final, 2.0.0.Final etc.), or you would

                                risk running on snapshot releases.

                                 

                                The github branching model and the maven release plugin do not mix gently,

                                (or at all, actually) unless there is something fundamental I am missing.

                                Is there a thought from your side on how to manage this in a sustainable manner?

                                 

                                While I have - thankfully - only the forge version constant located in a single

                                POM file within the reactor, it would still require some manual labour and a

                                maven release for each branch supported by the Forge plugin.

                                 

                                Assuming I find a bug in a plugin, and wanted to fix that bug in all branches

                                where it actually exists... this could quickly spiral out of maintainable control.

                                What's your take on this?

                                • 13. Re: How to debug ClassNotFoundExceptions for Forge JARs?
                                  lincolnthree

                                  Awesome! And good question. The master branch on GitHub is the current development branch. We use the maven release plugin to tag each new release at that time. So pull requests should be sent against github.com/forge/core master branch for Forge 1, and 2.0 branch for Forge 2. New features are included when the next release goes out - whichever features make it in, get released, the ones that don't make it wait until the next release.

                                  • 14. Re: How to debug ClassNotFoundExceptions for Forge JARs?
                                    lennartj

                                    Ah ... I realize I may have been somewhat unclear in my question.

                                     

                                    You gave an answer describing the release for JBoss Forge itself.

                                    However, my question pertained to the development of Forge Plugins. According the documentation "You should also create a git branch in your Plugin repository – the name of this branch should be exactly the same as the Forge API version you wish to support. Repeat this task for each Forge API version you wish to support.".

                                     

                                    For a plugin X, which supports 4 different Forge releases, a minimum of 4 branches should be created.

                                    This implies at least 4 different mvn release:prepare-style operations for the plugin to achieve stable releases for the plugins.

                                    In the main yaml, it would seem that most forge plugin artifacts use snapshot versions... which implies a non-stable release.

                                    What's your take on this situation?

                                    1 2 Previous Next