December 3, 2011

Spring 3.1 + Cloud Foundry + Local Development

This post will help you build a Spring 3.1 web application using MongoDB on Cloud Foundry.  In addition to pushing to Cloud Foundry, you will also be able to develop in your local environment with a MongoDB instance.

Goals
The goals for this blog posting will be to build the application locally, then publish to your local Cloud Foundry instance.  We will utilize the Cloud Foundry runtime, and the new Spring Profiles

Setup
  1. Create an account with Cloud Foundry (https://www.cloudfoundry.com/micro)
  2. Follow instructions to setup your own Micro Cloud
    1. I use VMWare's player
    2. Verify "vmc info" that the micro cloud console matches
  3. Download MongoDB (at least version 2.0)
  4. Install and be familiar with Maven 3 (http://maven.apache.org)
  5. Familiarize yourself with Spring 3.1, Spring Data and Spring MongoDB
  6. Clone or download the source (https://github.com/mike-ensor/first-cloud-app)
  7. Run the app locally with:
    mvn clean package cargo:run -DskipTests
  8. Go to http://localhost:8080/home

Profiles
New in Spring 3.1 are the environment profiles which allow a developer to activate groups of beans based on an environment parameter.  There are several "gotchas" that I've discovered, one being an undocumented ordering for beans using profiles.

Take a look at data-services.xml.  Notice how the MongoTemplate is defined before the .  This is against my intuition because the MongoTemplate takes a reference to the MongoFactory object, which is defined below the MongoTemplate definition.

The second "gotcha" came from when and where to set the parameter to enable Spring's profiles.  The documentation and blogs do not explicitly mention that the developer must specify the profile that is active.  It was implied by the documentation that "default" was active by default, but this is not true.  In order for the default profile to be active, I added it as a system property in my cargo settings.  (as long as it is a system environment property, feel free to set it anywhere or any way you'd like).  Take a look at the pom.xml file around line 40 for the local Maven property and then around line 253 for the environment variable to be set.

Local development vs. Cloud Development
One of the main goals I had for interacting with Cloud Foundry is that I wanted a local development environment to speed up and ease development and reduce complexity with debugging.  Notice that in data-services.xml there is a "cloud" profile and a "default".  The point of the "default" profile is to have beans that are constructed when on a local environment.  You can see that there are two definitions of MongoFactory, one using Spring Data MongoDB's XML namespace and one using CloudFoundry Runtime's namespace.  I am not going to cover why these work the way they do, so if you'd like information, refer to http://blog.springsource.org/2011/04/12/cloud-foundry-for-spring-developers/ and http://blog.springsource.org/2011/11/09/using-cloud-foundry-services-with-spring-applications-part-3-the-cloud-namespace/

Pushing to Cloud Foundry
Now that you have a local running instance of the webapp, you will notice that the artifact is called "first-cloud-app.war", which you can find in the "/target" folder.  This is a problem when pushing to the Cloud Foundry instance since the name cannot contain any non-alpha characters.  Cloud Foundry's vmc tool is built from the VCAP open source project that is responsible for the open source PaaS services.  Another PaaS service includes App Fog, which allows you to basically use the same commands, but replace "vmc" for "af".  Both services fall victim to the naming problem.

In order to get around the naming problem, I have created a Maven profile cloud that builds the WAR artifact as "mikeensor.war".  Please change this to match your application's name since you won't have the user/password to publish (or the DNS) to publish to my micro instance.  The name will need to fit into the URL pattern http://<applicationname>..cloudfoundry.me.

To publish to your local cloud foundry micro instance, goto the root folder and type the following.  (this is assuming your micro instance is running and there are no "red" errors.

mvn clean package -Pcloud
vmc push <application name> -path target/

(if you have already pushed before, you will need to type:
vmc update <application name> -path target/

Note: It is possible to use the Maven Plugin for Cloud Foundry, however, I have still not been able to get it to work without changing the name of the artifact.

Enabling and connecting to services
You must create a service(s) so that your application can bind to the data source.  The VCAP (vmc) application handles how the configuration works when loading your application into Cloud Foundry.  It does this via an environment variable that is consumed in the namespaced configuration element.

In my example, I created a MongoDB service by typing:
vmc create-service mongodb --name <what you want to call your instance>

I named mine "second" (because I had created a first) and you will see that in data-services.xml the cloud XML configuration refers to the name of the service.
 
Note that if you have multiple MongoDB instances, you will need to do some Spring configuration (@Qualifier) when you want to use different instances.  This is not covered by this blog posting.

Now you will need to "bind" the service to your application.  This is done by typing:
vmc bind-service <name above> <application name>


Testing it out
You should be able to goto http://..cloudfoundry.me/home (example: http://mikeensor.mikeensor.cloudfoundry.me/home)

Congratulations!  You should have not only successfully deployed to Cloud Foundry (micro instance), bound to a MongoDB instance, but should be able to run in your local environment too!  As I get time, I will try to add in more detailed features such as multiple types of storage and post other "gotchas" as I find them.

1 comment:

James said...

Hi Mike
Great article. I was hoping you'd be interested in joining up with DZone's MVB program (see dzone.com/aboutmvb).
If you're interested, send me a mail and we can discuss further.
Regards
James