users@jersey.java.net

Resource Management through nested sub-locators

From: Martin Probst <mail_at_martin-probst.com>
Date: Thu, 4 Jun 2009 20:05:53 +0200

Hi,

I'm trying to write an app where a resource opens a transactional
context that is then used in sublocators, e.g.:

@Path("/")
class MyResource {

  @Path("{child}") Child getChild(@PathParam("child") String childName) {
    Session session = getSession(...);
    try {
      return new Child(session.get(childName));
    } catch (Exception e) {
      // mhmhm
    } finally {
      // whoops ?!
    }
  }
}

class Child {
  @Path("FOO!!!") Foo getFoo(...) { ... };
}

So, basically I want to open a resource - not in the REST meaning, but
in the "file descriptor"/scarce system resource meaning -, in this
case a session, and use that in classes that have sub-locators.

All nice and dandy, but now I need to manage that resource. So I need
to make sure that it will absolutely always be
closed/recycled/whatever, and in case an exception happens my session
needs to be closed.

I found something that recommended @PreDestroy, and that will work for
the regular closing part, even though it's a bit ugly. Also, I'm not
sure of the semantics - will this be called in case of exceptions?
What happens if the @PreDestroy method throws an exception?

The other thing is to react when exceptions are thrown. I can
implement an ExceptionMapper<Throwable> or <RuntimeException> which
will then always be notified if something goes wrong within the web
application. The mapper would roll back my session and then ideally
re-throw the exception. But that is not allowed from the interface, so
it has to convert to a 500 response or something like that.

I'm pretty sure that this will work, but it seems like a pretty large
stretch of the design, coming from the simple try/catch/finally
construct I'm used to. The problem is of course that by passing back
the control to Jersey for sublocators, my application code is losing
control of the stack, and thus loosing the grip on exceptions and
return values.

Now, am I missing something or is this just a limitation?

If it is a limitation, I'd like to suggest maybe allowing resource
methods to request as a @Context parameter some special object which
is in effect the UriRule chain from Jersey (or rather some public
interface). Then I could do this (in getChild(...) above):

public void getChild(@Context RuleChain continuation) {
    Session session = getSession(...);
    try {
      continuation.continueWith(new Child(session.get(childName)));
      session.commit();
    } catch (Exception e) {
      session.rollback();
      throw e;
    } finally {
      session.close();
    }
}

So to allow users to keep the stack hierarchy intact. Or is this
already possible and I'm just missing the fact?

I think this should be a not totally uncommon use case to open some
scarce resource (files, sockets, images, whatever ...), use it in
subrules, and really make sure you close it. The workaround with
@PreDestroy and ExceptionMapper seems cumbersome and error prone, and
I'd guess that there may be a lot of corner cases which are otherwise
guaranteed to be covered by the finally block.

Martin