tomcat-maven-plugin with multiple modules building one war only - java

I try to build a web application based on multiple maven modules. One of the modules is called "web" and is solely responsible to package a war which should be deployed to a tomcat using the tomcat7-maven-plugin. I have following modules defined in my parent.pom:
common
persistence
persistence-embedded
service
rest
web
All of them are combined into one web-application-war, the web module has set packaging to war. The problem is, that my war file is deployed for each submodule (and the main-parent-module) over and over again when I run mvn tomcat7:redeploy, which leads to 7 deployments. Apparently, this is not how it should be. The tomcat7-maven-plugin configuration currently looks like this:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<ignorePackaging>true</ignorePackaging>
<url>http://localhost:8080/manager/text</url>
<server>tomcatServer</server>
<path>/webapp</path>
<warFile> /home/username/dev/maven-multimodule-example/web/target/maven-multimodule-example-1.0-SNAPSHOT.war</warFile>
<username>admin</username>
<password>password</password>
</configuration>
</plugin>
As you can see, I need to specify the warFile (which is not a solution but rather a hack, because I can't use ${project.basedir} which would lead to the submodule-dir) to make it work.
However, if I run the web application with mvn tomcat7:run, it looks quite good, because the other non-war-building modules are skipped by the plugin.
How can I configure the plugin the right way to deploy the war file only once?

Every configuration within the <build> section of a parent POM will be inherited and thus executed in all child modules. So if you want to deploy only once, add it to only one POM (e.g. the web POM).

Thanks to dunni's help I noticed my missunderstanding of how multimodule projects are built. Now I've placed the plugin configuration in the web module and added an execution, bound to the install phase so that I can rebuild the whole project and get it deployed to my tomcat. Obviously maven takes care of the right execution order of the modules.
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<url>http://localhost:8080/manager/text</url>
<server>tomcatServer</server>
<path>/webapp</path>
<warFile>${project.basedir}/target/${project.parent.artifactId}-${project.parent.version}.war</warFile>
<username>admin</username>
<password>password</password>
</configuration>
<executions>
<execution>
<id>redeployafterinstall</id>
<phase>install</phase>
<goals>
<goal>redeploy</goal>
</goals>
</execution>
</executions>
</plugin>

Related

Maven deploy two jars with different classifiers from two separate pom.xml

I want to deploy two jar artifacts with different classifiers, but at the moment that fails because both supply their own version of pom.xml. How can I fix that, so that both pom.xmls can be uploaded along with their artifacts?
Example - I have com.test.company.somelib-1.0.0-cmp1.jar and com.test.company.somelib-1.0.0-cmp2.jar, where cmpX is a classifier. Both packages contain (logically) the same code and classes (of the same version), they only differ slightly in the way they were preprocessed. The classifier annotation is there due to backwards compatibility we need to maintain.
Long story short, first artifact uploads fine, second one fails with Forbidden, because our repository does not allow overwriting artifacts (and I want to keep it that way).
There is a slightly different pipeline that creates both the packages, so it is easier to have their builds separate. I just want to deploy them as two packages of the same name and different classifier.
Thanks for help
Edit: it has been suggested to use Maven profiles. I can see that they would work, but they would not be ideal.
Consider the setup I have depicted on the picture below - there is a CI server (TeamCity).
There is a "starter" build (Sources). This build checkouts all required source files.
From this starter build several other builds are triggered (processing using x.x.x/compile). Each of those builds adjusts a template-pom.xml (fills in particular classifier and other info), and then builds and deploys its artifact to our Artifactory.
With the setup I want to achieve if I decide to add another processing-build, all I need to do is add another "branch". If I was using profiles, I would need to also add a new profile to the pom.xml file.
Correct me if I am wrong please. Profiles seem to be able to achieve the goal, but not ideally, at least in my case.
I strongly discourage having 2 (or more) different pom files with the same GAV.
But I understand your need is raised by legacy reasons.
I have not tried this myself but it could be working:
Leave one build (= maven project) as you have it now. On the other build skip the normal deployment and manually invoke the deploy-file goal of the deploy plugin like so:
<build>
<plugins>
<!-- skip normal execution of deploy plugin -->
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<executions>
<execution>
<id>default-deploy</id>
<configuration>
<skip>true</skip>
</configuration>
</execution>
</executions>
</plugin>
<!-- invoke with goal: deploy-file -->
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<executions>
<execution>
<id>someId</id>
<phase>deploy</phase>
<goals>
<goal>deploy-file</goal>
</goals>
<inherited>false</inherited>
<configuration>
<file>path-to-your-artifact-jar</file>
<generatePom>false</generatePom>
<artifactId>xxx</artifactId>
<groupId>xxx</groupId>
<version>xxx</version>
<classifier>xxx</classifier>
<packaging>xxx</packaging>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

How to generate separate jar files for application, source, and documentation (for central.sonatype.org)

Sonatype has a repository that I want to deploy a jar file to, and they ask for separate files for application, sources, and javadocs:
Example:
example-application-1.4.7.pom
example-application-1.4.7.jar
example-application-1.4.7-sources.jar
example-application-1.4.7-javadoc.jar
In Scala SBT, I have a command called "package" that generates the jar file for the project, but that only generates "example-application-1.4.7.jar".
Question: What should I do to generate the other two jar files?
In Maven, in order to get the additional -sources and -javadoc artifacts, add to your POM file the following:
<build>
<plugins>
<!-- additional plugin configurations, if any.. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Note the snippet above:
We are invoking the Maven Source Plugin to create an additional jar files for sources
We are invoking the Maven Javadoc Plugin to create an additional jar files for javadoc
Executing
mvn clean package
You will find these two additional jars in the target folder.
The .pom file instead is generated during the install phase, but it is not placed under the target folder. Basically, it is a copy of your pom.xml file, with a different extension and used by Maven during the dependency mediation process to check which transitive dependencies are required by the concerned artifact.
Executing
mvn clean install
Maven will install the artifact in your local cache (in your machine), under path_to_cache/.m2/repository/your_groupId/your_artifactId/your_version/. In this folder, you will also find the .pom file, which normally you don't need to distribute (it is created automatically by Maven).
Further note: you probably don't want to generate these additional jar files at each and every build, so to speed up normal builds and have them only on demand, you could wrap the snippet above in a Maven profile.
You can achieve this by removing the snippet above from your build section and add a further section at the end of your pom:
<profiles>
<profile>
<id>prepare-distribution</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
So that normal builds would not create these jars anymore, but when executing the following:
mvn clean install -Pprepare-distribution
You would instead get them back. the -P option is actually activating on demand the profile defined with the id prepare-distribution.
With Maven 3 a default profile already comes as part of the super pom which perform exactly the same actions (sources and javadoc artifact), hence no need to add anything to your existing project. Simply run:
mvn clean install -Prelease-profile
Or, to activate it via a property
mvn clean install -DperformRelease=true
However, as also specified in the super pom, this profile may be removed in future releases (although there since first Maven 3 version till version 3.3.9 so far)
NOTE: The release profile will be removed from future versions of the super POM
The main reason behind this warning is most probably to push for the usage of the Maven Release Plugin, which indirectly makes use of this profile via the useReleaseProfile option of the release:perform goal.
As highlighted by comments, if you are not familiar with maven (especially via console) I would definitely recommend to
Go through the official Maven in 5 minutes documentation for a quick but worthy look.
Play with Maven from the command line, is there where Maven gives you its best. IDE integrations are great, but command line is the real turning point.
Then play with the POM customization above, to get familiar with some concepts and behaviors, first directly as part of your default build, then moved to a profile.
Then, and only then, move to the Maven Release Plugin usage. I recommend it as last step because you would already have acquired more confidence and understanding and see it as less magic and more reasonable approach.

How to bind SASS plugin goal to tomcat7 deploy phase (maven)

I am developing a webapp running on Tomcat7, and using maven for dependencies/automated builds. Yesterday I started using the sass-maven-plugin, which is great. Its goal sass:update-stylesheets processes sass files and outputs css. Unfortunately, I can't have it executed during the webapp packaging. I am pretty new to maven too, so I might have missed something. Here's my understanding :
when I type mvn tomcat7:deploy, maven executes the deploy goal defined in the tomcat7 plugin
this plugin goes through some phases of the development lifecycle. More specifically, as mentioned in the doc, it "invokes the execution of the lifecycle phase package prior to executing itself."
if I map the goal sass:update-stylesheets to the package phase in <build><executions/></build>, it should be executed everytime I deploy/redeploy my app.
When I run mvn sass:update-stylesheets independently of tomcat7:deploy, everything is smooth. sass-maven-plugin gets the .scss files from src/main/resources, processes them and places the output in src/main/webapp/resources, where I want it to be to be deployed with my webapp. Unfortunately, if I don't run the command prior to tomcat7:deploy, I don't get any css for my pages. What did I get wrong? Also, is there any way I could map the sass:update-stylesheets to the phase process-resources, for instance, which would make more sense? Lastly, if this all works, will Eclipse's incremental build pick it up?
Here's my pom.xml (the relevant parts)
...
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
...
</configuration>
</plugin>
<!-- SASS processing -->
<plugin>
<groupId>org.jasig.maven</groupId>
<artifactId>sass-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<id>generate-css</id>
<phase>package</phase>
<goals>
<goal>update-stylesheets</goal>
</goals>
</execution>
</executions>
<configuration>
<useCompass>true</useCompass>
<resources>
<resource>
<source>
<directory>${basedir}/src/main/resources</directory>
</source>
<destination>${basedir}/src/main/webapp/resources</destination>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
Thanks in advance for your help.
You have configured the stuff in the plugin management section. Please move the execution and it's binding to the build section (that is, out of the pluginManagement's plugins section into build's plugins section).

adding ## to maven 3 artifact name for tomcat 7 parallel deployment

I have read quite a few answers on this forum, so hopefully I am asking something.
Recently we moved to Tomcat 7 and usual procedure is to pick up a war file from Nexus repository, stick it in tomcat webapps dir and start the server and use it.
But due to war file artifact name in Nexus being my-app-war-1.0.war context path in tomcat is not what is expected. I know that this can be configured by context.xml, but I was wondering if there is a way to add ## to artifact name that is deployed in Nexus.
I tried changing #{project.build.finalName} but it only changes artifact name in target directory, maven deploy plugin still uses artifactId, which is 'my-app-war'. So artifact in Nexus ends up being 'my-app-war-1.0.war' As artifactId in maven has a quite strict structure and ## is not allowed there I was wondering what would be the right way of adding ## to artifact name, as we are very likely to consider to use parallel deployment, so I am looking for ways to enable this functionality.
I guess I could deploy two versions of the same war file to Nexus, one being named slightly different(with ##), but then it`s easier to just rename it and save some space. I wonder was there any plan how would the ## would be added to application name, when Parallel naming feature was implemented in Tomcat.
You can use <classifier> configuration of maven-war-plugin. This way your war will be installed to the repository with the name ${project.artifactId}-${project.version}-my-app-war.war
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<classifier>##my-app-war</classifier>
</configuration>
</plugin>
The problem is that Nexus returning the following error if you include in maven version ##.
Illegal character in fragment at index 103
You can enter in <path> by deploying to Apache7 the characters ## for the paralell deployment as folowing:
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<executions>
<execution>
<id>remote</id>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
<configuration>
<mode>war</mode>
<path>/${project.artifactId}-##${project.version}</path>
<url>http://tomcat7.../manager/text</url>
<username>user</username>
<password>password</password>
<update>true</update>
</configuration>
</execution>
</executions>
</plugin>

maven yui compression on war:war

I'm trying to automatically compress both CSS and JS using maven and this plugin. I want to compress when the goal war is executed but I'm not figuring how:
<build>
<finalName>${artifactId}-${version}-production</finalName>
<plugins>
<plugin>
<groupId>net.sf.alchim</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<executions>
<execution>
<configuration>
<gzip>true</gzip>
<nosuffix>true</nosuffix>
</configuration>
<goals>
<goal>compress</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
You need to bind the execution to a phase so it will be executed when you run the war packaging. These are the available phases you can bind to for war packaging.
<plugin>
<groupId>net.sf.alchim</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<executions>
<execution>
<id>compress</id>
<phase>process-resources</phase>
...<!--rest of config is fine-->
Update: Are the js.gz files not being generated or just not included in the war?
One additional thing to check if you're still not seeing the content in the war is that the resources should be under src/main/resources, not src/main/webapp.
The yuicompressor plugin will process the js files in src/main/webapp, but they won't be included in the final war.
Update 2: reread your question after seeing your answer, I'd misread the goal you were running. To avoid running two goals you can do one of these:
Try instead of running the war goal, run install or package, this will invoke the standard lifecycle, and the yuicompressor plugin will be invoked in the process-resources phase.
Alternatively change the phase the yuicompressor goal is bound to in the example above to package so it is activated when you run the war:war goal.
for some weird reason war:war doesn't call the plugin in the phase process-resources: I just added a custom menu on nb 6.7 that call first compile, then war:war

Categories