mirror of https://github.com/apache/jclouds.git
Issue 144: replaced FutureFunctionCallable, FutureFunctionWrapper, RunnableFutureTask with Futures.compose and Futures.chain
git-svn-id: http://jclouds.googlecode.com/svn/trunk@2617 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
6a5a4df606
commit
1284fd67fa
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
package org.jclouds.atmosonline.saas.blobstore;
|
||||
|
||||
import static com.google.common.util.concurrent.Futures.compose;
|
||||
import static com.google.common.util.concurrent.Futures.makeListenable;
|
||||
import static org.jclouds.blobstore.options.ListContainerOptions.Builder.recursive;
|
||||
|
||||
import java.net.URI;
|
||||
|
@ -46,7 +48,6 @@ import org.jclouds.blobstore.domain.ResourceMetadata;
|
|||
import org.jclouds.blobstore.domain.Blob.Factory;
|
||||
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
|
||||
import org.jclouds.blobstore.strategy.ClearListStrategy;
|
||||
import org.jclouds.concurrent.FutureFunctionCallable;
|
||||
import org.jclouds.encryption.EncryptionService;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
|
@ -77,15 +78,13 @@ public class AtmosAsyncBlobStore extends BaseAtmosBlobStore implements AsyncBlob
|
|||
* This implementation uses the AtmosStorage HEAD Object command to return the result
|
||||
*/
|
||||
public Future<BlobMetadata> blobMetadata(String container, String key) {
|
||||
return wrapFuture(async.headFile(container + "/" + key),
|
||||
return compose(makeListenable(async.headFile(container + "/" + key)),
|
||||
new Function<AtmosObject, BlobMetadata>() {
|
||||
|
||||
@Override
|
||||
public BlobMetadata apply(AtmosObject from) {
|
||||
return object2BlobMd.apply(from);
|
||||
}
|
||||
|
||||
});
|
||||
}, service);
|
||||
}
|
||||
|
||||
public Future<Void> clearContainer(final String container) {
|
||||
|
@ -100,17 +99,18 @@ public class AtmosAsyncBlobStore extends BaseAtmosBlobStore implements AsyncBlob
|
|||
}
|
||||
|
||||
public Future<Boolean> createContainer(String container) {
|
||||
return wrapFuture(async.createDirectory(container), new Function<URI, Boolean>() {
|
||||
return compose(makeListenable(async.createDirectory(container)),
|
||||
new Function<URI, Boolean>() {
|
||||
|
||||
public Boolean apply(URI from) {
|
||||
return true;// no etag
|
||||
}
|
||||
public Boolean apply(URI from) {
|
||||
return true;// no etag
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public Future<Void> createDirectory(String container, String directory) {
|
||||
return wrapFuture(async.createDirectory(container + "/" + directory),
|
||||
return compose(makeListenable(async.createDirectory(container + "/" + directory)),
|
||||
new Function<URI, Void>() {
|
||||
|
||||
public Void apply(URI from) {
|
||||
|
@ -151,11 +151,11 @@ public class AtmosAsyncBlobStore extends BaseAtmosBlobStore implements AsyncBlob
|
|||
org.jclouds.blobstore.options.GetOptions... optionsList) {
|
||||
GetOptions httpOptions = blob2ObjectGetOptions.apply(optionsList);
|
||||
Future<AtmosObject> returnVal = async.readFile(container + "/" + key, httpOptions);
|
||||
return wrapFuture(returnVal, object2Blob);
|
||||
return compose(makeListenable(returnVal), object2Blob, service);
|
||||
}
|
||||
|
||||
public Future<? extends ListResponse<? extends ResourceMetadata>> list() {
|
||||
return wrapFuture(async.listDirectories(), container2ResourceList);
|
||||
return compose(makeListenable(async.listDirectories()), container2ResourceList, service);
|
||||
}
|
||||
|
||||
public Future<? extends ListContainerResponse<? extends ResourceMetadata>> list(
|
||||
|
@ -169,7 +169,8 @@ public class AtmosAsyncBlobStore extends BaseAtmosBlobStore implements AsyncBlob
|
|||
}
|
||||
}
|
||||
ListOptions nativeOptions = container2ContainerListOptions.apply(optionsList);
|
||||
return wrapFuture(async.listDirectory(container, nativeOptions), container2ResourceList);
|
||||
return compose(makeListenable(async.listDirectory(container, nativeOptions)),
|
||||
container2ResourceList, service);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -177,9 +178,7 @@ public class AtmosAsyncBlobStore extends BaseAtmosBlobStore implements AsyncBlob
|
|||
*/
|
||||
public Future<String> putBlob(final String container, final Blob blob) {
|
||||
final String path = container + "/" + blob.getMetadata().getName();
|
||||
|
||||
Callable<String> valueCallable = new FutureFunctionCallable<Void, String>(async
|
||||
.deletePath(path), new Function<Void, String>() {
|
||||
return compose(makeListenable(async.deletePath(path)), new Function<Void, String>() {
|
||||
|
||||
public String apply(Void from) {
|
||||
try {
|
||||
|
@ -200,8 +199,7 @@ public class AtmosAsyncBlobStore extends BaseAtmosBlobStore implements AsyncBlob
|
|||
}
|
||||
}
|
||||
|
||||
});
|
||||
return service.submit(valueCallable);
|
||||
}, service);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ package org.jclouds.atmosonline.saas.blobstore.internal;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
|
@ -36,10 +35,8 @@ import org.jclouds.blobstore.domain.Blob;
|
|||
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
|
||||
import org.jclouds.blobstore.reference.BlobStoreConstants;
|
||||
import org.jclouds.blobstore.strategy.ClearListStrategy;
|
||||
import org.jclouds.concurrent.FutureFunctionWrapper;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class BaseAtmosBlobStore {
|
||||
|
@ -83,11 +80,6 @@ public class BaseAtmosBlobStore {
|
|||
this.service = checkNotNull(service, "service");
|
||||
}
|
||||
|
||||
protected <F, T> Future<T> wrapFuture(Future<? extends F> future, Function<F, T> function) {
|
||||
return new FutureFunctionWrapper<F, T>(future, function, logFactory.getLogger(function
|
||||
.getClass().getName()));
|
||||
}
|
||||
|
||||
public Blob newBlob(String name) {
|
||||
Blob blob = blobFactory.create(null);
|
||||
blob.getMetadata().setName(name);
|
||||
|
|
|
@ -37,13 +37,13 @@ import org.jclouds.blobstore.options.ListContainerOptions;
|
|||
import org.jclouds.blobstore.reference.BlobStoreConstants;
|
||||
import org.jclouds.blobstore.strategy.ClearContainerStrategy;
|
||||
import org.jclouds.blobstore.strategy.ClearListStrategy;
|
||||
import org.jclouds.concurrent.FutureFunctionWrapper;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
|
@ -88,7 +88,7 @@ public class RecursiveRemove implements ClearListStrategy, ClearContainerStrateg
|
|||
for (Future<Void> isdeleted : deletes) {
|
||||
isdeleted.get(requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
return new FutureFunctionWrapper<Void, Void>(async.deletePath(fullPath),
|
||||
return Futures.compose(async.deletePath(fullPath),
|
||||
new Function<Void, Void>() {
|
||||
|
||||
public Void apply(Void from) {
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
package org.jclouds.atmosonline.saas.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
|
||||
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
@ -45,13 +47,13 @@ import org.jclouds.blobstore.domain.Blob;
|
|||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.functions.HttpGetOptionsListToGetOptions;
|
||||
import org.jclouds.blobstore.integration.internal.StubAsyncBlobStore;
|
||||
import org.jclouds.blobstore.integration.internal.StubAsyncBlobStore.FutureBase;
|
||||
import org.jclouds.concurrent.FutureFunctionWrapper;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
import org.jclouds.util.Utils;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
|
||||
/**
|
||||
* Implementation of {@link AtmosStorageAsyncClient} which keeps all data in a local Map object.
|
||||
|
@ -62,7 +64,6 @@ import com.google.common.base.Function;
|
|||
public class StubAtmosStorageAsyncClient implements AtmosStorageAsyncClient {
|
||||
private final HttpGetOptionsListToGetOptions httpGetOptionsConverter;
|
||||
private final StubAsyncBlobStore blobStore;
|
||||
private final LoggerFactory logFactory;
|
||||
private final AtmosObject.Factory objectProvider;
|
||||
private final ObjectToBlob object2Blob;
|
||||
private final BlobToObject blob2Object;
|
||||
|
@ -71,13 +72,12 @@ public class StubAtmosStorageAsyncClient implements AtmosStorageAsyncClient {
|
|||
private final ResourceMetadataListToDirectoryEntryList resource2ObjectList;
|
||||
|
||||
@Inject
|
||||
private StubAtmosStorageAsyncClient(StubAsyncBlobStore blobStore, LoggerFactory logFactory,
|
||||
private StubAtmosStorageAsyncClient(StubAsyncBlobStore blobStore,
|
||||
AtmosObject.Factory objectProvider,
|
||||
HttpGetOptionsListToGetOptions httpGetOptionsConverter, ObjectToBlob object2Blob,
|
||||
BlobToObject blob2Object, BlobMetadataToObject blob2ObjectInfo,
|
||||
ListOptionsToBlobStoreListOptions container2ContainerListOptions,
|
||||
ResourceMetadataListToDirectoryEntryList resource2ContainerList) {
|
||||
this.logFactory = logFactory;
|
||||
this.blobStore = blobStore;
|
||||
this.objectProvider = objectProvider;
|
||||
this.httpGetOptionsConverter = httpGetOptionsConverter;
|
||||
|
@ -89,24 +89,20 @@ public class StubAtmosStorageAsyncClient implements AtmosStorageAsyncClient {
|
|||
this.resource2ObjectList = checkNotNull(resource2ContainerList, "resource2ContainerList");
|
||||
}
|
||||
|
||||
protected <F, T> Future<T> wrapFuture(Future<? extends F> future, Function<F, T> function) {
|
||||
return new FutureFunctionWrapper<F, T>(future, function, logFactory.getLogger(function
|
||||
.getClass().getName()));
|
||||
}
|
||||
|
||||
public Future<URI> createDirectory(String directoryName) {
|
||||
final String container;
|
||||
if (directoryName.indexOf('/') != -1)
|
||||
container = directoryName.substring(0, directoryName.indexOf('/'));
|
||||
else
|
||||
container = directoryName;
|
||||
return wrapFuture(blobStore.createContainer(container), new Function<Boolean, URI>() {
|
||||
return Futures.compose(Futures.makeListenable(blobStore.createContainer(container)),
|
||||
new Function<Boolean, URI>() {
|
||||
|
||||
public URI apply(Boolean from) {
|
||||
return URI.create("http://stub/containers/" + container);
|
||||
}
|
||||
public URI apply(Boolean from) {
|
||||
return URI.create("http://stub/containers/" + container);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public Future<URI> createFile(String parent, AtmosObject object) {
|
||||
|
@ -121,24 +117,26 @@ public class StubAtmosStorageAsyncClient implements AtmosStorageAsyncClient {
|
|||
object.getContentMetadata().setName(path + "/" + file);
|
||||
}
|
||||
Blob blob = object2Blob.apply(object);
|
||||
return wrapFuture(blobStore.putBlob(container, blob), new Function<String, URI>() {
|
||||
return Futures.compose(Futures.makeListenable(blobStore.putBlob(container, blob)),
|
||||
new Function<String, URI>() {
|
||||
|
||||
public URI apply(String from) {
|
||||
return URI.create(uri);
|
||||
}
|
||||
public URI apply(String from) {
|
||||
return URI.create(uri);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public Future<Void> deletePath(String path) {
|
||||
if (path.indexOf('/') == -1)
|
||||
return wrapFuture(blobStore.deleteContainerImpl(path), new Function<Boolean, Void>() {
|
||||
return Futures.compose(Futures.makeListenable(blobStore.deleteContainerImpl(path)),
|
||||
new Function<Boolean, Void>() {
|
||||
|
||||
public Void apply(Boolean from) {
|
||||
return null;
|
||||
}
|
||||
public Void apply(Boolean from) {
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
else {
|
||||
String container = path.substring(0, path.indexOf('/'));
|
||||
path = path.substring(path.indexOf('/') + 1);
|
||||
|
@ -156,7 +154,7 @@ public class StubAtmosStorageAsyncClient implements AtmosStorageAsyncClient {
|
|||
else {
|
||||
String container = path.substring(0, path.indexOf('/'));
|
||||
path = path.substring(path.indexOf('/') + 1);
|
||||
return wrapFuture(blobStore.blobMetadata(container, path),
|
||||
return Futures.compose(Futures.makeListenable(blobStore.blobMetadata(container, path)),
|
||||
new Function<BlobMetadata, UserMetadata>() {
|
||||
public UserMetadata apply(BlobMetadata from) {
|
||||
return blob2ObjectInfo.apply(from).getUserMetadata();
|
||||
|
@ -169,10 +167,10 @@ public class StubAtmosStorageAsyncClient implements AtmosStorageAsyncClient {
|
|||
String container = path.substring(0, path.indexOf('/'));
|
||||
path = path.substring(path.indexOf('/') + 1);
|
||||
try {
|
||||
return wrapFuture(blobStore.getBlob(container, path), blob2Object);
|
||||
return Futures.compose(Futures.makeListenable(blobStore.getBlob(container, path)),
|
||||
blob2Object);
|
||||
} catch (Exception e) {
|
||||
Utils.<KeyNotFoundException> rethrowIfRuntimeOrSameType(e);
|
||||
throw new RuntimeException(e);
|
||||
return immediateFailedFuture(Throwables.getRootCause(e));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,7 +178,7 @@ public class StubAtmosStorageAsyncClient implements AtmosStorageAsyncClient {
|
|||
ListOptions... optionsList) {
|
||||
// org.jclouds.blobstore.options.ListOptions options = container2ContainerListOptions
|
||||
// .apply(optionsList);
|
||||
return wrapFuture(blobStore.list(), resource2ObjectList);
|
||||
return Futures.compose(Futures.makeListenable(blobStore.list()), resource2ObjectList);
|
||||
}
|
||||
|
||||
public Future<? extends BoundedSortedSet<? extends DirectoryEntry>> listDirectory(
|
||||
|
@ -194,7 +192,8 @@ public class StubAtmosStorageAsyncClient implements AtmosStorageAsyncClient {
|
|||
if (!path.equals(""))
|
||||
options.inDirectory(path);
|
||||
}
|
||||
return wrapFuture(blobStore.list(container, options), resource2ObjectList);
|
||||
return Futures.compose(Futures.makeListenable(blobStore.list(container, options)),
|
||||
resource2ObjectList);
|
||||
}
|
||||
|
||||
public AtmosObject newObject() {
|
||||
|
@ -205,19 +204,21 @@ public class StubAtmosStorageAsyncClient implements AtmosStorageAsyncClient {
|
|||
if (path.indexOf('/') == -1 || (path.endsWith("/")))
|
||||
return blobStore.containerExists(path);
|
||||
else {
|
||||
return new FutureBase<Boolean>() {
|
||||
public Boolean get() throws InterruptedException, ExecutionException {
|
||||
String container = path.substring(0, path.indexOf('/'));
|
||||
String blobName = path.substring(path.indexOf('/') + 1);
|
||||
try {
|
||||
blobStore.blobMetadata(container, blobName).get();
|
||||
return true;
|
||||
} catch (KeyNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
String container = path.substring(0, path.indexOf('/'));
|
||||
String blobName = path.substring(path.indexOf('/') + 1);
|
||||
try {
|
||||
blobStore.blobMetadata(container, blobName).get();
|
||||
return immediateFuture(true);
|
||||
} catch (KeyNotFoundException e) {
|
||||
return immediateFuture(false);
|
||||
} catch (InterruptedException e) {
|
||||
return immediateFuture(false);
|
||||
} catch (ExecutionException e) {
|
||||
if (Iterables.size(Iterables.filter(Throwables.getCausalChain(e),
|
||||
ResourceNotFoundException.class)) >= 1)
|
||||
return immediateFuture(false);
|
||||
return immediateFailedFuture(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,7 +226,8 @@ public class StubAtmosStorageAsyncClient implements AtmosStorageAsyncClient {
|
|||
String container = path.substring(0, path.indexOf('/'));
|
||||
String blobName = path.substring(path.indexOf('/') + 1);
|
||||
org.jclouds.blobstore.options.GetOptions getOptions = httpGetOptionsConverter.apply(options);
|
||||
return wrapFuture(blobStore.getBlob(container, blobName, getOptions), blob2Object);
|
||||
return Futures.compose(Futures.makeListenable(blobStore.getBlob(container, blobName,
|
||||
getOptions)), blob2Object);
|
||||
}
|
||||
|
||||
public Future<Void> updateFile(String parent, AtmosObject object) {
|
||||
|
|
|
@ -66,7 +66,7 @@ public class ParseAWSErrorFromXmlContent implements HttpErrorHandler {
|
|||
command.setException(new HttpResponseException(command, response, content));
|
||||
Utils.rethrowIfRuntime(he);
|
||||
}
|
||||
} else {
|
||||
} else if (response.getStatusCode() == 404){
|
||||
command.setException(new HttpResponseException(command, response));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -40,7 +40,6 @@ import org.jclouds.aws.s3.blobstore.internal.BaseS3BlobStore;
|
|||
import org.jclouds.aws.s3.domain.BucketMetadata;
|
||||
import org.jclouds.aws.s3.domain.ListBucketResponse;
|
||||
import org.jclouds.aws.s3.domain.ObjectMetadata;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.aws.s3.options.ListBucketOptions;
|
||||
import org.jclouds.blobstore.AsyncBlobStore;
|
||||
import org.jclouds.blobstore.KeyNotFoundException;
|
||||
|
@ -60,6 +59,7 @@ import org.jclouds.logging.Logger.LoggerFactory;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Iterables;
|
||||
import static com.google.common.util.concurrent.Futures.*;
|
||||
|
||||
public class S3AsyncBlobStore extends BaseS3BlobStore implements AsyncBlobStore {
|
||||
|
||||
|
@ -74,15 +74,14 @@ public class S3AsyncBlobStore extends BaseS3BlobStore implements AsyncBlobStore
|
|||
ExecutorService service) {
|
||||
super(async, sync, blobFactory, logFactory, clearContainerStrategy, object2BlobMd,
|
||||
object2Blob, blob2Object, container2BucketListOptions, blob2ObjectGetOptions,
|
||||
getDirectoryStrategy, mkdirStrategy, bucket2ResourceMd, bucket2ResourceList,
|
||||
service);
|
||||
getDirectoryStrategy, mkdirStrategy, bucket2ResourceMd, bucket2ResourceList, service);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation uses the S3 HEAD Object command to return the result
|
||||
*/
|
||||
public Future<BlobMetadata> blobMetadata(String container, String key) {
|
||||
return wrapFuture(async.headObject(container, key),
|
||||
return compose(makeListenable(async.headObject(container, key)),
|
||||
new Function<ObjectMetadata, BlobMetadata>() {
|
||||
|
||||
@Override
|
||||
|
@ -90,7 +89,7 @@ public class S3AsyncBlobStore extends BaseS3BlobStore implements AsyncBlobStore
|
|||
return object2BlobMd.apply(from);
|
||||
}
|
||||
|
||||
});
|
||||
}, service);
|
||||
}
|
||||
|
||||
public Future<Void> clearContainer(final String container) {
|
||||
|
@ -153,27 +152,27 @@ public class S3AsyncBlobStore extends BaseS3BlobStore implements AsyncBlobStore
|
|||
public Future<Blob> getBlob(String container, String key,
|
||||
org.jclouds.blobstore.options.GetOptions... optionsList) {
|
||||
GetOptions httpOptions = blob2ObjectGetOptions.apply(optionsList);
|
||||
Future<S3Object> returnVal = async.getObject(container, key, httpOptions);
|
||||
return wrapFuture(returnVal, object2Blob);
|
||||
return compose(makeListenable(async.getObject(container, key, httpOptions)), object2Blob,
|
||||
service);
|
||||
}
|
||||
|
||||
public Future<? extends ListResponse<? extends ResourceMetadata>> list() {
|
||||
return wrapFuture(
|
||||
async.listOwnedBuckets(),
|
||||
return compose(
|
||||
makeListenable(async.listOwnedBuckets()),
|
||||
new Function<SortedSet<BucketMetadata>, org.jclouds.blobstore.domain.ListResponse<? extends ResourceMetadata>>() {
|
||||
public org.jclouds.blobstore.domain.ListResponse<? extends ResourceMetadata> apply(
|
||||
SortedSet<BucketMetadata> from) {
|
||||
return new ListResponseImpl<ResourceMetadata>(Iterables.transform(from,
|
||||
bucket2ResourceMd), null, null, false);
|
||||
}
|
||||
});
|
||||
}, service);
|
||||
}
|
||||
|
||||
public Future<? extends ListContainerResponse<? extends ResourceMetadata>> list(
|
||||
String container, ListContainerOptions... optionsList) {
|
||||
ListBucketOptions httpOptions = container2BucketListOptions.apply(optionsList);
|
||||
Future<ListBucketResponse> returnVal = async.listBucket(container, httpOptions);
|
||||
return wrapFuture(returnVal, bucket2ResourceList);
|
||||
return compose(makeListenable(returnVal), bucket2ResourceList, service);
|
||||
}
|
||||
|
||||
public Future<String> putBlob(String container, Blob blob) {
|
||||
|
|
|
@ -21,7 +21,6 @@ package org.jclouds.aws.s3.blobstore.internal;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
|
@ -38,11 +37,8 @@ import org.jclouds.blobstore.domain.Blob;
|
|||
import org.jclouds.blobstore.strategy.ClearListStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetDirectoryStrategy;
|
||||
import org.jclouds.blobstore.strategy.MkdirStrategy;
|
||||
import org.jclouds.concurrent.FutureFunctionWrapper;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
public class BaseS3BlobStore {
|
||||
protected final S3AsyncClient async;
|
||||
protected final S3Client sync;
|
||||
|
@ -80,19 +76,13 @@ public class BaseS3BlobStore {
|
|||
this.container2BucketListOptions = checkNotNull(container2BucketListOptions,
|
||||
"container2BucketListOptions");
|
||||
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
|
||||
this.getDirectoryStrategy = checkNotNull(getDirectoryStrategy,
|
||||
"getDirectoryStrategy");
|
||||
this.getDirectoryStrategy = checkNotNull(getDirectoryStrategy, "getDirectoryStrategy");
|
||||
this.mkdirStrategy = checkNotNull(mkdirStrategy, "mkdirStrategy");
|
||||
this.bucket2ResourceMd = checkNotNull(bucket2ResourceMd, "bucket2ResourceMd");
|
||||
this.bucket2ResourceList = checkNotNull(bucket2ResourceList, "bucket2ResourceList");
|
||||
this.service = checkNotNull(service, "service");
|
||||
}
|
||||
|
||||
protected <F, T> Future<T> wrapFuture(Future<? extends F> future, Function<F, T> function) {
|
||||
return new FutureFunctionWrapper<F, T>(future, function, logFactory.getLogger(function
|
||||
.getClass().getName()));
|
||||
}
|
||||
|
||||
public Blob newBlob(String name) {
|
||||
Blob blob = blobFactory.create(null);
|
||||
blob.getMetadata().setName(name);
|
||||
|
|
|
@ -19,13 +19,14 @@
|
|||
package org.jclouds.aws.s3.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
|
||||
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -61,16 +62,14 @@ import org.jclouds.blobstore.domain.BlobMetadata;
|
|||
import org.jclouds.blobstore.domain.MutableBlobMetadata;
|
||||
import org.jclouds.blobstore.functions.HttpGetOptionsListToGetOptions;
|
||||
import org.jclouds.blobstore.integration.internal.StubAsyncBlobStore;
|
||||
import org.jclouds.blobstore.integration.internal.StubAsyncBlobStore.FutureBase;
|
||||
import org.jclouds.blobstore.options.ListContainerOptions;
|
||||
import org.jclouds.concurrent.FutureFunctionWrapper;
|
||||
import org.jclouds.date.DateService;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
|
||||
/**
|
||||
* Implementation of {@link S3AsyncBlobStore} which keeps all data in a local Map object.
|
||||
|
@ -83,7 +82,6 @@ public class StubS3AsyncClient implements S3AsyncClient {
|
|||
private final DateService dateService;
|
||||
private final HttpGetOptionsListToGetOptions httpGetOptionsConverter;
|
||||
private final StubAsyncBlobStore blobStore;
|
||||
private final LoggerFactory logFactory;
|
||||
private final S3Object.Factory objectProvider;
|
||||
private final Blob.Factory blobProvider;
|
||||
private final ObjectToBlob object2Blob;
|
||||
|
@ -93,7 +91,7 @@ public class StubS3AsyncClient implements S3AsyncClient {
|
|||
private final ResourceToBucketList resource2BucketList;
|
||||
|
||||
@Inject
|
||||
private StubS3AsyncClient(StubAsyncBlobStore blobStore, LoggerFactory logFactory,
|
||||
private StubS3AsyncClient(StubAsyncBlobStore blobStore,
|
||||
ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs,
|
||||
DateService dateService, S3Object.Factory objectProvider, Blob.Factory blobProvider,
|
||||
HttpGetOptionsListToGetOptions httpGetOptionsConverter, ObjectToBlob object2Blob,
|
||||
|
@ -101,7 +99,6 @@ public class StubS3AsyncClient implements S3AsyncClient {
|
|||
BucketToContainerListOptions bucket2ContainerListOptions,
|
||||
ResourceToBucketList resource2BucketList) {
|
||||
this.blobStore = blobStore;
|
||||
this.logFactory = logFactory;
|
||||
this.objectProvider = objectProvider;
|
||||
this.blobProvider = blobProvider;
|
||||
this.dateService = dateService;
|
||||
|
@ -125,11 +122,6 @@ public class StubS3AsyncClient implements S3AsyncClient {
|
|||
|
||||
public static final String DEFAULT_OWNER_ID = "abc123";
|
||||
|
||||
protected <F, T> Future<T> wrapFuture(Future<? extends F> future, Function<F, T> function) {
|
||||
return new FutureFunctionWrapper<F, T>(future, function, logFactory.getLogger(function
|
||||
.getClass().getName()));
|
||||
}
|
||||
|
||||
public Future<Boolean> putBucketIfNotExists(String name, PutBucketOptions... optionsList) {
|
||||
final PutBucketOptions options = (optionsList.length == 0) ? new PutBucketOptions()
|
||||
: optionsList[0];
|
||||
|
@ -141,7 +133,8 @@ public class StubS3AsyncClient implements S3AsyncClient {
|
|||
|
||||
public Future<ListBucketResponse> listBucket(final String name, ListBucketOptions... optionsList) {
|
||||
ListContainerOptions options = bucket2ContainerListOptions.apply(optionsList);
|
||||
return wrapFuture(blobStore.list(name, options), resource2BucketList);
|
||||
return Futures.compose(Futures.makeListenable(blobStore.list(name, options)),
|
||||
resource2BucketList);
|
||||
}
|
||||
|
||||
public Future<ObjectMetadata> copyObject(final String sourceBucket, final String sourceObject,
|
||||
|
@ -149,49 +142,41 @@ public class StubS3AsyncClient implements S3AsyncClient {
|
|||
CopyObjectOptions... nullableOptions) {
|
||||
final CopyObjectOptions options = (nullableOptions.length == 0) ? new CopyObjectOptions()
|
||||
: nullableOptions[0];
|
||||
return new FutureBase<ObjectMetadata>() {
|
||||
public ObjectMetadata get() throws InterruptedException, ExecutionException {
|
||||
ConcurrentMap<String, Blob> source = blobStore.getContainerToBlobs().get(sourceBucket);
|
||||
ConcurrentMap<String, Blob> dest = blobStore.getContainerToBlobs().get(
|
||||
destinationBucket);
|
||||
if (source.containsKey(sourceObject)) {
|
||||
Blob object = source.get(sourceObject);
|
||||
if (options.getIfMatch() != null) {
|
||||
if (!object.getMetadata().getETag().equals(options.getIfMatch()))
|
||||
blobStore.throwResponseException(412);
|
||||
|
||||
}
|
||||
if (options.getIfNoneMatch() != null) {
|
||||
if (object.getMetadata().getETag().equals(options.getIfNoneMatch()))
|
||||
blobStore.throwResponseException(412);
|
||||
}
|
||||
if (options.getIfModifiedSince() != null) {
|
||||
Date modifiedSince = dateService.rfc822DateParse(options.getIfModifiedSince());
|
||||
if (modifiedSince.after(object.getMetadata().getLastModified()))
|
||||
blobStore.throwResponseException(412);
|
||||
|
||||
}
|
||||
if (options.getIfUnmodifiedSince() != null) {
|
||||
Date unmodifiedSince = dateService
|
||||
.rfc822DateParse(options.getIfUnmodifiedSince());
|
||||
if (unmodifiedSince.before(object.getMetadata().getLastModified()))
|
||||
blobStore.throwResponseException(412);
|
||||
}
|
||||
Blob sourceS3 = source.get(sourceObject);
|
||||
MutableBlobMetadata newMd = blobStore
|
||||
.copy(sourceS3.getMetadata(), destinationObject);
|
||||
if (options.getAcl() != null)
|
||||
keyToAcl.put(destinationBucket + "/" + destinationObject, options.getAcl());
|
||||
|
||||
newMd.setLastModified(new Date());
|
||||
Blob newBlob = blobProvider.create(newMd);
|
||||
newBlob.setPayload(sourceS3.getContent());
|
||||
dest.put(destinationObject, newBlob);
|
||||
return blob2ObjectMetadata.apply(blobStore.copy(newMd));
|
||||
}
|
||||
throw new KeyNotFoundException(sourceBucket, sourceObject);
|
||||
ConcurrentMap<String, Blob> source = blobStore.getContainerToBlobs().get(sourceBucket);
|
||||
ConcurrentMap<String, Blob> dest = blobStore.getContainerToBlobs().get(destinationBucket);
|
||||
if (source.containsKey(sourceObject)) {
|
||||
Blob object = source.get(sourceObject);
|
||||
if (options.getIfMatch() != null) {
|
||||
if (!object.getMetadata().getETag().equals(options.getIfMatch()))
|
||||
return immediateFailedFuture(blobStore.returnResponseException(412));
|
||||
}
|
||||
};
|
||||
if (options.getIfNoneMatch() != null) {
|
||||
if (object.getMetadata().getETag().equals(options.getIfNoneMatch()))
|
||||
return immediateFailedFuture(blobStore.returnResponseException(412));
|
||||
}
|
||||
if (options.getIfModifiedSince() != null) {
|
||||
Date modifiedSince = dateService.rfc822DateParse(options.getIfModifiedSince());
|
||||
if (modifiedSince.after(object.getMetadata().getLastModified()))
|
||||
return immediateFailedFuture(blobStore.returnResponseException(412));
|
||||
|
||||
}
|
||||
if (options.getIfUnmodifiedSince() != null) {
|
||||
Date unmodifiedSince = dateService.rfc822DateParse(options.getIfUnmodifiedSince());
|
||||
if (unmodifiedSince.before(object.getMetadata().getLastModified()))
|
||||
return immediateFailedFuture(blobStore.returnResponseException(412));
|
||||
}
|
||||
Blob sourceS3 = source.get(sourceObject);
|
||||
MutableBlobMetadata newMd = blobStore.copy(sourceS3.getMetadata(), destinationObject);
|
||||
if (options.getAcl() != null)
|
||||
keyToAcl.put(destinationBucket + "/" + destinationObject, options.getAcl());
|
||||
|
||||
newMd.setLastModified(new Date());
|
||||
Blob newBlob = blobProvider.create(newMd);
|
||||
newBlob.setPayload(sourceS3.getContent());
|
||||
dest.put(destinationObject, newBlob);
|
||||
return immediateFuture((ObjectMetadata) blob2ObjectMetadata.apply(blobStore.copy(newMd)));
|
||||
}
|
||||
return immediateFailedFuture(new KeyNotFoundException(sourceBucket, sourceObject));
|
||||
}
|
||||
|
||||
public Future<String> putObject(final String bucketName, final S3Object object,
|
||||
|
@ -220,19 +205,11 @@ public class StubS3AsyncClient implements S3AsyncClient {
|
|||
}
|
||||
|
||||
public Future<AccessControlList> getBucketACL(final String bucket) {
|
||||
return new FutureBase<AccessControlList>() {
|
||||
public AccessControlList get() throws InterruptedException, ExecutionException {
|
||||
return getACLforS3Item(bucket);
|
||||
}
|
||||
};
|
||||
return immediateFuture(getACLforS3Item(bucket));
|
||||
}
|
||||
|
||||
public Future<AccessControlList> getObjectACL(final String bucket, final String objectKey) {
|
||||
return new FutureBase<AccessControlList>() {
|
||||
public AccessControlList get() throws InterruptedException, ExecutionException {
|
||||
return getACLforS3Item(bucket + "/" + objectKey);
|
||||
}
|
||||
};
|
||||
return immediateFuture(getACLforS3Item(bucket + "/" + objectKey));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -259,30 +236,18 @@ public class StubS3AsyncClient implements S3AsyncClient {
|
|||
}
|
||||
|
||||
public Future<Boolean> putBucketACL(final String bucket, final AccessControlList acl) {
|
||||
return new FutureBase<Boolean>() {
|
||||
public Boolean get() throws InterruptedException, ExecutionException {
|
||||
keyToAcl.put(bucket, sanitizeUploadedACL(acl));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
keyToAcl.put(bucket, sanitizeUploadedACL(acl));
|
||||
return immediateFuture(true);
|
||||
}
|
||||
|
||||
public Future<Boolean> putObjectACL(final String bucket, final String objectKey,
|
||||
final AccessControlList acl) {
|
||||
return new FutureBase<Boolean>() {
|
||||
public Boolean get() throws InterruptedException, ExecutionException {
|
||||
keyToAcl.put(bucket + "/" + objectKey, sanitizeUploadedACL(acl));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
keyToAcl.put(bucket + "/" + objectKey, sanitizeUploadedACL(acl));
|
||||
return immediateFuture(true);
|
||||
}
|
||||
|
||||
public Future<Boolean> bucketExists(final String bucketName) {
|
||||
return new FutureBase<Boolean>() {
|
||||
public Boolean get() throws InterruptedException, ExecutionException {
|
||||
return blobStore.getContainerToBlobs().containsKey(bucketName);
|
||||
}
|
||||
};
|
||||
return immediateFuture(blobStore.getContainerToBlobs().containsKey(bucketName));
|
||||
}
|
||||
|
||||
public Future<Boolean> deleteBucketIfEmpty(String bucketName) {
|
||||
|
@ -296,36 +261,28 @@ public class StubS3AsyncClient implements S3AsyncClient {
|
|||
public Future<S3Object> getObject(final String bucketName, final String key,
|
||||
final GetOptions... options) {
|
||||
org.jclouds.blobstore.options.GetOptions getOptions = httpGetOptionsConverter.apply(options);
|
||||
return wrapFuture(blobStore.getBlob(bucketName, key, getOptions), blob2Object);
|
||||
return Futures.compose(
|
||||
Futures.makeListenable(blobStore.getBlob(bucketName, key, getOptions)), blob2Object);
|
||||
}
|
||||
|
||||
public Future<ObjectMetadata> headObject(String bucketName, String key) {
|
||||
return wrapFuture(blobStore.blobMetadata(bucketName, key),
|
||||
return Futures.compose(Futures.makeListenable(blobStore.blobMetadata(bucketName, key)),
|
||||
new Function<BlobMetadata, ObjectMetadata>() {
|
||||
|
||||
@Override
|
||||
public ObjectMetadata apply(BlobMetadata from) {
|
||||
|
||||
return blob2ObjectMetadata.apply(from);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public Future<? extends SortedSet<BucketMetadata>> listOwnedBuckets() {
|
||||
return new FutureBase<SortedSet<BucketMetadata>>() {
|
||||
|
||||
public SortedSet<BucketMetadata> get() throws InterruptedException, ExecutionException {
|
||||
return Sets.newTreeSet(Iterables.transform(blobStore.getContainerToBlobs().keySet(),
|
||||
new Function<String, BucketMetadata>() {
|
||||
public BucketMetadata apply(String name) {
|
||||
return new BucketMetadata(name, null, null);
|
||||
}
|
||||
|
||||
}));
|
||||
return immediateFuture(Sets.newTreeSet(Iterables.transform(blobStore.getContainerToBlobs()
|
||||
.keySet(), new Function<String, BucketMetadata>() {
|
||||
public BucketMetadata apply(String name) {
|
||||
return new BucketMetadata(name, null, null);
|
||||
}
|
||||
};
|
||||
|
||||
})));
|
||||
}
|
||||
|
||||
public S3Object newS3Object() {
|
||||
|
@ -334,56 +291,33 @@ public class StubS3AsyncClient implements S3AsyncClient {
|
|||
|
||||
@Override
|
||||
public Future<LocationConstraint> getBucketLocation(String bucketName) {
|
||||
return new FutureBase<LocationConstraint>() {
|
||||
public LocationConstraint get() throws InterruptedException, ExecutionException {
|
||||
return LocationConstraint.US_STANDARD;
|
||||
}
|
||||
};
|
||||
return immediateFuture(LocationConstraint.US_STANDARD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Payer> getBucketPayer(String bucketName) {
|
||||
return new FutureBase<Payer>() {
|
||||
public Payer get() throws InterruptedException, ExecutionException {
|
||||
return Payer.BUCKET_OWNER;
|
||||
}
|
||||
};
|
||||
return immediateFuture(Payer.BUCKET_OWNER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> setBucketPayer(String bucketName, Payer payer) {
|
||||
return new FutureBase<Void>() {
|
||||
public Void get() throws InterruptedException, ExecutionException {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
return immediateFuture(null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> disableBucketLogging(String bucketName) {
|
||||
return new FutureBase<Void>() {
|
||||
public Void get() throws InterruptedException, ExecutionException {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
return immediateFuture(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> enableBucketLogging(String bucketName, BucketLogging logging) {
|
||||
return new FutureBase<Void>() {
|
||||
public Void get() throws InterruptedException, ExecutionException {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
return immediateFuture(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<BucketLogging> getBucketLogging(String bucketName) {
|
||||
return new FutureBase<BucketLogging>() {
|
||||
public BucketLogging get() throws InterruptedException, ExecutionException {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
return immediateFuture(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
package org.jclouds.azure.storage.blob.blobstore;
|
||||
|
||||
import static com.google.common.util.concurrent.Futures.compose;
|
||||
import static com.google.common.util.concurrent.Futures.makeListenable;
|
||||
import static org.jclouds.blobstore.options.ListContainerOptions.Builder.recursive;
|
||||
|
||||
import java.util.SortedSet;
|
||||
|
@ -81,7 +83,7 @@ public class AzureAsyncBlobStore extends BaseAzureBlobStore implements AsyncBlob
|
|||
* This implementation uses the AzureBlob HEAD Object command to return the result
|
||||
*/
|
||||
public Future<BlobMetadata> blobMetadata(String container, String key) {
|
||||
return wrapFuture(async.getBlobProperties(container, key),
|
||||
return compose(makeListenable(async.getBlobProperties(container, key)),
|
||||
new Function<BlobProperties, BlobMetadata>() {
|
||||
|
||||
@Override
|
||||
|
@ -89,7 +91,7 @@ public class AzureAsyncBlobStore extends BaseAzureBlobStore implements AsyncBlob
|
|||
return object2BlobMd.apply(from);
|
||||
}
|
||||
|
||||
});
|
||||
}, service);
|
||||
}
|
||||
|
||||
public Future<Void> clearContainer(final String container) {
|
||||
|
@ -120,26 +122,26 @@ public class AzureAsyncBlobStore extends BaseAzureBlobStore implements AsyncBlob
|
|||
org.jclouds.blobstore.options.GetOptions... optionsList) {
|
||||
GetOptions httpOptions = blob2ObjectGetOptions.apply(optionsList);
|
||||
Future<AzureBlob> returnVal = async.getBlob(container, key, httpOptions);
|
||||
return wrapFuture(returnVal, object2Blob);
|
||||
return compose(makeListenable(returnVal), object2Blob, service);
|
||||
}
|
||||
|
||||
public Future<? extends org.jclouds.blobstore.domain.ListResponse<? extends ResourceMetadata>> list() {
|
||||
return wrapFuture(
|
||||
async.listContainers(),
|
||||
return compose(
|
||||
makeListenable(async.listContainers()),
|
||||
new Function<SortedSet<ListableContainerProperties>, org.jclouds.blobstore.domain.ListResponse<? extends ResourceMetadata>>() {
|
||||
public org.jclouds.blobstore.domain.ListResponse<? extends ResourceMetadata> apply(
|
||||
SortedSet<ListableContainerProperties> from) {
|
||||
return new ListResponseImpl<ResourceMetadata>(Iterables.transform(from,
|
||||
container2ResourceMd), null, null, false);
|
||||
}
|
||||
});
|
||||
}, service);
|
||||
}
|
||||
|
||||
public Future<? extends ListContainerResponse<? extends ResourceMetadata>> list(
|
||||
String container, ListContainerOptions... optionsList) {
|
||||
ListBlobsOptions httpOptions = container2ContainerListOptions.apply(optionsList);
|
||||
Future<ListBlobsResponse> returnVal = async.listBlobs(container, httpOptions);
|
||||
return wrapFuture(returnVal, container2ResourceList);
|
||||
return compose(makeListenable(returnVal), container2ResourceList, service);
|
||||
}
|
||||
|
||||
public Future<String> putBlob(String container, Blob blob) {
|
||||
|
|
|
@ -21,7 +21,6 @@ package org.jclouds.azure.storage.blob.blobstore.internal;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
|
@ -38,11 +37,8 @@ import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
|
|||
import org.jclouds.blobstore.strategy.ClearListStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetDirectoryStrategy;
|
||||
import org.jclouds.blobstore.strategy.MkdirStrategy;
|
||||
import org.jclouds.concurrent.FutureFunctionWrapper;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
public class BaseAzureBlobStore {
|
||||
protected final AzureBlobAsyncClient async;
|
||||
protected final AzureBlobClient sync;
|
||||
|
@ -87,11 +83,6 @@ public class BaseAzureBlobStore {
|
|||
this.service = checkNotNull(service, "service");
|
||||
}
|
||||
|
||||
protected <F, T> Future<T> wrapFuture(Future<? extends F> future, Function<F, T> function) {
|
||||
return new FutureFunctionWrapper<F, T>(future, function, logFactory.getLogger(function
|
||||
.getClass().getName()));
|
||||
}
|
||||
|
||||
public Blob newBlob(String name) {
|
||||
Blob blob = blobFactory.create(null);
|
||||
blob.getMetadata().setName(name);
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
package org.jclouds.azure.storage.blob.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -51,13 +51,11 @@ import org.jclouds.blobstore.domain.Blob;
|
|||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.functions.HttpGetOptionsListToGetOptions;
|
||||
import org.jclouds.blobstore.integration.internal.StubAsyncBlobStore;
|
||||
import org.jclouds.blobstore.integration.internal.StubAsyncBlobStore.FutureBase;
|
||||
import org.jclouds.concurrent.FutureFunctionWrapper;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
|
||||
/**
|
||||
* Implementation of {@link AzureBlobAsyncClient} which keeps all data in a local Map object.
|
||||
|
@ -68,7 +66,6 @@ import com.google.common.collect.Iterables;
|
|||
public class StubAzureBlobAsyncClient implements AzureBlobAsyncClient {
|
||||
private final HttpGetOptionsListToGetOptions httpGetOptionsConverter;
|
||||
private final StubAsyncBlobStore blobStore;
|
||||
private final LoggerFactory logFactory;
|
||||
private final AzureBlob.Factory objectProvider;
|
||||
private final AzureBlobToBlob object2Blob;
|
||||
private final BlobToAzureBlob blob2Object;
|
||||
|
@ -78,14 +75,13 @@ public class StubAzureBlobAsyncClient implements AzureBlobAsyncClient {
|
|||
private final ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs;
|
||||
|
||||
@Inject
|
||||
private StubAzureBlobAsyncClient(StubAsyncBlobStore blobStore, LoggerFactory logFactory,
|
||||
private StubAzureBlobAsyncClient(StubAsyncBlobStore blobStore,
|
||||
ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs,
|
||||
AzureBlob.Factory objectProvider,
|
||||
HttpGetOptionsListToGetOptions httpGetOptionsConverter, AzureBlobToBlob object2Blob,
|
||||
BlobToAzureBlob blob2Object, BlobMetadataToBlobProperties blob2ObjectInfo,
|
||||
ListBlobsOptionsToListOptions container2ContainerListOptions,
|
||||
ResourceToListBlobsResponse resource2ContainerList) {
|
||||
this.logFactory = logFactory;
|
||||
this.containerToBlobs = containerToBlobs;
|
||||
this.blobStore = blobStore;
|
||||
this.objectProvider = objectProvider;
|
||||
|
@ -98,11 +94,6 @@ public class StubAzureBlobAsyncClient implements AzureBlobAsyncClient {
|
|||
this.resource2ObjectList = checkNotNull(resource2ContainerList, "resource2ContainerList");
|
||||
}
|
||||
|
||||
protected <F, T> Future<T> wrapFuture(Future<? extends F> future, Function<F, T> function) {
|
||||
return new FutureFunctionWrapper<F, T>(future, function, logFactory.getLogger(function
|
||||
.getClass().getName()));
|
||||
}
|
||||
|
||||
public Future<Boolean> createContainer(String container, CreateContainerOptions... options) {
|
||||
return blobStore.createContainer(container);
|
||||
}
|
||||
|
@ -116,12 +107,8 @@ public class StubAzureBlobAsyncClient implements AzureBlobAsyncClient {
|
|||
}
|
||||
|
||||
public Future<Void> deleteContainer(final String container) {
|
||||
return new FutureBase<Void>() {
|
||||
public Void get() throws InterruptedException, ExecutionException {
|
||||
StubAzureBlobAsyncClient.this.containerToBlobs.remove(container);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
StubAzureBlobAsyncClient.this.containerToBlobs.remove(container);
|
||||
return immediateFuture(null);
|
||||
}
|
||||
|
||||
public Future<Boolean> deleteRootContainer() {
|
||||
|
@ -130,11 +117,12 @@ public class StubAzureBlobAsyncClient implements AzureBlobAsyncClient {
|
|||
|
||||
public Future<AzureBlob> getBlob(String container, String key, GetOptions... options) {
|
||||
org.jclouds.blobstore.options.GetOptions getOptions = httpGetOptionsConverter.apply(options);
|
||||
return wrapFuture(blobStore.getBlob(container, key, getOptions), blob2Object);
|
||||
return Futures.compose(Futures.makeListenable(blobStore.getBlob(container, key, getOptions)),
|
||||
blob2Object);
|
||||
}
|
||||
|
||||
public Future<BlobProperties> getBlobProperties(String container, String key) {
|
||||
return wrapFuture(blobStore.blobMetadata(container, key),
|
||||
return Futures.compose(Futures.makeListenable(blobStore.blobMetadata(container, key)),
|
||||
new Function<BlobMetadata, BlobProperties>() {
|
||||
|
||||
@Override
|
||||
|
@ -153,7 +141,8 @@ public class StubAzureBlobAsyncClient implements AzureBlobAsyncClient {
|
|||
public Future<ListBlobsResponse> listBlobs(String container, ListBlobsOptions... optionsList) {
|
||||
org.jclouds.blobstore.options.ListContainerOptions options = container2ContainerListOptions
|
||||
.apply(optionsList);
|
||||
return wrapFuture(blobStore.list(container, options), resource2ObjectList);
|
||||
return Futures.compose(Futures.makeListenable(blobStore.list(container, options)),
|
||||
resource2ObjectList);
|
||||
}
|
||||
|
||||
public Future<ListBlobsResponse> listBlobs(ListBlobsOptions... options) {
|
||||
|
@ -162,21 +151,15 @@ public class StubAzureBlobAsyncClient implements AzureBlobAsyncClient {
|
|||
|
||||
public Future<? extends BoundedSortedSet<ListableContainerProperties>> listContainers(
|
||||
ListOptions... listOptions) {
|
||||
return new FutureBase<BoundedSortedSet<ListableContainerProperties>>() {
|
||||
return immediateFuture(new BoundedTreeSet<ListableContainerProperties>(Iterables.transform(
|
||||
blobStore.getContainerToBlobs().keySet(),
|
||||
new Function<String, ListableContainerProperties>() {
|
||||
public ListableContainerProperties apply(String name) {
|
||||
return new ListableContainerPropertiesImpl(URI.create("http://stub/" + name),
|
||||
new Date(), "");
|
||||
}
|
||||
|
||||
public BoundedSortedSet<ListableContainerProperties> get() throws InterruptedException,
|
||||
ExecutionException {
|
||||
return new BoundedTreeSet<ListableContainerProperties>(Iterables.transform(blobStore
|
||||
.getContainerToBlobs().keySet(),
|
||||
new Function<String, ListableContainerProperties>() {
|
||||
public ListableContainerProperties apply(String name) {
|
||||
return new ListableContainerPropertiesImpl(URI.create("http://stub/"
|
||||
+ name), new Date(), "");
|
||||
}
|
||||
|
||||
}), null, null, null, null, null);
|
||||
}
|
||||
};
|
||||
}), null, null, null, null, null));
|
||||
}
|
||||
|
||||
public AzureBlob newBlob() {
|
||||
|
@ -196,11 +179,7 @@ public class StubAzureBlobAsyncClient implements AzureBlobAsyncClient {
|
|||
}
|
||||
|
||||
public Future<Boolean> containerExists(final String container) {
|
||||
return new FutureBase<Boolean>() {
|
||||
public Boolean get() throws InterruptedException, ExecutionException {
|
||||
return blobStore.getContainerToBlobs().containsKey(container);
|
||||
}
|
||||
};
|
||||
return immediateFuture(blobStore.getContainerToBlobs().containsKey(container));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ import java.util.concurrent.TimeUnit;
|
|||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.blobstore.AsyncBlobStore;
|
||||
import org.jclouds.blobstore.KeyNotFoundException;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ListResponse;
|
||||
|
@ -43,9 +42,11 @@ import org.jclouds.blobstore.strategy.ContainsValueInListStrategy;
|
|||
import org.jclouds.blobstore.strategy.CountListStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetBlobsInListStrategy;
|
||||
import org.jclouds.blobstore.strategy.ListBlobMetadataStrategy;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.inject.Inject;
|
||||
|
@ -204,9 +205,10 @@ public abstract class BaseBlobMap<V> {
|
|||
try {
|
||||
return connection.blobMetadata(containerName, realKey).get(requestTimeoutMilliseconds,
|
||||
TimeUnit.MILLISECONDS) != null;
|
||||
} catch (KeyNotFoundException e) {
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
if (Iterables.size(Iterables.filter(Throwables.getCausalChain(e),
|
||||
ResourceNotFoundException.class)) >= 1)
|
||||
return false;
|
||||
Utils.<BlobRuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
throw new BlobRuntimeException(String.format("Error searching for %1$s:%2$s",
|
||||
containerName, realKey), e);
|
||||
|
|
|
@ -27,8 +27,8 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.blobstore.BlobMap;
|
||||
import org.jclouds.blobstore.AsyncBlobStore;
|
||||
import org.jclouds.blobstore.BlobMap;
|
||||
import org.jclouds.blobstore.KeyNotFoundException;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.options.ListContainerOptions;
|
||||
|
@ -40,6 +40,7 @@ import org.jclouds.blobstore.strategy.ListBlobMetadataStrategy;
|
|||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
|
@ -118,15 +119,13 @@ public class BlobMapImpl extends BaseBlobMap<Blob> implements BlobMap {
|
|||
return stripPrefix(connection.getBlob(containerName, realKey).get(
|
||||
requestTimeoutMilliseconds, TimeUnit.MILLISECONDS));
|
||||
} catch (Exception e) {
|
||||
if (e instanceof KeyNotFoundException)
|
||||
Throwable cause = Throwables.getRootCause(e);
|
||||
if (cause instanceof KeyNotFoundException) {
|
||||
return null;
|
||||
// the following will unwrap any exceptions, so we should double-check that it
|
||||
// wasn't unwrapped to a KNFE
|
||||
e = Utils.<BlobRuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
if (e instanceof KeyNotFoundException)
|
||||
return null;
|
||||
throw new BlobRuntimeException(String.format("Error geting object %1$s:%2$s",
|
||||
containerName, realKey), e);
|
||||
} else {
|
||||
throw new BlobRuntimeException(String.format("Error geting object %1$s:%2$s",
|
||||
containerName, realKey), cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ import org.jclouds.util.Utils;
|
|||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
|
@ -86,7 +87,10 @@ public class InputStreamMapImpl extends BaseBlobMap<InputStream> implements Inpu
|
|||
} catch (KeyNotFoundException e) {
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
Utils.<BlobRuntimeException> rethrowIfRuntimeOrSameType(e);
|
||||
Throwable cause = Throwables.getRootCause(e);
|
||||
if (cause instanceof KeyNotFoundException)
|
||||
return null;
|
||||
Throwables.propagateIfInstanceOf(e, BlobRuntimeException.class);
|
||||
throw new BlobRuntimeException(String.format("Error geting object %1$s:%2$s",
|
||||
containerName, realKey), e);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.jclouds.blobstore.strategy.ListBlobMetadataStrategy;
|
|||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.inject.Inject;
|
||||
|
@ -107,11 +108,15 @@ public class GetAllBlobsInListAndRetryOnFailure implements GetBlobsInListStrateg
|
|||
object.getMetadata().setName(key);
|
||||
objects.add(object);
|
||||
return;
|
||||
} catch (KeyNotFoundException e) {
|
||||
Thread.sleep(requestRetryMilliseconds);
|
||||
value = connection.getBlob(container, key);
|
||||
} catch (Exception e) {
|
||||
Throwable cause = Throwables.getRootCause(e);
|
||||
if (cause instanceof KeyNotFoundException) {
|
||||
Thread.sleep(requestRetryMilliseconds);
|
||||
value = connection.getBlob(container, key);
|
||||
} else {
|
||||
Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -19,6 +19,8 @@
|
|||
package org.jclouds.blobstore.integration.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
|
||||
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
@ -41,11 +43,8 @@ import java.util.Map.Entry;
|
|||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
@ -154,109 +153,99 @@ public class StubAsyncBlobStore implements AsyncBlobStore {
|
|||
}
|
||||
|
||||
public Future<Blob> getBlob(final String bucketName, final String key) {
|
||||
return new FutureBase<Blob>() {
|
||||
public Blob get() throws InterruptedException, ExecutionException {
|
||||
if (!getContainerToBlobs().containsKey(bucketName))
|
||||
throw new ContainerNotFoundException(bucketName);
|
||||
Map<String, Blob> realContents = getContainerToBlobs().get(bucketName);
|
||||
if (!realContents.containsKey(key))
|
||||
throw new KeyNotFoundException(bucketName, key);
|
||||
|
||||
Blob object = realContents.get(key);
|
||||
Blob returnVal = blobProvider.create(copy(object.getMetadata()));
|
||||
returnVal.setPayload(object.getContent());
|
||||
return returnVal;
|
||||
}
|
||||
};
|
||||
if (!getContainerToBlobs().containsKey(bucketName))
|
||||
return immediateFailedFuture(new ContainerNotFoundException(bucketName));
|
||||
Map<String, Blob> realContents = getContainerToBlobs().get(bucketName);
|
||||
if (!realContents.containsKey(key))
|
||||
return immediateFailedFuture(new KeyNotFoundException(bucketName, key));
|
||||
Blob object = realContents.get(key);
|
||||
Blob returnVal = blobProvider.create(copy(object.getMetadata()));
|
||||
returnVal.setPayload(object.getContent());
|
||||
return immediateFuture(returnVal);
|
||||
}
|
||||
|
||||
public Future<? extends ListContainerResponse<? extends ResourceMetadata>> list(
|
||||
final String name, ListContainerOptions... optionsList) {
|
||||
final ListContainerOptions options = (optionsList.length == 0) ? new ListContainerOptions()
|
||||
: optionsList[0];
|
||||
return new FutureBase<ListContainerResponse<ResourceMetadata>>() {
|
||||
public ListContainerResponse<ResourceMetadata> get() throws InterruptedException,
|
||||
ExecutionException {
|
||||
final Map<String, Blob> realContents = getContainerToBlobs().get(name);
|
||||
|
||||
if (realContents == null)
|
||||
throw new ContainerNotFoundException(name);
|
||||
final Map<String, Blob> realContents = getContainerToBlobs().get(name);
|
||||
|
||||
SortedSet<ResourceMetadata> contents = Sets.newTreeSet(Iterables.transform(realContents
|
||||
.keySet(), new Function<String, ResourceMetadata>() {
|
||||
public ResourceMetadata apply(String key) {
|
||||
MutableBlobMetadata md = copy(realContents.get(key).getMetadata());
|
||||
if (isDirectoryStrategy.execute(md))
|
||||
md.setType(ResourceType.RELATIVE_PATH);
|
||||
return md;
|
||||
}
|
||||
}));
|
||||
if (realContents == null)
|
||||
return immediateFailedFuture(new ContainerNotFoundException(name));
|
||||
|
||||
if (options.getMarker() != null) {
|
||||
final String finalMarker = options.getMarker();
|
||||
ResourceMetadata lastMarkerMetadata = Iterables.find(contents,
|
||||
new Predicate<ResourceMetadata>() {
|
||||
public boolean apply(ResourceMetadata metadata) {
|
||||
return metadata.getName().equals(finalMarker);
|
||||
}
|
||||
});
|
||||
contents = contents.tailSet(lastMarkerMetadata);
|
||||
contents.remove(lastMarkerMetadata);
|
||||
}
|
||||
|
||||
final String prefix = options.getDir();
|
||||
if (prefix != null) {
|
||||
contents = Sets.newTreeSet(Iterables.filter(contents,
|
||||
new Predicate<ResourceMetadata>() {
|
||||
public boolean apply(ResourceMetadata o) {
|
||||
return (o != null && o.getName().startsWith(prefix));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
int maxResults = contents.size();
|
||||
boolean truncated = false;
|
||||
String marker = null;
|
||||
if (options.getMaxResults() != null && contents.size() > 0) {
|
||||
SortedSet<ResourceMetadata> contentsSlice = firstSliceOfSize(contents, options
|
||||
.getMaxResults().intValue());
|
||||
maxResults = options.getMaxResults();
|
||||
if (!contentsSlice.contains(contents.last())) {
|
||||
// Partial listing
|
||||
truncated = true;
|
||||
marker = contentsSlice.last().getName();
|
||||
} else {
|
||||
marker = null;
|
||||
}
|
||||
contents = contentsSlice;
|
||||
}
|
||||
|
||||
final String delimiter = options.isRecursive() ? null : "/";
|
||||
if (delimiter != null) {
|
||||
SortedSet<String> commonPrefixes = null;
|
||||
Iterable<String> iterable = Iterables.transform(contents, new CommonPrefixes(
|
||||
prefix != null ? prefix : null, delimiter));
|
||||
commonPrefixes = iterable != null ? Sets.newTreeSet(iterable)
|
||||
: new TreeSet<String>();
|
||||
commonPrefixes.remove(CommonPrefixes.NO_PREFIX);
|
||||
|
||||
contents = Sets.newTreeSet(Iterables.filter(contents, new DelimiterFilter(
|
||||
prefix != null ? prefix : null, delimiter)));
|
||||
|
||||
Iterables.<ResourceMetadata> addAll(contents, Iterables.transform(commonPrefixes,
|
||||
new Function<String, ResourceMetadata>() {
|
||||
public ResourceMetadata apply(String o) {
|
||||
MutableResourceMetadata md = new MutableResourceMetadataImpl();
|
||||
md.setType(ResourceType.RELATIVE_PATH);
|
||||
md.setName(o);
|
||||
return md;
|
||||
}
|
||||
}));
|
||||
}
|
||||
return new ListContainerResponseImpl<ResourceMetadata>(contents, prefix, marker,
|
||||
maxResults, truncated);
|
||||
SortedSet<ResourceMetadata> contents = Sets.newTreeSet(Iterables.transform(realContents
|
||||
.keySet(), new Function<String, ResourceMetadata>() {
|
||||
public ResourceMetadata apply(String key) {
|
||||
MutableBlobMetadata md = copy(realContents.get(key).getMetadata());
|
||||
if (isDirectoryStrategy.execute(md))
|
||||
md.setType(ResourceType.RELATIVE_PATH);
|
||||
return md;
|
||||
}
|
||||
};
|
||||
}));
|
||||
|
||||
if (options.getMarker() != null) {
|
||||
final String finalMarker = options.getMarker();
|
||||
ResourceMetadata lastMarkerMetadata = Iterables.find(contents,
|
||||
new Predicate<ResourceMetadata>() {
|
||||
public boolean apply(ResourceMetadata metadata) {
|
||||
return metadata.getName().equals(finalMarker);
|
||||
}
|
||||
});
|
||||
contents = contents.tailSet(lastMarkerMetadata);
|
||||
contents.remove(lastMarkerMetadata);
|
||||
}
|
||||
|
||||
final String prefix = options.getDir();
|
||||
if (prefix != null) {
|
||||
contents = Sets.newTreeSet(Iterables.filter(contents, new Predicate<ResourceMetadata>() {
|
||||
public boolean apply(ResourceMetadata o) {
|
||||
return (o != null && o.getName().startsWith(prefix));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
int maxResults = contents.size();
|
||||
boolean truncated = false;
|
||||
String marker = null;
|
||||
if (options.getMaxResults() != null && contents.size() > 0) {
|
||||
SortedSet<ResourceMetadata> contentsSlice = firstSliceOfSize(contents, options
|
||||
.getMaxResults().intValue());
|
||||
maxResults = options.getMaxResults();
|
||||
if (!contentsSlice.contains(contents.last())) {
|
||||
// Partial listing
|
||||
truncated = true;
|
||||
marker = contentsSlice.last().getName();
|
||||
} else {
|
||||
marker = null;
|
||||
}
|
||||
contents = contentsSlice;
|
||||
}
|
||||
|
||||
final String delimiter = options.isRecursive() ? null : "/";
|
||||
if (delimiter != null) {
|
||||
SortedSet<String> commonPrefixes = null;
|
||||
Iterable<String> iterable = Iterables.transform(contents, new CommonPrefixes(
|
||||
prefix != null ? prefix : null, delimiter));
|
||||
commonPrefixes = iterable != null ? Sets.newTreeSet(iterable) : new TreeSet<String>();
|
||||
commonPrefixes.remove(CommonPrefixes.NO_PREFIX);
|
||||
|
||||
contents = Sets.newTreeSet(Iterables.filter(contents, new DelimiterFilter(
|
||||
prefix != null ? prefix : null, delimiter)));
|
||||
|
||||
Iterables.<ResourceMetadata> addAll(contents, Iterables.transform(commonPrefixes,
|
||||
new Function<String, ResourceMetadata>() {
|
||||
public ResourceMetadata apply(String o) {
|
||||
MutableResourceMetadata md = new MutableResourceMetadataImpl();
|
||||
md.setType(ResourceType.RELATIVE_PATH);
|
||||
md.setName(o);
|
||||
return md;
|
||||
}
|
||||
}));
|
||||
}
|
||||
return immediateFuture(new ListContainerResponseImpl<ResourceMetadata>(contents, prefix,
|
||||
marker, maxResults, truncated));
|
||||
|
||||
}
|
||||
|
||||
public MutableBlobMetadata copy(MutableBlobMetadata in) {
|
||||
|
@ -288,96 +277,54 @@ public class StubAsyncBlobStore implements AsyncBlobStore {
|
|||
return newMd;
|
||||
}
|
||||
|
||||
public BlobMetadata metadata(final String container, final String key) {
|
||||
if (!getContainerToBlobs().containsKey(container))
|
||||
throw new ContainerNotFoundException(container);
|
||||
Map<String, Blob> realContents = getContainerToBlobs().get(container);
|
||||
if (!realContents.containsKey(key))
|
||||
throw new KeyNotFoundException(container, key);
|
||||
return copy(realContents.get(key).getMetadata());
|
||||
}
|
||||
// public BlobMetadata metadata(final String container, final String key) {
|
||||
// if (!getContainerToBlobs().containsKey(container))
|
||||
// return immediateFailedFuture(new ContainerNotFoundException(container));
|
||||
// Map<String, Blob> realContents = getContainerToBlobs().get(container);
|
||||
// if (!realContents.containsKey(key))
|
||||
// return immediateFailedFuture(new KeyNotFoundException(container, key));
|
||||
// return copy(realContents.get(key).getMetadata());
|
||||
// }
|
||||
|
||||
public Future<Void> removeBlob(final String container, final String key) {
|
||||
return new FutureBase<Void>() {
|
||||
public Void get() throws InterruptedException, ExecutionException {
|
||||
if (getContainerToBlobs().containsKey(container)) {
|
||||
getContainerToBlobs().get(container).remove(key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
if (getContainerToBlobs().containsKey(container)) {
|
||||
getContainerToBlobs().get(container).remove(key);
|
||||
}
|
||||
return immediateFuture(null);
|
||||
}
|
||||
|
||||
public Future<Void> deleteContainer(final String container) {
|
||||
return new FutureBase<Void>() {
|
||||
public Void get() throws InterruptedException, ExecutionException {
|
||||
if (getContainerToBlobs().containsKey(container)) {
|
||||
getContainerToBlobs().remove(container);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
if (getContainerToBlobs().containsKey(container)) {
|
||||
getContainerToBlobs().remove(container);
|
||||
}
|
||||
return immediateFuture(null);
|
||||
}
|
||||
|
||||
public Future<Boolean> deleteContainerImpl(final String container) {
|
||||
return new FutureBase<Boolean>() {
|
||||
public Boolean get() throws InterruptedException, ExecutionException {
|
||||
if (getContainerToBlobs().containsKey(container)) {
|
||||
if (getContainerToBlobs().get(container).size() == 0)
|
||||
getContainerToBlobs().remove(container);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
Boolean returnVal = true;
|
||||
if (getContainerToBlobs().containsKey(container)) {
|
||||
if (getContainerToBlobs().get(container).size() == 0)
|
||||
getContainerToBlobs().remove(container);
|
||||
else
|
||||
returnVal = false;
|
||||
}
|
||||
return immediateFuture(returnVal);
|
||||
}
|
||||
|
||||
public Future<Boolean> containerExists(final String container) {
|
||||
return new FutureBase<Boolean>() {
|
||||
public Boolean get() throws InterruptedException, ExecutionException {
|
||||
return getContainerToBlobs().containsKey(container);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static abstract class FutureBase<V> implements Future<V> {
|
||||
public boolean cancel(boolean b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public V get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
return get();
|
||||
}
|
||||
return immediateFuture(getContainerToBlobs().containsKey(container));
|
||||
}
|
||||
|
||||
public Future<? extends ListResponse<? extends ResourceMetadata>> list() {
|
||||
return new FutureBase<ListResponse<? extends ResourceMetadata>>() {
|
||||
|
||||
public ListResponse<ResourceMetadata> get() throws InterruptedException,
|
||||
ExecutionException {
|
||||
return new ListResponseImpl<ResourceMetadata>(Iterables.transform(getContainerToBlobs()
|
||||
.keySet(), new Function<String, ResourceMetadata>() {
|
||||
public ResourceMetadata apply(String name) {
|
||||
MutableResourceMetadata cmd = create();
|
||||
cmd.setName(name);
|
||||
cmd.setType(ResourceType.CONTAINER);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
}), null, null, false);
|
||||
}
|
||||
|
||||
};
|
||||
return immediateFuture(new ListResponseImpl<ResourceMetadata>(Iterables.transform(
|
||||
getContainerToBlobs().keySet(), new Function<String, ResourceMetadata>() {
|
||||
public ResourceMetadata apply(String name) {
|
||||
MutableResourceMetadata cmd = create();
|
||||
cmd.setName(name);
|
||||
cmd.setType(ResourceType.CONTAINER);
|
||||
return cmd;
|
||||
}
|
||||
}), null, null, false));
|
||||
|
||||
}
|
||||
|
||||
|
@ -386,14 +333,10 @@ public class StubAsyncBlobStore implements AsyncBlobStore {
|
|||
}
|
||||
|
||||
public Future<Boolean> createContainer(final String name) {
|
||||
return new FutureBase<Boolean>() {
|
||||
public Boolean get() throws InterruptedException, ExecutionException {
|
||||
if (!getContainerToBlobs().containsKey(name)) {
|
||||
getContainerToBlobs().put(name, new ConcurrentHashMap<String, Blob>());
|
||||
}
|
||||
return getContainerToBlobs().containsKey(name);
|
||||
}
|
||||
};
|
||||
if (!getContainerToBlobs().containsKey(name)) {
|
||||
getContainerToBlobs().put(name, new ConcurrentHashMap<String, Blob>());
|
||||
}
|
||||
return immediateFuture(getContainerToBlobs().containsKey(name));
|
||||
}
|
||||
|
||||
public String getFirstQueryOrNull(String string, @Nullable HttpRequestOptions options) {
|
||||
|
@ -452,11 +395,11 @@ public class StubAsyncBlobStore implements AsyncBlobStore {
|
|||
return Sets.newTreeSet(slices.get(0));
|
||||
}
|
||||
|
||||
public void throwResponseException(int code) throws ExecutionException {
|
||||
public HttpResponseException returnResponseException(int code) {
|
||||
HttpResponse response = null;
|
||||
response = new HttpResponse(); // TODO: Get real object URL?
|
||||
response.setStatusCode(code);
|
||||
throw new ExecutionException(new HttpResponseException(new HttpCommand() {
|
||||
return new HttpResponseException(new HttpCommand() {
|
||||
|
||||
public int getRedirectCount() {
|
||||
return 0;
|
||||
|
@ -499,7 +442,7 @@ public class StubAsyncBlobStore implements AsyncBlobStore {
|
|||
@Override
|
||||
public void redirectPath(String newPath) {
|
||||
}
|
||||
}, response));
|
||||
}, response);
|
||||
}
|
||||
|
||||
public Future<String> putBlob(final String bucketName, final Blob object) {
|
||||
|
@ -531,14 +474,9 @@ public class StubAsyncBlobStore implements AsyncBlobStore {
|
|||
for (Entry<String, String> userMD : newMd.getUserMetadata().entrySet()) {
|
||||
blob.getAllHeaders().put(userMD.getKey(), userMD.getValue());
|
||||
}
|
||||
|
||||
return new FutureBase<String>() {
|
||||
public String get() throws InterruptedException, ExecutionException {
|
||||
return eTag;
|
||||
}
|
||||
};
|
||||
return immediateFuture(eTag);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
return immediateFailedFuture(new RuntimeException(e));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -546,95 +484,88 @@ public class StubAsyncBlobStore implements AsyncBlobStore {
|
|||
public Future<? extends Blob> getBlob(final String bucketName, final String key,
|
||||
GetOptions... optionsList) {
|
||||
final GetOptions options = (optionsList.length == 0) ? new GetOptions() : optionsList[0];
|
||||
return new FutureBase<Blob>() {
|
||||
public Blob get() throws InterruptedException, ExecutionException {
|
||||
if (!getContainerToBlobs().containsKey(bucketName))
|
||||
throw new ContainerNotFoundException(bucketName);
|
||||
Map<String, Blob> realContents = getContainerToBlobs().get(bucketName);
|
||||
if (!realContents.containsKey(key))
|
||||
throw new KeyNotFoundException(bucketName, key);
|
||||
if (!getContainerToBlobs().containsKey(bucketName))
|
||||
return immediateFailedFuture(new ContainerNotFoundException(bucketName));
|
||||
Map<String, Blob> realContents = getContainerToBlobs().get(bucketName);
|
||||
if (!realContents.containsKey(key))
|
||||
return immediateFailedFuture(new KeyNotFoundException(bucketName, key));
|
||||
|
||||
Blob object = realContents.get(key);
|
||||
Blob object = realContents.get(key);
|
||||
|
||||
if (options.getIfMatch() != null) {
|
||||
if (!object.getMetadata().getETag().equals(options.getIfMatch()))
|
||||
throwResponseException(412);
|
||||
}
|
||||
if (options.getIfNoneMatch() != null) {
|
||||
if (object.getMetadata().getETag().equals(options.getIfNoneMatch()))
|
||||
throwResponseException(304);
|
||||
}
|
||||
if (options.getIfModifiedSince() != null) {
|
||||
Date modifiedSince = options.getIfModifiedSince();
|
||||
if (object.getMetadata().getLastModified().before(modifiedSince)) {
|
||||
HttpResponse response = new HttpResponse();
|
||||
response.setStatusCode(304);
|
||||
throw new ExecutionException(new HttpResponseException(String.format(
|
||||
"%1$s is before %2$s", object.getMetadata().getLastModified(),
|
||||
modifiedSince), null, response));
|
||||
}
|
||||
|
||||
}
|
||||
if (options.getIfUnmodifiedSince() != null) {
|
||||
Date unmodifiedSince = options.getIfUnmodifiedSince();
|
||||
if (object.getMetadata().getLastModified().after(unmodifiedSince)) {
|
||||
HttpResponse response = new HttpResponse();
|
||||
response.setStatusCode(412);
|
||||
throw new ExecutionException(new HttpResponseException(String.format(
|
||||
"%1$s is after %2$s", object.getMetadata().getLastModified(),
|
||||
unmodifiedSince), null, response));
|
||||
}
|
||||
}
|
||||
Blob returnVal = copyBlob(object);
|
||||
|
||||
if (options.getRanges() != null && options.getRanges().size() > 0) {
|
||||
byte[] data;
|
||||
try {
|
||||
data = ByteStreams.toByteArray(returnVal.getPayload().getContent());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
for (String s : options.getRanges()) {
|
||||
if (s.startsWith("-")) {
|
||||
int length = Integer.parseInt(s.substring(1));
|
||||
out.write(data, data.length - length, length);
|
||||
} else if (s.endsWith("-")) {
|
||||
int offset = Integer.parseInt(s.substring(0, s.length() - 1));
|
||||
out.write(data, offset, data.length - offset);
|
||||
} else if (s.contains("-")) {
|
||||
String[] firstLast = s.split("\\-");
|
||||
int offset = Integer.parseInt(firstLast[0]);
|
||||
int last = Integer.parseInt(firstLast[1]);
|
||||
int length = (last < data.length) ? last + 1 : data.length - offset;
|
||||
out.write(data, offset, length);
|
||||
} else {
|
||||
throw new IllegalArgumentException("first and last were null!");
|
||||
}
|
||||
|
||||
}
|
||||
returnVal.setPayload(out.toByteArray());
|
||||
returnVal.setContentLength(out.size());
|
||||
returnVal.getMetadata().setSize(new Long(data.length));
|
||||
}
|
||||
returnVal.setPayload(returnVal.getPayload());
|
||||
return returnVal;
|
||||
if (options.getIfMatch() != null) {
|
||||
if (!object.getMetadata().getETag().equals(options.getIfMatch()))
|
||||
return immediateFailedFuture(returnResponseException(412));
|
||||
}
|
||||
if (options.getIfNoneMatch() != null) {
|
||||
if (object.getMetadata().getETag().equals(options.getIfNoneMatch()))
|
||||
return immediateFailedFuture(returnResponseException(304));
|
||||
}
|
||||
if (options.getIfModifiedSince() != null) {
|
||||
Date modifiedSince = options.getIfModifiedSince();
|
||||
if (object.getMetadata().getLastModified().before(modifiedSince)) {
|
||||
HttpResponse response = new HttpResponse();
|
||||
response.setStatusCode(304);
|
||||
return immediateFailedFuture(new HttpResponseException(String.format(
|
||||
"%1$s is before %2$s", object.getMetadata().getLastModified(), modifiedSince),
|
||||
null, response));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
if (options.getIfUnmodifiedSince() != null) {
|
||||
Date unmodifiedSince = options.getIfUnmodifiedSince();
|
||||
if (object.getMetadata().getLastModified().after(unmodifiedSince)) {
|
||||
HttpResponse response = new HttpResponse();
|
||||
response.setStatusCode(412);
|
||||
return immediateFailedFuture(new HttpResponseException(
|
||||
String.format("%1$s is after %2$s", object.getMetadata().getLastModified(),
|
||||
unmodifiedSince), null, response));
|
||||
}
|
||||
}
|
||||
Blob returnVal = copyBlob(object);
|
||||
|
||||
if (options.getRanges() != null && options.getRanges().size() > 0) {
|
||||
byte[] data;
|
||||
try {
|
||||
data = ByteStreams.toByteArray(returnVal.getPayload().getContent());
|
||||
} catch (IOException e) {
|
||||
return immediateFailedFuture(new RuntimeException(e));
|
||||
}
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
for (String s : options.getRanges()) {
|
||||
if (s.startsWith("-")) {
|
||||
int length = Integer.parseInt(s.substring(1));
|
||||
out.write(data, data.length - length, length);
|
||||
} else if (s.endsWith("-")) {
|
||||
int offset = Integer.parseInt(s.substring(0, s.length() - 1));
|
||||
out.write(data, offset, data.length - offset);
|
||||
} else if (s.contains("-")) {
|
||||
String[] firstLast = s.split("\\-");
|
||||
int offset = Integer.parseInt(firstLast[0]);
|
||||
int last = Integer.parseInt(firstLast[1]);
|
||||
int length = (last < data.length) ? last + 1 : data.length - offset;
|
||||
out.write(data, offset, length);
|
||||
} else {
|
||||
return immediateFailedFuture(new IllegalArgumentException(
|
||||
"first and last were null!"));
|
||||
}
|
||||
|
||||
}
|
||||
returnVal.setPayload(out.toByteArray());
|
||||
returnVal.setContentLength(out.size());
|
||||
returnVal.getMetadata().setSize(new Long(data.length));
|
||||
}
|
||||
returnVal.setPayload(returnVal.getPayload());
|
||||
return immediateFuture(returnVal);
|
||||
}
|
||||
|
||||
public Future<BlobMetadata> blobMetadata(final String container, final String key) {
|
||||
return new FutureBase<BlobMetadata>() {
|
||||
public BlobMetadata get() throws InterruptedException, ExecutionException {
|
||||
try {
|
||||
return copy(getBlob(container, key).get().getMetadata());
|
||||
} catch (Exception e) {
|
||||
Utils.<ContainerNotFoundException> rethrowIfRuntimeOrSameType(e);
|
||||
Utils.<KeyNotFoundException> rethrowIfRuntimeOrSameType(e);
|
||||
throw new RuntimeException(e);// TODO
|
||||
}
|
||||
}
|
||||
};
|
||||
try {
|
||||
return immediateFuture((BlobMetadata) copy(getBlob(container, key).get().getMetadata()));
|
||||
} catch (Exception e) {
|
||||
Utils.<ContainerNotFoundException> rethrowIfRuntimeOrSameType(e);
|
||||
Utils.<KeyNotFoundException> rethrowIfRuntimeOrSameType(e);
|
||||
return immediateFailedFuture(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Blob copyBlob(Blob object) {
|
||||
|
@ -648,12 +579,8 @@ public class StubAsyncBlobStore implements AsyncBlobStore {
|
|||
}
|
||||
|
||||
public Future<Void> clearContainer(final String container) {
|
||||
return new FutureBase<Void>() {
|
||||
public Void get() throws InterruptedException, ExecutionException {
|
||||
getContainerToBlobs().get(container).clear();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
getContainerToBlobs().get(container).clear();
|
||||
return immediateFuture(null);
|
||||
}
|
||||
|
||||
public Future<Void> createDirectory(final String container, final String directory) {
|
||||
|
|
|
@ -57,7 +57,8 @@ public class RetryOnNotFoundGetAllBlobsStrategyTest {
|
|||
|
||||
@BeforeTest
|
||||
void setUp() {
|
||||
blobProvider = Guice.createInjector(new BlobStoreObjectModule()).getInstance(Blob.Factory.class);
|
||||
blobProvider = Guice.createInjector(new BlobStoreObjectModule()).getInstance(
|
||||
Blob.Factory.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -81,7 +82,8 @@ public class RetryOnNotFoundGetAllBlobsStrategyTest {
|
|||
map.ifNotFoundRetryOtherwiseAddToSet("container", "key", futureObject, objects);
|
||||
// should have retried once
|
||||
assert System.currentTimeMillis() >= time + map.requestRetryMilliseconds;
|
||||
assertEquals(Utils.toStringAndClose((InputStream) objects.iterator().next().getContent()), "goo");
|
||||
assertEquals(Utils.toStringAndClose((InputStream) objects.iterator().next().getContent()),
|
||||
"goo");
|
||||
assert !objects.contains(null);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,30 +19,35 @@
|
|||
package org.jclouds.concurrent;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Transforms the result of a future as soon as it is available.
|
||||
*
|
||||
* Temporarily here until the following is resolved: <a
|
||||
* href="http://code.google.com/p/guava-libraries/issues/detail?id=310"> guava issue 310</a>
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class FutureExceptionParser<T> implements Future<T> {
|
||||
public class FutureExceptionParser<T> implements ListenableFuture<T> {
|
||||
|
||||
private final Future<T> delegate;
|
||||
private final ListenableFuture<T> delegate;
|
||||
private final Function<Exception, T> function;
|
||||
private final Logger logger;
|
||||
|
||||
public FutureExceptionParser(Future<T> delegate, Function<Exception, T> function) {
|
||||
public FutureExceptionParser(ListenableFuture<T> delegate, Function<Exception, T> function) {
|
||||
this(delegate, function, Logger.NULL);
|
||||
}
|
||||
|
||||
public FutureExceptionParser(Future<T> delegate, Function<Exception, T> function, Logger logger) {
|
||||
public FutureExceptionParser(ListenableFuture<T> delegate, Function<Exception, T> function,
|
||||
Logger logger) {
|
||||
this.delegate = delegate;
|
||||
this.function = function;
|
||||
this.logger = logger;
|
||||
|
@ -89,4 +94,9 @@ public class FutureExceptionParser<T> implements Future<T> {
|
|||
return delegate.isDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(Runnable listener, Executor exec) {
|
||||
delegate.addListener(listener, exec);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.concurrent;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* Transforms the result of a future as soon as it is available.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class FutureFunctionCallable<F, T> implements Callable<T> {
|
||||
|
||||
private final Future<F> future;
|
||||
private final Function<F, T> function;
|
||||
private final Logger logger;
|
||||
|
||||
public FutureFunctionCallable(Future<F> future, Function<F, T> function) {
|
||||
this(future, function, Logger.NULL);
|
||||
}
|
||||
|
||||
public FutureFunctionCallable(Future<F> future, Function<F, T> function, Logger logger) {
|
||||
this.future = future;
|
||||
this.function = function;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public T call() throws Exception {
|
||||
try {
|
||||
F input = future.get();
|
||||
logger.debug("Processing intermediate result for: %s", input);
|
||||
T result = function.apply(input);
|
||||
logger.debug("Processed intermediate result for: %s", input);
|
||||
return result;
|
||||
} catch (ExecutionException e) {
|
||||
if (e.getCause() instanceof Error)
|
||||
throw (Error) e.getCause();
|
||||
throw (Exception) e.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.concurrent;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* Transforms the result of a future once requested via get().
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class FutureFunctionWrapper<F, T> implements Future<T>, Function<F, T> {
|
||||
|
||||
private final Future<? extends F> future;
|
||||
private final Function<F, T> function;
|
||||
private final Logger logger;
|
||||
|
||||
public FutureFunctionWrapper(Future<? extends F> future, Function<F, T> function) {
|
||||
this(future, function, Logger.NULL);
|
||||
}
|
||||
|
||||
public FutureFunctionWrapper(Future<? extends F> future, Function<F, T> function, Logger logger) {
|
||||
this.future = future;
|
||||
this.function = function;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public T apply(F input) {
|
||||
logger.debug("Processing intermediate result for: %s", input);
|
||||
T result = function.apply(input);
|
||||
logger.debug("Processed intermediate result for: %s", input);
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return future.cancel(mayInterruptIfRunning);
|
||||
}
|
||||
|
||||
public T get() throws InterruptedException, ExecutionException {
|
||||
return apply(future.get());
|
||||
}
|
||||
|
||||
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
return apply(future.get(timeout, unit));
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return future.isCancelled();
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return future.isDone();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.concurrent;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* Future that is a result of a task ran within a single thread. As such, cancel is not valid, as
|
||||
* the operation is already complete.
|
||||
*
|
||||
* This class is like {@link FutureTask} except that it does not attempt {@code Thread.interrupt() }
|
||||
* which is sometimes prohibited.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class RunnableFutureTask<V> implements Future<V> {
|
||||
private ExecutionException executionException;
|
||||
private InterruptedException interruptedException;
|
||||
private CancellationException cancellationException;
|
||||
private V value;
|
||||
private boolean ran = false;
|
||||
|
||||
private final Callable<V> task;
|
||||
|
||||
public RunnableFutureTask(Callable<V> task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @param mayInterruptIfRunning
|
||||
* - ignored as this cannot be called at the same time as the task is running
|
||||
*/
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
if (ran) {
|
||||
return false;
|
||||
} else {
|
||||
cancellationException = new CancellationException();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return cancellationException != null;
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return ran || cancellationException != null || interruptedException != null
|
||||
|| executionException != null;
|
||||
}
|
||||
|
||||
public V get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
return get();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
value = task.call();
|
||||
} catch (InterruptedException e) {
|
||||
interruptedException = e;
|
||||
} catch (Exception e) {
|
||||
executionException = new ExecutionException(e);
|
||||
} finally {
|
||||
ran = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public V get() throws InterruptedException, ExecutionException {
|
||||
if (cancellationException != null)
|
||||
throw cancellationException;
|
||||
if (interruptedException != null)
|
||||
throw interruptedException;
|
||||
if (executionException != null)
|
||||
throw executionException;
|
||||
checkState(ran, "run() was never called");
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -18,9 +18,10 @@
|
|||
*/
|
||||
package org.jclouds.http;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Used for passing objects for response processing
|
||||
*
|
||||
|
@ -31,10 +32,11 @@ public class HttpCommandRendezvous<T> {
|
|||
private final HttpCommand command;
|
||||
@SuppressWarnings("unchecked")
|
||||
private final SynchronousQueue rendezvous;
|
||||
private final Future<T> future;
|
||||
private final ListenableFuture<T> future;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public HttpCommandRendezvous(HttpCommand command, SynchronousQueue rendezvous, Future<T> future) {
|
||||
public HttpCommandRendezvous(HttpCommand command, SynchronousQueue rendezvous,
|
||||
ListenableFuture<T> future) {
|
||||
this.command = command;
|
||||
this.rendezvous = rendezvous;
|
||||
this.future = future;
|
||||
|
@ -58,7 +60,7 @@ public class HttpCommandRendezvous<T> {
|
|||
return command;
|
||||
}
|
||||
|
||||
public Future<T> getFuture() {
|
||||
public ListenableFuture<T> getFuture() {
|
||||
return future;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
package org.jclouds.http;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Command that utilizes RESTFul apis and extracts <code>T</code> from the HttpResponse.
|
||||
|
@ -36,5 +37,5 @@ public interface TransformingHttpCommand<T> extends HttpCommand {
|
|||
* @throws ExecutionException
|
||||
* if there is a fatal error preventing the command from invoking
|
||||
*/
|
||||
Future<T> execute() throws ExecutionException;
|
||||
ListenableFuture<T> execute() throws ExecutionException;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ package org.jclouds.http;
|
|||
import java.util.concurrent.Future;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.inject.internal.Nullable;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Executor which will invoke and transform the response of an {@code EndpointCommand} into generic
|
||||
|
@ -40,11 +40,8 @@ public interface TransformingHttpCommandExecutorService {
|
|||
* what to execute
|
||||
* @param responseTransformer
|
||||
* how to transform the response from the above command
|
||||
* @param exceptionTransformer
|
||||
* maps any non-critical exceptions to the return type {@code <T>}
|
||||
* @return value of the intended response.
|
||||
*/
|
||||
public <T> Future<T> submit(HttpCommand command, Function<HttpResponse, T> responseTransformer,
|
||||
@Nullable Function<Exception, T> exceptionTransformer);
|
||||
public <T> ListenableFuture<T> submit(HttpCommand command, Function<HttpResponse, T> responseTransformer);
|
||||
|
||||
}
|
||||
|
|
|
@ -18,15 +18,16 @@
|
|||
*/
|
||||
package org.jclouds.http;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import static com.google.common.util.concurrent.Futures.compose;
|
||||
import static com.google.common.util.concurrent.Futures.makeListenable;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.jclouds.concurrent.FutureFunctionCallable;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import javax.inject.Inject;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Executor which will invoke and transform the response of an {@code EndpointCommand} into generic
|
||||
|
@ -38,25 +39,20 @@ public class TransformingHttpCommandExecutorServiceImpl implements
|
|||
TransformingHttpCommandExecutorService {
|
||||
private final HttpCommandExecutorService client;
|
||||
private final ExecutorService executorService;
|
||||
private final LoggerFactory logFactory;
|
||||
|
||||
@Inject
|
||||
public TransformingHttpCommandExecutorServiceImpl(HttpCommandExecutorService client,
|
||||
ExecutorService executorService, LoggerFactory logFactory) {
|
||||
ExecutorService executorService) {
|
||||
this.client = client;
|
||||
this.executorService = executorService;
|
||||
this.logFactory = logFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public <T> Future<T> submit(HttpCommand command, Function<HttpResponse, T> responseTransformer,
|
||||
Function<Exception, T> exceptionTransformer) {
|
||||
public <T> ListenableFuture<T> submit(HttpCommand command, Function<HttpResponse, T> responseTransformer) {
|
||||
Future<HttpResponse> responseFuture = client.submit(command);
|
||||
Callable<T> valueCallable = new FutureFunctionCallable<HttpResponse, T>(responseFuture,
|
||||
responseTransformer, logFactory.getLogger(responseTransformer.getClass().getName()));
|
||||
return executorService.submit(valueCallable);
|
||||
return compose(makeListenable(responseFuture), responseTransformer, executorService);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.jclouds.http;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
|
@ -32,7 +31,7 @@ import org.jclouds.logging.Logger;
|
|||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.inject.internal.Nullable;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Executor which will invoke and transform the response of an {@code EndpointCommand} into generic
|
||||
|
@ -46,7 +45,6 @@ public class TransformingHttpCommandImpl<T> implements TransformingHttpCommand<T
|
|||
|
||||
private final TransformingHttpCommandExecutorService executorService;
|
||||
private final Function<HttpResponse, T> transformer;
|
||||
private final Function<Exception, T> exceptionTransformer;
|
||||
|
||||
private GeneratedHttpRequest<?> request;
|
||||
private volatile int failureCount;
|
||||
|
@ -59,19 +57,17 @@ public class TransformingHttpCommandImpl<T> implements TransformingHttpCommand<T
|
|||
|
||||
@Inject
|
||||
public TransformingHttpCommandImpl(TransformingHttpCommandExecutorService executorService,
|
||||
GeneratedHttpRequest<?> request, Function<HttpResponse, T> transformer,
|
||||
@Nullable Function<Exception, T> exceptionTransformer) {
|
||||
GeneratedHttpRequest<?> request, Function<HttpResponse, T> transformer) {
|
||||
this.request = request;
|
||||
this.executorService = executorService;
|
||||
this.transformer = transformer;
|
||||
this.exceptionTransformer = exceptionTransformer;
|
||||
this.failureCount = 0;
|
||||
}
|
||||
|
||||
public Future<T> execute() throws ExecutionException {
|
||||
public ListenableFuture<T> execute() throws ExecutionException {
|
||||
if (exception != null)
|
||||
throw new ExecutionException(exception);
|
||||
return executorService.submit(this, transformer, exceptionTransformer);
|
||||
return executorService.submit(this, transformer);
|
||||
}
|
||||
|
||||
public int getFailureCount() {
|
||||
|
|
|
@ -53,9 +53,8 @@ public class RestModule extends AbstractModule {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
public TransformingHttpCommand<?> create(GeneratedHttpRequest<?> request,
|
||||
Function<HttpResponse, ?> transformer, Function<Exception, ?> exceptionTransformer) {
|
||||
return new TransformingHttpCommandImpl(executorService, request, transformer,
|
||||
exceptionTransformer);
|
||||
Function<HttpResponse, ?> transformer) {
|
||||
return new TransformingHttpCommandImpl(executorService, request, transformer);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,10 +42,10 @@ import org.jclouds.logging.Logger;
|
|||
import org.jclouds.rest.InvocationContext;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.google.inject.internal.Nullable;
|
||||
|
||||
@Singleton
|
||||
public class AsyncRestClientProxy<T> implements InvocationHandler {
|
||||
|
@ -142,7 +142,7 @@ public class AsyncRestClientProxy<T> implements InvocationHandler {
|
|||
.getName(), transformer.getClass().getSimpleName());
|
||||
|
||||
logger.debug("Invoking %s.%s", declaring.getSimpleName(), method.getName());
|
||||
Future<?> result = commandFactory.create(request, transformer, exceptionParser).execute();
|
||||
ListenableFuture<?> result = commandFactory.create(request, transformer).execute();
|
||||
|
||||
if (exceptionParser != null) {
|
||||
logger.trace("Exceptions from %s.%s are parsed by %s", declaring.getSimpleName(),
|
||||
|
@ -164,8 +164,7 @@ public class AsyncRestClientProxy<T> implements InvocationHandler {
|
|||
|
||||
public static interface Factory {
|
||||
public TransformingHttpCommand<?> create(GeneratedHttpRequest<?> request,
|
||||
Function<HttpResponse, ?> transformer,
|
||||
@Nullable Function<Exception, ?> exceptionTransformer);
|
||||
Function<HttpResponse, ?> transformer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
*/
|
||||
package org.jclouds.concurrent;
|
||||
|
||||
import static com.google.common.util.concurrent.Futures.makeListenable;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
|
@ -31,51 +31,52 @@ import org.testng.annotations.Test;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.util.concurrent.Executors;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Tests behavior of FutureExceptionParser
|
||||
* Tests behavior of ListenableFutureExceptionParser
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "concurrent.FutureExceptionParserTest")
|
||||
@Test(groups = "unit", testName = "concurrent.ListenableFutureExceptionParserTest")
|
||||
public class FutureExceptionParserTest {
|
||||
ExecutorService executorService = Executors.sameThreadExecutor();
|
||||
|
||||
@Test
|
||||
public void testGet() throws InterruptedException, ExecutionException {
|
||||
Future<?> future = createFuture(new RuntimeException("foo"));
|
||||
ListenableFuture<?> future = createListenableFuture(new RuntimeException("foo"));
|
||||
assertEquals(future.get(), "foo");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ExecutionException.class)
|
||||
public void testGetUnmatched() throws InterruptedException, ExecutionException {
|
||||
Future<?> future = createFuture(new Exception("foo"));
|
||||
ListenableFuture<?> future = createListenableFuture(new Exception("foo"));
|
||||
assertEquals(future.get(), "foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLongTimeUnit() throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
Future<?> future = createFuture(new RuntimeException("foo"));
|
||||
ListenableFuture<?> future = createListenableFuture(new RuntimeException("foo"));
|
||||
assertEquals(future.get(1, TimeUnit.SECONDS), "foo");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ExecutionException.class)
|
||||
public void testGetLongTimeUnitUnmatched() throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
Future<?> future = createFuture(new Exception("foo"));
|
||||
ListenableFuture<?> future = createListenableFuture(new Exception("foo"));
|
||||
assertEquals(future.get(1, TimeUnit.SECONDS), "foo");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Future<?> createFuture(final Exception exception) {
|
||||
Future<?> future = executorService.submit(new Callable<String>() {
|
||||
private ListenableFuture<?> createListenableFuture(final Exception exception) {
|
||||
ListenableFuture<?> future = makeListenable(executorService.submit(new Callable<String>() {
|
||||
|
||||
public String call() throws Exception {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
});
|
||||
}));
|
||||
|
||||
future = new FutureExceptionParser(future, new Function<Exception, String>() {
|
||||
|
||||
|
|
|
@ -37,13 +37,10 @@ import org.jclouds.http.TransformingHttpCommandImpl;
|
|||
import org.jclouds.http.functions.ReturnStringIf200;
|
||||
import org.jclouds.http.internal.HttpWire;
|
||||
import org.jclouds.http.internal.JavaUrlHttpCommandExecutorService;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
@ -60,25 +57,25 @@ public class BackoffLimitedRetryHandlerTest {
|
|||
long startTime = System.nanoTime();
|
||||
handler.imposeBackoffExponentialDelay(1, "TEST FAILURE: 1");
|
||||
long elapsedTime = (System.nanoTime() - startTime) / 1000000;
|
||||
assert(elapsedTime >= 49) : elapsedTime;
|
||||
assert (elapsedTime >= 49) : elapsedTime;
|
||||
assertTrue(elapsedTime < 50 + acceptableDelay);
|
||||
|
||||
startTime = System.nanoTime();
|
||||
handler.imposeBackoffExponentialDelay(2, "TEST FAILURE: 2");
|
||||
elapsedTime = (System.nanoTime() - startTime) / 1000000;
|
||||
assert(elapsedTime >= 199) : elapsedTime;
|
||||
assert (elapsedTime >= 199) : elapsedTime;
|
||||
assertTrue(elapsedTime < 200 + acceptableDelay);
|
||||
|
||||
startTime = System.nanoTime();
|
||||
handler.imposeBackoffExponentialDelay(3, "TEST FAILURE: 3");
|
||||
elapsedTime = (System.nanoTime() - startTime) / 1000000;
|
||||
assert(elapsedTime >= 449) : elapsedTime;
|
||||
assert (elapsedTime >= 449) : elapsedTime;
|
||||
assertTrue(elapsedTime < 450 + acceptableDelay);
|
||||
|
||||
startTime = System.nanoTime();
|
||||
handler.imposeBackoffExponentialDelay(4, "TEST FAILURE: 4");
|
||||
elapsedTime = (System.nanoTime() - startTime) / 1000000;
|
||||
assert(elapsedTime >= 799) : elapsedTime;
|
||||
assert (elapsedTime >= 799) : elapsedTime;
|
||||
assertTrue(elapsedTime < 800 + acceptableDelay);
|
||||
|
||||
startTime = System.nanoTime();
|
||||
|
@ -96,14 +93,7 @@ public class BackoffLimitedRetryHandlerTest {
|
|||
JavaUrlHttpCommandExecutorService httpService = new JavaUrlHttpCommandExecutorService(
|
||||
execService, new DelegatingRetryHandler(), new DelegatingErrorHandler(),
|
||||
new HttpWire(Executors.newCachedThreadPool()));
|
||||
executorService = new TransformingHttpCommandExecutorServiceImpl(httpService, execService,
|
||||
new LoggerFactory() {
|
||||
|
||||
public Logger getLogger(String category) {
|
||||
return Logger.NULL;
|
||||
}
|
||||
|
||||
});
|
||||
executorService = new TransformingHttpCommandExecutorServiceImpl(httpService, execService);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -164,14 +154,8 @@ public class BackoffLimitedRetryHandlerTest {
|
|||
private HttpCommand createCommand() throws SecurityException, NoSuchMethodException {
|
||||
Method method = IntegrationTestAsyncClient.class.getMethod("download", String.class);
|
||||
|
||||
HttpCommand command = new TransformingHttpCommandImpl<String>(executorService, processor
|
||||
.createRequest(method, "1"), new ReturnStringIf200(),
|
||||
new Function<Exception, String>() {
|
||||
public String apply(Exception from) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return command;
|
||||
return new TransformingHttpCommandImpl<String>(executorService, processor.createRequest(
|
||||
method, "1"), new ReturnStringIf200());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.jclouds.http.pool;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.util.concurrent.Futures.makeListenable;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
@ -33,7 +34,6 @@ import java.util.concurrent.TimeoutException;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.concurrent.FutureExceptionParser;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpCommandRendezvous;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
|
@ -45,6 +45,7 @@ import org.jclouds.util.Utils;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
|
@ -130,9 +131,8 @@ public class ConnectionPoolTransformingHttpCommandExecutorService<C> extends Bas
|
|||
* will be processed via the {@link #invoke(TransformingHttpCommandExecutorService) invoke}
|
||||
* method.
|
||||
*/
|
||||
public <T> Future<T> submit(HttpCommand command,
|
||||
final Function<HttpResponse, T> responseTransformer,
|
||||
Function<Exception, T> exceptionTransformer) {
|
||||
public <T> ListenableFuture<T> submit(HttpCommand command,
|
||||
final Function<HttpResponse, T> responseTransformer) {
|
||||
exceptionIfNotActive();
|
||||
final SynchronousQueue<?> channel = new SynchronousQueue<Object>();
|
||||
// should block and immediately parse the response on exit.
|
||||
|
@ -151,11 +151,9 @@ public class ConnectionPoolTransformingHttpCommandExecutorService<C> extends Bas
|
|||
}
|
||||
});
|
||||
|
||||
HttpCommandRendezvous<T> rendezvous = new HttpCommandRendezvous<T>(command, channel, future);
|
||||
HttpCommandRendezvous<T> rendezvous = new HttpCommandRendezvous<T>(command, channel,
|
||||
makeListenable(future));
|
||||
commandQueue.add(rendezvous);
|
||||
if (exceptionTransformer != null) {
|
||||
return new FutureExceptionParser<T>(rendezvous.getFuture(), exceptionTransformer);
|
||||
}
|
||||
return rendezvous.getFuture();
|
||||
}
|
||||
|
||||
|
@ -227,4 +225,5 @@ public class ConnectionPoolTransformingHttpCommandExecutorService<C> extends Bas
|
|||
endpoint.getPort()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
package org.jclouds.rackspace.cloudfiles.blobstore;
|
||||
|
||||
import static com.google.common.util.concurrent.Futures.compose;
|
||||
import static com.google.common.util.concurrent.Futures.makeListenable;
|
||||
import static org.jclouds.blobstore.options.ListContainerOptions.Builder.recursive;
|
||||
|
||||
import java.util.SortedSet;
|
||||
|
@ -83,7 +85,7 @@ public class CloudFilesAsyncBlobStore extends BaseCloudFilesBlobStore implements
|
|||
*/
|
||||
public Future<BlobMetadata> blobMetadata(String container, String key) {
|
||||
|
||||
return wrapFuture(async.getObjectInfo(container, key),
|
||||
return compose(makeListenable(async.getObjectInfo(container, key)),
|
||||
new Function<MutableObjectInfoWithMetadata, BlobMetadata>() {
|
||||
|
||||
@Override
|
||||
|
@ -91,7 +93,7 @@ public class CloudFilesAsyncBlobStore extends BaseCloudFilesBlobStore implements
|
|||
return object2BlobMd.apply(from);
|
||||
}
|
||||
|
||||
});
|
||||
}, service);
|
||||
}
|
||||
|
||||
public Future<Void> clearContainer(final String container) {
|
||||
|
@ -129,19 +131,19 @@ public class CloudFilesAsyncBlobStore extends BaseCloudFilesBlobStore implements
|
|||
org.jclouds.blobstore.options.GetOptions... optionsList) {
|
||||
GetOptions httpOptions = blob2ObjectGetOptions.apply(optionsList);
|
||||
Future<CFObject> returnVal = async.getObject(container, key, httpOptions);
|
||||
return wrapFuture(returnVal, object2Blob);
|
||||
return compose(makeListenable(returnVal), object2Blob, service);
|
||||
}
|
||||
|
||||
public Future<? extends ListResponse<? extends ResourceMetadata>> list() {
|
||||
return wrapFuture(
|
||||
async.listContainers(),
|
||||
return compose(
|
||||
makeListenable(async.listContainers()),
|
||||
new Function<SortedSet<ContainerMetadata>, org.jclouds.blobstore.domain.ListResponse<? extends ResourceMetadata>>() {
|
||||
public org.jclouds.blobstore.domain.ListResponse<? extends ResourceMetadata> apply(
|
||||
SortedSet<ContainerMetadata> from) {
|
||||
return new ListResponseImpl<ResourceMetadata>(Iterables.transform(from,
|
||||
container2ResourceMd), null, null, false);
|
||||
}
|
||||
});
|
||||
}, service);
|
||||
}
|
||||
|
||||
public Future<? extends ListContainerResponse<? extends ResourceMetadata>> list(
|
||||
|
@ -150,7 +152,7 @@ public class CloudFilesAsyncBlobStore extends BaseCloudFilesBlobStore implements
|
|||
.apply(optionsList);
|
||||
Future<ListContainerResponse<ObjectInfo>> returnVal = async.listObjects(container,
|
||||
httpOptions);
|
||||
return wrapFuture(returnVal, container2ResourceList);
|
||||
return compose(makeListenable(returnVal), container2ResourceList, service);
|
||||
}
|
||||
|
||||
public Future<String> putBlob(String container, Blob blob) {
|
||||
|
@ -174,7 +176,6 @@ public class CloudFilesAsyncBlobStore extends BaseCloudFilesBlobStore implements
|
|||
|
||||
public Future<Boolean> directoryExists(final String container, final String directory) {
|
||||
return service.submit(new Callable<Boolean>() {
|
||||
|
||||
public Boolean call() throws Exception {
|
||||
try {
|
||||
getDirectoryStrategy.execute(CloudFilesAsyncBlobStore.this, container, directory);
|
||||
|
|
|
@ -21,7 +21,6 @@ package org.jclouds.rackspace.cloudfiles.blobstore.internal;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
|
@ -29,7 +28,6 @@ import org.jclouds.blobstore.domain.Blob;
|
|||
import org.jclouds.blobstore.strategy.ClearListStrategy;
|
||||
import org.jclouds.blobstore.strategy.GetDirectoryStrategy;
|
||||
import org.jclouds.blobstore.strategy.MkdirStrategy;
|
||||
import org.jclouds.concurrent.FutureFunctionWrapper;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
import org.jclouds.rackspace.cloudfiles.CloudFilesAsyncClient;
|
||||
import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
|
||||
|
@ -41,8 +39,6 @@ import org.jclouds.rackspace.cloudfiles.blobstore.functions.ContainerToResourceM
|
|||
import org.jclouds.rackspace.cloudfiles.blobstore.functions.ObjectToBlob;
|
||||
import org.jclouds.rackspace.cloudfiles.blobstore.functions.ObjectToBlobMetadata;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
public class BaseCloudFilesBlobStore {
|
||||
protected final CloudFilesAsyncClient async;
|
||||
protected final CloudFilesClient sync;
|
||||
|
@ -88,11 +84,6 @@ public class BaseCloudFilesBlobStore {
|
|||
this.service = checkNotNull(service, "service");
|
||||
}
|
||||
|
||||
protected <F, T> Future<T> wrapFuture(Future<? extends F> future, Function<F, T> function) {
|
||||
return new FutureFunctionWrapper<F, T>(future, function, logFactory.getLogger(function
|
||||
.getClass().getName()));
|
||||
}
|
||||
|
||||
public Blob newBlob(String name) {
|
||||
Blob blob = blobFactory.create(null);
|
||||
blob.getMetadata().setName(name);
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
package org.jclouds.rackspace.cloudfiles.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -34,11 +34,8 @@ import org.jclouds.blobstore.domain.BlobMetadata;
|
|||
import org.jclouds.blobstore.domain.ListContainerResponse;
|
||||
import org.jclouds.blobstore.functions.HttpGetOptionsListToGetOptions;
|
||||
import org.jclouds.blobstore.integration.internal.StubAsyncBlobStore;
|
||||
import org.jclouds.blobstore.integration.internal.StubAsyncBlobStore.FutureBase;
|
||||
import org.jclouds.blobstore.options.ListContainerOptions;
|
||||
import org.jclouds.concurrent.FutureFunctionWrapper;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
import org.jclouds.rackspace.cloudfiles.CloudFilesAsyncClient;
|
||||
import org.jclouds.rackspace.cloudfiles.blobstore.functions.BlobToObject;
|
||||
import org.jclouds.rackspace.cloudfiles.blobstore.functions.ListContainerOptionsToBlobStoreListContainerOptions;
|
||||
|
@ -56,6 +53,7 @@ import org.jclouds.rackspace.cloudfiles.options.ListCdnContainerOptions;
|
|||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
|
||||
/**
|
||||
* Implementation of {@link CloudFilesAsyncClient} which keeps all data in a local Map object.
|
||||
|
@ -65,7 +63,6 @@ import com.google.common.collect.Sets;
|
|||
public class StubCloudFilesAsyncClient implements CloudFilesAsyncClient {
|
||||
private final HttpGetOptionsListToGetOptions httpGetOptionsConverter;
|
||||
private final StubAsyncBlobStore blobStore;
|
||||
private final LoggerFactory logFactory;
|
||||
private final CFObject.Factory objectProvider;
|
||||
private final ObjectToBlob object2Blob;
|
||||
private final BlobToObject blob2Object;
|
||||
|
@ -74,7 +71,7 @@ public class StubCloudFilesAsyncClient implements CloudFilesAsyncClient {
|
|||
private final ResourceToObjectList resource2ObjectList;
|
||||
|
||||
@Inject
|
||||
private StubCloudFilesAsyncClient(StubAsyncBlobStore blobStore, LoggerFactory logFactory,
|
||||
private StubCloudFilesAsyncClient(StubAsyncBlobStore blobStore,
|
||||
ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs,
|
||||
CFObject.Factory objectProvider,
|
||||
HttpGetOptionsListToGetOptions httpGetOptionsConverter, ObjectToBlob object2Blob,
|
||||
|
@ -82,7 +79,6 @@ public class StubCloudFilesAsyncClient implements CloudFilesAsyncClient {
|
|||
ListContainerOptionsToBlobStoreListContainerOptions container2ContainerListOptions,
|
||||
ResourceToObjectList resource2ContainerList) {
|
||||
this.blobStore = blobStore;
|
||||
this.logFactory = logFactory;
|
||||
this.objectProvider = objectProvider;
|
||||
this.httpGetOptionsConverter = httpGetOptionsConverter;
|
||||
this.object2Blob = checkNotNull(object2Blob, "object2Blob");
|
||||
|
@ -93,17 +89,8 @@ public class StubCloudFilesAsyncClient implements CloudFilesAsyncClient {
|
|||
this.resource2ObjectList = checkNotNull(resource2ContainerList, "resource2ContainerList");
|
||||
}
|
||||
|
||||
protected <F, T> Future<T> wrapFuture(Future<? extends F> future, Function<F, T> function) {
|
||||
return new FutureFunctionWrapper<F, T>(future, function, logFactory.getLogger(function
|
||||
.getClass().getName()));
|
||||
}
|
||||
|
||||
public Future<Boolean> containerExists(final String container) {
|
||||
return new FutureBase<Boolean>() {
|
||||
public Boolean get() throws InterruptedException, ExecutionException {
|
||||
return blobStore.getContainerToBlobs().containsKey(container);
|
||||
}
|
||||
};
|
||||
return immediateFuture(blobStore.getContainerToBlobs().containsKey(container));
|
||||
}
|
||||
|
||||
public Future<Boolean> createContainer(String container) {
|
||||
|
@ -136,11 +123,12 @@ public class StubCloudFilesAsyncClient implements CloudFilesAsyncClient {
|
|||
|
||||
public Future<CFObject> getObject(String container, String key, GetOptions... options) {
|
||||
org.jclouds.blobstore.options.GetOptions getOptions = httpGetOptionsConverter.apply(options);
|
||||
return wrapFuture(blobStore.getBlob(container, key, getOptions), blob2Object);
|
||||
return Futures.compose(Futures.makeListenable(blobStore.getBlob(container, key, getOptions)),
|
||||
blob2Object);
|
||||
}
|
||||
|
||||
public Future<MutableObjectInfoWithMetadata> getObjectInfo(String container, String key) {
|
||||
return wrapFuture(blobStore.blobMetadata(container, key),
|
||||
return Futures.compose(Futures.makeListenable(blobStore.blobMetadata(container, key)),
|
||||
new Function<BlobMetadata, MutableObjectInfoWithMetadata>() {
|
||||
|
||||
@Override
|
||||
|
@ -159,24 +147,19 @@ public class StubCloudFilesAsyncClient implements CloudFilesAsyncClient {
|
|||
|
||||
public Future<? extends SortedSet<ContainerMetadata>> listContainers(
|
||||
org.jclouds.rackspace.cloudfiles.options.ListContainerOptions... options) {
|
||||
return new FutureBase<SortedSet<ContainerMetadata>>() {
|
||||
|
||||
public SortedSet<ContainerMetadata> get() throws InterruptedException, ExecutionException {
|
||||
return Sets.newTreeSet(Iterables.transform(blobStore.getContainerToBlobs().keySet(),
|
||||
new Function<String, ContainerMetadata>() {
|
||||
public ContainerMetadata apply(String name) {
|
||||
return new ContainerMetadata(name, -1, -1);
|
||||
}
|
||||
|
||||
}));
|
||||
return immediateFuture(Sets.newTreeSet(Iterables.transform(blobStore.getContainerToBlobs()
|
||||
.keySet(), new Function<String, ContainerMetadata>() {
|
||||
public ContainerMetadata apply(String name) {
|
||||
return new ContainerMetadata(name, -1, -1);
|
||||
}
|
||||
};
|
||||
})));
|
||||
}
|
||||
|
||||
public Future<ListContainerResponse<ObjectInfo>> listObjects(String container,
|
||||
org.jclouds.rackspace.cloudfiles.options.ListContainerOptions... optionsList) {
|
||||
ListContainerOptions options = container2ContainerListOptions.apply(optionsList);
|
||||
return wrapFuture(blobStore.list(container, options), resource2ObjectList);
|
||||
return Futures.compose(Futures.makeListenable(blobStore.list(container, options)),
|
||||
resource2ObjectList);
|
||||
}
|
||||
|
||||
public Future<String> putObject(String container, CFObject object) {
|
||||
|
|
Loading…
Reference in New Issue