views:

62

answers:

2

NOTE: Please ignore my use of MultivaluedMap instead of multiple vargs String...args.

Is there a standard way in java of doing this?

What I have is a resource, that is returned from a remote server. But before each query, the remote connection must be open, and after the returns are returned - it must be closed.

So a natural way of doing this is something like:

Connection c = config.configureConnection();
c.open();       //open
List<Car> cars;
try{
   cars = c.getCars();
}finally{
   c.close();   //close
}

Now I want to implement something that operates on the level of the resources themselves, without worrying about connection, for example:

List<Car> cars = new CarResource().all(); //opens and closes connection

The way I am currently doing it is by having one abstract class, AbstractQueriable call abstract methods query(String ...args) and query(int id), which any class extending it must implement.

The AbstractQuerieable implements the Queriable interface, which makes it expose the three public methods filter(String ...args), all() and get(int id) - which are the public facing methods.

Here is the Queriable interface:

public interface Queriable <T>{
    public T get(String id);
    /** Simply returns all resources */
    public Collection<T> all(); 
    public Collection<T> filter(MultivaluedMap<String, String> args);   
}

here is the AbstractQueriable class that implements it:

public abstract class AbstractQueriable<T> implements Queriable<T> {

@Override
public final T get(String id) {
    setup();
    try {
        return query(id);
    } finally {
        cleanup();
    }
}

@Override
public final Collection<T> filter(MultivaluedMap<String, String> args) {
    setup();
    try {
            return query(args);
    } finally {
        cleanup();
    }
}

/**
 * Returns all resources.
 * 
 * This is a convenience method that is equivalent to passing an empty
 * arguments list to the filter function.
 * 
 * @return The collection of all resources if possible
 */
    @Override
public final Collection<T> all() {      
    return filter(null);
}

/**
 * Queries for a resource by id.
 * 
 * @param id
 *            id of the resource to return
 * @return
 */
protected abstract T query(String id);

/**
 * Queries for a resource by given arguments.
 * 
 * @param args
 *            Map of arguments, where each key is the argument name, and the
 *            corresponing values are the values
 * @return The collection of resources found
 */
protected abstract Collection<T> query(MultivaluedMap<String, String> args);

private void cleanup() {
    Repository.close();
}

private void setup() {
    Repository.open();
}

and finally my resource, which I want to use in the code, must extend the AbstractQueriable class, for example (please note that the details of these methods are not important):

public class CarRepositoryResource extends AbstractQueriable<Car> {

    @Override
    protected Car query(String id) {
        MultivaluedMap<String, String> params = new MultivaluedMapImpl();
        params.add("CarID", id);

        // Delegate the query to the parametarized version
        Collection<cars> cars = query(params);
        if (cars == null || cars.size() == 0) {
            throw new WebApplicationException(Response.Status.NOT_FOUND);
        }
        if (cars.size() > 1) {
            throw new WebApplicationException(Response.Status.NOT_FOUND);
        }
        return cars.iterator().next();
    }

    @Override
    protected Collection<Car> query(MultivaluedMap<String, String> params) {
        Collection<Car> cars = new ArrayList<Car>();        

        Response response = Repository.getConnection().doQuery("Car");
        while (response.next()) {
            Returned returned = response.getResult();
            if (returned != null) {
                cars.add(returned);
            }
        }
        return cars;
    }

}

which finally, I can use in my code:

Collection<Car> cars = new CarRepositoryResource().all();
//... display cars to the client etc...

There are a few things I don't like about this kind of setup:

  1. I must instantiate a new instance of my "CarRepositoryResource" every time I do a query.
  2. The method names "query", while internal and private, are still confusing and clunky.
  3. I am not sure if there is a better pattern or framework out there.

The connection that I am using does not support/implement the JDBC api and is not sql-based.

+1  A: 

You could use a variation of the (in)famous Open session in view pattern.

Basically it comes down to this:

  1. Define a "context" in which connections are available (usually the request in web applications)
  2. Handle (possibly lazy) initialization and release of a connection when entering/exiting the context
  3. Code your methods taking for granted they will only be used inside such a context

It is not difficult to implement (storing the connection in a static ThreadLocal to make it thread safe) and will definitely spare a few open/close calls (performance-wise that could be a big gain, depending on how heavy your connection is).

The context class could look something like (consider this pseudo-code);

public class MyContext{
  private static final
  ThreadLocal<Connection> connection = new ThreadLocal<Connection>();

  public static void enter() {
     connection.set(initializeConnection());
     // this is eager initialization
     // if you think it will often the case that no connection is actually
     // required inside a context, you can defer the actual initialization
     // until the first call to get()
  }

  public static void exit() {
    try { connection.close(); }
    catch(Throwable t) { /* panic! */ }
    finally { connection.set(null); }
  }

  public static Connection get() {
    Connection c = connection.get();
    if (c == null) throw new IllegalStateException("blah blah");
    return c;
  }
}

Then you would use connections like this:

MyContext.enter();
try {
   // connections are available here:
   // anything that calls MyContext.get()
   // gets (the same) valid connection instance
} finally {
  MyContext.exit();
}

This block can be put wherever you want (in webapps it usually wraps the processing of each request) - from the main method if you are coding a simple case when you want a single connection available for the whole lifespan of your application, to the finest methods in your API.

giorgiga
Interesting. So in my simple example it will be something like:MyContext.enter();try { Collection<Car> cars = Car.all();} finally { MyContext.exit();}
drozzy
You have the option to do more than just one query between enter()/exit(), like multiple queries through your connection (eg: get a car by id and then list all its previous owners - via the same connection) or even consuming the results.(continues)
giorgiga
The latter is an interesting option (similar to what one does in hibernate using the open session in view pattern): Car.all() could return a lazy list (one that fetches data only when/if actually needed, maybe extending AbstractSequentialList). That would require support for executing concurrent queries on the same connection or (if your connection is not transactional and not too heavy to open/close) using multiple connections per context (you would then close them all in Context.exit()).(continues)
giorgiga
The advantage of the pattern is that it decouples resource management (open/close) from resource usage (queries) - the down side is that you are adding a constraint on the environment your code executes into and you have to worry about reentrance and concurrent usage (implementation is greatly simplified if your connection is not transactional).If you don't need random access and can, in the general case, do without Collection.size() you'll probably want Cars.all() to return an Iterator instead of a full-blown List.
giorgiga
I see. But would I still not have to worry about calling enter() and exit() on the context? I mean in a sense I would equally call connection.open() and connection.close() in the same places?
drozzy
Yep, but you could put it in some place your execution flow always passes through (a filter in a webapp, maybe some base event handler class you then extend in a GUI app) and then forget about connection management.Java has no provision for automatic resource management (yet), so there is no way around finally{ close() }.There are proposals for adding that as a language feature (eg: http://mail.openjdk.java.net/pipermail/coin-dev/2009-February/000011.html) - I don't know if/when they are going to be implemented.
giorgiga
A: 

You might want to take a look at fluent interfaces (with an interesting example here) and its "Builder" pattern.

You would query like this:

cars().in(DB).where(id().isEqualTo(1234));

This way you can hide the connection/disconnection code in the outermost cars() method, for example.

louisgab