Java 8, Tomcat 8, and RESTEasy on Mac OS X

The main idea for this blog post was using the Mac, for quickly developing and deploying a Web app in Java. I’m using RestEasy on top of Tomcat as my server platform and Intellij IDEA as my preferred IDE. Once the webapp has been built and tested locally, IDEA is also used for archiving the webapp and remotely deploying it to a Linux box.

RESTEasy is used to build a simple wrapper, exposing the implemented functionality as Web Service, but without having to modify the core implementation and to keep it independent from all Web-Service related resources.

So let’s get started.

1. Java 8

1st stop is at Oracle.com, to pick up the latest Java 8 JDK. As I’m writting this, Java SE Development Kit 8u5 downloads as jdk-8u5-macosx-x64.dmg into my ~/Downloads folder.
Opening the dmg file and running the installer, copies the Java VM and Runtime into

and to make sure that this new Java version is used, I’m editing the hidden

file (TextMate for instance, will edit this file, if you enter mate ~/.bash_profile). The line that needs to go into bash_profile should look like this:

and after closing and re-opening the terminal, java -version should respond like so:

2. Tomcat 8

Next stop is Apache.org, to pick up the latest Tomcat distribution. The current version for Tomcat is 8.0.8 and I’m downloading the Binary Distributions – Core tar.gz file.
The next few steps include uncompressing the archive, followed by moving its files into /Library/Tomcat, and changing their ownership and permissions.

(I have written in much more details about those steps here.

Now it’s time to install Activata’s Tomcat Controller, a tiny freeware app, providing a UI to quickly start/stop Tomcat. Launch it, but click the Start button only after entering /Library/Tomcat for its Tomcat Home Directory preference.
Clicking View loads Tomcat’s default home page in your browser.

Almost done with Tomcat. Let’s just fix some settings, while we are here. To access Tomcat’s manager-gui and admin-gui, a username and password need to be entered into /Library/Tomcat/conf/tomcat-users.xml

If the Mac is your development or staging server and you also have a remote production server, you want to change its conf/tomcat-users.xml file as well and also make some changes to its conf/server.xml file, but more about this later.

3. RestEasy

Next stop is RestEasy, a JBoss project that provides various frameworks to help you build RESTful Web Services and RESTful Java applications. RestEasy’s current version is 3.0.7, a 44MB download, go and get it.
Fortunately, we won’t need all of it. Uncompress the zip archive and keep it at a safe place for now. For me that is ~/MyRepo/resteasy-jaxrs-3.0.7.Final

4. Java App and Web App

Now, I’m launching IntelliJ, arguably the best IDE for Java development, and create a new Empty Project, naming it Easy. Before adding any modules, I’m setting the Project SDK to 1.8. Next comes the creation of two new modules inside this still empty project.

  1. A Simple Java (not EE) Java application module, I named MyApp
  2. A Java EE Web Application Project, I call MyWeb

4.1. Java Application Module

The simple Java application I’m going to write is just a simple Dictionary, exposing this functionality:

  • lookup word – returns its meaning
  • enter word, meaning – enters a new entry into the dictionary
  • delete word – removes an entry from the dictionary
  • content – returns the complete dictionary
  • serialize – returns the complete dictionary, json-encoded

 

The serialization into JSON is mainly to have at least one dependent module library. In this case, I’m using Richard Hightower’s wickedly fast boon json parser. I created a lib folder inside the module, copied the boon.jar into it, and finally added it as a module dependency.

4.2. Web Application Module

Moving on. Let’s work on the Web Module. Again, I’m creating a lib folder inside the module, and copy the following jars from the RestEASY project:

  • commons-logging-1.1.1.jar
  • jackson-annotations-2.3.2.jar
  • jackson-core-2.3.2.jar
  • jackson-core-asl-1.9.12.jar
  • jackson-databind-2.3.2.jar
  • jackson-jaxrs-1.9.12.jar
  • jackson-jaxrs-base-2.3.2.jar
  • jackson-jaxrs-json-provider-2.3.2.jar
  • jackson-mapper-asl-1.9.12.jar
  • jackson-module-jaxb-annotations-2.3.2.jar
  • jackson-xc-1.9.12.jar
  • javax.json-1.0.3.jar
  • javax.json-api-1.0.jar
  • jaxb-api-2.2.7.jar
  • jaxrs-api-3.0.7.Final.jar
  • resteasy-cache-core-3.0.7.Final.jar
  • resteasy-jackson-provider-3.0.7.Final.jar
  • resteasy-jaxb-provider-3.0.7.Final.jar
  • resteasy-jaxrs-3.0.7.Final.jar
  • resteasy-jettison-provider-3.0.7.Final.jar

All these jars need to be added as module dependencies (scope is compile). Moreover, the /Library/Tomcat/lib/servlet-api.jar (located in Tomcat’s lib folder) needs to be added as a dependencies as well, but here, the provided scope is used, so that it’s not deployed with the web-app. While still in the UI for setting up all these dependencies, I’m adding the MyApp module as a Module-Dependency to the MyWeb module.

Here is the RedHat/JBoss documentation for RESTEasy – currently for JBoss Enterprise Application Platform 6.3.

The idea for the next step is to expose the Dictionary as a WebService, with little effort, but also without having to modify the Dictionary class, which ideally should remain independent from all Web-Service related resources. So we simply build a small wrapper:

4.2.1. The JAX-RS application class publishes our REST services to the runtime

4.2.2. The service class wraps each Dictionary method

The service can expose the same Dictionary to all users or maintain a different one for each user.

The content() method shows how a dynamically generated JSON – File could be returned.

4.2.3. The Deployment Descriptor

At this point, application and web module are done and the project structure in IntelliJ IDEA looks something like this:

The configuration screen for the “Artifact MyWeb:war exploded” in IntelliJ IDEA looks something like this:

5. Run/Debug Configuration

The Run/Debug configuration, on the Server tab, selects Tomcat 8.0.8 as the Application Server.
And on the Deployment tab, /service is entered as the context. I.e.
http://localhost:8080/service will be the URL to access this web app. In the deployment descriptor (web.xml) /dictionary/* was mapped to dispatch the MyApplication. Therefore: http://localhost:8080/service/dictionary/phoenix would be the URL to find the meaning for ‘phoenix’ in the dictionary.

With all this configured, Tomcat can now easily be started in the RUN or DEBUG mode and new entries can be posted into the dictionary or meaning can be retrieved with GET request.

6. Remote Deployment

To deploy the web app on a remote Tomcat instance, instead of or additionally to locally, a few configuration changes are necessary on the remote end.
I downloaded the “JMX Remote jar” from Tomcat’s distribution site (look under Extras) into the remote server’s tomcat/lib directory.

Tomcat’s conf/server.xml file needs to be edited and the following listener needs to be inserted:

Then I added the following line close to the top into tomcat’s bin/catalina.sh file.

JAVA_OPTS="-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=1099
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.local.only=false
-Djava.rmi.server.hostname=192.168.200.16"

Additionally, like aforementioned, the conf/tomcat-users.xml may need to be edited as well.
Finally, if the remote server has firewall rules deployed, then those need to be adjusted, for instance like so:

#JMX
-A INPUT -m state --state NEW -m tcp -p tcp --dport 10001 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 10002 -j ACCEPT
#Tomcat HTTP
-A INPUT -m state --state NEW -m tcp -p tcp --dport 8888 -j ACCEPT

With all these changes applied, the remote JMX capabilities of Tomcat can now be tested from a client laptop, by launching jconsole from a terminal end entering the following connection string under remote process: service:jmx:rmi://(hostname):10002/jndi/rmi://(hostname):10001/jmxrmi

Back in IntelliJ, I create a new Artifact for MyWeb module. The same as the one that is already there, but this time is a WebApplication Archive (and not exploded). On top, I replace the current name ‘MyWeb:war’ with ‘service’, which matches the context name.

6.1. Remote Run/Debug Configuration

So only thing missing is the Run/Debug configuration for the remote server. The important thing here is to declare how files are being deployed (in my case that is sftp) and the JMX port to tell Tomcat about a new app, starting it, etc.

And on the Deployment tab, the service artifact is deployed into ‘/’ which on Tomcat will create a context named ‘service’.

 

Leave a Reply