I work for CloudBees Inc., they are a great company with great products. I have mostly been working on the DEV@ side of the fence which is focused on continuous integration and basically the development side of your application, but we also have the RUN@ side of the fence where we provide a platform as a service (PaaS) for running your java web applications on the cloud. I could give you the sales pitch, but I’ll leave it at: the technologies and people behind RUN@ were one of the key reasons why I decided to join CloudBees.
Well I’ve been busy on some stuff since joining, so I decided it was time to actually try out the RUN@ stuff for my self. So here is my experience:
My test application:
I’m on the Apache Maven PMC, so I’m going to build it with… shock… horror… Maven.
I am partial to the odd bit of JSF, so it will be a JSF 2.0 application based off of Apache MyFaces.
I love Jetty as a servlet container for local testing, so we’ll use that hammer too.
Let’s get started…
First the pom.xml
<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/xsd/maven-4.0.0.xsd">
4.0.0
com.blogspot.javaadventure.cloudbees.run
jsf2-hello-world
0.1-SNAPSHOT
war
JSF 2.0 Hello World
A JSF 2.0 web application that says hello world.
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<project.build.outputEncoding>UTF-8</project.build.outputEncoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
org.apache.myfaces.core
myfaces-api
2.0.5
org.apache.myfaces.core
myfaces-impl
2.0.5
junit
junit
4.8.2
test
maven-clean-plugin
2.4.1
maven-compiler-plugin
2.3.2
1.6
1.6
maven-deploy-plugin
2.6
maven-failsafe-plugin
2.8.1
integration-test
verify
maven-install-plugin
2.3.1
maven-jar-plugin
2.3.1
maven-surefire-plugin
2.8.1
maven-release-plugin
2.1
maven-resources-plugin
2.5
org.mortbay.jetty
jetty-maven-plugin
8.0.0.M2
maven-release-plugin
true
install
Then the src/main/webapp/WEB-INF/web.xml
<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">
JSF 2.0 Hello World
A JSF 2.0 web application that says hello world.
javax.faces.STATE_SAVING_METHOD
server
javax.faces.DEFAULT_SUFFIX
.xhtml
javax.faces.FACELETS_SKIP_COMMENTS
true
javax.faces.PROJECT_STAGE
Production
org.apache.myfaces.webapp.StartupServletContextListener
Faces Servlet
javax.faces.webapp.FacesServlet
1
Faces Servlet
*.xhtml
60
index.xhtml
Then the backing bean (src/main/java/com/blogspot/javaadventure/cloudbees/run/GreeterBean.java)
package com.blogspot.javaadventure.cloudbees.run;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import java.io.Serializable;
@ManagedBean(name=“greeter”)
@ViewScoped
public class GreeterBean implements Serializable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getResponse() {
if (name != null && !name.isEmpty()) {
return “Hello " + name;
} else {
return null;
}
}
}
Should always have some tests (src/test/java/com/blogspot/javaadventure/cloudbees/run/GreeterBeanTest.java)
package com.blogspot.javaadventure.cloudbees.run;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
public class GreeterBeanTest {
@Test
public void nullNameMeansNoGreeting() throws Exception {
GreeterBean instance = new GreeterBean();
instance.setName(null);
assertThat(instance.getResponse(), nullValue());
}
@Test
public void noNameMeansNoGreeting() throws Exception {
GreeterBean instance = new GreeterBean();
instance.setName(””);
assertThat(instance.getResponse(), nullValue());
}
@Test
public void aNameMeansGreeting() throws Exception {
GreeterBean instance = new GreeterBean();
instance.setName(“Fred”);
assertThat(instance.getResponse(), notNullValue());
}
}
Next the page of our web application (src/main/webapp/index.xhtml), i’m going to use the JSF 2.0 ajax support (because it’s there)
xmlns:ui=“http://java.sun.com/jsf/facelets"
xmlns:h=“http://java.sun.com/jsf/html"
xmlns:f=“http://java.sun.com/jsf/core">
<ui:insert name=“metadata”/>
<h:head>
JSF 2.0 Hello World
</h:head>
<h:body>
<f:view>
<h:form>
<h:outputLabel for=“greeter” value=“Please tell me your name:”/>
<h:inputText id=“greeter” value=”#{greeter.name}">
<f:ajax event=“keyup” render=“text”/>
</h:inputText>
</h:form>
<h:outputText id=“text” value="${greeter.response}”/>
</f:view>
</h:body>
Let’s test it locally
$ mvn jetty:run[INFO] Scanning for projects…
[INFO]
[INFO] ————————————————————————
[INFO] Building JSF 2.0 Hello World 0.1-SNAPSHOT
[INFO] ————————————————————————
[INFO]
…WARNING:
*** WARNING: Apache MyFaces-2 is running in DEVELOPMENT mode. ***
*** ^^^^^^^^^^^ ***
*** Do NOT deploy to your live server(s) without changing this. ***
*** See Application#getProjectStage() for more information. ***
2011-05-17 10:22:10.982:INFO::Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server
Fire up a browser to http://localhost:8080/ and here’s what we get:OK, so now I turn off DEVELOPMENT mode in the web.xml, build my app and deploy it to RUN@cloud… and here’s what we get:That was cool. Didn’t have to change anything (other than switch to production mode for safety as it’s being deployed in the wild) and I did all this in under 20 minutes (including signing up for RUN@cloud)
My next steps will be to integrate this web application with DEV@cloud and our Jenkins plugin for deployment to RUN@cloud so that I can show off continuous deployment! But that will be a different day!