}
public DHTFuture<PutEntity> put(final Key key,
final Value value, PutConfig config) {
final PutConfig cfg = configProvider.get(config);
int w = cfg.getStoreConfig().getW();
if (w < 1) {
throw new IllegalArgumentException("w=" + w);
}
if (w >= 2 && !value.isRepeatable()) {
throw new IllegalArgumentException(
"The value is not repeatable: w=" + w);
}
final Object lock = new Object();
synchronized (lock) {
// This is the DHTFuture we're going to return to the caller
// of this method (in most cases the user).
DHTProcess<PutEntity> process = NopProcess.create();
final DHTFuture<PutEntity> userFuture
= futureManager.submit(process, cfg);
// This will get initialized once we've found the k-closest
// Contacts to the given KUID
final ValueReference<DHTFuture<StoreEntity>> storeFutureRef
= new ValueReference<DHTFuture<StoreEntity>>();
// This will get initialized once we've found the k-closest
// Contacts to the given KUID
final ValueReference<DHTFuture<ValueEntity>> clockFutureRef
= new ValueReference<DHTFuture<ValueEntity>>();
// Start the lookup for the given KUID
final DHTFuture<NodeEntity> lookupFuture
= discoveryManager.discover(key.getId(),
cfg.getLookupConfig());
// Let's wait for the result of the FIND_NODE operation. On success we're
// going to initialize the storeFutureRef and do the actual STOREing.
lookupFuture.addAsyncFutureListener(new AsyncFutureListener<NodeEntity>() {
@Override
public void operationComplete(AsyncFuture<NodeEntity> future) {
synchronized (lock) {
try {
if (!future.isCancelled()) {
handleNodeEntity(future.get());
} else {
handleCancelled();
}
} catch (Throwable t) {
handleException(t);
}
}
}
private void handleNodeEntity(final NodeEntity nodeEntity) {
Contact[] contacts = nodeEntity.getContacts();
DHTFuture<StoreEntity> storeFuture
= storeFutureRef.make(store(contacts,
key, value, cfg.getStoreConfig()));
storeFuture.addAsyncFutureListener(new AsyncFutureListener<StoreEntity>() {
@Override
public void operationComplete(AsyncFuture<StoreEntity> future) {
synchronized (lock) {