Saturday, October 15, 2011

Faking Block Programming In Java

While I was writing some server-side code to talk to a web service, I did the total n00b thing of forgetting to close my connection when I was done with the call. This works fine in test cases, but in any sort of real-world situation, you'll quickly exhaust your connection pool as connections linger, unavailable, until they time out. And as I fixed the problem, I realized I had done the same thing in one other place — I haven't written client code in a while. Then I realized that I had a recurring pattern:


HttpMethod get;
try {
get = new GetMethod(url);
get.execute();

// pull the response body out and do stuff with it
} finally {
if (get != null) {
get.releaseConnection();
}
}


This ensures that, even in the case of an Exception, the connection gets released. Fairly straightforward. But who wanted little copies of that code all over the system? And, worse, what if someone forgot to do this, just as I did? Anytime you set up code people have to remember to type, you ensure that someday someone will forget.

This would be an obvious use case for a closure. In fact, it reminded me of the File.open method in Ruby that takes a block of code as an argument. The method creates a File object, calls the block of code you pass in with said File object, and then closes the file even if there was an exception.

The only problem: pure Java doesn't support closures. (Some JVM-compatible languages like Scala do, however.)

But you can mimic the behavior to some degree with anonymous inner classes, and you can use Java Generics to provide type checking. I created a MethodOperator interface that looks like this


public interface MethodOperator<T> {
public T actOnMethodPostResponse(HttpMethod method) throws Exception;
}


The <T> and public T … bits basically mean that when I have to instantiate one of these, I can also declare it as being of some type, which then gets returned from the one method.

Once I had that code, I added a simple utility method:

protected <T> T actOnHttpMethod(HttpMethod method, MethodOperator operator) throws Exception {
try {
executeMethod(method); // utility method that checks for errors and so forth on the method
return (T)operator.actOnMethodPostResponse(method);
} catch (Exception e) {
log.error("Error talking to http server",e);
throw e;
} finally {
if (method != null) {
method.releaseConnection();
}
}
}


And can invoke it with something like this:

IdResponse response = actOnHttpMethod(post,new MethodOperator<IdResponse>() {
public IdResponse actOnMethodPostResponse(HttpMethod method) {
// unmarshal the response and create an IdResponse object with it
}
});


The actOnHttpMethod will do the request, hand my object the response, and then close the connection for me.

Inner classes definitely suffer from readability problems, but this setup ensures that it's very easy for developers to not even think about connection management. Furthermore, I can add features and have them automatically used by every client. For instance, if I wanted to profile the request/response time or add logging. If I ever want to add support for asynchronous calls, I can write a new utility method that does all the work of enqueuing the method and so forth, invoking the MethodOperator code as needed, and then change specific code to say actOnHttpMethodAsync or something instead of actOnHttpMethod. A minimal change in client code plus a utility method, and I've added a more scalable alternative in situations where I don't care about waiting for the response.

Once I refactored all that away, I then realized that I could refactor even more. At the moment, I handle a response in one of two ways: I either ignore it (for things like DELETEs) or I unmarshal the contents from XML into Java. Once I had my whole framework in place, I realized I could make implementations of the MethodOperator interface that would cover these two cases.

I created the following:

public class IgnoreResponseMethodOperator implements MethodOperator<Object> {
public Object actOnMethodPostResponse(HttpMethod method) {
return null;
}
}

public class XmlUnmarshallingMethodOperator<T> implements MethodOperator {
public T actOnMethodPostResponse(HttpMethod method) throws Exception {
JAXBContext context = JAXBContext.newInstance(Constants.JAXB_PACKAGES);
Unmarshaller unmarshaller = context.createUnmarshaller();
return (T)unmarshaller.unmarshal(method.getResponseBodyAsStream());
}
}


Now my client code actually looks like this:

IdResponse response = actOnHttpMethod(post,new XmlUnmarshallingMethodOperator<IdResponse>());


I still get all the value of the code that manages connections around my code, but now I don't even have to worry about the unreadability of anonymous inner classes.

(You could make the case that this will create a lot of object churn. If it does, I can look at making a thread-safe implementation that will let me re-use the MethodOperator objects. That's very easy to do with the IgnoreResponseMethodOperator, but tougher with the type-safe xml unmarshaller. I imagine I'd have to create instances for each type of object I might get back. Given that there aren't too many, this wouldn't be too bad. But first I'll see if that's actually a problem.)

No comments:

Post a Comment