tags:

views:

985

answers:

2

I'm trying to manage a contended resource (as in: database session) while programming a RESTful web application in Jersey. Usually I'd write code like this:

Session session = getSession();
try {
  doWork();
  session.commit();
} finally {
  session.rollback(); // doesn't hurt after commit
  session.release(); // or whatever
}

Now with Jersey, I have a resource like this:

@Path("/")
class MyResource {
  @Path("{child}") public Child getChild(...) {
    // how do I manage my session here ???
    return child;
  }
}

The problem is that I need to acquire the session in getChild(), but I cannot make sure I properly release it after work has been done as I've then already given back control to the web application.

Child needs access to the session as well, so I cannot encapsulate all the work in one method:

class Child {
  @Path("{subchild}") public Subchild getSubchild(...) {
    return new Subchild(session.get(...));
  }
}

I cannot wrap the whole application in a servlet Filter as I need information from the Jersey-level to construct my session. Now I could just open it in MyResource, use a regular servlet filter to make sure I always close it, but then I don't know when to rollback and when to commit the session. I could use an ExceptionMapper to be notified of all exceptions, but that would need to be an ExceptionMapper, and this just seems so extremely ugly, with the conceptual try/finally spread over three classes with different lifetimes and so on.

Is there a "right way" to do this kind of resource management in Jersey? How would I make sure I properly close e.g. a FileInputStream after a resource and it's sub-locatos have used it?

A: 

In a REST application, you are not required to pass anything to a call. If you are doing the work in getChild, that's where all of the logic should be. Guessing at what you are doing, the above should read:

@Path("/{childId}")
class ChildResource {  

    @GET
    public Child getChild(@PathParam("childId") String childId) {    
        //Really, move this into a data access object
        Session session = getSession();
        try {  
            doWork();  
            session.commit();
        } finally {  
            session.rollback(); 
            // doesn't hurt after commit  
            session.release(); 
            // or whatever
        }
        return child;  
    }
}
stevedbrown
The problem is that Child can have arbitrary sub-locators that might need access to the session, too. I'll update the question.
Martin Probst
A: 

This thread contains some relevant discussion.

Bas de Bakker