Xin Li
posted this on September 21, 2011 23:46
This tutorial explains how to use the PostgreSQL service for Micro Cloud Foundry from a java and Spring application. This application manages a basic guestbook page. Every visitor can sign the guestbook by filling a simple form. All visitors that have already singed are listed below the form with date.
Go to http://www.cloudfoundry.com/micro to get the Micro Cloud Foundry virtual machine image, and follow blog http://support.cloudfoundry.com/entries/20316811-micro-cloud-foundr... to install and configure your Micro Cloud Foundry properly.
Once you get your Micro Cloud Foundry up and running, you should be able see similar console like this:

Type "7" to check the status of various services, including PostgreSQL:

Now stop thinking about cloud, focus on the java application for a while.
Please follow steps below to create an empty web application:
* Start Eclipse
* Open the [New Project] dialog box, e.g. by using File > New > Project...
* Select Maven > Maven Project and click Next.
* Verify that the Create a simple project checkbox is disabled and click Next.
* Enter maven-archetype-webapp as a filter, select maven-archetype-webapp in the artifact list and click Next.
* Enter Group Id (e.g. Guestbook), Artifact Id (e.g. Guestbook), Version (e.g. 1.0) and Package (guest), and click Finish to create the project.
To add dependency on the Spring framework and automatically download all required java package from Maven repository, open the pom.xml, copy and paste following to replace its content.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Guestbook</groupId>
<artifactId>Guestbook</artifactId>
<packaging>war</packaging>
<version>1.0</version>
<name>Guestbook Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.6.0.Final</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
<finalName>Guestbook</finalName>
</build>
</project>
To store objects in a database using JPA we need to define an entity class:
* Right click the Guestbook project node (in the "Package Explorer" window), select New > Source Folder, enter src/main/java as Folder Name and click Finish.
* Open the [New Java Class] dialog box, e.g. by right clicking the new source directory node (in the [Package Explorer] window) and selecting New > Class.
* Enter guest as the package name - use exactly that case sensitive package name.
* Enter Guest as the class name - use exactly that case sensitive class name.
* Click Finish to create the new entity class.
* Copy and paste to replace the new source file content with following code:
package guest;
import java.io.Serializable;
import java.sql.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Guest implements Serializable {
private static final long serialVersionUID = 1L;
// Persistent Fields:
@Id
@GeneratedValue
Long id;
private String name;
private Date signingDate;
// Constructors:
public Guest() {
}
public Guest(String name) {
this.name = name;
this.signingDate = new Date(System.currentTimeMillis());
}
// String Representation:
@Override
public String toString() {
return name + " (signed on " + signingDate + ")";
}
}
We also need to configure JPA by setting a META-INF/persistence.xml file:
* Right click the src/main/resources node (in the "Project Explorer") and select New > Folder.
* The parent folder should be resources.
* Enter META-INF as a new folder name and click Finish.
* Right click the new MATA-INF folder in the "Project Explorer" window, select New > File, enter persistence.xml as file name and click Finish.
* Copy and paste following code to replace the new file content.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="GuestbookPU">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.session_factory_name" value="SESSION_FACTORY" />
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.cache.provider_class"
value="org.hibernate.cache.HashtableCacheProvider" />
</properties>
</persistence-unit>
</persistence>
Operations on the database will be performed by an instance of a Data Access Object (DAO) that we will define in this step as a Spring MVC component:
* Open the [New Java Class] dialog box by right clicking the guest package node (in the "Package Explorer" window) and selecting New > Class.
* The package name should be guest.
* Enter GuestDao as the class name - use exactly that case sensitive class name.
* Click Finish to create the new DAO Spring component class.
* Again, copy and paste following code to replace the new file content.
package guest;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class GuestDao {
// Injected database connection:
@PersistenceContext
private EntityManager em;
// Stores a new guest:
@Transactional
public void persist(Guest guest) {
em.persist(guest);
}
// Retrieves all the guests:
public List<Guest> getAllGuests() {
TypedQuery<Guest> query =
em.createQuery("SELECT g FROM Guest g ORDER BY g.id", Guest.class);
return query.getResultList();
}
}
In this step we will add a Spring Controller to manage guestbook web requests:
* Open the [New Java Class] dialog box by right clicking the guest package node (in the "Package Explorer" window) and selecting New > Class.
* The package name should be guest.
* Enter GuestController as the class name - use exactly that case sensitive class name.
* Click Finish to create the new Spring Controller class.
* Copy and paste following code to replace the new file content.
package guest;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class GuestController {
@Autowired
private GuestDao guestDao;
@RequestMapping(value = "/guest")
public ModelAndView guestbook(HttpServletRequest request) {
// Handle a new guest (if any):
String name = request.getParameter("name");
if (name != null)
guestDao.persist(new Guest(name));
// Prepare the result view (guest.jsp):
return new ModelAndView("guest.jsp", "guestDao", guestDao);
}
}
In this step we will add the JSP that generates the guestbook HTML output:
* Open the "New JSP File" dialog box by right clicking WEB-INF under src/main/webapp (in the "Package Explorer" window), selecting New > Other... > Web > JSP File and clicking Next.
* The parent folder should be WEB-INF (to prevent direct access to the JSP bypassing Spring).
* Enter guest as the jsp file name - use exactly that case sensitive class name.
* Click Finish to create the new JSP file.
* Copy and paste following code to replace the new file content.
<%@page contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@page import="guest.*"%>
<jsp:useBean id="guestDao" type="guest.GuestDao" scope="request" />
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>JPA Guestbook Web Application Tutorial - Powered by
PostgreSQL service in Cloud Foundry</title>
</head>
<body>
<form method="POST" action="guest.html">Name: <input type="text"
name="name" /> <input type="submit" value="Add" /></form>
<hr>
<ol>
<%
for (Guest guest : guestDao.getAllGuests()) {
%>
<li><%=guest%></li>
<%
}
%>
</ol>
<hr>
</body>
</html>
And replace the generated index.jsp with:
<jsp:forward page="guest.html" />
To integrate the Spring Framework into a web application we have to add the definition of the Spring dispatcher servlet to the web.xml configuration file and to configure that servlet using another xml configuration file.
Open the web.xml file (under src/main/webapp/WEB-INF) in a text editor, copy and paste to replace the default content of the web.xml file with the following new content:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Additional spring configuration is set in another XML file (whose name is derived from the name of the Spring dispatcher servlet in web.xml). To generate that file:
* Right click the WEB-INF node in the "Package Explorer" window, select New > Other... > XML > XML File and click Next.
* The parent folder should be Guestbook/src/main/webapp/WEB-INF.
* Enter spring-servlet as the File Name.
* Click Finish to create the XML file.
* Copy and paste following code to replace the file content.
<?xml version="1.0" encoding="windows-1252"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- Use @Component annotations for bean definitions -->
<context:component-scan base-package="guest" />
<!-- Use @Controller annotations for MVC controller definitions -->
<mvc:annotation-driven />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:guest" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<!-- Add Transaction support -->
<bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
<!-- Use @Transaction annotations for managing transactions -->
<tx:annotation-driven transaction-manager="myTxManager" />
<!-- View resolver -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/" />
</bean>
</beans>
The settings above guides Spring to support annotations (for components, controllers and transactions), to inject a JPA EntityManager, to manage transactions and to look for JSP pages in the WEB-INF directory.
Open a command prompt (Windows) or terminal (Linux) and "cd" to the location of the Guest project in the Eclipse workspace. Type command "mvn package" to generate war file Guestbook.war
mvn package
[...]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3 seconds
[INFO] Finished at: Mon Aug 08 23:59:32 GMT-08:00 2011
[INFO] Final Memory: 31M/428M
[INFO] ------------------------------------------------------------------------
Now we are ready to push the application to Micro Cloud Foundry. Change to the target directory before doing vmc push. Here, I will call my application "'guestbook"
$vmc push
Would you like to deploy from the current directory? [Yn]: y
Application Name: guestbook
Application Deployed URL: 'guestbook.yourcloud.cloudfoundry.me'?
Detected a Java SpringSource Spring Application, is this correct? [Yn]: y
Memory Reservation [Default:512M] (64M, 128M, 256M or 512M)
Creating Application: OK
Would you like to bind any services to 'guestbook'? [yN]: y
Would you like to use an existing provisioned service [yN]? n
The following system services are available::
1. mongodb
2. mysql
3. postgresql
4. redis
Please select one you wish to provision: 3
Specify the name of the service [postgresql-9a305]: guestbook
Creating Service: OK
Binding Service: OK
Uploading Application:
Checking for available resources: OK
Processing resources: OK
Packing application: OK
Uploading (9M): OK
Push Status: OK
Staging Application: OK
Starting Application: OK
Now your application is running inside the Micro Cloud Foundry! You can also use "vmc services", "vmc apps" commands to retrieve service and application information.


Now you can go to http://guestbook.yourcloud.cloudfoundry.me and see the web page:

Type anything you want and click on "Add', what you just type will appear in the page, and of course stored in PostgreSQL database.

Now it's time to deploy this sample application to a bigger cloud: www.cloudfoundry.com and see how the application works without any change in code and configuration!
First, use vmc target command to point to Cloud Foundry:
$vmc target api.cloudfoundry.com
Successfully targeted to [http://api.cloudfoundry.com]
$vmc login
Email: [Your Cloud Foundry email]
Password: [Your Cloud Foundry password]
Successfully logged into [http://api.cloudfoundry.com]
Then use the same vmc push command used above to deploy the application:
$vmc push
Would you like to deploy from the current directory? [Yn]: y
Application Name: guestbook-mycloud
Application Deployed URL: 'guestbook-mycloud.cloudfoundry.com'?
Detected a Java SpringSource Spring Application, is this correct? [Yn]: y
Memory Reservation [Default:512M] (64M, 128M, 256M or 512M)
Creating Application: OK
Would you like to bind any services to 'guestbook-postgresql'? [yN]: y
Would you like to use an existing provisioned service [yN]? n
The following system services are available::
1. mongodb
2. mysql
3. postgresql
4. rabbitmq
5. redis
Please select one you wish to provision: 3
Specify the name of the service [postgresql-a9x55]: guestbook
Creating Service: OK
Binding Service: OK
Uploading Application:
Checking for available resources: OK
Processing resources: OK
Packing application: OK
Uploading (9M): OK
Push Status: OK
Staging Application: OK
Starting Application: OK
The application behaves exactly the same as in Micro Cloud Foundry:

Micro Cloud Foundry™ is a complete instance of Cloud Foundry on your own computer. It brings all services that a developer needs to his/her own computer, without bothering IT and waiting for service provisioning. Developer can deploy application to Micro Cloud Foundry environment in development and QA cycle, once the application is certified for production, just deploy to a bigger cloud environment Cloudfoundry.com, it runs without any change! It's superior to traditional method of software development, in that it's fast and developer self-service.