Java Magazine Logo
Originally published in the July/August 2014 issue of Java Magazine. Subscribe today.

Server-Side Deployment on the JVM

by Casimir Saternos

Published July 2014

JVM deployments with the server outside, inside, and alongside a web app

Over time, the success of a web application can influence technology choices for ongoing support and customization. For example, Twitter was initially a Ruby on Rails application but the back-end Ruby services were replaced with applications running on the Java Virtual Machine (JVM) and written in Scala. With this in mind, it is important to recognize that Java development practices and the use of the JVM have expanded greatly in recent years. These changes can ease the transition from starter projects to large-scale, mature applications.

This article will demonstrate how a project can initially be developed very quickly with a view toward a variety of deployment options. More specifically, a small web application will be written in Ruby but packaged in a web application archive (WAR) file. Options for deploying the WAR file with the server outside, inside, or alongside allow such an application the type of scalability and availability demanded in modern high-traffic, cloud-based deployments. By using a standard WAR file for deployment, the application is packaged in a form that can readily be replaced with a similar package written in Java or other JVM language.

Note: For the example described in this article, you can use any Ruby implementation of your choice (either JRuby or a C-based Ruby).

Java and Alternative JVM Languages

The JVM has emerged as the preeminent language-independent virtual machine target and is optimized to run on a wide range of platforms. It has matured over the years and now supports a growing number of alternative languages that compile to JVM bytecode. Each release of the JVM includes new features that enhance the JVM’s ability to support and optimize the performance of additional languages. These qualities have resulted in the popularity of the JVM and make it a serious consideration for many types of software projects.

Java is a fine general-purpose software development language, but it is not necessarily the best option for every project. JVM languages include JRuby, Jython, Groovy, JavaScript, Scala, and Clojure. These languages are impressive implementations in their own right, and all share the desirable quality of running on the JVM. During the initial phases of a project, it might be preferable to use scripting languages specifically geared for programmer productivity. By using JVM implementations, a project written in one language can be ported more easily to another, if needed at a later point.

Creative Types

Programmers are creative people and typically delight in contriving clever ways to solve problems.

JRuby is one of a number of popular JVM languages in use. It is less “strict” than Java in several ways, which promotes quick initial development. But some of the features that make Ruby a popular choice for programmer productivity can be the source of problems as a project grows. Java provides type safety and the high performance required by more-mature projects. One way the process of transitioning a project from Ruby to Java can be simplified is by packaging Ruby code in a Java WAR file. This allows the target deployment hardware and the foundational software that is installed to remain constant when the project transitions from JRuby to Java.

Deployment Options

Although much time and attention are spent during the process of software development, the end goal is deployment to a production environment for end users. This goal is best achieved by up-front planning that, at a minimum, does not result in a choice that is untenable for production usage. Deployment practices are driven by each application’s unique functional and technical requirements. Target server capabilities, expected web traffic patterns, and available hardware also contribute to the decision of where an application will be deployed. After one or more deployment destinations have been selected, the manner of deployment needs to be considered.

Programmers are creative people and typically delight in contriving clever ways to solve problems. This quality is commendable when addressing end users’ requirements, as long as standards and conventions provide the structure for the work. Build and deployment tasks are not the place for creativity. These tasks do not directly meet end user needs and should be completed as efficiently and consistently as possible. Creativity in build and deployment practices results in highly customized unique projects that are difficult to support and modify. In the end, this type of “snowflake” project automation hampers the development efforts it is meant to promote.

Server outside. Traditionally, web application servers were installed independently and configured by system administrators. WAR files or enterprise archive (EAR) files were then deployed to these servers after all installation and configuration was completed. The server was outside the web application. This method is still a great way to deploy applications and conforms with Java EE standards that are well established and understood among Java developers.

However, one challenge with this method is that each developer needs an application server for local testing. Unless an application server is readily available on a preconfigured virtual machine, individual developers are required to configure their own workstations. This process might be scripted and straightforward, but in some cases, developers are forced to cobble together a configuration whose description is buried in e-mail messages and then debug error-log messages to resolve configuration issues.

Another challenge is that developers might use different processes to deploy an application. One developer might use a web interface, another might copy the file into a directory that is “watched” by the application server, and another might run a utility or homegrown script to deploy the application. Such inconsistencies in the deployment process can frustrate attempts to have clear communication among developers.

These problems can be overcome by incorporating deployment functionality within the project itself. For instance, Maven-based projects can use standard plugins (for example, for Oracle WebLogic Server) that reduce the deployment process to a single command. This is an improvement that provides consistency and control among developers.

Server within a development project. There are also build plugins that embed a server, such as Jetty or Apache Tomcat, within a plugin used by the project. This approach eliminates the need to install an independent web application server. The server (and any associated configuration) can be maintained within version control. If the server is updated, all developers have the updated version the next time they retrieve the latest code.

This solution is specifically geared toward developers, however, not the actual deployment. It is unusual to deploy an application that runs on a server provided through a Maven plugin. In general, teams that use such plugins still deploy to an external server for centralized testing efforts and final production. A server should not be coupled to a project build tool when deployed to a production environment.

Server inside and alongside. This leads to two more-recent solutions: embed the server inside the application archive itself or deploy the server alongside the application. A server can be included inside the application code and controlled within this context. This method reduces the deployment requirements to a single, standalone archive that can be invoked using the java -jar command. An alternative is to keep the application server code separate, and include it alongside the actual web application. This method is typically performed by passing the application server as the first argument to the java -jar command and passing the web application as the second argument.

Example Project

The following example project will demonstrate the three methods of deployment (outside, inside, and alongside) using a minimal example written in Ruby. This project is intentionally minimal to focus on the specific concerns at hand. It shows how to create a non-Java-based web application that can be packaged in a WAR file and deployed using a server running outside, inside, or alongside the application.

Ruby packages (analogous to Java archive [JAR] files) are called gems. Two gems are required by the web application created in this project. The web application is written using the Sinatra gem, which is a domain-specific language (DSL) for web development. The JSON gem is used to illustrate the ease of creating a web API. The project will demonstrate that both Ruby code and gems can be packaged together for distribution in a single WAR file.

Write the application. Create a new directory whose name will be used as the name of the WAR file:

mkdir testwebapp
cd testwebapp


Next, include the bundler gem to provide dependency management similar to what Java developers know from tools such as Maven or Ivy:

gem install bundler


Note:
The implementation of Ruby in use at this point does not need to be JRuby. Another gem called Warbler includes JRuby and will be used when the WAR file is created.

With bundler installed, run the following command to create a configuration file called a Gemfile.

bundle init


The contents of this file can then be populated to reference the two dependent gems:

source "https://rubygems.org"
gem "json","1.8.0"
gem "sinatra","1.4.3"


Download and install the gems locally by running the bundle command:

bundle


Next, create a Ruby script named webapp.rb in a directory named bin:

mkdir bin
touch bin/webapp.rb


Edit this file and add the Ruby code to create the web application, as shown in Listing 1. The code includes the two gems referenced earlier, and it creates a web application class that responds to two URL paths.

require 'sinatra'
require 'json'

class Hiwar < Sinatra::Application
   get "/" do
      "<h1>Hello World</h1>"
   end

   get "/json" do
      content_type :json
      {:greeting => 'Hello', :audience => 'World'}.to_json
   end
end

Listing 1

Next create a config.ru file that will be used as the entry point for running a Sinatra web application:

touch config.ru


Add the required libraries along with a command to kick off the web application server:

require 'rubygems'
require 'bin/webapp'

run Hiwar.new


Package the application.
Use Warbler to package the Ruby code in a JAR file:

gem install warbler


Create a configuration file to list gem dependencies that are intended to be packaged:

mkdir config
warble config


Replace the contents of config/warble.rb to indicate which directories and gems should be packaged in the WAR file:

Warbler::Config.new do |config|
   config.dirs = %w(config bin)
   config.gems += ["json",
 "sinatra"]
end


Run the warble command to create the actual WAR file:

warble executable war


Use the standard Java SDK jar utility to view the contents of the newly created WAR file:

jar tf testwebapp.war


Deploy and run the application.
The newly created WAR file can be deployed to an existing, previously installed web application server. The server is outside the web application at the time of development, so initial deployment involves accessing a web page, running a utility, or simply copying the file. Tomcat, for instance, can be installed at an arbitrary location. In the example below, the CATALINA_BASE environment variable can point to a directory such as /opt/local/apache-tomcat-6.0.18.

Easy to Port

During the initial phases of a project, it might be preferable to use scripting languages specifically geared for programmer productivity. By using JVM implementations, a project written in one language can be ported more easily to another, if needed at a later point.

The server can be started by running a script, for example:

$CATALINA_BASE/bin/startup.sh 


The archive can be deployed by copying it to the required directory:

cp testwebapp.war \
$CATALINA_BASE/webapps/


With the application running, you can use a browser or a utility such as curl to execute requests at the two configured URLs:

curl http://localhost:8080/json
curl http://localhost:8080/


The WAR file is packaged in such a way that it can be run using an embedded server. The server is inside the web application during development and deployment.

java -jar testwebapp.war


There are limitations to including a server inside the application. For example, any change in configuration will require an entirely new build and deployment cycle. Instead, the server can be deployed alongside the application using Jetty Runner, as shown in Listing 2.

Learn More


 Ruby programming language

 Warbler: A gem to make a Java JAR or WAR file out of any Ruby, Rails, or Rack application

Note: The following command has been broken into multiple lines for readability. It must be executed in a single line.

curl -O http://repo2.maven.org/maven2/org/mortbay/jetty/
jetty-runner/8.1.9.v20130131/jetty-runner-8.1.9.v20130131.jar

Listing 2

Jetty Runner is an independent JAR file that can be upgraded or configured without the need to change and repackage application code, as shown in Listing 3.

java -jar jetty-runner-8.1.9.v20130131.jar testwebapp.war 

Listing 3

Conclusion

It is difficult to predict the future in any realm of life. A software project can span years of time, be developed by teams of developers, and be used by a broad audience of users. The specific purpose of an application can vary significantly as a business pivots or changes focus. The amount of web traffic an application gets or changes in the development team can affect technical and deployment needs.

The JVM is an effective piece of technology that provides a wide range of options for subsequent growth due to its cross-platform, multilanguage support. This flexibility, along with the established standard of using WAR files for web application deployment, reduces the need to attempt to predict how a web application will fare in the future, freeing you to focus on more-pressing business and technical concerns at hand.


saternos



Casimir Saternos
is a software developer, software architect, and the author of Client-Server Web Apps with JavaScript and Java (O’Reilly Media, 2014). His articles have appeared in Java Magazine and on Oracle Technology Network.