How should i separate production and dev connection settings - java

I have an application which I am working on which will eventually of course need a development and production environment. The key is the database connection settings which obviously I want to separate.
What is the correct process for separating these setting so that I don't deploy to production with the dev setting and visa versa so i don't deploy to dev with the production settings.
I was thinking potentially a properties file which is prefixed with prod and dev but I am not sure how robust that approach might be?
Thanks
To extend the questions a little further
Based on one of the comments i have looked in to the maven solution, as we are using open shift - there is already some pre-generated pom.xml code which looks as follows;
<profiles>
<profile>
<!-- When built in OpenShift the openshift profile will be used when invoking
mvn. -->
<!-- Use this profile for any OpenShift specific customization your app
will need. -->
<!-- By default that is to put the resulting archive into the deployments
folder. -->
<!-- http://maven.apache.org/guides/mini/guide-building-for-different-environments.html -->
<id>openshift</id>
<build>
<finalName>TomcatHotOrNot</finalName>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<outputDirectory>deployments</outputDirectory>
<warName>TomcatHotOrNot</warName>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
So based on the answer provided Using Maven for multiple deployment environment (production/development) - how would this need to be adapted to follow the solution there?
Thanks

Related

Can't access Maven properties with Spring

Hello I am new to Maven in general so I'd like to apologise in advance if I get things wrong.
I have a Maven project with spring in which I also access a MySQL database.often the MySQL database is not accessible so I use a local database for testing, I swap between the two by changing the active profile.
I set up the profiles by putting this in my POM.xml:
<profiles>
<profile>
<id>Local</id>
<dependencies>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.3</version>
<classifier>jdk5</classifier>
</dependency>
</dependencies>
<properties>
<jdbc.url>jdbc:hsqldb:file:databaseName</jdbc.url>
<jdbc.username>a</jdbc.username>
<jdbc.password></jdbc.password>
<jdbc.driver>org.hsqldb.jdbcDriver</jdbc.driver>
</properties>
</profile>
<profile>
<id>MySQL</id>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
</dependencies>
<properties>
<jdbc.url>jdbc:mysql://mysql.website.ac.uk:3306</jdbc.url>
<jdbc.username>user</jdbc.username>
<jdbc.password>1234</jdbc.password>
<jdbc.driver>com.mysql.jdbc.Driver</jdbc.driver>
</properties>
</profile>
</profiles>
When I try to access the properties variables through for example ${jdbc.url} they are not converted to the actual values as defined in the profile and I get errors. I suspect it might have something to do with Spring Boot.
Apart from the specific sprint-boot problem I think you are missing the maven resource filtering configuration.
Maven properties are not automatically propagated to Spring unless you put them into a separate properties files which must then be managed by spring (Usually via PropertyPlaceholderConfigurer).
But without maven filtering turned on properties are not automatically resolved, usually if you do not have many items under tour src/resources folder you can just enable filtering globally with
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
And your properties file should replace placeholders with maven values.
If, on the other hand in you have several resources in src/main/resources, you should check documentation more deeply to avoid binary files corruption
I think that spring boot is simply wrapping up all the process automatically in your application properties files.
You specified properties in profile, so there is a workaround. Annotations such as #Value("${name}") are referencing to externalized configuration, e.g. from application.yml. You should use this file to load properties you want. #property_name# loads property from your maven profile.
jdbc:
url: #jdbc.url#
username: #jdbc.username#
and so on...
Then these properties will be accessible in your code.
Maven properties are not put into environment variables or JVM variables that you can access by Spring.
However you can usually instruct maven plugin to do it for you.
For example configuration of maven-failsafe-plugin I use to set up test db:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<includes>**/*Integration.java</includes>
<environmentVariables>
<mysql.version>${mysql.version}</mysql.version>
<test.mysql.username>${test.mysql.username}</test.mysql.username>
<test.mysql.password>${test.mysql.password}</test.mysql.password>
<test.mysql.port>${test.mysql.port}</test.mysql.port>
<test.mysql.db>${test.mysql.db}</test.mysql.db>
</environmentVariables>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>

Converting Eclipse dynamic web project to maven project with modules

so I just started a new project at work where I've gotten some code, really strange code...
So the project structure was as follows:
simple-java-project-1 ---> eclipse java project which holds some database-connectors
simple-java-project-2 ---> holds the logic of converting, formatting etc of the data, uses the connectors from project-1
dynamic-web-project --> just gets the jars from project1 and project2 and offer's a websocket api to send this data etc.
I would like to convert this mess to a well structured maven project. So I created a master maven project with this pom:
......bla bla bla....
<modules>
<module>the-connectors</module>
<module>the-logic</module>
<module>the-dynamic-web-module</module>
</modules>
<dependencies>.....</dependencies/>
And the modules as well. I added the dependencies needed to them.
So now the hard part I didn't get : How can I achive that the whole project is deployed to the local tomcat and runs?
The web.xml and /WEB-INF/ stuff is in the "the-dynamic-web-module" module for now,...
Any ideas or hints?Thanks in advance.
You should add the tomcat7-maven-plugin to your the-dynamic-web-module:
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/</path>
<uriEncoding>UTF-8</uriEncoding>
<systemProperties>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>
After building and installing the 2 other modules (mvn install), go to the-dynamic-web-module and launch mvn tomcat7:run. Then with your browser, go to localhost:8080/ and you should get your app.

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

Best Approach to Set Up External Dependency in Maven

I hope I'm explaining this as accurately as possible, and I want to know if I set up the maven dependencies correctly, or if there's a better way to do it.
Most of my development team's projects rely on a home-grown jar that is deployed at server class loader. The reason for this jar to reside at this level is to the ease of updating the jar at one place without repackaging each project that's using it, assuming changes made to it are backward-compatible.
I develop my web apps against Jetty in my local development. So, in order for the web apps to work locally, I set up the dependencies this way:-
<dependencies>
<!-- Configuring external jar dependency -->
<dependency>
<groupId>com.test.app</groupId>
<artifactId>app-jar</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${env.EXTERNAL_JAR}</systemPath>
</dependency>
...
</dependencies>
<build>
<plugins>
<!-- Configuring Jetty -->
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.26</version>
<configuration>
<contextPath>/${project.parent.artifactId}</contextPath>
<jettyEnvXml>${env.JETTY_ENV_XML}</jettyEnvXml>
<scanIntervalSeconds>1</scanIntervalSeconds>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>7777</port>
</connector>
</connectors>
<webAppConfig>
<extraClasspath>${env.EXTERNAL_JAR}</extraClasspath>
</webAppConfig>
</configuration>
</plugin>
...
</plugins>
</build>
In this approach, I set up an environment variable that points to the external jar path, and reference it in my pom.xml as ${env.EXTERNAL_JAR}.
After doing some reading, it seems like using "system" scope is considered a bad practice. So, I installed this external jar in Nexus and change the scope to "provided":-
<dependency>
<groupId>com.test.app</groupId>
<artifactId>app-jar</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
This allows me to compile my project properly, but I'm not sure if it is even possible for me to get rid of the "EXTERNAL_JAR" environment variable completely because it's still needed by Jetty for the runtime to work properly. My take is using "provided" scope is a little tedious and more work, because I now need to remember to update the jar in Nexus when it is modified AND I still need to update the jar located at the path pointed by the environment variable.
Is there a way for me to expose the external jar to Jetty through maven dependencies, yet not being packaged into the project when the war file is built?
What are you advice on this? Should I just stick with "system" scope so that I just need to update the jar at one place, or should I use "provided" scope? Or if there's even a better way to do this?
Thanks much.
You should be able to add dependencies to the jetty plugin. And then I have the provided scope for the project itself.
http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin
as in
<project>
...
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
<systemProperties>
<systemProperty>
<name>logback.configurationFile</name>
<value>./src/etc/logback.xml</value>
</systemProperty>
</systemProperties>
</configuration>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.15</version>
</dependency>
</dependencies>
</plugin>
...
<project>
The best thing to do is setup an external repository with your dependency, and add it to your pom.
<repositories>
<repository>
<id>my-repo</id>
<name>my-repo</name>
<url>http://your.repo.url</url>
</repository>
</repositories>
and then you can add your dependency as
<dependency>
<groupId>com.test.app</groupId>
<artifactId>app-jar</artifactId>
<version>1.0</version>
</dependency>
I approve of provided. Provided means - download the dependency for compile-time, but I expect to see it on classpath on the application server.
I did not realize you care only for your local development, so the following would be useful if you were running Jetty on an external server:
Maven will let you deploy a file to a server using the Wagon plugin. So a part of your build process could be pushing the proper .jar into your Jetty server. That way you would not have to do it manually. I would prefer this solution to running a local Maven repository on the Jetty server as suggested by #Paul.
If you wanted to be super-clever (usually a bad idea), you might try to set up a repository directly on the machine with Jetty, that would serve the jar directly from your Jetty install. That way you would not have to modify Nexus, the jars would be only at one place. You can even set up Nexus to mirror another repository, so it could pick things up automatically.
It is a bad practice to modify .jar contents and keep the same Maven coordinates. So this "clever" approach would not work that great anyway.

Maven: how to copy artifact to specific directory?

The "install" goal copies the artifact to the target directory and to the local repository.
How can I tell Maven to copy it also to a given directory (like the deploy directory of JBoss for example).
The goal copy of maven-dependency-plugin does what you want, see the example.
It is however not a good idea to copy anything outside your target directory (or ${project.build.directory} to be precise) - especially if such action is attached to a build phase, because it introduces unexpected side-effects of the build, and sometimes even loss of reproducibility.
As #Andreas_D notes, there is a better alternative for JBoss deployment purpose; similarly for deploying to other appservers.
According to http://maven.apache.org/plugins/maven-dependency-plugin/examples/copying-artifacts.html you can copy the just built artifact to a specific directory:
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<executions>
<execution>
<id>copy-installed</id>
<phase>install</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<type>${project.packaging}</type>
</artifactItem>
</artifactItems>
<outputDirectory>some-other-place</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
</project>
If you want to copy file to a webserver (local or distant) you can use Maven upload plugin :
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-upload-plugin</artifactId>
<version>1.1</version>
<configuration>
<resourceSrc>
${project.build.directory}/${project.build.finalName}.${project.packaging}
</resourceSrc>
<resourceDest>${jboss.deployDir}</resourceDest>
<serverId>${jboss.host}</serverId>
<url>${jboss.deployUrl}</url>
</configuration>
</plugin>
And to configure parameters in a smart way, I use maven profiles :
<profiles>
<!-- local deployment -->
<profile>
<id>developpement</id>
<properties>
<jboss.host>localhost</jboss.host>
<jboss.deployDir>appli/jboss-4.0.4.GA/server/default/deploy/</jboss.deployDir>
<jboss.deployUrl>file://C:/</jboss.deployUrl>
</properties>
</profile>
<!-- distant deployment -->
<profile>
<id>validation</id>
<properties>
<jboss.host>ENV_val</jboss.host>
<jboss.deployDir>/home/envval/jboss/server/default/deploy/</jboss.deployDir>
<jboss.deployUrl>scp://PROJECT_LAN_HOST</jboss.deployUrl>
</properties>
</profile>
</profiles>
I've created an "ant launcher", to use it by clicking under Eclipse ant view :
<target name="copy war to JBoss local" description="Copy war to local JBoss">
<maven goal="upload:upload" options="-Pdeveloppement" />
</target>
But you can simply run it on a command line :
mvn upload:upload -Pdeveloppement
By the way, for distant deployment, you may need a login password for scp to work. You have to add them to you Maven settings.xml file :
<settings>
...
<servers>
<server>
<id>ENV_val</id>
<username>login</username>
<password>password</password>
</server>
</servers>
...
</settings>
The best approach would be to use a plugin which will actually deploy your application, such as cargo or jboss-maven plugin (credit to #Andreas_D for that one).
This would be a better approach to using a copy or generic upload tool since deploying is what you are actually trying to do.
With the cargo plugin you have the option to deploy to a variety of running servers. We took this approach to test locally in jetty using the jetty plugin during the build and had a profile to deploy to tomcat on demand via cargo.
Note: If you have your target server (JBOSS) installed locally on the dev box as well then you can also use cargo to start/stop your server during your build process as well. The downside of this approach is that you will need it to reference it's location in the pom file, so either all devs install it in the same location or a system property that defines where it is located (similar to JAVA_HOME).

Categories