When this series debuted almost two years ago, I described Java™ development 2.0 as the effect, primarily, of two exciting trends: (1) developers using open source tools and frameworks to build software applications from top to bottom; and (2) shops renting — or borrowing — the application infrastructure required to manage every level of the software development life cycle, including application deployment.
Early in the series, I covered two cloud platforms for Java web development: Google App Engine and Amazon EC2 (see Resources). Each in its own way embodies the potential of Java 2.0. Whereas GAE is a PaaS, or platform as a service, offering, EC2 is more of an infrastructure as a service, or IaaS. Think of EC2 as an on-demand virtual environment that lets you install pretty much anything you'd like. GAE is more picky, being set up just for developing Python and Java web applications.
Compared to EC2, GAE has up till now provided a faster, easier path for cloud-based application development. But over the past few years, the market for PaaS has heated up. The concept has caught on, and some say it's about to catch fire (see Resources). So it shouldn't surprise anyone that Amazon has recently announced its own PaaS platform, called Elastic Beanstalk.
Both GAE and Beanstalk are cloud platforms especially tailored to Java application development. Like GAE, Beanstalk has you deploy WAR files to an amorphous, super-scalable environment, in this case powered by EC2. But unlike GAE, Beanstalk lets you customize the application environment — something that holds certain (and often sensible) appeal for software developers.
For instance, unlike GAE, Beanstalk gives you total control over the number of nodes your application is hosted on, which makes horizontal scaling easy and efficient. You can also use any Java library you like, which is another area where GAE can be fussy. As for more general-purpose PssS tasks, Beanstalk offers load balancing across nodes, versioning of deployment artifacts, and even low-level remote terminal access to EC2 instances. Reporting is built in, so you can check up on the health and performance of your application environment anytime.
Beanstalk's advantages over GAE are rooted in fundamentally different cloud-based service models. GAE currently is a strict PaaS play: You don't have a lot of choices to make when you go the GAE route, and for some scenarios that works out. You have one choice of a datastore (Bigtable), and a limited number of Java libraries to choose from. Right now, for instance, you can't build a web application that relies on Hibernate, although this could change in the future (see Resources). Once you've deployed your web application, you don't have a tremendous amount of control over it. In fact, from a cloud-scaling standpoint, you don't have any. In essence, with GAE, you leave the scaling up to Google, which kind of makes sense given Google's expertise in that area. But some developers and companies want more control over their applications. And they want it in the cloud.
The lack of data privacy safeguards is also a sore point for some. When you build a GAE web app, you don't get to say where your data will live. In domains where data is king, or where data privacy is king, it's not very comforting, or copacetic, to just send it off to the ether-like abstraction of Bigtable. In some cases, GAE is simply ruled out for this very reason.
Before we can explore Beanstalk, I need to build a web application that will demonstrate some of its features. My application, dubbed Magnus, takes location data from a mobile device and persists it to a datastore. Given that millions of mobile devices are connected at any one time, Magnus needs to be able to scale quickly and easily if its popularity explodes. I'll be using horizontal scaling and will fine-tune Beanstalk to ensure that I have all the application instances I need, when I need them.
Building the application isn't the main point of this article, so I'll make quick work of it. First, I'll use the Java-based Play framework to build a simple REST endpoint where mobile devices will post a JSON document describing the device's geographic coordinates. Play bills itself as a full-stack alternative to "bloated enterprise Java stacks." It's easy to get up and running quickly, and I like the framework's simple routing system. Its reliance on a stateless model makes building RESTful applications a snap, and Play lets me easily plug in my own persistence model — one that uses MongoDB.
For this application, I'll store location coordinates in a MongoDB instance hosted by MongoHQ, which is another PaaS provider. I'll just create a datastore and then quickly add documents to it via HTTP. MongoHQ will handle the rest.
I'm going to omit the account administration web interface for this application. In a real-world scenario, end users would create accounts for the Magnus service. I'd then perhaps embed additional account information into the corresponding JSON document describing the account's location. For now, the URL will suffice to associate a location to an account.
So, say a device is associated with account 12345 and that the device is currently located in Quebec, Canada. The corresponding JSON document sent to my web application would look like Listing 1:
Listing 1. A simple JSON document describing a location
{
"name":"location payload",
"latitude":"46.49",
"longitude":"71.11",
"timestamp":"02-02-2011 14:43"
}
|
I'd use an HTTP PUT call to put this document to the following URL, which corresponds to the location of an account:
Listing 2. A RESTful URI for the location of an account
http://some.web.address.com/location/12345 |
The location is the resource in the URI in Listing 2. I'm essentially updating the location of account 12345 with an HTTP PUT to this address. The response will be a JSON document acknowledging the request.
To create my location document, I'll use Morphia, which is an ORM-like library for mapping POJOs to MongoDB. My location document, represented by a plain old Java object, is shown in Listing 3:
Listing 3. Creating the location document
@Entity(value = "locations", noClassnameStored = true)
public class Location {
@Id
private ObjectId id;
private String accountId;
private double latitude;
private double longitude;
private Date timestamp;
public Location(String accountId, Date timestamp, double lat, double lon) {
this.accountId = accountId;
this.timestamp = timestamp;
this.latitude = lat;
this.longitude = lon;
}
public void save() throws Exception {
Mongo mongo = new Mongo("gnome.mongohq.com", 34256);
Datastore datastore = new Morphia().createDatastore(mongo, "magnus",
"username", "password".toCharArray());
datastore.save(this);
}
}
|
Note that I've hardcoded the connection information to MongoHQ, which you would probably never want to do in real life. It works for demonstration purposes, though!
I tie it all together with a simple controller in Play and a route definition. The controller will act as an endpoint for receiving JSON requests. My route definition is shown in Listing 4:
Listing 4. A Play route definition
PUT /location/{id} Application.saveLocation
|
This definition states that any HTTP PUT requests to a URI meeting the pattern /location/{some id} will be routed to the saveLocation method of the Application class.
Finally, the saveLocation is almost as simple as what you
see in Listing 5:
Listing 5. The saveLocation method
public static void saveLocation(String id, JsonObject body) throws Exception {
double latitude = body.getAsJsonPrimitive("latitude").getAsDouble();
double longitude = body.getAsJsonPrimitive("longitude").getAsDouble();
String when = body.getAsJsonPrimitive("timestamp").getAsString();
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm");
Date dt = formatter.parse(when);
new Location(id, dt, latitude, longitude).save();
renderText("success");
}
|
Play passes in the trailing ID to the requested URL (that is, 12345) and the JSON body (I had to create a JSON binding, which is documented on the Play website). I promptly obtain a few pieces of data from the JSON document — namely the latitude, longitude, and time — create a Location instance, and save it. Lastly, I provide a response, which for now is just a text string; later on I'll change it and deploy a new version. There's no error handling in this code, but note that you would need it in a real-world application.
My application currently has one reachable endpoint that only accepts a JSON request, which will require some tools to fashion. I'd also like to have a normal endpoint that I can hit with a browser to verify that everything is working after I deploy my application. So, I'm going to implement the index method on Play's Application class (which is invoked by default if you hit the root path) to quickly return some text. In other words, I'm going to add renderText("Magnus Web is live");) to the index method of the Application class.
My last step is to create a war file to deploy to Beanstalk, which is basically a glorified Tomcat container. With Play, I simply run the command play war -o ../magnus --zip, which will create a file dubbed magnus.war containing my Play application.
And with that, my soon-to-be wildly successful, location-gathering, don't-care-about-privacy application is built. My next step is to ensure it has the massive Beanstalk scalability it's going to need, once people realize that providing their location constantly is a good idea — right?
Presuming you've signed up for Beanstalk, you start by logging in to your AWS Management Console. From there, select the Elastic Beanstalk tab, then click the Upload your own application option, followed by the Launch Application button. This will result in a dialog requesting a few pieces of information, as shown in Figure 1:
Figure 1. Creating a new Beanstalk application
In this dialog, you have to provide a name, which will also be the URL of your application. You also need to provide a war file. Once you've hit the Continue button, you'll be taken back to the AWS Management Console, while the application fires up. This could take a while — for instance, I saw times of up to 10 minutes.
Once your application is fully deployed and everything has been configured on Amazon's end, you should see a nice green box next to your application's name. The green light means the application is good to go, as you can see in Figure 2:
Figure 2. Magnus is ready!
When I click the URL offered by Amazon, magnus.elasticbeanstalk.com, I can see that my application is live. Note that what you're seeing in Figure 3 is the result of the code I added in the "health check" section:
Figure 3. Magnus lives!
You start to see the real power of Beanstalk when you click the Edit Configuration link in the Environmental Details section on the bottom right of the Beanstalk Management Console. Clicking this link brings up a dialog with a host of options, including some really neat possibilities.
Figure 4. Editing your environment's configuration
Beanstalk offers a number of high-level deployment options, including how much memory, I/O performance, local storage, and so on, you'd like for application instances. It also lets you configure your application's load balancer and auto scaling, which is the option that controls horizontal nodes. With auto scaling, you decide how many instances of your application you want running and how to trigger each new instance.
Auto scaling is an exceptionally powerful aspect of Beanstalk, putting application scalability directly into your hands. You could, for example, set auto scaling to fire up new instances based on some metric, such as incoming traffic. Once the traffic died down, the application would scale back — all without any manual intervention. Now that's truly elastic computing!
With Magnus live on the web, let's test out adding locations to a sample account. I'm going to cheat by using a tool to push a JSON document to my endpoint. RESTClient uses HTTP PUT to send a JSON document to my application. As you can see in Figure 5, things are going smoothly so far:
Figure 5. RESTClient reports an incoming payload
The final sanity check is to see if the JSON document was persisted to MongoDB, which you'll recall is running over at MongoHQ.
Figure 6. MongoHQ's interface showing Magnus's location document
I left the response of the endpoint rather simple in the initial phase of application development. Now I'd like to make a slight change and redeploy the application.
Beanstalk, like GAE, supports versioned deployments. Thus, you can have multiple versions deployed but only one will be "live" at any given time. This feature lets you easily move between versions as needed; for example, to roll back should a deployment go badly.
Click the Versions tab toward the upper-left corner of the Beanstalk console's Application Details section and you should see your first release.
Figure 7. Beanstalk displays an application version
On my local machine, I'm going to change the saveLocation method of the Application class. Specifically, I'm going to make the last line of the method read renderJSON("{success}");. The response will return a simple JSON doc rather than a simple text string.
When you hit the Upload New Version button, you should see the familiar dialog shown in Figure 8. It's here that I provide my war file a version label.
Figure 8. Redeploying Magnus
As you can see in Figure 8, I've specified that I'd like the WAR file uploaded but not deployed. After the WAR file has been uploaded, I can then deploy it at my leisure via the Versions tab.
Figure 9. Redeploying Magnus and making a new default version
I clicked the check box next to my desired version. Now I can make that the live version by simply hitting the Deploy Version button, as shown in Figure 9.
Of course, if you ever want to turn off Beanstalk, you can do so. You must go to the Actions drop-down box on the right-hand side of the management console and select Terminate the Environment. Don't forget also to delete your versioned WAR files. You'll be charged for the space in S3 until you do!
Figure 10. Terminating Beanstalk
Elastic Beanstalk gives developers ready access to Amazon's EC2 infrastructure and makes it configurable well beyond what we've come to accept from GAE. As I demonstrated with my location-based mobile application, even a newish Java web framework like Play was welcome, and persisting documents via MongoDB instances, running at MongoHQ.com, was not a problem.
For my application, I didn't have to start any databases, start any instances of Tomcat, or even ensure that any ports were open. The process was simple and quick. What's even better, my application will auto scale to four instances in the case of a traffic spike, with a load balancer in front that I didn't have to configure. On the flip-side, if I wanted more control I could have it, as my little experiment with versioned deployments showed. The total cost to get started was an unbeatable $0.00.
Amazon's Beanstalk is just one of several PaaS alternatives emerging to make the Java 2.0 landscape richer and more exciting. As smart, innovative companies begin to carve out new niches in this growing space, we can be sure that rapid development into enterprise environments, with minimal cost, is here to stay.
Learn
- "Video demo: An introduction to MongoDB" (Andrew Glover, developerWorks): This brief demo explains what MongoDB is, how to use it, and and where it's most applicable.
- Java
development 2.0: This developerWorks series explores technologies that are redefining the Java development landscape. Topics have included Amazon EC2 (October 2009); Google App Engine (August 2009); MongoDB (September 2010); and Bigtable (May 2010).
- The Java technology zone technical podcast series: Get the information you need directly from the developers you respect, in this forward-looking podcast series moderated by Andrew Glover. Select interviews from Series 1:
Sacha Labourey on CloudBees (December 2010); Max Ross on Google App Engine (November 2010); Eliot Horowitz on MongoDB (September 2010).
- "Salesforce
To Acquire Ruby PaaS Heroku " (John Waters, Application Development Trends, December 2010): Technology trend watchers say PaaS is heating up in 2011. Witness the recent $200 million purchase of Heroku by SalesForce.com.
- "Domain-model
persistence with Morphia and MongoDB" (John D'Emic, developerWorks, January
2010): Learn how to use Morphia to persist, load, delete, and query a Java domain model mapped to MongoDB.
- developerWorks Cloud computing:
Find out more about Cloud computing, including the technologies and industry players.
-
Browse the
Java technology bookstore for books on these and other technical topics.
-
developerWorks Java technology zone: Find hundreds of articles about every aspect of Java programming.
Get products and technologies
- Amazon Elastic Beanstalk: Read the
reference documentation, sign up, and get started with Amazon's PaaS alternative to GAE.
- The Play framework: Billed as a Java framework built by Web developers, Play focuses on developer productivity and targets RESTful architectures.
- MongoDB: A humongously scalable document-oriented database. It's written in C++ but uses JSON-style documents for storage, making it Java compatible.
- MongoHQ: MongoDB's hosted database storage in the cloud.
Discuss
- Get involved in the developerWorks community. Connect with other developerWorks users while exploring the developer-driven blogs, forums, groups, and wikis.

Andrew Glover is a developer, author, speaker, and entrepreneur with a passion for behavior-driven development, Continuous Integration, and Agile software development. He is the founder of the easyb Behavior-Driven Development (BDD) framework and is the co-author of three books: Continuous Integration, Groovy in Action, and Java Testing Patterns. You can keep up with him at his blog and by following him on Twitter.




