Archive for February, 2010

Why won’t my span respond to click events? Strings vs. DOM elements

I had another fun opportunity to work on a web app (I’ve been doing a lot of them lately) over the last week. This time I built on my recent JSON experience by writing a Rails app that only communicates in JSON. Rather than have the output built using Rails views the output is sent as JSON to a JavaScript client in the user’s web browser.

Once in the web browser, the data has to be parsed and split up into different sentences based on what the user wants to do with the data.  Once the data is split into sentences it’s appended to divs that show the sentences in the web browser.  Some of these sentences have to be clickable, they must respond to a “click” event coming from the user.  This is completely ordinary in most JavaScript web apps.  The user clicks, the browser responds.  Imagine my surprise when my sentences weren’t responding to the click input.

I wasn’t surprised for very long, however.  By looking at how I prepared the sentence in the JavaScript code made it pretty obvious what was going on.

data[index] = data[index] + ". <span class=\"my_class\">" + choices[choiceIndex++] + "</span>";

This created the sentence that was to be clickable. It’s just string data that creates a span with a class. This is something jQuery can find by doing $(“.my_class”). Once I have all the spans with that class I can add a click event to them. Well, that’s true, but those spans have to be DOM objects before jQuery can find them.

The way I was doing it, those spans were just string data. Sure, the browser displayed them with the correct style but jQuery was unable to find them because they were not internalized as DOM objects. Opening a JavaScript console with Google Chrome would allow me to run the same code to make the spans respond to click events and it would actually work. Chrome’s console reads the DOM after the page has been rendered and creates the DOM objects based on the rendered page when the spans are in place. This is no good to me. I can’t tell my customer to tell his customers to open a JavaScript console and run this cryptic command after loading the page.

In order to get the behavior we want we have to create DOM objects using jQuery so jQuery can then find these objects to add the click behavior to them. Rather than creating spans as string data we use the jQuery function to create a DOM element with the correct class and text.

elm = $("<span class=\"my_class\">" + choices[choiceIndex++] + ". </span>");
elm.click(function(){
                  alert("Hey! You got the right answer!");
                  document.location = "http://localhost:3000";
                });

The jQuery function, $( ), first looks for elements based on the class, id or attribute selector passed in to it. If there is no selector then the function looks for any tags in the string passed in to it. If there are tags, in our case span tags, jQuery creates the appropriate DOM element based on the content of those tags! This is great! Now I can pass in my string data and have jQuery return a DOM element that I then bind to the click function specified.

Adding the click function later also works now.

$(".my_class").click(function() {
                  alert("Hey! You got the right answer!");
                  document.location = "http://localhost:3000";
                });

I’m happy with the way I can build a DOM element using the jQuery function. In order for jQuery to find the objects we look for those objects have to be DOM elements, not just string data appended to a div. DOM elements respond to events, strings do not.

User authorization in RESTful Spring

I’m having a lot of fun with the new RESTful features in Spring 3.0. I’m sure you could tell by the number of RESTful Spring posts lately.

Last night I wrote a user authorization interceptor that makes sure there is a user associated with each resource request that requires it. I’m structuring most of my new web apps in such a way that user authorization is required for almost all actions.  I had to make a choice of how to enforce user authorization in the app.  The two choices were between a Servlet filter and a HandlerInterceptor.

A Servlet Filter is part of the Java EE Servlet package.  Most of my Java web projects use Servlet Filters in some way so I wasn’t immediately opposed to using one to make sure there is a logged in user associated with a request.  Because I wanted possible errors to be properly rendered in my different view types using Spring I decided to use a HandlerInterceptor.

A HandlerInterceptor is a Spring interface that is pretty much analogous to a Servlet Filter in terms of structure, though it’s a little more focused in purposed.  The HandlerInterceptor is mostly concerned with text-based content, where Filters can be applied to any content type.  Filters are also more appropriate for setting headers and gzipping responses.  The Handler Interceptor is targeted for application logic.

This interceptor only checks to see that there is a user object associated with an resource request before passing it on to the handler (a controller).  In practice this may include more detailed authorization checks but for the example just checking for a user is fine.

@Component
public class UserAuthorizationInterceptor extends HandlerInterceptorAdapter {

  private static final String UNAUTHORIZED_MSG = "You are not logged in.  You must log in or supply an API token.";

  @Override
  public boolean preHandle(HttpServletRequest request,
                        HttpServletResponse response,
                        Object handler) throws Exception {

    String uri = request.getRequestURI();
    User user = (User) request.getSession().getAttribute("user");

    if (user != null || uri.indexOf("login") != -1) {
      return true;
    } else {
      response.sendError(HttpServletResponse.SC_FORBIDDEN, UNAUTHORIZED_MSG);
      return false;
    }
  }
}

Initially I wanted any error messages to be rendered by my Atom, RSS and JSON views. Any error message generated by the application should come back to the user in the requested data format. But this is a RESTful app. The REST philosophy already addresses the only error message that should come out of an authorization check with HTTP status codes. The only error message that should come out of this interceptor is an “unauthorized” message. HTTP supplies the 401 status code to indicate a user is unauthorized.

The implication of using the 401 code is that the user should use HTTP authentication, either basic or digest. That’s not appropriate for an application using OpenID and API tokens for user authentication. Instead the 403 status code is more appropriate. This means the client is forbidden from accessing the requested resource. The server understood the request but the client is not allowed to access the resource, which is exactly the case when there is no logged in user associated with the request.

Because HTTP already provides plenty of status codes for things that can go wrong we should rely on those codes when building RESTful applications. There is no reason to supply an application-generated error message when the protocol supplies everything we need to deal with the problem. The REST philosophy actually makes it much easier to write web apps because we’re using HTTP as it is intended to be used which takes a lot of responsibility off of our application code.

Spring 3.0 Web MVC and JSON

Over the weekend I got a chance to use Spring 3.0′s MappingJacksonJsonView and ContentNegotiatingViewResolver. I’m very happy with how easy it was to integrate with my code. I didn’t have to do very much at all to get JSON out of my web app.

Why would I want JSON out of the app instead of HTML?  Interoperability is one reason.  Now instead of being bound to one web app, my own, my data can be shuttled to other apps in a commonly understood notation without screen scraping.  Of course we can also use Atom and RSS for data that can be massaged into those formats with the ContentNegotiatingViewResolver as well.  For stuff that can’t coerced into standardized XML, JSON is a great choice.

If you don’t know what JSON is, it’s basically a JavaScript text representation of a map that drills down into your object hierarchy if you have one. Let’s say I want to get my user information. The JSON representation is:

{ "firstname":"Anthony", "lastname":"Chaves", "userid":"123456", "address":{ "street":"A Fake Street", "city": "Bradford", "state":"MA" } }

This JSON is valid JavaScript and parsed by the library of your choice. The first three fields are just string data. The address field is another map that contains data about my address. This is produced because my Java class User has a field of class Address. Address contains the street, city and state fields.

To get the JSON output we should use a MappingJacksonJsonView. This view uses the Jackson library to map our Java objects to JSON. We need the Jackson core and mapper jars on our classpath to make this view work. I just copied them into my WEB-INF/lib directory.

It should be noted that I could not get any combination of configuration and Jackson jar files to work using Glassfish 2.1.1. Deploying the app failed due to a java.lang.VerifyError with the message “Cannot extend a final class.” Duh. The same app worked right from the start on Tomcat 6.0.24.

Because we want to preserve the functionality of the web app and its HTML output we can’t cut out the UrlBasedViewResolver completely. We want the app to function as normal when we get requests for .html files but return JSON when we get requests for .json files. So user.html would be used to get the HTML output of a user page and user.json would be used to get the above JSON output for a different app.

Spring 3.0 has a ContentNegotiatingViewResolver that does just this. Based on the client accept header and the file extension, this view resolver determines the best view resolver to pass the request on to after the controller does its processing.

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
  <property name="mediaTypes">
    <map>
      <entry key="html" value="text/html"/>
      <entry key="json" value="application/json"/>
    </map>
  </property>
  <property name="viewResolvers">
    <list>
      <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
      </bean>
    </list>
  </property>
  <property name="defaultViews">
    <list>
      <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
        <property name="prefixJson" value="true"/>
      </bean>
    </list>
  </property>
</bean>

For text/html content the ContentNegotiatingViewResolver sends requests on to the old UrlBasedViewResolver after the controller method returns. For application/json or application/javascript requests the ContentNegotiatingViewResolver passes the request on to the MappingJacksonJsonView. This view parses the object tree into JSON and gives us the output we want.

The object tree is based on the objects in the Spring Web MVC model. This means we have to add them to a ModelMap object in the controller. In an HTML-based web app we might store data in the HttpSession object. For JSON we need it in the ModelMap. Let’s say we’re adding a tag to something.

@RequestMapping(method=RequestMethod.GET)
public String getBookmarksWithTag(@RequestParam(value="tag") String tag, HttpSession session, ModelMap model) {
  User user = (User) session.getAttribute("user");

 doSomethingUseful(user);

  model.addAttribute(user);
  return "tags";
}

By placing the User object into the ModelMap, Spring has a reference to it when it comes time to make some JSON. We still return a string, “tags”, so the UrlBasedViewResolver still returns the same jsp for text/html content. After this controller method returns, Spring takes the result and sends it to the ContentNegotiatingViewResolver. The “tags” return value is not used if the request is sent to the MappingJacksonJsonView. It has no use for jsps. If the request were for text/html the “tags” string would be used by the UrlBasedViewResolver.

Like I said, I’m happy with the new REST support in Spring 3.0 Web MVC. It’s certainly lagging behind Rails in trendy features but it’s far more flexible overall. There is a certain “style” to writing web apps that Rails guys have. I’m convinced it’s just as easy to use this style in Spring as it is to do it in Rails but the huge amount of extraneous documentation and classes in Spring makes it more difficult than it should be to get down to business. I’m not making a statement about the Spring framework itself, it’s certainly possible to do everything I want and need. I just haven’t seen a good style guide or cookbook for RESTful web apps. Maybe it’s because some of the features are still so new, being just added to the 3.0 branch. Maybe we just haven’t found the right idioms yet.