Java development 2.0: Climb the Elastic Beanstalk

Scale the cloud with Amazon's infinitely flexible PaaS

For those who want more control over their environment but like the plug-and-play scalability of PaaS, Beanstalk could be a good and welcome alternative to Google App Engine. Andrew Glover's guided tour of Beanstalk starts with a location-based mobile application (built using the Play framework and MongoDB), which he then ports to the Beanstalk environment. Configuring Beanstalk is both easy and rewarding, he finds, with choice and flexibility over and above what's offered by GAE.

Andrew Glover, Author and developer, Beacon50

Andrew GloverAndrew 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.



22 February 2011

Also available in Chinese Russian Japanese Portuguese

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.

About this series

The Java development landscape has changed radically since Java technology first emerged. Thanks to mature open source frameworks and reliable for-rent deployment infrastructures, it's now possible to assemble, test, run, and maintain Java applications quickly and inexpensively. In this series, Andrew Glover explores the spectrum of technologies and tools that make this new Java development paradigm possible.

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.

Amazon's 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.

Video demo: An introduction to MongoDB

This demo introduces MongoDB, shows you how it works, and explains in which domain models it is most useful.

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 or GAE?

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.


Magnus and the Beanstalk

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.

Sign up for AWS

To get started with Beanstalk, you'll need to sign up with Amazon Web Services. Beanstalk currently offers a free plan, though a price will surely follow as you scale to more resources and bandwidth.

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.

Building the application

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.

The location document

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.

A quick health check

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?


Magnus climbs the Beanstalk

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
A screenshot displaying Beanstalk's new application screen.

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!
A screenshot stating that the new Beanstalk app is ready to be accessed.

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!
A screenshot confirming that the new Beanstalk app is live.

Configuring Beanstalk

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
A screenshot of a dialog box for configuring Beanstalk.

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!


Test it out

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
A screenshot of a RESTClient report.

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
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.


Versioned deployments

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
A screenshot from the Beanstalk management console showing application details of Magnus v1.

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
A screenshot showing details of the redeployed application.

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
A screenshot of the Beanstalk interface to redeploy the application.

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
A screenshot showing the selections to terminate Beanstalk.

Up and down the 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.

Resources

Learn

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.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology, Open source, Cloud computing
ArticleID=627251
ArticleTitle=Java development 2.0: Climb the Elastic Beanstalk
publish-date=02222011