package com.googlecode.objectify.cache;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* A Future which merges some previously loaded values with the results of another
* Future that is in progress. It can apply to any key/value pair type; typically
* it will be for Key/Entity or Key<T>/T
*
* @author Jeff Schnitzer <jeff@infohazard.org>
*/
public class MergeFuture<K, V> implements Future<Map<K, V>>
{
/**
* Values that we have obtained. Starts with just the preloaded values,
* then when the pending is complete the values get appended to this collection.
*/
Map<K, V> loaded;
/** Pending requests - if null, this Future is complete and all values are in loaded */
Future<Map<K, V>> pending;
/**
* @param preloaded is a collection of entities that have already been obtained, say
* from the memcache. TAKES OWNERSHIP OF THE MAP OBJECT - it will be modified later.
* @param pending is a future of entities that will be obtained sometime later, or
* null if merging is unnecessary and the preloaded values complete the result.
*/
public MergeFuture(Map<K, V> preloaded, Future<Map<K, V>> pending)
{
assert preloaded != null;
this.loaded = preloaded;
this.pending = pending;
}
/* (non-Javadoc)
* @see java.util.concurrent.Future#cancel(boolean)
*/
@Override
public boolean cancel(boolean mayInterruptIfRunning)
{
//return this.raw.cancel(mayInterruptIfRunning);
throw new UnsupportedOperationException("This makes my head spin. Don't do it.");
}
/* (non-Javadoc)
* @see java.util.concurrent.Future#isCancelled()
*/
@Override
public boolean isCancelled()
{
return false;
}
/**
*
* @see java.util.concurrent.Future#isDone()
*/
@Override
public boolean isDone()
{
if (this.pending == null)
return true;
else
return this.pending.isDone();
}
/* (non-Javadoc)
* @see java.util.concurrent.Future#get()
*/
@Override
public Map<K, V> get() throws InterruptedException, ExecutionException
{
if (this.pending != null)
{
this.loaded.putAll(this.pending.get());
this.pending = null;
}
return this.loaded;
}
/* (non-Javadoc)
* @see java.util.concurrent.Future#get(long, java.util.concurrent.TimeUnit)
*/
@Override
public Map<K, V> get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
{
if (this.pending != null)
{
this.loaded.putAll(this.pending.get(timeout, unit));
this.pending = null;
}
return this.loaded;
}
}