Java development 2.0: Git-commit your Java apps with Heroku's PaaS

Heroku extends its Ruby roots for Java application scalability

Heroku is a PaaS option that truly brings something new to the Java™ development landscape — in part because its native language (and mindset) is Ruby. Heroku combines Ruby's flexible, fun-first approach to application development with Git's smart, distributed deployment model, making both accessible to Java developers via familiar Java libraries. In this installment of Java development 2.0, Andrew Glover builds a fresh incarnation of his mobile, location-based application, using Apache Wink, Jetty, and Maven; he then deploys it to Heroku using Git's high-efficiency, scalable infrastructure.

Share:

Andrew Glover, CTO, App47

 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.



15 November 2011

Also available in Chinese Russian Japanese Spanish

IBM in the cloud

To find out more about IBM's presence in the cloud, look no further than IBM SmartCloud Application Services, a cloud application platform delivered as a service. You'll find details on the following:

  • Application Services: Ready-to-run, enterprise-level services for collaboration, analytics, and business process management
  • Application Life Cycle: Technologies enabling collaboration and automation of application development, while providing visibility throughout the application lifecycle
  • Integration Services: Simple and security-rich integration of data, applications and services across cloud environments, delivered with a unified layer of service management
  • Workload Services: Performance optimization services, from applications to workload patterns, that help ensure quality of service and availability, while supporting multi-tenancy and workload mobility across clouds

Recent articles in the Java development 2.0 series have turned the spotlight on PaaS (Platform as a Service) options for Java development. This time I invite you to check out Heroku, another popular PaaS system recently extended to support Java applications.

With roots in Ruby, Heroku's approach to Java application development and deployment is decidedly different from what you may have experienced with other Java PaaS options, notably Amazon's Elastic Beanstalk and Google App Engine (GAE). Before launching into a hands-on introduction to Heroku, I think it could be helpful to look at what it shares in common with these two platforms, as well as where it's different.

GAE and Beanstalk: Two kinds of heavyweight

As we've learned from previous articles in this series, Google App Engine and Amazon's Elastic Beanstalk are polar opposites in terms of flexibility. Whereas GAE is a pretty tight sandbox, requiring that you play by its rules or not at all, Elastic Beanstalk is fully customizable: if it runs on the JVM, Amazon's PaaS will let you use it. GAE restricts your choice of Java libraries, and it also controls most of how your application scales. In fact, deploying apps to GAE is an exercise in letting go: You won't know where your web app lives or even how many application instances are alive. On the upside, Google does all the scaling for you, and it goes without saying that GAE apps scale very well. Releasing control means that you don't have to worry about much, aside from writing rock-solid code, of course.

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.

Amazon's Elastic Beanstalk is on the other side of the ring. In addition to giving you your choice of tools, it allows a heck of a lot control over how an application scales. The downside of this is obvious: without hands-on participation, Amazon does very little for you. Still, if you want to fine-tune your application deployment, and you want a highly scalable infrastructure, Amazon's Elastic Beanstalk is a darn good bet.

Given an ease-of-use scale encompassing both coding and deployment, with a range of 10 to 0 (10 being painful and 0 effortless), I'd put GAE at 4, and Elastic Beanstalk at 6. GAE lets me run a script and upload files seamlessly, but the limited range of compatible development tools sometimes cramps my style. Conversely, Elastic Beanstalk lets me use any library I like, but the road to deployment is longer and sometimes more tedious; I take on a measure of complexity in exchange for more control.

Heroku the challenger

Like GAE and Elastic Beanstalk, Heroku is built to scale horizontally. You deploy your code into what Heroku calls dynos, which are basically web containers. If you want to scale your system, just add more dynos, thus enabling Heroku to handle more simultaneous web requests. It's a simple concept that provides more control than GAE without the configuration requirements of Elastic Beanstalk.

Ruby and Heroku

While Heroku started out targeting the Ruby community — its parent company even employs Ruby's creator! — Heroku has recently been extended to support Clojure, Node.js, and the Java language. While Heroku's Ruby-first approach (and Ruby command-line) might be off-putting to some Java developers, I think it makes for refreshing differences. In particular, Heroku's Git-based deployment model makes building and scaling cloud-based web apps simple and fun.

On Heroku, Git — not Ant or Maven — is your deployment pipeline. When you're ready to deploy your application, you do so via a Git push, something I'll discuss in-depth later in the article.

As compared to GAE and Elastic Beanstalk on the ease-of-use scale, Heroku is a 2, which means it's pretty close to effortless. Heroku gives me great flexibility in terms of tools, so I can choose the most productive tools for any given job. In terms of configuration, Heroku allows more control than GAE, but less than Elastic Beanstalk — which sometimes is just right. It's also easy to port an application built on Heroku to Elastic Beanstalk: If I ever need more fine-grained control over an application's scalability, I know that I can just move it on over!


Getting started with Heroku

To get started with Heroku, you'll need to install and set up the following:

Note that Maven isn't required for Heroku, I'm just using it as my build tool. Heroku's Java documentation is also based on Maven.

Build and run the app

Once you have everything installed, pick the directory you'll be working in and run the following Maven command (code broken to accommodate page width):

mvn archetype:generate -DarchetypeGroupId=org.mortbay.jetty.archetype 
  -DarchetypeArtifactId=jetty-archetype-assembler -DarchetypeVersion=7.5.0.RC0

Creating REST endpoints

Wink happens to be one of a few libraries available for creating RESTful applications. In previous articles, I've created such apps using Play and Gretty, both of which do more than Wink to ease the process of creating RESTful endpoints. I chose Wink because Play is a full-stack framework, which in this case is more than I need. And Gretty is about as lightweight as lightweight gets, which could be less than I want. Wink doesn't bundle a Servlet container or contain an ORM framework — all it does is build RESTful resources. In this case, I decided that specialization was a good thing.

Maven will prompt you to provide a groupId and an artifactId. I typically use my package name for groupId and my project name for artifactId. Maven will then generate a project structure capable of building and running a web application on top of Jetty. Thus, in one step, you have the skeleton of a web application ready to be deployed into Heroku’s cloud infrastructure. While Jetty is the Maven archetype used, Heroku doesn't just support Jetty on the web server side. In fact, Heroku doesn't even know about Jetty — nor does it care.

The default app generated by the previous Maven command is your run-of-the-mill, pedestrian "hello world" application. In fact, if you go into the app's src directory, followed by main—>webapp, you’ll see an index.html file. Run the application and that file will (as you've probably guessed) print out the text "hello world."

Running the application is also easy. If you type the command mvn install in your newly generated project directory (which bears the name you gave for artifactId), a shell script will be generated for your desired operating system (mine is OSX). Just type $>sh target/bin/webapp, then go to http://localhost:8080 in your favorite browser, and prepare to be greeted.


Heroku in the real world

With Heroku, you can deploy any Java library you like. For the sake of example, and familiarity — at least for those of you who have been reading for a while — I’m going to build another incarnation of my location-gathering mobile web service, Magnus, which debuted in my introduction to Amazon's Elastic Beanstalk (see Resources). For my RESTful library, I’m going to use Apache Wink, which is an implementation of the JAX-RS specification. My web service implementation will provide a PUT endpoint that accepts JSON and inserts relevant data obtained from the document into a MongoDB instance. That, in turn, will be hosted at MongoHQ, by way of Morphia (see Resources).

The first thing I have to do is update Magnus's Maven pom.xml file with the new Wink and Morphia dependencies, as shown in Listing 1:

Listing 1. Adding Wink and Morphia to a Maven POM
<dependency>
 <groupId>org.apache.wink</groupId>
 <artifactId>wink-server</artifactId>
 <version>1.1.3-incubating</version>
</dependency>

<dependency>
 <groupId>org.apache.wink</groupId>
 <artifactId>wink-json-provider</artifactId>
 <version>1.1.3-incubating</version>
</dependency>

<dependency>
 <groupId>com.google.code.morphia</groupId>
 <artifactId>morphia</artifactId>
 <version>0.99</version>
</dependency>

Note that I also update my POM file to look inside Morphia's Maven repository and obtain version 0.99:

Listing 2. Adding a new repo to a Maven POM
<repositories>
 <repository>
  <id>morphia repository</id>
  <url>http://morphia.googlecode.com/svn/mavenrepo/</url>
 </repository>
</repositories>

Next, I create a location resource — a Wink endpoint that will represent user locations:

Listing 3. Creating a Wink LocationResource
@Path("/location")
public class LocationResource {

 @PUT
 @Consumes(MediaType.APPLICATION_JSON)
 @Path("{id}")
 public String updateAccountLocation(@PathParam("id") int accountId, JSONObject 
  requestJSON) {
  try{

   double latitude = Double.parseDouble(requestJSON.get("latitude").toString());
   double longitude = Double.parseDouble(requestJSON.get("longitude").toString());

   SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm");
   Date dt = formatter.parse(requestJSON.get("timestamp").toString());

   new Location(accountId, dt, latitude, longitude).save();
   return new JSONObject().put("status", "success").toString();
  }catch(Exception e){
   return "failure with " + requestJSON;
  }
 } 
}

Wink has me describe my RESTful service via three annotations: One for my HTTP method (PUT), another for my expected request content type (JSON), and the last to indicate that the endpoint accepts a parameter (in this case location/:accountId).

This Location class is the same Morphia-backed object introduced in my introduction to Elastic Beanstalk. It simply creates a document in MongoHQ that represents a location for a given account. The location (theoretically received from a mobile device) is represented by the RESTful endpoint's parameter.

Wink and Jetty

Next, I want to hook up Wink with Jetty, so I need to do two things: create an Application class and configure things in my web.xml file.

The purpose of the Wink Application class (shown in Listing 4) is to load corresponding resource classes:

Listing 4. A Wink Application class
public class MarmarisApplication extends Application {
 @Override
 public Set<Class<?>> getClasses() {
  Set<Class<?>> classes = new HashSet<Class<?>>();
  classes.add(LocationResource.class);
  return classes;
 }
}

In Listing 5, I then update my app's web.xml file, adding attributes specific to Wink, such as a pointer to my Application class and my desired URL pattern, which in this case is /service/resource:

Listing 5. Hooking up Wink via web.xml
<servlet>
 <servlet-name>MarmarisApp</servlet-name>
 <servlet-class>org.apache.wink.server.internal.servlet.RestServlet</servlet-class>
 <init-param>
  <param-name>javax.ws.rs.Application</param-name>
  <param-value>com.b50.marmaris.MarmarisApplication</param-value>
 </init-param>
 <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
 <servlet-name>MarmarisApp</servlet-name>
 <url-pattern>/service/*</url-pattern>
</servlet-mapping>

As a test, try re-running the mvn install command and starting the app (in this case Magnus) locally. You should be able to submit a JSON document (shown in Listing 6) to the endpoint http://localhost:8080/service/location/{account_id}, where account_id is a number.

Listing 6. A JSON document representing a location
{
 "name":"location payload",
 "latitude":"46.49",
 "longitude":"71.11",
 "timestamp":"09-02-2011 14:43"
}

Writing this application wasn't hard, and now we're ready for the even easier part: deploying it in Heroku's cloud!


Heroku and Git

Heroku's deployment pipeline is Git, which can take some adjustment if you're unfamiliar with distributed version control. Deploying to Heroku (via Git) is similar to issuing a Subversion commit into a different branch off the mainline. But in this case, Heroku is not the main code repository; it's just an alternate remote repository. To deploy an application, you push its source code via Git.

Note that rather than deploying war files, Heroku has you deploy your project as is. As you'll see when we start building our application's Procfile, Heroku is just a JVM looking for some code to execute. (If you want to see now what I'm talking about, check out the generated Main.java file in your project's package structure, then correlate its entry in your POM.)

Git a tip

If you're a Github user, you can think of Heroku as just another repository into which you push desired branches of your code base, such as development, QA, or staging.

While not immediately intuitive, Heroku's deployment model makes sense once you start using it. What's more, Heroku's tight integration with Git makes pushing various branches to different environments quick and painless.

Two-stage deployment

Deployment set up happens in two steps: First, you need to create and commit your code to a local Git repository. You can do this in your project's root directory, by typing the commands in Listing 7 in a terminal:

Listing 7. Git initialization and commit
$> git init
$> git add .
$> git commit -m "initial commit before Heroko deployment"

Now your local Git repository has a snapshot of your code (that is, the code has been versioned).

Next, you'll create an application in Heroku. I've done it in Listing 8 via the heroku command-line client (here's where it's essential that you have Ruby and RubyGems installed):

Listing 8. Creating a Heroku application
$> heroku create marmaris --stack cedar

The heroku create command in Listing 8 creates an application named "marmaris" on the cedar stack. Note that you'll have to choose a different application name, as that one is now taken. Alternately, you can leave the name to Heroku, and it will generate a unique one for you.

Heroku has a number of stacks. Cedar supports Java and Node.js, while others (like Bamboo) support newer versions of Ruby. When you execute the heroku create command, it will update your Git configuration and add a remote repository dubbed heroku.

Heroku's Procfile

Before you can deploy your code base to Heroku, you need to tell it how to run your application. This is easily done with a Procfile, which is simply a text file stating a command. My Procfile, shown below, points to the webapp shell script found in my target directory.

Listing 9. Creating a Procfile
$> echo 'web: sh target/bin/webapp' > Procfile

After creating a new file, it's important that you notify Git; otherwise Heroku won't know about it when you deploy the app via a Git push.

Listing 10. Notifying Git
$> git add Profile
$> git commit -m "updated to include my Profile"

Finally, to deploy the application, you'll simply issue a Git push to the heroku remote repository, shown in Listing 11:

Listing 11. Deploying to Heroku
$> git push heroku

You should see a series of messages returned by heroku, but look for the one that says something like:

http://your_app_name.herokuapp.com deployed to Heroku

Enter that URL in your favorite browser and (assuming you've left the default index.html file in your project directory) you will see a "hello, world!" printout.

While "hello, world!" is always quite interesting, the purpose of this application was to accept location information via HTTP PUTs. Consequently, using WizTools.org's RESTClient, I can issue an HTTP PUT against my RESTful endpoint, provide a JSON document, and bingo! I send a nice JSON response with the wonderful word success.


Scaling and maintaining Heroku

Heroku by default runs your app on a single dyno. This dyno, which is free, essentially turns itself off in times of no activity and spins itself back up when a request comes along. If you need to scale your app, you add more dynos, which you can do via the heroku scale command:

Listing 12. Scaling the application
$> heroku scale web=2

If you ever need to, you can also scale back an application by reducing the number of requested dynos. For instance, in this case I'd scale back to web=1. You can do both of these operations via Heroku's web interface, as well.

You can also tail logs on Heroku via the heroku logs command in Listing 13:

Listing 13. Watching logs on Heroku in real time
$> heroku logs -t

The heroku command-line client supports numerous features to scale, monitor, and manage your application; see Resources for documentation. Heroku also supports many third-party add-ons, in addition to a default datastore. I recommend checking out Heroku's support for MongoHQ and PostgreSQL.


In conclusion

Podcast: Adam Wiggins and Jesper Joergensen on Heroku

In this podcast, learn more about Heroku's beginings, it's support for multiple languages, and how to get started.

Heroku's tight integration with Git presents a new paradigm for deploying and scaling Java apps via the cloud, but it also makes the process exceptionally easy and powerful. All in all, having the freedom to use unlimited Java libraries and then deploy the resulting applications near-effortlessly is something that definitely works for me.

Resources

Learn

Get products and technologies

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, Cloud computing
ArticleID=774545
ArticleTitle=Java development 2.0: Git-commit your Java apps with Heroku's PaaS
publish-date=11152011