David is a systems architect who has been developing software professionally since 1991. He started programming in Java way back with Java 1.0 developing desktop applications and applets. Since 2001 he has been developing enterprise applications using both Java standards and open source solutions. David is the author of "Building SOA-Based Composite Applications using NetBeans 6" and "Seam 2.x Web Development". David is a DZone MVB and is not an employee of DZone and has posted 23 posts at DZone. You can read more from them at their website. View Full User Profile

Single Spring Application Deployment for both Local and CloudFoundry.com Servers

04.28.2011
| 8611 views |
  • submit to reddit

In my previous post I showed how it’s possible, using Spring 3.0, to deploy a database application to CloudFoundry.com and what changes are needed for a CloudFoundry.com datasource.  In this post, I’m going to show how a Spring 3.1 application can be configured at runtime to use either a local MySQL database or a CloudFoundry.com MySQL database thus allowing a single deployable Spring application to be deployed either locally or on CloudFoundry.com.

Deploying a Spring application to CloudFoundry.com does not mandate the use of Spring 3.1, however Spring 3.1 makes the process much easier due to the new profile features. So, first off, we must upgrade to Spring 3.1

Upgrading to Spring 3.1

To upgrade a Spring STS application to use Spring 3.1 is an easy procedure. In the project’s pom.xml file, we first need to change the version number of Spring to 3.1.0.M1. I say it’s easy with a STS application as everything else (for example, Spring’s Milestone Maven repository) is already preconfigured in the pom.xml file.

<properties>
<org.springframework-version>3.1.0.M1</org.springframework-version>
</properties>

If you’re not using Maven, you can download Spring 3.1 M1 from the Community Download page.

Having upgraded the version in Maven, we need to change the namespaces for any application context files. This is as straightforward as changing schema locations to be xxx-3.1.xsd instead of xxx-3.0.xsd

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">

Upgrading to Spring 3.1.M1 will unfortunately have some side effects within STS. After upgrading, you may see that some lines within application context files are flagged with errors such as:

Error occured processing XML 'org/springframework/core/convert/support/ArrayToCollectionConverter'. See Error Log for more details

This is because STS (v2.6) does not currently fully support Spring 3.1 due to some API changes in 3.1.  Support for Spring 3.1 can be tracked on SpringSource’s Jira issue #1655.

Configuring Bean Definition Profiles

After configuring an application to use Spring 3.1, we can start using the new profiles feature to specify both a cloud datasource and a local datasource.

<beans xmlns=http://www.springframework.org/schema/beans …

<beans profile="default">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}" />
</beans>
<beans profile="cloud">
<cloud:data-source id="dataSource" />
</beans>
</beans>

In this XML fragment, we can see that there are embedded <beans /> elements inside the main <beans /> element.  This is a new feature of Spring 3.1 that allows different configurations to be easily specified within one configuration file. Here we’ve defined a bean called dataSource as a JDBC datasource and as a CloudFoundry.com datasource.  The profile attribute allows us to specify which profile the bean is to be instantiated in.  So, in the “default” profile, i.e. a local profile where development and testing is most likely to be performed, a JDBC datasource is defined.  The “cloud” profile specifies a datasource for CloudFoundry.com.  A bean profile can be set to cover multiple profiles, but in this example, the dataSource bean is either a local JDBC datasource or a CloudFoundry.com datasource and can never be defined in both cases.

For a detailed description of Spring’s bean definition profiles, check out Chris Beams blog post.

Choosing a Profile at Runtime

The final stage of changing an application to use the bean definition profiles defined above is to add a class that implements the org.springframework.context.ApplicationContextInitializer interface.  This interface allows the spring container to be customised before it in initialized. In our instance, we can hook into this and, depending on the environment, set the active profile to be the “default”, local JDBC datasource, or the “cloud” CloudFoundry.com datasource.

public class Initializer implements

ApplicationContextInitializer<ConfigurableWebApplicationContext> {

protected final Log logger = LogFactory.getLog(getClass());

public void initialize(ConfigurableWebApplicationContext ctx) {
ConfigurableEnvironment environment = ctx.getEnvironment();

ApplicationInstanceInfo instanceInfo = new CloudEnvironment()
.getInstanceInfo();

if (instanceInfo == null) {
// We are running locally.
logger.info("Setting default profile.");
environment.setActiveProfiles("default");
} else {
// We are running in the cloud.
logger.info("Setting cloud profile.");
environment.setActiveProfiles("cloud");
}
}
}
 

In this class, we attempt to get the instanceInfo of the CloudEnvironment class.  If this returns null, the application is not running on CloudFoundry.com and the local “default” bean definition profile is set as the active profile.  If, however, a valid instance is returned, then the app is running on CloudFoundry.com and the “cloud” bean definition profile is set as the active profile.

That’s all there is to it and now the application can be developed and deployed as easily locally as it can on CloudFoundry.com

The sample code used in this post can be found on GitHib at https://github.com/daveys/spring-todo

From http://www.davidsalter.co.uk/1/post/2011/04/single-spring-application-deployment-for-both-local-and-cloudfoundrycom-servers.html

 

Published at DZone with permission of David Salter, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags: