Issue 352: refactored request signing

This commit is contained in:
Adrian Cole 2010-09-13 18:24:16 -07:00
parent d276b70162
commit f068a06354
51 changed files with 1234 additions and 655 deletions

View File

@ -51,7 +51,6 @@ import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore; import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata; import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.concurrent.Futures; import org.jclouds.concurrent.Futures;
@ -86,9 +85,8 @@ public class AtmosAsyncBlobStore extends BaseAsyncBlobStore {
ObjectToBlob object2Blob, ObjectToBlobMetadata object2BlobMd, BlobToObject blob2Object, ObjectToBlob object2Blob, ObjectToBlobMetadata object2BlobMd, BlobToObject blob2Object,
BlobStoreListOptionsToListOptions container2ContainerListOptions, BlobStoreListOptionsToListOptions container2ContainerListOptions,
DirectoryEntryListToResourceMetadataList container2ResourceList, Crypto crypto, DirectoryEntryListToResourceMetadataList container2ResourceList, Crypto crypto,
BlobToHttpGetOptions blob2ObjectGetOptions, Provider<FetchBlobMetadata> fetchBlobMetadataProvider, BlobToHttpGetOptions blob2ObjectGetOptions, Provider<FetchBlobMetadata> fetchBlobMetadataProvider) {
SignRequestForBlobStrategy signRequestForBlob) { super(context, blobUtils, service, defaultLocation, locations);
super(context, blobUtils, service, defaultLocation, locations, signRequestForBlob);
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions"); this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
this.sync = checkNotNull(sync, "sync"); this.sync = checkNotNull(sync, "sync");
this.async = checkNotNull(async, "async"); this.async = checkNotNull(async, "async");

View File

@ -0,0 +1,81 @@
/**
*
* Copyright (C) 2010 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.atmosonline.saas.blobstore;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.blobstore.util.BlobStoreUtils.cleanRequest;
import java.lang.reflect.Method;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.atmosonline.saas.AtmosStorageAsyncClient;
import org.jclouds.atmosonline.saas.blobstore.functions.BlobToObject;
import org.jclouds.atmosonline.saas.domain.AtmosObject;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.options.GetOptions;
import org.jclouds.rest.internal.RestAnnotationProcessor;
/**
*
* @author Adrian Cole
*/
@Singleton
public class AtmosBlobRequestSigner implements BlobRequestSigner {
private final RestAnnotationProcessor<AtmosStorageAsyncClient> processor;
private final BlobToObject blobToObject;
private final Method getMethod;
private final Method deleteMethod;
private final Method createMethod;
@Inject
public AtmosBlobRequestSigner(RestAnnotationProcessor<AtmosStorageAsyncClient> processor, BlobToObject blobToObject)
throws SecurityException, NoSuchMethodException {
this.processor = checkNotNull(processor, "processor");
this.blobToObject = checkNotNull(blobToObject, "blobToObject");
this.getMethod = AtmosStorageAsyncClient.class.getMethod("readFile", String.class, GetOptions[].class);
this.deleteMethod = AtmosStorageAsyncClient.class.getMethod("deletePath", String.class);
this.createMethod = AtmosStorageAsyncClient.class.getMethod("createFile", String.class, AtmosObject.class);
}
@Override
public HttpRequest signGetBlob(String container, String name) {
return cleanRequest(processor.createRequest(getMethod, getPath(container, name)));
}
@Override
public HttpRequest signPutBlob(String container, Blob blob) {
return cleanRequest(processor.createRequest(createMethod, container, blobToObject.apply(blob)));
}
@Override
public HttpRequest signRemoveBlob(String container, String name) {
return cleanRequest(processor.createRequest(deleteMethod, getPath(container, name)));
}
private String getPath(String container, String name) {
return checkNotNull(container, "container") + "/" + checkNotNull(name, "name");
}
}

View File

@ -43,7 +43,6 @@ import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseBlobStore; import org.jclouds.blobstore.internal.BaseBlobStore;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata; import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.crypto.Crypto; import org.jclouds.crypto.Crypto;
@ -73,9 +72,8 @@ public class AtmosBlobStore extends BaseBlobStore {
ObjectToBlobMetadata object2BlobMd, BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd, BlobToObject blob2Object,
BlobStoreListOptionsToListOptions container2ContainerListOptions, BlobStoreListOptionsToListOptions container2ContainerListOptions,
DirectoryEntryListToResourceMetadataList container2ResourceList, Crypto crypto, DirectoryEntryListToResourceMetadataList container2ResourceList, Crypto crypto,
BlobToHttpGetOptions blob2ObjectGetOptions, Provider<FetchBlobMetadata> fetchBlobMetadataProvider, BlobToHttpGetOptions blob2ObjectGetOptions, Provider<FetchBlobMetadata> fetchBlobMetadataProvider) {
SignRequestForBlobStrategy signRequestForBlob) { super(context, blobUtils, defaultLocation, locations);
super(context, blobUtils, defaultLocation, locations, signRequestForBlob);
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions"); this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
this.sync = checkNotNull(sync, "sync"); this.sync = checkNotNull(sync, "sync");
this.container2ContainerListOptions = checkNotNull(container2ContainerListOptions, this.container2ContainerListOptions = checkNotNull(container2ContainerListOptions,

View File

@ -26,17 +26,17 @@ import javax.inject.Singleton;
import org.jclouds.atmosonline.saas.AtmosStorageAsyncClient; import org.jclouds.atmosonline.saas.AtmosStorageAsyncClient;
import org.jclouds.atmosonline.saas.AtmosStorageClient; import org.jclouds.atmosonline.saas.AtmosStorageClient;
import org.jclouds.atmosonline.saas.blobstore.AtmosAsyncBlobStore; import org.jclouds.atmosonline.saas.blobstore.AtmosAsyncBlobStore;
import org.jclouds.atmosonline.saas.blobstore.AtmosBlobRequestSigner;
import org.jclouds.atmosonline.saas.blobstore.AtmosBlobStore; import org.jclouds.atmosonline.saas.blobstore.AtmosBlobStore;
import org.jclouds.atmosonline.saas.blobstore.strategy.FindMD5InUserMetadata; import org.jclouds.atmosonline.saas.blobstore.strategy.FindMD5InUserMetadata;
import org.jclouds.atmosonline.saas.blobstore.strategy.SignReadFile;
import org.jclouds.blobstore.AsyncBlobStore; import org.jclouds.blobstore.AsyncBlobStore;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.attr.ConsistencyModel; import org.jclouds.blobstore.attr.ConsistencyModel;
import org.jclouds.blobstore.config.BlobStoreMapModule; import org.jclouds.blobstore.config.BlobStoreMapModule;
import org.jclouds.blobstore.internal.BlobStoreContextImpl; import org.jclouds.blobstore.internal.BlobStoreContextImpl;
import org.jclouds.blobstore.strategy.ContainsValueInListStrategy; import org.jclouds.blobstore.strategy.ContainsValueInListStrategy;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope; import org.jclouds.domain.LocationScope;
import org.jclouds.domain.internal.LocationImpl; import org.jclouds.domain.internal.LocationImpl;
@ -67,7 +67,7 @@ public class AtmosBlobStoreContextModule extends AbstractModule {
new TypeLiteral<BlobStoreContextImpl<AtmosStorageClient, AtmosStorageAsyncClient>>() { new TypeLiteral<BlobStoreContextImpl<AtmosStorageClient, AtmosStorageAsyncClient>>() {
}).in(Scopes.SINGLETON); }).in(Scopes.SINGLETON);
bind(ContainsValueInListStrategy.class).to(FindMD5InUserMetadata.class); bind(ContainsValueInListStrategy.class).to(FindMD5InUserMetadata.class);
bind(SignRequestForBlobStrategy.class).to(SignReadFile.class); bind(BlobRequestSigner.class).to(AtmosBlobRequestSigner.class);
} }
@Provides @Provides

View File

@ -1,66 +0,0 @@
/**
*
* Copyright (C) 2010 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.atmosonline.saas.blobstore.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import java.lang.reflect.Method;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.atmosonline.saas.AtmosStorageAsyncClient;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.options.GetOptions;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import com.google.common.collect.ImmutableMultimap;
/**
*
* @author Adrian Cole
*/
@Singleton
public class SignReadFile implements SignRequestForBlobStrategy {
private final RestAnnotationProcessor<AtmosStorageAsyncClient> processor;
private final Method method;
@Inject
public SignReadFile(RestAnnotationProcessor<AtmosStorageAsyncClient> processor) throws SecurityException,
NoSuchMethodException {
this.processor = checkNotNull(processor, "processor");
this.method = AtmosStorageAsyncClient.class.getMethod("readFile", String.class, GetOptions[].class);
}
@Override
public HttpRequest apply(String container, String name) {
GeneratedHttpRequest<AtmosStorageAsyncClient> returnVal = processor.createRequest(method, checkNotNull(container,
"container")
+ "/" + checkNotNull(name, "name"));
for (HttpRequestFilter filter : returnVal.getFilters())
filter.filter(returnVal);
return new HttpRequest(returnVal.getMethod(), returnVal.getEndpoint(), ImmutableMultimap.copyOf(returnVal
.getHeaders()));
}
}

View File

@ -17,7 +17,7 @@
* ==================================================================== * ====================================================================
*/ */
package org.jclouds.atmosonline.saas.blobstore.integration; package org.jclouds.atmosonline.saas.blobstore;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
@ -25,29 +25,36 @@ import java.io.IOException;
import java.util.Properties; import java.util.Properties;
import org.jclouds.atmosonline.saas.AtmosStorageAsyncClient; import org.jclouds.atmosonline.saas.AtmosStorageAsyncClient;
import org.jclouds.atmosonline.saas.blobstore.strategy.SignReadFile;
import org.jclouds.atmosonline.saas.config.AtmosStorageRestClientModule; import org.jclouds.atmosonline.saas.config.AtmosStorageRestClientModule;
import org.jclouds.atmosonline.saas.filters.SignRequest; import org.jclouds.atmosonline.saas.filters.SignRequest;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.date.TimeStamp; import org.jclouds.date.TimeStamp;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.RequiresHttp;
import org.jclouds.io.payloads.PhantomPayload;
import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestClientTest; import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory; import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.RestContextFactory.ContextSpec; import org.jclouds.rest.RestContextFactory.ContextSpec;
import org.jclouds.rest.internal.RestAnnotationProcessor; import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.inject.Module; import com.google.inject.Module;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
@Test(groups = "unit", testName = "emcsaas.SignReadFileTest") @Test(groups = "unit", testName = "emcsaas.AtmosBlobRequestSignerTest")
public class SignReadFileTest extends RestClientTest<AtmosStorageAsyncClient> { public class AtmosBlobRequestSignerTest extends RestClientTest<AtmosStorageAsyncClient> {
public void testSignReadFile() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException, private BlobRequestSigner signer;
private Factory blobFactory;
public void testSignGetBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException { NoSuchMethodException, IOException {
HttpRequest request = new SignReadFile(processor).apply("container", "name"); HttpRequest request = signer.signGetBlob("container", "name");
assertRequestLineEquals(request, "GET https://accesspoint.atmosonline.com/rest/namespace/container/name HTTP/1.1"); assertRequestLineEquals(request, "GET https://accesspoint.atmosonline.com/rest/namespace/container/name HTTP/1.1");
assertNonPayloadHeadersEqual( assertNonPayloadHeadersEqual(
@ -58,6 +65,47 @@ public class SignReadFileTest extends RestClientTest<AtmosStorageAsyncClient> {
assertEquals(request.getFilters().size(), 0); assertEquals(request.getFilters().size(), 0);
} }
public void testSignRemoveBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
HttpRequest request = signer.signRemoveBlob("container", "name");
assertRequestLineEquals(request,
"DELETE https://accesspoint.atmosonline.com/rest/namespace/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(
request,
"Accept: */*\nDate: Thu, 05 Jun 2008 16:38:19 GMT\nx-emc-signature: Q3zmO6KNAViNXquiCZSMx/0nuuc=\nx-emc-uid: identity\n");
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
public void testSignPutBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
Blob blob = blobFactory.create(null);
blob.getMetadata().setName("name");
blob.setPayload(new PhantomPayload(2l, new byte[] { 0, 2, 4, 8 }));
blob.getPayload().setContentType("text/plain");
HttpRequest request = signer.signPutBlob("container", blob);
assertRequestLineEquals(request,
"POST https://accesspoint.atmosonline.com/rest/namespace/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(
request,
"Accept: */*\nDate: Thu, 05 Jun 2008 16:38:19 GMT\nx-emc-signature: aLpB1oQaCA27AXT6Nzam7s0f0pI=\nx-emc-uid: identity\n");
assertContentHeadersEqual(request, "text/plain", (long) 2l, new byte[] { 0, 2, 4, 8 });
assertEquals(request.getFilters().size(), 0);
}
@BeforeClass
protected void setupFactory() throws IOException {
super.setupFactory();
this.blobFactory = injector.getInstance(Blob.Factory.class);
this.signer = injector.getInstance(BlobRequestSigner.class);
}
@Override @Override
protected void checkFilters(HttpRequest request) { protected void checkFilters(HttpRequest request) {
assertEquals(request.getFilters().size(), 1); assertEquals(request.getFilters().size(), 1);

View File

@ -17,18 +17,16 @@
* ==================================================================== * ====================================================================
*/ */
package org.jclouds.blobstore.strategy; package org.jclouds.atmosonline.saas.blobstore.integration;
import org.jclouds.blobstore.strategy.internal.SignRequestForBlobUnsupported; import org.jclouds.blobstore.integration.internal.BaseBlobSignerLiveTest;
import org.jclouds.http.HttpRequest; import org.testng.annotations.Test;
import com.google.inject.ImplementedBy;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@ImplementedBy(SignRequestForBlobUnsupported.class) @Test(groups = { "live" }, testName = "emcsaas.AtmosBlobSignerLiveTest")
public interface SignRequestForBlobStrategy { public class AtmosBlobSignerLiveTest extends BaseBlobSignerLiveTest {
HttpRequest apply(String container, String name);
} }

View File

@ -39,7 +39,7 @@ public class AtmosStorageTestInitializer extends TransientBlobStoreTestInitializ
@Override @Override
protected BlobStoreContext createLiveContext(Module configurationModule, String url, String app, protected BlobStoreContext createLiveContext(Module configurationModule, String url, String app,
String identity, String credential) throws IOException { String identity, String credential) throws IOException {
return new BlobStoreContextFactory().createContext("atmosonline", identity, credential, ImmutableSet return new BlobStoreContextFactory().createContext("synaptic", identity, credential, ImmutableSet
.of(configurationModule, new Log4JLoggingModule()), new Properties()); .of(configurationModule, new Log4JLoggingModule()), new Properties());
} }

View File

@ -53,7 +53,6 @@ import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore; import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata; import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.concurrent.Futures; import org.jclouds.concurrent.Futures;
@ -90,8 +89,8 @@ public class S3AsyncBlobStore extends BaseAsyncBlobStore {
BucketToResourceMetadata bucket2ResourceMd, ContainerToBucketListOptions container2BucketListOptions, BucketToResourceMetadata bucket2ResourceMd, ContainerToBucketListOptions container2BucketListOptions,
BucketToResourceList bucket2ResourceList, ObjectToBlob object2Blob, BucketToResourceList bucket2ResourceList, ObjectToBlob object2Blob,
BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider, SignRequestForBlobStrategy signRequestForBlob) { Provider<FetchBlobMetadata> fetchBlobMetadataProvider) {
super(context, blobUtils, service, defaultLocation, locations, signRequestForBlob); super(context, blobUtils, service, defaultLocation, locations);
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions"); this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
this.async = checkNotNull(async, "async"); this.async = checkNotNull(async, "async");
this.sync = checkNotNull(sync, "sync"); this.sync = checkNotNull(sync, "sync");

View File

@ -0,0 +1,79 @@
/**
*
* Copyright (C) 2010 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.aws.s3.blobstore;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.blobstore.util.BlobStoreUtils.cleanRequest;
import java.lang.reflect.Method;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.aws.s3.S3AsyncClient;
import org.jclouds.aws.s3.blobstore.functions.BlobToObject;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.options.PutObjectOptions;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.options.GetOptions;
import org.jclouds.rest.internal.RestAnnotationProcessor;
/**
*
* @author Adrian Cole
*/
@Singleton
public class S3BlobRequestSigner implements BlobRequestSigner {
private final RestAnnotationProcessor<S3AsyncClient> processor;
private final BlobToObject blobToObject;
private final Method getMethod;
private final Method deleteMethod;
private final Method createMethod;
@Inject
public S3BlobRequestSigner(RestAnnotationProcessor<S3AsyncClient> processor, BlobToObject blobToObject)
throws SecurityException, NoSuchMethodException {
this.processor = checkNotNull(processor, "processor");
this.blobToObject = checkNotNull(blobToObject, "blobToObject");
this.getMethod = S3AsyncClient.class.getMethod("getObject", String.class, String.class, GetOptions[].class);
this.deleteMethod = S3AsyncClient.class.getMethod("deleteObject", String.class, String.class);
this.createMethod = S3AsyncClient.class.getMethod("putObject", String.class, S3Object.class,
PutObjectOptions[].class);
}
@Override
public HttpRequest signGetBlob(String container, String name) {
return cleanRequest(processor.createRequest(getMethod, container, name));
}
@Override
public HttpRequest signPutBlob(String container, Blob blob) {
return cleanRequest(processor.createRequest(createMethod, container, blobToObject.apply(blob)));
}
@Override
public HttpRequest signRemoveBlob(String container, String name) {
return cleanRequest(processor.createRequest(deleteMethod, container, name));
}
}

View File

@ -47,7 +47,6 @@ import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseBlobStore; import org.jclouds.blobstore.internal.BaseBlobStore;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata; import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
@ -79,8 +78,8 @@ public class S3BlobStore extends BaseBlobStore {
Supplier<Set<? extends Location>> locations, S3Client sync, BucketToResourceMetadata bucket2ResourceMd, Supplier<Set<? extends Location>> locations, S3Client sync, BucketToResourceMetadata bucket2ResourceMd,
ContainerToBucketListOptions container2BucketListOptions, BucketToResourceList bucket2ResourceList, ContainerToBucketListOptions container2BucketListOptions, BucketToResourceList bucket2ResourceList,
ObjectToBlob object2Blob, BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object, ObjectToBlob object2Blob, BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object,
ObjectToBlobMetadata object2BlobMd, Provider<FetchBlobMetadata> fetchBlobMetadataProvider, SignRequestForBlobStrategy signRequestForBlob) { ObjectToBlobMetadata object2BlobMd, Provider<FetchBlobMetadata> fetchBlobMetadataProvider) {
super(context, blobUtils, defaultLocation, locations, signRequestForBlob); super(context, blobUtils, defaultLocation, locations);
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions"); this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
this.sync = checkNotNull(sync, "sync"); this.sync = checkNotNull(sync, "sync");
this.bucket2ResourceMd = checkNotNull(bucket2ResourceMd, "bucket2ResourceMd"); this.bucket2ResourceMd = checkNotNull(bucket2ResourceMd, "bucket2ResourceMd");

View File

@ -27,16 +27,16 @@ import org.jclouds.aws.Region;
import org.jclouds.aws.s3.S3AsyncClient; import org.jclouds.aws.s3.S3AsyncClient;
import org.jclouds.aws.s3.S3Client; import org.jclouds.aws.s3.S3Client;
import org.jclouds.aws.s3.blobstore.S3AsyncBlobStore; import org.jclouds.aws.s3.blobstore.S3AsyncBlobStore;
import org.jclouds.aws.s3.blobstore.S3BlobRequestSigner;
import org.jclouds.aws.s3.blobstore.S3BlobStore; import org.jclouds.aws.s3.blobstore.S3BlobStore;
import org.jclouds.aws.s3.blobstore.strategy.SignGetObject;
import org.jclouds.aws.suppliers.DefaultLocationSupplier; import org.jclouds.aws.suppliers.DefaultLocationSupplier;
import org.jclouds.blobstore.AsyncBlobStore; import org.jclouds.blobstore.AsyncBlobStore;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.attr.ConsistencyModel; import org.jclouds.blobstore.attr.ConsistencyModel;
import org.jclouds.blobstore.config.BlobStoreMapModule; import org.jclouds.blobstore.config.BlobStoreMapModule;
import org.jclouds.blobstore.internal.BlobStoreContextImpl; import org.jclouds.blobstore.internal.BlobStoreContextImpl;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope; import org.jclouds.domain.LocationScope;
import org.jclouds.domain.internal.LocationImpl; import org.jclouds.domain.internal.LocationImpl;
@ -68,7 +68,7 @@ public class S3BlobStoreContextModule extends AbstractModule {
bind(BlobStore.class).to(S3BlobStore.class).in(Scopes.SINGLETON); bind(BlobStore.class).to(S3BlobStore.class).in(Scopes.SINGLETON);
bind(BlobStoreContext.class).to(new TypeLiteral<BlobStoreContextImpl<S3Client, S3AsyncClient>>() { bind(BlobStoreContext.class).to(new TypeLiteral<BlobStoreContextImpl<S3Client, S3AsyncClient>>() {
}).in(Scopes.SINGLETON); }).in(Scopes.SINGLETON);
bind(SignRequestForBlobStrategy.class).to(SignGetObject.class); bind(BlobRequestSigner.class).to(S3BlobRequestSigner.class);
} }
@Provides @Provides

View File

@ -1,65 +0,0 @@
/**
*
* Copyright (C) 2010 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.aws.s3.blobstore.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import java.lang.reflect.Method;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.aws.s3.S3AsyncClient;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.options.GetOptions;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import com.google.common.collect.ImmutableMultimap;
/**
*
* @author Adrian Cole
*/
@Singleton
public class SignGetObject implements SignRequestForBlobStrategy {
private final RestAnnotationProcessor<S3AsyncClient> processor;
private final Method method;
@Inject
public SignGetObject(RestAnnotationProcessor<S3AsyncClient> processor) throws SecurityException,
NoSuchMethodException {
this.processor = checkNotNull(processor, "processor");
this.method = S3AsyncClient.class.getMethod("getObject", String.class, String.class, GetOptions[].class);
}
@Override
public HttpRequest apply(String container, String name) {
GeneratedHttpRequest<S3AsyncClient> returnVal = processor.createRequest(method, checkNotNull(container,
"container"), checkNotNull(name, "name"));
for (HttpRequestFilter filter : returnVal.getFilters())
filter.filter(returnVal);
return new HttpRequest(returnVal.getMethod(), returnVal.getEndpoint(), ImmutableMultimap.copyOf(returnVal
.getHeaders()));
}
}

View File

@ -82,7 +82,7 @@ public class ComputeAndBlobStoreTogetherHappilyLiveTest extends BlobStoreAndComp
// instead of hard-coding to amazon s3, we can use any blobstore, conceding this test is // instead of hard-coding to amazon s3, we can use any blobstore, conceding this test is
// configured for amz. Note we are getting temporary access to a private blob. // configured for amz. Note we are getting temporary access to a private blob.
HttpRequest signedRequestOfInstallScript = blobContext.getBlobStore().signRequestForBlob(tag, "openjdk/install"); HttpRequest signedRequestOfInstallScript = blobContext.getSigner().signGetBlob(tag, "openjdk/install");
// so one of our commands is to execute the contents of the blob above // so one of our commands is to execute the contents of the blob above
Statement installOpenJDK = execHttpResponse(signedRequestOfInstallScript); Statement installOpenJDK = execHttpResponse(signedRequestOfInstallScript);

View File

@ -0,0 +1,140 @@
/**
*
* Copyright (C) 2010 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.aws.s3.blobstore;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Properties;
import org.jclouds.aws.s3.S3AsyncClient;
import org.jclouds.aws.s3.config.S3RestClientModule;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.date.TimeStamp;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp;
import org.jclouds.io.payloads.PhantomPayload;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.RestContextFactory.ContextSpec;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
@Test(groups = "unit", testName = "s3.S3BlobRequestSignerTest")
public class S3BlobRequestSignerTest extends RestClientTest<S3AsyncClient> {
private BlobRequestSigner signer;
private Factory blobFactory;
public void testSignGetBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
HttpRequest request = signer.signGetBlob("container", "name");
assertRequestLineEquals(request, "GET https://container.s3.amazonaws.com/name HTTP/1.1");
assertNonPayloadHeadersEqual(
request,
"Authorization: AWS identity:0uvBv1wEskuhFHYJF/L6kEV9A7o=\nDate: Thu, 05 Jun 2008 16:38:19 GMT\nHost: container.s3.amazonaws.com\n");
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
public void testSignRemoveBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
HttpRequest request = signer.signRemoveBlob("container", "name");
assertRequestLineEquals(request, "DELETE https://container.s3.amazonaws.com/name HTTP/1.1");
assertNonPayloadHeadersEqual(
request,
"Authorization: AWS identity:4FnyjdX/ULdDMRbVlLNjZfEo9RQ=\nDate: Thu, 05 Jun 2008 16:38:19 GMT\nHost: container.s3.amazonaws.com\n");
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
public void testSignPutBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
Blob blob = blobFactory.create(null);
blob.getMetadata().setName("name");
blob.setPayload(new PhantomPayload(2l, new byte[] { 0, 2, 4, 8 }));
blob.getPayload().setContentType("text/plain");
HttpRequest request = signer.signPutBlob("container", blob);
assertRequestLineEquals(request, "PUT https://container.s3.amazonaws.com/name HTTP/1.1");
assertNonPayloadHeadersEqual(
request,
"Authorization: AWS identity:j9Dy/lmmvlCKjA4lkqZenLxMkR4=\nDate: Thu, 05 Jun 2008 16:38:19 GMT\nHost: container.s3.amazonaws.com\n");
assertContentHeadersEqual(request, "text/plain", (long) 2l, new byte[] { 0, 2, 4, 8 });
assertEquals(request.getFilters().size(), 0);
}
@BeforeClass
protected void setupFactory() throws IOException {
super.setupFactory();
this.blobFactory = injector.getInstance(Blob.Factory.class);
this.signer = injector.getInstance(BlobRequestSigner.class);
}
@Override
protected void checkFilters(HttpRequest request) {
}
@Override
protected TypeLiteral<RestAnnotationProcessor<S3AsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<S3AsyncClient>>() {
};
}
@Override
protected Module createModule() {
return new TestS3RestClientModule();
}
@RequiresHttp
@ConfiguresRestClient
private static final class TestS3RestClientModule extends S3RestClientModule {
@Override
protected void configure() {
super.configure();
}
@Override
protected String provideTimeStamp(@TimeStamp Supplier<String> cache) {
return "Thu, 05 Jun 2008 16:38:19 GMT";
}
}
@Override
public ContextSpec<?, ?> createContextSpec() {
return new RestContextFactory().createContextSpec("s3", "identity", "credential", new Properties());
}
}

View File

@ -17,21 +17,16 @@
* ==================================================================== * ====================================================================
*/ */
package org.jclouds.blobstore.strategy.internal; package org.jclouds.aws.s3.blobstore.integration;
import javax.inject.Singleton; import org.jclouds.blobstore.integration.internal.BaseBlobSignerLiveTest;
import org.testng.annotations.Test;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.http.HttpRequest;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Test(groups = { "live" }, testName = "s3.S3BlobSignerLiveTest")
public class SignRequestForBlobUnsupported implements SignRequestForBlobStrategy { public class S3BlobSignerLiveTest extends BaseBlobSignerLiveTest {
@Override
public HttpRequest apply(String container, String name) {
throw new UnsupportedOperationException();
}
} }

View File

@ -1,76 +0,0 @@
/**
*
* Copyright (C) 2010 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.aws.s3.blobstore.strategy;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import org.jclouds.aws.s3.BaseS3AsyncClientTest;
import org.jclouds.aws.s3.config.S3RestClientModule;
import org.jclouds.date.TimeStamp;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp;
import org.jclouds.rest.ConfiguresRestClient;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.inject.Module;
/**
* Tests behavior of {@code SignGetObject}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "s3.SignGetObjectTest")
public class SignGetObjectTest extends BaseS3AsyncClientTest {
public void testSignGetObject() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
HttpRequest request = new SignGetObject(processor).apply( "bucket", "object");
assertRequestLineEquals(request, "GET https://bucket.s3.amazonaws.com/object HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Authorization: AWS identity:1UqxCBECNncBHUhxJ3Y/Q1O3IiA=\nDate: 2009-11-08T15:54:08.897Z\nHost: bucket.s3.amazonaws.com\n");
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
@RequiresHttp
@ConfiguresRestClient
protected static final class TestS3RestClientModule extends S3RestClientModule {
@Override
protected void configure() {
super.configure();
}
@Override
protected String provideTimeStamp(@TimeStamp Supplier<String> cache) {
return "2009-11-08T15:54:08.897Z";
}
}
@Override
protected Module createModule() {
return new TestS3RestClientModule();
}
}

View File

@ -52,7 +52,6 @@ import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore; import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.concurrent.Futures; import org.jclouds.concurrent.Futures;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
@ -85,8 +84,8 @@ public class AzureAsyncBlobStore extends BaseAsyncBlobStore {
ListOptionsToListBlobsOptions blobStore2AzureContainerListOptions, ListOptionsToListBlobsOptions blobStore2AzureContainerListOptions,
ListBlobsResponseToResourceList azure2BlobStoreResourceList, AzureBlobToBlob azureBlob2Blob, ListBlobsResponseToResourceList azure2BlobStoreResourceList, AzureBlobToBlob azureBlob2Blob,
BlobToAzureBlob blob2AzureBlob, BlobPropertiesToBlobMetadata blob2BlobMd, BlobToAzureBlob blob2AzureBlob, BlobPropertiesToBlobMetadata blob2BlobMd,
BlobToHttpGetOptions blob2ObjectGetOptions, SignRequestForBlobStrategy signRequestForBlob) { BlobToHttpGetOptions blob2ObjectGetOptions) {
super(context, blobUtils, service, defaultLocation, locations, signRequestForBlob); super(context, blobUtils, service, defaultLocation, locations);
this.async = checkNotNull(async, "async"); this.async = checkNotNull(async, "async");
this.container2ResourceMd = checkNotNull(container2ResourceMd, "container2ResourceMd"); this.container2ResourceMd = checkNotNull(container2ResourceMd, "container2ResourceMd");
this.blobStore2AzureContainerListOptions = checkNotNull(blobStore2AzureContainerListOptions, this.blobStore2AzureContainerListOptions = checkNotNull(blobStore2AzureContainerListOptions,

View File

@ -0,0 +1,77 @@
/**
*
* Copyright (C) 2010 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.azure.storage.blob.blobstore;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.blobstore.util.BlobStoreUtils.cleanRequest;
import java.lang.reflect.Method;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.azure.storage.blob.AzureBlobAsyncClient;
import org.jclouds.azure.storage.blob.blobstore.functions.BlobToAzureBlob;
import org.jclouds.azure.storage.blob.domain.AzureBlob;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.options.GetOptions;
import org.jclouds.rest.internal.RestAnnotationProcessor;
/**
*
* @author Adrian Cole
*/
@Singleton
public class AzureBlobRequestSigner implements BlobRequestSigner {
private final RestAnnotationProcessor<AzureBlobAsyncClient> processor;
private final BlobToAzureBlob blobToBlob;
private final Method getMethod;
private final Method deleteMethod;
private final Method createMethod;
@Inject
public AzureBlobRequestSigner(RestAnnotationProcessor<AzureBlobAsyncClient> processor, BlobToAzureBlob blobToBlob)
throws SecurityException, NoSuchMethodException {
this.processor = checkNotNull(processor, "processor");
this.blobToBlob = checkNotNull(blobToBlob, "blobToBlob");
this.getMethod = AzureBlobAsyncClient.class.getMethod("getBlob", String.class, String.class, GetOptions[].class);
this.deleteMethod = AzureBlobAsyncClient.class.getMethod("deleteBlob", String.class, String.class);
this.createMethod = AzureBlobAsyncClient.class.getMethod("putBlob", String.class, AzureBlob.class);
}
@Override
public HttpRequest signGetBlob(String container, String name) {
return cleanRequest(processor.createRequest(getMethod, container, name));
}
@Override
public HttpRequest signPutBlob(String container, Blob blob) {
return cleanRequest(processor.createRequest(createMethod, container, blobToBlob.apply(blob)));
}
@Override
public HttpRequest signRemoveBlob(String container, String name) {
return cleanRequest(processor.createRequest(deleteMethod, container, name));
}
}

View File

@ -46,7 +46,6 @@ import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseBlobStore; import org.jclouds.blobstore.internal.BaseBlobStore;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.http.options.GetOptions; import org.jclouds.http.options.GetOptions;
@ -76,8 +75,8 @@ public class AzureBlobStore extends BaseBlobStore {
ListOptionsToListBlobsOptions blobStore2AzureContainerListOptions, ListOptionsToListBlobsOptions blobStore2AzureContainerListOptions,
ListBlobsResponseToResourceList azure2BlobStoreResourceList, AzureBlobToBlob azureBlob2Blob, ListBlobsResponseToResourceList azure2BlobStoreResourceList, AzureBlobToBlob azureBlob2Blob,
BlobToAzureBlob blob2AzureBlob, BlobPropertiesToBlobMetadata blob2BlobMd, BlobToAzureBlob blob2AzureBlob, BlobPropertiesToBlobMetadata blob2BlobMd,
BlobToHttpGetOptions blob2ObjectGetOptions, SignRequestForBlobStrategy signRequestForBlob) { BlobToHttpGetOptions blob2ObjectGetOptions) {
super(context, blobUtils, defaultLocation, locations, signRequestForBlob); super(context, blobUtils, defaultLocation, locations);
this.sync = checkNotNull(sync, "sync"); this.sync = checkNotNull(sync, "sync");
this.container2ResourceMd = checkNotNull(container2ResourceMd, "container2ResourceMd"); this.container2ResourceMd = checkNotNull(container2ResourceMd, "container2ResourceMd");
this.blobStore2AzureContainerListOptions = checkNotNull(blobStore2AzureContainerListOptions, this.blobStore2AzureContainerListOptions = checkNotNull(blobStore2AzureContainerListOptions,

View File

@ -26,17 +26,17 @@ import javax.inject.Singleton;
import org.jclouds.azure.storage.blob.AzureBlobAsyncClient; import org.jclouds.azure.storage.blob.AzureBlobAsyncClient;
import org.jclouds.azure.storage.blob.AzureBlobClient; import org.jclouds.azure.storage.blob.AzureBlobClient;
import org.jclouds.azure.storage.blob.blobstore.AzureAsyncBlobStore; import org.jclouds.azure.storage.blob.blobstore.AzureAsyncBlobStore;
import org.jclouds.azure.storage.blob.blobstore.AzureBlobRequestSigner;
import org.jclouds.azure.storage.blob.blobstore.AzureBlobStore; import org.jclouds.azure.storage.blob.blobstore.AzureBlobStore;
import org.jclouds.azure.storage.blob.blobstore.strategy.FindMD5InBlobProperties; import org.jclouds.azure.storage.blob.blobstore.strategy.FindMD5InBlobProperties;
import org.jclouds.azure.storage.blob.blobstore.strategy.SignGetBlob;
import org.jclouds.blobstore.AsyncBlobStore; import org.jclouds.blobstore.AsyncBlobStore;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.attr.ConsistencyModel; import org.jclouds.blobstore.attr.ConsistencyModel;
import org.jclouds.blobstore.config.BlobStoreMapModule; import org.jclouds.blobstore.config.BlobStoreMapModule;
import org.jclouds.blobstore.internal.BlobStoreContextImpl; import org.jclouds.blobstore.internal.BlobStoreContextImpl;
import org.jclouds.blobstore.strategy.ContainsValueInListStrategy; import org.jclouds.blobstore.strategy.ContainsValueInListStrategy;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope; import org.jclouds.domain.LocationScope;
import org.jclouds.domain.internal.LocationImpl; import org.jclouds.domain.internal.LocationImpl;
@ -66,7 +66,7 @@ public class AzureBlobStoreContextModule extends AbstractModule {
bind(BlobStoreContext.class).to(new TypeLiteral<BlobStoreContextImpl<AzureBlobClient, AzureBlobAsyncClient>>() { bind(BlobStoreContext.class).to(new TypeLiteral<BlobStoreContextImpl<AzureBlobClient, AzureBlobAsyncClient>>() {
}).in(Scopes.SINGLETON); }).in(Scopes.SINGLETON);
bind(ContainsValueInListStrategy.class).to(FindMD5InBlobProperties.class); bind(ContainsValueInListStrategy.class).to(FindMD5InBlobProperties.class);
bind(SignRequestForBlobStrategy.class).to(SignGetBlob.class); bind(BlobRequestSigner.class).to(AzureBlobRequestSigner.class);
} }
@Provides @Provides

View File

@ -1,64 +0,0 @@
/**
*
* Copyright (C) 2010 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.azure.storage.blob.blobstore.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import java.lang.reflect.Method;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.azure.storage.blob.AzureBlobAsyncClient;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.options.GetOptions;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import com.google.common.collect.ImmutableMultimap;
/**
*
* @author Adrian Cole
*/
@Singleton
public class SignGetBlob implements SignRequestForBlobStrategy {
private final RestAnnotationProcessor<AzureBlobAsyncClient> processor;
private final Method method;
@Inject
public SignGetBlob(RestAnnotationProcessor<AzureBlobAsyncClient> processor) throws SecurityException,
NoSuchMethodException {
this.processor = checkNotNull(processor, "processor");
this.method = AzureBlobAsyncClient.class.getMethod("getBlob", String.class, String.class, GetOptions[].class);
}
@Override
public HttpRequest apply(String container, String name) {
HttpRequest returnVal = processor.createRequest(method, checkNotNull(container,
"container"), checkNotNull(name, "name"));
for (HttpRequestFilter filter : returnVal.getFilters())
filter.filter(returnVal);
returnVal.getFilters().clear();
return new HttpRequest(returnVal.getMethod(), returnVal.getEndpoint(), ImmutableMultimap.copyOf(returnVal.getHeaders()));
}
}

View File

@ -0,0 +1,139 @@
/**
*
* Copyright (C) 2010 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.azure.storage.blob.blobstore;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Properties;
import org.jclouds.azure.storage.blob.AzureBlobAsyncClient;
import org.jclouds.azure.storage.blob.config.AzureBlobRestClientModule;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.date.TimeStamp;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp;
import org.jclouds.io.payloads.PhantomPayload;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.RestContextFactory.ContextSpec;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
@Test(groups = "unit", testName = "s3.AzureBlobBlobRequestSignerTest")
public class AzureBlobBlobRequestSignerTest extends RestClientTest<AzureBlobAsyncClient> {
private BlobRequestSigner signer;
private Factory blobFactory;
public void testSignGetBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
HttpRequest request = signer.signGetBlob("container", "name");
assertRequestLineEquals(request, "GET https://identity.blob.core.windows.net/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(
request,
"Authorization: SharedKeyLite identity:nI6ca9CdLWhPoMuSzk4perqx5pzi2hx7YBJ92FCqeXM=\nDate: Thu, 05 Jun 2008 16:38:19 GMT\nx-ms-version: 2009-09-19\n");
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
public void testSignRemoveBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
HttpRequest request = signer.signRemoveBlob("container", "name");
assertRequestLineEquals(request, "DELETE https://identity.blob.core.windows.net/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(
request,
"Authorization: SharedKeyLite identity:+BDU2AGqS9LwevaKH+jaRKNrxTZ3LsFDpnnWFKpN0jc=\nDate: Thu, 05 Jun 2008 16:38:19 GMT\nx-ms-version: 2009-09-19\n");
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
public void testSignPutBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
Blob blob = blobFactory.create(null);
blob.getMetadata().setName("name");
blob.setPayload(new PhantomPayload(2l, new byte[] { 0, 2, 4, 8 }));
blob.getPayload().setContentType("text/plain");
HttpRequest request = signer.signPutBlob("container", blob);
assertRequestLineEquals(request, "PUT https://identity.blob.core.windows.net/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(
request,
"Authorization: SharedKeyLite identity:LT+HBNzhbRsZY07kC+/JxeuAURbxTmwJaIe464LO36c=\nDate: Thu, 05 Jun 2008 16:38:19 GMT\nx-ms-blob-type: BlockBlob\nx-ms-version: 2009-09-19\n");
assertContentHeadersEqual(request, "text/plain", (long) 2l, new byte[] { 0, 2, 4, 8 });
assertEquals(request.getFilters().size(), 0);
}
@BeforeClass
protected void setupFactory() throws IOException {
super.setupFactory();
this.blobFactory = injector.getInstance(Blob.Factory.class);
this.signer = injector.getInstance(BlobRequestSigner.class);
}
@Override
protected void checkFilters(HttpRequest request) {
}
@Override
protected TypeLiteral<RestAnnotationProcessor<AzureBlobAsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<AzureBlobAsyncClient>>() {
};
}
@Override
protected Module createModule() {
return new TestAzureBlobRestClientModule();
}
@RequiresHttp
@ConfiguresRestClient
private static final class TestAzureBlobRestClientModule extends AzureBlobRestClientModule {
@Override
protected void configure() {
super.configure();
}
@Override
protected String provideTimeStamp(@TimeStamp Supplier<String> cache) {
return "Thu, 05 Jun 2008 16:38:19 GMT";
}
}
@Override
public ContextSpec<?, ?> createContextSpec() {
return new RestContextFactory().createContextSpec("azureblob", "identity", "credential", new Properties());
}
}

View File

@ -1,102 +0,0 @@
/**
*
* Copyright (C) 2010 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.azure.storage.blob.blobstore.config;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Properties;
import org.jclouds.azure.storage.blob.AzureBlobAsyncClient;
import org.jclouds.azure.storage.blob.blobstore.strategy.SignGetBlob;
import org.jclouds.azure.storage.blob.config.AzureBlobRestClientModule;
import org.jclouds.azure.storage.filters.SharedKeyLiteAuthentication;
import org.jclouds.date.TimeStamp;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.RestContextFactory.ContextSpec;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of {@code SignGetBlob}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "azureblob.SignGetBlobTest")
public class SignGetBlobTest extends RestClientTest<AzureBlobAsyncClient> {
public void testSignGetBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
HttpRequest request = new SignGetBlob(processor).apply("container", "blob");
assertRequestLineEquals(request, "GET https://identity.blob.core.windows.net/container/blob HTTP/1.1");
assertNonPayloadHeadersEqual(
request,
"Authorization: SharedKeyLite identity:bX3fHsuXQQEzvLey2TD76FcDDvDIHZpgSX2j5oH4Iy8=\nDate: 2009-11-08T15:54:08.897Z\nx-ms-version: 2009-09-19\n");
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
@RequiresHttp
@ConfiguresRestClient
protected static final class TestAzureBlobRestClientModule extends AzureBlobRestClientModule {
@Override
protected void configure() {
super.configure();
}
@Override
protected String provideTimeStamp(@TimeStamp Supplier<String> cache) {
return "2009-11-08T15:54:08.897Z";
}
}
@Override
protected Module createModule() {
return new TestAzureBlobRestClientModule();
}
@Override
protected void checkFilters(HttpRequest request) {
assertEquals(request.getFilters().size(), 1);
assertEquals(request.getFilters().get(0).getClass(), SharedKeyLiteAuthentication.class);
}
@Override
protected TypeLiteral<RestAnnotationProcessor<AzureBlobAsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<AzureBlobAsyncClient>>() {
};
}
@Override
public ContextSpec<?, ?> createContextSpec() {
return new RestContextFactory().createContextSpec("azureblob", "identity", "credential", new Properties());
}
}

View File

@ -0,0 +1,32 @@
/**
*
* Copyright (C) 2010 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.azure.storage.blob.blobstore.integration;
import org.jclouds.blobstore.integration.internal.BaseBlobSignerLiveTest;
import org.testng.annotations.Test;
/**
*
* @author Adrian Cole
*/
@Test(groups = { "live" }, testName = "azureblob.AzureBlobSignerLiveTest")
public class AzureBlobSignerLiveTest extends BaseBlobSignerLiveTest {
}

View File

@ -45,6 +45,7 @@ See http://code.google.com/p/jclouds for details."
domain.BlobMetadata domain.StorageMetadata domain.Blob domain.BlobMetadata domain.StorageMetadata domain.Blob
options.ListContainerOptions] options.ListContainerOptions]
[org.jclouds.io Payloads] [org.jclouds.io Payloads]
[org.jclouds.io.payloads PhantomPayload]
[java.util Arrays] [java.util Arrays]
[java.security DigestOutputStream MessageDigest] [java.security DigestOutputStream MessageDigest]
[com.google.common.collect ImmutableSet])) [com.google.common.collect ImmutableSet]))
@ -238,13 +239,34 @@ Options can also be specified for extension modules
([container-name path #^BlobStore blobstore] ([container-name path #^BlobStore blobstore]
(.getBlob blobstore container-name path))) (.getBlob blobstore container-name path)))
(defn sign-blob-request (defn sign-get-blob-request
"Get a signed http request for a blob, so that you can retrieve it "Get a signed http request for a blob, so that you can retrieve it
in another application. ex. curl" in another application. ex. curl"
([container-name path] ([container-name path]
(sign-blob-request container-name path *blobstore*)) (sign-get-blob-request container-name path *blobstore*))
([container-name path #^BlobStore blobstore] ([container-name path #^BlobStore blobstore]
(.signRequestForBlob blobstore container-name path))) (.signGetBlob (.getContext blobstore) container-name path)))
(defn sign-remove-blob-request
"Get a signed http request for deleting a blob in another application.
ex. curl"
([container-name path]
(sign-remove-blob-request container-name path *blobstore*))
([container-name path #^BlobStore blobstore]
(.signRemoveBlob (.getContext blobstore) container-name path)))
(defn sign-put-blob-request
"Get a signed http request for uploading a blob in another application.
ex. curl"
([container-name path content-type size]
(sign-put-blob-request container-name path content-type size *blobstore*))
([container-name path content-type size #^BlobStore blobstore]
(.signPutBlob (.getContext blobstore) container-name
(doto (.newBlob blobstore path)
(.setPayload (doto
;; until we pass content md5
(PhantomPayload. size nil)
(.setContentType content-type)))))))
(defn get-blob-stream (defn get-blob-stream
"Get an inputstream from the blob at a given path" "Get an inputstream from the blob at a given path"

View File

@ -20,7 +20,6 @@
package org.jclouds.blobstore; package org.jclouds.blobstore;
import java.util.Set; import java.util.Set;
import com.google.common.util.concurrent.ListenableFuture;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -31,7 +30,8 @@ import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.options.GetOptions; import org.jclouds.blobstore.options.GetOptions;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.http.HttpRequest;
import com.google.common.util.concurrent.ListenableFuture;
/** /**
* Provides hooks needed to run a blob store asynchronously * Provides hooks needed to run a blob store asynchronously
@ -49,11 +49,6 @@ public interface AsyncBlobStore {
*/ */
Blob newBlob(String name); Blob newBlob(String name);
/**
* @see BlobStore#signRequestForBlob
*/
HttpRequest signRequestForBlob(String container, String name);
/** /**
* @see BlobStore#listAssignableLocations * @see BlobStore#listAssignableLocations
*/ */

View File

@ -0,0 +1,83 @@
/**
*
* Copyright (C) 2010 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.blobstore;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.internal.RequestSigningUnsupported;
import org.jclouds.http.HttpRequest;
import org.jclouds.io.payloads.PhantomPayload;
import com.google.inject.ImplementedBy;
/**
* Generates signed requests for blobs. useful in other tools such as backup utilities.
*
* @author Adrian Cole
*/
@ImplementedBy(RequestSigningUnsupported.class)
public interface BlobRequestSigner {
/**
* gets a signed request, including headers as necessary, to access a blob from an external
* client.
*
* @param container
* container where the blob resides
* @param directory
* full path to the blob
* @throws UnsupportedOperationException
* if not supported by the provider
*/
HttpRequest signGetBlob(String container, String name);
/**
* gets a signed request, including headers as necessary, to delete a blob from an external
* client.
*
* @param container
* container where the blob resides
* @param directory
* full path to the blob
* @throws UnsupportedOperationException
* if not supported by the provider
*/
HttpRequest signRemoveBlob(String container, String name);
/**
* gets a signed request, including headers as necessary, to upload a blob from an external
* client.
*
* <pre>
* Blob blob = context.getBlobStore.newBlob();
* blob.getMetadata().setName(&quot;name&quot;);
* blob.setPayload(new PhantomPayload(length, md5));
* blob.getPayload().setContentType(&quot;text/plain&quot;);
* </pre>
*
* @param container
* container where the blob resides
* @param blob
* what to upload
* @throws UnsupportedOperationException
* if not supported by the provider
* @see PhantomPayload
*/
HttpRequest signPutBlob(String container, Blob blob);
}

View File

@ -30,7 +30,6 @@ import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.options.GetOptions; import org.jclouds.blobstore.options.GetOptions;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.http.HttpRequest;
/** /**
* Synchronous access to a BlobStore such as Amazon S3 * Synchronous access to a BlobStore such as Amazon S3
@ -51,19 +50,6 @@ public interface BlobStore {
*/ */
Blob newBlob(String name); Blob newBlob(String name);
/**
* gets a signed request, including headers as necessary, to access a blob from an external
* client.
*
* @param container
* container where the blob resides
* @param directory
* full path to the blob
* @throws UnsupportedOperationException
* if not supported by the provider
*/
HttpRequest signRequestForBlob(String container, String name);
/** /**
* The get locations command returns all the valid locations for containers. A location has a * The get locations command returns all the valid locations for containers. A location has a
* scope, which is typically region or zone. A region is a general area, like eu-west, where a * scope, which is typically region or zone. A region is a general area, like eu-west, where a

View File

@ -36,6 +36,12 @@ import com.google.inject.ImplementedBy;
*/ */
@ImplementedBy(BlobStoreContextImpl.class) @ImplementedBy(BlobStoreContextImpl.class)
public interface BlobStoreContext { public interface BlobStoreContext {
/**
*
* Generates signed requests for blobs. useful in other tools such as backup utilities.
*
*/
BlobRequestSigner getSigner();
/** /**
* Creates a <code>Map<String,InputStream></code> view of the specified container. Use this for * Creates a <code>Map<String,InputStream></code> view of the specified container. Use this for

View File

@ -77,7 +77,6 @@ import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.GetOptions; import org.jclouds.blobstore.options.GetOptions;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.IfDirectoryReturnNameStrategy; import org.jclouds.blobstore.strategy.IfDirectoryReturnNameStrategy;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.crypto.Crypto; import org.jclouds.crypto.Crypto;
import org.jclouds.crypto.CryptoStreams; import org.jclouds.crypto.CryptoStreams;
@ -125,8 +124,8 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
HttpGetOptionsListToGetOptions httpGetOptionsConverter, HttpGetOptionsListToGetOptions httpGetOptionsConverter,
IfDirectoryReturnNameStrategy ifDirectoryReturnName, Blob.Factory blobFactory, BlobUtils blobUtils, IfDirectoryReturnNameStrategy ifDirectoryReturnName, Blob.Factory blobFactory, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
Supplier<Set<? extends Location>> locations, SignRequestForBlobStrategy signRequestForBlob) { Supplier<Set<? extends Location>> locations) {
super(context, blobUtils, service, defaultLocation, locations, signRequestForBlob); super(context, blobUtils, service, defaultLocation, locations);
this.blobFactory = blobFactory; this.blobFactory = blobFactory;
this.dateService = dateService; this.dateService = dateService;
this.crypto = crypto; this.crypto = crypto;

View File

@ -37,11 +37,9 @@ import org.jclouds.blobstore.domain.Blob;
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.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.blobstore.util.internal.BlobUtilsImpl; import org.jclouds.blobstore.util.internal.BlobUtilsImpl;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.http.HttpRequest;
import org.jclouds.util.Utils; import org.jclouds.util.Utils;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
@ -59,18 +57,16 @@ public abstract class BaseAsyncBlobStore implements AsyncBlobStore {
protected final ExecutorService service; protected final ExecutorService service;
protected final Supplier<Location> defaultLocation; protected final Supplier<Location> defaultLocation;
protected final Supplier<Set<? extends Location>> locations; protected final Supplier<Set<? extends Location>> locations;
protected final SignRequestForBlobStrategy signRequestForBlob;
@Inject @Inject
protected BaseAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils, protected BaseAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
Supplier<Set<? extends Location>> locations, SignRequestForBlobStrategy signRequestForBlob) { Supplier<Set<? extends Location>> locations) {
this.context = checkNotNull(context, "context"); this.context = checkNotNull(context, "context");
this.blobUtils = checkNotNull(blobUtils, "blobUtils"); this.blobUtils = checkNotNull(blobUtils, "blobUtils");
this.service = checkNotNull(service, "service"); this.service = checkNotNull(service, "service");
this.defaultLocation = checkNotNull(defaultLocation, "defaultLocation"); this.defaultLocation = checkNotNull(defaultLocation, "defaultLocation");
this.locations = checkNotNull(locations, "locations"); this.locations = checkNotNull(locations, "locations");
this.signRequestForBlob = checkNotNull(signRequestForBlob, "signRequestForBlob");
} }
@Override @Override
@ -271,8 +267,5 @@ public abstract class BaseAsyncBlobStore implements AsyncBlobStore {
protected abstract boolean deleteAndVerifyContainerGone(String container); protected abstract boolean deleteAndVerifyContainerGone(String container);
@Override
public HttpRequest signRequestForBlob(String container, String name) {
return signRequestForBlob.apply(container, name);
}
} }

View File

@ -33,11 +33,9 @@ import org.jclouds.blobstore.domain.Blob;
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.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.blobstore.util.internal.BlobUtilsImpl; import org.jclouds.blobstore.util.internal.BlobUtilsImpl;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.http.HttpRequest;
import org.jclouds.util.Utils; import org.jclouds.util.Utils;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
@ -52,16 +50,14 @@ public abstract class BaseBlobStore implements BlobStore {
protected final BlobUtils blobUtils; protected final BlobUtils blobUtils;
protected final Supplier<Location> defaultLocation; protected final Supplier<Location> defaultLocation;
protected final Supplier<Set<? extends Location>> locations; protected final Supplier<Set<? extends Location>> locations;
protected final SignRequestForBlobStrategy signRequestForBlob;
@Inject @Inject
protected BaseBlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation, protected BaseBlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
Supplier<Set<? extends Location>> locations, SignRequestForBlobStrategy signRequestForBlob) { Supplier<Set<? extends Location>> locations) {
this.context = checkNotNull(context, "context"); this.context = checkNotNull(context, "context");
this.blobUtils = checkNotNull(blobUtils, "blobUtils"); this.blobUtils = checkNotNull(blobUtils, "blobUtils");
this.defaultLocation = checkNotNull(defaultLocation, "defaultLocation"); this.defaultLocation = checkNotNull(defaultLocation, "defaultLocation");
this.locations = checkNotNull(locations, "locations"); this.locations = checkNotNull(locations, "locations");
this.signRequestForBlob = checkNotNull(signRequestForBlob, "signRequestForBlob");
} }
@Override @Override
@ -224,8 +220,4 @@ public abstract class BaseBlobStore implements BlobStore {
protected abstract boolean deleteAndVerifyContainerGone(String container); protected abstract boolean deleteAndVerifyContainerGone(String container);
@Override
public HttpRequest signRequestForBlob(String container, String name) {
return signRequestForBlob.apply(container, name);
}
} }

View File

@ -26,6 +26,7 @@ import javax.inject.Singleton;
import org.jclouds.blobstore.AsyncBlobStore; import org.jclouds.blobstore.AsyncBlobStore;
import org.jclouds.blobstore.BlobMap; import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.InputStreamMap; import org.jclouds.blobstore.InputStreamMap;
@ -46,22 +47,23 @@ public class BlobStoreContextImpl<S, A> implements BlobStoreContext {
private final RestContext<S, A> providerSpecificContext; private final RestContext<S, A> providerSpecificContext;
private final ConsistencyModel consistencyModel; private final ConsistencyModel consistencyModel;
private final Utils utils; private final Utils utils;
private final BlobRequestSigner blobRequestSigner;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Inject @Inject
public BlobStoreContextImpl(BlobMap.Factory blobMapFactory, Utils utils, public BlobStoreContextImpl(BlobMap.Factory blobMapFactory, Utils utils, ConsistencyModel consistencyModel,
ConsistencyModel consistencyModel, InputStreamMap.Factory inputStreamMapFactory, InputStreamMap.Factory inputStreamMapFactory, AsyncBlobStore ablobStore, BlobStore blobStore,
AsyncBlobStore ablobStore, BlobStore blobStore, RestContext providerSpecificContext) { RestContext providerSpecificContext, BlobRequestSigner blobRequestSigner) {
// unravel guice and avoid passing in a million type args by not injecting generic types for // unravel guice and avoid passing in a million type args by not injecting generic types for
// rest context // rest context
this.providerSpecificContext = checkNotNull(providerSpecificContext, this.providerSpecificContext = checkNotNull(providerSpecificContext, "providerSpecificContext");
"providerSpecificContext");
this.consistencyModel = checkNotNull(consistencyModel, "consistencyModel"); this.consistencyModel = checkNotNull(consistencyModel, "consistencyModel");
this.blobMapFactory = checkNotNull(blobMapFactory, "blobMapFactory"); this.blobMapFactory = checkNotNull(blobMapFactory, "blobMapFactory");
this.inputStreamMapFactory = checkNotNull(inputStreamMapFactory, "inputStreamMapFactory"); this.inputStreamMapFactory = checkNotNull(inputStreamMapFactory, "inputStreamMapFactory");
this.ablobStore = checkNotNull(ablobStore, "ablobStore"); this.ablobStore = checkNotNull(ablobStore, "ablobStore");
this.blobStore = checkNotNull(blobStore, "blobStore"); this.blobStore = checkNotNull(blobStore, "blobStore");
this.utils = utils; this.utils = checkNotNull(utils, "utils");
this.blobRequestSigner = checkNotNull(blobRequestSigner, "blobRequestSigner");
} }
@Override @Override
@ -134,4 +136,9 @@ public class BlobStoreContextImpl<S, A> implements BlobStoreContext {
public boolean equals(Object obj) { public boolean equals(Object obj) {
return providerSpecificContext.equals(obj); return providerSpecificContext.equals(obj);
} }
@Override
public BlobRequestSigner getSigner() {
return blobRequestSigner;
}
} }

View File

@ -0,0 +1,50 @@
/**
*
* Copyright (C) 2010 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.blobstore.internal;
import javax.inject.Singleton;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.http.HttpRequest;
/**
*
* @author Adrian Cole
*/
@Singleton
public class RequestSigningUnsupported implements BlobRequestSigner {
@Override
public HttpRequest signGetBlob(String container, String name) {
throw new UnsupportedOperationException();
}
@Override
public HttpRequest signPutBlob(String container, Blob blob) {
throw new UnsupportedOperationException();
}
@Override
public HttpRequest signRemoveBlob(String container, String name) {
throw new UnsupportedOperationException();
}
}

View File

@ -37,14 +37,27 @@ import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata; import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.functions.ExceptionToValueOrPropagate; import org.jclouds.functions.ExceptionToValueOrPropagate;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.collect.ImmutableMultimap;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class BlobStoreUtils { public class BlobStoreUtils {
public static <T> HttpRequest cleanRequest(GeneratedHttpRequest<T> returnVal) {
for (HttpRequestFilter filter : returnVal.getFilters())
filter.filter(returnVal);
HttpRequest toReturn = new HttpRequest(returnVal.getMethod(), returnVal.getEndpoint(), ImmutableMultimap
.copyOf(returnVal.getHeaders()));
if (returnVal.getPayload() != null)
toReturn.setPayload(returnVal.getPayload());
return toReturn;
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static final ExceptionToValueOrPropagate keyNotFoundToNullOrPropagate = new ExceptionToValueOrPropagate( public static final ExceptionToValueOrPropagate keyNotFoundToNullOrPropagate = new ExceptionToValueOrPropagate(
@ -131,8 +144,7 @@ public class BlobStoreUtils {
} }
} }
public static void createParentIfNeededAsync(AsyncBlobStore asyncBlobStore, String container, public static void createParentIfNeededAsync(AsyncBlobStore asyncBlobStore, String container, Blob blob) {
Blob blob) {
String name = blob.getMetadata().getName(); String name = blob.getMetadata().getName();
if (name.indexOf('/') > 0) { if (name.indexOf('/') > 0) {
asyncBlobStore.createDirectory(container, parseDirectoryFromPath(name)); asyncBlobStore.createDirectory(container, parseDirectoryFromPath(name));

View File

@ -28,8 +28,6 @@ import java.net.URLConnection;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.crypto.CryptoStreams; import org.jclouds.crypto.CryptoStreams;
import org.jclouds.http.HttpRequest;
import org.jclouds.util.Utils;
import org.testng.annotations.Optional; import org.testng.annotations.Optional;
import org.testng.annotations.Parameters; import org.testng.annotations.Parameters;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -76,26 +74,4 @@ public class BaseBlobLiveTest extends BaseBlobStoreIntegrationTest {
} }
} }
@Test
public void testSignUrl() throws Exception {
String name = "hello";
String text = "fooooooooooooooooooooooo";
Blob blob = context.getBlobStore().newBlob(name);
blob.setPayload(text);
blob.getPayload().setContentType("text/plain");
String container = getContainerName();
try {
context.getBlobStore().putBlob(container, blob);
HttpRequest request = context.getBlobStore().signRequestForBlob(container, name);
assertEquals(request.getFilters().size(), 0);
assertEquals(Utils.toStringAndClose(context.utils().http().get(request)), text);
request = context.getAsyncBlobStore().signRequestForBlob(container, name);
assertEquals(request.getFilters().size(), 0);
assertEquals(Utils.toStringAndClose(context.utils().http().get(request)), text);
} finally {
returnContainer(container);
}
}
} }

View File

@ -0,0 +1,97 @@
/**
*
* Copyright (C) 2010 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.blobstore.integration.internal;
import static org.testng.Assert.assertEquals;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.http.HttpRequest;
import org.jclouds.util.Utils;
import org.testng.annotations.Test;
/**
* Tests integrated functionality of all signature commands.
* <p/>
* Each test uses a different container name, so it should be perfectly fine to run in parallel.
*
* @author Adrian Cole
*/
@Test(groups = { "live" }, testName = "blobstore.BlobLiveTest")
public class BaseBlobSignerLiveTest extends BaseBlobStoreIntegrationTest {
@Test
public void testSignRemoveUrl() throws Exception {
String name = "hello";
String text = "fooooooooooooooooooooooo";
Blob blob = context.getBlobStore().newBlob(name);
blob.setPayload(text);
blob.getPayload().setContentType("text/plain");
String container = getContainerName();
try {
context.getBlobStore().putBlob(container, blob);
HttpRequest request = context.getSigner().signRemoveBlob(container, name);
assertEquals(request.getFilters().size(), 0);
context.utils().http().invoke(request);
assert !context.getBlobStore().blobExists(container, name);
} finally {
returnContainer(container);
}
}
@Test
public void testSignGetUrl() throws Exception {
String name = "hello";
String text = "fooooooooooooooooooooooo";
Blob blob = context.getBlobStore().newBlob(name);
blob.setPayload(text);
blob.getPayload().setContentType("text/plain");
String container = getContainerName();
try {
context.getBlobStore().putBlob(container, blob);
HttpRequest request = context.getSigner().signGetBlob(container, name);
assertEquals(request.getFilters().size(), 0);
assertEquals(Utils.toStringAndClose(context.utils().http().invoke(request)), text);
} finally {
returnContainer(container);
}
}
@Test
public void testSignPutUrl() throws Exception {
String name = "hello";
String text = "fooooooooooooooooooooooo";
Blob blob = context.getBlobStore().newBlob(name);
blob.setPayload(text);
blob.getPayload().setContentType("text/plain");
String container = getContainerName();
try {
HttpRequest request = context.getSigner().signPutBlob(container, blob);
assertEquals(request.getFilters().size(), 0);
Utils.toStringAndClose(context.utils().http().invoke(request));
assert context.getBlobStore().blobExists(container, name);
} finally {
returnContainer(container);
}
}
}

View File

@ -36,6 +36,6 @@ import com.google.common.base.Function;
public class ReturnInputStream implements Function<HttpResponse, InputStream> { public class ReturnInputStream implements Function<HttpResponse, InputStream> {
public InputStream apply(HttpResponse from) { public InputStream apply(HttpResponse from) {
return from.getPayload().getInput(); return from.getPayload() != null ? from.getPayload().getInput() : null;
} }
} }

View File

@ -0,0 +1,50 @@
/**
*
* Copyright (C) 2010 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.io.payloads;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.annotation.Nullable;
/**
* @author Adrian Cole
*/
public class PhantomPayload extends BasePayload<Object> {
public PhantomPayload(@Nullable Long contentLength, @Nullable byte[] contentMD5) {
super(Object.class, null, contentLength, contentMD5);
}
/**
* {@inheritDoc}
*/
@Override
public InputStream getInput() {
throw new UnsupportedOperationException();
}
@Override
public void writeTo(OutputStream outstream) throws IOException {
throw new UnsupportedOperationException();
}
}

View File

@ -92,8 +92,9 @@ public interface HttpAsyncClient {
/** /**
* @see HttpClient#get * @see HttpClient#get
*/ */
@Path("")
@ExceptionParser(ReturnNullOnNotFoundOr404.class) @ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<InputStream> get(HttpRequest location); ListenableFuture<InputStream> invoke(HttpRequest location);
@GET @GET
@Path("") @Path("")

View File

@ -63,10 +63,7 @@ public interface HttpClient {
*/ */
InputStream get(URI location); InputStream get(URI location);
/** InputStream invoke(HttpRequest location);
* @return null if the resource didn't exist.
*/
InputStream get(HttpRequest location);
InputStream get(URI location, HttpRequestOptions options); InputStream get(URI location, HttpRequestOptions options);

View File

@ -84,23 +84,29 @@ public abstract class BaseRestClientTest {
propagate(e); propagate(e);
} }
assertEquals(payload, toMatch); assertEquals(payload, toMatch);
if (request.getFirstHeaderOrNull(TRANSFER_ENCODING) == null) { Long length = new Long(payload.getBytes().length);
assertEquals(request.getPayload().getContentLength(), new Long(payload.getBytes().length));
} else {
assertEquals(request.getFirstHeaderOrNull(TRANSFER_ENCODING), "chunked");
assert request.getPayload().getContentLength() == null
|| request.getPayload().getContentLength().equals(new Long(payload.getBytes().length));
}
assertEquals(request.getPayload().getContentType(), contentType);
try { try {
assertEquals(request.getPayload().getContentMD5(), contentMD5 ? CryptoStreams.md5(request.getPayload()) assertContentHeadersEqual(request, contentType, length, contentMD5 ? CryptoStreams
: null); .md5(request.getPayload()) : null);
} catch (IOException e) { } catch (IOException e) {
propagate(e); propagate(e);
} }
} }
} }
protected void assertContentHeadersEqual(HttpRequest request, String contentType, Long length, byte[] contentMD5) {
if (request.getFirstHeaderOrNull(TRANSFER_ENCODING) == null) {
assertEquals(request.getPayload().getContentLength(), length);
} else {
assertEquals(request.getFirstHeaderOrNull(TRANSFER_ENCODING), "chunked");
assert request.getPayload().getContentLength() == null
|| request.getPayload().getContentLength().equals(length);
}
assertEquals(request.getPayload().getContentType(), contentType);
assertEquals(request.getPayload().getContentMD5(), contentMD5);
}
protected void assertNonPayloadHeadersEqual(HttpRequest request, String toMatch) { protected void assertNonPayloadHeadersEqual(HttpRequest request, String toMatch) {
assertEquals(sortAndConcatHeadersIntoString(request.getHeaders()), toMatch); assertEquals(sortAndConcatHeadersIntoString(request.getHeaders()), toMatch);
} }

View File

@ -40,7 +40,6 @@ import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore; import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata; import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.concurrent.Futures; import org.jclouds.concurrent.Futures;
@ -89,8 +88,8 @@ public class CloudFilesAsyncBlobStore extends BaseAsyncBlobStore {
BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions, BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob, BlobToObject blob2Object, ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob, BlobToObject blob2Object,
ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions, ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider, SignRequestForBlobStrategy signRequestForBlob) { Provider<FetchBlobMetadata> fetchBlobMetadataProvider) {
super(context, blobUtils, service, defaultLocation, locations, signRequestForBlob); super(context, blobUtils, service, defaultLocation, locations);
this.sync = sync; this.sync = sync;
this.async = async; this.async = async;
this.container2ResourceMd = container2ResourceMd; this.container2ResourceMd = container2ResourceMd;

View File

@ -0,0 +1,77 @@
/**
*
* Copyright (C) 2010 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.rackspace.cloudfiles.blobstore;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.blobstore.util.BlobStoreUtils.cleanRequest;
import java.lang.reflect.Method;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.options.GetOptions;
import org.jclouds.rackspace.cloudfiles.CloudFilesAsyncClient;
import org.jclouds.rackspace.cloudfiles.blobstore.functions.BlobToObject;
import org.jclouds.rackspace.cloudfiles.domain.CFObject;
import org.jclouds.rest.internal.RestAnnotationProcessor;
/**
*
* @author Adrian Cole
*/
@Singleton
public class CloudFilesBlobRequestSigner implements BlobRequestSigner {
private final RestAnnotationProcessor<CloudFilesAsyncClient> processor;
private final BlobToObject blobToObject;
private final Method getMethod;
private final Method deleteMethod;
private final Method createMethod;
@Inject
public CloudFilesBlobRequestSigner(RestAnnotationProcessor<CloudFilesAsyncClient> processor, BlobToObject blobToObject)
throws SecurityException, NoSuchMethodException {
this.processor = checkNotNull(processor, "processor");
this.blobToObject = checkNotNull(blobToObject, "blobToObject");
this.getMethod = CloudFilesAsyncClient.class.getMethod("getObject", String.class, String.class, GetOptions[].class);
this.deleteMethod = CloudFilesAsyncClient.class.getMethod("removeObject", String.class, String.class);
this.createMethod = CloudFilesAsyncClient.class.getMethod("putObject", String.class, CFObject.class);
}
@Override
public HttpRequest signGetBlob(String container, String name) {
return cleanRequest(processor.createRequest(getMethod, container, name));
}
@Override
public HttpRequest signPutBlob(String container, Blob blob) {
return cleanRequest(processor.createRequest(createMethod, container, blobToObject.apply(blob)));
}
@Override
public HttpRequest signRemoveBlob(String container, String name) {
return cleanRequest(processor.createRequest(deleteMethod, container, name));
}
}

View File

@ -37,7 +37,6 @@ import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseBlobStore; import org.jclouds.blobstore.internal.BaseBlobStore;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata; import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
@ -78,8 +77,8 @@ public class CloudFilesBlobStore extends BaseBlobStore {
BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions, BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob, BlobToObject blob2Object, ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob, BlobToObject blob2Object,
ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions, ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider, SignRequestForBlobStrategy signRequestForBlob) { Provider<FetchBlobMetadata> fetchBlobMetadataProvider) {
super(context, blobUtils, defaultLocation, locations, signRequestForBlob); super(context, blobUtils, defaultLocation, locations);
this.sync = sync; this.sync = sync;
this.container2ResourceMd = container2ResourceMd; this.container2ResourceMd = container2ResourceMd;
this.container2ContainerListOptions = container2ContainerListOptions; this.container2ContainerListOptions = container2ContainerListOptions;

View File

@ -24,18 +24,18 @@ import java.util.Set;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.blobstore.AsyncBlobStore; import org.jclouds.blobstore.AsyncBlobStore;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.attr.ConsistencyModel; import org.jclouds.blobstore.attr.ConsistencyModel;
import org.jclouds.blobstore.config.BlobStoreMapModule; import org.jclouds.blobstore.config.BlobStoreMapModule;
import org.jclouds.blobstore.internal.BlobStoreContextImpl; import org.jclouds.blobstore.internal.BlobStoreContextImpl;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.rackspace.cloudfiles.CloudFilesAsyncClient; import org.jclouds.rackspace.cloudfiles.CloudFilesAsyncClient;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient; import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import org.jclouds.rackspace.cloudfiles.blobstore.CloudFilesAsyncBlobStore; import org.jclouds.rackspace.cloudfiles.blobstore.CloudFilesAsyncBlobStore;
import org.jclouds.rackspace.cloudfiles.blobstore.CloudFilesBlobRequestSigner;
import org.jclouds.rackspace.cloudfiles.blobstore.CloudFilesBlobStore; import org.jclouds.rackspace.cloudfiles.blobstore.CloudFilesBlobStore;
import org.jclouds.rackspace.cloudfiles.blobstore.strategy.SignGetObject;
import org.jclouds.rackspace.config.RackspaceLocationsModule; import org.jclouds.rackspace.config.RackspaceLocationsModule;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
@ -63,7 +63,7 @@ public class CloudFilesBlobStoreContextModule extends AbstractModule {
bind(BlobStore.class).to(CloudFilesBlobStore.class).in(Scopes.SINGLETON); bind(BlobStore.class).to(CloudFilesBlobStore.class).in(Scopes.SINGLETON);
bind(BlobStoreContext.class).to(new TypeLiteral<BlobStoreContextImpl<CloudFilesClient, CloudFilesAsyncClient>>() { bind(BlobStoreContext.class).to(new TypeLiteral<BlobStoreContextImpl<CloudFilesClient, CloudFilesAsyncClient>>() {
}).in(Scopes.SINGLETON); }).in(Scopes.SINGLETON);
bind(SignRequestForBlobStrategy.class).to(SignGetObject.class); bind(BlobRequestSigner.class).to(CloudFilesBlobRequestSigner.class);
} }
@Provides @Provides

View File

@ -1,64 +0,0 @@
/**
*
* Copyright (C) 2010 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.rackspace.cloudfiles.blobstore.strategy;
import static com.google.common.base.Preconditions.checkNotNull;
import java.lang.reflect.Method;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.blobstore.strategy.SignRequestForBlobStrategy;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.options.GetOptions;
import org.jclouds.rackspace.cloudfiles.CloudFilesAsyncClient;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import com.google.common.collect.ImmutableMultimap;
/**
*
* @author Adrian Cole
*/
@Singleton
public class SignGetObject implements SignRequestForBlobStrategy {
private final RestAnnotationProcessor<CloudFilesAsyncClient> processor;
private final Method method;
@Inject
public SignGetObject(RestAnnotationProcessor<CloudFilesAsyncClient> processor) throws SecurityException,
NoSuchMethodException {
this.processor = checkNotNull(processor, "processor");
this.method = CloudFilesAsyncClient.class.getMethod("getObject", String.class, String.class, GetOptions[].class);
}
@Override
public HttpRequest apply(String container, String name) {
HttpRequest returnVal = processor.createRequest(method, checkNotNull(container,
"container"), checkNotNull(name, "name"));
for (HttpRequestFilter filter : returnVal.getFilters())
filter.filter(returnVal);
returnVal.getFilters().clear();
return new HttpRequest(returnVal.getMethod(), returnVal.getEndpoint(), ImmutableMultimap.copyOf(returnVal.getHeaders()));
}
}

View File

@ -0,0 +1,116 @@
/**
*
* Copyright (C) 2010 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.rackspace.cloudfiles.blobstore;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Properties;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.http.HttpRequest;
import org.jclouds.io.payloads.PhantomPayload;
import org.jclouds.rackspace.cloudfiles.CloudFilesAsyncClient;
import org.jclouds.rackspace.cloudfiles.config.CloudFilesRestClientModule;
import org.jclouds.rackspace.cloudservers.TestRackspaceAuthenticationRestClientModule;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.RestContextFactory.ContextSpec;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
@Test(groups = "unit", testName = "cloudfiles.CloudFilesBlobRequestSignerTest")
public class CloudFilesBlobRequestSignerTest extends RestClientTest<CloudFilesAsyncClient> {
private BlobRequestSigner signer;
private Factory blobFactory;
public void testSignGetBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
HttpRequest request = signer.signGetBlob("container", "name");
assertRequestLineEquals(request, "GET http://storageUrl/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(request, "X-Auth-Token: testtoken\n");
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
public void testSignRemoveBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
HttpRequest request = signer.signRemoveBlob("container", "name");
assertRequestLineEquals(request, "DELETE http://storageUrl/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(request, "X-Auth-Token: testtoken\n");
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
public void testSignPutBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
Blob blob = blobFactory.create(null);
blob.getMetadata().setName("name");
blob.setPayload(new PhantomPayload(2l, new byte[] { 0, 2, 4, 8 }));
blob.getPayload().setContentType("text/plain");
HttpRequest request = signer.signPutBlob("container", blob);
assertRequestLineEquals(request, "PUT http://storageUrl/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(request, "X-Auth-Token: testtoken\n");
assertContentHeadersEqual(request, "text/plain", (long) 2l, new byte[] { 0, 2, 4, 8 });
assertEquals(request.getFilters().size(), 0);
}
@BeforeClass
protected void setupFactory() throws IOException {
super.setupFactory();
this.blobFactory = injector.getInstance(Blob.Factory.class);
this.signer = injector.getInstance(BlobRequestSigner.class);
}
@Override
protected void checkFilters(HttpRequest request) {
}
@Override
protected TypeLiteral<RestAnnotationProcessor<CloudFilesAsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<CloudFilesAsyncClient>>() {
};
}
@Override
protected Module createModule() {
return new CloudFilesRestClientModule(new TestRackspaceAuthenticationRestClientModule());
}
@Override
public ContextSpec<?, ?> createContextSpec() {
return new RestContextFactory().createContextSpec("cloudfiles", "identity", "credential", new Properties());
}
}

View File

@ -0,0 +1,32 @@
/**
*
* Copyright (C) 2010 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.rackspace.cloudfiles.blobstore.integration;
import org.jclouds.blobstore.integration.internal.BaseBlobSignerLiveTest;
import org.testng.annotations.Test;
/**
*
* @author Adrian Cole
*/
@Test(groups = { "live" }, testName = "cloudfiles.CloudFilesBlobSignerLiveTest")
public class CloudFilesBlobSignerLiveTest extends BaseBlobSignerLiveTest {
}

View File

@ -1,60 +0,0 @@
package org.jclouds.rackspace.cloudfiles.blobstore.strategy;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Properties;
import org.jclouds.http.HttpRequest;
import org.jclouds.rackspace.cloudfiles.CloudFilesAsyncClient;
import org.jclouds.rackspace.cloudfiles.config.CloudFilesRestClientModule;
import org.jclouds.rackspace.cloudservers.TestRackspaceAuthenticationRestClientModule;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.RestContextFactory.ContextSpec;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.Test;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of {@code SignGetBlob}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "cloudfiles.SignGetBlobTest")
public class SignGetBlobTest extends RestClientTest<CloudFilesAsyncClient> {
public void testSignGetBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
HttpRequest request = new SignGetObject(processor).apply("container", "blob");
assertRequestLineEquals(request, "GET http://storageUrl/container/blob HTTP/1.1");
assertNonPayloadHeadersEqual(request, "X-Auth-Token: testtoken\n");
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
protected Module createModule() {
return new CloudFilesRestClientModule(new TestRackspaceAuthenticationRestClientModule());
}
@Override
protected void checkFilters(HttpRequest request) {
}
@Override
protected TypeLiteral<RestAnnotationProcessor<CloudFilesAsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<CloudFilesAsyncClient>>() {
};
}
@Override
public ContextSpec<?, ?> createContextSpec() {
return new RestContextFactory().createContextSpec("cloudfiles", "identity", "credential", new Properties());
}
}