Saturday, 25 May 2013

Exposing the version of your Maven built web application

Sometimes its useful to expose the version of your web application - I find it useful so vsConsole can display the version of the deployed application for each environment on the dashboard. If you build your app with Maven, you can use this code to get the version, and simply wire up a controller/rest endpoint to return it as text/plain. To expose the version of your maven built spring web application, you can use a REST controller like that shown below. Note, you won't see a valid version while running in the IDE - it'll only work when running the Maven built WAR. If you want to add the Jersey dependencies to your spring application try using the following dependency declaration.

Monday, 6 May 2013

Avoid embedding database connection information in your code

I've seen projects where the application code base contains database connection information - passwords and all, or, WAR files are rebuilt for each environment with properties substituted appropriately for the target environment.

Rather than putting database information in the application code, it makes more sense to use a JDNI data source provided by the container. This way the exact same application code is deployed to all environments, and we don't encounter any exposed passwords - since the owner of the container (in production environments the infrastructure/support team) define the data source themselves.

Database access via JNDI data source in Tomcat

In your application server you want to define a data source which points to the database server and schema of your choice. Here, I'm using the H2 database, and assuming this is the DEV Tomcat server, I point it to the DEV schema - define this resource in the Tomcat context.xml:

 <Resource name="jdbc/app1db" auth="Container" type="javax.sql.DataSource"
               maxActive="100" maxIdle="30" maxWait="10000"
               username="sa" password="" driverClassName="org.h2.Driver"
In your TST, UAT, PRD servers you define similar data sources, pointing to the appropriate schemas, all with the same name.

Your application server MUST have the database driver on its classpath, so you will want to add the appropriate driver jar to TOMCAT_HOME/lib.

Other containers such as GlassFish, WebLogic, WebSphere and JBoss will have equivalent ways of achieving this same configuration.

Now, in your application all you need to do is define the JNDI data source, which never changes:

    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:comp/env/jdbc/app1db"/>
With the database connection information encapsulated within the container, you don't need these details in the source code, you don't expose passwords to anyone and you don't need to repackage your application for each environment - deployment is simple. 

Another similar use-case is for the mail server. You may also want to expose a String which could point to a properties file or server address - this can then be referenced in your spring application context.

Below are xml snippets of a Tomcat configuration which exposes some resources and a Spring application context file that uses those resources.

Thursday, 2 May 2013

Deploying to Tomcat 7 with Maven

It's sometimes nice to be able to update a development Tomcat 7 server from Maven - this makes it simple to hook automatic deployment into a CI server or just update the dev server as a developer.

First, the Tomcat manager application needs to be installed (check Tomcat's webapps directory for the manager application) and configured with the appropriate user credentials:

Now, I needed to define the server admin credentials in my maven settings (~/.m2/settings.xml):

Then, I updated the POM to configure the maven tomcat plugin:

Now, using 'mvn tomcat7:redeploy' lets me update the dev server.

Note however, on Windows you may have some problems with undeploying the application - after an undeploy command, some jars may be left over in the webapps/appname directory. When you try to redeploy your app you'll see an error containing "cannot invoke tomcat manager fail - unable to delete...".

To work around this, you can change the TOMCAT_HOME/conf/context.xml to include the 'antiJARLocking' attribute like so:
<Context antiJARLocking="true">
The documentation points out though that this will impact start up times of applications.

In my case, I noticed problems when doing a redeploy to Tomcat - most likely unrelated to Maven and/or the maven tomcat plugin and more to do with PermGen (I saw perm gen OutOfMemory: PermGen space errors in the tomcat7-stderr logs, and the Tomcat process was consuming 100% cpu). Adding the following switches to the Tomcat JVM settings seems to have fixed it for now:
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled -XX:PermSize=64m -XX:MaxPermSize=128m -Xmx992M
 (In this instance, I'm running Tomcat 7 as a Windows service on JDK7 with a 50MB WAR file).