Jetty
  1. Jetty
  2. JETTY-1517

Resolve submodule artifacts in reactor builds with Maven 3

    Details

    • Type: Improvement Improvement
    • Status: Open Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 8.1.3
    • Fix Version/s: None
    • Component/s: Maven
    • Labels:
      None
    • Number of attachments :
      0

      Description

      As an improvement on extraClasspath, the jetty-maven-plugin could resolve submodule artifacts from reactor builds, like the tomcat7-maven-plugin does [1].

      In many cases, that would allow removing extraClasspath (which has to be updated each time you add/remove/rename a sibling submodule) and simply calling mvn jetty:run -pl :my-webapp -am instead.
      AFAICT, that was the original use-case for adding extraClasspath (see JETTY-1206), and Maven 3 now gives us the tools to do that more easily.

      For that to work, the jetty-maven-plugin would also need to automatically ignore non-war modules.

      [1] See http://tomcat.apache.org/maven-plugin-2.0-beta-1/run-mojo-features.html and http://svn.apache.org/repos/asf/tomcat/maven-plugin/trunk/common-tomcat-maven-plugin/src/main/java/org/apache/tomcat/maven/common/run/DefaultClassLoaderEntriesCalculator.java (the API seems to be getProjectReferences)

        Activity

        Hide
        Jan Bartel added a comment -

        Thomas,

        I had a look at the code you provided links for, and I can't see how the submodules' classes are being put onto the webapp classloader's classpath. Do you have any further links to code or doco that can clarify that?

        Also, if one executes a commandline like in your example (mvn jetty:run -pl my-webapp -am), won't that work right now, without any modifications? In other words, won't jetty:run be invoked in the my-webapp module, with its dependent projects rebuilt?

        thanks Jan

        Show
        Jan Bartel added a comment - Thomas, I had a look at the code you provided links for, and I can't see how the submodules' classes are being put onto the webapp classloader's classpath. Do you have any further links to code or doco that can clarify that? Also, if one executes a commandline like in your example (mvn jetty:run -pl my-webapp -am), won't that work right now, without any modifications? In other words, won't jetty:run be invoked in the my-webapp module, with its dependent projects rebuilt? thanks Jan
        Hide
        Thomas Broyer added a comment - - edited

        You're right, it comes for free with dependency resolution. It looks like the only issue is that jetty:run does not ignore non-war projects (see below). Note that it would then work but would include the dependent projects' build.outputDirectory to the setWebInfLib, which is weird (adding a directory to what is expected to be a list of JARs); but that's a detail.

        As for mvn jetty:run -pl my-webapp -am it'll invoke jetty:run on each project, starting with the reactor. For example, in a project where basic-server depends on basic-shared:jar and basic-client:war, with basic being the parent/reactor module, mvn -pl basic-server -am jetty:run gives the following:

        [INFO] Scanning for projects...
        [INFO] ------------------------------------------------------------------------
        [INFO] Reactor Build Order:
        [INFO] 
        [INFO] basic
        [INFO] basic-shared
        [INFO] basic-client
        [INFO] basic-server
        [INFO]                                                                         
        [INFO] ------------------------------------------------------------------------
        [INFO] Building basic 0.1-SNAPSHOT
        [INFO] ------------------------------------------------------------------------
        [INFO] 
        [INFO] >>> jetty-maven-plugin:8.1.3.v20120416:run (default-cli) @ basic >>>
        [INFO] 
        [INFO] <<< jetty-maven-plugin:8.1.3.v20120416:run (default-cli) @ basic <<<
        [INFO] 
        [INFO] --- jetty-maven-plugin:8.1.3.v20120416:run (default-cli) @ basic ---
        [INFO] Configuring Jetty for project: basic
        [INFO] webAppSourceDirectory /home//basic/src/main/webapp does not exist. Defaulting to /home//basic/src/main/webapp
        [INFO] Reload Mechanic: automatic
        [INFO] Classes directory /home//basic/target/classes does not exist
        [INFO] Context path = /
        [INFO] Tmp directory = /home//basic/target/tmp
        [INFO] Web defaults = org/eclipse/jetty/webapp/webdefault.xml
        [INFO] Web overrides =  none
        [INFO] web.xml file = null
        [INFO] Webapp directory = /home//basic/src/main/webapp
        2012-08-21 10:49:04.473:INFO:oejs.Server:jetty-8.1.3.v20120416
        2012-08-21 10:49:04.617:INFO:oejpw.PlusConfiguration:No Transaction manager found - if your webapp requires one, please configure one.
        2012-08-21 10:49:04.986:INFO:oejsh.ContextHandler:started o.m.j.p.JettyWebAppContext{/,file:/home//basic/src/main/webapp},file:/home//basic/src/main/webapp
        2012-08-21 10:49:04.986:INFO:oejsh.ContextHandler:started o.m.j.p.JettyWebAppContext{/,file:/home//basic/src/main/webapp},file:/home//basic/src/main/webapp
        2012-08-21 10:49:04.986:INFO:oejsh.ContextHandler:started o.m.j.p.JettyWebAppContext{/,file:/home//basic/src/main/webapp},file:/home//basic/src/main/webapp
        2012-08-21 10:49:05.068:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8080
        [INFO] Started Jetty Server
        

        With Tomcat, each project would be compiled (due to the @Execute( phase = LifecyclePhase.PROCESS_CLASSES ) annotation on the mojo) but then the mojo would skip the module unless it's of type war (in my case, I then simply configure the plugin to skip the basic-client module, as it's only ever used as an overlay in basic-server and cannot be run standalone, so that mvn tomcat7:run -pl basic-server -am compiles all the basic-server dependencies and ends up launching basic-server in Tomcat).

        This lead me to find a workaround to make it work like Tomcat: declare in the parent module that the jetty-maven-plugin is skipped by default (set skip to true in build/pluginManagement) and then set skip back to false in basic-server.
        I.e. in basic:

          <build>
            <pluginManagement>
              <plugins>
                <plugin>
                  <groupId>org.mortbay.jetty</groupId>
                  <artifactId>jetty-maven-plugin</artifactId>
                  <version>${jetty-maven-plugin.version}</version>
                  <configuration>
                    <skip>true</skip>
                  </configuration>
                </plugin>
        

        and then in basic-server:

          <properties>
            <jetty.skip>false</jetty.skip>
          </properties>
        
          <build>
            <pluginManagement>
              <plugins>
                <plugin>
                  <groupId>org.mortbay.jetty</groupId>
                  <artifactId>jetty-maven-plugin</artifactId>
                  <configuration>
                    <skip>${jetty.skip}</skip>
                  </configuration>
                </plugin>
        

        (or some variant using e.g. the default-cli execution ID)

        Show
        Thomas Broyer added a comment - - edited You're right, it comes for free with dependency resolution. It looks like the only issue is that jetty:run does not ignore non-war projects (see below). Note that it would then work but would include the dependent projects' build.outputDirectory to the setWebInfLib , which is weird (adding a directory to what is expected to be a list of JARs); but that's a detail. As for mvn jetty:run -pl my-webapp -am it'll invoke jetty:run on each project, starting with the reactor. For example, in a project where basic-server depends on basic-shared:jar and basic-client:war , with basic being the parent/reactor module, mvn -pl basic-server -am jetty:run gives the following: [INFO] Scanning for projects... [INFO] ------------------------------------------------------------------------ [INFO] Reactor Build Order: [INFO] [INFO] basic [INFO] basic-shared [INFO] basic-client [INFO] basic-server [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building basic 0.1-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] >>> jetty-maven-plugin:8.1.3.v20120416:run (default-cli) @ basic >>> [INFO] [INFO] <<< jetty-maven-plugin:8.1.3.v20120416:run (default-cli) @ basic <<< [INFO] [INFO] --- jetty-maven-plugin:8.1.3.v20120416:run (default-cli) @ basic --- [INFO] Configuring Jetty for project: basic [INFO] webAppSourceDirectory /home//basic/src/main/webapp does not exist. Defaulting to /home//basic/src/main/webapp [INFO] Reload Mechanic: automatic [INFO] Classes directory /home//basic/target/classes does not exist [INFO] Context path = / [INFO] Tmp directory = /home//basic/target/tmp [INFO] Web defaults = org/eclipse/jetty/webapp/webdefault.xml [INFO] Web overrides = none [INFO] web.xml file = null [INFO] Webapp directory = /home//basic/src/main/webapp 2012-08-21 10:49:04.473:INFO:oejs.Server:jetty-8.1.3.v20120416 2012-08-21 10:49:04.617:INFO:oejpw.PlusConfiguration:No Transaction manager found - if your webapp requires one, please configure one. 2012-08-21 10:49:04.986:INFO:oejsh.ContextHandler:started o.m.j.p.JettyWebAppContext{/,file:/home//basic/src/main/webapp},file:/home//basic/src/main/webapp 2012-08-21 10:49:04.986:INFO:oejsh.ContextHandler:started o.m.j.p.JettyWebAppContext{/,file:/home//basic/src/main/webapp},file:/home//basic/src/main/webapp 2012-08-21 10:49:04.986:INFO:oejsh.ContextHandler:started o.m.j.p.JettyWebAppContext{/,file:/home//basic/src/main/webapp},file:/home//basic/src/main/webapp 2012-08-21 10:49:05.068:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8080 [INFO] Started Jetty Server With Tomcat, each project would be compiled (due to the @Execute( phase = LifecyclePhase.PROCESS_CLASSES ) annotation on the mojo) but then the mojo would skip the module unless it's of type war (in my case, I then simply configure the plugin to skip the basic-client module, as it's only ever used as an overlay in basic-server and cannot be run standalone, so that mvn tomcat7:run -pl basic-server -am compiles all the basic-server dependencies and ends up launching basic-server in Tomcat). This lead me to find a workaround to make it work like Tomcat: declare in the parent module that the jetty-maven-plugin is skipped by default (set skip to true in build/pluginManagement ) and then set skip back to false in basic-server . I.e. in basic : <build> <pluginManagement> <plugins> <plugin> <groupId> org.mortbay.jetty </groupId> <artifactId> jetty-maven-plugin </artifactId> <version> ${jetty-maven-plugin.version} </version> <configuration> <skip> true </skip> </configuration> </plugin> and then in basic-server : <properties> <jetty.skip> false </jetty.skip> </properties> <build> <pluginManagement> <plugins> <plugin> <groupId> org.mortbay.jetty </groupId> <artifactId> jetty-maven-plugin </artifactId> <configuration> <skip> ${jetty.skip} </skip> </configuration> </plugin> (or some variant using e.g. the default-cli execution ID)
        Hide
        Thomas Broyer added a comment - - edited

        Ah, note that reactor-resolution only works for classes and resources (project.build.outputDirectory), and specifically not for web resources. Those would have to be computed out of the MavenProject#getProjectReferences, if at all possible (the Tomcat plugin doesn't do it, see MTOMCAT-158). A workaround would be to use mvn -pl my-webapp -am package jetty:run but then Artifact#getFile would return the packaged JAR for the dependencies, defeating the purpose of launching jetty:run in a reactor build (which is to use the build.outputDirectory directly, so the webapp can be restarted easily while your IDE compiles the classes there on-the-fly, and without the need to package the dependencies). Maybe for overlays support, the plugin could require that prepare-package or war:exploded by run previously on the WAR dependencies, and then look at the output for these (<project.build.directory>/<project.build.finalName>) out of the getProjectReferences.

        See also MNG-5214: for now (pending Maven 3.1.0), Maven will give you the build.outputDirectory for a dependency with type war; after the fix, Artifact#getFile() will instead return null.

        Show
        Thomas Broyer added a comment - - edited Ah, note that reactor-resolution only works for classes and resources ( project.build.outputDirectory ), and specifically not for web resources. Those would have to be computed out of the MavenProject#getProjectReferences , if at all possible (the Tomcat plugin doesn't do it, see MTOMCAT-158 ). A workaround would be to use mvn -pl my-webapp -am package jetty:run but then Artifact#getFile would return the packaged JAR for the dependencies, defeating the purpose of launching jetty:run in a reactor build (which is to use the build.outputDirectory directly, so the webapp can be restarted easily while your IDE compiles the classes there on-the-fly, and without the need to package the dependencies). Maybe for overlays support, the plugin could require that prepare-package or war:exploded by run previously on the WAR dependencies, and then look at the output for these ( <project.build.directory>/<project.build.finalName> ) out of the getProjectReferences . See also MNG-5214 : for now (pending Maven 3.1.0), Maven will give you the build.outputDirectory for a dependency with type war ; after the fix, Artifact#getFile() will instead return null.

          People

          • Assignee:
            Jan Bartel
            Reporter:
            Thomas Broyer
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated: