Building for local and production in IntelliJ using Maven - java

I have a simple spring mvc app, using maven with intellij.
How do you go about creating seperate files for both production and development?
e.g. say I want to set a production and development mysql connection string for nhibernate?
How can I have it such that when I build it will take the correct file to use to grab configuration information? (and any advice on naming conventions for the files?)

Using an ant task is pretty straight forward for this.
First, create a couple profiles under <project> in your pom:
<profiles>
<profile>
<id>build-dev</id>
<activation>
<!-- <activeByDefault>true</activeByDefault> -->
<property>
<name>env</name>
<value>dev</value>
</property>
</activation>
<properties>
<config.name>config.dev.properties</config.name>
</properties>
</profile>
<profile>
<id>build-prod</id>
<activation>
<property>
<name>env</name>
<value>prod</value>
</property>
</activation>
<properties>
<config.name>config.prod.properties</config.name>
</properties>
</profile>
</profiles>
Then use the maven-antrun-plugin
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<delete file="${project.build.outputDirectory}/config.properties"/>
<copy file="src/main/resources/${config.name}" tofile="${project.build.outputDirectory}/config.properties"/>
<delete file="${project.build.outputDirectory}/config.dev.properties"/>
<delete file="${project.build.outputDirectory}/config.prod.properties"/>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
Now you just specify the profile you want when you run mvn. If you want a default, uncomment and place the:
<!-- <activeByDefault>true</activeByDefault> -->
section in the profile you want by default. As it is, the build will fail on the ant task if neither is specified.

There are a ton of ways to go about this.
In general, things like DB connection strings can go into property files, and replaced in the Spring XML configuration files using a PropertyPlaceholderConfigurer. One common-ish trick is to then create a custom implementation that looks for a -D startup parameter, a user name, a machine name, etc. that can be used to decide which property file to actually use.
The same trick can be used for the Spring configuration files as well by creating an implementation of an XmlWebApplicationContext (? I can never remember what to subclass) that adds/modifies the default getConfigLocations to add, say, files prefaced with a user or machine name, -D startup parameter value, and so on.
Btw, you're not using NHibernate if you're using Java, you're using Hibernate.
Edit Brian's approach is one of those "tons of ways", I just like to keep it configurable without building, i.e., dynamic based on arbitrary "local" conditions, etc. so I can swap things out really easily.

Related

what's the best way to store username/password for Ant SCP task

I need use a scp task to transfer a whole folder with many sub-folders and files. Currently I use below way:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<phase>validate</phase>
<configuration>
<tasks>
<mkdir dir="${project.build.directory}/yy" />
<scp file="user:password#host:/home/xx/yy/*" todir="${project.build.directory}/yy" trust="yes"/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-jsch</artifactId>
<version>1.7.1</version>
</dependency>
</dependencies>
</plugin>
And it also works if I hard code username and password. But I don't want to make this public in code base. So I make it store in maven-settings.xml like below:
pom.xml
<scp file="${scpUserName}:${scpUserPassword}#company.net:/home/xx/yy/*" todir="${project.build.directory}/yy" trust="yes"/>
settings.xml
<profiles>
<profile>
<id>unix</id>
<activation>
<os>
<family>unix</family>
</os>
</activation>
<properties>
<scpUserName>xxx</scpUserName>
<scpUserPassword>xxx</scpUserPassword>
</properties>
</profile>
</profiles>
But I still need make username/password public in Teamcity server so that all agent servers can build whole project successfully. I wonder if there are any better way for this?
Maven documentation explains. First create a master password
mvn --encrypt-master-password <password>
Enter the result into settings-security.xml
<settingsSecurity>
<master>the result here</master>
</settingsSecurity>
For the individual passwords, encrypt like this
mvn --encrypt-password <password>
And you can use it directly in your Maven plugin
<properties>
<scpUserName>xxx<sscpUserName>
<scpUserPassword>the result here</scpUserPassword>
</properties>
When your build server invokes Maven, you will need to supply the master password. You can do so by storing the password using a password vault or something.

Setting default arguments for Maven [duplicate]

I have a Maven pom.xml with a plugin that I want to be able to control on the command line. Everything works otherwise fine, except even after searching the net a while I can't figure out how to set a default value for my control property:
<plugin>
...
<configuration>
<param>${myProperty}</param>
</configuration>
...
</plugin>
So if I run Maven with
mvn -DmyProperty=something ...
everything's fine, but I'd like to have a specific value assigned to myProperty also without the -DmyProperty=... switch. How can this be done?
You can have the property default value defined in <build>/<properties> or in a profile like shown below. When you supply the property value on command line with -DmyProperty=anotherValue then it will override the definition from the POM. That is, all definitions of property values in the POM are set only a default value for the properties.
<profile>
...
<properties>
<myProperty>defaultValue</myProperty>
</properties>
...
<configuration>
<param>${myProperty}</param>
</configuration>
...
</profile>
Taylor L's approach works fine, but you don't need the extra profile. You can just declare property values in the POM file.
<project>
...
<properties>
<!-- Sets the location that Apache Cargo will use to install containers when they are downloaded.
Executions of the plug-in should append the container name and version to this path.
E.g. apache-tomcat-5.5.20 -->
<cargo.container.install.dir>${user.home}/.m2/cargo/containers</cargo.container.install.dir>
</properties>
</project>
You can also set properties in your user settings.xml file in the event that you want each user to be able to set their own defaults. We use this approach to hide credentials that the CI server uses for some plug-ins from regular developers.
You could use something like below:
<profile>
<id>default</id>
<properties>
<env>default</env>
<myProperty>someValue</myProperty>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
#akostadinov's solution works great for common usage... But if the desired property shall be used by reactor component during dependency resolution phase (very early in mvn pom hierarchy processing...) you should use profile "none activation" test mechanism to ensure the optional command line provided value is always prioritized regarding the value provided inside pom.xml. And this whatever deep is your pom hierarchy.
To do so, add this kind of profile in your parent pom.xml :
<profiles>
<profile>
<id>my.property</id>
<activation>
<property>
<name>!my.property</name>
</property>
</activation>
<properties>
<my.property>${an.other.property} or a_static_value</my.property>
</properties>
</profile>
</profiles>
This might work for you:
<profiles>
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugin>
<configuration>
<param>Foo</param>
</configuration>
</plugin>
</build>
...
</profile>
<profile>
<id>notdefault</id>
...
<build>
<plugin>
<configuration>
<param>${myProperty}</param>
</configuration>
</plugin>
</build>
...
</profile>
</profiles>
That way,
mvn clean will use "foo" as your default param. In cases when you need to override, use mvn -P notdefault -DmyProperty=something
I took sal's approach but flatten it a bit.
<profiles>
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugin>
<configuration>
<version>LATEST</version>
</configuration>
</plugin>
</build>
</profile>
</profiles>
Now you have 2 options:
Using default value: MVN install (all $version will be replaced with LATEST)
Using own value: MVN install -P! Default -Dversion=0.9 (all $version will be 0.9)

Use specific xml files in production vs development

We have a maven based Spring Web-Application. All the web-calls are Restful and need authentication. But for development purpose, it is a pain to do all the needful. So for the development cycle, it is preferred to not have any security.
Using a maven flag or something, how do we generate separate builds for production and development?
All the security related stuff are in web.xml and applicationContext.xml. We can have 2 copies (one for development and the other for production). In the maven build, what is the simplest way to include the necessary files and omit others.
PS: I have seen examples of doing above using assembly plugin. I do not need all that but just a simple way to do it. I am using maven-war-plugin to generate war file.
Use profiles. You define them in your pom.xml (see below) and then when you build you include them. For command line this is simply
mvn -P <profile> <target>
most IDE's provide a way to set a profile.
pom.xml:
<properties>
<!-- default -->
<webXmlPath>src\main\webapp\WEB-INF\web-test.xml</webXmlPath>
</properties>
<profiles>
<profile>
<id>Production</id>
<properties>
<webXmlPath>src\main\webapp\WEB-INF\web.xml</webXmlPath>
</properties>
<build>
<finalName>${artifactId}</finalName>
</build>
</profile>
<profile>
<id>Accept</id>
<properties>
<webXmlPath>src\main\webapp\WEB-INF\web-accept.xml</webXmlPath>
</properties>
<build>
<finalName>${artifactId}-accept</finalName>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<webXml>${webXmlPath}</webXml>
</configuration>
</plugin>
</plugins>
</build>

Is it possible to define a Maven 3 profile (and its activation policy) in one place and reuse it later?

My build process is very complex and I need to perform a few actions when running in Windows and a few in Linux, and those actions need to be placed in many different POMs.
I know I can activate a certain profile according to the OS. But all examples I find include taking action inside the <profiles> ... </profiles> tags, which also include the activation criteria for those profiles. What I'm trying to avoid is having to declare many sections like this:
POM 1:
</profiles>
<profile>
<activation>
<os>
<family>Windows</family>
<arch>x86</arch>
</os>
</activation>
<build>
...
</build>
</profile>
...
</profiles>
Then the same when I need to do something for windows in a different POM, many times all over the place... For some profiles the activation is more extensive.
I wanted to define the activation policy in one place, then do something like:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<!-- if profile A is active -->
<source>1.6</source>
<target>1.6</target>
<!-- if profile B is active -->
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
Just configuring the plugin differently according to the active profile, without having to duplicate the plugin declaration and everything for each profile in a ton of POM files...
Also, how do I configure things in multiple places if profile A is active? Would I have to declare the tag in each POM with its activation policy all over again or is there a way to avoid all this duplication?
Any help is appreciated, I'm a bit confused and surprised how hard is to find anything beyond basic examples on the net.
You can define your global build for various profile in super-pom and inherit it in all the pom

How to read maven settings in .m2/settings.xml file from plugin

Three questions in decreasing order of importance - Links will do.
I need to read certain maven settings such as proxies, servers in my maven plugin. How do I read them from my plugin. I can read from .m2/settings.xml file but I think there must be an easier way (some API that already does it).
I see from developers cookbook there is a class org.apache.maven.project.MavenProject What dependency I need for this to be available in my plugin - I feel this would be good to have.
Is it possible to have my own properties in settings.xml say for example
<users> <user> <username>user_name1</username> <password>encrypted_password</password> </user></users>
How ?
PS: I am a beginner.
Update 1
I was able to create and read custom properties following Injecting POM Properties via Settings.xml. However I would like to have configuration similar to what cargo provides. E.g.
<servers>
<server>
<id>tomcat7_local</id>
<configuration>
<cargo.hostname>localhost</cargo.hostname>
<cargo.remote.uri>http://localhost:8080/manager/text</cargo.remote.uri>
<cargo.remote.username>my_username</cargo.remote.username>
<cargo.remote.password>my_password</cargo.remote.password>
<cargo.servlet.port>8080</cargo.servlet.port>
</configuration>
</server>
<server>
<id>tomcat6_local</id>
<configuration>
<cargo.hostname>localhost</cargo.hostname>
<cargo.remote.uri>http://localhost:8080/manager</cargo.remote.uri>
<cargo.remote.username>my_username</cargo.remote.username>
<cargo.remote.password>my_password</cargo.remote.password>
<cargo.servlet.port>8080</cargo.servlet.port>
</configuration>
</server>
</servers>
How do I achieve this. Have a kind of workaround for my 3rd problem not sure if its the right way.
Edit
Thanks Jordan002! I know I can have multiple profiles but I didn't know to use them. This way by having profiles I can set my variable's value or rather inject the value in my plugin by saying something like #Parameter(alias = "cargo.hostname")
private String hostname; But as I see, for cargo plugin all it requires is defined like below
<servers>
<server>
<id>someId</id>
<configuration>
<!-- Configurations are placed here -->
</configuration>
</servers>
Similarly, or may be not so similar as there is no configuration here
<proxies>
<proxy>
<active>true</active>
<protocol>http</protocol>
<host>My_proxy_host</host>
<port>My_proxy_port</port>
</proxy>
</proxies>
is where I can put proxy information that maven uses. Now, I don't want to redefine it inside some profiles and I don't want to parse this file to get informations.
Further, I would like do something like cargo is doing. It lets me write all the configuration inside servers and in project's pom I only have to do following
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<configuration>
<container>
<containerId>tomcat7x</containerId>
<type>remote</type>
</container>
<configuration>
<type>runtime</type>
<properties>
<cargo.server.settings>tomcat7_local</cargo.server.settings>
</properties>
</configuration>
<deployer>
<type>remote</type>
</deployer>
<deployables>
<deployable>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<type>war</type>
<properties>
<context>${project.artifactId}</context>
</properties>
</deployable>
</deployables>
</configuration>
</plugin>
And cargo picks up configurations(s) that I defined for tomcat7_local, no need to write a profile for this.
Inject the setttings component as described here http://maven.apache.org/plugin-tools/maven-plugin-tools-annotations/
Its in Maven core org.apache.maven:maven-core:3.0.5
use properties directly and not nested. e.g. http://maven.apache.org/examples/injecting-properties-via-settings.html
I'm not too familiar with the Cargo plugin, but from the documentation, it appears to be configurable as any other Maven plugin would be. What I would change from your 'Update 1' would be to make tomcat6 and tomcat7 profiles:
<profiles>
<profile>
<id>tomcat6_local</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<cargo.hostname>localhost</cargo.hostname>
<cargo.remote.uri>http://localhost:8080/manager/text</cargo.remote.uri>
<cargo.remote.username>my_username</cargo.remote.username>
<cargo.remote.password>my_password</cargo.remote.password>
<cargo.servlet.port>8080</cargo.servlet.port>
</properties>
</profile>
<profile>
<id>tomcat7_local</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<cargo.hostname>localhost</cargo.hostname>
<cargo.remote.uri>http://localhost:8080/manager</cargo.remote.uri>
<cargo.remote.username>my_username</cargo.remote.username>
<cargo.remote.password>my_password</cargo.remote.password>
<cargo.servlet.port>8080</cargo.servlet.port>
</properties>
</profile>
</profiles>
and indicate at run time which tomcat you would like to start/stop by passing in the appropriate profile:
mvn install -P tomcat6_local
Hope this helps.

Categories