the devil is in the details

2009.05.14

Handling Errors Using jQuery.load

Following on from my last post on integrating HTML content from another  system into an existing site, I realized I wasn't handling failures very gracefully. To recap, I was using the load method of jQuery:

$(document).ready(function() {
$('#races a').click(function () {
$('#results').load('Racing/' + $(this).attr('href') + ' #wrap');
return false;
});
});

I was surprised to find there wasn't much information about how to go about capturing an error if it occurs. It turns out you can get it by passing a callback function to the load function. This function accepts 3 parameters: responseText, textStatus and an XMLHttpRequest. I'm not exactly sure why they decided to give you responseText and textStatus when you have an XMLHttpRequest (an object that already encapsulates both of these values so passing them as parameters is a violation of the DRY principle).

Anyways, here is how to do it using the callback function:

$(document).ready(function() {
$('#races a').click(function () {
$('#results').load('Racing/' + $(this).attr('href') + ' #wrap', "", function(responseText, textStatus, XMLHttpRequest) {
switch (XMLHttpRequest.status) {
case 200: break;
case 404:
$('#results').html('<p>Looks like the results have not been uploaded to the server yet. Please check back later.</p>');
break;
default:
$('#results').html('<p>' + XMLHttpRequest.status + ': ' + XMLHttpRequest.statusText + '. Please contact the club and let them know.</p>');
break;
}
});
return false;
});
});

Now you can get specific about how you report your error based on the response code. For example, if you see something in the 400 range you know there has been a client problem (e.g. 404 not found), versus a 500 series status for server side problems. In this case, I explicitly handle 404 errors and have a generic catch-all for anything else.

2008.09.15

HTTP Response Codes

HTTP Response Code Activity Diagram
HTTP has a pretty well thought out set of response codes.

  • Server borked? 503.
  • Access denied? 403.
  • Not found? 404. 
  • All good? 200.

Up until now there hasn't really been a concise, easy to follow, way of figuring out what response code is the most appropriate. Allan Dean fixes that with his handy dandy activity guide for determining the appropriate HTTP response. Nice to see it also covers ETags.

It's kind of fun - now you can play the "find the 201" game.

Should be very useful for RESTful developers.

2008.08.20

Scala Compiler Plugins

Did you know you can write plugins for the Scala Compiler? I can imagine using this to implement DBC analysis at compile time. How cool would that be?!

2008.05.01

Wide Finder, Two.Oh!

Tim Bray started a project last year that attempted to find the fastest way to do string wrangling on log files using Erlang. The idea is to see how languages (like Erlang) that work  well on multi-core machines  compare with more traditional languages; in terms of designing a solution and performance. Pretty soon, Really Smart People were contributing solutions, including those written in languages that are not concurrent savvy per se (e.g. Perl). As it turns out, a Perl implementation kicked Erlang's butt, but the project was somewhat flawed as Tim points out in "Wide Finder 2":

There were a few problems last time. First, the disk wasn’t big enough and the sample data was too small (much smaller than the computer’s memory). Second, I could never get big Java programs to run properly on that system, something locked up and went weird. Finally, when I had trouble compiling other people’s code, I eventually ran out of patience and gave up. One consequence is that no C or C++ candidates ever ran successfully.

This time, we have sample data that’s larger than main memory and we have our own computer, and I’ll be willing to give anyone who’s seriously interested their own account to get on and fine-tune their own code.

What I loved about this the first time around was the discussion around how people approached the problem and their refinement of strategies based on some serious analysis of the bottlenecks. This is kind of geeky, but this is the type of stuff I find fascinating. Tim must have spent a fair bit of time lobbying for the corporate resources needed to get round 2 off the ground, so hat's off to you Tim, and well done Sun for having the foresight to back this project.

2008.04.04

Simple Spring 2.5 App with 2.5

Wanted to send some link love to Cagatay Civici who has created a really nice, minimal, concise sample application that showcases a bunch of latest and greatest Java webapp technologies:

  • JSF (MyFaces 1.2.2 with Facelets)
  • Spring 2.5
  • JPA with Hibernate
  • HSQLDB for persistence
  • Jetty for deployment
  • Maven2 for build

I like the Generic DAO idea. Get it here: Annotation Driven JSF-Spring-JPA.

2007.11.02

JSR 311 not RESTful?

Elliot thinks JSR-311, JAX-RS: The Java API for RESTful Web Services isn't really that RESTful at all, so the name should be changed to something along the lines of "Java HTTP Server API". Initially, I thought no way, but I think Elliot may be on to something.

I've done a little bit of playing around with Jersey, and I've found the annotations to be quite helpful in building a RESTful interface to our domain objects. Here, for example, are the relevant bits of our UsersResource class which sits the behind the /users uri:

@UriTemplate("/users")
public class UsersResource {
    @HttpContext
    private UriInfo uriInfo;
   
    private FormatterFactory formatterFactory = new DefaultUserFormatterFactory(); // Spring injected
    private RealmManager realmManager = RealmManager.instance(); // Spring injected   

    @HttpMethod("GET")
    @ProduceMime("application/json")

    public JSONObject getUsersAsJsonArray() throws JSONException {
    JsonFormatter formatter = formatterFactory.getSummaryFormatter();
   
    JSONObject o = new JSONObject();
        JSONArray objectArray = new JSONArray();

    Search search = new Search(createFilter());
    search.setFilter(filter);
    realmManager.execute(search);

        for (Object item : search.getResults()) {
            objectArray.put(formatter.format(uriInfo, item));
        }
    o.put("totalCount", search.getTotal());
    o.put("users", objectArray);

        return o;
    }

    @UriTemplate("{username}")
    public UserResource getUser(@UriParam("username") String username) {
User user = realmManager.getUser(username);
        if (null == user) {
            throw new WebApplicationException(new RuntimeException("user '" + username + "' does not exist."), 404);
        }
   
        return new UserResource(formatterFactory, uriInfo, user);
    }

    private UserFilter createFilter() {
        UserFilter filter = new UserFilter();
   
        // Populate a filter using uri parameters
        try {
            MultivaluedMap<String, String> queryParameters = uriInfo.getQueryParameters();
            for (Map.Entry<String, List<String>> entry : queryParameters.entrySet()) {
                String value = entry.getValue().get(0);
                PropertyUtils.setSimpleProperty(filter, entry.getKey(), value);
            }
        } catch (IllegalAccessException e) {
            throw new WebApplicationException(e);
        } catch (InvocationTargetException e) {
            throw new WebApplicationException(e);
        } catch (NoSuchMethodException e) {
            // ignore - this is a parameter that doesn't match a setter on the filter
}
        return filter;
    }
}

I've bolded that JAX-RS annotations. Is there anything there that is REST specific? Not really. It is mostly uri munging. Then again, you could also say the same of REST when it gets down to the nuts and bolts of implementation.

On the other hand, REST is more than just uri munging - it is an architectural style, and Elliot is right when he says:

An API is probably the wrong place to enforce architectural decisions

2007.08.01

.htaccess settings for parsing PHP script in HTML

I have a simple website with a common header and footer hosted on www.netnation.com. Instead of duplicating the common bits on every page and creating a maintenance nightmare, I opted to use php include statements. The problem was I don't particulary want to bother users with the implementation details, so I want my URLs to end with ".html" (not ".php"). After racking my brains out and trying every combination I could find on Google, it turns out the following is the magic incarnation:

AddHandler php-script .html
Action php-script /cgi-bin/php

Put those lines in your .htaccess file (in every directory), and your embedded php script in .html files will be parsed correctly.

If anyone knows why this works and the other stuff doesn't, please feel free to educate me and future visitors by commenting.

2007.01.30

Acegi Petclinic JUnit

My last post on how to use Acegi Security while JUnit integration testing drew a fair bit of traffic, so I thought I'd write a small Eclipse project that pulls all the bits together, and updated to run with Spring 2.0 and Acegi 1.0.3.

To build this project I followed the following steps:

  1. Got petclinic 2.0.2 going (download Spring here) and followed the instructions in the readme.txt files.
  2. Got acegi 1.0.3 (download Acegi here) and followed the instructions on integrating it with petclinic as described here (including the optional bonus section - "securing the middle tier").
  3. (optional) Ran the JdbcClinicTests from within Eclipse. This allowed me to step through the code in the debugger.
  4. Modified JdbcClinicTests so that it used the Acegi post-interceptor.

To get JdbcClinicTests working with Acegi (Step 4) I made the following changes:

  1. Add
    /WEB-INF/applicationContext-acegi-security.xml
  2. to JdbcClinicTests.getConfigLocations.

  3. Applied the same changes to /test/../applicationContext-jdbc.xml that were done in step 2 above - i.e. add a "postInterceptor" entry to the clinic bean and create a "methodSecurityInterceptor" bean.
  4. Add the acegi libraries to the debug profile, and include the war directory (so that it can find users.properties and the acegi context file). Here is a screen grab of my settings: Download acegi-debug-settings.gif

If you ran the project at this point you would get a AuthenticationCredentialsNotFoundException for every single test. To prevent this, we need to use a TestingAuthenticationProvider instead. I created a class called AcegiTestIntegration that does the replacement on the fly in its' constructor, and has a setAuthenticationToken method that sets up the security context.

For example, here is how it is initialized in the JdbcClinic.setClinic method:

acegiTestIntegration = new AcegiTestIntegration(getApplicationContext());
acegiTestIntegration.setAuthenticationToken(dianne);

The variable dianne is declared as:

private TestingAuthenticationToken dianne = new TestingAuthenticationToken("dianne", "emu", new GrantedAuthority[] {ROLE_USER});

Now if you ran the project, every test would pass except the last one - testInsertVisit - which would get an AccessDeniedException. Success! You have validated that only users with the supervisor role can invoke the method. Now, to get the unit test to pass, we simply catch the exception, and set up a token that should pass:

try {
this.clinic.storeVisit(visit);
fail("Should of thrown an AccessDeniedException because dianne is not ROLE_SUPERVISOR");
} catch (AccessDeniedException e) {
// expected - dianne is ROLE_USER, not ROLE_SUPERVISOR
}
acegiTestIntegration.setAuthenticationToken(marissa); // ROLE_SUPERVISOR
this.clinic.storeVisit(visit);

That's it.

Choose from one of the following downloads:

Additional notes:

  • An alternative approach you may want to consider is having seperate applicationContext-acegi-security.xml files - one for production and one for testing. The testing one would be configured to use a TestingAuthenticationProvider. The down side to this is having to move different configuration files around in the build script and/or keeping changes in sync between the files.
  • AcegiTestIntegration could be configured as a bean and injected into the test class. In this case, make it ApplicationContextAware and move the code that is in the constructor to it's setApplicationContext method, then get rid of the constructor.

Please leave a comment if you find this useful, or have suggestions for improvements. Thanks.

2006.12.19

ETags considered useful

Nice post about how using ETags can save you bandwidth and computation.

Summary: when you send something to a client, give them a token they can use later to see if that something has changed. If nothing has changed, then don't send anything.

I'd love to turn this on for our application somehow, but given the dynamic nature of it I suspect it could get a bit tricky. The stats Joe shows indicate that roughly 1 out 4 requests don't need a reply. I'd be interested to know what the breakdown of "user agents" making the requests were, as not every browser is ETag savvy. My other concern would be that once I got into the messy details, I would discover there are problems using this type of caching mechanism in a clustered environment.

How does that quote from go? - "If it was easy, everyone would be doing it."

2006.05.10

How to fix schema info messages in Visual Studio 2005 when using App.config and remoting

Sorry for the title, but I'm hoping to save some time for people who are searching for a solution to this problem in the future.

I'm using Visual Studio 2005 (build 8.0.50727-4200) to create a project that uses .Net remoting. When I try to configure remoting using App.config via RemotingConfiguration.Configure(...), I get annoying messages in the error list window telling me that it "Could not find schema information for the element 'application'".   The problem is because DotNetConfig.xsd in c:\program files\microsoft visual studio 8\xml\schemas doesn't have all the bits required to understand remoting.

Here is how to fix the problem:

  1. Open App.config
  2. Select the XML | Create Schema menu option
  3. Copy everything inside the <xs:element name="system.runtime.remoting"> tag to the clipboard
  4. Open C:\Program Files\Microsoft Visual Studio 8\Xml\Schemas\DotNetConfig.xsd
  5. Search for "remoting"
  6. Change the line that says
    <xs:element name="system.runtime.remoting" vs:help="configuration/system.runtime.remoting"/>
    to
    <xs:element name="system.runtime.remoting" vs:help="configuration/system.runtime.remoting">
    </xs:element>
  7. Paste the clipboard contents inside the remoting element

This will only pick up the elements and attributes you are currently using in App.Config. If you change the file you will have to go through this rigmorale again, or edit DotNetConfig.xsd by hand.

I imagine this will get fixed eventually, but in the mean time I hope this helps.