2

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>
A_Di-Matteo
  • 26,902
  • 7
  • 94
  • 128
Shahar Hamuzim Rajuan
  • 5,610
  • 9
  • 53
  • 91
  • You usually do not use Maven to start a server that has to be targeted by another module. I would use Jenkins to do that. One use case when you use Maven is for integration-tests, where you start the jetty, perform the tests (so staying in the same Maven build), then stop the jetty. – Tome Nov 26 '15 at 12:41
  • @Tome You are correct, and i am using jenkins for that. the problem is that i need to use different settings.xml file for the test. so I'll have to use a different maven build. – Shahar Hamuzim Rajuan Nov 26 '15 at 12:50

1 Answers1

2

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.

A_Di-Matteo
  • 26,902
  • 7
  • 94
  • 128
  • I agree , and I am using jenkins for my CI. the problem is that I need to use different settings.xml file for the test. so I'll have to use a different maven build instead of working with the phases. – Shahar Hamuzim Rajuan Nov 26 '15 at 12:55
  • Sorry I saw your comment only after having sent my answer. By settings.xml, you mean Maven settings.xml files? – A_Di-Matteo Nov 26 '15 at 13:06
  • Yes. but let's just say that I want to start my application and leave it running until I call to "jetty-stop", meaning the "jetty-start" part will be independent. – Shahar Hamuzim Rajuan Nov 26 '15 at 13:27
  • Ok, you could then use a 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. – A_Di-Matteo Nov 26 '15 at 14:19
  • @ShacharHamuzimRajuan I made it work, see the update 2 on the answer above, I tried to put as much details as possible but I obviously missed something (I couldn't attach the sample project I crafted). If you need further details, just let me know. – A_Di-Matteo Nov 26 '15 at 21:02
  • Wow,Thanks for that detailed answer and your effort. Sadly as you mentioned you wouldn't advice this approach, So I now working on making it work the basic simple start/test/stop flow.I just integrated the two settings.xml files and now I'm able to run the test as part of the flow. – Shahar Hamuzim Rajuan Nov 28 '15 at 09:49
  • While we are on it, and I see that you are a maven wiz, I will follow up with this question: Now that I want to run the simple flow, I have 5 profiles generate-schema,run,test.stop. the test will run on a different child module when I declare it in the mvn goals/properties: --batch-mode --errors clean --activate-profiles generate-schema,unpack-war,start-jetty,test,stop-jetty --projects apm-tests,apm-tests\apm-adapter-tests verify. How can I make the child module run only the tests and skip the rest of the profiles ()generate-schema and etc.) – Shahar Hamuzim Rajuan Nov 28 '15 at 10:18
  • I would suggest to create another question then since in comments would be difficult to provide the right level of details and further updating the first answer would lead to confusion. I would suggest to accept this answer then, since it go to the point (I hope) and then create a new one for the new scenario. You can link the next answer here so that I can follow it up. – A_Di-Matteo Nov 28 '15 at 20:42
  • Answer accepted :) Here is the followup question: http://stackoverflow.com/questions/33977452/how-to-ignore-maven-profiles-in-child-module – Shahar Hamuzim Rajuan Nov 28 '15 at 23:03