mirror of https://github.com/apache/jclouds.git
Issue 80: public acl for atmos
This commit is contained in:
parent
9257f3a1e6
commit
1f535ebb6f
|
@ -44,7 +44,9 @@ import org.jclouds.atmos.functions.ParseObjectFromHeadersAndHttpContent;
|
|||
import org.jclouds.atmos.functions.ParseSystemMetadataFromHeaders;
|
||||
import org.jclouds.atmos.functions.ParseUserMetadataFromHeaders;
|
||||
import org.jclouds.atmos.functions.ReturnEndpointIfAlreadyExists;
|
||||
import org.jclouds.atmos.functions.ReturnTrueIfGroupACLIsOtherRead;
|
||||
import org.jclouds.atmos.options.ListOptions;
|
||||
import org.jclouds.atmos.options.PutOptions;
|
||||
import org.jclouds.blobstore.functions.ThrowContainerNotFoundOn404;
|
||||
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
|
@ -107,7 +109,7 @@ public interface AtmosAsyncClient {
|
|||
@ExceptionParser(ReturnEndpointIfAlreadyExists.class)
|
||||
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||
@Consumes(MediaType.WILDCARD)
|
||||
ListenableFuture<URI> createDirectory(@PathParam("directoryName") String directoryName);
|
||||
ListenableFuture<URI> createDirectory(@PathParam("directoryName") String directoryName, PutOptions... options);
|
||||
|
||||
/**
|
||||
* @see AtmosClient#createFile
|
||||
|
@ -117,7 +119,8 @@ public interface AtmosAsyncClient {
|
|||
@Consumes(MediaType.WILDCARD)
|
||||
ListenableFuture<URI> createFile(
|
||||
@PathParam("parent") String parent,
|
||||
@PathParam("name") @ParamParser(AtmosObjectName.class) @BinderParam(BindMetadataToHeaders.class) AtmosObject object);
|
||||
@PathParam("name") @ParamParser(AtmosObjectName.class) @BinderParam(BindMetadataToHeaders.class) AtmosObject object,
|
||||
PutOptions... options);
|
||||
|
||||
/**
|
||||
* @see AtmosClient#updateFile
|
||||
|
@ -128,7 +131,8 @@ public interface AtmosAsyncClient {
|
|||
@Consumes(MediaType.WILDCARD)
|
||||
ListenableFuture<Void> updateFile(
|
||||
@PathParam("parent") String parent,
|
||||
@PathParam("name") @ParamParser(AtmosObjectName.class) @BinderParam(BindMetadataToHeaders.class) AtmosObject object);
|
||||
@PathParam("name") @ParamParser(AtmosObjectName.class) @BinderParam(BindMetadataToHeaders.class) AtmosObject object,
|
||||
PutOptions... options);
|
||||
|
||||
/**
|
||||
* @see AtmosClient#readFile
|
||||
|
@ -190,12 +194,14 @@ public interface AtmosAsyncClient {
|
|||
@Consumes(MediaType.WILDCARD)
|
||||
ListenableFuture<Boolean> pathExists(@PathParam("path") String path);
|
||||
|
||||
// signature currently doesn't work
|
||||
// @POST
|
||||
// @QueryParams(keys = "acl")
|
||||
// @Headers(keys = { "x-emc-useracl", "x-emc-groupacl" }, values = { "root=FULL_CONTROL",
|
||||
// "other=READ" })
|
||||
// @Consumes(MediaType.WILDCARD)
|
||||
// void makePublic(@Endpoint URI url);
|
||||
/**
|
||||
* @see AtmosClient#isPublic
|
||||
*/
|
||||
@HEAD
|
||||
@ResponseParser(ReturnTrueIfGroupACLIsOtherRead.class)
|
||||
@Path("/{path}")
|
||||
@Consumes(MediaType.WILDCARD)
|
||||
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||
ListenableFuture<Boolean> isPublic(@PathParam("path") String path);
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.jclouds.atmos.domain.DirectoryEntry;
|
|||
import org.jclouds.atmos.domain.SystemMetadata;
|
||||
import org.jclouds.atmos.domain.UserMetadata;
|
||||
import org.jclouds.atmos.options.ListOptions;
|
||||
import org.jclouds.atmos.options.PutOptions;
|
||||
import org.jclouds.concurrent.Timeout;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
|
||||
|
@ -52,13 +53,13 @@ public interface AtmosClient {
|
|||
|
||||
BoundedSet<? extends DirectoryEntry> listDirectory(String directoryName, ListOptions... options);
|
||||
|
||||
URI createDirectory(String directoryName);
|
||||
URI createDirectory(String directoryName, PutOptions... options);
|
||||
|
||||
@Timeout(duration = 10, timeUnit = TimeUnit.MINUTES)
|
||||
URI createFile(String parent, AtmosObject object);
|
||||
URI createFile(String parent, AtmosObject object, PutOptions... options);
|
||||
|
||||
@Timeout(duration = 10, timeUnit = TimeUnit.MINUTES)
|
||||
void updateFile(String parent, AtmosObject object);
|
||||
void updateFile(String parent, AtmosObject object, PutOptions... options);
|
||||
|
||||
@Timeout(duration = 10, timeUnit = TimeUnit.MINUTES)
|
||||
AtmosObject readFile(String path, GetOptions... options);
|
||||
|
@ -73,4 +74,6 @@ public interface AtmosClient {
|
|||
|
||||
boolean pathExists(String path);
|
||||
|
||||
boolean isPublic(String path);
|
||||
|
||||
}
|
||||
|
|
|
@ -19,8 +19,10 @@
|
|||
package org.jclouds.atmos.blobstore;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.jclouds.atmos.options.PutOptions.Builder.publicRead;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
@ -79,6 +81,7 @@ public class AtmosAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
private final Crypto crypto;
|
||||
private final BlobToHttpGetOptions blob2ObjectGetOptions;
|
||||
private final Provider<FetchBlobMetadata> fetchBlobMetadataProvider;
|
||||
private final Map<String, Boolean> isPublic;
|
||||
|
||||
@Inject
|
||||
AtmosAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
|
||||
|
@ -87,7 +90,8 @@ public class AtmosAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
ObjectToBlob object2Blob, ObjectToBlobMetadata object2BlobMd, BlobToObject blob2Object,
|
||||
BlobStoreListOptionsToListOptions container2ContainerListOptions,
|
||||
DirectoryEntryListToResourceMetadataList container2ResourceList, Crypto crypto,
|
||||
BlobToHttpGetOptions blob2ObjectGetOptions, Provider<FetchBlobMetadata> fetchBlobMetadataProvider) {
|
||||
BlobToHttpGetOptions blob2ObjectGetOptions, Provider<FetchBlobMetadata> fetchBlobMetadataProvider,
|
||||
Map<String, Boolean> isPublic) {
|
||||
super(context, blobUtils, service, defaultLocation, locations);
|
||||
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
|
||||
this.sync = checkNotNull(sync, "sync");
|
||||
|
@ -100,6 +104,7 @@ public class AtmosAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
this.object2BlobMd = checkNotNull(object2BlobMd, "object2BlobMd");
|
||||
this.crypto = checkNotNull(crypto, "crypto");
|
||||
this.fetchBlobMetadataProvider = checkNotNull(fetchBlobMetadataProvider, "fetchBlobMetadataProvider");
|
||||
this.isPublic = checkNotNull(isPublic, "isPublic");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -231,11 +236,18 @@ public class AtmosAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
*/
|
||||
@Override
|
||||
public ListenableFuture<String> putBlob(final String container, final Blob blob) {
|
||||
final org.jclouds.atmos.options.PutOptions options = new org.jclouds.atmos.options.PutOptions();
|
||||
try {
|
||||
if (isPublic.get(container + "/"))
|
||||
options.publicRead();
|
||||
} catch (NullPointerException e) {
|
||||
// MapMaker
|
||||
}
|
||||
return Futures.makeListenable(service.submit(new Callable<String>() {
|
||||
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
return AtmosUtils.putBlob(sync, crypto, blob2Object, container, blob);
|
||||
return AtmosUtils.putBlob(sync, crypto, blob2Object, container, blob, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -264,7 +276,13 @@ public class AtmosAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
public ListenableFuture<Boolean> createContainerInLocation(Location location, String container,
|
||||
CreateContainerOptions options) {
|
||||
if (options.isPublicRead())
|
||||
throw new UnsupportedOperationException("publicRead");
|
||||
return Futures.compose(async.createDirectory(container, publicRead()), new Function<URI, Boolean>() {
|
||||
|
||||
public Boolean apply(URI from) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}, service);
|
||||
return createContainerInLocation(location, container);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import javax.inject.Singleton;
|
|||
import org.jclouds.atmos.AtmosAsyncClient;
|
||||
import org.jclouds.atmos.blobstore.functions.BlobToObject;
|
||||
import org.jclouds.atmos.domain.AtmosObject;
|
||||
import org.jclouds.atmos.options.PutOptions;
|
||||
import org.jclouds.blobstore.BlobRequestSigner;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
|
||||
|
@ -58,7 +59,7 @@ public class AtmosBlobRequestSigner implements BlobRequestSigner {
|
|||
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
|
||||
this.getMethod = AtmosAsyncClient.class.getMethod("readFile", String.class, GetOptions[].class);
|
||||
this.deleteMethod = AtmosAsyncClient.class.getMethod("deletePath", String.class);
|
||||
this.createMethod = AtmosAsyncClient.class.getMethod("createFile", String.class, AtmosObject.class);
|
||||
this.createMethod = AtmosAsyncClient.class.getMethod("createFile", String.class, AtmosObject.class, PutOptions[].class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
package org.jclouds.atmos.blobstore;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.jclouds.atmos.options.PutOptions.Builder.publicRead;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -67,6 +69,7 @@ public class AtmosBlobStore extends BaseBlobStore {
|
|||
private final Crypto crypto;
|
||||
private final BlobToHttpGetOptions blob2ObjectGetOptions;
|
||||
private final Provider<FetchBlobMetadata> fetchBlobMetadataProvider;
|
||||
private final Map<String, Boolean> isPublic;
|
||||
|
||||
@Inject
|
||||
AtmosBlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
|
||||
|
@ -74,7 +77,8 @@ public class AtmosBlobStore extends BaseBlobStore {
|
|||
ObjectToBlobMetadata object2BlobMd, BlobToObject blob2Object,
|
||||
BlobStoreListOptionsToListOptions container2ContainerListOptions,
|
||||
DirectoryEntryListToResourceMetadataList container2ResourceList, Crypto crypto,
|
||||
BlobToHttpGetOptions blob2ObjectGetOptions, Provider<FetchBlobMetadata> fetchBlobMetadataProvider) {
|
||||
BlobToHttpGetOptions blob2ObjectGetOptions, Provider<FetchBlobMetadata> fetchBlobMetadataProvider,
|
||||
Map<String, Boolean> isPublic) {
|
||||
super(context, blobUtils, defaultLocation, locations);
|
||||
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
|
||||
this.sync = checkNotNull(sync, "sync");
|
||||
|
@ -86,6 +90,7 @@ public class AtmosBlobStore extends BaseBlobStore {
|
|||
this.object2BlobMd = checkNotNull(object2BlobMd, "object2BlobMd");
|
||||
this.crypto = checkNotNull(crypto, "crypto");
|
||||
this.fetchBlobMetadataProvider = checkNotNull(fetchBlobMetadataProvider, "fetchBlobMetadataProvider");
|
||||
this.isPublic = checkNotNull(isPublic, "isPublic");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -205,7 +210,14 @@ public class AtmosBlobStore extends BaseBlobStore {
|
|||
*/
|
||||
@Override
|
||||
public String putBlob(final String container, final Blob blob) {
|
||||
return AtmosUtils.putBlob(sync, crypto, blob2Object, container, blob);
|
||||
final org.jclouds.atmos.options.PutOptions options = new org.jclouds.atmos.options.PutOptions();
|
||||
try {
|
||||
if (isPublic.get(container + "/"))
|
||||
options.publicRead();
|
||||
} catch (NullPointerException e) {
|
||||
// MapMaker
|
||||
}
|
||||
return AtmosUtils.putBlob(sync, crypto, blob2Object, container, blob, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -229,8 +241,10 @@ public class AtmosBlobStore extends BaseBlobStore {
|
|||
|
||||
@Override
|
||||
public boolean createContainerInLocation(Location location, String container, CreateContainerOptions options) {
|
||||
if (options.isPublicRead())
|
||||
throw new UnsupportedOperationException("publicRead");
|
||||
if (options.isPublicRead()) {
|
||||
sync.createDirectory(container, publicRead());
|
||||
return true;
|
||||
}
|
||||
return createContainerInLocation(location, container);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
*/
|
||||
package org.jclouds.atmos.blobstore.config;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.atmos.AtmosAsyncClient;
|
||||
import org.jclouds.atmos.AtmosClient;
|
||||
import org.jclouds.atmos.blobstore.AtmosAsyncBlobStore;
|
||||
|
@ -34,7 +39,10 @@ import org.jclouds.blobstore.internal.BlobStoreContextImpl;
|
|||
import org.jclouds.blobstore.strategy.ContainsValueInListStrategy;
|
||||
import org.jclouds.location.config.JustProviderLocationModule;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Scopes;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
|
@ -57,4 +65,19 @@ public class AtmosBlobStoreContextModule extends AbstractModule {
|
|||
bind(BlobRequestSigner.class).to(AtmosBlobRequestSigner.class);
|
||||
install(new JustProviderLocationModule());
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected Map<String, Boolean> isPublic(final AtmosClient client) {
|
||||
return new MapMaker().expireAfterWrite(30, TimeUnit.SECONDS).makeComputingMap(new Function<String, Boolean>() {
|
||||
public Boolean apply(String directory) {
|
||||
return client.isPublic(directory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "isPublic()";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,8 @@ public class BlobToContentMetadata implements Function<BlobMetadata, MutableCont
|
|||
public MutableContentMetadata apply(BlobMetadata base) {
|
||||
MutableBlobMetadataImpl to = new MutableBlobMetadataImpl();
|
||||
HttpUtils.copy(base.getContentMetadata(), to.getContentMetadata());
|
||||
return new DelegatingMutableContentMetadata(base.getName(), to.getContentMetadata());
|
||||
return new DelegatingMutableContentMetadata(base.getUri(), base.getName(), base.getUri() != null ? base.getUri()
|
||||
.getPath() : null, to.getContentMetadata());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import javax.inject.Singleton;
|
|||
|
||||
import org.jclouds.atmos.domain.AtmosObject;
|
||||
import org.jclouds.atmos.domain.FileType;
|
||||
import org.jclouds.atmos.filters.ShareUrl;
|
||||
import org.jclouds.atmos.functions.AtmosObjectName;
|
||||
import org.jclouds.blobstore.domain.MutableBlobMetadata;
|
||||
import org.jclouds.blobstore.domain.StorageType;
|
||||
|
@ -34,7 +35,9 @@ import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
|
|||
import org.jclouds.http.HttpUtils;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
|
@ -43,13 +46,16 @@ import com.google.common.collect.Maps;
|
|||
@Singleton
|
||||
public class ObjectToBlobMetadata implements Function<AtmosObject, MutableBlobMetadata> {
|
||||
private final AtmosObjectName objectName;
|
||||
private static final Set<String> systemMetadata = ImmutableSet.of("atime", "mtime", "ctime",
|
||||
"itime", "type", "uid", "gid", "objectid", "objname", "size", "nlink", "policyname",
|
||||
"content-md5");
|
||||
private final ShareUrl shareUrl;
|
||||
|
||||
private static final Set<String> systemMetadata = ImmutableSet.of("atime", "mtime", "ctime", "itime", "type", "uid",
|
||||
"gid", "objectid", "objname", "size", "nlink", "policyname", "content-md5");
|
||||
|
||||
@Inject
|
||||
protected ObjectToBlobMetadata(AtmosObjectName objectName) {
|
||||
protected ObjectToBlobMetadata(AtmosObjectName objectName, ShareUrl shareUrl)
|
||||
throws SecurityException, NoSuchMethodException {
|
||||
this.objectName = objectName;
|
||||
this.shareUrl = shareUrl;
|
||||
}
|
||||
|
||||
public MutableBlobMetadata apply(AtmosObject from) {
|
||||
|
@ -60,6 +66,10 @@ public class ObjectToBlobMetadata implements Function<AtmosObject, MutableBlobMe
|
|||
to.setLastModified(from.getSystemMetadata().getLastUserDataModification());
|
||||
HttpUtils.copy(from.getContentMetadata(), to.getContentMetadata());
|
||||
to.setName(objectName.apply(from));
|
||||
to.setUri(from.getContentMetadata().getUri());
|
||||
to.setContainer(Iterables.get(Splitter.on('/').split(from.getContentMetadata().getPath()),0));
|
||||
if (from.getAllHeaders().containsEntry("x-emc-groupacl", "other=READ"))
|
||||
to.setPublicUri(shareUrl.apply(from.getContentMetadata().getPath()));
|
||||
if (from.getSystemMetadata().getType() == FileType.DIRECTORY) {
|
||||
to.setType(StorageType.FOLDER);
|
||||
} else {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package org.jclouds.atmos.config;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
@ -43,8 +44,8 @@ import com.google.common.base.Suppliers;
|
|||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
* Configures the EMC Atmos Online Storage authentication service connection,
|
||||
* including logging and http transport.
|
||||
* Configures the EMC Atmos Online Storage authentication service connection, including logging and
|
||||
* http transport.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
|
@ -74,7 +75,7 @@ public class AtmosRestClientModule extends RestClientModule<AtmosClient, AtmosAs
|
|||
@Provides
|
||||
@TimeStamp
|
||||
Supplier<String> provideTimeStampCache(@Named(Constants.PROPERTY_SESSION_INTERVAL) long seconds,
|
||||
final DateService dateService) {
|
||||
final DateService dateService) {
|
||||
return Suppliers.memoizeWithExpiration(new Supplier<String>() {
|
||||
public String get() {
|
||||
return dateService.rfc822DateFormat();
|
||||
|
@ -82,6 +83,12 @@ public class AtmosRestClientModule extends RestClientModule<AtmosClient, AtmosAs
|
|||
}, seconds, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@TimeStamp
|
||||
protected Long provideShareableUrlTimeout() {
|
||||
return new Date().getTime() + TimeUnit.HOURS.toMillis(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bindErrorHandlers() {
|
||||
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseAtmosErrorFromXmlContent.class);
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
package org.jclouds.atmos.domain;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.jclouds.atmos.domain.internal.DelegatingMutableContentMetadata;
|
||||
|
||||
import com.google.inject.ImplementedBy;
|
||||
|
@ -34,4 +36,11 @@ public interface MutableContentMetadata extends org.jclouds.io.MutableContentMet
|
|||
|
||||
public void setName(String name);
|
||||
|
||||
public URI getUri();
|
||||
|
||||
public void setUri(URI uri);
|
||||
|
||||
public String getPath();
|
||||
|
||||
public void setPath(String path);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ public class AtmosObjectImpl extends PayloadEnclosingImpl implements AtmosObject
|
|||
}
|
||||
|
||||
public AtmosObject create(MutableContentMetadata contentMetadata, SystemMetadata systemMetadata,
|
||||
UserMetadata userMetadata) {
|
||||
UserMetadata userMetadata) {
|
||||
return new AtmosObjectImpl(contentMetadata, systemMetadata, userMetadata);
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ public class AtmosObjectImpl extends PayloadEnclosingImpl implements AtmosObject
|
|||
private Multimap<String, String> allHeaders = LinkedHashMultimap.create();
|
||||
|
||||
public AtmosObjectImpl(MutableContentMetadata contentMetadata, SystemMetadata systemMetadata,
|
||||
UserMetadata userMetadata) {
|
||||
UserMetadata userMetadata) {
|
||||
this.contentMetadata = contentMetadata;
|
||||
this.systemMetadata = systemMetadata;
|
||||
this.userMetadata = userMetadata;
|
||||
|
@ -165,7 +165,7 @@ public class AtmosObjectImpl extends PayloadEnclosingImpl implements AtmosObject
|
|||
@Override
|
||||
public void setPayload(Payload data) {
|
||||
this.payload = data;
|
||||
this.contentMetadata = new DelegatingMutableContentMetadata(contentMetadata.getName(),
|
||||
payload.getContentMetadata());
|
||||
this.contentMetadata = new DelegatingMutableContentMetadata(contentMetadata.getUri(), contentMetadata.getName(),
|
||||
contentMetadata.getPath(), payload.getContentMetadata());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
package org.jclouds.atmos.domain.internal;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.jclouds.atmos.domain.MutableContentMetadata;
|
||||
import org.jclouds.io.ContentMetadataBuilder;
|
||||
import org.jclouds.io.payloads.BaseMutableContentMetadata;
|
||||
|
@ -29,16 +31,21 @@ import com.google.common.collect.Multimap;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
public class DelegatingMutableContentMetadata implements MutableContentMetadata {
|
||||
private URI uri;
|
||||
private String name;
|
||||
private String path;
|
||||
private final org.jclouds.io.MutableContentMetadata delegate;
|
||||
|
||||
public DelegatingMutableContentMetadata() {
|
||||
this(null, new BaseMutableContentMetadata());
|
||||
this(null, null, null, new BaseMutableContentMetadata());
|
||||
}
|
||||
|
||||
public DelegatingMutableContentMetadata(String name, org.jclouds.io.MutableContentMetadata delegate) {
|
||||
public DelegatingMutableContentMetadata(URI uri, String name, String path,
|
||||
org.jclouds.io.MutableContentMetadata delegate) {
|
||||
this.uri = uri;
|
||||
this.name = name;
|
||||
this.delegate = delegate;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -90,15 +97,10 @@ public class DelegatingMutableContentMetadata implements MutableContentMetadata
|
|||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
DelegatingMutableContentMetadata other = (DelegatingMutableContentMetadata) obj;
|
||||
if (delegate == null) {
|
||||
if (other.delegate != null)
|
||||
if (uri == null) {
|
||||
if (other.uri != null)
|
||||
return false;
|
||||
} else if (!delegate.equals(other.delegate))
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
} else if (!uri.equals(other.uri))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -107,14 +109,13 @@ public class DelegatingMutableContentMetadata implements MutableContentMetadata
|
|||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((delegate == null) ? 0 : delegate.hashCode());
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((uri == null) ? 0 : uri.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[name=" + name + ", delegate=" + delegate + "]";
|
||||
return "[uri=" + uri + ", name=" + name + ", path=" + path + ", delegate=" + delegate + "]";
|
||||
}
|
||||
|
||||
public org.jclouds.io.MutableContentMetadata getDelegate() {
|
||||
|
@ -162,4 +163,24 @@ public class DelegatingMutableContentMetadata implements MutableContentMetadata
|
|||
return delegate.toBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUri(URI uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2011 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.atmos.filters;
|
||||
|
||||
import static org.jclouds.Constants.LOGGER_SIGNATURE;
|
||||
import static org.jclouds.Constants.PROPERTY_CREDENTIAL;
|
||||
import static org.jclouds.Constants.PROPERTY_IDENTITY;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
|
||||
import org.jclouds.crypto.Crypto;
|
||||
import org.jclouds.crypto.CryptoStreams;
|
||||
import org.jclouds.date.TimeStamp;
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.io.InputSuppliers;
|
||||
import org.jclouds.location.Provider;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* Signs the EMC Atmos Online Storage request.
|
||||
*
|
||||
* @see <a href="https://community.emc.com/community/labs/atmos_online" />
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
@Singleton
|
||||
public class ShareUrl implements Function<String, URI> {
|
||||
|
||||
private final String uid;
|
||||
private final byte[] key;
|
||||
private final URI provider;
|
||||
private final javax.inject.Provider<Long> timeStampProvider;
|
||||
private final javax.inject.Provider<UriBuilder> uriBuilders;
|
||||
private final Crypto crypto;
|
||||
|
||||
@Resource
|
||||
Logger logger = Logger.NULL;
|
||||
|
||||
@Resource
|
||||
@Named(LOGGER_SIGNATURE)
|
||||
Logger signatureLog = Logger.NULL;
|
||||
|
||||
@Inject
|
||||
public ShareUrl(@Named(PROPERTY_IDENTITY) String uid, @Named(PROPERTY_CREDENTIAL) String encodedKey,
|
||||
@Provider URI provider, @TimeStamp javax.inject.Provider<Long> timeStampProvider,
|
||||
javax.inject.Provider<UriBuilder> uriBuilders, Crypto crypto) {
|
||||
this.uid = uid;
|
||||
this.key = CryptoStreams.base64(encodedKey);
|
||||
this.provider = provider;
|
||||
this.uriBuilders = uriBuilders;
|
||||
this.timeStampProvider = timeStampProvider;
|
||||
this.crypto = crypto;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI apply(String path) throws HttpException {
|
||||
String requestedResource = new StringBuilder().append("/rest/namespace/").append(path).toString();
|
||||
long expires = timeStampProvider.get();
|
||||
String signature = signString(createStringToSign(requestedResource, expires));
|
||||
return uriBuilders.get().uri(provider).path(requestedResource).queryParam("uid", uid).queryParam("expires",
|
||||
expires).queryParam("signature", signature).build();
|
||||
}
|
||||
|
||||
public String createStringToSign(String requestedResource, long expires) {
|
||||
StringBuilder toSign = new StringBuilder();
|
||||
toSign.append("GET\n");
|
||||
toSign.append(requestedResource.toLowerCase()).append("\n");
|
||||
toSign.append(uid).append("\n");
|
||||
toSign.append(expires);
|
||||
return toSign.toString();
|
||||
}
|
||||
|
||||
public String signString(String toSign) {
|
||||
String signature;
|
||||
try {
|
||||
signature = CryptoStreams.base64(CryptoStreams.mac(InputSuppliers.of(toSign), crypto.hmacSHA1(key)));
|
||||
} catch (Exception e) {
|
||||
throw new HttpException("error signing request", e);
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
|
||||
}
|
|
@ -21,12 +21,16 @@ package org.jclouds.atmos.functions;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.jclouds.http.HttpUtils.attemptToParseSizeAndRangeFromHeaders;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.atmos.domain.AtmosObject;
|
||||
import org.jclouds.blobstore.functions.ParseSystemAndUserMetadataFromHeaders;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.rest.InvocationContext;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
|
@ -36,16 +40,18 @@ import com.google.common.base.Function;
|
|||
* @see ParseMetadataFromHeaders
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class ParseObjectFromHeadersAndHttpContent implements Function<HttpResponse, AtmosObject> {
|
||||
public class ParseObjectFromHeadersAndHttpContent implements Function<HttpResponse, AtmosObject>,
|
||||
InvocationContext<ParseObjectFromHeadersAndHttpContent> {
|
||||
|
||||
private final ParseSystemMetadataFromHeaders systemMetadataParser;
|
||||
private final ParseUserMetadataFromHeaders userMetadataParser;
|
||||
private final AtmosObject.Factory objectProvider;
|
||||
private URI uri;
|
||||
private String path;
|
||||
|
||||
@Inject
|
||||
public ParseObjectFromHeadersAndHttpContent(ParseSystemMetadataFromHeaders systemMetadataParser,
|
||||
ParseUserMetadataFromHeaders userMetadataParser, AtmosObject.Factory objectProvider) {
|
||||
ParseUserMetadataFromHeaders userMetadataParser, AtmosObject.Factory objectProvider) {
|
||||
this.systemMetadataParser = checkNotNull(systemMetadataParser, "systemMetadataParser");
|
||||
this.userMetadataParser = checkNotNull(userMetadataParser, "userMetadataParser");
|
||||
this.objectProvider = checkNotNull(objectProvider, "objectProvider");
|
||||
|
@ -63,9 +69,22 @@ public class ParseObjectFromHeadersAndHttpContent implements Function<HttpRespon
|
|||
checkNotNull(from, "http response");
|
||||
AtmosObject object = objectProvider.create(systemMetadataParser.apply(from), userMetadataParser.apply(from));
|
||||
object.getContentMetadata().setName(object.getSystemMetadata().getObjectName());
|
||||
object.getContentMetadata().setPath(path);
|
||||
object.getContentMetadata().setUri(uri);
|
||||
object.getAllHeaders().putAll(from.getHeaders());
|
||||
object.setPayload(from.getPayload());
|
||||
object.getContentMetadata().setContentLength(attemptToParseSizeAndRangeFromHeaders(from));
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParseObjectFromHeadersAndHttpContent setContext(HttpRequest request) {
|
||||
this.uri = request.getEndpoint();
|
||||
return setPath(GeneratedHttpRequest.class.cast(request).getArgs().get(0).toString());
|
||||
}
|
||||
|
||||
private ParseObjectFromHeadersAndHttpContent setPath(String path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,27 +16,24 @@
|
|||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.atmos.blobstore.functions;
|
||||
package org.jclouds.atmos.functions;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code ObjectToBlobMetadata}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit")
|
||||
public class ObjectToBlobMetadataTest {
|
||||
@Singleton
|
||||
public class ReturnTrueIfGroupACLIsOtherRead implements Function<HttpResponse, Boolean> {
|
||||
|
||||
public void testFromWhenTypeIsDirectory() {
|
||||
Injector injector = Guice.createInjector();
|
||||
injector.getInstance(ObjectToBlobMetadata.class);
|
||||
|
||||
assertEquals("", "");
|
||||
public Boolean apply(HttpResponse from) {
|
||||
checkNotNull(from, "http response");
|
||||
return from.getHeaders().containsEntry("x-emc-groupacl", "other=READ");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2011 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.atmos.options;
|
||||
|
||||
import org.jclouds.http.options.BaseHttpRequestOptions;
|
||||
|
||||
/**
|
||||
* Contains options supported in the REST API for the PUT operations.
|
||||
* <p/>
|
||||
* <h2>
|
||||
* Usage</h2> The recommended way to instantiate a PutOptions object is to statically import
|
||||
* PutOptions.Builder.* and invoke a static creation method followed by an instance mutator (if
|
||||
* needed):
|
||||
* <p/>
|
||||
* <code>
|
||||
* import org.jclouds.atmos.options.PutOptions.Builder.*
|
||||
* import org.jclouds.atmos.AtmosClient;
|
||||
*
|
||||
* AtmosClient connection = // get connection
|
||||
* connection.createDirectory("directory", publicRead());
|
||||
* <code>
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
public class PutOptions extends BaseHttpRequestOptions {
|
||||
public static final PutOptions NONE = new PutOptions();
|
||||
|
||||
/**
|
||||
* Add public access to all users
|
||||
*
|
||||
*/
|
||||
public PutOptions publicRead() {
|
||||
this.replaceHeader("x-emc-useracl", "root=FULL_CONTROL");
|
||||
this.replaceHeader("x-emc-groupacl", "other=READ");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
/**
|
||||
* @see PutOptions#publicRead
|
||||
*/
|
||||
public static PutOptions publicRead() {
|
||||
PutOptions options = new PutOptions();
|
||||
return options.publicRead();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ import org.jclouds.atmos.AtmosClient;
|
|||
import org.jclouds.atmos.blobstore.functions.BlobToObject;
|
||||
import org.jclouds.atmos.domain.AtmosError;
|
||||
import org.jclouds.atmos.filters.SignRequest;
|
||||
import org.jclouds.atmos.options.PutOptions;
|
||||
import org.jclouds.atmos.xml.ErrorHandler;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.crypto.Crypto;
|
||||
|
@ -56,8 +57,8 @@ public class AtmosUtils {
|
|||
@Inject
|
||||
Provider<ErrorHandler> errorHandlerProvider;
|
||||
|
||||
public AtmosError parseAtmosErrorFromContent(HttpCommand command, HttpResponse response,
|
||||
InputStream content) throws HttpException {
|
||||
public AtmosError parseAtmosErrorFromContent(HttpCommand command, HttpResponse response, InputStream content)
|
||||
throws HttpException {
|
||||
AtmosError error = (AtmosError) factory.create(errorHandlerProvider.get()).parse(content);
|
||||
if (error.getCode() == 1032) {
|
||||
error.setStringSigned(signer.createStringToSign(command.getCurrentRequest()));
|
||||
|
@ -66,11 +67,11 @@ public class AtmosUtils {
|
|||
|
||||
}
|
||||
|
||||
public static String putBlob(final AtmosClient sync, Crypto crypto, BlobToObject blob2Object,
|
||||
String container, Blob blob) {
|
||||
public static String putBlob(final AtmosClient sync, Crypto crypto, BlobToObject blob2Object, String container,
|
||||
Blob blob, PutOptions options) {
|
||||
final String path = container + "/" + blob.getMetadata().getName();
|
||||
deleteAndEnsureGone(sync, path);
|
||||
sync.createFile(container, blob2Object.apply(blob));
|
||||
sync.createFile(container, blob2Object.apply(blob), options);
|
||||
return path;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ package org.jclouds.atmos;
|
|||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Properties;
|
||||
|
||||
|
@ -35,7 +34,9 @@ import org.jclouds.atmos.functions.ParseDirectoryListFromContentAndHeaders;
|
|||
import org.jclouds.atmos.functions.ParseObjectFromHeadersAndHttpContent;
|
||||
import org.jclouds.atmos.functions.ParseSystemMetadataFromHeaders;
|
||||
import org.jclouds.atmos.functions.ReturnEndpointIfAlreadyExists;
|
||||
import org.jclouds.atmos.functions.ReturnTrueIfGroupACLIsOtherRead;
|
||||
import org.jclouds.atmos.options.ListOptions;
|
||||
import org.jclouds.atmos.options.PutOptions;
|
||||
import org.jclouds.blobstore.binders.BindBlobToMultipartFormTest;
|
||||
import org.jclouds.blobstore.functions.ThrowContainerNotFoundOn404;
|
||||
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
|
||||
|
@ -49,6 +50,7 @@ import org.jclouds.rest.ConfiguresRestClient;
|
|||
import org.jclouds.rest.RestClientTest;
|
||||
import org.jclouds.rest.RestContextFactory;
|
||||
import org.jclouds.rest.RestContextSpec;
|
||||
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
|
@ -71,8 +73,7 @@ public class AtmosAsyncClientTest extends RestClientTest<AtmosAsyncClient> {
|
|||
private BlobToObject blobToObject;
|
||||
|
||||
public void testListDirectories() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = AtmosAsyncClient.class.getMethod("listDirectories", Array.newInstance(ListOptions.class, 0)
|
||||
.getClass());
|
||||
Method method = AtmosAsyncClient.class.getMethod("listDirectories", ListOptions[].class);
|
||||
HttpRequest request = processor.createRequest(method);
|
||||
|
||||
assertRequestLineEquals(request, "GET https://accesspoint.atmosonline.com/rest/namespace HTTP/1.1");
|
||||
|
@ -87,8 +88,7 @@ public class AtmosAsyncClientTest extends RestClientTest<AtmosAsyncClient> {
|
|||
}
|
||||
|
||||
public void testListDirectory() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = AtmosAsyncClient.class.getMethod("listDirectory", String.class, Array.newInstance(
|
||||
ListOptions.class, 0).getClass());
|
||||
Method method = AtmosAsyncClient.class.getMethod("listDirectory", String.class, ListOptions[].class);
|
||||
HttpRequest request = processor.createRequest(method, "directory");
|
||||
|
||||
assertRequestLineEquals(request, "GET https://accesspoint.atmosonline.com/rest/namespace/directory/ HTTP/1.1");
|
||||
|
@ -103,8 +103,7 @@ public class AtmosAsyncClientTest extends RestClientTest<AtmosAsyncClient> {
|
|||
}
|
||||
|
||||
public void testListDirectoriesOptions() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = AtmosAsyncClient.class.getMethod("listDirectories", Array.newInstance(ListOptions.class, 0)
|
||||
.getClass());
|
||||
Method method = AtmosAsyncClient.class.getMethod("listDirectories", ListOptions[].class);
|
||||
HttpRequest request = processor.createRequest(method, new ListOptions().limit(1).token("asda"));
|
||||
|
||||
assertRequestLineEquals(request, "GET https://accesspoint.atmosonline.com/rest/namespace HTTP/1.1");
|
||||
|
@ -119,8 +118,7 @@ public class AtmosAsyncClientTest extends RestClientTest<AtmosAsyncClient> {
|
|||
}
|
||||
|
||||
public void testListDirectoryOptions() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = AtmosAsyncClient.class.getMethod("listDirectory", String.class, Array.newInstance(
|
||||
ListOptions.class, 0).getClass());
|
||||
Method method = AtmosAsyncClient.class.getMethod("listDirectory", String.class, ListOptions[].class);
|
||||
HttpRequest request = processor.createRequest(method, "directory", new ListOptions().limit(1).token("asda"));
|
||||
|
||||
assertRequestLineEquals(request, "GET https://accesspoint.atmosonline.com/rest/namespace/directory/ HTTP/1.1");
|
||||
|
@ -135,7 +133,7 @@ public class AtmosAsyncClientTest extends RestClientTest<AtmosAsyncClient> {
|
|||
}
|
||||
|
||||
public void testCreateDirectory() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = AtmosAsyncClient.class.getMethod("createDirectory", String.class);
|
||||
Method method = AtmosAsyncClient.class.getMethod("createDirectory", String.class, PutOptions[].class);
|
||||
HttpRequest request = processor.createRequest(method, "dir");
|
||||
|
||||
assertRequestLineEquals(request, "POST https://accesspoint.atmosonline.com/rest/namespace/dir/ HTTP/1.1");
|
||||
|
@ -149,8 +147,25 @@ public class AtmosAsyncClientTest extends RestClientTest<AtmosAsyncClient> {
|
|||
checkFilters(request);
|
||||
}
|
||||
|
||||
public void testCreateDirectoryOptions() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = AtmosAsyncClient.class.getMethod("createDirectory", String.class, PutOptions[].class);
|
||||
HttpRequest request = processor.createRequest(method, "dir", PutOptions.Builder.publicRead());
|
||||
|
||||
assertRequestLineEquals(request, "POST https://accesspoint.atmosonline.com/rest/namespace/dir/ HTTP/1.1");
|
||||
assertNonPayloadHeadersEqual(request, HttpHeaders.ACCEPT
|
||||
+ ": */*\nx-emc-groupacl: other=READ\nx-emc-useracl: root=FULL_CONTROL\n");
|
||||
assertPayloadEquals(request, "", "application/octet-stream", false);
|
||||
|
||||
assertResponseParserClassEquals(method, request, ParseURIFromListOrLocationHeaderIf20x.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnEndpointIfAlreadyExists.class);
|
||||
|
||||
checkFilters(request);
|
||||
}
|
||||
|
||||
public void testCreateFile() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = AtmosAsyncClient.class.getMethod("createFile", String.class, AtmosObject.class);
|
||||
Method method = AtmosAsyncClient.class.getMethod("createFile", String.class, AtmosObject.class,
|
||||
PutOptions[].class);
|
||||
HttpRequest request = processor.createRequest(method, "dir", blobToObject
|
||||
.apply(BindBlobToMultipartFormTest.TEST_BLOB));
|
||||
|
||||
|
@ -165,8 +180,27 @@ public class AtmosAsyncClientTest extends RestClientTest<AtmosAsyncClient> {
|
|||
checkFilters(request);
|
||||
}
|
||||
|
||||
public void testCreateFileOptions() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = AtmosAsyncClient.class.getMethod("createFile", String.class, AtmosObject.class,
|
||||
PutOptions[].class);
|
||||
HttpRequest request = processor.createRequest(method, "dir", blobToObject
|
||||
.apply(BindBlobToMultipartFormTest.TEST_BLOB), PutOptions.Builder.publicRead());
|
||||
|
||||
assertRequestLineEquals(request, "POST https://accesspoint.atmosonline.com/rest/namespace/dir/hello HTTP/1.1");
|
||||
assertNonPayloadHeadersEqual(request, HttpHeaders.ACCEPT
|
||||
+ ": */*\nx-emc-groupacl: other=READ\nx-emc-useracl: root=FULL_CONTROL\n");
|
||||
assertPayloadEquals(request, "hello", "text/plain", false);
|
||||
|
||||
assertResponseParserClassEquals(method, request, ParseURIFromListOrLocationHeaderIf20x.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
|
||||
checkFilters(request);
|
||||
}
|
||||
|
||||
public void testUpdateFile() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = AtmosAsyncClient.class.getMethod("updateFile", String.class, AtmosObject.class);
|
||||
Method method = AtmosAsyncClient.class.getMethod("updateFile", String.class, AtmosObject.class,
|
||||
PutOptions[].class);
|
||||
HttpRequest request = processor.createRequest(method, "dir", blobToObject
|
||||
.apply(BindBlobToMultipartFormTest.TEST_BLOB));
|
||||
|
||||
|
@ -181,6 +215,24 @@ public class AtmosAsyncClientTest extends RestClientTest<AtmosAsyncClient> {
|
|||
checkFilters(request);
|
||||
}
|
||||
|
||||
public void testUpdateFileOptions() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = AtmosAsyncClient.class.getMethod("updateFile", String.class, AtmosObject.class,
|
||||
PutOptions[].class);
|
||||
HttpRequest request = processor.createRequest(method, "dir", blobToObject
|
||||
.apply(BindBlobToMultipartFormTest.TEST_BLOB), PutOptions.Builder.publicRead());
|
||||
|
||||
assertRequestLineEquals(request, "PUT https://accesspoint.atmosonline.com/rest/namespace/dir/hello HTTP/1.1");
|
||||
assertNonPayloadHeadersEqual(request, HttpHeaders.ACCEPT
|
||||
+ ": */*\nx-emc-groupacl: other=READ\nx-emc-useracl: root=FULL_CONTROL\n");
|
||||
assertPayloadEquals(request, "hello", "text/plain", false);
|
||||
|
||||
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ThrowKeyNotFoundOn404.class);
|
||||
|
||||
checkFilters(request);
|
||||
}
|
||||
|
||||
public void testReadFile() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = AtmosAsyncClient.class.getMethod("readFile", String.class, GetOptions[].class);
|
||||
HttpRequest request = processor.createRequest(method, "dir/file");
|
||||
|
@ -226,6 +278,21 @@ public class AtmosAsyncClientTest extends RestClientTest<AtmosAsyncClient> {
|
|||
checkFilters(request);
|
||||
}
|
||||
|
||||
public void testIsPublic() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = AtmosAsyncClient.class.getMethod("isPublic", String.class);
|
||||
HttpRequest request = processor.createRequest(method, "dir/file");
|
||||
|
||||
assertRequestLineEquals(request, "HEAD https://accesspoint.atmosonline.com/rest/namespace/dir/file HTTP/1.1");
|
||||
assertNonPayloadHeadersEqual(request, HttpHeaders.ACCEPT + ": */*\n");
|
||||
assertPayloadEquals(request, null, null, false);
|
||||
|
||||
assertResponseParserClassEquals(method, request, ReturnTrueIfGroupACLIsOtherRead.class);
|
||||
assertSaxResponseParserClassEquals(method, null);
|
||||
assertExceptionParserClassEquals(method, ReturnFalseOnNotFoundOr404.class);
|
||||
|
||||
checkFilters(request);
|
||||
}
|
||||
|
||||
public void testNewObject() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = AtmosAsyncClient.class.getMethod("newObject");
|
||||
assertEquals(method.getReturnType(), AtmosObject.class);
|
||||
|
|
|
@ -53,7 +53,7 @@ import com.google.common.collect.Sets;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "live", sequential = true)
|
||||
@Test(groups = "live", singleThreaded = true)
|
||||
public class AtmosClientLiveTest extends BaseBlobStoreIntegrationTest {
|
||||
|
||||
public AtmosClient getApi() {
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.jclouds.atmos.domain.DirectoryEntry;
|
|||
import org.jclouds.atmos.domain.SystemMetadata;
|
||||
import org.jclouds.atmos.domain.UserMetadata;
|
||||
import org.jclouds.atmos.options.ListOptions;
|
||||
import org.jclouds.atmos.options.PutOptions;
|
||||
import org.jclouds.blobstore.TransientAsyncBlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||
|
@ -87,7 +88,8 @@ public class StubAtmosAsyncClient implements AtmosAsyncClient {
|
|||
this.service = service;
|
||||
}
|
||||
|
||||
public ListenableFuture<URI> createDirectory(String directoryName) {
|
||||
@Override
|
||||
public ListenableFuture<URI> createDirectory(String directoryName, PutOptions... options) {
|
||||
final String container;
|
||||
final String path;
|
||||
if (directoryName.indexOf('/') != -1) {
|
||||
|
@ -112,7 +114,8 @@ public class StubAtmosAsyncClient implements AtmosAsyncClient {
|
|||
}, service);
|
||||
}
|
||||
|
||||
public ListenableFuture<URI> createFile(String parent, AtmosObject object) {
|
||||
@Override
|
||||
public ListenableFuture<URI> createFile(String parent, AtmosObject object, PutOptions... options) {
|
||||
final String uri = "http://stub/containers/" + parent + "/" + object.getContentMetadata().getName();
|
||||
String file = object.getContentMetadata().getName();
|
||||
String container = parent;
|
||||
|
@ -132,6 +135,7 @@ public class StubAtmosAsyncClient implements AtmosAsyncClient {
|
|||
}, service);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> deletePath(String path) {
|
||||
if (path.indexOf('/') == path.length() - 1) {
|
||||
// chop off the trailing slash
|
||||
|
@ -150,10 +154,12 @@ public class StubAtmosAsyncClient implements AtmosAsyncClient {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<SystemMetadata> getSystemMetadata(String path) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<UserMetadata> getUserMetadata(String path) {
|
||||
if (path.indexOf('/') == -1)
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -168,6 +174,7 @@ public class StubAtmosAsyncClient implements AtmosAsyncClient {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<AtmosObject> headFile(String path) {
|
||||
String container = path.substring(0, path.indexOf('/'));
|
||||
path = path.substring(path.indexOf('/') + 1);
|
||||
|
@ -178,12 +185,14 @@ public class StubAtmosAsyncClient implements AtmosAsyncClient {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<BoundedSet<? extends DirectoryEntry>> listDirectories(ListOptions... optionsList) {
|
||||
// org.jclouds.blobstore.options.ListOptions options = container2ContainerListOptions
|
||||
// .apply(optionsList);
|
||||
return Futures.compose(blobStore.list(), resource2ObjectList, service);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<BoundedSet<? extends DirectoryEntry>> listDirectory(String directoryName,
|
||||
ListOptions... optionsList) {
|
||||
org.jclouds.blobstore.options.ListContainerOptions options = container2ContainerListOptions.apply(optionsList);
|
||||
|
@ -197,10 +206,12 @@ public class StubAtmosAsyncClient implements AtmosAsyncClient {
|
|||
return Futures.compose(blobStore.list(container, options), resource2ObjectList, service);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AtmosObject newObject() {
|
||||
return this.objectProvider.create(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Boolean> pathExists(final String path) {
|
||||
if (path.indexOf('/') == path.length() - 1) {
|
||||
// chop off the trailing slash
|
||||
|
@ -218,6 +229,7 @@ public class StubAtmosAsyncClient implements AtmosAsyncClient {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<AtmosObject> readFile(String path, GetOptions... options) {
|
||||
String container = path.substring(0, path.indexOf('/'));
|
||||
String blobName = path.substring(path.indexOf('/') + 1);
|
||||
|
@ -225,7 +237,13 @@ public class StubAtmosAsyncClient implements AtmosAsyncClient {
|
|||
return Futures.compose(blobStore.getBlob(container, blobName, getOptions), blob2Object, service);
|
||||
}
|
||||
|
||||
public ListenableFuture<Void> updateFile(String parent, AtmosObject object) {
|
||||
@Override
|
||||
public ListenableFuture<Void> updateFile(String parent, AtmosObject object, PutOptions... options) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Boolean> isPublic(String path) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,9 @@ public class BaseContainerLiveTest extends BaseBlobStoreIntegrationTest {
|
|||
|
||||
BlobMetadata metadata = context.getBlobStore().blobMetadata(containerName, "hello");
|
||||
|
||||
assertEquals(Strings2.toStringAndClose(metadata.getPublicUri().toURL().openStream()), TEST_STRING);
|
||||
assert metadata.getPublicUri() != null : metadata;
|
||||
|
||||
assertEquals(Strings2.toStringAndClose(context.utils().http().get(metadata.getPublicUri())), TEST_STRING);
|
||||
|
||||
} finally {
|
||||
// this container is now public, so we can't reuse it directly
|
||||
|
|
Loading…
Reference in New Issue