Issue 301: removed encryption service dependency from blob and added helper methods to blobstore.clj

This commit is contained in:
Adrian Cole 2010-07-08 10:42:18 -07:00
parent ef496e7262
commit 31d2da3c6f
28 changed files with 249 additions and 263 deletions

View File

@ -27,7 +27,6 @@ import org.jclouds.atmosonline.saas.domain.SystemMetadata;
import org.jclouds.atmosonline.saas.domain.UserMetadata; import org.jclouds.atmosonline.saas.domain.UserMetadata;
import org.jclouds.atmosonline.saas.domain.internal.AtmosObjectImpl; import org.jclouds.atmosonline.saas.domain.internal.AtmosObjectImpl;
import org.jclouds.blobstore.config.BlobStoreObjectModule; import org.jclouds.blobstore.config.BlobStoreObjectModule;
import org.jclouds.encryption.EncryptionService;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -52,25 +51,22 @@ public class AtmosObjectModule extends AbstractModule {
} }
private static class AtmosObjectFactory implements AtmosObject.Factory { private static class AtmosObjectFactory implements AtmosObject.Factory {
@Inject
EncryptionService encryptionService;
@Inject @Inject
Provider<MutableContentMetadata> metadataProvider; Provider<MutableContentMetadata> metadataProvider;
public AtmosObject create(MutableContentMetadata contentMetadata) { public AtmosObject create(MutableContentMetadata contentMetadata) {
return new AtmosObjectImpl(encryptionService, contentMetadata != null ? contentMetadata return new AtmosObjectImpl(contentMetadata != null ? contentMetadata : metadataProvider
: metadataProvider.get()); .get());
} }
public AtmosObject create(SystemMetadata systemMetadata, UserMetadata userMetadata) { public AtmosObject create(SystemMetadata systemMetadata, UserMetadata userMetadata) {
return new AtmosObjectImpl(encryptionService, metadataProvider.get(), systemMetadata, return new AtmosObjectImpl(metadataProvider.get(), systemMetadata, userMetadata);
userMetadata);
} }
public AtmosObject create(MutableContentMetadata contentMetadata, public AtmosObject create(MutableContentMetadata contentMetadata,
SystemMetadata systemMetadata, UserMetadata userMetadata) { SystemMetadata systemMetadata, UserMetadata userMetadata) {
return new AtmosObjectImpl(encryptionService, contentMetadata, systemMetadata, return new AtmosObjectImpl(contentMetadata, systemMetadata, userMetadata);
userMetadata);
} }
} }

View File

@ -26,7 +26,6 @@ import org.jclouds.atmosonline.saas.domain.AtmosObject;
import org.jclouds.atmosonline.saas.domain.MutableContentMetadata; import org.jclouds.atmosonline.saas.domain.MutableContentMetadata;
import org.jclouds.atmosonline.saas.domain.SystemMetadata; import org.jclouds.atmosonline.saas.domain.SystemMetadata;
import org.jclouds.atmosonline.saas.domain.UserMetadata; import org.jclouds.atmosonline.saas.domain.UserMetadata;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.Payload; import org.jclouds.http.Payload;
import org.jclouds.http.PayloadEnclosing; import org.jclouds.http.PayloadEnclosing;
import org.jclouds.http.internal.PayloadEnclosingImpl; import org.jclouds.http.internal.PayloadEnclosingImpl;
@ -57,10 +56,9 @@ public class AtmosObjectImpl extends PayloadEnclosingImpl implements AtmosObject
private final SetPayloadPropertiesMutableContentMetadata contentMetadata; private final SetPayloadPropertiesMutableContentMetadata contentMetadata;
private Multimap<String, String> allHeaders = LinkedHashMultimap.create(); private Multimap<String, String> allHeaders = LinkedHashMultimap.create();
public AtmosObjectImpl(EncryptionService encryptionService, public AtmosObjectImpl(MutableContentMetadata contentMetadata, SystemMetadata systemMetadata,
MutableContentMetadata contentMetadata, SystemMetadata systemMetadata,
UserMetadata userMetadata) { UserMetadata userMetadata) {
super(encryptionService); super();
this.contentMetadata = linkMetadataToThis(contentMetadata); this.contentMetadata = linkMetadataToThis(contentMetadata);
this._contentMetadata = this.contentMetadata.getDelegate(); this._contentMetadata = this.contentMetadata.getDelegate();
this.systemMetadata = systemMetadata; this.systemMetadata = systemMetadata;
@ -68,9 +66,8 @@ public class AtmosObjectImpl extends PayloadEnclosingImpl implements AtmosObject
} }
@Inject @Inject
public AtmosObjectImpl(EncryptionService encryptionService, public AtmosObjectImpl(MutableContentMetadata contentMetadata) {
MutableContentMetadata contentMetadata) { this(contentMetadata, null, new UserMetadata());
this(encryptionService, contentMetadata, null, new UserMetadata());
} }
/** /**

View File

@ -112,6 +112,7 @@ public class AtmosStorageClientLiveTest {
URI container1; URI container1;
URI container2; URI container2;
private BlobStoreContext context;
@BeforeGroups(groups = { "live" }) @BeforeGroups(groups = { "live" })
public void setupClient() throws InterruptedException, ExecutionException, TimeoutException, public void setupClient() throws InterruptedException, ExecutionException, TimeoutException,
@ -120,15 +121,14 @@ public class AtmosStorageClientLiveTest {
"jclouds.test.identity"); "jclouds.test.identity");
String credential = checkNotNull(System.getProperty("jclouds.test.credential"), String credential = checkNotNull(System.getProperty("jclouds.test.credential"),
"jclouds.test.credential"); "jclouds.test.credential");
BlobStoreContext blobStoreContext = new BlobStoreContextFactory().createContext( context = new BlobStoreContextFactory().createContext("atmosonline", identity, credential,
"atmosonline", identity, credential, ImmutableSet ImmutableSet.<Module> of(new Log4JLoggingModule()));
.<Module> of(new Log4JLoggingModule())); RestContext<AtmosStorageClient, AtmosStorageAsyncClient> restContext = context
RestContext<AtmosStorageClient, AtmosStorageAsyncClient> context = blobStoreContext
.getProviderSpecificContext(); .getProviderSpecificContext();
connection = context.getApi(); connection = restContext.getApi();
for (DirectoryEntry entry : connection.listDirectories()) { for (DirectoryEntry entry : connection.listDirectories()) {
if (entry.getObjectName().startsWith(containerPrefix)) { if (entry.getObjectName().startsWith(containerPrefix)) {
blobStoreContext.getBlobStore().deleteContainer(entry.getObjectName()); context.getBlobStore().deleteContainer(entry.getObjectName());
} }
} }
} }
@ -226,7 +226,7 @@ public class AtmosStorageClientLiveTest {
object.getContentMetadata().setName(name); object.getContentMetadata().setName(name);
object.setPayload(Payloads.newPayload(data)); object.setPayload(Payloads.newPayload(data));
object.getContentMetadata().setContentLength(16l); object.getContentMetadata().setContentLength(16l);
object.generateMD5(); context.utils().encryption().generateMD5BufferingIfNotRepeatable(object);
object.getContentMetadata().setContentType("text/plain"); object.getContentMetadata().setContentType("text/plain");
object.getUserMetadata().getMetadata().put("Metadata", metadataValue); object.getUserMetadata().getMetadata().put("Metadata", metadataValue);
replaceObject(object); replaceObject(object);

View File

@ -25,7 +25,6 @@ import org.jclouds.aws.s3.domain.MutableObjectMetadata;
import org.jclouds.aws.s3.domain.S3Object; import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.domain.internal.S3ObjectImpl; import org.jclouds.aws.s3.domain.internal.S3ObjectImpl;
import org.jclouds.blobstore.config.BlobStoreObjectModule; import org.jclouds.blobstore.config.BlobStoreObjectModule;
import org.jclouds.encryption.EncryptionService;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -49,14 +48,11 @@ public class S3ObjectModule extends AbstractModule {
} }
private static class S3ObjectFactory implements S3Object.Factory { private static class S3ObjectFactory implements S3Object.Factory {
@Inject
EncryptionService encryptionService;
@Inject @Inject
Provider<MutableObjectMetadata> metadataProvider; Provider<MutableObjectMetadata> metadataProvider;
public S3Object create(MutableObjectMetadata metadata) { public S3Object create(MutableObjectMetadata metadata) {
return new S3ObjectImpl(encryptionService, metadata != null ? metadata : metadataProvider return new S3ObjectImpl(metadata != null ? metadata : metadataProvider.get());
.get());
} }
} }

View File

@ -25,7 +25,6 @@ import javax.inject.Inject;
import org.jclouds.aws.s3.domain.AccessControlList; import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.MutableObjectMetadata; import org.jclouds.aws.s3.domain.MutableObjectMetadata;
import org.jclouds.aws.s3.domain.S3Object; import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.Payload; import org.jclouds.http.Payload;
import org.jclouds.http.PayloadEnclosing; import org.jclouds.http.PayloadEnclosing;
import org.jclouds.http.internal.PayloadEnclosingImpl; import org.jclouds.http.internal.PayloadEnclosingImpl;
@ -64,8 +63,8 @@ public class S3ObjectImpl extends PayloadEnclosingImpl implements S3Object, Comp
private Multimap<String, String> allHeaders = LinkedHashMultimap.create(); private Multimap<String, String> allHeaders = LinkedHashMultimap.create();
@Inject @Inject
public S3ObjectImpl(EncryptionService encryptionService, MutableObjectMetadata metadata) { public S3ObjectImpl(MutableObjectMetadata metadata) {
super(encryptionService); super();
this.metadata = linkMetadataToThis(metadata); this.metadata = linkMetadataToThis(metadata);
this._metadata = this.metadata.getDelegate(); this._metadata = this.metadata.getDelegate();
} }

View File

@ -25,7 +25,6 @@ import org.jclouds.azure.storage.blob.domain.AzureBlob;
import org.jclouds.azure.storage.blob.domain.MutableBlobProperties; import org.jclouds.azure.storage.blob.domain.MutableBlobProperties;
import org.jclouds.azure.storage.blob.domain.internal.AzureBlobImpl; import org.jclouds.azure.storage.blob.domain.internal.AzureBlobImpl;
import org.jclouds.blobstore.config.BlobStoreObjectModule; import org.jclouds.blobstore.config.BlobStoreObjectModule;
import org.jclouds.encryption.EncryptionService;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -50,14 +49,11 @@ public class AzureBlobModule extends AbstractModule {
} }
private static class AzureBlobFactory implements AzureBlob.Factory { private static class AzureBlobFactory implements AzureBlob.Factory {
@Inject
EncryptionService encryptionService;
@Inject @Inject
Provider<MutableBlobProperties> metadataProvider; Provider<MutableBlobProperties> metadataProvider;
public AzureBlob create(MutableBlobProperties metadata) { public AzureBlob create(MutableBlobProperties metadata) {
return new AzureBlobImpl(encryptionService, metadata != null ? metadata : metadataProvider return new AzureBlobImpl(metadata != null ? metadata : metadataProvider.get());
.get());
} }
} }

View File

@ -24,7 +24,6 @@ import javax.inject.Inject;
import org.jclouds.azure.storage.blob.domain.AzureBlob; import org.jclouds.azure.storage.blob.domain.AzureBlob;
import org.jclouds.azure.storage.blob.domain.MutableBlobProperties; import org.jclouds.azure.storage.blob.domain.MutableBlobProperties;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.Payload; import org.jclouds.http.Payload;
import org.jclouds.http.PayloadEnclosing; import org.jclouds.http.PayloadEnclosing;
import org.jclouds.http.internal.PayloadEnclosingImpl; import org.jclouds.http.internal.PayloadEnclosingImpl;
@ -45,8 +44,8 @@ public class AzureBlobImpl extends PayloadEnclosingImpl implements AzureBlob, Co
private Multimap<String, String> allHeaders = LinkedHashMultimap.create(); private Multimap<String, String> allHeaders = LinkedHashMultimap.create();
@Inject @Inject
public AzureBlobImpl(EncryptionService encryptionService, MutableBlobProperties properties) { public AzureBlobImpl(MutableBlobProperties properties) {
super(encryptionService); super();
this.properties = linkMetadataToThis(properties); this.properties = linkMetadataToThis(properties);
this._properties = this.properties.getDelegate(); this._properties = this.properties.getDelegate();
} }

View File

@ -39,10 +39,9 @@ import org.jclouds.azure.storage.blob.domain.ListBlobsResponse;
import org.jclouds.azure.storage.blob.options.ListBlobsOptions; import org.jclouds.azure.storage.blob.options.ListBlobsOptions;
import org.jclouds.azure.storage.domain.BoundedSet; import org.jclouds.azure.storage.domain.BoundedSet;
import org.jclouds.azure.storage.options.ListOptions; import org.jclouds.azure.storage.options.ListOptions;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.BlobStoreContextFactory; import org.jclouds.blobstore.BlobStoreContextFactory;
import org.jclouds.blobstore.ContainerNotFoundException; import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.encryption.internal.JCEEncryptionService;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.http.options.GetOptions; import org.jclouds.http.options.GetOptions;
import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.logging.log4j.config.Log4JLoggingModule;
@ -67,15 +66,16 @@ public class AzureBlobClientLiveTest {
protected AzureBlobClient client; protected AzureBlobClient client;
private String containerPrefix = System.getProperty("user.name") + "-azureblob"; private String containerPrefix = System.getProperty("user.name") + "-azureblob";
private EncryptionService encryptionService = new JCEEncryptionService();
private BlobStoreContext context;
@BeforeTest @BeforeTest
public void setupClient() throws IOException { public void setupClient() throws IOException {
identity = System.getProperty("jclouds.test.identity"); identity = System.getProperty("jclouds.test.identity");
String credential = System.getProperty("jclouds.test.credential"); String credential = System.getProperty("jclouds.test.credential");
client = (AzureBlobClient) new BlobStoreContextFactory().createContext("azureblob", identity, context = new BlobStoreContextFactory().createContext("azureblob", identity, credential,
credential, ImmutableSet.<Module> of(new Log4JLoggingModule())) ImmutableSet.<Module> of(new Log4JLoggingModule()));
.getProviderSpecificContext().getApi(); client = (AzureBlobClient) context.getProviderSpecificContext().getApi();
} }
@Test @Test
@ -113,7 +113,7 @@ public class AzureBlobClientLiveTest {
ListBlobsResponse list = client.listBlobs(privateContainer); ListBlobsResponse list = client.listBlobs(privateContainer);
assertEquals(list.getUrl(), URI.create(String.format("https://%s.blob.core.windows.net/%s", assertEquals(list.getUrl(), URI.create(String.format("https://%s.blob.core.windows.net/%s",
identity, privateContainer))); identity, privateContainer)));
// TODO ... check to see the container actually exists // TODO .. check to see the container actually exists
} }
@Test(timeOut = 5 * 60 * 1000) @Test(timeOut = 5 * 60 * 1000)
@ -231,12 +231,12 @@ public class AzureBlobClientLiveTest {
AzureBlob object = client.newBlob(); AzureBlob object = client.newBlob();
object.getProperties().setName("object"); object.getProperties().setName("object");
object.setPayload(data); object.setPayload(data);
object.generateMD5(); context.utils().encryption().generateMD5BufferingIfNotRepeatable(object);
object.getProperties().setContentType("text/plain"); object.getProperties().setContentType("text/plain");
object.getProperties().getMetadata().put("mykey", "metadata-value"); object.getProperties().getMetadata().put("mykey", "metadata-value");
byte[] md5 = object.getProperties().getContentMD5(); byte[] md5 = object.getProperties().getContentMD5();
String newEtag = client.putBlob(privateContainer, object); String newEtag = client.putBlob(privateContainer, object);
assertEquals(encryptionService.hex(md5), encryptionService.hex(object.getProperties() assertEquals(context.utils().encryption().hex(md5), context.utils().encryption().hex(object.getProperties()
.getContentMD5())); .getContentMD5()));
// Test HEAD of missing object // Test HEAD of missing object
@ -253,8 +253,8 @@ public class AzureBlobClientLiveTest {
// http://code.google.com/p/jclouds/issues/detail?id=92 // http://code.google.com/p/jclouds/issues/detail?id=92
// assertEquals(metadata.getSize(), data.length()); // assertEquals(metadata.getSize(), data.length());
assertEquals(metadata.getContentType(), "text/plain"); assertEquals(metadata.getContentType(), "text/plain");
// Azure doesn't return the Content-MD5 on head request... // Azure doesn't return the Content-MD5 on head request..
assertEquals(encryptionService.hex(md5), encryptionService.hex(object.getProperties() assertEquals(context.utils().encryption().hex(md5), context.utils().encryption().hex(object.getProperties()
.getContentMD5())); .getContentMD5()));
assertEquals(metadata.getETag(), newEtag); assertEquals(metadata.getETag(), newEtag);
assertEquals(metadata.getMetadata().entrySet().size(), 1); assertEquals(metadata.getMetadata().entrySet().size(), 1);
@ -276,7 +276,7 @@ public class AzureBlobClientLiveTest {
// TODO assertEquals(getBlob.getName(), object.getProperties().getName()); // TODO assertEquals(getBlob.getName(), object.getProperties().getName());
assertEquals(getBlob.getPayload().getContentLength(), new Long(data.length())); assertEquals(getBlob.getPayload().getContentLength(), new Long(data.length()));
assertEquals(getBlob.getProperties().getContentType(), "text/plain"); assertEquals(getBlob.getProperties().getContentType(), "text/plain");
assertEquals(encryptionService.hex(md5), encryptionService.hex(getBlob.getProperties() assertEquals(context.utils().encryption().hex(md5), context.utils().encryption().hex(getBlob.getProperties()
.getContentMD5())); .getContentMD5()));
assertEquals(newEtag, getBlob.getProperties().getETag()); assertEquals(newEtag, getBlob.getProperties().getETag());
// wait until we can update metadata // wait until we can update metadata
@ -318,7 +318,7 @@ public class AzureBlobClientLiveTest {
object.setPayload(bais); object.setPayload(bais);
object.getPayload().setContentLength(new Long(data.getBytes().length)); object.getPayload().setContentLength(new Long(data.getBytes().length));
newEtag = client.putBlob(privateContainer, object); newEtag = client.putBlob(privateContainer, object);
assertEquals(encryptionService.hex(md5), encryptionService.hex(getBlob.getProperties() assertEquals(context.utils().encryption().hex(md5), context.utils().encryption().hex(getBlob.getProperties()
.getContentMD5())); .getContentMD5()));
// Test GET with options // Test GET with options

View File

@ -22,7 +22,7 @@
Current supported services are: Current supported services are:
[s3, azureblob, atmos, cloudfiles, walrus, googlestorage] [s3, azureblob, atmos, cloudfiles, walrus, googlestorage]
Here's a quick example of how to view blob resources in rackspace Here's a quick example of how to viewresources in rackspace
(use 'org.jclouds.blobstore) (use 'org.jclouds.blobstore)
(use 'clojure.contrib.pprint) (use 'clojure.contrib.pprint)
@ -92,8 +92,6 @@ Options can also be specified for extension modules
(def *blobstore*) (def *blobstore*)
(def *encryption-service* (JCEEncryptionService.)) ;; TODO: use guice
(def *max-retries* 3) (def *max-retries* 3)
(defmacro with-blobstore [[& blobstore-or-args] & body] (defmacro with-blobstore [[& blobstore-or-args] & body]
@ -222,7 +220,7 @@ Options can also be specified for extension modules
(.putBlob blobstore container-name blob))) (.putBlob blobstore container-name blob)))
(defn blob-metadata (defn blob-metadata
"Get blob metadata from given path" "Get metadata from given path"
([container-name path] ([container-name path]
(blob-metadata container-name path *blobstore*)) (blob-metadata container-name path *blobstore*))
([container-name path blobstore] ([container-name path blobstore]
@ -268,17 +266,29 @@ example:
(.list (as-blobstore blobstore) container-name (.list (as-blobstore blobstore) container-name
(.inDirectory (new ListContainerOptions) dir)))) (.inDirectory (new ListContainerOptions) dir))))
(defn md5-blob
"add a content md5 to a blob. note that this implies rebuffering, if theisn't repeatable"
([blob]
(md5-blob *blobstore*))
([blob blobstore]
(.generateMD5BufferingIfNotRepeatable (.encryption (.utils (blobstore-context blobstore)))
blob)))
(defn blob
"create a new blob with the specified payload"
([name payload]
(blob name payload *blobstore*))
([name payload blobstore]
(doto (.newBlob blobstore name)
(.setPayload payload))))
(defn upload-blob (defn upload-blob
"Create an blob representing text data: "Create anrepresenting text data:
container, name, string -> etag" container, name, string -> etag"
([container-name name data] ;; TODO: allow payload to be a stream ([container-name name data]
(upload-blob container-name name data *blobstore*)) (upload-blob container-name name data *blobstore*))
([container-name name data blobstore] ([container-name name data blobstore]
(put-blob container-name (put-blob container-name
(doto (.newBlob blobstore name) (md5-blob (blob name data) blobstore) blobstore)))
(.setPayload data)
(.generateMD5))
blobstore)))
(defmulti #^{:arglists '[[container-name name target] (defmulti #^{:arglists '[[container-name name target]
[container-name name target blobstore]]} [container-name name target blobstore]]}

View File

@ -31,6 +31,7 @@ import org.jclouds.blobstore.strategy.ContainsValueInListStrategy;
import org.jclouds.blobstore.strategy.GetBlobsInListStrategy; import org.jclouds.blobstore.strategy.GetBlobsInListStrategy;
import org.jclouds.blobstore.strategy.PutBlobsStrategy; import org.jclouds.blobstore.strategy.PutBlobsStrategy;
import org.jclouds.blobstore.strategy.internal.ListContainerAndRecurseThroughFolders; import org.jclouds.blobstore.strategy.internal.ListContainerAndRecurseThroughFolders;
import org.jclouds.encryption.EncryptionService;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Scopes; import com.google.inject.Scopes;
@ -83,11 +84,14 @@ public class BlobStoreMapModule extends AbstractModule {
@Inject @Inject
PutBlobsStrategy putBlobsStrategy; PutBlobsStrategy putBlobsStrategy;
@Inject @Inject
EncryptionService encryptionService;
@Inject
ListContainerAndRecurseThroughFolders listStrategy; ListContainerAndRecurseThroughFolders listStrategy;
public InputStreamMap create(String containerName, ListContainerOptions options) { public InputStreamMap create(String containerName, ListContainerOptions options) {
return new InputStreamMapImpl(connection, blobFactory, getAllBlobs, listStrategy, return new InputStreamMapImpl(connection, blobFactory, getAllBlobs, listStrategy,
containsValueStrategy, putBlobsStrategy, containerName, options); containsValueStrategy, putBlobsStrategy, containerName, options,
encryptionService);
} }
} }

View File

@ -24,7 +24,6 @@ import javax.inject.Provider;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.MutableBlobMetadata; import org.jclouds.blobstore.domain.MutableBlobMetadata;
import org.jclouds.blobstore.domain.internal.BlobImpl; import org.jclouds.blobstore.domain.internal.BlobImpl;
import org.jclouds.encryption.EncryptionService;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -47,14 +46,12 @@ public class BlobStoreObjectModule extends AbstractModule {
} }
private static class BlobFactory implements Blob.Factory { private static class BlobFactory implements Blob.Factory {
@Inject
EncryptionService encryptionService;
@Inject @Inject
Provider<MutableBlobMetadata> metadataProvider; Provider<MutableBlobMetadata> metadataProvider;
public Blob create(MutableBlobMetadata metadata) { public Blob create(MutableBlobMetadata metadata) {
return new BlobImpl(encryptionService, metadata != null ? metadata : metadataProvider return new BlobImpl(metadata != null ? metadata : metadataProvider.get());
.get());
} }
} }

View File

@ -25,7 +25,6 @@ import javax.inject.Inject;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.MutableBlobMetadata; import org.jclouds.blobstore.domain.MutableBlobMetadata;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.Payload; import org.jclouds.http.Payload;
import org.jclouds.http.PayloadEnclosing; import org.jclouds.http.PayloadEnclosing;
import org.jclouds.http.internal.PayloadEnclosingImpl; import org.jclouds.http.internal.PayloadEnclosingImpl;
@ -49,8 +48,8 @@ public class BlobImpl extends PayloadEnclosingImpl implements Blob, Comparable<B
private Multimap<String, String> allHeaders = LinkedHashMultimap.create(); private Multimap<String, String> allHeaders = LinkedHashMultimap.create();
@Inject @Inject
public BlobImpl(EncryptionService encryptionService, MutableBlobMetadata metadata) { public BlobImpl(MutableBlobMetadata metadata) {
super(encryptionService); super();
this.metadata = linkMetadataToThis(metadata); this.metadata = linkMetadataToThis(metadata);
this._metadata = this.metadata.getDelegate(); this._metadata = this.metadata.getDelegate();
} }

View File

@ -21,6 +21,7 @@ package org.jclouds.blobstore.functions;
import javax.inject.Inject; import javax.inject.Inject;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.Payloads; import org.jclouds.http.Payloads;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -28,10 +29,12 @@ import com.google.common.base.Function;
public class ObjectMD5 implements Function<Object, byte[]> { public class ObjectMD5 implements Function<Object, byte[]> {
protected final Blob.Factory blobFactory; protected final Blob.Factory blobFactory;
protected final EncryptionService encryptionService;
@Inject @Inject
ObjectMD5(Blob.Factory blobFactory) { ObjectMD5(EncryptionService encryptionService, Blob.Factory blobFactory) {
this.blobFactory = blobFactory; this.blobFactory = blobFactory;
this.encryptionService = encryptionService;
} }
public byte[] apply(Object from) { public byte[] apply(Object from) {
@ -43,7 +46,7 @@ public class ObjectMD5 implements Function<Object, byte[]> {
object.setPayload(Payloads.newPayload(from)); object.setPayload(Payloads.newPayload(from));
} }
if (object.getMetadata().getContentMD5() == null) if (object.getMetadata().getContentMD5() == null)
object.generateMD5(); encryptionService.generateMD5BufferingIfNotRepeatable(object);
return object.getPayload().getContentMD5(); return object.getPayload().getContentMD5();
} }

View File

@ -38,6 +38,7 @@ import org.jclouds.blobstore.strategy.ContainsValueInListStrategy;
import org.jclouds.blobstore.strategy.GetBlobsInListStrategy; import org.jclouds.blobstore.strategy.GetBlobsInListStrategy;
import org.jclouds.blobstore.strategy.PutBlobsStrategy; import org.jclouds.blobstore.strategy.PutBlobsStrategy;
import org.jclouds.blobstore.strategy.internal.ListContainerAndRecurseThroughFolders; import org.jclouds.blobstore.strategy.internal.ListContainerAndRecurseThroughFolders;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.Payload; import org.jclouds.http.Payload;
import org.jclouds.http.payloads.ByteArrayPayload; import org.jclouds.http.payloads.ByteArrayPayload;
import org.jclouds.http.payloads.FilePayload; import org.jclouds.http.payloads.FilePayload;
@ -58,14 +59,16 @@ import com.google.common.base.Function;
* @see BaseBlobMap * @see BaseBlobMap
*/ */
public class InputStreamMapImpl extends BaseBlobMap<InputStream> implements InputStreamMap { public class InputStreamMapImpl extends BaseBlobMap<InputStream> implements InputStreamMap {
protected final EncryptionService encryptionService;
@Inject @Inject
public InputStreamMapImpl(BlobStore connection, Blob.Factory blobFactory, public InputStreamMapImpl(BlobStore connection, Blob.Factory blobFactory,
GetBlobsInListStrategy getAllBlobs, ListContainerAndRecurseThroughFolders listStrategy, GetBlobsInListStrategy getAllBlobs, ListContainerAndRecurseThroughFolders listStrategy,
ContainsValueInListStrategy containsValueStrategy, PutBlobsStrategy putBlobsStrategy, ContainsValueInListStrategy containsValueStrategy, PutBlobsStrategy putBlobsStrategy,
String containerName, ListContainerOptions options) { String containerName, ListContainerOptions options, EncryptionService encryptionService) {
super(connection, getAllBlobs, containsValueStrategy, putBlobsStrategy, listStrategy, super(connection, getAllBlobs, containsValueStrategy, putBlobsStrategy, listStrategy,
containerName, options); containerName, options);
this.encryptionService = encryptionService;
} }
@Override @Override
@ -129,14 +132,22 @@ public class InputStreamMapImpl extends BaseBlobMap<InputStream> implements Inpu
new Function<Map.Entry<? extends String, ? extends Object>, Blob>() { new Function<Map.Entry<? extends String, ? extends Object>, Blob>() {
@Override @Override
public Blob apply(Map.Entry<? extends String, ? extends Object> from) { public Blob apply(Map.Entry<? extends String, ? extends Object> from) {
Blob blob = blobstore.newBlob(prefixer.apply(from.getKey())); String name = from.getKey();
blob.setPayload(newPayload(from.getValue())); Object value = from.getValue();
blob.generateMD5(); return newBlobWithMD5(name, value);
return blob;
} }
})); }));
} }
@VisibleForTesting
Blob newBlobWithMD5(String name, Object value) {
Blob blob = blobstore.newBlob(prefixer.apply(name));
blob.setPayload(newPayload(value));
encryptionService.generateMD5BufferingIfNotRepeatable(blob);
return blob;
}
@Override @Override
public InputStream putString(String key, String value) { public InputStream putString(String key, String value) {
return putInternal(key, new StringPayload(value)); return putInternal(key, new StringPayload(value));
@ -166,9 +177,7 @@ public class InputStreamMapImpl extends BaseBlobMap<InputStream> implements Inpu
@VisibleForTesting @VisibleForTesting
InputStream putInternal(String name, Payload payload) { InputStream putInternal(String name, Payload payload) {
InputStream returnVal = containsKey(name) ? get(name) : null; InputStream returnVal = containsKey(name) ? get(name) : null;
Blob blob = blobstore.newBlob(prefixer.apply(name)); Blob blob = newBlobWithMD5(name, payload);
blob.setPayload(payload);
blob.generateMD5();
blobstore.putBlob(containerName, blob); blobstore.putBlob(containerName, blob);
return returnVal; return returnVal;
} }

View File

@ -47,7 +47,6 @@ import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.StorageType; import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.encryption.internal.JCEEncryptionService; import org.jclouds.encryption.internal.JCEEncryptionService;
import org.jclouds.http.BaseJettyTest; import org.jclouds.http.BaseJettyTest;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
@ -68,25 +67,22 @@ import com.google.common.io.ByteStreams;
import com.google.common.io.InputSupplier; import com.google.common.io.InputSupplier;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.Guice;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest { public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
private byte[] oneHundredOneConstitutions; private byte[] oneHundredOneConstitutions;
private EncryptionService encryptionService;
private byte[] oneHundredOneConstitutionsMD5; private byte[] oneHundredOneConstitutionsMD5;
@BeforeClass(groups = { "integration", "live" }) @BeforeClass(groups = { "integration", "live" })
@Override @Override
public void setUpResourcesOnThisThread(ITestContext testContext) throws Exception { public void setUpResourcesOnThisThread(ITestContext testContext) throws Exception {
encryptionService = Guice.createInjector().getInstance(EncryptionService.class); super.setUpResourcesOnThisThread(testContext);
Payload result = encryptionService Payload result = context.utils().encryption().generatePayloadWithMD5For(
.generatePayloadWithMD5For(getTestDataSupplier().getInput()); getTestDataSupplier().getInput());
oneHundredOneConstitutions = (byte[]) result.getRawContent(); oneHundredOneConstitutions = (byte[]) result.getRawContent();
oneHundredOneConstitutionsMD5 = result.getContentMD5(); oneHundredOneConstitutionsMD5 = result.getContentMD5();
super.setUpResourcesOnThisThread(testContext);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -119,7 +115,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
@Override @Override
public Void apply(Blob from) { public Void apply(Blob from) {
assertEquals(encryptionService.md5(from.getPayload().getInput()), assertEquals(context.utils().encryption().md5(from.getPayload().getInput()),
oneHundredOneConstitutionsMD5); oneHundredOneConstitutionsMD5);
return null; return null;
} }
@ -151,7 +147,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
String key = "apples"; String key = "apples";
Date before = new Date(System.currentTimeMillis() - 1000); Date before = new Date(System.currentTimeMillis() - 1000);
// first create the object // first create the blob
addObjectAndValidateContent(containerName, key); addObjectAndValidateContent(containerName, key);
// now, modify it // now, modify it
addObjectAndValidateContent(containerName, key); addObjectAndValidateContent(containerName, key);
@ -251,13 +247,13 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
String key = "apples"; String key = "apples";
addObjectAndValidateContent(containerName, key); addObjectAndValidateContent(containerName, key);
Blob object1 = context.getBlobStore().getBlob(containerName, key, range(0, 5)); Blob blob1 = context.getBlobStore().getBlob(containerName, key, range(0, 5));
assertEquals(getContentAsStringOrNullAndClose(object1), TEST_STRING.substring(0, 6)); assertEquals(getContentAsStringOrNullAndClose(blob1), TEST_STRING.substring(0, 6));
Blob object2 = context.getBlobStore().getBlob(containerName, key, Blob blob2 = context.getBlobStore().getBlob(containerName, key,
range(6, TEST_STRING.length())); range(6, TEST_STRING.length()));
assertEquals(getContentAsStringOrNullAndClose(object2), TEST_STRING.substring(6, assertEquals(getContentAsStringOrNullAndClose(blob2), TEST_STRING.substring(6, TEST_STRING
TEST_STRING.length())); .length()));
} finally { } finally {
returnContainer(containerName); returnContainer(containerName);
} }
@ -271,10 +267,10 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
String key = "apples"; String key = "apples";
addObjectAndValidateContent(containerName, key); addObjectAndValidateContent(containerName, key);
Blob object = context.getBlobStore().getBlob(containerName, key, Blob blob = context.getBlobStore().getBlob(containerName, key,
range(0, 5).range(6, TEST_STRING.length())); range(0, 5).range(6, TEST_STRING.length()));
assertEquals(getContentAsStringOrNullAndClose(object), TEST_STRING); assertEquals(getContentAsStringOrNullAndClose(blob), TEST_STRING);
} finally { } finally {
returnContainer(containerName); returnContainer(containerName);
} }
@ -289,12 +285,12 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
// String key = "apples"; // String key = "apples";
// //
// addObjectAndValidateContent(containerName, key); // addObjectAndValidateContent(containerName, key);
// Blob object = context.getBlobStore().getBlob(containerName, key, tail(5)).get(30, // Blob blob = context.getBlobStore().getBlob(containerName, key, tail(5)).get(30,
// TimeUnit.SECONDS); // TimeUnit.SECONDS);
// assertEquals(BlobStoreUtils.getContentAsStringAndClose(object), TEST_STRING // assertEquals(BlobStoreUtils.getContentAsStringAndClose(blob), TEST_STRING
// .substring(TEST_STRING.length() - 5)); // .substring(TEST_STRING.length() - 5));
// assertEquals(object.getContentLength(), 5); // assertEquals(blob.getContentLength(), 5);
// assertEquals(object.getMetadata().getSize(), TEST_STRING.length()); // assertEquals(blob.getMetadata().getSize(), TEST_STRING.length());
// } finally { // } finally {
// returnContainer(containerName); // returnContainer(containerName);
// } // }
@ -309,12 +305,12 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
// String key = "apples"; // String key = "apples";
// //
// addObjectAndValidateContent(containerName, key); // addObjectAndValidateContent(containerName, key);
// Blob object = context.getBlobStore().getBlob(containerName, key, startAt(5)).get(30, // Blob blob = context.getBlobStore().getBlob(containerName, key, startAt(5)).get(30,
// TimeUnit.SECONDS); // TimeUnit.SECONDS);
// assertEquals(BlobStoreUtils.getContentAsStringAndClose(object), TEST_STRING.substring(5, // assertEquals(BlobStoreUtils.getContentAsStringAndClose(blob), TEST_STRING.substring(5,
// TEST_STRING.length())); // TEST_STRING.length()));
// assertEquals(object.getContentLength(), TEST_STRING.length() - 5); // assertEquals(blob.getContentLength(), TEST_STRING.length() - 5);
// assertEquals(object.getMetadata().getSize(), TEST_STRING.length()); // assertEquals(blob.getMetadata().getSize(), TEST_STRING.length());
// } finally { // } finally {
// returnContainer(containerName); // returnContainer(containerName);
// } // }
@ -339,7 +335,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
} }
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
public void objectNotFound() throws InterruptedException { public void blobNotFound() throws InterruptedException {
String containerName = getContainerName(); String containerName = getContainerName();
String key = "test"; String key = "test";
try { try {
@ -407,17 +403,17 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
@Test(groups = { "integration", "live" }, dataProvider = "putTests") @Test(groups = { "integration", "live" }, dataProvider = "putTests")
public void testPutObject(String key, String type, Object content, Object realObject) public void testPutObject(String key, String type, Object content, Object realObject)
throws InterruptedException, IOException { throws InterruptedException, IOException {
Blob object = context.getBlobStore().newBlob(key); Blob blob = context.getBlobStore().newBlob(key);
object.getMetadata().setContentType(type); blob.getMetadata().setContentType(type);
object.setPayload(Payloads.newPayload(content)); blob.setPayload(Payloads.newPayload(content));
if (content instanceof InputStream) { if (content instanceof InputStream) {
object.generateMD5(); context.utils().encryption().generateMD5BufferingIfNotRepeatable(blob);
} }
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
assertNotNull(context.getBlobStore().putBlob(containerName, object)); assertNotNull(context.getBlobStore().putBlob(containerName, blob));
object = context.getBlobStore().getBlob(containerName, object.getMetadata().getName()); blob = context.getBlobStore().getBlob(containerName, blob.getMetadata().getName());
String returnedString = getContentAsStringOrNullAndClose(object); String returnedString = getContentAsStringOrNullAndClose(blob);
assertEquals(returnedString, realObject); assertEquals(returnedString, realObject);
PageSet<? extends StorageMetadata> set = context.getBlobStore().list(containerName); PageSet<? extends StorageMetadata> set = context.getBlobStore().list(containerName);
assert set.size() == 1 : set; assert set.size() == 1 : set;
@ -430,20 +426,20 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
public void testMetadata() throws InterruptedException { public void testMetadata() throws InterruptedException {
String key = "hello"; String key = "hello";
Blob object = context.getBlobStore().newBlob(key); Blob blob = context.getBlobStore().newBlob(key);
object.setPayload(TEST_STRING); blob.setPayload(TEST_STRING);
object.getMetadata().setContentType(MediaType.TEXT_PLAIN); blob.getMetadata().setContentType(MediaType.TEXT_PLAIN);
object.getMetadata().setSize(new Long(TEST_STRING.length())); blob.getMetadata().setSize(new Long(TEST_STRING.length()));
// NOTE all metadata in jclouds comes out as lowercase, in an effort to normalize the // NOTE all metadata in jclouds comes out as lowercase, in an effort to normalize the
// providers. // providers.
object.getMetadata().getUserMetadata().put("Adrian", "powderpuff"); blob.getMetadata().getUserMetadata().put("Adrian", "powderpuff");
object.getMetadata().setContentMD5( blob.getMetadata().setContentMD5(
new JCEEncryptionService().md5(Utils.toInputStream(TEST_STRING))); new JCEEncryptionService().md5(Utils.toInputStream(TEST_STRING)));
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
assertNull(context.getBlobStore().blobMetadata(containerName, "powderpuff")); assertNull(context.getBlobStore().blobMetadata(containerName, "powderpuff"));
addBlobToContainer(containerName, object); addBlobToContainer(containerName, blob);
Blob newObject = validateContent(containerName, key); Blob newObject = validateContent(containerName, key);
BlobMetadata metadata = newObject.getMetadata(); BlobMetadata metadata = newObject.getMetadata();
@ -452,10 +448,10 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
validateMetadata(context.getBlobStore().blobMetadata(containerName, key)); validateMetadata(context.getBlobStore().blobMetadata(containerName, key));
// write 2 items with the same key to ensure that provider doesn't accept dupes // write 2 items with the same key to ensure that provider doesn't accept dupes
object.getMetadata().getUserMetadata().put("Adrian", "wonderpuff"); blob.getMetadata().getUserMetadata().put("Adrian", "wonderpuff");
object.getMetadata().getUserMetadata().put("Adrian", "powderpuff"); blob.getMetadata().getUserMetadata().put("Adrian", "powderpuff");
addBlobToContainer(containerName, object); addBlobToContainer(containerName, blob);
validateMetadata(context.getBlobStore().blobMetadata(containerName, key)); validateMetadata(context.getBlobStore().blobMetadata(containerName, key));
} finally { } finally {

View File

@ -59,15 +59,15 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
putFiveStrings(map); putFiveStrings(map);
putFiveStringsUnderPath(map); putFiveStringsUnderPath(map);
Collection<Blob> values = map.values(); Collection<Blob> blobs = map.values();
assertConsistencyAwareMapSize(map, 5); assertConsistencyAwareMapSize(map, 5);
Set<String> valuesAsString = new HashSet<String>(); Set<String> blobsAsString = new HashSet<String>();
for (Blob object : values) { for (Blob blob : blobs) {
valuesAsString.add(getContentAsStringOrNullAndClose(object)); blobsAsString.add(getContentAsStringOrNullAndClose(blob));
} }
valuesAsString.removeAll(fiveStrings.values()); blobsAsString.removeAll(fiveStrings.values());
assert valuesAsString.size() == 0 : valuesAsString.size() + ": " + values + ": " assert blobsAsString.size() == 0 : blobsAsString.size() + ": " + blobs + ": "
+ valuesAsString; + blobsAsString;
} finally { } finally {
returnContainer(bucketName); returnContainer(bucketName);
} }
@ -90,12 +90,12 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
} }
private void assertConsistencyAwareContentEquals(final Map<String, Blob> map, final String key, private void assertConsistencyAwareContentEquals(final Map<String, Blob> map, final String key,
final String value) throws InterruptedException { final String blob) throws InterruptedException {
assertConsistencyAware(new Runnable() { assertConsistencyAware(new Runnable() {
public void run() { public void run() {
Blob old = map.remove(key); Blob old = map.remove(key);
try { try {
assertEquals(getContentAsStringOrNullAndClose(old), value); assertEquals(getContentAsStringOrNullAndClose(old), blob);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -116,16 +116,16 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
for (Entry<String, Blob> entry : entries) { for (Entry<String, Blob> entry : entries) {
assertEquals(fiveStrings.get(entry.getKey()), getContentAsStringOrNullAndClose(entry assertEquals(fiveStrings.get(entry.getKey()), getContentAsStringOrNullAndClose(entry
.getValue())); .getValue()));
Blob value = entry.getValue(); Blob blob = entry.getValue();
value.setPayload(""); blob.setPayload("");
value.generateMD5(); context.utils().encryption().generateMD5BufferingIfNotRepeatable(blob);
entry.setValue(value); entry.setValue(blob);
} }
assertConsistencyAware(new Runnable() { assertConsistencyAware(new Runnable() {
public void run() { public void run() {
for (Blob value : map.values()) { for (Blob blob : map.values()) {
try { try {
assertEquals(getContentAsStringOrNullAndClose(value), ""); assertEquals(getContentAsStringOrNullAndClose(blob), "");
} catch (IOException e) { } catch (IOException e) {
Throwables.propagate(e); Throwables.propagate(e);
} }
@ -144,10 +144,10 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
try { try {
Map<String, Blob> map = createMap(context, bucketName); Map<String, Blob> map = createMap(context, bucketName);
putStringWithMD5(map, "one", "apple"); putStringWithMD5(map, "one", "apple");
Blob object = context.getBlobStore().newBlob("one"); Blob blob = context.getBlobStore().newBlob("one");
object.setPayload("apple"); blob.setPayload("apple");
object.generateMD5(); context.utils().encryption().generateMD5BufferingIfNotRepeatable(blob);
assertConsistencyAwareContainsValue(map, object); assertConsistencyAwareContainsValue(map, blob);
} finally { } finally {
returnContainer(bucketName); returnContainer(bucketName);
} }
@ -172,14 +172,14 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
String bucketName = getContainerName(); String bucketName = getContainerName();
try { try {
Map<String, Blob> map = createMap(context, bucketName); Map<String, Blob> map = createMap(context, bucketName);
Blob object = context.getBlobStore().newBlob("one"); Blob blob = context.getBlobStore().newBlob("one");
object.setPayload(Utils.toInputStream("apple")); blob.setPayload(Utils.toInputStream("apple"));
object.generateMD5(); context.utils().encryption().generateMD5BufferingIfNotRepeatable(blob);
Blob old = map.put(object.getMetadata().getName(), object); Blob old = map.put(blob.getMetadata().getName(), blob);
getOneReturnsAppleAndOldValueIsNull(map, old); getOneReturnsAppleAndOldValueIsNull(map, old);
object.setPayload(Utils.toInputStream("bear")); blob.setPayload(Utils.toInputStream("bear"));
object.generateMD5(); context.utils().encryption().generateMD5BufferingIfNotRepeatable(blob);
Blob apple = map.put(object.getMetadata().getName(), object); Blob apple = map.put(blob.getMetadata().getName(), blob);
getOneReturnsBearAndOldValueIsApple(map, apple); getOneReturnsBearAndOldValueIsApple(map, apple);
} finally { } finally {
returnContainer(bucketName); returnContainer(bucketName);
@ -193,10 +193,10 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
Map<String, Blob> map = createMap(context, bucketName); Map<String, Blob> map = createMap(context, bucketName);
Map<String, Blob> newMap = new HashMap<String, Blob>(); Map<String, Blob> newMap = new HashMap<String, Blob>();
for (String key : fiveInputs.keySet()) { for (String key : fiveInputs.keySet()) {
Blob object = context.getBlobStore().newBlob(key); Blob blob = context.getBlobStore().newBlob(key);
object.setPayload(fiveInputs.get(key)); blob.setPayload(fiveInputs.get(key));
object.getPayload().setContentLength((long) fiveBytes.get(key).length); blob.getPayload().setContentLength((long) fiveBytes.get(key).length);
newMap.put(key, object); newMap.put(key, blob);
} }
map.putAll(newMap); map.putAll(newMap);
assertConsistencyAwareMapSize(map, 5); assertConsistencyAwareMapSize(map, 5);
@ -222,9 +222,9 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
Map<String, Blob> newMap = new HashMap<String, Blob>(); Map<String, Blob> newMap = new HashMap<String, Blob>();
for (String key : keySet) { for (String key : keySet) {
Blob object = context.getBlobStore().newBlob(key); Blob blob = context.getBlobStore().newBlob(key);
object.setPayload(key); blob.setPayload(key);
newMap.put(key, object); newMap.put(key, blob);
} }
map.putAll(newMap); map.putAll(newMap);
newMap.clear(); newMap.clear();
@ -239,19 +239,19 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
} }
@Override @Override
protected void putStringWithMD5(Map<String, Blob> map, String key, String value) { protected void putStringWithMD5(Map<String, Blob> map, String key, String text) {
Blob object = context.getBlobStore().newBlob(key); Blob blob = context.getBlobStore().newBlob(key);
object.setPayload(value); blob.setPayload(text);
object.generateMD5(); context.utils().encryption().generateMD5BufferingIfNotRepeatable(blob);
map.put(key, object); map.put(key, blob);
} }
protected void putFiveStrings(Map<String, Blob> map) { protected void putFiveStrings(Map<String, Blob> map) {
Map<String, Blob> newMap = new HashMap<String, Blob>(); Map<String, Blob> newMap = new HashMap<String, Blob>();
for (Map.Entry<String, String> entry : fiveStrings.entrySet()) { for (Map.Entry<String, String> entry : fiveStrings.entrySet()) {
Blob object = context.getBlobStore().newBlob(entry.getKey()); Blob blob = context.getBlobStore().newBlob(entry.getKey());
object.setPayload(entry.getValue()); blob.setPayload(entry.getValue());
newMap.put(entry.getKey(), object); newMap.put(entry.getKey(), blob);
} }
map.putAll(newMap); map.putAll(newMap);
} }
@ -259,9 +259,9 @@ public abstract class BaseBlobMapIntegrationTest extends BaseMapIntegrationTest<
protected void putFiveStringsUnderPath(Map<String, Blob> map) { protected void putFiveStringsUnderPath(Map<String, Blob> map) {
Map<String, Blob> newMap = new HashMap<String, Blob>(); Map<String, Blob> newMap = new HashMap<String, Blob>();
for (Map.Entry<String, String> entry : fiveStringsUnderPath.entrySet()) { for (Map.Entry<String, String> entry : fiveStringsUnderPath.entrySet()) {
Blob object = context.getBlobStore().newBlob(entry.getKey()); Blob blob = context.getBlobStore().newBlob(entry.getKey());
object.setPayload(entry.getValue()); blob.setPayload(entry.getValue());
newMap.put(entry.getKey(), object); newMap.put(entry.getKey(), blob);
} }
map.putAll(newMap); map.putAll(newMap);
} }

View File

@ -25,6 +25,7 @@ import java.security.Key;
import org.jclouds.encryption.internal.JCEEncryptionService; import org.jclouds.encryption.internal.JCEEncryptionService;
import org.jclouds.http.Payload; import org.jclouds.http.Payload;
import org.jclouds.http.PayloadEnclosing;
import org.jclouds.http.payloads.ByteArrayPayload; import org.jclouds.http.payloads.ByteArrayPayload;
import com.google.inject.ImplementedBy; import com.google.inject.ImplementedBy;
@ -55,6 +56,15 @@ public interface EncryptionService {
byte[] md5(InputStream toEncode); byte[] md5(InputStream toEncode);
/**
* generate an MD5 Hash for the current data.
* <p/>
* <h2>Note</h2>
* <p/>
* If this is an InputStream, it will be converted to a byte array first.
*/
<T extends PayloadEnclosing> T generateMD5BufferingIfNotRepeatable(T payloadEnclosing);
Payload generateMD5BufferingIfNotRepeatable(Payload in); Payload generateMD5BufferingIfNotRepeatable(Payload in);
ByteArrayPayload generatePayloadWithMD5For(InputStream toEncode); ByteArrayPayload generatePayloadWithMD5For(InputStream toEncode);

View File

@ -19,11 +19,13 @@
package org.jclouds.encryption.internal; package org.jclouds.encryption.internal;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import org.jclouds.encryption.EncryptionService; import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.Payload; import org.jclouds.http.Payload;
import org.jclouds.http.PayloadEnclosing;
/** /**
* *
@ -76,4 +78,16 @@ public abstract class BaseEncryptionService implements EncryptionService {
return payload; return payload;
} }
/**
* {@inheritDoc}
*/
@Override
public <T extends PayloadEnclosing> T generateMD5BufferingIfNotRepeatable(T payloadEnclosing) {
checkState(payloadEnclosing != null, "payloadEnclosing");
Payload newPayload = generateMD5BufferingIfNotRepeatable(payloadEnclosing.getPayload());
if (newPayload != payloadEnclosing.getPayload())
payloadEnclosing.setPayload(newPayload);
return payloadEnclosing;
}
} }

View File

@ -20,16 +20,18 @@ package org.jclouds.http;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.io.Closeables.closeQuietly;
import static com.google.inject.internal.Lists.newArrayList; import static com.google.inject.internal.Lists.newArrayList;
import java.io.File;
import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.List; import java.util.List;
import org.jclouds.http.internal.PayloadEnclosingImpl;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.inject.internal.Nullable; import com.google.inject.internal.Nullable;
/** /**
@ -37,7 +39,7 @@ import com.google.inject.internal.Nullable;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class HttpRequest extends HttpMessage { public class HttpRequest extends PayloadEnclosingImpl implements PayloadEnclosing {
private List<HttpRequestFilter> requestFilters = newArrayList(); private List<HttpRequestFilter> requestFilters = newArrayList();
private String method; private String method;
@ -45,6 +47,26 @@ public class HttpRequest extends HttpMessage {
private Payload payload; private Payload payload;
private char[] skips; private char[] skips;
/**
* synchronized as there is no concurrent version. Headers may change in flight due to redirects.
*/
private Multimap<String, String> headers = Multimaps.synchronizedMultimap(LinkedHashMultimap
.<String, String> create());
public Multimap<String, String> getHeaders() {
return headers;
}
/**
* try to get the value, then try as lowercase.
*/
public String getFirstHeaderOrNull(String string) {
Collection<String> values = headers.get(string);
if (values.size() == 0)
values = headers.get(string.toLowerCase());
return (values.size() >= 1) ? values.iterator().next() : null;
}
/** /**
* *
* @param endpoint * @param endpoint
@ -104,31 +126,6 @@ public class HttpRequest extends HttpMessage {
return method; return method;
} }
public Payload getPayload() {
return payload;
}
public void setPayload(Payload data) {
closeContentIfPresent();
this.payload = checkNotNull(data, "data");
}
public void setPayload(InputStream data) {
setPayload(Payloads.newPayload(checkNotNull(data, "data")));
}
public void setPayload(byte[] data) {
setPayload(Payloads.newPayload(checkNotNull(data, "data")));
}
public void setPayload(String data) {
setPayload(Payloads.newPayload(checkNotNull(data, "data")));
}
public void setPayload(File data) {
setPayload(Payloads.newPayload(checkNotNull(data, "data")));
}
/** /**
* characters to skip encoding on. * characters to skip encoding on.
*/ */
@ -160,18 +157,6 @@ public class HttpRequest extends HttpMessage {
this.endpoint = endpoint; this.endpoint = endpoint;
} }
@Override
protected void finalize() throws Throwable {
closeContentIfPresent();
super.finalize();
}
private void closeContentIfPresent() {
if (getPayload() != null && getPayload().getInput() != null) {
closeQuietly(getPayload().getInput());
}
}
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;

View File

@ -47,13 +47,4 @@ public interface PayloadEnclosing {
Payload getPayload(); Payload getPayload();
/**
* generate an MD5 Hash for the current data.
* <p/>
* <h2>Note</h2>
* <p/>
* If this is an InputStream, it will be converted to a byte array first.
*/
void generateMD5();
} }

View File

@ -19,7 +19,6 @@
package org.jclouds.http.internal; package org.jclouds.http.internal;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.io.Closeables.closeQuietly; import static com.google.common.io.Closeables.closeQuietly;
import static org.jclouds.http.Payloads.newPayload; import static org.jclouds.http.Payloads.newPayload;
@ -28,7 +27,6 @@ import java.io.InputStream;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.Payload; import org.jclouds.http.Payload;
import org.jclouds.http.PayloadEnclosing; import org.jclouds.http.PayloadEnclosing;
@ -37,29 +35,16 @@ import org.jclouds.http.PayloadEnclosing;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class PayloadEnclosingImpl implements PayloadEnclosing { public class PayloadEnclosingImpl implements PayloadEnclosing {
private final EncryptionService encryptionService;
protected Payload payload; protected Payload payload;
public PayloadEnclosingImpl(EncryptionService encryptionService, @Nullable Payload payload) { public PayloadEnclosingImpl() {
this.encryptionService = encryptionService; this(null);
}
public PayloadEnclosingImpl(@Nullable Payload payload) {
this.payload = payload; this.payload = payload;
} }
public PayloadEnclosingImpl(EncryptionService encryptionService) {
this(encryptionService, null);
}
/**
* {@inheritDoc}
*/
@Override
public void generateMD5() {
checkState(payload != null, "payload");
Payload newPayload = encryptionService.generateMD5BufferingIfNotRepeatable(payload);
if (newPayload != payload)
setPayload(newPayload);
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@ -98,6 +83,7 @@ public class PayloadEnclosingImpl implements PayloadEnclosing {
*/ */
@Override @Override
public void setPayload(String data) { public void setPayload(String data) {
closeContentIfPresent();
setPayload(newPayload(checkNotNull(data, "data"))); setPayload(newPayload(checkNotNull(data, "data")));
} }
@ -140,4 +126,9 @@ public class PayloadEnclosingImpl implements PayloadEnclosing {
return true; return true;
} }
@Override
protected void finalize() throws Throwable {
closeContentIfPresent();
super.finalize();
}
} }

View File

@ -614,10 +614,11 @@ public class RestAnnotationProcessorTest {
assertEquals(request.getPayload().getRawContent(), "\"data\""); assertEquals(request.getPayload().getRawContent(), "\"data\"");
} }
public void testCreatePostWithPathRequest() throws SecurityException, NoSuchMethodException, IOException { public void testCreatePostWithPathRequest() throws SecurityException, NoSuchMethodException,
IOException {
Method method = TestPost.class.getMethod("postWithPath", String.class, MapBinder.class); Method method = TestPost.class.getMethod("postWithPath", String.class, MapBinder.class);
HttpRequest request = factory(TestPost.class).createRequest(method, HttpRequest request = factory(TestPost.class).createRequest(method, "data",
"data", new org.jclouds.rest.MapBinder() { new org.jclouds.rest.MapBinder() {
public void bindToRequest(HttpRequest request, Map<String, String> postParams) { public void bindToRequest(HttpRequest request, Map<String, String> postParams) {
request.setPayload(postParams.get("fooble")); request.setPayload(postParams.get("fooble"));
} }
@ -625,7 +626,7 @@ public class RestAnnotationProcessorTest {
public void bindToRequest(HttpRequest request, Object toBind) { public void bindToRequest(HttpRequest request, Object toBind) {
throw new RuntimeException("this shouldn't be used in POST"); throw new RuntimeException("this shouldn't be used in POST");
} }
} ); });
assertRequestLineEquals(request, "POST http://localhost:9999/data HTTP/1.1"); assertRequestLineEquals(request, "POST http://localhost:9999/data HTTP/1.1");
assertHeadersEqual(request, "Content-Length: 4\nContent-Type: application/unknown\n"); assertHeadersEqual(request, "Content-Length: 4\nContent-Type: application/unknown\n");
assertPayloadEquals(request, "data"); assertPayloadEquals(request, "data");
@ -1405,10 +1406,8 @@ public class RestAnnotationProcessorTest {
public void testPutPayloadEnclosing() throws SecurityException, NoSuchMethodException, public void testPutPayloadEnclosing() throws SecurityException, NoSuchMethodException,
IOException { IOException {
Method method = TestTransformers.class.getMethod("put", PayloadEnclosing.class); Method method = TestTransformers.class.getMethod("put", PayloadEnclosing.class);
HttpRequest request = factory(TestQuery.class).createRequest( HttpRequest request = factory(TestQuery.class).createRequest(method,
method, new PayloadEnclosingImpl(newStringPayload("whoops")));
new PayloadEnclosingImpl(injector.getInstance(EncryptionService.class),
newStringPayload("whoops")));
assertRequestLineEquals(request, "PUT http://localhost:9999?x-ms-version=2009-07-17 HTTP/1.1"); assertRequestLineEquals(request, "PUT http://localhost:9999?x-ms-version=2009-07-17 HTTP/1.1");
assertHeadersEqual(request, "Content-Length: 6\nContent-Type: application/unknown\n"); assertHeadersEqual(request, "Content-Length: 6\nContent-Type: application/unknown\n");
assertPayloadEquals(request, "whoops"); assertPayloadEquals(request, "whoops");
@ -1417,10 +1416,10 @@ public class RestAnnotationProcessorTest {
public void testPutPayloadEnclosingGenerateMD5() throws SecurityException, public void testPutPayloadEnclosingGenerateMD5() throws SecurityException,
NoSuchMethodException, IOException { NoSuchMethodException, IOException {
Method method = TestTransformers.class.getMethod("put", PayloadEnclosing.class); Method method = TestTransformers.class.getMethod("put", PayloadEnclosing.class);
PayloadEnclosing payloadEnclosing = new PayloadEnclosingImpl(injector PayloadEnclosing payloadEnclosing = new PayloadEnclosingImpl(newStringPayload("whoops"));
.getInstance(EncryptionService.class), newStringPayload("whoops"));
payloadEnclosing.generateMD5(); injector.getInstance(EncryptionService.class).generateMD5BufferingIfNotRepeatable(
payloadEnclosing);
HttpRequest request = factory(TestQuery.class).createRequest(method, payloadEnclosing); HttpRequest request = factory(TestQuery.class).createRequest(method, payloadEnclosing);
assertRequestLineEquals(request, "PUT http://localhost:9999?x-ms-version=2009-07-17 HTTP/1.1"); assertRequestLineEquals(request, "PUT http://localhost:9999?x-ms-version=2009-07-17 HTTP/1.1");
assertHeadersEqual(request, assertHeadersEqual(request,
@ -1432,11 +1431,11 @@ public class RestAnnotationProcessorTest {
public void testPutInputStreamPayloadEnclosingGenerateMD5() throws SecurityException, public void testPutInputStreamPayloadEnclosingGenerateMD5() throws SecurityException,
NoSuchMethodException, IOException { NoSuchMethodException, IOException {
Method method = TestTransformers.class.getMethod("put", PayloadEnclosing.class); Method method = TestTransformers.class.getMethod("put", PayloadEnclosing.class);
PayloadEnclosing payloadEnclosing = new PayloadEnclosingImpl(injector PayloadEnclosing payloadEnclosing = new PayloadEnclosingImpl(
.getInstance(EncryptionService.class),
newInputStreamPayload(toInputStream("whoops"))); newInputStreamPayload(toInputStream("whoops")));
payloadEnclosing.generateMD5(); injector.getInstance(EncryptionService.class).generateMD5BufferingIfNotRepeatable(
payloadEnclosing);
HttpRequest request = factory(TestQuery.class).createRequest(method, payloadEnclosing); HttpRequest request = factory(TestQuery.class).createRequest(method, payloadEnclosing);
assertRequestLineEquals(request, "PUT http://localhost:9999?x-ms-version=2009-07-17 HTTP/1.1"); assertRequestLineEquals(request, "PUT http://localhost:9999?x-ms-version=2009-07-17 HTTP/1.1");
assertHeadersEqual(request, assertHeadersEqual(request,

View File

@ -41,7 +41,7 @@ public class PCSFileImpl extends PayloadEnclosingImpl implements PCSFile, Compar
@Inject @Inject
public PCSFileImpl(MutableFileInfo metadata) { public PCSFileImpl(MutableFileInfo metadata) {
super(null);// no MD5 support super();// no MD5 support
this.metadata = metadata; this.metadata = metadata;
} }

View File

@ -78,7 +78,7 @@ public class SDNClientLiveTest {
Blob blob = connection.newBlob(); Blob blob = connection.newBlob();
blob.getMetadata().setName("test.txt"); blob.getMetadata().setName("test.txt");
blob.setPayload("value"); blob.setPayload("value");
blob.generateMD5(); context.utils().encryption().generateMD5BufferingIfNotRepeatable(blob);
byte[] md5 = blob.getMetadata().getContentMD5(); byte[] md5 = blob.getMetadata().getContentMD5();
connection.upload(uploadInfo.getHost(), uploadInfo.getToken(), containerName, blob); connection.upload(uploadInfo.getHost(), uploadInfo.getToken(), containerName, blob);

View File

@ -22,7 +22,6 @@ import javax.inject.Inject;
import javax.inject.Provider; import javax.inject.Provider;
import org.jclouds.blobstore.config.BlobStoreObjectModule; import org.jclouds.blobstore.config.BlobStoreObjectModule;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.rackspace.cloudfiles.domain.CFObject; import org.jclouds.rackspace.cloudfiles.domain.CFObject;
import org.jclouds.rackspace.cloudfiles.domain.MutableObjectInfoWithMetadata; import org.jclouds.rackspace.cloudfiles.domain.MutableObjectInfoWithMetadata;
import org.jclouds.rackspace.cloudfiles.domain.internal.CFObjectImpl; import org.jclouds.rackspace.cloudfiles.domain.internal.CFObjectImpl;
@ -50,14 +49,11 @@ public class CFObjectModule extends AbstractModule {
} }
private static class CFObjectFactory implements CFObject.Factory { private static class CFObjectFactory implements CFObject.Factory {
@Inject
EncryptionService encryptionService;
@Inject @Inject
Provider<MutableObjectInfoWithMetadata> metadataProvider; Provider<MutableObjectInfoWithMetadata> metadataProvider;
public CFObject create(MutableObjectInfoWithMetadata metadata) { public CFObject create(MutableObjectInfoWithMetadata metadata) {
return new CFObjectImpl(encryptionService, metadata != null ? metadata : metadataProvider return new CFObjectImpl(metadata != null ? metadata : metadataProvider.get());
.get());
} }
} }

View File

@ -22,7 +22,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject; import javax.inject.Inject;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.Payload; import org.jclouds.http.Payload;
import org.jclouds.http.PayloadEnclosing; import org.jclouds.http.PayloadEnclosing;
import org.jclouds.http.internal.PayloadEnclosingImpl; import org.jclouds.http.internal.PayloadEnclosingImpl;
@ -45,8 +44,8 @@ public class CFObjectImpl extends PayloadEnclosingImpl implements CFObject, Comp
private Multimap<String, String> allHeaders = LinkedHashMultimap.create(); private Multimap<String, String> allHeaders = LinkedHashMultimap.create();
@Inject @Inject
public CFObjectImpl(EncryptionService encryptionService, MutableObjectInfoWithMetadata info) { public CFObjectImpl(MutableObjectInfoWithMetadata info) {
super(encryptionService); super();
this.info = linkMetadataToThis(info); this.info = linkMetadataToThis(info);
this._info = this.info.getDelegate(); this._info = this.info.getDelegate();

View File

@ -386,7 +386,7 @@ public class CloudFilesClientLiveTest extends BaseBlobStoreIntegrationTest {
CFObject object = getApi().newCFObject(); CFObject object = getApi().newCFObject();
object.getInfo().setName(key); object.getInfo().setName(key);
object.setPayload(data); object.setPayload(data);
object.generateMD5(); context.utils().encryption().generateMD5BufferingIfNotRepeatable(object);
object.getInfo().setContentType("text/plain"); object.getInfo().setContentType("text/plain");
object.getInfo().getMetadata().put("Metadata", "metadata-value"); object.getInfo().getMetadata().put("Metadata", "metadata-value");
return object; return object;

View File

@ -102,7 +102,7 @@ public class BlobStoreFileObject extends AbstractFileObject {
protected void onClose() throws IOException { protected void onClose() throws IOException {
try { try {
blob.setPayload(file); blob.setPayload(file);
blob.generateMD5(); context.getContext().utils().encryption().generateMD5BufferingIfNotRepeatable(blob);
logger.info(String.format(">> put: %s/%s %d bytes", getContainer(), logger.info(String.format(">> put: %s/%s %d bytes", getContainer(),
getNameTrimLeadingSlashes(), blob.getPayload().getContentLength())); getNameTrimLeadingSlashes(), blob.getPayload().getContentLength()));
String tag = context.putBlob(getContainer(), blob); String tag = context.putBlob(getContainer(), blob);