users@jax-rs-spec.java.net

[jax-rs-spec users] evaluate Preconditions in an independent class

From: Thomas Koch <thomas_at_koch.ro>
Date: Fri, 16 Mar 2012 10:18:54 +0100

Hi,

I'm currently prototyping an AtomPub server for my bachelor thesis and while
doing so came up with a nice interface (I believe) to handle HTTP
preconditions. I'm not that experienced yet, so I might miss something.

The current JAX-RS way to evaluate preconditions has IMHO 2 shortcomings:

a) It isn't save against concurrent updates:

    @PUT
    ResponseBuilder rb = request.evaluatePreconditions(etag);
    // right now another concurrent request updates the resource
    if (rb == null)
      return doUpdate(foo);

b) It does not return boolean but an instance of ResponseBuilder

c) It can return null. Ugly.

The interface is just

    interface Preconditions {
        boolean shouldPerform(EntityTag etag);
        boolean shouldPerform(org.joda.DateTime dt);
        boolean shouldPerform(EntityTag etag, org.joda.DateTime dt);
    }

The interface is implemented by two classes, GetHeadPreconditions and
PutDeletePreconditions. I've not yet thought about an equivalent to JAX-RS
evaluatePreconditions() method without parameters.

The Preconditions instance is given to my applications CollectionStorage. In
the end it's not the resource method that knows the state of resources but
most likely some storage. You can see from my below CollectionStorage example
that it comes in handy to have the received preconditions available as an
individual entity that can be sent around.
                                                                                                                               
  interface CollectionStorage {
                                                                                                                               
    void post(Id, Resource);
    GetResult conditionalGet(Id, Preconditions);
                                                                                                                               
    // @return whether the precondition was fulfilled and the action performed
    boolean conditionalPut(Id, Resource, DateTime, Preconditions);
    boolean conditionalDelete(Id, DateTime, Preconditions)
                                                                                                                               
    ResultList listUpdates(PaginationRange, Preconditions);
                                                                                                                               
    static class ResultList {
          static ResultList NOT_MODIFIED = new ResultList(NOT_MODIFIED);
          Iterable<Resource> it;
          int total;
          Status status;
          EntityTag etag;
    }
                                                                                                                               
    static class GetResult {
         static GetResult NOT_FOUND = new GetResult(NOT_FOUND);
         static GetResult NOT_MODIFIED = new GetResult(NOT_MODIFIED);
                                                                                                                               
         Status status;
         Resource resource;
    }
  }

Regards,

Thomas Koch, http://www.koch.ro