Page 2 of 5
When dealing with distributed systems, it is unwise to assume that objects will continue to operate seamlessly over long periods of time. Connections may time out; servers may crash or become unreachable on the network. Objects that make use of these resources may as a result also become broken. In fact, objects can fail in local systems, too. In either situation, if the broken object that the client has been using has come from a resource pool, things get a bit tricky.
On one hand, we have promised that, once we have taken an object from the pool, we will put it back. On the other, the next client will expect the object to be valid and useful when it takes it from the pool. If a broken object is put back into the pool, it will most likely cause problems for the next client that tries to use it.
What we really need is a mechanism that allows clients to return broken resources in a way that gracefully acknowledges that
the resource is faulty. To do this we need to be able to call an explicit method on ResourcePool rather than returning the broken resource with releaseResource().
The scenario above is analogous to renting a car: you pick up your car from the rental agency expecting it to run properly; if it breaks down as soon as you drive out of the parking lot, however, you would expect the rental agency to replace it with one that works. No reputable car rental company would simply put the car back out on its rental lot without repairing it first. We'll come back to our car rental metaphor momentarily; first, let's review our resource pool interface in order to help solve our dilemma.
In our Java systems, we introduce a new method signature on the ResourcePool interface. This allows clients to signal to the pool that the resource they are replacing may be broken.
To keep the examples simple, we haven't specified any exceptions in the ResourcePool interface:
interface ResourcePool
{
public Object getResource();
public void releaseResource(Object resource);
public void putBackBrokenResource(Object resource);
}
Here's how the client code may look. We'll keep to our metaphor of a car rental agency, assuming that we have a PoolFactory that is responsible for creating object pools, and that the pool manages HireCar (RentalCar) objects:
ResourcePool pool = PoolFactory.getPool();
int numTries=0;
boolean done=false;
while(!done)
{
HireCar hireCar = null;
try
{
hireCar = (HireCar)pool.getResource();
hireCar.startEngine();
//other operations
done=true;
}
catch(CarBrokenException exp)
{
pool.putBackBrokenResource(hireCar);
numTries++;
if(numTries==MAX_TRIES)
throw exp;
}
finally
{
pool.releaseResource(hireCar);
}
}
For the purposes of this article, it is a little off-topic to consider a releaseResource() or getResource() method that does throw a Throwable, but this case brings some interesting issues to light. For more information on exceptions, see Resources.
With our new method in place, client code can put suspect objects back into the pool with a clear conscience. We leave it
as the responsibility of the pool to deal with such objects. Now let's look at how we might implement a Car pool given the above interfaces.