How to configure maven jar plugin to exclude properties on profile - maven

I have this configuration in my pom
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<configuration>
<excludes>
<exclude>**/logging/*</exclude>
<exclude>**/config/*</exclude>
</excludes>
</configuration>
</plugin>
I use profiles to handle different behaviour from local environment to production environment.
Is it possible not activate the exclusions when executing mvn install with local profile?
I tried to set a blank properties on local environment like this
but the plugin complains.

This is a workaround solution, maybe a better one exists. I think the easiest you could do is to let your DEV environment free from any config of the jar plugin. And then place your PROD config in a dedicated profile :
<profiles>
<profile>
<id>PROD</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<configuration>
<excludes>
<exclude>**/logging/*</exclude>
<exclude>**/config/*</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
When you need to build the production jar, launch :
mvn clean install -PPROD

Are the logging and config files resources for testing only? If yes, put them in ${basedir}/src/test/resources. They'll be on the classpath for your tests but will not end up in the final jar, and you won't need specific jar plugin config.

The best workaround I found is to use an invalid value to filter on when executing on DEV environment.
<profiles>
<profile>
<id>env-local</id>
<activation>
<property>
<name>env</name>
<value>local</value>
</property>
</activation>
<properties>
<jndi.iban0>cont0Data</jndi.iban0>
<config.file.path>classpath:config</config.file.path>
<logging.file.path>classpath:logging</logging.file.path>
<exclude.logging>none</exclude.logging>
<exclude.config>none</exclude.config>
</properties>
</profile>
</profiles>

Related

Running multiple Maven profiles + Cucumber JVM

Since the Cucumber JVM does not support Profiles, I'm trying to use Maven instead. What I want to do is activate a certain subset of tests based on its tag, and point it to the correct environment.
Here is my feature file:
Feature: Validate data
#dev
Scenario: Dev environment
Given dev data
#qa
Scenario: Test environment
Given test data
Here is my pom.xml:
...
<profiles>
<profile>
<id>dev</id>
<properties>
<cucumber.options>
--tags #dev
</cucumber.options>
<base.url>http://dev.base.url.to.application</base.url>
</properties>
</profile>
<profile>
<id>qa</id>
<properties>
<cucumber.options>
--tags #qa
</cucumber.options>
<base.url>http://qa.base.url.to.application</base.url>
</properties>
</profile>
<profile>
<id>firefox</id>
<properties>
<driver.class>org.openqa.selenium.firefox.FirefoxDriver</driver.class>
</properties>
</profile>
<profile>
<id>chrome</id>
<properties>
<driver.class>org.openqa.selenium.chrome.ChromeDriver</driver.class>
</properties>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<encoding>UTF-8</encoding>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<cucumber.options>${cucumber.options}</cucumber.options>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</project>
When I try to run multiple profiles at once, i.e., using the following command:
mvn test -P dev,qa
Only one of my tests gets executed. If I run it without profiles, both tests get executed (the qa profile in specific). Have I configured my profiles improperly? Or is it an issue with my tags?
In the dev profile you set the cucumber.options property to --tags #dev. In the qa profile you set the cucumber.options property to --tags #qa. So when combining these profiles with -P dev,qa the qa profile will override the value of the cucucumber.options set by the dev profile.
And because this is a single element combine.children=merge will not work and there is no good way to merge these profiles.

In maven, how to override plugin configuration in settings.xml

I want to override a particular plugin configuration that's defined in the pom.xml. I don't want to modify the pom.xml for various reasons. Is there a way to define a config attribute for that plugin in settings.xml that override corresponding pom.xml plugin config?
In the below example, you'll notice that the plugin xx-plugin is defined in profile1 in pom.xml. In my settings.xml I've already defined profile2 to override property prop1 from pom.xml. But how to override config3. I apologize if this is a silly question. I am a little new to maven.
This is what my pom.xml looks like:
<profile>
<id>profile1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>com.xx.yyy</groupId>
<artifactId>xx-plugin</artifactId>
<executions>
<execution>
<id>xx-install</id>
<phase>install</phase>
<goals>
<goal>xx-install</goal>
</goals>
<configuration>
<config1>AAA</config1>
<config2>BBB</config2>
<config3>CCC</config3> <!-- I want to override this with value DDD -->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
This is what my settings.xml looks like:
<profile>
<id>profile2</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<prop1>overriden-value</prop1> <!-- This works -->
</properties>
<!-- Somehow override config3 here -->
<!-- <config3>DDD</config3> -->
</profile>
AFAIK you can only override properties with settings.xml profiles. You'd have to change your plugin's configuration to use a property instead of a fixed value:
<!-- define your property -->
<properties>
<prop1>CCC</prop1>
</properties>
<profile>
<id>profile1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>com.xx.yyy</groupId>
<artifactId>xx-plugin</artifactId>
<executions>
<execution>
<id>xx-install</id>
<phase>install</phase>
<goals>
<goal>xx-install</goal>
</goals>
<configuration>
<config1>AAA</config1>
<config2>BBB</config2>
<config3>${prop1}</config3> <!-- I want to override this with value DDD -->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
Remember that profiles with activeByDefault set to true will get deactivated if any other profile gets activated in your build invocation. See http://maven.apache.org/guides/introduction/introduction-to-profiles.html
If you do not want to change the pom.xml for a plugin you can set the configuration as JVM parameter when running maven as stated in the Generic Configuration chapter of the Maven Guide to Configuring Plugins.
Example:
mvn my-plugin:my-goal -Dplugin.property=ABC
Example for the wildfly plugin (this is where I needed it and did not want to change the pom.xml of a demo project when deploying to a server group in a domain context):
mvn clean install wildfly:deploy -Dwildfly.serverGroups=<server-group-name>
The maven documentation also states that most plugins define help goals to explain users how to configure them.
Exaple for the wildfly plugin:
mvn wildfly:help -Dgoal=deploy -Ddetail

Pass VM argument for Database configuration -D for Junit test using Maven

While executing Junit test cases on Eclipse we are passing VM arguments for DB configuration by -D, but while uploading the same Junit test cases to Sonar by Maven it's not working as no VM argument is set.
I have tried to pass arguments by MAVEN_OPTS on MVN.sh but it's not working.
Instead of setting your DB configuration on the command line with system properties, consider setting them with profiles.
Add something like this to your pom.xml:
<profiles>
<profile>
<id>sonar</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.3</version>
<configuration>
<systemPropertyVariables>
<db.user>foo</db.user>
<db.password>bar</db.password>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Documentation:
http://maven.apache.org/guides/introduction/introduction-to-profiles.html
http://maven.apache.org/plugins/maven-surefire-plugin/examples/system-properties.html

How to configure maven to use different log4j.properties files in different environments

I want to be able to use different log4j configuration for different environments.
In my development environment, I want to use log4j.properties (A). But when I build in Maven for the production environment, I want to use log4j.properties (B).
Please tell me how to configure this in my pom.xml?
You can use profiles to achieve the desired behavior:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>log4j</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>output_directory</outputDirectory>
<resources>
<resource>${log4j.file}</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<log4j.file>path_to_file_A</log4j.file>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<log4j.file>path_to_file_B</log4j.file>
</properties>
</profile>
</profiles>
1. in your project add 3 folders :
Your Project\src\main\resources\
\A > log4j.properties
\B > log4j.properties
\Default > log4j.properties
2. in pom.xml
<properties>
<param>Default</param>
</properties>
<build>
<resources>
<resource>
<directory>src/main/resources/${param}</directory>
</resource>
</resources>
</build>
3.
- if : mvn clean install : classpath => log4j.properties(Default)
- if : mvn clean install -Dparam=A : classpath => log4j.properties(A)
- if : mvn clean install -Dparam=B : classpath => log4j.properties(B)
> much better than using profiles is more extensible without touching the pom
You don't need the maven-resources-plugin if you have a simple environment.
In this example, log4j.properties B is the file you use for production and is in the directory src/main/java and log4j.properties A is the file you use for development and is in the directory /Users/junger/.m2/.
In your pom.xml:
<properties>
<log4j.properties.directory>src/main/java</log4j.properties.directory>
</properties>
<build>
<resources>
<resource>
<directory>${log4j.properties.directory}</directory>
<includes>
<include>log4j.properties</include>
</includes>
</resource>
</resources>
</build>
Now, in your /Users/junger/.m2/settings.xml (create one if it doesn't exist):
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<log4j.properties.directory>/Users/devuser/.m2/</log4j.properties.directory>
</properties>
</profile>
</profile>
By using this method, each developer can have a different log4j.properties directory and you keep your pom.xml clean.
Simplest way for me,
Define a system variable ENV and set its value _dev for your development env.
Where you refer this file use like this log4j${ENV}.properties
So,
In production it simply use log4j.xml and for your dev log4j_dev.xml
In order to prevent problems it would be better to create also ENV variable for production as _pro so for production log4j_pro.xml, for dev log4j_dev.xml will be used.
I believe that relying on different files than copying resource is better practice.
There is a very simple solution good for small projects with jar packaging (I haven't tested it on war packaged projects). The only disadvantage is that you have to duplicate all resources, but if your only resource is log4j.properties this is not a problem.
If you have a directory tree like this:
...
You should have the following pom:
<build>
<finalName>${project.artifactId}</finalName>
<sourceDirectory>src/</sourceDirectory>
<resources>
<resource>
<directory>${resources.path}</directory>
</resource>
</resources>
</build>
<profiles>
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<resources.path>resources/prod</resources.path>
</properties>
</profile>
<profile>
<id>dev</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<resources.path>resources/dev</resources.path>
</properties>
</profile>
</profiles>
Then when you use dev profile log4j.properties from resources/dev is used. When you use any other profile or no profile at all then log4j.properties from resources/prod is used. So your *.jar should look like this:
Of course if you have different resources location, for example main/java/resources/..., you should specify it instead of resources/...
To some extent you can reference environment variables inside a log4j.properties to add environment dependent behavior.
e.g.
log4j.rootLogger=${rootLoggerLevel}, ${appender}

GlassFish 3 + Maven + remote deploy

I couldn't find any clear answer about how to deploy simple Maven based project to remote GlassFish server via maven like
mvn package xxx:deploy
I think only cargo plugin supports GlassFish 3. Right?
I've problems at configuration side.
Any sample remote GlassFish deployment will be great. Cargo is not a must, if others are support remote GlassFish then we can also use it too.
In case you want to only use maven-glassfish-plugin (let say version 2.1), you can do a remote deploy by specifying the "host" parameter. Below is an example where configurations are setup in maven settings.xml and an plugin loads them using a profile:
In settings.xml define a profile:
<profile>
<id>production-config</id>
<properties>
<glassfish.glassfishDirectory>/var/local/glassfish/</glassfish.glassfishDirectory>
<glassfish.user>admin</glassfish.user>
<glassfish.adminPassword>adminadmin</glassfish.adminPassword>
<glassfish.domain.name>prd-domain</glassfish.domain.name>
<glassfish.domain.host>NAMEOFYOURREMOTEHOST</glassfish.domain.host>
<glassfish.domain.adminPort>10161</glassfish.domain.adminPort>
.
.
</properties>
</profile>
Next put this profile in your active profiles:
<activeProfiles>
<activeProfile>production-config</activeProfile>
</activeProfiles>
In your maven project pom.xml, create a profile and add the maven-glassfish-plugin in your list of profiles:
<profile>
<id>production</id>
<activation>
<activeByDefault>false</activeByDefault>
<os>
<arch>x86</arch>
<family>linux</family>
</os>
<property>
<name>profile</name>
<value>production</value>
</property>
<file>
<exists>
${glassfish.glassfishDirectory}/domains/${glassfish.domain.name}/config/domain.passwords
</exists>
</file>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.glassfish.maven.plugin</groupId>
<artifactId>maven-glassfish-plugin</artifactId>
<configuration>
<terse>true</terse>
<echo>true</echo>
<debug>true</debug>
<glassfishDirectory>${glassfish.glassfishDirectory}</glassfishDirectory>
<user>${glassfish.user}</user>
<adminPassword>${glassfish.adminPassword}</adminPassword>
<domain>
<name>${glassfish.domain.name}</name>
<host>${glassfish.domain.host}</host>
<adminPort>${glassfish.domain.adminPort}</adminPort>
</domain>
<components>
<component>
<name>${project.artifactId}</name>
<artifact>${project.build.directory}/${project.build.finalName}.war</artifact>
</component>
</components>
</configuration>
<executions>
<execution>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
This should do the trick. You can run this profile using maven : mvn glassfish:deploy -P production or just mvn deploy -P production (since we have added the goal deploy inside the executions part of plugin)
Using the model above you can create different profile per environment (dev, acc, tst, prd), and use different settings. For instance you can create a developer profile where a local glassfish is being used to deploy and run unit/integration tests on it.
Common mistake people make is to mix up the settings for the machine from where you are doing the remote deployment with the host where deployment is to be installed. glassfishDirectory is place from where you are running the deployment plugin from. As a result of mistake plugin just hangs, doing nothing and just waiting giving the impression that something is happening. Another mistake is to specify a password file instead of a password for a remote deploy which will also result in nothing.
As far as I know and could find around, only Cargo delivers (or deploys, in this case).
This is an example tested as working on a Maven OSGi WAR project:
<build>
<plugins>
...
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.1.2</version>
<configuration>
<container>
<containerId>glassfish3x</containerId>
<type>remote</type>
</container>
<configuration>
<type>runtime</type>
<properties>
<cargo.hostname>myhostname</cargo.hostname>
<cargo.remote.username>myusername</cargo.remote.username>
<cargo.remote.password>mypassword</cargo.remote.password>
</properties>
</configuration>
</configuration>
<dependencies>
<dependency>
<groupId>org.glassfish.deployment</groupId>
<artifactId>deployment-client</artifactId>
<version>3.2-b06</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
As you can see, the trick lies in the deployment-client dependency.
For the sake of completeness, you then just mvn package cargo:deploy and Bob's your uncle.

Resources