Create two profiles and use them in Java class - maven

How can use two Maven profiles with for example <id = env>that will contain id, password, account# that will pass those values into .java class and in Maven command line I just run something like:
mvn test ${env=stage}
and it will take id, password, account# from profile that I choose. Or may be there are other way to do that not using profiles?

In general, you can declare properties in Maven. You can set them in different ways:
Command line:
mvn ... -DmyProperty=myValue
In a <properties> section in a POM or in settings.xml (in the latter in a <profile> section only) like:
<profile>
<id>stage</id>
<properties>
<user>you</user>
<password>your</password>
<accountNo>42</accountNo>
</properties>
<profile>
Activate profiles on the command line with:
mvn ... -Pstage ...
or use one of the other activation mechanisms described in the doc Maven, Introduction to Build Profiles.
Use properties in your POM with ${user}, ${password}, ${accountNo}.

Related

Could i use maven profile to swith between different value application.properties

I have application-prod.yml application-dev.yml, and application.properties which containing just one line code like below
spring.profiles.active=dev
for maven production build, it should use spring.profiles.active=prod , then it will build with application-prod.yml, for development build, it should use spring.profiles.active=dev, then maven
will use application-dev.yml to build
could I use pom.xml's different profile to do switch for this value switch in applicaiton.properties?
You can use a Maven property for this, reference it in your yml file (with ${...}) and filter the resource (i.e. the yml file) with the maven resources plugin.
It seems that what you're after is "externalized configuration". According to the excellent 12factor guidelines, it is best not to keep such config inside your code-repository.
Refer to the relevant section in the Spring Boot manual to see which options you have (and there are many). What it comes down to is that you provide your application.yml/properties file on the filesystem and your application will read it from there, rather than from the classpath.
Also, note that spring-profiles are not meant to be used to distinguish between development environments, but rather to put the application in different functional modes (e.g. to enable or disable specific features).
If you want the content of your properties file changed at build time, then you can use Maven filtering. Maven filtering allows to replace a placeholder in your properties (or yaml) file by values from Maven properties.
Assuming you have a property in your POM called targetEnv, which might have either the value dev or prod (depending on the active Maven profile), then you can refer it in your properties file (or yaml file) by using the following syntax :
spring.profiles.active=#targetEnv#
However, if you want to follow Spring Boot recommandations, it is better to enable and disable the Spring profiles by the means of environment variables in your target environment. For instance, you can use an environment variable spring.profiles.active with the desired value and it will override the value in your properties file.
You need to define a custom property in each of your Maven profiles and set their values to match with suffixes of corresponding properties files that you want to load with a particular profile.
<profile>
<id>dev</id>
<properties>
<activatedProperties>dev</activatedProperties>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>release</id>
<properties>
<activatedProperties>release</activatedProperties>
</properties>
</profile>
Next, in the build section of the same file, configure filtering for the Resources Plugin. That will allow you to insert properties defined in the previous step into any file in the resources directory, which is the subsequent step.
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
…
</build>
Finally, add the following line to the application.properties.
spring.profiles.active=#activatedProperties#
For more details, please see spring boot properties per maven profile
For official guide to load from external configLoad from external Config

Goal specific javax.net.ssl.trustStore

I've got a Maven project for which i use org.apache.tomcat.maven:tomcat6-maven-plugin to deploy to a remote Tomcat.
This tomcat is configured so that i need to specify:
-Djavax.net.ssl.trustStore=mykeystore.jks -Djavax.net.ssl.trustStorePassword=mypassword
My problem is that by doing so, I can't download dependencies anymore from remote repositories through my company proxy as it tries to establish a secure connection using this truststore and it fails...
I'm looking for a way to connect to both ends (maven repo and my remote tomcat) without having to set/unset my MAVEN_OPTS variable every time...
I've seen that I can have a <configuration /> element in my settings.xml, but I can't find what to put in it.
Thanks...
Using different profiles with maven:
Define the active profiles in your pom (you can also define profiles in settings.xml but I think this should work for your case):
<profiles>
<profile>
<id>TOMCAT_DEPLOY</id>
<activation>
// Rules to active the profile
<activeByDefault>true</activeByDefault>
</activation>
<properties>
</properties>
// Add rest of profile specific configuration
</profile>
</profiles>
For executing maven with an specific profile, basically you have a list of active profiles and you can execute one of them according to different triggers:
A profile can be triggered/activated in several ways:
Explicitly, Through Maven settings, Based on environment variables OS settings or based on some Present or missing files
Please, read this link where you can have all information about profiles and how activate them for any execution

Is it possible to use a maven property to activate a profile based upon a file?

I would like to download the JACOB dlls when they're not in my local repository.
As a consequence, I have those two profiles
<profile>
<id>use-jacob-dll</id>
<activation>
<file>
<exists>${settings.localRepository}/com/hynnet/jacob/1.18/jacob-1.18-x64.dll</exists>
</file>
</activation>
<dependencies>
<dependency>
<groupId>${jacob.groupId}</groupId>
<artifactId>jacob</artifactId>
<type>dll</type>
<classifier>x64</classifier>
<version>${jacob.version}</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>download-jacob-dll</id>
<activation>
<file>
<missing>${settings.localRepository}/com/hynnet/jacob/1.18/jacob-1.18-x64.dll</missing>
</file>
</activation>
But, even when download-jacob-dll has accomplished its goal, a call to mvn help:active-profiles indicates the following
The following profiles are active:
- tests-for-eclipse (source: com.capgemini.admdt:kpitv:1.2.4-SNAPSHOT)
- download-jacob-dll (source: com.capgemini.admdt:kpitv:1.2.4-SNAPSHOT)
I suspect it is due to the fact that I use the ${settings.localRepository} in my activation property.
Question: Is it the cause of the failure? And if so, how can I activate my profile only when dependency is missing ?
Is it possible to use a maven property to activate a profile based upon a file?
No, as stated by the Maven documentation on profiles
Supported variables are system properties like ${user.home} and environment variables like ${env.HOME}. Please note that properties and values defined in the POM itself are not available for interpolation here, e.g. the above example activator cannot use ${project.build.directory} but needs to hard-code the path target.
However, from the POM documentation we also get that
a given filename may activate the profile by the existence of a file, or if it is missing. NOTE: interpolation for this element is limited to ${basedir}, System properties and request properties.
Hence, indeed no Maven properties except ${basedir} are allowed.
And if so, how can I activate my profile only when dependency is missing?
By hardcoded path to the dependency or concerned file would be a solution, even though not portable like the solution you meant.
Alternatively you could use a request property as mentioned by the documentation above, thus need to configure the activation with a property which then must be passed from the command line (more portable but more fragile as well):
<activation>
<file>
<missing>${path}/com/hynnet/jacob/1.18/jacob-1.18-x64.dll</missing>
</file>
</activation>
Then invoke maven as following:
mvn clean install -Dpath=path_to_local_rep
The solution above could be reasonable in some contexts like Jenkins jobs.

how is the properties set in this pom.xml?

This is the snippet of pom.xml from my project.
<properties>
<Port>2020</Port>
<threads>20</threads>
<test.suite />
<test.suite.path />
<useTag />
<useTestCase />
<args>-Dthreads=${threads} -Dtest.suite.path=${test.suite.path} -Dappenv=${test.app.env} -Dtest.suite=${test.suite} -DuseTag=${useTag} -DuseTestCase=${useTestCase}</args>
</properties>
when maven build is made, I am wondering how the variables test.suite, test.suite.path, useTestCase are set? I do not see it anywhere in the pom. but the Jenkins build is working fine and it has substituted values for these placeholders.
what is the use of using this kind of property setting. <variable/> rather than <variable>...</variable> ?
To say exactly how those properties are set in your case we need to see the entire pom structure including the parent pom(s) as well as your Jenkins job configuration.
However, I know of two ways that these properties can be set:
Through a profile in one of your parent poms
Through system properties when maven is invoked
My guess is that you have a profile in one of your parents that sets these properties. Something like this:
<profile>
<id>jenkins</id>
<properties>
<test.suite>...</test.suite>
...
</properties>
</profile>
And that this profile is activated on your Jenkins server. Look here for information how the profile can be activated.
The other option is that these properties are specified as system properties when maven is invoked from Jenkins.
As for why <variable/> is used over <variable></variable> it is a matter of taste. <variable/> means the same thing as <variable></variable> in XML.

Inherited profiles in Maven

I have the following profiles in my parent pom
<profile>
<id>P1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>P2</id>
<activation>
<file>
<exists>${project.basedir}/src/main/whatever</exists>
</file>
</activation>
</profile>
Why P1 is active in child POM and P2 isn't?
The directory ${project.basedir}/src/main/whatever, does not exist in the parent project, but exists in the child one.
Profile P2 is not activated because the path under its exists tag does not resolve to an existing path even though the directory ${project.basedir}/src/main/whatever exists. If you rewrite the property ${project.basedir} as ${basedir}, it should activate the P2 profile.
That should mean that the ${project.basedir} does not resolve to the project base directory as it should. The help:effective-pom shows that it does, though. I have reported this (MNG-5516).
Also I think that P1 will not be active if P2 is.
That is correct. Quoting the documentation for activeByDefault:
This profile (P1 in this example) will automatically be active for all builds unless another profile in the same POM is activated using one of the previously described methods. All profiles that are active by default are automatically deactivated when a profile in the POM is activated on the command line or through its activation config.
The word inherit got me confused, because the "profile inheritance" works in project aggregation but not in project inheritance.
To make things clear, I simulated this situation. Empty pom means that it is empty except for the standard model, group, artifact and version tags.
Simple scenario
Directory structure:
simple
\-pom.xml
pom content:
<profiles>
<profile>
<id>P1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>P2</id>
<activation>
<file>
<exists>${basedir}/dir/</exists>
</file>
</activation>
</profile>
</profiles>
If there is no dir directory mvn help:all-profiles outputs:
Profile Id: P1 (Active: true , Source: pom)
Profile Id: P2 (Active: false , Source: pom)
If there is dir directory mvn help:all-profiles outputs:
Profile Id: P2 (Active: true , Source: pom)
Profile Id: P1 (Active: false , Source: pom)
Project inheritance
Directory structure:
inheritance
|--child
| \-pom.xml // child pom
\-pom.xml // parent pom
Child pom is empty while parent pom has the profiles as in the simple scenario. Regardless of the existence of the inheritance/child/dir directory running mvn help:all-profiles from child directory outputs:
Profile Id: P1 (Active: false , Source: pom)
Profile Id: P2 (Active: false , Source: pom)
When running mvn help:effective-pom from child directory it shows that the profiles are indeed not inherited. It behaves as documented:
Elements in the POM that are merged are the following:
dependencies
developers and contributors
plugin lists (including reports)
plugin executions with matching ids
plugin configuration
resources
No profiles are mentioned here.
Project aggregation
Directory structure:
aggregation
|--module
| \-pom.xml // module pom
\-pom.xml // aggregator pom
Module pom is empty while aggregator pom has the profiles as in the simple scenario. If there is no aggregation/module/dir directory running mvn help:all-profiles from module directory outputs:
Profile Id: P1 (Active: true , Source: pom)
Profile Id: P2 (Active: false , Source: pom)
If there is aggregation/module/dir directory running mvn help:all-profiles from module directory outputs:
Profile Id: P2 (Active: true , Source: pom)
Profile Id: P1 (Active: false , Source: pom)
When running mvn help:effective-pom from module directory it shows that the profiles are inherited. This is not explicitly documented:
Project inheritance
If you have several Maven projects, and they all have similar configurations, you can refactor your projects by pulling out those similar configurations and making a parent project. Thus, all you have to do is to let your Maven projects inherit that parent project, and those configurations would then be applied to all of them.
Notes:
That does not apply to profiles, as it has been shown.
Runnnig a maven build from inheritance directory will run only parent build.
Project aggregation
And if you have a group of projects that are built or processed together, you can create a parent project and have that parent project declare those projects as its modules. By doing so, you'd only have to build the parent and the rest will follow.
Notes:
Runnnig a maven build from aggregation directory will run the build of each module and the aggregator (the actual order is determined by maven based on different criteria).
Conclusion
Profiles can be defined globally, per user or per project. Since the aggregated projects are built together (in the same build) some sort of profile resolution must be run to calculate the active ones. So this is the confusing part:
When projects are inherited profiles are not inherited from parent pom to child pom.
when projects are aggregated profiles are inherited from aggregator pom to module pom.
This was tested this using Maven 3.1.0. and 3.0.5.
Just to clarify on this, Maven Profiles are in fact inherited. For a reference to another SO question see: Inheriting Maven profiles. I have successfully inherited profiles in my project and no additional work is needed.
As for the original question, you have a variable defined in the exists element. According to the documentation:
As of Maven 2.0.9, the tags and could be
interpolated. Supported variables are system properties like
${user.home} and environment variables like ${env.HOME}. Please note
that properties and values defined in the POM itself are not available
for interpolation here, e.g. the above example activator cannot use
${project.build.directory} but needs to hard-code the path target.
So, what I get from that is that ${project.basedir} cannot be used and will not work. If however you have it defined as an environment variable, it will work.
One caveat that I found is that in the parent pom <plugin-management> should be used to configure the plugins. However, for within the profiles I find that <plugin-management> must not be used in order for the profile-specific configuration to work.
The problem is not with inheritance but with interpolation (i.e. which values are supported for ${...}): file-based profile activation only supports limited interpolation: see http://maven.apache.org/pom.html#Activation
So ${project.basedir} isn't supported but only ${basedir} (and system properties).
For more details, you can have a look at the model building algorithm: http://maven.apache.org/ref/3.2.1/maven-model-builder/
Full model interpolation happens after profile activation: so even if your effective pom shows interpolated value for ${project.basedir}, the value isn't calculated when profile activation happens.
In Maven 3.2.2, there are multiple enhancements regarding this: documentation in http://jira.codehaus.org/browse/MNG-5590, warning at runtime in http://jira.codehaus.org/browse/MNG-5608 and better effective pom result http://jira.codehaus.org/browse/MNG-5612
In general, Maven profiles are not inherited (see http://jira.codehaus.org/browse/MNG-5127 for a discussion and links to blog posts that might be useful). I've had success doing something like this:
<!-- Parent -->
<profile>
<id>P2</id>
<activation>
<file>
<exists>${project.basedir}/src/main/whatever</exists>
</file>
</activation>
<!-- all the things you want to define for the child POMs -->
</profile>
<!-- Child -->
<!-- Include only the activation block, which must match parent's exactly -->
<!-- Whatever is in the parent will be inherited -->
<profile>
<id>P2</id>
<activation>
<file>
<exists>${project.basedir}/src/main/whatever</exists>
</file>
</activation>
</profile>
Also I think that P1 will not be active if P2 is. This is because <activeByDefault> is true for P1. The element name is a little misleading in my opinion. "Active by default" implies "always active" when it really means "active only if no other profile in this POM is active."
The above discovered using Maven 3.0.x.
Remove the P2 from the second profile that has the file based activation.
<profiles>
<profile>
<id>P1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>P2</id>
<activation>
<file>
<exists>${basedir}/dir/</exists>
</file>
</activation>
</profile>
</profiles>

Resources