Cloud Foundry allows you to run many instances of your application, add and remove services, when needed, and so on. You may want to read some info on getting started.
Register on Cloud Foundry
The first step is to register on Cloud Foundry. You will either manage your cloud app using a command line VMC tool, or using Cloud Foundry extension for Spring Tool Suite/Eclipse. I chose to use the IDE independent VMC.The Spring Data MongoDB app
The Spring app I am using is available to download from my GitHub (specifically, the version for this article is tagged as BlogPost1 and you can also get it from the tags view). Below I will show you some of the steps you need to make to get your Spring MongoDB app up and running - locally for now. More information is available from the Cloud Foundry Spring Application Development page.Things to remember:
- Cloud Foundry technology support is limited, so you have to figure out beforehand whether your stack will even work.
- At this moment, Java 7 is not supported on Cloud Foundry, so you need to downgrade your project to Java 6.
- Similarly, only certain versions of Spring and Spring Data MongoDB are supported.
- Only Tomcat 6 is supported at the moment. Locally I'm developing against Tomcat 7, but due to Cloud Foundry limitations it has to work on Tomcat 6 as well (no problems with that).
- Servlet Spec 3.0 is not supported - back to 2.5.
apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'war' apply plugin: 'eclipse-wtp' group = 'me.m1key.audiolicious' version = '0.0.1-SNAPSHOT' sourceCompatibility = 1.6 targetCompatibility = 1.6 repositories { mavenLocal() mavenCentral() mavenRepo name: "spring-test-mvc", url: 'http://repo.springsource.org/libs-milestone/' mavenRepo url:'http://maven.springframework.org/milestone/' } project.ext.finalName = 'audiolicious-cloud.war' war { archiveName = finalName } task deployment(type: Copy) { from('build/libs/' + finalName) into("$System.env.TOMCAT_HOME/webapps/") } project.ext.springVersion = '3.1.2.RELEASE' dependencies { compile group: 'org.springframework', name: 'spring-beans', version: springVersion, force: true compile group: 'org.springframework', name: 'spring-context', version: springVersion, force: true compile group: 'org.springframework', name: 'spring-core', version: springVersion, force: true compile group: 'org.springframework', name: 'spring-webmvc', version: springVersion, force: true compile group: 'org.springframework.data', name: 'spring-data-mongodb', version: '1.0.4.RELEASE' compile group: 'org.mongodb', name: 'mongo-java-driver', version: '2.9.1' compile group: 'org.slf4j', name: 'slf4j-api', version: '1.6.6' compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.6.6' compile group: 'org.apache.velocity', name: 'velocity', version: '1.7' compile group: 'org.cloudfoundry', name: 'cloudfoundry-runtime', version: '0.8.2' testCompile group: 'org.springframework', name: 'spring-test', version: springVersion testCompile group: 'junit', name: 'junit', version: '4.+' testCompile 'org.hamcrest:hamcrest-all:1.3' testCompile 'javax.servlet:servlet-api:2.5' testCompile 'org.springframework:spring-test-mvc:1.0.0.M2' } configurations.all { resolutionStrategy { force group: 'org.springframework', name: 'spring-aop', version: springVersion force group: 'org.springframework', name: 'spring-expression', version: springVersion force group: 'org.springframework', name: 'spring-tx', version: springVersion } }Meanwhile, in your src/main/webapp/WEB-INF/web.xml...
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="AudioliciousCloud" version="2.5" metadata-complete="true"> <display-name>Spring MVC tutorial</display-name> <servlet> <servlet-name>audiolicious</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:audiolicious-servlet.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>audiolicious</servlet-name> <url-pattern>*.go</url-pattern> </servlet-mapping> </web-app>And the Spring servlet file (src/main/resources/audiolicious-servlet.xml).
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:mongo="http://www.springframework.org/schema/data/mongo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-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/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd"> <!-- Enabling Spring beans auto-discovery --> <context:component-scan base-package="me.m1key.audiolicious.cloud" /> <!-- Enabling Spring MVC configuration through annotations --> <mvc:annotation-driven /> <bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"> <property name="resourceLoaderPath"> <value>/</value> </property> </bean> <!-- Defining which view resolver to use --> <bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> <property name="prefix"> <value>/velocity/</value> </property> <property name="suffix"> <value>.vm</value> </property> </bean> <mongo:db-factory id="mongoDbFactory" dbname="adlcs_cloud" host="127.0.0.1" port="27017" /> <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> <constructor-arg name="mongoDbFactory" ref="mongoDbFactory" /> </bean> <mongo:repositories base-package="me.m1key.audiolicious.cloud.repositories" /> </beans>What's important here is MongoDB configuration. If you configure it this way, it will allow Cloud Foundry to inject its own values for host name and port, so that it also works on the cloud.
MongoDB repository
One of the nice features of Spring Data MongoDB is that you can (just like in Grails) ask it to create simple repositories for you - you just define interfaces, Spring will provide the implementation.package me.m1key.audiolicious.cloud.repositories; import me.m1key.audiolicious.cloud.entities.Song; import org.springframework.data.repository.CrudRepository; public interface SongRepository extends CrudRepository<Song, Long> { }This gives me a CRUD repo that I don't have to implement myself. You can add methods to this interface, such as findByLastName, and Spring will know how to implement them. For more information on this, see the repositories reference. You can extend this behaviour by implementing your own, more sophisticated methods.
Entity. Notice no annotations:
package me.m1key.audiolicious.cloud.entities; public class Song { private String name; private String albumName; private String artistName; private String songKey; public Song(String name, String albumName, String artistName, String songKey) { super(); this.name = name; this.albumName = albumName; this.artistName = artistName; this.songKey = songKey; } public String getName() { return name; } // Omitted for brevity. }
In part 2 of this tutorial I will show you how to deploy this on Cloud Foundry.
PS. Tomcat debugging
This is the stuff I added in my catalina.sh (this is Linux syntax then) file to get remote debugging from my IDE to work.JAVA_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n $JAVA_OPTS" JPDA_TRANSPORT=dt_socket JPDA_ADDRESS=8000