Maven 3 profile with extensions - maven

My question had been addressed in this thread, but the explanation is not clear.
I have this build definition in one of my pom.xml files:
<build>
<finalName>${my.project}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
<extensions>
<extension>
<groupId>org.kuali.maven.wagons</groupId>
<artifactId>maven-s3-wagon</artifactId>
<version>1.1.19</version>
</extension>
</extensions>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/settings.properties</include>
</includes>
</resource>
</resources>
</build>
Notice that I'm using the maven-s3-wagon extension.
Next, I would like to have 2 different profiles, each with it's own settings, plugins and extensions but maven does not allow the extensions tag under a profile.
When I try using a profile:
<profiles>
<profile>
<id>local-build</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<finalName>${my.project}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
<extensions>
<extension>
<groupId>org.kuali.maven.wagons</groupId>
<artifactId>maven-s3-wagon</artifactId>
<version>1.1.19</version>
</extension>
</extensions>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/settings.properties</include>
</includes>
</resource>
</resources>
</build>
</profile>
</profiles>
I get a an error in my pom:
cvc-complex-type.2.4.a: Invalid content was found starting with element 'extensions'. One of '{"http://maven.apache.org/POM/4.0.0":defaultGoal, "http://maven.apache.org/POM/
4.0.0":resources, "http://maven.apache.org/POM/4.0.0":testResources, "http://maven.apache.org/POM/4.0.0":directory, "http://maven.apache.org/POM/4.0.0":filters, "http://
maven.apache.org/POM/4.0.0":pluginManagement}' is expected.
Question So using the extension tag means I can't use profiles? How can I use or change build extensions via profile?

Indeed, the official Maven POM reference is not clear about the possible usage of extensions as part of a Maven profile, since it states you can have a build element within it, but not what of the build section.
However, the official Maven model effectively filters and provides what of the build section you can actually use within a profile section. And indeed extensions is not there.
However, what are Maven extensions? Build/Lifecycle enhancement, but also (and essentially): a library added to the runtime classpath of the Maven build, which participates to the build, but it is not packaged with the final artifact.
Hence, in such a scenario (if you need to have extensions in profile or have a profile to change/add an extension) you could use the following trick:
Have an harmless extension as default extension of your build (where harmless means whatever library which could be part of your build classpath and essentially not affect it at all)
Have properties defining the GAV coordinates (GroupId, ArtifactId, Version) of this extension
Have a profile which overrides these properties with the desired (useful) extension
As an example, given the following sample POM:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample</groupId>
<artifactId>project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<extension.groupId>junit</extension.groupId>
<extension.artifactId>junit</extension.artifactId>
<extension.version>4.11</extension.version>
</properties>
<build>
<extensions>
<extension>
<groupId>${extension.groupId}</groupId>
<artifactId>${extension.artifactId}</artifactId>
<version>${extension.version}</version>
</extension>
</extensions>
</build>
<profiles>
<profile>
<id>customize-extension</id>
<properties>
<extension.groupId>junit</extension.groupId>
<extension.artifactId>junit</extension.artifactId>
<extension.version>4.12</extension.version>
</properties>
</profile>
</profiles>
</project>
The default build (without the customize-extension profile activated), would use the default defined properties and as such add junit as build extension: this is harmless (although it may create conflicts with another junit version of your build, so make sure you use the same version of use an even more harmless library for that).
You can check Maven will pick it up by running a really first build phase, just to check information in our case, and enable the debug flag:
mvn initialize -X
And checking as part of the build log:
[DEBUG] Populating class realm extension>junit:junit:4.11
[DEBUG] Included: junit:junit:jar:4.11
Now let's use our trick: let's add (change) a build extension via profile:
mvn initialize -X -Pcustomize-extension
And as part of our build log we would have:
[DEBUG] Populating class realm extension>junit:junit:4.12
[DEBUG] Included: junit:junit:jar:4.12
Bingo. Maven picked up a different extension (in this case, a different version, the 4.12) and we succeeded on changing (or actually adding a meaningful) build extension via profile.

Just a crazy idea: use modules
Define a parent pom like this:
<groupId>org.example</groupId>
<artifactId>my-parent</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<profiles>
<profile>
<id>use-pom1</id>
<modules>
<module>pom1</module>
</modules>
</profile>
<profile>
<id>use-pom2</id>
<modules>
<module>pom2</module>
</modules>
</profile>
</profiles>
Define the desired extensions on pom1 and pom2.

I think the solution is here http://maven.apache.org/guides/mini/guide-using-extensions.html
Define a build section where extensions are defined and then into the profile set the attribute true ( like in the second profile shown below )
<build>
<extensions>
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
<version>2.9</version>
</extension>
</extensions>
</build>
<profiles>
<profile>
<id>create-default</id>
<activation>
<activeByDefault>true</activeByDefault>
<property>
<name>build</name>
<value>full</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>create-core</id>
<activation>
<property>
<name>build</name>
<value>full</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<extensions>true</extensions>
<version>2.6</version>
<configuration>
<finalName>import-station-core-${project.version}</finalName>
</configuration>
<executions>
<execution>
<id>make-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

Related

Jenkins cannot build maven with [0.0.1,)

I'm trying to run the build of a project, which has as dependence, a jar of my own.
Code dependency:
<profile>
<id>local-profile</id>
<activation>
<activeByDefault>true</activeByDefault>
<property>
<name>ambient</name>
<value>local</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>com.enterprise</groupId>
<artifactId>enterpriseUtil</artifactId>
<version>[0.0.1,)</version>
</dependency>
</dependencies>
<build>
<finalName>${finalName}</finalName>
<resources>
<resource>
<directory>src/main/resources_local</directory>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin-version}</version><!--$NO-MVN-MAN-VER$ -->
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin-version}</version><!--$NO-MVN-MAN-VER$ -->
<configuration>
<attachClasses>true</attachClasses>
<warSourceExcludes>META-INF/context.xml</warSourceExcludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
The strangest thing is that a local build succeeds, even if I exclude the dependency from my .m2, and download from my nexus
The error:
No versions available for com.enterprise:enterpriseUtil:jar:[0.0.1,) within specified range -> [Help 1]

Maven web resource filtering SNAPSHOT version

Using Maven, I'd like to update a parameter in a file to either "true" or "false" based on if the version number is a SNAPSHOT or not. Currently I use the maven-war-plugin to update some other properties based on Maven properties. I've tried to use the maven properties along with the maven-release-plugin, but this seems to not work:
Maven pom.xml:
<project>
...
<properties>
<someProperty>value</somePropery>
<isSnapshot>true</isSnapshot>
</properties>
<profiles>
<profile>
<id>release</id>
<properties>
<isSnapshot>false</isSnapshot>
</properties>
</profile>
</profiles>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<webResources>
<resource>
<directory>src/main/webapp</directory>
<filtering>true</filtering>
</resource>
</webResources>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<releaseProfiles>release</releaseProfiles>
</configuration>
</plugin>
</plugins>
</build>
</project>
Running a mvn release:prepare and mvn release:perform seems to ignore the overridden property in the final war. This seems to stem from the fact that the release profile is active during the release:perform phase, but not the release:prepare phase when the war is actually built.
Is there a better way to do this or am I missing something?
Edit:
I am running this release from a project pom, which this war pom is a submodule.

Maven Plugin Surefire no accepting outputDirectory

In Maven pom tried to have a single profile only for tests and their reports. Also all test related reports should end up in a single folder per project.
Acording to the documentation this should do the trick
<profiles>
<profile>
<id>integration</id>
<activation>
<property>
<name>integration</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<excludes>
<exclude>**/*$*</exclude>
<exclude>**/*_closure*</exclude>
<exclude>**/support/**</exclude>
</excludes>
<outputDirectory>${basedir}/target/reports</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Still all reports end up in ..\target\surefire-reports. Any idea why the ouputDirectory settings doesn't work
According to the documentation you have to use the reportsDirectory instead of outputDirectory which does not exist.

optimizing maven build performance

I have a Maven web application. This is taking too much time to build(30-40 mins).I would like to reduce it to less than 10 mins. My pom.xml is as below.
<?xml version="1.0" encoding="utf-8"?>
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>se.mysite.etc.settings</groupId>
<artifactId>projects</artifactId>
<version>1.5</version>
</parent>
<groupId>se.myweb.portal</groupId>
<artifactId>myweb-se-main</artifactId>
<name>myweb-se-main</name>
<version>3.1.81-B2_forv-SNAPSHOT</version>
<packaging>pom</packaging>
<inceptionYear>2009</inceptionYear>
<properties>
<release.version>${project.version}</release.version>
<acc.version>2.3.42-TEST-MAINT-SNAPSHOT</acc.version>
<cxf.version>2.5.3</cxf.version>
<spring.version>3.0.3.RELEASE</spring.version>
<spring.security.version>2.0.4</spring.security.version>
<spring.webflow.version>2.1.1.RELEASE</spring.webflow.version>
<commonportal.version>1.9.9-SPRING3</commonportal.version>
<junit.version>4.5</junit.version>
<java.source.version>1.6</java.source.version>
<cobertura.maxmem>1024M</cobertura.maxmem>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<scm>
<connection>scm:hg:http://test1/myweb</connection>
<developerConnection>scm:hg:http://test1/myweb</developerConnection>
<tag/>
<url>http://test1/myweb</url>
</scm>
<profiles>
<profile>
<id>dev</id>
<dependencies>
<!--some dependencies-->
</dependencies>
<modules>
<module>../project1</module>
<module>../project2</module>
<module>../project3</module>
<module>../project4</module>
</modules>
</profile>
<profile>
<id>dist</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<!--some dependencies-->
</dependencies>
<modules>
<module>../project1</module>
<module>../project2</module>
<module>../project3</module>
<module>../project4</module>
<module>../project5</module>
<module>../project6</module>
</modules>
</profile>
<profile>
<id>backend</id>
<dependencies>
<!--some dependencies-->
<modules>
<module>../project3</module>
<module>../project1</module>
<module>../project2</module>
<module>../project4</module>
<module>../project9</module>
</modules>
</profile>
<profile>
<id>frontend</id>
<!--some dependencies-->
<modules>
<module>../project10</module>
<module>../project11</module>
</modules>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<forkMode>always</forkMode>
<argLine>-Xms512m -Xmx2048m -XX:MaxPermSize=2048m</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>webtest</id>
<build>
<finalName>myweb-web-test</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-XX:MaxPermSize=512m</argLine>
</configuration>
</plugin>
</plugins>
</build>
<!--some dependencies-->
<modules>
<module>../myweb-web-test</module>
</modules>
</profile>
<profile>
<id>redeploy_web_app</id>
<activation>
<property>
<name>redeployWebApp</name>
</property>
</activation>
<properties>
<user.tomcat.home>${env.DEST_DIR}</user.tomcat.home>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.6</version>
<dependencies>
<!--some dependencies-->
</dependencies>
<executions>
<execution>
<id>delete_project_artifact</id>
<phase>prepare-package</phase>
<configuration>
<tasks>
<taskdef classpathref="maven.plugin.classpath" resource="net/sf/antcontrib/antcontrib.properties"/>
<if>
<equals arg1="${project.packaging}" arg2="war"/>
<then>
<echo message="Removing ${project.artifactId}.${project.packaging} from ${user.tomcat.home}/webapps"/>
<delete dir="${user.tomcat.home}/webapps/${project.artifactId}"/>
<delete file="${user.tomcat.home}/webapps/${project.artifactId}.${project.packaging}"/>
</then>
</if>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>copy_project_artifact</id>
<phase>package</phase>
<configuration>
<tasks>
<taskdef classpathref="maven.plugin.classpath" resource="net/sf/antcontrib/antcontrib.properties"/>
<if>
<equals arg1="${project.packaging}" arg2="war"/>
<then>
<echo message="Copying ${project.build.finalName}.${project.packaging}"/>
<copy file="${project.build.directory}/${project.build.finalName}.${project.packaging}" overwrite="true" tofile="${user.tomcat.home}/webapps/${project.artifactId}.${project.packaging}"/>
</then>
</if>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<!-- General dependencies -->
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<instrumentation>
<excludes>
<exclude>se.mysite/**/Test*.class</exclude>
</excludes>
</instrumentation>
</configuration>
<executions>
<execution>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- TODO: Use UTF-8 here or not??? -->
<encoding>UTF-8</encoding>
<!-- encoding>ISO-8859-1</encoding-->
<source>${java.source.version}</source>
<target>${java.source.version}</target>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.1</version>
<configuration>
<scmCommentPrefix>II Release:</scmCommentPrefix>
</configuration>
</plugin>
</plugins>
</build>
<organization>
<name>mysite AB</name>
<url>http://www.mysite.se</url>
</organization>
</project>
My compile command is below.
mvn -U -DartifactsTarget=$DEST_DIR/lib/tpp -P dev -Dmaven.test.failure.ignore=true -Dtesting.testsToExclude=**/Test*.java -f pom.xml $* -DredeployWebApp install
It is taking almost 30 mins to build.
I am using maven 3.0.4. I explored that using the following options we can optimize the build time.
Using maven parallel processing
Using plexus compiler plugin
Using maven power shell
Please let me know if I need to any other changes to my pom.xml or any other techniques that would optimize the performance.
Optimizing the Maven build of a Java project comes down to 3 factors:
Compilation and Tests
Complexity of the Maven build
Optimizing the Maven (binary) performance
Compilation and Tests
If, for example, you have GWT in your application and you're compiling for 20 different permutations then this will be a problem if you're doing this the whole time.
There are ways to get around this by maybe only doing the full build when you need to, and otherwise limiting the build by using the draftCompile or optimizationLevel options.
The same thing applies to your tests: if you have hundreds of tests, the length of time that each test takes starts to become significant. Common ways to increase performance in tests are:
Don't use Thread.sleep(..), use mutex's and locks.
Share configuration (persistence units, mocks) across multiple tests instead of doing the setup per test.
Make it a unit test instead of an integration test, unless you really need to. Too many integration tests is a bad code smell, in any case.
Complexity of the Maven Build
If you have 10's or hundreds of modules, with a complex dependency tree, maven will need time to calculate the dependency tree. Use `dependency:analyze' to figure out whether or not there are unused dependencies and remove them.
Also, the number of plugins used in each module's build will increase the build time.
Optimizing Maven (binary) performance
I use the following options:
export MAVEN_OPTS="-Dmaven.wagon.provider.http=httpclient -Dmaven.artifact.threads=12 -Dhttp.tcp.nodelay=false -Xmx2048M -Xss256M -XX:+CMSClassUnloadingEnabled -XX:-UseGCOverheadLimit -XX:MaxPermSize=256M -T2C"
-Dmaven.wagon.provider.http=httpclient:
Changes the http connection mechanism, my theory is that the Apache HttpClient library is faster and better than the default Java HttpURLConnection class
-Dmaven.artifact.threads=12:
The number of threads used to download artifacts.
-Dhttp.tcp.nodelay=false:
Turns off Nagle's algorithm increasing performance (but also bandwidth used). This is a Wagon property.
-T2C: This was an expiremental build introduced in maven 3: the number of threads per build. See Parallel builds in Maven 3
Please feel to edit this post if you have other tips!

In maven - how to rename the output .war file based on the name of the profile in use

I have three profiles in my pom.xml for our application...
dev (for use on a developer's)
qa (for use on our internal qa server)
prod (production).
When we run our maven build all three profiles ouput a war file with the same name. I would like to output $profilename-somearbitraryname.war
Any ideas?
You've answered yourself correctly:
<profiles>
<profile>
<id>dev</id>
<properties>
<rp.build.warname>dev</rp.build.warname>
</properties>
</profile>
<profile>
<id>qa</id>
<properties>
<rp.build.warname>qa</rp.build.warname>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<rp.build.warname>prod</rp.build.warname>
</properties>
</profile>
</profiles>
but there is a simpler way to redefine WAR name:
<build>
<finalName>${rp.build.warname}-somearbitraryname</finalName>
<!-- ... -->
</build>
No maven-war-plugin is needed.
The answer was simple...
Define a property in each profile like this...
<profile>
<id>qa</id>
<properties>
<rp.build.warname>ourapp-qa</rp.build.warname>
</properties>
</profile>
Then add this to your plugins...
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<packagingExcludes>WEB-INF/web.xml</packagingExcludes>
<warName>${rp.build.warname}</warName>
</configuration>
</plugin>
In maven you must use <bundleFileName> in the <module>
You should follow this link to ensure your modules are rewritted:
http://maven.apache.org/plugins/maven-ear-plugin/examples/customizing-a-module-filename.html
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.10.1</version>
<configuration>
[...]
<modules>
<ejbModule>
<groupId>artifactGroupId</groupId>
<artifactId>artifactId</artifactId>
<bundleFileName>anotherName-1.2.3.jar</bundleFileName>
</ejbModule>
</modules>
</configuration>
</plugin>
</plugins>
</build>

Resources