Sunday, January 25, 2015

Implementing Rails with Java and Jersey

Overview


The code for this little diversion has been submitted to github at: https://github.com/broadbear/login. Is is somewhat raw, with plenty of TODO's still present throughout. The intricacies of the code are not detailed in this article, however, if you are familiar with Rails conventions, you should be able to find your way around my code.

I have been developing a new user login model for my web apps. I am at somewhat of a crossroads as to what technologies to use. I was tempted to learn something new, like Node.js, or Rails. Node.js interests me as a technology, as it represents a full JavaScript stack for webapps, and might be a revolutionary concept in itself. However, Rails is hugely popular in the start-up community, so I started tinkering with that instead. Needless to say, I was amazed at how elegant Rails is. I have worked primarily with Java stack frameworks, such as Struts/2, Jersey, etc. As I went through the Rails Guides and the Rails Tutorial book, I couldn't believe how easy web development could be. I must admit, when I first heard of Rails' popularity, I thought it was a flash in the pan. I considered it somewhat limited and didn't think it would gain traction. I have heard mutterings of agreement with this perspective. Now I am left wondering why some would have it in for Rails. It is not at all limited, and is a breeze to work with.

It is possible that some in the Java community reject Rails because they do not know anything about it. One tremendous advantage of Rails is that it is a self contained ecosystem. With Java, you are left cobbling together libraries and plugins to accomplish a task. I used to think this was an advantage. You can access a vast universe of technologies to help you build your applications. However, it is quite common for some component to only accomplish part of what you need, or to break things altogether. With Rails, much functionality is bundled together with the core product, or accessible through highly vetted Gems. One case in point is rake and DB migrations. In Java, you are left seeking a solution to enable multiple developers to submit changes to a single DB instance. With Rails, this is built right in. I will touch on this in a subsequent section.

While I was quite taken with Rails, it still represented a considerable technological jump for me, and I wanted to continue to exercise my Java skills.

I like Jersey. It is Oracle's reference implementation of the jax-rs spec, and is a fairly simple little framework for developing RESTful API's in Java. I also discovered that it has the ability to return templated pages (html) instead of JSON or XML representations. This gave me the MVC ability that I needed to build out a complete web application as opposed to just a REST API. Having worked with Struts and Struts 2, I was pleased with Jersery's simple approach to MVC. It seems Struts is a framework built primarily to implement MVC. Struts 2 has JSON and REST plugins that allow you to create a RESTful interface, but they are still done in a Strutsy way. Jersey REST is very straight forward. Just create a method and annotate it with a path. The most difficult aspect of Jersey is its scant, poorly written, documentation and its somewhat raw API. Its MVC capabilities are extremely minimal in comparison to Struts. With this minimization comes simplicity. Any method can return a reference to a template (a Viewable instance), and a single 'model' instance. The model can be any bean. If you need access to anything else, you can stash it in the session, or any other scoped object floating around in the Servlets ecosystem. The Viewable can reference a few different template types, including JSP, which is interesting. It gives you another perspective on Servlets/JSPs. It left me wondering, how much functionality do you really need? Do the advantages of all the additional functionality of Servlets/JSPs, Struts, etc. outweigh the added complexity?

Rails excels at exemplary documentation. The Rails Tutorial is an amazing, free(ish) resource that steps you through building an almost fully functional user activation/login/reset implementation. This is something that can be applied to almost any web project. If nothing else, it is a terrific collection of requirements for user login that any web site needs. If you sat down to try to piece all of these use cases together from imagination or trial and error, you would certainly forget some things, and have to stamp out plenty of bugs.

Seriously? Every web framework should have a version of Rails Tutorial customized for their specific language and platform.

In addition, a lot of what makes Rails so pleasant to use is convention. The names of paths, controllers, view templates, and tables all follow a rigid convention that you can deviate from if you really want to.

So I had this idea. Why not go through the Rails Tutorial and attempt to build my webapp login apparatus in Java/Jersey? Sure, Java and Ruby are quite different, but perhaps I can benefit from attempting to adhere to their model, doing things in a Java way when required. In the end, even if I abandoned doing things like Rails/Ruby, at least I would end up with a user login interface that would enable users to activate accounts and reset passwords.

This article recounts some of my experiences during the process of implementing my user login interface using Java and Jersey (and Bootstrap, Gradle, Heroku, ...).

ActiveRecord


I have seen attempts to create objects that do too many things. This goes against my understanding of Software Engineering best practice. Basically, I have seen people create objects that represent a bean-like entity, and then add methods that perform operations on that entity. I don't like this pattern as it seems to violate separation of concerns. You end up with beans that contain a lot of additional code, and often nebulous methods that do things to or with that bean. This also differs from the well known Java Enterprise pattern, the DAO. With DAO, beans are essentially value objects, and the DAO abstracts the persist. Beans are fetched and stored via the DAO.

With ActiveRecord, the bean inherits from a super class that has methods that enable the bean to be created, saved, updated, deleted in persist. I was skeptical at first, but learned that this pattern was championed by none other than Martin Fowler of Refactoring fame.

As my persist is MongoDB, I implemented the ActiveRecord pattern with the MongoDB Java driver, and eventually incorporated Morphia to simplify interaction with the data store. I implemented generic create, save, etc... methods myself. This has gone well, but I doubt my code is flexible enough in its current state. As I continue, I foresee considerable more implementation of my ActiveRecord will be required. Instead I am pondering bringing Spring into the project and gutting the ActiveRecord code with JPA. JPA has concepts like relationships between entities built in. This is something also included with Rails' implementation, but my implementation will require additional development to support this as transparently as the others. JPA would also move me in the direction of separation of concerns comparable to DAO's with JPA's Repository concept.

Having errors stored in the ActiveRecord object is very neat. This way you can attempt to validate the ActiveRecord object, and return the object itself to the view as the model. If there are any validation errors, they are present in the object, and therefore through the model. This has proven to be a powerful convention that simplifies so much in comparison to Servlets/JSPs and even Struts.

Validation


Jersey provides some validation capabilities, however, Rails embeds validation in the ActiveRecord object. This enables the ActiveRecord instance to encapsulate the error collection so it is accessible through the model by the view template. Jersey validation is handled by annotations on the resource method and arguments of that method. This means validation occurs before the resource method is invoked, so errors need to be caught, and the proper view template managed in a different place. Instead of researching further into the resource life-cycle, I chose to implement a similar convention to Rails, and added Hibernate Validator to the save and updateAttributes methods of ActiveRecord. Hibernate Validator is essentially an implementation of JSR 349 - Bean Validation 1.1, and is what Jersey uses to perform its own validations. This was somewhat complicated as the API is somewhat dense, but I ultimately came to a decent solution. Validation is driven off of annotations on properties of a model class. Hibernate Validator also allows you to define your own annotations, including cross parameter validations.  This enabled me to create a 'Unique' annotation to ensure user defined ids are unique, and a 'Matches' annotation that ensures the password and password confirmation match. These seem like simple things to perform in code, but enabling the validation to occur in one step, and having errors propagated to a single collection really simplifies validation as a whole. With Hibernate Validator, errors are propagated to a Set of ConstraintViolations. I found ConstraintViolations difficult to instantiate, and the Set difficult to work with. Adding non-conforming validations, such as comparing two strings, to the validation step gets messy. While not as flexible as I would like, Hibernate Validator enabled me tuck validation away in approximately the same places as Rails, and to populate an error collection on the ActiveRecord instance. If errors are detected, the resource method can re-render the form, and errors can be detected by the view template and populated in the final result.

Routes


I basically lifted the crud URL templates from the Rails Tutorial. Routes are declared and managed in a separate Ruby file. In Jersey, Paths are defined by annotations on the class and methods. I quite like defining paths with annotations, so there is no complaint there. However, in Rails, these paths/routes are referenced via methods that seem to magically be available anywhere; in the controllers, even the view templates. This presented somewhat of a challenge in Java. My solution was to define a Routes class and have methods that return the the paths as Strings. The Routes class can also be stashed in the session, making it available to the templates. Usage is somewhat more gaudy than Rails, but having the routes retrievable this way helps standardize the paths you will inevitably reference throughout your application. I was able to unify path declaration inside the Routes class. Annotations accept constant parameters, and getter methods can perform some simple string replace on the path templates. These getter methods are callable from expression language (since Servlet 3.0), and thus are accessible from JSP view templates.

Rendering vs Redirecting vs ... JSON!


The Rails guide shows how easy it is to distinguish between returning HTML and returning JSON. I ran into some complications with Jersey, but nothing too terrible. Rails makes it easy to add a .json suffix to your path which you can decipher in your controller, and return a JSON representation as opposed to an HTML representation. Something like this can be done in Jersey, although, I had to resort to something akin to regular expressions in my path declarations, and ran into a naming conflict that I could only work around by adding similar regular expressions to resource methods that did not require them.

Rendering and redirecting is where Jersey gets a little vague. Jersey enables you to build up a Response instance. The problem with this is that it is too general. It can be difficult to figure out how to get it to do exactly what you need it to do when you need it done. There are some convenience conventions, such as being able to return a Viewable instance, or a bean instance, but these were too restrictive. I found it best to stick with Response return types, and work with the ambiguities of the Response object. This is one of the few areas where I felt the need to add code to the ApplicationController super class that all of my resource classes inherit from. This convention comes directly from Rails. I was able to wrap most of the Response building functionality in two methods, one for redirecting, one for 'rendering' and my code looks somewhat similar to the Ruby code in this respect. So far I have not needed much more flexibility than these two methods. This plus the ActiveRecord pattern has lead to some fairly concise code.

With good JSON serialization support via Jackson, you just have to return an object in the Response and it will be automatically serialized to JSON.

Here is some example code demonstrating the conciseness (with the path format regular expression to detect JSON return format):

@Path("users/{id}{format:(.json)?}")
@GET
public Response show(@PathParam("id") String id,
                  @PathParam("format") String format) {
    User user = User.find(User.class, id);
    if (StringUtils.contains(format, "json")) {
        return Response.ok(user).build();
    }
    else {
        return render("/users/show.jsp", user);
    }
}

You can see, retrieving a user is a single line of code, called with a param parsed from the path via an annotation. Another path param determines the representation type to be returned. If JSON is required, a simple Response is built passing the user instance as the entity. The user instance is auto-serialized into JSON via Jackson and added to the HTTP response body. If an html representation is desired, the 'render' method is called with the path to the view template and the user instance as the model. This is not quite as concise as Rails, but we are certainly approaching it.

Although Rails supports suffix content negotiation (appending the path with .json or other), I have read literature that discourages this (RESTful Web Services Cookbook). However, the reason cited in the literature may not be particularly relevant for most projects, and that is probably why Rails continues to support content negotiation in this way.

The Cookbook recommends supporting content negotiation via the Accepts header. The Jersey developers seem to agree. Jersey supports content negotiation via the @Produces annotation. When the choice is between XML or JSON, two media types can be included in an annotation, and the final representation format will be based on information in the request Accepts header. When there is a greater disparity between formats, such as JSON vs html, you can declare multiple methods with that same path annotation, but different @Produces annotations. The correct method will be selected based on information in the Accepts request header. The advantage to this form of content negotiation is that it is more formal, and Jersey parses the Accepts header for you. Parsing the Accepts header can be somewhat complicated. The downside is that the code becomes littered with more, albeit simpler, methods. Below is an example that converts the initial path based content negotiation code listed above to be driven off of an Accepts header:

@Path(Routes.USER_PATH)
@GET
@Permissions({"view-user"})
@Produces(MediaType.TEXT_HTML)
public Response show(@PathParam("id") String id) {
    User user = User.find(User.class, id);
    return render("/users/show.jsp", user);
}

@Path(Routes.USER_PATH)
@GET
@Permissions({"view-user"})
@Produces(MediaType.APPLICATION_JSON)
public Response showAsJson(@PathParam("id") String id) {
    User user = User.find(User.class, id);
    return Response.ok(user).build();
}

You can see the original method has been split into two separate methods that return different formats. If a request arrives with an Accepts header of 'text/html', the show() method will be invoked and an HTML representation added to the response. If a request arrives with an Accepts header of 'application/json', the showAsJson() method will be invoked, and a JSON representation added to the response.

The Flash


I added a Rails flash-like concept to the HttpSession that is easily accessible to Jersey resources as well as JSPs. This allows you to pass messages to pages after a redirect.

Permissions


Permissions are implemented in a centralized location, on the session helper, so they are accessible from resources as well as views. A Permissions annotation was created for use in the controllers, while permission checking is available to views directly through the session helper.

Additional topics


Rake is really cool. Managing DB updates on a team can be very tricky, especially with relational databases. On one project we used Liquibase, which somewhat reminds me of what Rails has included. With Rake, you can generate a 'db migration' script. The migration script is in a 'domain specific language' and not just SQL. This saves you from having to seek out a solution yourself and bolt it on to a project the way we did. Liquibase worked, but you had to create the scripts yourself, and you were writing in SQL, which limited your flexibility if you wanted to switch out the data store, even among different relational database types. And, if you didn't do the scripts just right, Liquibase wouldn't handle them properly, and your scripts might go ignored, or worse, irreparably break something. Having DB migrations integrated tightly with Rails is a very good thing.

Of course, with a schema-less data store like MongoDB, this is somewhat easier to manage, so I have gone without addressing this little aspect of Rails.

Code generation and scaffolding was pretty cool as well. A similar concept could probably be implemented with Java/Jersey as well, but it was not immediately necessary.

I haven't found a particularly elegant way of implementing Rails' before_action concept in the controllers. Rails enables you to define one or more a 'before_action' command in a controller, and declare what controller methods it applies to. This is basically how the author of the Rails Tutorial restricts method invocation to logged in, admin users, etc. With ActiveRecord, I just added some template methods in the base class that the subclass can optionally implement. With the resources (controllers), I initially attempted to implement them as filters attachable via an annotation. This may come in handy, for instance, with permissions, but it is not as concise as before_action in Rails. Filters actually added so much annotation 'noise' I decided not to use them and just repeated the code in each relevant resource method. I am assuming there could be some sort of solution in AspectJ or something, but this will come later as it is time to press on.

Future


I will need some way to internationalize. I am not sure of Jersey's support for this. This was well supported in Struts. I'm sure Rails has something as well.

Basically, when I started, I was like 'how will I do all this stuff with Jersey.' Following Rails Tutorial, I was able to tuck a lot of functionality away in nice little convention methods and classes that mimic Rails. There were some successes and some failures, but in all it is nice to have a structure imposed on my Jersey app that I can intuitively carry through the entire app. Is it a new framework? No, not yet. Could it be? Possibly. Java on Rails?

2 comments:

Christian said...

The Rails equivalent on Java would probably be Grails. With version 2.2+ you can do some pretty power stuff to expose and use rest with very little actual coding. I think if you want to work in the JVM with a Rails-like framework then Grails is a no-brainer. http://grails.github.io/grails-doc/latest/guide/webServices.html

broadbear said...

Thanks for the comment. I thought Grails might fill this space, however, they seem to have positioned Grails as 'a great framework based on this revolutionary new language, Groovy' instead of 'a superior Java stack where you'll have to pick up a little Groovy, but don't worry, you'll like it.' This somewhat alienates the Java crowd. I wanted to see if I could recreate some Rails-like conventions with familiar Java-based technologies.