Maven property referencing a list - maven

I am working with a (custom, internally developed, details do not matter here) Maven plugin which takes a list of names, like this:
<configuration>
<names>
<name>Alice</name>
<name>Bob</name>
<name>Joe</name>
<name>Sally</name>
</names>
...
The list is hard-coded in the POM file.
I'd like to have something a little more dynamic, so that I can use a user-defined variable to specify a single name. I can do it this way:
mvn clean package -Dname=Bob
<configuration>
<names>
<name>${name}</name>
</names>
The problem is that the only way I've found so far to do this is to have two profiles with duplicate plugin configurations: one with the pre-defined list, and one with the single user-defined value:
<profiles>
<profile>
<id>default</id>
...
<configuration>
<names>
<name>Alice</name>
<name>Bob</name>
<name>Joe</name>
<name>Sally</name>
</names>
...
</profile>
<profile>
<id>single-value</id>
<activation>
<property>
<name>name</name>
</property>
</activation>
...
<configuration>
<names>
<name>${name}</name>
</names>
...
</profile>
</profiles>
This works, but my problem with it is that both profiles have almost completely identical configurations (and they are rather lengthy configurations as well) for this plugin, except for the list of names.
What I'd like to do is have a Maven property contain a list, rather than a single value. Something like this:
<project>
<properties>
<names>
<name>bob</name>
</names>
</properties>
...
So that my single-value profile will simple redefine the names property. But of course, this doesn't work so easily: the code sample above produces a non-parseable POM error.
Is there any way to do what I want with some other Maven plugin, or trick?

Use a parameter which takes a comma-separated value. In your code, translate this String to a List of Strings. You should really wonder if you want this to be set by commandline or if it is sufficient enough to do it only in the plugin configuration. The latter is preferred of course.
Just as a small example: see http://maven.apache.org/plugins/maven-site-plugin/site-mojo.html#locales

Related

How to negate a property in pom.xml?

I'd like to negate a boolean property as defined in pom.xml.
Meaning, given a property ${doSomething} I need to pass <skip> to a plugin where the value of <skip> should be the negation of ${doSomething}.
If ${doSomething} is false, then I want to skip. If it is true, then I don't want to skip. Any ideas?
Clarification: I am not talking about using the negation of a property for profile activation. I just want to pass the negation of a boolean into a plugin.
Apart from profile activation, Maven doesn't have a boolean logic implemented. So if want to negate a property to pass it to a plugin, you'll need to do it yourself. It is a bit clumsy, but you could use the build-helper-maven-plugin:bsh-property goal, which enables to write a BeanShell script and export variables defined in it as Maven properties:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.12</version>
<executions>
<execution>
<id>negate-prop</id>
<phase>initialize</phase>
<goals>
<goal>bsh-property</goal>
</goals>
<configuration>
<source>dontDoSomething = !${doSomething};</source>
<properties>
<property>dontDoSomething</property>
</properties>
</configuration>
</execution>
</executions>
</plugin>
You can't override the property, but you can define a new one containing the result of the negation; in the example above, it is dontDoSomething. This is ran in the initialize phase so that the rest of the plugins can use it as a parameter, with the standard ${dontDoSomething}.
This could be enhanced to have a default value for dontDoSomething if doSomething doesn't exist.
<source>
value = project.getProperties().getProperty("doSomething");
dontDoSomething = value == null ? false : !Boolean.parseBoolean(value);
</source>
BeanShell is a scripting language that looks very much like Java and you can use existing Java methods. In the above, the property "doSomething" is retrieved from the project's properties (project is injected by the plugin at evaluation-time with the current Maven project); it it isn't defined, we return false, otherwise, we negate the value.
If doSomething is specifically a system property, it could also be possible to (ab)use the profile activation feature and have 2 profiles: one activated by a property being true and setting another to false, and a second profile doing the inverse:
<profiles>
<profile>
<id>pro-1</id>
<activation>
<property>
<name>doSomething</name>
<value>!false</value>
</property>
</activation>
<properties>
<dontDoSomething>false</dontDoSomething>
</properties>
</profile>
<profile>
<id>pro-2</id>
<activation>
<property>
<name>doSomething</name>
<value>false</value>
</property>
</activation>
<properties>
<dontDoSomething>true</dontDoSomething>
</properties>
</profile>
</profiles>
This won't work if doSomething is a Maven property set in the <properties> tag for example. It will need to be passed as a system property with mvn -DdoSomething=true|false. The corresponding profile will be activated according to the value of the system property, which will define the dontDoSomething property to its inverse. If the property isn't defined, pro-1 will be active, setting dontDoSomething to the default value of false. All of this is quite ugly though...
I don't know the exact answer but I think you could try the following to invert the properties value (from http://maven.apache.org/guides/introduction/introduction-to-profiles.html). Declare another property where you invert the value of the first property:
<property>
<name>dontDoSomething</name>
<value>!${doSomething}</value>
</property>

CATALINA_HOME and Maven + LOG4J

I have this line in log4j:
log4j.appender.FILE.File=${catalina.home}/logs/debug.log
Works perfectly when I run the project from IntelliJ.
But when I try to run a TestNG test (from maven) it fails:
log4j:ERROR setFile(null,true) call failed.
java.io.FileNotFoundException: /logs/debug.log (No such file or directory)
I could hardcode the path and all will be good. But I don't want that solution since I can deploy on various systems where ${catalina.home} is in different place.
I develop on a mac and deploy on freebsd and centos. Tomcat is in different places all the time. I could use /var/log/myapp.log but ...
Is any way to define a common variable (available in IntelliJ and when I run the maven test) with the log file path?
Please try to use the Maven Profile which will be activated when the ${env.catalina.home} is not existed, together with the Maven Surefire Plugin:Using System Properties.
<profile>
<id>mock-catalina-home</id>
<activation>
<property>
<name>!env.catalina.home</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.14</version>
<configuration>
<encoding>UTF-8</encoding>
<systemProperties>
<property>
<name>catalina.home</name>
<value>PATH_TO_CATALINA_HOME</value>
</property>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>
</profile>
Please note that the PATH_TO_CATALINA_HOME can be referred by the Maven Properties as well. e.g.
<systemProperties>
<property>
<name>PATH_TO_CATALINA_HOME</name>
<value>${my.dev.catalina.home}</value>
</property>
</systemProperties>
This will help us to define the ${my.dev.catalina.home} to be various values.
I hope this may help.
In order for the log4j properties file get the correct value for ${catalina.home} when running the tests from maven, it needs to be in a file that is filtered by maven (src/main/resources is a directory for files like that). Also, the variable 'catalina.home' needs to be setup in maven. You can create a variable AKA maven property that uses an environment variable so you can define the different location for the tomcat install on each machine:
<properties>
<catalina.home>${env.catalina.home}</catalina.home>
<properties>
You can also specify the location of the log files in relation to the home directory for your user account.
In log4j this would use the following format: ${user.home}/weblogs/log4j1.log
In log4j 2, this would use the following format: ${sys:user.home}/weblogs/log4j2Rolling.log
log4j 2 can use the Java system properties, environmental variables, or Maven properties

Maven Multiproject Profile activation via property

I have a problem to activate a profile. There is a master pom with the profile:
<profile>
<id>EntityUpdater</id>
<activation>
<property>
<name>entityupdater.start</name>
<value>true</value>
</property>
</activation>
....
In my childpom (jar package) I specify the property:
<properties>
<!-- ENTITY UPDATER CONFIG -->
<entityupdater.start>true</entityupdater.start>
....
But in the build process the profile does not start.
I would be very happy if anyone could help me.
Best regards, Daniel
Unfortunately, Maven can only trigger property based profiles, if you are passing them in from the command-line as JVM args:
mvn clean package -Dentityupdater.start

Control Maven Reactor Modules with External Property File

My question is similar to this: How to exclude a module from a Maven reactor build?; however what I'd like to do is define a way of turning off-on modules based on a property. This property will be defined in an external property file we're using as our build profile.
The problem is that the property file isn't read in until the lifecycle after the Reactor is run (it appears Reactor is always run first).
Something like:
propertyfile.properties
module1.enabled = true
module2.enabled = false
module3.enabled = true
pom.xml
<profiles>
<profile>
<id>module1</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>module</name>
<value>true</value>
</property>
</activation>
</profile>
...
</profiles>

Maven: include resource file based on profile

I'm converting an Ant webapp project over to Maven. I have most of it working, but I'm stuck trying to figure out how to copy some resource files from different sources based on the profile.
I have src/main/resources/persistence-{dev, prod}.xml. One of these needs to be included in the war file as WEB-INF/classes/META-INF/persistence.xml.
I would like the dev version to be copied when the dev profile is active, and the prod version when prod is active.
Just use the maven resources plugin like so http://maven.apache.org/plugins/maven-resources-plugin/examples/include-exclude.html and have a property for the file name or extension set in a profile.
If you are not wedded to the paradigm of having 3 separate persistence.xml files and copying one or the other selectively, you can use maven profiles with filtering like this (just implemented this the other day and today came across your post):
In persistence.xml:
<property name="hibernate.show_sql" value="${hibernate.debug}" />
<property name="hibernate.format_sql" value="${hibernate.debug}" />
In pom.xml create a profile and define the variable:
<profiles>
<profile>
<id>hib-debug</id>
<properties>
<hibernate.debug>true</hibernate.debug>
</properties>
</profile>
</profiles>
define a default for when you build without specifying a profile:
<properties>
<hibernate.debug>false</hibernate.debug>
</properties>
and.... make sure you turn on resource filtering:
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
Then you build with mvn -Phib-debug and voila! Substitution is done.

Resources