My Adventures into REST with Java, Jetty, JRebel, Jersey, Maven, and IntelliJ

Okay, so last week I read through this book on REST in practice by Ian Robinson. It was a real eye-opener. The book goes through CRUD services and then takes it a step further by using AtomPub for collections and history tracking for implementing a publish-subscribe protocol. I originally passed of the idea as stupid or not worth looking into, but I gave that section a go and have been converted. I have been tasked with redoing the service (now seen as resource) architecture for another project and was wondering how I could get it done most effectively.

I was first very reluctant to do the research wondering what was wrong with traditional SOA and SOAP. Briefly put, there is nothing wrong with it, but there are nicer ways to achieve simple things which are more redundant to change and extension. The way proposed in the book really fits an agile development approach better. During my research into how to do things the easiest way, I was questioning everything, even the value in using certain libraries.

After much consideration and discussion, the following POC was put together:

  • IntelliJ IDE: JDeveloper 10g is really starting to age quickly and I have experience with eclipse. I have also heard amazing things about IntelliJ, hence the decision to use this IDE for the POC.
  • Jetty Webserver: It can be embedded into the test code, boots REALLY  fast and is broken down into only the components you need, very lightweight.
  • JRebel plugin: I hate having to wait for redeploys to servers, or packaging of EARs or WARs for deployment and then going through the process of deploying for each change. Stopping and starting servers is also not on!
  • Jersey REST: I was reluctant to use it at first, but after reading the REST in Practice book, I decided to give it a go and now truly understand how much it actually does for me. It is not just URI templating.
  • Maven: Once again, was not a decision to be taken likely, but Jersey and Jetty both make heavy use of maven and the integration with IntelliJ is phenomenal.

Configuring IntelliJ

This is the easiest step. Firstly download IntelliJ and install it. It is a licensed IDE, but you can test it out for 30 days. Mine has 4 days left on the trial. I went with all the standard options for the IDE as I was testing it out. I did make sure that I had the J2EE stuff enabled though. You will see loads of options that can be set, feel free to fiddle.

Configuring JRebel

There is no separate install for JRebel. You can get the plugin by installing via the plugin manager within the IDE. There are literally loads of plugins to choose from, but we are only interested in the JRebel plugin. Once again you will have to register for a JRebel license. It too has a 30 day trial and you should get one, this is by far the coolest thing here. My license expires in 5 days.

Configuring Maven

There is really nothing you need to do here except start a new Maven module in IntelliJ.

You should then be starting with the following blank project

Now I know that you can create the projects from archetypes… this is how I went about it.

Configuring Jetty

The largest difficulty I had was actually figuring out how to get all the correct modules for Jetty. Also I was not really familiar with Maven, so it took some time to find out where to get everything. The documentation for Jetty is good, if you can find it. Also, my needs were very specific. I did not want to run Jetty using maven to start it. I wanted a main method that would boot a simple server that would read a web.xml for its configuration, to get the web.xml – I right-clicked on the project and added framework support for a web application.

I found out where you can get the information for dependencies in maven at mvnrepositories and here is the page for maven Jetty dependencies. If you include the following into your pom, IntelliJ will tell you that the modules do not exist and ask if it can import them.

The reason I am not providing the textual representation, is that these version will become outdated and you should learn to use the mvnrespository to get your dependencies. It really does make life easier, so why the four dependencies?

  • jetty-server is the bare bones and allows you to host html pages
  • jetty-webapp is the module I included to allow me to configure jetty with a web.xml file, which should be easier to migrate between servers, as nothing is specific to jetty in this POC.
  • jetty-servlet was required for me to test the basic servlet case to know that I actually configured jetty correctly, it is also used for Jersey as we shall shortly see.
  • jsp-2.1-glassfish was more of me being pedantic than anything else. I configured my web.xml to have a welcome page which was a jsp and not html and was irritated that there was no support for it in jetty. The initial included module I used did not work, this one does.

The nicest thing about jetty is that, if you want extra functionality, all you have to do is include the dependencies and you will have it when you next boot the server. No configuration necessary besides the include. The added bonus is that IntelliJ handles all of this really neatly through highlighting libraries in your pom that are not there and, with your permission, auto acquiring them.

Configuring Jersey

Lastly, here is the jersey information in the pom.

Should be self-explanatory, the jersey-json module is included because I still want to test the application/xml, application/json auto conversion when using jaxb, as discussed at theserverlabs.com. The mvnrespository for Jersey has more modules you can include if you so wish. I have this repository linked in my pom, although I got it from the Jersey documentation, I do not think it is needed. I am just including it here for brevity.

Booting the server

There is a lot of documentation for embedding the server within code for quick development cycles. Here is the easiest configuration I found to work. I will not be packing the resources into a war when developing, it takes time, complicates jrebel, and all for no benefit.

public class StartJetty {
    public static void main(String[] args) throws Exception {
        Server server = new Server(8081);
        WebAppContext context = new WebAppContext();
        context.setDescriptor("web/WEB-INF/web.xml");
        context.setResourceBase("web");
        context.setContextPath("/");
        context.setParentLoaderPriority(true);
        server.setHandler(context);
        server.start();
        server.join();

    }
}

The base path when you run anything in IntelliJ is the project directory. Thus relatively you start referencing files from there (web.xml). I use port 8081 because there is a lot of competition for that port on my machine (8081 as well actually). I like to keep the embedded server with my test code, as it will not be deployed to production.

What is really nice is that IntelliJ automatically includes everything in the classpath for the classloaders to use without you needing to do anything, so separating it out is really easy. Now that you can start your server, how do you configure it?

Configuring by using the web.xml

Here is an excellent resource for reference on the web.xml file. Starting with the basics, let us configure the server to host a html page. The page needs to be in the root of the web folder for this configuration. Here is the snippet from the web.xml file to achieve this.

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>

And here is what is contained in the html file.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        ">
<html>
<head>
    <title>HTML Page</title>
</head>
<body>
<h1>HTML Page</h1>
</body>
</html>

Test the basic server is working

To test the basic jetty server module we will boot the server and go to the URI http://localhost:8081. You should see now how quickly jetty boots, even with the additional modules added. You should be seeing the following when you navigate to the URI.

Test the JSP module is working

Now to test that the JSP module we included for jetty is actually working. Change your web.xml file to look like this.

<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>

The JSP page code is the following and also in the root of the web directory.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>JSP Page</title>
  </head>
  <body>
  <h1>Index JSP Page WOOT! JSPs work!</h1>
  </body>
</html>

You will have to restart the server, as you have changed the config for the server, just kill it and start it again (there is an optimisation you can make here). You should be seeing something along the lines of this.

Your web directory should be looking something like this now.

Test the servlet module is working

So let us make sure that jetty can handle servlets before we try to even consider looking into jersey (it is actually easy). Here is some code for the simplest vanilla servlet you could write.

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/plain");
        resp.getWriter().println("hello world");
    }
}

We will want to register the servlet with the jetty server, so in the web.xml include

<servlet>
    <servlet-name>servlet</servlet-name>
    <servlet-class>avdw.HelloServlet</servlet-class>
</servlet>

And we want to give it a location, so also include

<servlet-mapping>
    <servlet-name>servlet</servlet-name>
    <url-pattern>/servlet</url-pattern>
</servlet-mapping>

If you were to restart your server now and navigate to http://localhost:8081/servlet, you should be seeing the following.

Test the jersey module is working

Now, we know that the jetty server works and can handle JSP pages and servlets. To allow it to handle jersey classes, we only need to register where to find the jersey classes (which represent resources), notice that the init-param is the packages where the jersey classes sit.

    <servlet>
        <servlet-name>jersey</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>avdw</param-value>
        </init-param>
    </servlet>

And then we map the jersey container to a context path, enabling us to access it

<servlet-mapping>
    <servlet-name>jersey</servlet-name>
    <url-pattern>/jersey/*</url-pattern>
</servlet-mapping>

Which allows us to now run the jersey resources. So given the following HelloResource jersey class

@Path("/hello")
public class HelloResource {
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String sayHello() {
        return "Hello World PLAIN text";
    }

    @GET
    @Produces(MediaType.TEXT_XML)
    public String sayXMLHello() {
        return "<?xml version="1.0"?><hello> Hello World XML, YAY!!!</hello>";
    }
    @GET
    @Produces(MediaType.TEXT_HTML)
    public String sayHtmlHello() {
        return "<html><title>Hello World HTML</title><body><h1>Hello World HTML JRebel Rules!</body></h1></html>";
    }

    @POST
    @Consumes({"text/xml", "text/plain", MediaType.TEXT_HTML})
    @Produces(MediaType.TEXT_PLAIN)
    public String sayPostHello() {
        return "Hello World Post!";
    }
}

Which is located in the following package structure

When you run the server and navigate to http://localhost:8081/jersey/hello, you should be seeing…

Notice that in the logs, jetty only checks the package for resources when you load the URI for the first time and then collects what is running there and does the mappings, and then it caches the information. Also, notice that it does not pick up the servlet and thus does not serve the servlet as well.

Everything configured!!!! Not quite yet, there are some other things that make this POC very efficient for developing.

Speed up development with JRebel

You still have to restart the server for each change you make to the classes, JSP’s, and I think the HTML files. However, instead of booting the server with the normal [run/debug] commands, boot it with the JRebel [run/debug] commands. What JRebel does is identify which files have been changed when you build the whole project, or when you build a single file, and will hotswap the file in the JVM with the newly compiled file. Thus, instead of

  1. Spelling mistake fixed or debug statement inserted
  2. Compile change
  3. Kill server
  4. Start server
  5. Refresh page

All you have to do now is

  1. Fix spelling mistake, or insert debug statement
  2. Compile change [ctrl+F9]
  3. Refresh page

Try it! It is a huge boost in productivity. Especially for small changes, you will compile and refresh more often and identify bugs sooner, instead of developing for longer without deploying to avoid the time that is wasted and potentially introducing various bugs, where you struggle to identify them because you did so many things.

Testing with the RESTful service tools in IntelliJ

There is a built in tool for testing RESTful services in IntelliJ. Here is a screenshot of it and it can be found at Tools->WebServices->RESTful Web Services->TEST RESTful Web Service

Results

Let us quickly review what has been done here:

  1. First we installed IntelliJ & JRebel
  2. Configured Jetty & Jersey
  3. Configured our Jetty Server with a web.xml
  4. Made sure our embedded Jetty server was working correctly
  5. Tested JRebel and Jersey

The way forward from here is to actually write the RESTful service. The work progression would be to only implement what is needed on the resource for when it is needed. To understand more about RESTful services, I highly recommend reading the book REST in Practice.

To give you an idea of how the test REST client in IntelliJ can benefit you, remember that in our HelloResource there were three methods mapped to the GET verb. Watch what happens when we configure the request header’s Accept parameter (here is the full RFC2616 of the HTTP/1.1 header).

text/xml

text/html

OPTIONS

Making small changes can be executed in lightning speed with a simple compile and refresh with this configuration. If you do not believe me then try it, if you have a better way, then please let me know! I am eager to learn.

EDIT: to get Jersey working with json

I have since gotten jersey to work with POJO conversion to JSON. Once you have included the library, as shown above, you will have to update the web.xml to have this init parameter.

    <servlet>
        <servlet-name>jersey</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>avdw</param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>
    </servlet>

After which you can just set the return type to be a POJO and say that it produces json.

public class StartJetty {
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public LinkVO newAttempt(AttemptVO attempt) {
        return new LinkVO();
    }

 

Downloads

IntelliJ Project: POC-JettyJRebelJersey

 

  • http://arhipov.blogspot.com Anton

    Cool story!
    With the Jersey plugin turned on from JRebel you should be able to add new resources on the fly also.

    • Andrew

      I can do this, the only problem I have is with the configuration of Jetty with Jersey. I configure everything with the web.xml which is fine. So when Jetty starts, it configures itself and when I run the first servlet things are great. The problem is that if I change annotations, create new methods, change method structure at all, then JRebel reloads the class, but not of the config in Jetty happens.

      The crux of it is, once I have the structure of how things are going to be configured and my input, output defined and setup, then JRebel works like a dream when debugging and doing changes internal to the methods. Before that, during the setup phase, JRebel is a bit sketchy.

  • Rajan

    Great one! Actullay this one solved my problem of rest and embeded jetty

    • http://www.avanderw.co.za/ Andrew van der Westhuizen

      I am glad that this worked for someone other than me. Thank you for taking the time to respond with your success.

  • Shawn

    Thanks for this. Very helpful. I followed your path but using Scala and used an annotation for the hello servlet.

    • http://www.avanderw.co.za/ Andrew van der Westhuizen

      How is Scala and do you have any experience with Groovy? Two scripting languages I intend to look into after some Django.

  • Kinisoftware

    Great post! :)

    I found your post yesterday while googling about Jetty and IntelliJ. I have a problem with booting my Jetty server from Java class (as you did https://gist.github.com/kinisoftware/5607277) because of “src/main/webapp” path. Everything works fine using “/” but I need to use “src/main/webpp” in order to keep maven test goal working too.

    I am not able to configure IntelliJ 12 in the correct way in order to achieve what I want. I supposed I have to change the web resource directory in the project structure what nothing worked at all.

    Thank you in advance! 😉

    Cheers!

    • http://www.avanderw.co.za/ Andrew van der Westhuizen

      I think I had a similar issue when using

      WebAppContext webAppContext = new WebAppContext(“src/main/webapp”, APP_NAME);

      Which is why I think I specifically set the descriptor and resource base separately e.g.

      WebAppContext context = new WebAppContext();
      context.setDescriptor(“web/WEB-INF/web.xml”);
      context.setResourceBase(“web”);
      context.setContextPath(“/”);

      Resource base is which folder is hosted and the context path is configuring the URL that serves that folder.

      • Kinisoftware

        Worked! :) Thanks a lot!

  • Mayank

    Thank Your for such a great explanation. I am trying to setup this environment but while starting the server I get this error, and following is my Pom file. I am stuck with this for last 4 hours, please tell me if you know what’s going on here. Thank You So much
    —-

    Connected to the target VM, address: ‘127.0.0.1:53481′, transport: ‘socket’
    Exception in thread “main” java.lang.SecurityException: class “javax.servlet.HttpConstraintElement”‘s signer information does not match signer information of other classes in the same package
    at java.lang.ClassLoader.checkCerts(ClassLoader.java:944)
    at java.lang.ClassLoader.preDefineClass(ClassLoader.java:658)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:786)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    Disconnected from the target VM, address: ‘127.0.0.1:53481′, transport: ‘socket’
    at mayank.StartJetty.main(StartJetty.java:16)

    Process finished with exit code 1

    ———————Pom file———

    org.mortbay.jetty
    jsp-2.1-glassfish
    9.1.02.B04.p0

    org.eclipse.jetty
    jetty-server
    9.0.5.v20130815

    org.eclipse.jetty
    jetty-servlet
    9.0.5.v20130815

    org.eclipse.jetty
    jetty-webapp
    9.0.5.v20130815

    com.sun.jersey
    jersey-server
    1.17.1

    com.sun.jersey
    jersey-servlet
    1.17.1

    com.sun.jersey
    jersey-json
    1.17.1

    • http://www.avanderw.co.za/ Andrew van der Westhuizen

      This happens when classes belonging to the same package are loaded from different JAR files, and those JAR files have signatures signed with different certificates – or, perhaps more often, at least one is signed and one or more others are not (which includes classes loaded from directories since those AFAIK cannot be signed).

      So either make sure all JARs (or at least those which contain classes from the same packages) are signed using the same certificate, or remove the signatures from the manifest of JAR files with overlapping packages.

      http://stackoverflow.com/questions/2877262/java-securityexception-signer-information-does-not-match

    • http://www.facebook.com/hrishikesh.kumar.mishra Hrishikesh Mishra

      I am facing same problem.