Run Jetty with jetty-maven-plugin and finish the b

2019-07-12 03:14发布

问题:

I want to Run Jetty with jetty-maven-plugin and finish the build when jetty is running.

I created a pom.xml that starts jetty and deploying a war file, after the jetty starts I want maven to finish the build while leaving the jetty running, So that I could start another maven build to run tests on the server I just ran jetty on.

Then I will create another maven build that just stops the jetty server.

Problem is that I didn't managed to start jetty and make the maven build stop after that, Does anyone knows how to do that?

p.s I used "run-forked" for that, but it still waited for a stop signal so the build was stuck.

This is the jetty-start profile:

 <profile>
           <id>start-jetty</id>
            <activation>
                <activeByDefault>false</activeByDefault>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.eclipse.jetty</groupId>
                        <artifactId>jetty-maven-plugin</artifactId>
                        <configuration>
                            <war>${unpacked.war.directory}</war>
                            <contextXml>${unpacked.war.directory}/WEB-INF/jetty-web.xml</contextXml>
                            <webApp>
                                <contextPath>/qabin</contextPath>
                            </webApp>
                            <systemProperties>
                                <systemProperty>
                                    <name>mercy.td.sa_config_dir</name>
                                    <value>${tests.runtime}</value>
                                </systemProperty>
                                <systemProperty>
                                    <name>jetty.port</name>
                                    <value>${jetty.start.port}</value>
                                </systemProperty>
                            </systemProperties>
                            <stopPort>${jetty.stop.port}</stopPort>
                            <stopKey>STOP</stopKey>
                        </configuration>
                        <executions>
                            <execution>
                                <id>start-jetty</id>
                                <phase>pre-integration-test</phase>
                                <goals>
                                    <goal>run-forked</goal>
                                </goals>
                                <configuration>
                                    <scanIntervalSeconds>0</scanIntervalSeconds>
                                    <daemon>true</daemon>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>

回答1:

It should be clear that Maven is a build tool, not a commands executor tool. Starting/stopping Jetty should be part of the same build within an integration tests execution phase. Moreover, you are also creating dependencies between two maven builds (which are not effectively builds indeed), which may be a problem as part of your CI environment if ever the stop build fails - for whatever reason - and leave the started jetty up and running and as such consume resources on your CI server for undefined time.

A simple start/test/stop flow could be implemented as following as part of the same Maven build:

        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>integration-test</id>
                            <goals>
                                <goal>test</goal>
                            </goals>
                            <phase>integration-test</phase>
                            <configuration>
                                <excludes>
                                    <exclude>none</exclude>
                                </excludes>
                                <includes>
                                    <include>**/*IntegrationTest.java</include>
                                </includes>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.eclipse.jetty</groupId>
                    <artifactId>jetty-maven-plugin</artifactId>
                    <version>9.2.8.v20150217</version>
                    <configuration>
                        <scanIntervalSeconds>10</scanIntervalSeconds>
                        <stopKey>foo</stopKey>
                        <stopPort>9999</stopPort>
                        <stopWait>2</stopWait>
                        <webApp>
                            <contextPath>/examplecomponent</contextPath>
                        </webApp>
                        <httpConnector>
                            <port>7777</port>
                        </httpConnector>
                    </configuration>
                    <executions>
                        <execution>
                            <id>start-jetty</id>
                            <phase>pre-integration-test</phase>
                            <goals>
                                <goal>start</goal>
                            </goals>
                            <configuration>
                                <scanIntervalSeconds>0</scanIntervalSeconds>
                            </configuration>
                        </execution>
                        <execution>
                            <id>stop-jetty</id>
                            <phase>post-integration-test</phase>
                            <goals>
                                <goal>stop</goal>
                            </goals>
                        </execution>
                    </executions>
                    <dependencies>
                        <dependency>
                            <groupId>org.eclipse.jetty</groupId>
                            <artifactId>jetty-util</artifactId>
                            <version>9.2.8.v20150217</version>
                        </dependency>
                    </dependencies>
                </plugin>
            </plugins>
        </build>

Basically, you configure the surefire plugin to skip integration tests during the test phase, then start jetty before the integration test fase, execute integration tests (based on suffix) and then stop jetty afterwards.

I would also suggest to move it a profile in order to make the default build faster and independent from integration tests, so that it can also run successfully when offline, then activate the profile when required (i.e. on the CI build).

Updated: if you really need to have a start in a maven project and a stop in an other maven module, you could apply the following approach: Have an aggregator/multimodule maven project: a module will provide the start, another module will provide the stop, other modules will use the running jetty. However, the maven reactor may not invoke them in the order you wish, you should then make sure the stop module depends on the start module (has it as dependency) and any module requiring the running module will also have the start module as dependency. Moreover, the stop module should also depend on testing module so that it will be executed only at the end. That should do the trick. Hence, to summarize:

  • jetty-question (the aggregator project)
    • start-jetty-module
    • use-jetty-module (has start-jetty-module as dependency)
    • stop-jetty-module (has start-jetty-module and use-jetty-module as dependencies)

Updated 2: Below the working approach (tested on Windows machine) Here is the pom file of the aggregator project, jetty-question:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.stackoverflow</groupId>
  <artifactId>jetty-question</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>pom</packaging>
  <modules>
    <module>jetty-start</module>
    <module>jetty-stop</module>
    <module>jetty-use</module>
  </modules>
</project>

Note the modules declaration and the packaging as pom (required for aggregators).

Here is the pom file of the jetty-start module, which is a folder nested under jetty-question

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.stackoverflow</groupId>
        <artifactId>jetty-question</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <artifactId>jetty-start</artifactId>
    <packaging>war</packaging>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.6</version>
                <executions>
                    <execution>
                        <phase>verify</phase>
                        <configuration>
                            <target>
                                <exec executable="cmd.exe" spawn="true">
                                    <arg value="/c" />
                                    <arg value="mvn jetty:run" />
                                </exec>
                            </target>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.2.8.v20150217</version>
                <configuration>
                    <scanIntervalSeconds>10</scanIntervalSeconds>
                    <stopKey>foo</stopKey>
                    <stopPort>9999</stopPort>
                    <stopWait>2</stopWait>
                    <webApp>
                        <contextPath>/jetty-start</contextPath>
                    </webApp>
                    <httpConnector>
                        <port>7777</port>
                    </httpConnector>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.eclipse.jetty</groupId>
                        <artifactId>jetty-util</artifactId>
                        <version>9.2.8.v20150217</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
</project>

Note: the module is configuring the jetty plugin and then executing a background process via the antrun plugin to execute mvn jetty:run In my example code, the deployed application simple provided an index.html page printing Hello world.

Here is the pom file of the jetty-use module:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.stackoverflow</groupId>
        <artifactId>jetty-question</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <artifactId>jetty-use</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.stackoverflow</groupId>
            <artifactId>jetty-start</artifactId>
            <version>1.0.0-SNAPSHOT</version>
            <type>war</type>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>2.47.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

Important: as described above, it needs a dependencies on the jetty-start module so that the reactor maven build will execute it after the jetty-start (and as such we are sure jetty would be running when executing this build). Note the dependencies for Junit and selenium, I used them to effectively test the running jetty via the junit integration test below:

public class AppIntegrationTest extends TestCase {

    public void testApp() throws Exception {
    // Create a new instance of the Firefox driver
    WebDriver driver = new HtmlUnitDriver();

    // Launch the Online Store Website
    driver.get("http://localhost:7777/jetty-start");

    WebElement element = driver.findElement(By.id("title"));
    Assert.assertNotNull(element);
    Assert.assertNotNull(element.getText());
    Assert.assertEquals("Hello World!", element.getText());
    }
}

Finally, here is the pom file of the jetty-stop module

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.stackoverflow</groupId>
        <artifactId>jetty-question</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <artifactId>jetty-stop</artifactId>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.6</version>
                <executions>
                    <execution>
                        <phase>verify</phase>
                        <configuration>
                            <target>
                                <exec executable="cmd.exe" spawn="true">
                                    <arg value="/c" />
                                    <arg value="mvn jetty:stop" />
                                </exec>
                            </target>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.2.8.v20150217</version>
                <configuration>
                    <scanIntervalSeconds>10</scanIntervalSeconds>
                    <stopKey>foo</stopKey>
                    <stopPort>9999</stopPort>
                    <stopWait>2</stopWait>
                    <httpConnector>
                        <port>7777</port>
                    </httpConnector>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.eclipse.jetty</groupId>
                        <artifactId>jetty-util</artifactId>
                        <version>9.2.8.v20150217</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>com.stackoverflow</groupId>
            <artifactId>jetty-start</artifactId>
            <version>1.0.0-SNAPSHOT</version>
            <type>war</type>
        </dependency>
        <dependency>
            <groupId>com.stackoverflow</groupId>
            <artifactId>jetty-use</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

Note the similar configuration to the jetty-start module. This module is also configuring the jetty plugin and it is stopping it via the antrun plugin which will execute in background the mvn jetty:stop goal. Also note the dependencies of this module: it needs to depend on both jetty-start and jetty-use so that the maven reactor build will execute it at the end.

Further notes: the jetty configuration on the jetty-start and jetty-stop module need obviously to share the stop key and stop port. For this example, server port is harcoded in the pom file (which also needs to be the same for both jetty-start and jetty-stop modules), but you could also move it to a property in the parent module. Moreover, the antrun plugin executes a background process in Windows mode. If you are running on Linux a & suffix should also make the trick. I would also suggest to keep it in a multimodule project so that you can make sure that dependencies are coupled together.

Although I would not advice this approach as described at the top of this answer, it was challenging and fun to get it to work, so thank you for the fun. Hope you get it work too.