17

I have a multimodule maven project, and one of the modules is for distribution.

Project \
| moduleA \
| moduleB \
| ...
| dist-module \

The distribution contains an executable jar that I'd like to easily execute. However, to execute it I have to type something like:

java -jar dist-module/target/dist-module-1.0-SNAPSHOT-full-dist/myJar.jar

It would be quite preferable to simply type:

mvn exec:java \ OR
mvn exec:exec

Unfortunately, I can't find a way to get the java goal to execute a .jar. The exec goal will actually do it, but there's a catch: the jar contains an embedded jetty server, and due to the way exec works (doesn't use the same JVM as maven) the server doesn't terminate unless I kill the process manually, which is similarly bothersome.

Any recommendations on how to do this using maven?

Edit:
For clarification, this command will primarily be used for simple manual smoke-testing; to read the log output and ensure the program started up properly in its distribution environment. As such, it should probably be a blocking call with ctrl-c terminating both the server and maven.

The embedded server is specialized to run a few specific applications, and does not automatically reload them. So, there's not a big need to keep the server running independently of maven for long periods of time.

Shaun
  • 2,490
  • 6
  • 30
  • 39
  • What is the task of the jetty? – Nachtgold Mar 04 '13 at 11:52
  • Can you attach the pom with the problematic exec:java goal definition? – Haim Raman Mar 05 '13 at 12:08
  • There is no good way, because maven is a build and deploy tool. If your jar is a part of a build process, then write a maven plugin for it. If you just want to use maven to run your app, maybe it's better to think of something else. – kan Mar 06 '13 at 11:53
  • You want the server to be terminated when maven finishes, or you want another way to stop it? – Pablo Grisafi Mar 06 '13 at 14:46

2 Answers2

30

mvn exec:java runs the app directly from the compiler output below target/ - no need to run from the jar:

    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.2.1</version>
        <executions>
            <execution>
                <id>default-cli</id>
                <goals>
                    <goal>java</goal>
                </goals>
                <configuration>
                    <mainClass>uk.co.pookey.hibernate.App</mainClass>
                    <systemProperties>
                        <systemProperty>
                            <key>derby.stream.error.file</key>
                            <value>${basedir}/target/derby.log</value>
                        </systemProperty>
                    </systemProperties>
                </configuration>
            </execution>
        </executions>
    </plugin>            

If you want to run the jar with mvn exec:exec :

    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.2.1</version>
        <executions>
            <execution>
                <id>default-cli</id>
                <goals>
                    <goal>exec</goal>
                </goals>
                <configuration>
                    <executable>java</executable>
                    <!-- optional -->
                    <workingDirectory>/tmp</workingDirectory>
                    <arguments>
                        <argument>-jar</argument>
                        <argument>${basedir}/target/hibernate-derby-memory-${project.version}.jar</argument>
                    </arguments>
                </configuration>                        
            </execution>
        </executions>
    </plugin>         

If you have problems with jetty terminating, I'd recommend running an integration test (or just don't exit the jetty main thread without terminating jetty first, or just use jetty's stop port)! It is possible to run a JVM in the background and let maven stop it again after testing. There are three phases for this: pre-integration-test, integration-test or post-integration-test. You can read more about this at http://docs.codehaus.org/display/MAVENUSER/Maven+and+Integration+Testing . When using jetty maven plugin, the pom.xml config could like:

   <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <!-- test start/stop: -->
        <executions>                
            <execution>
                <id>start-jetty</id>
                <phase>pre-integration-test</phase>
                <goals>
                    <goal>deploy-war</goal>
                </goals>
                <configuration>
                    <daemon>true</daemon>
                    <systemProperties>
                        <systemProperty>
                            <name>some.prop</name>
                            <value>false</value>
                        </systemProperty>
                    </systemProperties>
                </configuration>
            </execution>
            <execution>
                <id>stop-jetty</id>
                <phase>post-integration-test</phase>
                <goals>
                    <goal>stop</goal>
                </goals>
            </execution>
        </executions>    
    </plugin>

Instead of binding the jetty maven plugin to these phases, you could bind the maven antrun plugin to execute arbitrary commands.

user1050755
  • 11,218
  • 4
  • 45
  • 56
  • I need to run the jar because it contains logic that identifies its path and specifies other resources in the same directory. Hence, it's actually the distribution project that needs to execute the code. However, using maven for integration testing is an interesting possibility that's worth exploring, so +1 for that at the very least. – Shaun Mar 08 '13 at 12:31
  • Looks like you are re-inventing the wheel. If you need proper distribution, think about using war files and possibly the tanukisoft wrapper to run them in production -- if you don't want to use entire application servers like tomcat and jetty is enough for you. The tanukisoft wrapper starts a jetty app server and runs your webapps from an unpacked distribution archive. If you need an example, look at Archiva's source code. If you need help, I have done that before... And when using war files, you could use the jetty-integration example I have mentioned. – user1050755 Mar 09 '13 at 08:43
  • If you have a stripped down version of your server project, I could give it a try. Shouldn't be too complicated. But I never managed to set up jetty webapps programmatically :-) – user1050755 Mar 09 '13 at 08:52
  • With a `install` it gets executed fine by the `mvn clean install` command. – Stephane Jan 05 '17 at 10:09
  • The link is dead – jbuddy Aug 26 '20 at 06:09
3

I would use the maven ant or gmaven (then use groovy ant builder) if you want to execute stuff

After your edits it sounds like your using something like DropWizard. You might want to see how they are solving that problem.

Edit based on comments:

The Spring Boot Maven will create executable wars as well as execute them and you don't need Spring Boot nor Spring. More details in my answer here: Can spring-boot-maven-plugin be used for non spring project?

Adam Gent
  • 47,843
  • 23
  • 153
  • 203
  • While I feel user1050755's answer more directly addresses the question, you have my thanks for bringing DropWizard to my attention. It doesn't quite suit my project's needs, but it's similar enough to be an interesting case study. – Shaun Mar 11 '13 at 16:01
  • The both links in this answer are dead as of this writing. – Stephan Jul 14 '17 at 17:59
  • @Stephan Actually the best option I now recommend is the Spring Boot maven plugin which incidentally does not need Spring Boot or even Spring. See my answer here: https://stackoverflow.com/questions/42696495/can-spring-boot-maven-plugin-be-used-for-non-spring-project/43017960#43017960 – Adam Gent Jul 17 '17 at 17:43