Extend maven cargo plugins jvmargs - maven

I have a maven project which extends an existing parent project (It's the "standard product" from which my product will be a "Customized product").
The parent declares a org.codehaus.cargo / cargo-maven2-plugin and passes it some VM args under configuration / cargo.jvmargs. Like this:
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.4.18</version>
<configuration>
<container>
<containerId>tomcat8x</containerId>
[...]
<dependencies>
[...]
</dependencies>
</container>
<configuration>
<properties>
<cargo.jvmargs>-ArgA -ArgB -ArgC</cargo.jvmargs>
</properties>
<configfiles>
[...]
</configfiles>
<files>
[...]
</files>
</configuration>
</configuration>
</plugin>
Now in my custom project, I want to extend these jvm args with one more argument (Let's say -ArgD), so that the args are -ArgA -ArgB -ArgC -ArgD. I don't want to override the entire plugin only to do this one little change.
I know that I can specify this: cargo:run -Dcargo.jvmargs="-ArgD" but the problem here is: All other args (ArgA, ArgB, ArgC) get overridden/removed, only ArgD will remain. What I need is something like cargo:run -Dcargo.jvmargs="current_cargo.jvmargs + -ArgD".
Is this possible somehow?

The cleanest possibility would be to move jvmargs in parent pom to maven property. Then in your custom project you would be able combine jvmargs using maven property with your custom values. For example:
Parent pom:
<properties>
<cargo.base.jvmargs>-ArgA -ArgB -ArgC</cargo.base.jvmargs>
</properties>
[...]
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.5.0</version>
<configuration>
[...]
<configuration>
<properties>
<cargo.jvmargs>${cargo.base.jvmargs}</cargo.jvmargs>
</properties>
[...]
</configuration>
</configuration>
</plugin>
Your custom pom:
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<configuration>
[...]
<configuration>
<properties>
<cargo.jvmargs>${cargo.base.jvmargs} -ArgD</cargo.jvmargs>
</properties>
[...]
</configuration>
</configuration>
</plugin>
If there isn't possibility to modify parent pom you may use Cargo property cargo.start.jvmargs (see this page). This property add java arguments to container when it is started.

Related

Parent POM is not flattened when deployed to Nexus

I have a multi-module Maven project where the project version is set via the revision variable.
<groupId>pricing</groupId>
<artifactId>pricing-backend-pom</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<properties>
<revision>3.0.7</revision>
</properties>
<modules>
<module>pricing-backend-war</module>
<module>pricing-backend-model</module>
<module>pricing-backend-client</module>
</modules>
<build>
<plugins>
<!-- flatten before deploy. removes $revision -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.2.7</version>
<configuration>
</configuration>
<executions>
<!-- enable flattening -->
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<!-- ensure proper cleanup -->
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
During the Gitlab build, the project is deployed to a Nexus repository. Each module and the parent appear in Nexus but only the modules appear to be flattened. The module POMs each contain <version>3.0.7</version> but the parent POM still contains <version>${revision}</version>.
I find it difficult to understand why the parent is deployed differently to the modules. I have checked the build logs but cannot see any indication that the parent is handled in a different way.
The parent POM taken from Nexus:
<groupId>pricing</groupId>
<artifactId>pricing-backend-pom</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<properties>
<revision>3.0.7</revision>
...
A module POM:
<groupId>pricing</groupId>
<artifactId>pricing-backend-client</artifactId>
<version>3.0.7</version>
<dependencies>
...
The build applies the required version:
$ echo New version= ${MAVEN_VERSION}
New version= -Drevision=3.0.7-SNAPSHOT
$ mvn $MAVEN_CLI_OPTS ${MAVEN_VERSION} deploy -DskipTests
The pom file to be installed can be explicitly set:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.4</version>
<configuration>
<pomFile>.flattened-pom.xml</pomFile>
</configuration>
</plugin>
Above, flatten-maven-plugin has been previously invoked to produce .flattened-pom.xml
If you do a test by adding -Drevision=<someVersion> to the command line, does that produce correct results in Nexus?
I suspect it will.
Properties are interpolated very early in the process. When the command first runs, ${revision} is undefined, so Maven leaves it as-is. The flatten then calculates ${revision}, but that only applies from the time the plugin runs and later.
You can try researching "late binding" properties (they start with '#' instead of '$') but I'm not sure if those work in top level fields like the GAV coords.

OSGi Code coverage - Jacoco + Easymock

I'm currently working on a Java OSGi project(based on Apache felix runtime) with a project setup like the one below:
pkg | parent maven project
persistence | real plugin
persistence.tests | test plugin (indeed a Fragment project with fragment host the persistence plugin above )
... others like the ones above
Basically I use maven + tycho to manage the lifecycle of the project. the whole stuff flows through a continuos integration pipeline which involves jenkins for building, testing, deploying and forwarding code analysis to a Sonarqube server. Just like mentioned above, tests are implemented through Fragment projects pointing OSGi bundles to be tested. In these tests I make use of EasyMock library to generate mocked OSGi bundles.
In order to make Sonarqube aware of tests coverage I had to add Jacoco (maven plugin) into my sets of tools. After a few adjustments to the configuration of my parent pom.xml file I ended up with something that is working partially: jacoco code coverage is only working for classes included in test plugins (the fragment projects). As you may guess - though better than nothing - this result is far from being useful. I need to evalute test coverage on real OSGi bundles. After some googling I understood that the problem could be linked to the usage of EasyMock library, since this alterate original classes during execution causing a mismatch between test classes and real classes. According to my understanding, to solve I need to disable jacoco on-the-fly instrumentation and use offline instrumentation instead.
Nevertheless I'm not able to understand :
what does this really means
how to do it
Can someone kindly revert on this ?
This is the maven command i'm running to generate jacoco report
mvn -f com.mycompany.osgi.myproject.pkg/pom.xml clean test
Below my current parent pom.xml
<?xml version="1.0" encoding="UTF-8"?><project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.osgi</groupId>
<artifactId>com.mycompany.osgi.myproject.pkg</artifactId>
<packaging>pom</packaging>
<version>1.0.0</version>
<properties>
<tycho.version>1.0.0</tycho.version>
<surefire.version>2.16</surefire.version>
<main.basedir>${project.basedir}</main.basedir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jacoco.version>0.7.9</jacoco.version>
<!-- Sonar-JaCoCo properties -->
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.junit.reportPaths>${project.basedir}/target/surefire-reports</sonar.junit.reportPaths>
<sonar.jacoco.reportPaths>${project.basedir}/target/jacoco.exec</sonar.jacoco.reportPaths>
</properties>
<modules>
<module>../com.mycompany.osgi.myproject.core.persistence</module>
<module>../com.mycompany.osgi.myproject.core.persistence.tests</module>
</modules>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-compiler-plugin</artifactId>
<version>${tycho.version}</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-maven-plugin</artifactId>
<version>${tycho.version}</version>
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire.version}</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>${surefire.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>test</id>
<phase>test</phase>
<configuration>
<testClassesDirectory>${project.build.outputDirectory}</testClassesDirectory>
</configuration>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
<repositories>
...
</repositories>
<distributionManagement>
...
</distributionManagement>
As suggested by #Godin, my problems were solved using the following jacoco plugin configurations
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<configuration>
<dataFile>../com.mycompany.myproject.pkg/target/jacoco.exec</dataFile>
<destFile>../com.mycompany.myproject.pkg/target/jacoco.exec</destFile>
<outputDirectory>../com.mycompany.myproject.pkg/target/site/jacoco</outputDirectory>
</configuration>
</plugin>
and this project configuration to instruct sonarqube to read expected resources
<properties>
...
<!-- Sonar-JaCoCo properties -->
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.junit.reportPaths>com.mycompany.myproject.pkg/target/surefire-reports</sonar.junit.reportPaths>
<sonar.jacoco.reportPaths>com.mycompany.myproject.pkg/target/jacoco.exec</sonar.jacoco.reportPaths>
</properties>

Duplication in maven: are profiles additive to project, or do they replace declared items?

Provided you have the following defined in your POM.xml:
<project>
<!-- ... -->
<build>
<plugins>
<plugin>
<artifactId>plugin-X</artifactId>
<!-- plugin config -->
</plugin>
<plugins>
</build>
<profiles>
<profile>
<id>foo</id>
<build>
<plugins>
<plugin>
<artifactId>plugin-X</artifactId>
<!-- plugin config -->
</plugin>
<plugins>
</build>
<profile>
</profiles>
</project>
If the plugin config for plugin-X is exactly the same for profile foo as it is for a build without a selected profile, do you have to redeclare the plugin at all on the profile level? If so, do you also have to redeclare all config settings for it?
If you declared plugin-Y in project.profile.build.plugins instead of plugin-X (but left it declared on the project level), which plugins would be run when you run mvn -P foo? Only plugin-Y, or also plugin-X?
More generally speaking, are profiles additive to what is declared on the project level, or do they override it? (If they are additive, how do you "remove" entities that were declared on a project level when you run a build profile and don't want them for that specific profile?)
I know profile configuration gets inherited from parent pom files ("from either the build/plugins or pluginManagement sections of the parent") with options "merge", "append", and "override". I think what I really want to know is: how does maven behave when the same/similar information is defined on the project and profile levels in the same pom file...
This isn't a full answer, but another piece of the puzzle - in addition to my earlier comments, and maven's Guide to Configuring Plug-ins.
Given the following pom.xml file:
</profiles>
<properties>
<foo>main</foo>
<bar>main</bar>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>validate</phase>
<configuration>
<target>
<echo>${foo}</echo>
<echo>${bar}</echo>
<echo>${baz}</echo>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>p</id>
<properties>
<bar>prof</bar>
<baz>prof</baz>
</properties>
</profile>
</profiles>
</project>
When I run mvn validate, I get the following output:
[echo] main
[echo] main
[echo] ${baz}
Running mvn validate -P p however yields:
[echo] main
[echo] prof
[echo] prof
That means that properties at least are merged, appending new items and replacing those that are redefined.
Also, if I add another plugin to the profile (such as surefire), it will execute when running the profile with mvn <phase> -P p, so the profile inherits antrun and adds surefire. Plugin re-definitions however replace the original; adding
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>validate</phase>
<configuration>
<target>
<echo>Tada!</echo>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
only prints Tada!, but no longer the original antrun output (even when changing the new addition's phase to initialize. Adding <inherited>true</inherited> to any of the two plugin definitions doesn't make a difference. The behaviour might be plugin-specific, though.

Define different value per profile for same Maven property

I'm facing a problem with maven property per profiles. I have two profiles, each one has the same property 'prop.key' with different values. When I call mvn clean package -PA -PB or mvn clean package -PB -PA both are using the same value 'B-1.0-SNAPSHOT'. I'm using maven 3.0.4.
Below my POM :
<?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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test.module</groupId>
<artifactId>test-module</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<prop.key>UNKNOWN</prop.key>
</properties>
<profiles>
<profile>
<id>A</id>
<properties>
<prop.key>A-${project.version}</prop.key>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<id>A</id>
<phase>package</phase>
<configuration>
<tasks name="a" description="a-desc">
<echo message="RUN A = ${prop.key}" level="info"/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>B</id>
<properties>
<prop.key>B-${project.version}</prop.key>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<id>B</id>
<phase>package</phase>
<configuration>
<tasks name="b" description="b-desc">
<echo message="RUN B = ${prop.key}" level="info"/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
I have found 'similar topic' but with opposite result!
Is it a bug or a feature of maven?
You can write
mvn package -PA,B
for short.
The result is the same:
[echo] RUN A = B-1.0-SNAPSHOT and
[echo] RUN B = B-1.0-SNAPSHOT
This is the correct behaviour of maven.
One property can only have one specific value per run. You can overwrite a "default value" with a version in a profile. But if you redefine it in two profiles and activate both, one of the profiles "wins".
It is not possible to have one value per profile for one and the same property. Profiles do not have their own variable scope. Properties are always global.
I would think you get this behavior because last parameter for profile gets picked.
Try
mvn clean package -PA,B
See Maven introduction to profiles.
Profiles can be explicitly specified using the -P CLI option.
This option takes an argument that is a comma-delimited list of
profile-ids to use. When this option is specified, no profiles other
than those specified in the option argument will be activated.
When you run mvn package -PA,B, maven will read both profiles A and B, and the properties from later one in the pom.xml file will take precedence (B is defined below A in pom.xml), result in <prop.key>B-${project.version}</prop.key> will be used.

Rename profile activated dependency when building executable JAR

I am fairly new to working with Maven to build my Java projects, and have run into a situation I don't know how to handle.
I have a Java application that has 3 dependencies, let's call them a, b, and c. However, c will be a different artifact depending on the platform we are building on, so I've used profiles to achieve this. Here is a snippet from my pom.xml:
<profiles>
<profile>
<id>win32</id>
<activation>
<os>
<family>windows</family>
<arch>x86</arch>
</os>
</activation>
<dependencies>
<dependency>
<groupId>com.seanbright</groupId>
<artifactId>c-win32-x86</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>win64</id>
<activation>
<os>
<family>windows</family>
<arch>amd64</arch>
</os>
</activation>
<dependencies>
<dependency>
<groupId>com.seanbright</groupId>
<artifactId>c-win32-x86_64</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</profile>
</profiles>
The a and b artifacts are listed as dependencies at the POM level as they are platform agnostic and aren't activated along with the profile. They aren't shown here for the sake of brevity.
Now I want to build an executable JAR of my project, and include a, b, and c in a lib/ directory along side the generated JAR from my code, so I would end up with something like this:
target/my-project-1.0.0.jar
target/lib/a-1.0.0.jar
target/lib/b-1.0.0.jar
target/lib/c-1.0.0.jar
The manifest in my-project-1.0.0.jar will have the appropriate classpath so that it can be double clicked on and the application will launch. I use the dependency:copy-dependencies and jar:jar goals to make all of this work:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>copy-dependencies</id>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<mainClass>com.seanbright.myproject.Launch</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
And... it works. The only problem, is that c is copied to the lib/ directory (and added to the Class-Path in the manifest) as c-win32-x86-1.0.0.jar or c-win32-x86_64-1.0.0.jar depending on the active profile, and I want it to end up as c-1.0.0.jar instead.
Using dependency:copy with destFileName instead of dependency:copy-dependencies results in the correct filename, but the entry in the Class-Path still refers to the "fully qualified" artifact name (i.e. lib/c-win32-x86-1.0.0.jar).
Am I going about this the wrong way? Is there an easier way to accomplish what I am trying to do?
The Set Up The Classpath:Altering The Classpath: Using a Custom Classpath Format told us as the following: -
At times, you may have dependency archives in a custom format within your own archive, one that doesn't conform to any of the above classpath layouts. If you wish to define a custom layout for dependency archives within your archive's manifest classpath, try using the <classpathLayoutType> element with a value of 'custom', along with the <customClasspathLayout> element, like this:
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathLayoutType>custom</classpathLayoutType>
<customClasspathLayout>WEB-INF/lib/$${artifact.groupIdPath}/$${artifact.artifactId}-$${artifact.version}$${dashClassifier?}.$${artifact.extension}</customClasspathLayout>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
...
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
...
</project>
This classpath layout is a little more involved than the previous examples. To understand how the value of the <customClasspathLayout> configuration is interpreted, it's useful to understand the rules applied when resolving expressions within the value:
If present, trim off the prefix 'artifact.' from the expression.
Attempt to resolve the expression as a reference to the Artifact using reflection (eg. 'artifactId' becomes a reference to the method 'getArtifactId()').
Attempt to resolve the expression as a reference to the ArtifactHandler of the current Artifact, again using reflection (eg. 'extension' becomes a reference to the method 'getExtension()').
Attempt to resolve the expression as a key in the special-case Properties instance, which contains the following mappings:
'dashClassifier': If the Artifact has a classifier, this will be '- $artifact.classifier', otherwise this is an empty string.
'dashClassifier?': This is a synonym of 'dashClassifier'.
'groupIdPath': This is the equivalent of '$artifact.groupId', with all '.'characters replaced by '/'.
The manifest classpath produced using the above configuration would look like this:
Class-Path: WEB-INF/lib/org/codehaus/plexus/plexus-utils-1.1.jar WEB-INF/lib/commons-lang/commons-lang-2.1.jar
I hope this may help.

Resources