enforced blobs must have uri, container, and can have publicAccess

This commit is contained in:
Adrian Cole 2011-04-03 18:15:09 -07:00
parent fc8bb96363
commit 53c735fdff
91 changed files with 2222 additions and 980 deletions

View File

@ -51,6 +51,7 @@ import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.collect.Memoized;
@ -258,4 +259,12 @@ public class AtmosAsyncBlobStore extends BaseAsyncBlobStore {
return putBlob(container, blob);
}
@Override
public ListenableFuture<Boolean> createContainerInLocation(Location location, String container,
CreateContainerOptions options) {
if (options.isPublicRead())
throw new UnsupportedOperationException("publicRead");
return createContainerInLocation(location, container);
}
}

View File

@ -43,6 +43,7 @@ import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.collect.Memoized;
@ -225,4 +226,10 @@ public class AtmosBlobStore extends BaseBlobStore {
sync.deletePath(container + "/" + key);
}
@Override
public boolean createContainerInLocation(Location location, String container, CreateContainerOptions options) {
if (options.isPublicRead())
throw new UnsupportedOperationException("publicRead");
return createContainerInLocation(location, container);
}
}

View File

@ -36,8 +36,8 @@ import org.jclouds.io.payloads.BaseMutableContentMetadata;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
/**
* @author Adrian Cole
@ -61,10 +61,11 @@ public class DirectoryEntryListToResourceMetadataList implements
StorageType type = from.getType() == FileType.DIRECTORY ? StorageType.FOLDER : StorageType.BLOB;
if (type == StorageType.FOLDER)
return new StorageMetadataImpl(type, from.getObjectID(), from.getObjectName(), defaultLocation
.get(), null, null, null, Maps.<String, String> newHashMap());
.get(), null, null, null,ImmutableMap.<String,String>of());
else
return new BlobMetadataImpl(from.getObjectID(), from.getObjectName(), defaultLocation.get(),
null, null, null, Maps.<String, String> newHashMap(), new BaseMutableContentMetadata());
null, null, null,ImmutableMap.<String,String>of(), null,
null, new BaseMutableContentMetadata());
}
}), from.getToken());

View File

@ -33,7 +33,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.functions.ThrowContainerNotFoundOn404;
import org.jclouds.blobstore.functions.ReturnNullOnContainerNotFound;
import org.jclouds.cloudfiles.domain.ContainerCDNMetadata;
import org.jclouds.cloudfiles.functions.ParseCdnUriFromHeaders;
import org.jclouds.cloudfiles.functions.ParseContainerCDNMetadataFromHeaders;
@ -86,7 +86,7 @@ public interface CloudFilesAsyncClient extends CommonSwiftAsyncClient {
*/
@HEAD
@ResponseParser(ParseContainerCDNMetadataFromHeaders.class)
@ExceptionParser(ThrowContainerNotFoundOn404.class)
@ExceptionParser(ReturnNullOnContainerNotFound.class)
@Path("/{container}")
@Endpoint(CDNManagement.class)
ListenableFuture<ContainerCDNMetadata> getCDNMetadata(@PathParam("container") String container);

View File

@ -23,10 +23,10 @@ import java.util.List;
import java.util.Properties;
import org.jclouds.blobstore.BlobStoreContextBuilder;
import org.jclouds.cloudfiles.blobstore.config.CloudFilesBlobStoreContextModule;
import org.jclouds.cloudfiles.config.CloudFilesRestClientModule;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule;
import org.jclouds.cloudfiles.config.CloudFilesRestClientModule;
import com.google.inject.Injector;
import com.google.inject.Module;
@ -44,8 +44,7 @@ import com.google.inject.Module;
* @author Adrian Cole, Andrew Newdigate
* @see CloudFilesBlobStoreContext
*/
public class CloudFilesContextBuilder extends
BlobStoreContextBuilder<CloudFilesClient, CloudFilesAsyncClient> {
public class CloudFilesContextBuilder extends BlobStoreContextBuilder<CloudFilesClient, CloudFilesAsyncClient> {
public CloudFilesContextBuilder(Properties props) {
super(CloudFilesClient.class, CloudFilesAsyncClient.class, props);
@ -53,7 +52,7 @@ public class CloudFilesContextBuilder extends
@Override
protected void addContextModule(List<Module> modules) {
modules.add(new SwiftBlobStoreContextModule());
modules.add(new CloudFilesBlobStoreContextModule());
}
@Override

View File

@ -0,0 +1,96 @@
/**
*
* 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.cloudfiles.blobstore;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.cloudfiles.CloudFilesAsyncClient;
import org.jclouds.cloudfiles.CloudFilesClient;
import org.jclouds.cloudfiles.blobstore.functions.EnableCDNAndCache;
import org.jclouds.collect.Memoized;
import org.jclouds.concurrent.Futures;
import org.jclouds.domain.Location;
import org.jclouds.openstack.swift.blobstore.SwiftAsyncBlobStore;
import org.jclouds.openstack.swift.blobstore.functions.BlobStoreListContainerOptionsToListContainerOptions;
import org.jclouds.openstack.swift.blobstore.functions.BlobToObject;
import org.jclouds.openstack.swift.blobstore.functions.ContainerToResourceList;
import org.jclouds.openstack.swift.blobstore.functions.ContainerToResourceMetadata;
import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlob;
import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlobMetadata;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.util.concurrent.ListenableFuture;
/**
*
* @author Adrian Cole
*/
@Singleton
public class CloudFilesAsyncBlobStore extends SwiftAsyncBlobStore {
private final EnableCDNAndCache enableCDNAndCache;
@Inject
protected CloudFilesAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations, CloudFilesClient sync, CloudFilesAsyncClient async,
ContainerToResourceMetadata container2ResourceMd,
BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob, BlobToObject blob2Object,
ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider, EnableCDNAndCache enableCDNAndCache) {
super(context, blobUtils, service, defaultLocation, locations, sync, async, container2ResourceMd,
container2ContainerListOptions, container2ResourceList, object2Blob, blob2Object, object2BlobMd,
blob2ObjectGetOptions, fetchBlobMetadataProvider);
this.enableCDNAndCache = enableCDNAndCache;
}
@Override
public ListenableFuture<Boolean> createContainerInLocation(Location location, final String container,
CreateContainerOptions options) {
ListenableFuture<Boolean> returnVal = createContainerInLocation(location, container);
if (options.isPublicRead())
return Futures.compose(createContainerInLocation(location, container), new Function<Boolean, Boolean>() {
@Override
public Boolean apply(Boolean input) {
if (Boolean.TRUE.equals(input)) {
return enableCDNAndCache.apply(container) != null;
}
return false;
}
}, service);
return returnVal;
}
}

View File

@ -0,0 +1,61 @@
package org.jclouds.cloudfiles.blobstore;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.cloudfiles.blobstore.functions.EnableCDNAndCache;
import org.jclouds.collect.Memoized;
import org.jclouds.domain.Location;
import org.jclouds.openstack.swift.CommonSwiftClient;
import org.jclouds.openstack.swift.blobstore.SwiftBlobStore;
import org.jclouds.openstack.swift.blobstore.functions.BlobStoreListContainerOptionsToListContainerOptions;
import org.jclouds.openstack.swift.blobstore.functions.BlobToObject;
import org.jclouds.openstack.swift.blobstore.functions.ContainerToResourceList;
import org.jclouds.openstack.swift.blobstore.functions.ContainerToResourceMetadata;
import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlob;
import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlobMetadata;
import com.google.common.base.Supplier;
/**
*
* @author Adrian Cole
*/
@Singleton
public class CloudFilesBlobStore extends SwiftBlobStore {
private EnableCDNAndCache enableCDNAndCache;
@Inject
protected CloudFilesBlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations, CommonSwiftClient sync,
ContainerToResourceMetadata container2ResourceMd,
BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob, BlobToObject blob2Object,
ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider, EnableCDNAndCache enableCDNAndCache) {
super(context, blobUtils, defaultLocation, locations, sync, container2ResourceMd, container2ContainerListOptions,
container2ResourceList, object2Blob, blob2Object, object2BlobMd, blob2ObjectGetOptions,
fetchBlobMetadataProvider);
this.enableCDNAndCache = enableCDNAndCache;
}
@Override
public boolean createContainerInLocation(Location location, String container, CreateContainerOptions options) {
try {
return createContainerInLocation(location, container);
} finally {
if (options.isPublicRead())
enableCDNAndCache.apply(container);
}
}
}

View File

@ -0,0 +1,71 @@
/**
*
* 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.cloudfiles.blobstore.config;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.inject.Singleton;
import org.jclouds.cloudfiles.CloudFilesClient;
import org.jclouds.cloudfiles.blobstore.CloudFilesAsyncBlobStore;
import org.jclouds.cloudfiles.blobstore.CloudFilesBlobStore;
import org.jclouds.cloudfiles.blobstore.functions.CloudFilesObjectToBlobMetadata;
import org.jclouds.cloudfiles.domain.ContainerCDNMetadata;
import org.jclouds.openstack.swift.blobstore.SwiftAsyncBlobStore;
import org.jclouds.openstack.swift.blobstore.SwiftBlobStore;
import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule;
import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlobMetadata;
import com.google.common.base.Function;
import com.google.common.collect.MapMaker;
import com.google.inject.Provides;
/**
*
* @author Adrian Cole
*/
public class CloudFilesBlobStoreContextModule extends SwiftBlobStoreContextModule {
@Provides
@Singleton
protected Map<String, URI> cdnContainer(final CloudFilesClient client) {
return new MapMaker().expireAfterWrite(30, TimeUnit.SECONDS).makeComputingMap(new Function<String, URI>() {
public URI apply(String container) {
ContainerCDNMetadata md = client.getCDNMetadata(container);
return md != null ? md.getCDNUri() : null;
}
@Override
public String toString() {
return "getCDNMetadata()";
}
});
}
@Override
protected void configure() {
super.configure();
bind(SwiftBlobStore.class).to(CloudFilesBlobStore.class);
bind(SwiftAsyncBlobStore.class).to(CloudFilesAsyncBlobStore.class);
bind(ObjectToBlobMetadata.class).to(CloudFilesObjectToBlobMetadata.class);
}
}

View File

@ -0,0 +1,51 @@
/**
*
* 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.cloudfiles.blobstore.functions;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.blobstore.domain.MutableBlobMetadata;
import org.jclouds.blobstore.strategy.IfDirectoryReturnNameStrategy;
import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlobMetadata;
import org.jclouds.openstack.swift.domain.ObjectInfo;
/**
* @author Adrian Cole
*/
@Singleton
public class CloudFilesObjectToBlobMetadata extends ObjectToBlobMetadata {
private final PublicUriForObjectInfo publicUriForObjectInfo;
@Inject
public CloudFilesObjectToBlobMetadata(IfDirectoryReturnNameStrategy ifDirectoryReturnName,
PublicUriForObjectInfo publicUriForObjectInfo) {
super(ifDirectoryReturnName);
this.publicUriForObjectInfo = publicUriForObjectInfo;
}
public MutableBlobMetadata apply(ObjectInfo from) {
if (from == null)
return null;
MutableBlobMetadata to = super.apply(from);
to.setPublicUri(publicUriForObjectInfo.apply(from));
return to;
}
}

View File

@ -0,0 +1,54 @@
/**
*
* 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.cloudfiles.blobstore.functions;
import java.net.URI;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.cloudfiles.CloudFilesClient;
import com.google.common.base.Function;
/**
*
* @author Adrian Cole
*/
@Singleton
public class EnableCDNAndCache implements Function<String, URI> {
private final Map<String, URI> cdnContainer;
private final CloudFilesClient sync;
@Inject
public EnableCDNAndCache(CloudFilesClient sync, Map<String, URI> cdnContainer) {
this.sync = sync;
this.cdnContainer = cdnContainer;
}
@Override
public URI apply(String input) {
URI uri = sync.enableCDN(input);
cdnContainer.put(input, uri);
return uri;
}
}

View File

@ -0,0 +1,59 @@
/**
*
* 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.cloudfiles.blobstore.functions;
import java.net.URI;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.openstack.swift.domain.ObjectInfo;
import com.google.common.base.Function;
/**
* @author Adrian Cole
*/
@Singleton
public class PublicUriForObjectInfo implements Function<ObjectInfo, URI> {
private final Map<String, URI> cdnContainer;
private final Provider<UriBuilder> uriBuilders;
@Inject
public PublicUriForObjectInfo(Map<String, URI> cdnContainer, Provider<UriBuilder> uriBuilders) {
this.cdnContainer = cdnContainer;
this.uriBuilders = uriBuilders;
}
public URI apply(ObjectInfo from) {
if (from == null)
return null;
try {
return uriBuilders.get().uri(cdnContainer.get(from.getContainer())).path(from.getName()).replaceQuery("")
.build();
} catch (NullPointerException e) {
// MapMaker constructed maps are not allowed to return null;
return null;
}
}
}

View File

@ -21,7 +21,6 @@ package org.jclouds.cloudfiles.domain;
import java.net.URI;
/**
*
* @author James Murty
@ -79,11 +78,7 @@ public class ContainerCDNMetadata implements Comparable<ContainerCDNMetadata> {
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (cdn_enabled ? 1231 : 1237);
result = prime * result + ((cdn_uri == null) ? 0 : cdn_uri.hashCode());
result = prime * result + (log_retention ? 1231 : 1237);
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + (int) (ttl ^ (ttl >>> 32));
return result;
}
@ -96,22 +91,11 @@ public class ContainerCDNMetadata implements Comparable<ContainerCDNMetadata> {
if (getClass() != obj.getClass())
return false;
ContainerCDNMetadata other = (ContainerCDNMetadata) obj;
if (cdn_enabled != other.cdn_enabled)
return false;
if (cdn_uri == null) {
if (other.cdn_uri != null)
return false;
} else if (!cdn_uri.equals(other.cdn_uri))
return false;
if (log_retention != other.log_retention)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (ttl != other.ttl)
return false;
return true;
}
@ -129,8 +113,8 @@ public class ContainerCDNMetadata implements Comparable<ContainerCDNMetadata> {
@Override
public String toString() {
return "ContainerCDNMetadata [cdn_enabled=" + cdn_enabled + ", cdn_uri=" + cdn_uri
+ ", log_retention=" + log_retention + ", name=" + name + ", referrer_acl="
+ referrer_acl + ", ttl=" + ttl + ", useragent_acl=" + useragent_acl + "]";
return String.format(
"[name=%s, cdn_uri=%s, cdn_enabled=%s, log_retention=%s, referrer_acl=%s, ttl=%s, useragent_acl=%s]",
name, cdn_uri, cdn_enabled, log_retention, referrer_acl, ttl, useragent_acl);
}
}

View File

@ -25,10 +25,8 @@ import static org.testng.Assert.assertTrue;
import java.net.URI;
import java.util.Set;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.cloudfiles.domain.ContainerCDNMetadata;
import org.jclouds.cloudfiles.options.ListCdnContainerOptions;
import org.jclouds.http.HttpResponseException;
import org.jclouds.openstack.swift.CommonSwiftClientLiveTest;
import org.testng.annotations.Test;
@ -74,28 +72,21 @@ public class CloudFilesClientLiveTest extends CommonSwiftClientLiveTest<CloudFil
assertTrue(cdnMetadata.isCDNEnabled());
assertEquals(cdnMetadata.getCDNUri(), cdnUri);
final long initialTTL = cdnMetadata.getTTL();
cdnMetadata = getApi().getCDNMetadata(containerNameWithoutCDN);
assert cdnMetadata == null || !cdnMetadata.isCDNEnabled() : containerNameWithoutCDN
+ " should not have metadata";
try {
cdnMetadata = getApi().getCDNMetadata(containerNameWithoutCDN);
assert cdnMetadata == null || !cdnMetadata.isCDNEnabled() : containerNameWithoutCDN
+ " should not have metadata";
} catch (ContainerNotFoundException e) {
} catch (HttpResponseException e) {
}
assert getApi().getCDNMetadata("DoesNotExist") == null;
try {
cdnMetadata = getApi().getCDNMetadata("DoesNotExist");
assert false : "should not exist";
} catch (ContainerNotFoundException e) {
} catch (HttpResponseException e) {
}
// List CDN metadata for containers, and ensure all CDN info is
// available for enabled
// container
Set<ContainerCDNMetadata> cdnMetadataList = getApi().listCDNContainers();
assertTrue(cdnMetadataList.size() >= 1);
final long initialTTL = cdnMetadata.getTTL();
assertTrue(cdnMetadataList.contains(new ContainerCDNMetadata(containerNameWithCDN, true, initialTTL, cdnUri)));
// Test listing with options

View File

@ -79,6 +79,7 @@ import org.jclouds.blobstore.domain.internal.MutableStorageMetadataImpl;
import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.HttpGetOptionsListToGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.GetOptions;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.IfDirectoryReturnNameStrategy;
@ -660,10 +661,17 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
String eTag = CryptoStreams.hex(object.getPayload().getContentMetadata().getContentMD5());
return eTag;
}
@Override
public ListenableFuture<String> putBlobMultipart(String container, Blob blob) {
return putBlob(container, blob);
}
@Override
public ListenableFuture<Boolean> createContainerInLocation(Location location, String container,
CreateContainerOptions options) {
if (options.isPublicRead())
throw new UnsupportedOperationException("publicRead");
return createContainerInLocation(location, container);
}
}

View File

@ -21,6 +21,7 @@ package org.jclouds.s3.blobstore;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@ -30,19 +31,6 @@ import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.s3.S3AsyncClient;
import org.jclouds.s3.S3Client;
import org.jclouds.s3.blobstore.functions.BlobToObject;
import org.jclouds.s3.blobstore.functions.BucketToResourceList;
import org.jclouds.s3.blobstore.functions.BucketToResourceMetadata;
import org.jclouds.s3.blobstore.functions.ContainerToBucketListOptions;
import org.jclouds.s3.blobstore.functions.ObjectToBlob;
import org.jclouds.s3.blobstore.functions.ObjectToBlobMetadata;
import org.jclouds.s3.domain.BucketMetadata;
import org.jclouds.s3.domain.ListBucketResponse;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.s3.options.ListBucketOptions;
import org.jclouds.s3.util.S3Utils;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
@ -51,6 +39,7 @@ import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils;
@ -58,6 +47,25 @@ import org.jclouds.collect.Memoized;
import org.jclouds.concurrent.Futures;
import org.jclouds.domain.Location;
import org.jclouds.http.options.GetOptions;
import org.jclouds.s3.S3AsyncClient;
import org.jclouds.s3.S3Client;
import org.jclouds.s3.blobstore.functions.BlobToObject;
import org.jclouds.s3.blobstore.functions.BucketToResourceList;
import org.jclouds.s3.blobstore.functions.BucketToResourceMetadata;
import org.jclouds.s3.blobstore.functions.ContainerToBucketListOptions;
import org.jclouds.s3.blobstore.functions.ObjectToBlob;
import org.jclouds.s3.blobstore.functions.ObjectToBlobMetadata;
import org.jclouds.s3.domain.AccessControlList;
import org.jclouds.s3.domain.BucketMetadata;
import org.jclouds.s3.domain.CannedAccessPolicy;
import org.jclouds.s3.domain.ListBucketResponse;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.s3.domain.AccessControlList.GroupGranteeURI;
import org.jclouds.s3.domain.AccessControlList.Permission;
import org.jclouds.s3.options.ListBucketOptions;
import org.jclouds.s3.options.PutBucketOptions;
import org.jclouds.s3.options.PutObjectOptions;
import org.jclouds.s3.util.S3Utils;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
@ -81,15 +89,16 @@ public class S3AsyncBlobStore extends BaseAsyncBlobStore {
private final BlobToObject blob2Object;
private final ObjectToBlobMetadata object2BlobMd;
private final Provider<FetchBlobMetadata> fetchBlobMetadataProvider;
private final Map<String, AccessControlList> bucketAcls;
@Inject
protected S3AsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations, S3AsyncClient async, S3Client sync,
BucketToResourceMetadata bucket2ResourceMd, ContainerToBucketListOptions container2BucketListOptions,
BucketToResourceList bucket2ResourceList, ObjectToBlob object2Blob,
BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider) {
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations, S3AsyncClient async, S3Client sync,
BucketToResourceMetadata bucket2ResourceMd, ContainerToBucketListOptions container2BucketListOptions,
BucketToResourceList bucket2ResourceList, ObjectToBlob object2Blob,
BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider, Map<String, AccessControlList> bucketAcls) {
super(context, blobUtils, service, defaultLocation, locations);
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
this.async = checkNotNull(async, "async");
@ -101,6 +110,7 @@ public class S3AsyncBlobStore extends BaseAsyncBlobStore {
this.blob2Object = checkNotNull(blob2Object, "blob2Object");
this.object2BlobMd = checkNotNull(object2BlobMd, "object2BlobMd");
this.fetchBlobMetadataProvider = checkNotNull(fetchBlobMetadataProvider, "fetchBlobMetadataProvider");
this.bucketAcls = checkNotNull(bucketAcls, "bucketAcls");
}
/**
@ -109,11 +119,11 @@ public class S3AsyncBlobStore extends BaseAsyncBlobStore {
@Override
public ListenableFuture<PageSet<? extends StorageMetadata>> list() {
return Futures.compose(async.listOwnedBuckets(),
new Function<Set<BucketMetadata>, org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>>() {
public org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata> apply(Set<BucketMetadata> from) {
return new PageSetImpl<StorageMetadata>(Iterables.transform(from, bucket2ResourceMd), null);
}
}, service);
new Function<Set<BucketMetadata>, org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>>() {
public org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata> apply(Set<BucketMetadata> from) {
return new PageSetImpl<StorageMetadata>(Iterables.transform(from, bucket2ResourceMd), null);
}
}, service);
}
/**
@ -137,8 +147,7 @@ public class S3AsyncBlobStore extends BaseAsyncBlobStore {
*/
@Override
public ListenableFuture<Boolean> createContainerInLocation(Location location, String container) {
location = location != null ? location : defaultLocation.get();
return async.putBucketInRegion(location.getId(), container);
return createContainerInLocation(location, container, CreateContainerOptions.NONE);
}
/**
@ -153,9 +162,9 @@ public class S3AsyncBlobStore extends BaseAsyncBlobStore {
ListBucketOptions httpOptions = container2BucketListOptions.apply(options);
ListenableFuture<ListBucketResponse> returnVal = async.listBucket(container, httpOptions);
ListenableFuture<PageSet<? extends StorageMetadata>> list = Futures.compose(returnVal, bucket2ResourceList,
service);
service);
return (options.isDetailed()) ? Futures.compose(list,
fetchBlobMetadataProvider.get().setContainerName(container), service) : list;
fetchBlobMetadataProvider.get().setContainerName(container), service) : list;
}
/**
@ -222,7 +231,11 @@ public class S3AsyncBlobStore extends BaseAsyncBlobStore {
*/
@Override
public ListenableFuture<String> putBlob(String container, Blob blob) {
return async.putObject(container, blob2Object.apply(blob));
PutObjectOptions options = new PutObjectOptions();
AccessControlList acl = bucketAcls.get(container);
if (acl != null && acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ))
options.withAcl(CannedAccessPolicy.PUBLIC_READ);
return async.putObject(container, blob2Object.apply(blob), options);
}
/**
@ -243,4 +256,14 @@ public class S3AsyncBlobStore extends BaseAsyncBlobStore {
return putBlob(container, blob);
}
@Override
public ListenableFuture<Boolean> createContainerInLocation(Location location, String container,
CreateContainerOptions options) {
PutBucketOptions putBucketOptions = new PutBucketOptions();
if (options.isPublicRead())
putBucketOptions.withBucketAcl(CannedAccessPolicy.PUBLIC_READ);
location = location != null ? location : defaultLocation.get();
return async.putBucketInRegion(location.getId(), container, putBucketOptions);
}
}

View File

@ -21,22 +21,13 @@ package org.jclouds.s3.blobstore;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.s3.S3Client;
import org.jclouds.s3.blobstore.functions.BlobToObject;
import org.jclouds.s3.blobstore.functions.BucketToResourceList;
import org.jclouds.s3.blobstore.functions.BucketToResourceMetadata;
import org.jclouds.s3.blobstore.functions.ContainerToBucketListOptions;
import org.jclouds.s3.blobstore.functions.ObjectToBlob;
import org.jclouds.s3.blobstore.functions.ObjectToBlobMetadata;
import org.jclouds.s3.domain.BucketMetadata;
import org.jclouds.s3.options.ListBucketOptions;
import org.jclouds.s3.util.S3Utils;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
@ -45,12 +36,29 @@ import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.collect.Memoized;
import org.jclouds.domain.Location;
import org.jclouds.http.options.GetOptions;
import org.jclouds.s3.S3Client;
import org.jclouds.s3.blobstore.functions.BlobToObject;
import org.jclouds.s3.blobstore.functions.BucketToResourceList;
import org.jclouds.s3.blobstore.functions.BucketToResourceMetadata;
import org.jclouds.s3.blobstore.functions.ContainerToBucketListOptions;
import org.jclouds.s3.blobstore.functions.ObjectToBlob;
import org.jclouds.s3.blobstore.functions.ObjectToBlobMetadata;
import org.jclouds.s3.domain.AccessControlList;
import org.jclouds.s3.domain.BucketMetadata;
import org.jclouds.s3.domain.CannedAccessPolicy;
import org.jclouds.s3.domain.AccessControlList.GroupGranteeURI;
import org.jclouds.s3.domain.AccessControlList.Permission;
import org.jclouds.s3.options.ListBucketOptions;
import org.jclouds.s3.options.PutBucketOptions;
import org.jclouds.s3.options.PutObjectOptions;
import org.jclouds.s3.util.S3Utils;
import org.jclouds.util.Assertions;
import com.google.common.base.Function;
@ -72,6 +80,7 @@ public class S3BlobStore extends BaseBlobStore {
private final ObjectToBlobMetadata object2BlobMd;
private final BlobToHttpGetOptions blob2ObjectGetOptions;
private final Provider<FetchBlobMetadata> fetchBlobMetadataProvider;
private final Map<String, AccessControlList> bucketAcls;
@Inject
protected S3BlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
@ -79,7 +88,7 @@ public class S3BlobStore extends BaseBlobStore {
BucketToResourceMetadata bucket2ResourceMd, ContainerToBucketListOptions container2BucketListOptions,
BucketToResourceList bucket2ResourceList, ObjectToBlob object2Blob,
BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider) {
Provider<FetchBlobMetadata> fetchBlobMetadataProvider, Map<String, AccessControlList> bucketAcls) {
super(context, blobUtils, defaultLocation, locations);
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
this.sync = checkNotNull(sync, "sync");
@ -90,6 +99,7 @@ public class S3BlobStore extends BaseBlobStore {
this.blob2Object = checkNotNull(blob2Object, "blob2Object");
this.object2BlobMd = checkNotNull(object2BlobMd, "object2BlobMd");
this.fetchBlobMetadataProvider = checkNotNull(fetchBlobMetadataProvider, "fetchBlobMetadataProvider");
this.bucketAcls = checkNotNull(bucketAcls, "bucketAcls");
}
/**
@ -125,8 +135,7 @@ public class S3BlobStore extends BaseBlobStore {
*/
@Override
public boolean createContainerInLocation(Location location, String container) {
location = location != null ? location : defaultLocation.get();
return sync.putBucketInRegion(location.getId(), container);
return createContainerInLocation(location, container, CreateContainerOptions.NONE);
}
/**
@ -222,7 +231,11 @@ public class S3BlobStore extends BaseBlobStore {
*/
@Override
public String putBlob(String container, Blob blob) {
return sync.putObject(container, blob2Object.apply(blob));
PutObjectOptions options = new PutObjectOptions();
AccessControlList acl = bucketAcls.get(container);
if (acl != null && acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ))
options.withAcl(CannedAccessPolicy.PUBLIC_READ);
return sync.putObject(container, blob2Object.apply(blob), options);
}
/**
@ -257,4 +270,13 @@ public class S3BlobStore extends BaseBlobStore {
protected boolean deleteAndVerifyContainerGone(final String container) {
return S3Utils.deleteAndVerifyContainerGone(sync, container);
}
@Override
public boolean createContainerInLocation(Location location, String container, CreateContainerOptions options) {
PutBucketOptions putBucketOptions = new PutBucketOptions();
if (options.isPublicRead())
putBucketOptions.withBucketAcl(CannedAccessPolicy.PUBLIC_READ);
location = location != null ? location : defaultLocation.get();
return sync.putBucketInRegion(location.getId(), container, putBucketOptions);
}
}

View File

@ -19,6 +19,11 @@
package org.jclouds.s3.blobstore.config;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.inject.Singleton;
import org.jclouds.blobstore.AsyncBlobStore;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.BlobStore;
@ -34,10 +39,13 @@ import org.jclouds.s3.blobstore.S3AsyncBlobStore;
import org.jclouds.s3.blobstore.S3BlobRequestSigner;
import org.jclouds.s3.blobstore.S3BlobStore;
import org.jclouds.s3.blobstore.functions.LocationFromBucketLocation;
import org.jclouds.s3.domain.AccessControlList;
import org.jclouds.s3.domain.BucketMetadata;
import com.google.common.base.Function;
import com.google.common.collect.MapMaker;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
@ -70,5 +78,19 @@ public class S3BlobStoreContextModule extends AbstractModule {
}).to(LocationFromBucketLocation.class);
}
@Provides
@Singleton
protected Map<String, AccessControlList> bucketAcls(final S3Client client) {
return new MapMaker().expireAfterWrite(30, TimeUnit.SECONDS).makeComputingMap(
new Function<String, AccessControlList>() {
public AccessControlList apply(String bucketName) {
return client.getBucketACL(bucketName);
}
@Override
public String toString() {
return "getBucketAcl()";
}
});
}
}

View File

@ -19,29 +19,36 @@
package org.jclouds.s3.blobstore.functions;
import static com.google.common.base.Preconditions.checkArgument;
import java.util.Map.Entry;
import javax.inject.Singleton;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpUtils;
import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.s3.domain.MutableObjectMetadata;
import org.jclouds.s3.domain.internal.MutableObjectMetadataImpl;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.http.HttpUtils;
import com.google.common.base.Function;
/**
* @author Adrian Cole
*/
@Singleton
public class BlobToObjectMetadata implements Function<BlobMetadata, MutableObjectMetadata> {
public class BlobToObjectMetadata implements Function<BlobMetadata, MutableObjectMetadata>,
InvocationContext<BlobToObjectMetadata> {
private String bucket;
public MutableObjectMetadata apply(BlobMetadata from) {
if (from == null)
return null;
MutableObjectMetadata to = new MutableObjectMetadataImpl();
HttpUtils.copy(from.getContentMetadata(), to.getContentMetadata());
to.setUri(from.getUri());
to.setETag(from.getETag());
to.setKey(from.getName());
to.setBucket(bucket);
to.setLastModified(from.getLastModified());
if (from.getUserMetadata() != null) {
for (Entry<String, String> entry : from.getUserMetadata().entrySet())
@ -49,4 +56,16 @@ public class BlobToObjectMetadata implements Function<BlobMetadata, MutableObjec
}
return to;
}
@Override
public BlobToObjectMetadata setContext(HttpRequest request) {
checkArgument(request instanceof GeneratedHttpRequest<?>, "note this handler requires a GeneratedHttpRequest");
return setBucket(GeneratedHttpRequest.class.cast(request).getArgs().get(0).toString());
}
private BlobToObjectMetadata setBucket(String bucket) {
this.bucket = bucket;
return this;
}
}

View File

@ -24,9 +24,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.s3.domain.S3Object;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.s3.domain.S3Object;
import com.google.common.base.Function;

View File

@ -19,15 +19,20 @@
package org.jclouds.s3.blobstore.functions;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.blobstore.domain.MutableBlobMetadata;
import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
import org.jclouds.blobstore.strategy.IfDirectoryReturnNameStrategy;
import org.jclouds.http.HttpUtils;
import org.jclouds.s3.domain.AccessControlList;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.s3.domain.AccessControlList.GroupGranteeURI;
import org.jclouds.s3.domain.AccessControlList.Permission;
import com.google.common.base.Function;
@ -37,10 +42,13 @@ import com.google.common.base.Function;
@Singleton
public class ObjectToBlobMetadata implements Function<ObjectMetadata, MutableBlobMetadata> {
private final IfDirectoryReturnNameStrategy ifDirectoryReturnName;
private final Map<String, AccessControlList> bucketAcls;
@Inject
public ObjectToBlobMetadata(IfDirectoryReturnNameStrategy ifDirectoryReturnName) {
public ObjectToBlobMetadata(IfDirectoryReturnNameStrategy ifDirectoryReturnName,
Map<String, AccessControlList> bucketAcls) {
this.ifDirectoryReturnName = ifDirectoryReturnName;
this.bucketAcls = bucketAcls;
}
public MutableBlobMetadata apply(ObjectMetadata from) {
@ -48,6 +56,15 @@ public class ObjectToBlobMetadata implements Function<ObjectMetadata, MutableBlo
return null;
MutableBlobMetadata to = new MutableBlobMetadataImpl();
HttpUtils.copy(from.getContentMetadata(), to.getContentMetadata());
try {
AccessControlList bucketAcl = bucketAcls.get(from.getBucket());
if (bucketAcl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ))
to.setPublicUri(from.getUri());
} catch (NullPointerException e) {
// MapMaker cannot return null, but a call to get acls can
}
to.setUri(from.getUri());
to.setContainer(from.getBucket());
to.setETag(from.getETag());
to.setName(from.getKey());
to.setLastModified(from.getLastModified());

View File

@ -19,6 +19,7 @@
package org.jclouds.s3.domain;
import java.net.URI;
import java.util.Date;
import java.util.Map;
@ -50,6 +51,8 @@ public interface MutableObjectMetadata extends ObjectMetadata {
*/
void setKey(String key);
void setBucket(String bucket);
/**
* Every bucket and object in Amazon S3 has an owner, the user that created the bucket or object.
* The owner of a bucket or object cannot be changed. However, if the object is overwritten by
@ -80,4 +83,6 @@ public interface MutableObjectMetadata extends ObjectMetadata {
void setUserMetadata(Map<String, String> userMetadata);
void setUri(URI uri);
}

View File

@ -19,6 +19,7 @@
package org.jclouds.s3.domain;
import java.net.URI;
import java.util.Date;
import java.util.Map;
@ -50,6 +51,10 @@ public interface ObjectMetadata extends Comparable<ObjectMetadata> {
*/
String getKey();
String getBucket();
URI getUri();
/**
* Every bucket and object in Amazon S3 has an owner, the user that created the bucket or object.
* The owner of a bucket or object cannot be changed. However, if the object is overwritten by

View File

@ -19,6 +19,8 @@
package org.jclouds.s3.domain;
import java.net.URI;
import java.util.Date;
import java.util.Map;
import org.jclouds.io.ContentMetadataBuilder;
@ -38,19 +40,49 @@ public class ObjectMetadataBuilder {
return new ObjectMetadataBuilder();
}
private final ContentMetadataBuilder contentMetadataBuilder = new ContentMetadataBuilder().contentType("binary/octet-stream");
private final ContentMetadataBuilder contentMetadataBuilder = new ContentMetadataBuilder()
.contentType("binary/octet-stream");
private String key;
private StorageClass storageClass;
private String bucket;
private URI uri;
private StorageClass storageClass = StorageClass.STANDARD;
private String cacheControl;
private Date lastModified;
private String eTag;
private CanonicalUser owner;
private Map<String, String> userMetadata = ImmutableMap.of();
public ObjectMetadataBuilder key(String key) {
this.key = key;
return this;
}
public ObjectMetadataBuilder bucket(String bucket) {
this.bucket = bucket;
return this;
}
public ObjectMetadataBuilder owner(CanonicalUser owner) {
this.owner = owner;
return this;
}
public ObjectMetadataBuilder eTag(String eTag) {
this.eTag = eTag;
return this;
}
public ObjectMetadataBuilder uri(URI uri) {
this.uri = uri;
return this;
}
public ObjectMetadataBuilder lastModified(Date lastModified) {
this.lastModified = lastModified;
return this;
}
public ObjectMetadataBuilder storageClass(StorageClass storageClass) {
this.storageClass = storageClass;
return this;
@ -98,7 +130,6 @@ public class ObjectMetadataBuilder {
public ObjectMetadataBuilder contentType(String contentType) {
contentMetadataBuilder.contentType(contentType);
return this;
}
public ObjectMetadata build() {
@ -106,8 +137,13 @@ public class ObjectMetadataBuilder {
toReturn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(contentMetadataBuilder.build()));
toReturn.setCacheControl(cacheControl);
toReturn.setKey(key);
toReturn.setBucket(bucket);
toReturn.setUri(uri);
toReturn.setETag(eTag);
toReturn.setOwner(owner);
toReturn.setStorageClass(storageClass);
toReturn.setUserMetadata(userMetadata);
toReturn.setLastModified(lastModified);
return toReturn;
}

View File

@ -19,16 +19,19 @@
package org.jclouds.s3.domain.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.Serializable;
import java.net.URI;
import java.util.Date;
import java.util.Map;
import org.jclouds.s3.domain.CanonicalUser;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.io.ContentMetadata;
import org.jclouds.io.payloads.BaseImmutableContentMetadata;
import org.jclouds.s3.domain.CanonicalUser;
import org.jclouds.s3.domain.ObjectMetadata;
import com.google.common.collect.Maps;
import com.google.common.collect.ImmutableMap;
/**
* Returns the metadata parsable from a bucket listing
@ -41,29 +44,38 @@ public class BucketListObjectMetadata implements Serializable, ObjectMetadata {
private static final long serialVersionUID = -4415449798024051115L;
private final String key;
private final String bucket;
private final URI uri;
private final Date lastModified;
private final String eTag;
private final CanonicalUser owner;
private final StorageClass storageClass;
private final String cacheControl;
private final Map<String, String> userMetadata;
private final ContentMetadata contentMetadata;
public BucketListObjectMetadata(String key, Date lastModified, String eTag, byte[] md5, long contentLength,
CanonicalUser owner, StorageClass storageClass) {
this.key = key;
public BucketListObjectMetadata(String key, String bucket, URI uri, Date lastModified, String eTag, byte[] md5,
long contentLength, CanonicalUser owner, StorageClass storageClass) {
this.key = checkNotNull(key, "key");
this.bucket = checkNotNull(bucket, "bucket");
this.uri = checkNotNull(uri, "uri");
this.lastModified = lastModified;
this.eTag = eTag;
this.owner = owner;
this.contentMetadata = new BaseImmutableContentMetadata(null, contentLength, md5, null, null, null);
this.storageClass = storageClass;
this.cacheControl = null;
this.userMetadata = Maps.newHashMap();
}
/**
*{@inheritDoc}
*/
@Override
public URI getUri() {
return uri;
}
/**
*{@inheritDoc}
*/
@Override
public String getKey() {
return key;
}
@ -71,6 +83,15 @@ public class BucketListObjectMetadata implements Serializable, ObjectMetadata {
/**
*{@inheritDoc}
*/
@Override
public String getBucket() {
return bucket;
}
/**
*{@inheritDoc}
*/
@Override
public CanonicalUser getOwner() {
return owner;
}
@ -78,6 +99,7 @@ public class BucketListObjectMetadata implements Serializable, ObjectMetadata {
/**
*{@inheritDoc}
*/
@Override
public StorageClass getStorageClass() {
return storageClass;
}
@ -85,13 +107,15 @@ public class BucketListObjectMetadata implements Serializable, ObjectMetadata {
/**
*{@inheritDoc}
*/
@Override
public String getCacheControl() {
return cacheControl;
return null;
}
/**
*{@inheritDoc}
*/
@Override
public Date getLastModified() {
return lastModified;
}
@ -99,6 +123,7 @@ public class BucketListObjectMetadata implements Serializable, ObjectMetadata {
/**
*{@inheritDoc}
*/
@Override
public String getETag() {
return eTag;
}
@ -106,15 +131,17 @@ public class BucketListObjectMetadata implements Serializable, ObjectMetadata {
/**
*{@inheritDoc}
*/
@Override
public int compareTo(ObjectMetadata o) {
return (this == o) ? 0 : getKey().compareTo(o.getKey());
return (this == o) ? 0 : getUri().compareTo(o.getUri());
}
/**
*{@inheritDoc}
*/
@Override
public Map<String, String> getUserMetadata() {
return userMetadata;
return ImmutableMap.of();
}
/**
@ -129,14 +156,7 @@ public class BucketListObjectMetadata implements Serializable, ObjectMetadata {
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((cacheControl == null) ? 0 : cacheControl.hashCode());
result = prime * result + ((contentMetadata == null) ? 0 : contentMetadata.hashCode());
result = prime * result + ((eTag == null) ? 0 : eTag.hashCode());
result = prime * result + ((key == null) ? 0 : key.hashCode());
result = prime * result + ((lastModified == null) ? 0 : lastModified.hashCode());
result = prime * result + ((owner == null) ? 0 : owner.hashCode());
result = prime * result + ((storageClass == null) ? 0 : storageClass.hashCode());
result = prime * result + ((userMetadata == null) ? 0 : userMetadata.hashCode());
result = prime * result + ((uri == null) ? 0 : uri.hashCode());
return result;
}
@ -149,47 +169,19 @@ public class BucketListObjectMetadata implements Serializable, ObjectMetadata {
if (getClass() != obj.getClass())
return false;
BucketListObjectMetadata other = (BucketListObjectMetadata) obj;
if (cacheControl == null) {
if (other.cacheControl != null)
if (uri == null) {
if (other.uri != null)
return false;
} else if (!cacheControl.equals(other.cacheControl))
return false;
if (contentMetadata == null) {
if (other.contentMetadata != null)
return false;
} else if (!contentMetadata.equals(other.contentMetadata))
return false;
if (eTag == null) {
if (other.eTag != null)
return false;
} else if (!eTag.equals(other.eTag))
return false;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
if (lastModified == null) {
if (other.lastModified != null)
return false;
} else if (!lastModified.equals(other.lastModified))
return false;
if (owner == null) {
if (other.owner != null)
return false;
} else if (!owner.equals(other.owner))
return false;
if (storageClass == null) {
if (other.storageClass != null)
return false;
} else if (!storageClass.equals(other.storageClass))
return false;
if (userMetadata == null) {
if (other.userMetadata != null)
return false;
} else if (!userMetadata.equals(other.userMetadata))
} else if (!uri.equals(other.uri))
return false;
return true;
}
@Override
public String toString() {
return String.format(
"[uri=%s, key=%s, bucket=%s, contentMetadata=%s, eTag=%s, lastModified=%s, owner=%s, storageClass=%s]",
uri, key, bucket, contentMetadata, eTag, lastModified, owner, storageClass);
}
}

View File

@ -20,13 +20,16 @@
package org.jclouds.s3.domain.internal;
import java.io.Serializable;
import java.net.URI;
import java.util.Date;
import java.util.Map;
import org.jclouds.s3.domain.CanonicalUser;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.io.ContentMetadata;
import org.jclouds.io.payloads.BaseImmutableContentMetadata;
import org.jclouds.s3.domain.CanonicalUser;
import org.jclouds.s3.domain.ObjectMetadata;
import com.google.common.collect.ImmutableMap;
/**
* Returns the metadata parsable from a bucket listing
@ -38,57 +41,68 @@ public class CopyObjectResult implements Serializable, ObjectMetadata {
/** The serialVersionUID */
private static final long serialVersionUID = -4415449798024051115L;
private final String key;
private final Date lastModified;
private final String eTag;
private final CanonicalUser owner;
private final StorageClass storageClass;
private final String cacheControl;
private final Map<String, String> userMetadata;
private final BaseImmutableContentMetadata contentMetadata;
public CopyObjectResult(Date lastModified, String eTag) {
this.key = null;
this.lastModified = lastModified;
this.eTag = eTag;
this.owner = null;
this.storageClass = StorageClass.STANDARD;
this.contentMetadata = new BaseImmutableContentMetadata(null, null, null, null, null, null);
this.cacheControl = null;
this.userMetadata = null;
}
/**
*{@inheritDoc}
*/
@Override
public String getKey() {
return key;
return null;
}
/**
*{@inheritDoc}
*/
@Override
public String getBucket() {
return null;
}
/**
*{@inheritDoc}
*/
@Override
public URI getUri() {
return null;
}
/**
*{@inheritDoc}
*/
@Override
public CanonicalUser getOwner() {
return owner;
return null;
}
/**
*{@inheritDoc}
*/
@Override
public StorageClass getStorageClass() {
return storageClass;
return null;
}
/**
*{@inheritDoc}
*/
@Override
public String getCacheControl() {
return cacheControl;
return null;
}
/**
*{@inheritDoc}
*/
@Override
public Date getLastModified() {
return lastModified;
}
@ -96,6 +110,7 @@ public class CopyObjectResult implements Serializable, ObjectMetadata {
/**
*{@inheritDoc}
*/
@Override
public String getETag() {
return eTag;
}
@ -103,15 +118,17 @@ public class CopyObjectResult implements Serializable, ObjectMetadata {
/**
*{@inheritDoc}
*/
@Override
public int compareTo(ObjectMetadata o) {
return (this == o) ? 0 : getKey().compareTo(o.getKey());
return (this == o) ? 0 : getETag().compareTo(o.getETag());
}
/**
*{@inheritDoc}
*/
@Override
public Map<String, String> getUserMetadata() {
return userMetadata;
return ImmutableMap.of();
}
/**
@ -126,14 +143,8 @@ public class CopyObjectResult implements Serializable, ObjectMetadata {
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((cacheControl == null) ? 0 : cacheControl.hashCode());
result = prime * result + ((contentMetadata == null) ? 0 : contentMetadata.hashCode());
result = prime * result + ((eTag == null) ? 0 : eTag.hashCode());
result = prime * result + ((key == null) ? 0 : key.hashCode());
result = prime * result + ((lastModified == null) ? 0 : lastModified.hashCode());
result = prime * result + ((owner == null) ? 0 : owner.hashCode());
result = prime * result + ((storageClass == null) ? 0 : storageClass.hashCode());
result = prime * result + ((userMetadata == null) ? 0 : userMetadata.hashCode());
return result;
}
@ -146,47 +157,22 @@ public class CopyObjectResult implements Serializable, ObjectMetadata {
if (getClass() != obj.getClass())
return false;
CopyObjectResult other = (CopyObjectResult) obj;
if (cacheControl == null) {
if (other.cacheControl != null)
return false;
} else if (!cacheControl.equals(other.cacheControl))
return false;
if (contentMetadata == null) {
if (other.contentMetadata != null)
return false;
} else if (!contentMetadata.equals(other.contentMetadata))
return false;
if (eTag == null) {
if (other.eTag != null)
return false;
} else if (!eTag.equals(other.eTag))
return false;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
if (lastModified == null) {
if (other.lastModified != null)
return false;
} else if (!lastModified.equals(other.lastModified))
return false;
if (owner == null) {
if (other.owner != null)
return false;
} else if (!owner.equals(other.owner))
return false;
if (storageClass == null) {
if (other.storageClass != null)
return false;
} else if (!storageClass.equals(other.storageClass))
return false;
if (userMetadata == null) {
if (other.userMetadata != null)
return false;
} else if (!userMetadata.equals(other.userMetadata))
return false;
return true;
}
@Override
public String toString() {
return String.format("[eTag=%s, lastModified=%s]", eTag, lastModified);
}
}

View File

@ -20,15 +20,16 @@
package org.jclouds.s3.domain.internal;
import java.io.Serializable;
import java.net.URI;
import java.util.Date;
import java.util.Map;
import org.jclouds.s3.domain.CanonicalUser;
import org.jclouds.s3.domain.MutableObjectMetadata;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.http.HttpUtils;
import org.jclouds.io.MutableContentMetadata;
import org.jclouds.io.payloads.BaseMutableContentMetadata;
import org.jclouds.s3.domain.CanonicalUser;
import org.jclouds.s3.domain.MutableObjectMetadata;
import org.jclouds.s3.domain.ObjectMetadata;
import com.google.common.collect.Maps;
@ -43,6 +44,8 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
private static final long serialVersionUID = -4648755473986695062L;
private String key;
private String bucket;
private URI uri;
private Date lastModified;
private String eTag;
private CanonicalUser owner;
@ -60,11 +63,15 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
this.storageClass = StorageClass.STANDARD;
this.contentMetadata = new BaseMutableContentMetadata();
HttpUtils.copy(from.getContentMetadata(), this.contentMetadata);
this.key = from.getKey();
this.uri = from.getUri();
this.bucket = from.getBucket();
}
/**
*{@inheritDoc}
*/
@Override
public String getKey() {
return key;
}
@ -72,6 +79,31 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/**
*{@inheritDoc}
*/
@Override
public String getBucket() {
return bucket;
}
/**
*{@inheritDoc}
*/
@Override
public URI getUri() {
return uri;
}
/**
*{@inheritDoc}
*/
@Override
public void setUri(URI uri) {
this.uri = uri;
}
/**
*{@inheritDoc}
*/
@Override
public CanonicalUser getOwner() {
return owner;
}
@ -79,6 +111,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/**
*{@inheritDoc}
*/
@Override
public StorageClass getStorageClass() {
return storageClass;
}
@ -86,6 +119,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/**
*{@inheritDoc}
*/
@Override
public String getCacheControl() {
return cacheControl;
}
@ -93,6 +127,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/**
*{@inheritDoc}
*/
@Override
public Date getLastModified() {
return lastModified;
}
@ -100,6 +135,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/**
*{@inheritDoc}
*/
@Override
public String getETag() {
return eTag;
}
@ -107,6 +143,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/**
*{@inheritDoc}
*/
@Override
public int compareTo(ObjectMetadata o) {
return (this == o) ? 0 : getKey().compareTo(o.getKey());
}
@ -114,6 +151,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/**
*{@inheritDoc}
*/
@Override
public Map<String, String> getUserMetadata() {
return userMetadata;
}
@ -121,6 +159,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/**
*{@inheritDoc}
*/
@Override
public void setCacheControl(String cacheControl) {
this.cacheControl = cacheControl;
}
@ -128,6 +167,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/**
*{@inheritDoc}
*/
@Override
public void setETag(String eTag) {
this.eTag = eTag;
}
@ -135,6 +175,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/**
*{@inheritDoc}
*/
@Override
public void setKey(String key) {
this.key = key;
}
@ -142,6 +183,15 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/**
*{@inheritDoc}
*/
@Override
public void setBucket(String bucket) {
this.bucket = bucket;
}
/**
*{@inheritDoc}
*/
@Override
public void setLastModified(Date lastModified) {
this.lastModified = lastModified;
}
@ -149,6 +199,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/**
*{@inheritDoc}
*/
@Override
public void setOwner(CanonicalUser owner) {
this.owner = owner;
}
@ -156,6 +207,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/**
*{@inheritDoc}
*/
@Override
public void setStorageClass(StorageClass storageClass) {
this.storageClass = storageClass;
}
@ -163,6 +215,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/**
*{@inheritDoc}
*/
@Override
public void setUserMetadata(Map<String, String> userMetadata) {
this.userMetadata = userMetadata;
}
@ -187,14 +240,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((cacheControl == null) ? 0 : cacheControl.hashCode());
result = prime * result + ((contentMetadata == null) ? 0 : contentMetadata.hashCode());
result = prime * result + ((eTag == null) ? 0 : eTag.hashCode());
result = prime * result + ((key == null) ? 0 : key.hashCode());
result = prime * result + ((lastModified == null) ? 0 : lastModified.hashCode());
result = prime * result + ((owner == null) ? 0 : owner.hashCode());
result = prime * result + ((storageClass == null) ? 0 : storageClass.hashCode());
result = prime * result + ((userMetadata == null) ? 0 : userMetadata.hashCode());
result = prime * result + ((uri == null) ? 0 : uri.hashCode());
return result;
}
@ -207,54 +253,21 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
if (getClass() != obj.getClass())
return false;
MutableObjectMetadataImpl other = (MutableObjectMetadataImpl) obj;
if (cacheControl == null) {
if (other.cacheControl != null)
if (uri == null) {
if (other.uri != null)
return false;
} else if (!cacheControl.equals(other.cacheControl))
return false;
if (contentMetadata == null) {
if (other.contentMetadata != null)
return false;
} else if (!contentMetadata.equals(other.contentMetadata))
return false;
if (eTag == null) {
if (other.eTag != null)
return false;
} else if (!eTag.equals(other.eTag))
return false;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
if (lastModified == null) {
if (other.lastModified != null)
return false;
} else if (!lastModified.equals(other.lastModified))
return false;
if (owner == null) {
if (other.owner != null)
return false;
} else if (!owner.equals(other.owner))
return false;
if (storageClass == null) {
if (other.storageClass != null)
return false;
} else if (!storageClass.equals(other.storageClass))
return false;
if (userMetadata == null) {
if (other.userMetadata != null)
return false;
} else if (!userMetadata.equals(other.userMetadata))
} else if (!uri.equals(other.uri))
return false;
return true;
}
@Override
public String toString() {
return "[key=" + key + ", cacheControl=" + cacheControl + ", contentMetadata=" + contentMetadata + ", eTag="
+ eTag + ", lastModified=" + lastModified + ", owner=" + owner + ", storageClass=" + storageClass
+ ", userMetadata=" + userMetadata + "]";
return String
.format(
"[key=%s, bucket=%s, uri=%s, eTag=%s, cacheControl=%s, contentMetadata=%s, lastModified=%s, owner=%s, storageClass=%s, userMetadata=%s]",
key, bucket, uri, eTag, cacheControl, contentMetadata, lastModified, owner, storageClass,
userMetadata);
}
}

View File

@ -53,7 +53,6 @@ public class ParseObjectFromHeadersAndHttpContent implements Function<HttpRespon
S3Object object = objectProvider.create(metadata);
object.getAllHeaders().putAll(from.getHeaders());
object.setPayload(from.getPayload());
return object;
}

View File

@ -106,6 +106,7 @@ public class ParseObjectMetadataFromHeaders implements Function<HttpResponse, Mu
@Override
public ParseObjectMetadataFromHeaders setContext(HttpRequest request) {
blobMetadataParser.setContext(request);
blobToObjectMetadata.setContext(request);
return this;
}

View File

@ -19,6 +19,8 @@
package org.jclouds.s3.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import java.net.URI;
import org.jclouds.http.functions.ParseSax;
@ -79,11 +81,11 @@ public class AccessControlListHandler extends ParseSax.HandlerWithResult<AccessC
}
else if (qName.equals("ID") || qName.equals("EmailAddress") || qName.equals("URI")) {
currentId = currentText.toString().trim();
currentId = currentOrNull(currentText);
} else if (qName.equals("DisplayName")) {
currentDisplayName = currentText.toString().trim();
currentDisplayName = currentOrNull(currentText);
} else if (qName.equals("Permission")) {
currentPermission = currentText.toString().trim();
currentPermission = currentOrNull(currentText);
}
currentText = new StringBuilder();
}

View File

@ -19,6 +19,8 @@
package org.jclouds.s3.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import java.net.URI;
import java.util.Set;
@ -68,9 +70,9 @@ public class BucketLoggingHandler extends ParseSax.HandlerWithResult<BucketLoggi
public void endElement(String uri, String name, String qName) {
if (qName.equals("TargetBucket")) {
this.targetBucket = currentText.toString().trim();
this.targetBucket = currentOrNull(currentText);
} else if (qName.equals("TargetPrefix")) {
this.targetPrefix = currentText.toString().trim();
this.targetPrefix = currentOrNull(currentText);
} else if (qName.equals("Grantee")) {
if ("AmazonCustomerByEmail".equals(currentGranteeType)) {
currentGrantee = new EmailAddressGrantee(currentId);
@ -82,11 +84,11 @@ public class BucketLoggingHandler extends ParseSax.HandlerWithResult<BucketLoggi
} else if (qName.equals("Grant")) {
targetGrants.add(new Grant(currentGrantee, currentPermission));
} else if (qName.equals("ID") || qName.equals("EmailAddress") || qName.equals("URI")) {
currentId = currentText.toString().trim();
currentId = currentOrNull(currentText);
} else if (qName.equals("DisplayName")) {
currentDisplayName = currentText.toString().trim();
currentDisplayName = currentOrNull(currentText);
} else if (qName.equals("Permission")) {
currentPermission = currentText.toString().trim();
currentPermission = currentOrNull(currentText);
}
currentText = new StringBuilder();
}

View File

@ -19,6 +19,8 @@
package org.jclouds.s3.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import java.util.Date;
import javax.inject.Inject;
@ -51,9 +53,9 @@ public class CopyObjectHandler extends ParseSax.HandlerWithResult<ObjectMetadata
public void endElement(String uri, String name, String qName) {
if (qName.equals("ETag")) {
this.currentETag = currentText.toString().trim();
this.currentETag = currentOrNull(currentText);
} else if (qName.equals("LastModified")) {
this.currentLastModified = dateParser.iso8601DateParse(currentText.toString().trim());
this.currentLastModified = dateParser.iso8601DateParse(currentOrNull(currentText));
} else if (qName.equals("CopyObjectResult")) {
metadata = new CopyObjectResult(currentLastModified, currentETag);
}

View File

@ -19,6 +19,8 @@
package org.jclouds.s3.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import java.util.Date;
import java.util.Set;
@ -62,15 +64,15 @@ public class ListAllMyBucketsHandler extends ParseSax.HandlerWithResult<Set<Buck
public void endElement(String uri, String name, String qName) {
if (qName.equals("ID")) { // owner stuff
currentOwner = new CanonicalUser(currentText.toString().trim());
currentOwner = new CanonicalUser(currentOrNull(currentText));
} else if (qName.equals("DisplayName")) {
currentOwner.setDisplayName(currentText.toString().trim());
currentOwner.setDisplayName(currentOrNull(currentText));
} else if (qName.equals("Bucket")) {
buckets.add(new BucketMetadata(currentName, currentCreationDate, currentOwner));
} else if (qName.equals("Name")) {
currentName = currentText.toString().trim();
currentName = currentOrNull(currentText);
} else if (qName.equals("CreationDate")) {
currentCreationDate = dateParser.iso8601DateParse(currentText.toString().trim());
currentCreationDate = dateParser.iso8601DateParse(currentOrNull(currentText));
}
currentText = new StringBuilder();
}

View File

@ -19,24 +19,25 @@
package org.jclouds.s3.xml;
import java.util.Date;
import java.util.Set;
import static org.jclouds.util.SaxUtils.currentOrNull;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.s3.domain.CanonicalUser;
import org.jclouds.s3.domain.ListBucketResponse;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.s3.domain.ObjectMetadata.StorageClass;
import org.jclouds.s3.domain.internal.BucketListObjectMetadata;
import org.jclouds.s3.domain.internal.ListBucketResponseImpl;
import org.jclouds.crypto.CryptoStreams;
import org.jclouds.date.DateService;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.s3.domain.CanonicalUser;
import org.jclouds.s3.domain.ListBucketResponse;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.s3.domain.ObjectMetadataBuilder;
import org.jclouds.s3.domain.internal.ListBucketResponseImpl;
import org.jclouds.util.Strings2;
import org.xml.sax.Attributes;
import com.google.common.collect.Sets;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
/**
* Parses the following XML document:
@ -49,11 +50,14 @@ import com.google.common.collect.Sets;
* />
*/
public class ListBucketHandler extends ParseSax.HandlerWithResult<ListBucketResponse> {
private Set<ObjectMetadata> contents;
private Set<String> commonPrefixes;
private Builder<ObjectMetadata> contents = ImmutableSet.<ObjectMetadata> builder();
private Builder<String> commonPrefixes = ImmutableSet.<String> builder();
private CanonicalUser currentOwner;
private StringBuilder currentText = new StringBuilder();
private ObjectMetadataBuilder builder = new ObjectMetadataBuilder();
private final Provider<UriBuilder> uriBuilders;
private final DateService dateParser;
private String bucketName;
@ -64,25 +68,19 @@ public class ListBucketHandler extends ParseSax.HandlerWithResult<ListBucketResp
private boolean isTruncated;
@Inject
public ListBucketHandler(DateService dateParser) {
public ListBucketHandler(DateService dateParser, Provider<UriBuilder> uriBuilders) {
this.dateParser = dateParser;
this.contents = Sets.newLinkedHashSet();
this.commonPrefixes = Sets.newLinkedHashSet();
this.uriBuilders = uriBuilders;
}
public ListBucketResponse getResult() {
return new ListBucketResponseImpl(bucketName, contents, prefix, marker,
return new ListBucketResponseImpl(bucketName, contents.build(), prefix, marker,
(isTruncated && nextMarker == null) ? currentKey : nextMarker, maxResults, delimiter, isTruncated,
commonPrefixes);
commonPrefixes.build());
}
private boolean inCommonPrefixes;
private String currentKey;
private Date currentLastModified;
private String currentETag;
private byte[] currentMD5;
private long currentSize;
private StorageClass currentStorageClass;
private String nextMarker;
public void startElement(String uri, String name, String qName, Attributes attrs) {
@ -93,45 +91,48 @@ public class ListBucketHandler extends ParseSax.HandlerWithResult<ListBucketResp
public void endElement(String uri, String name, String qName) {
if (qName.equals("ID")) {
currentOwner = new CanonicalUser(currentText.toString().trim());
currentOwner = new CanonicalUser(currentOrNull(currentText));
} else if (qName.equals("DisplayName")) {
currentOwner.setDisplayName(currentText.toString().trim());
currentOwner.setDisplayName(currentOrNull(currentText));
} else if (qName.equals("Key")) { // content stuff
currentKey = currentText.toString().trim();
currentKey = currentOrNull(currentText);
builder.key(currentKey);
builder.uri(uriBuilders.get().uri(getRequest().getEndpoint()).path(currentKey).replaceQuery("").build());
} else if (qName.equals("LastModified")) {
currentLastModified = dateParser.iso8601DateParse(currentText.toString().trim());
builder.lastModified(dateParser.iso8601DateParse(currentOrNull(currentText)));
} else if (qName.equals("ETag")) {
currentETag = currentText.toString().trim();
currentMD5 = CryptoStreams.hex(Strings2.replaceAll(currentETag, '"', ""));
String currentETag = currentOrNull(currentText);
builder.eTag(currentETag);
builder.contentMD5(CryptoStreams.hex(Strings2.replaceAll(currentETag, '"', "")));
} else if (qName.equals("Size")) {
currentSize = new Long(currentText.toString().trim());
builder.contentLength(new Long(currentOrNull(currentText)));
} else if (qName.equals("Owner")) {
builder.owner(currentOwner);
currentOwner = null;
} else if (qName.equals("StorageClass")) {
currentStorageClass = ObjectMetadata.StorageClass.valueOf(currentText.toString().trim());
builder.storageClass(ObjectMetadata.StorageClass.valueOf(currentOrNull(currentText)));
} else if (qName.equals("Contents")) {
contents.add(new BucketListObjectMetadata(currentKey, currentLastModified, currentETag, currentMD5,
currentSize, currentOwner, currentStorageClass));
contents.add(builder.build());
builder = new ObjectMetadataBuilder().bucket(bucketName);
} else if (qName.equals("Name")) {
this.bucketName = currentText.toString().trim();
this.bucketName = currentOrNull(currentText);
builder.bucket(bucketName);
} else if (qName.equals("Prefix")) {
String prefix = currentText.toString().trim();
String prefix = currentOrNull(currentText);
if (inCommonPrefixes)
commonPrefixes.add(prefix);
else
this.prefix = prefix;
} else if (qName.equals("Delimiter")) {
if (!currentText.toString().equals(""))
this.delimiter = currentText.toString().trim();
this.delimiter = currentOrNull(currentText);
} else if (qName.equals("Marker")) {
if (!currentText.toString().equals(""))
this.marker = currentText.toString().trim();
this.marker = currentOrNull(currentText);
} else if (qName.equals("NextMarker")) {
if (!currentText.toString().equals(""))
this.nextMarker = currentText.toString().trim();
this.nextMarker = currentOrNull(currentText);
} else if (qName.equals("MaxKeys")) {
this.maxResults = Integer.parseInt(currentText.toString().trim());
this.maxResults = Integer.parseInt(currentOrNull(currentText));
} else if (qName.equals("IsTruncated")) {
this.isTruncated = Boolean.parseBoolean(currentText.toString().trim());
this.isTruncated = Boolean.parseBoolean(currentOrNull(currentText));
}
currentText = new StringBuilder();
}

View File

@ -19,6 +19,8 @@
package org.jclouds.s3.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import org.jclouds.aws.domain.Region;
import org.jclouds.http.functions.ParseSax;
@ -39,7 +41,7 @@ public class LocationConstraintHandler extends ParseSax.HandlerWithResult<String
}
public void endElement(String uri, String name, String qName) {
region = fromValue(currentText.toString().trim());
region = fromValue(currentOrNull(currentText));
}
/**
@ -48,14 +50,8 @@ public class LocationConstraintHandler extends ParseSax.HandlerWithResult<String
* {@code US_STANDARD} is returned as "" xml documents.
*/
public static String fromValue(String v) {
if (v.equals(""))
if (v == null || "".equals(v))
return Region.US_STANDARD;
if (v.equals(Region.EU))
return Region.EU;
else if (v.equals(Region.US_WEST_1))
return Region.US_WEST_1;
else if (v.equals(Region.AP_SOUTHEAST_1))
return Region.AP_SOUTHEAST_1;
return v;
}

View File

@ -19,6 +19,8 @@
package org.jclouds.s3.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import org.jclouds.s3.domain.Payer;
import org.jclouds.http.functions.ParseSax;
@ -39,7 +41,7 @@ public class PayerHandler extends ParseSax.HandlerWithResult<Payer> {
}
public void endElement(String uri, String name, String qName) {
constraint = Payer.fromValue(currentText.toString().trim());
constraint = Payer.fromValue(currentOrNull(currentText));
}
public void characters(char ch[], int start, int length) {

View File

@ -22,19 +22,20 @@ package org.jclouds.s3.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI;
import java.util.TreeSet;
import org.jclouds.s3.domain.CanonicalUser;
import org.jclouds.s3.domain.ListBucketResponse;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.s3.domain.ObjectMetadata.StorageClass;
import org.jclouds.s3.domain.internal.BucketListObjectMetadata;
import org.jclouds.s3.domain.internal.ListBucketResponseImpl;
import org.jclouds.crypto.CryptoStreams;
import org.jclouds.date.DateService;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.s3.domain.CanonicalUser;
import org.jclouds.s3.domain.ListBucketResponse;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.s3.domain.ObjectMetadataBuilder;
import org.jclouds.s3.domain.internal.ListBucketResponseImpl;
import org.jclouds.util.Strings2;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
@ -63,59 +64,68 @@ public class ListBucketHandlerTest extends BaseHandlerTest {
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/list_bucket.xml");
ListBucketResponse result = createParser().parse(is);
CanonicalUser owner = new CanonicalUser("e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0",
"ferncam");
ListBucketResponse expected = new ListBucketResponseImpl("adriancole.org.jclouds.s3.amazons3testdelimiter",
ImmutableList.of(
(ObjectMetadata) new BucketListObjectMetadata("apps/0", dateService
.iso8601DateParse("2009-05-07T18:27:08.000Z"), "\"c82e6a0025c31c5de5947fda62ac51ab\"",
CryptoStreams.hex("c82e6a0025c31c5de5947fda62ac51ab"), 8, owner, StorageClass.STANDARD),
(ObjectMetadata) new BucketListObjectMetadata("apps/1", dateService
.iso8601DateParse("2009-05-07T18:27:09.000Z"), "\"944fab2c5a9a6bacf07db5e688310d7a\"",
CryptoStreams.hex("944fab2c5a9a6bacf07db5e688310d7a"), 8, owner, StorageClass.STANDARD),
(ObjectMetadata) new BucketListObjectMetadata("apps/2", dateService
.iso8601DateParse("2009-05-07T18:27:09.000Z"), "\"a227b8888045c8fd159fb495214000f0\"",
CryptoStreams.hex("a227b8888045c8fd159fb495214000f0"), 8, owner, StorageClass.STANDARD),
(ObjectMetadata) new BucketListObjectMetadata("apps/3", dateService
.iso8601DateParse("2009-05-07T18:27:09.000Z"), "\"c9caa76c3dec53e2a192608ce73eef03\"",
CryptoStreams.hex("c9caa76c3dec53e2a192608ce73eef03"), 8, owner, StorageClass.STANDARD),
(ObjectMetadata) new BucketListObjectMetadata("apps/4", dateService
.iso8601DateParse("2009-05-07T18:27:09.000Z"), "\"1ce5d0dcc6154a647ea90c7bdf82a224\"",
CryptoStreams.hex("1ce5d0dcc6154a647ea90c7bdf82a224"), 8, owner, StorageClass.STANDARD),
(ObjectMetadata) new BucketListObjectMetadata("apps/5", dateService
.iso8601DateParse("2009-05-07T18:27:09.000Z"), "\"79433524d87462ee05708a8ef894ed55\"",
CryptoStreams.hex("79433524d87462ee05708a8ef894ed55"), 8, owner, StorageClass.STANDARD),
(ObjectMetadata) new BucketListObjectMetadata("apps/6", dateService
.iso8601DateParse("2009-05-07T18:27:10.000Z"), "\"dd00a060b28ddca8bc5a21a49e306f67\"",
CryptoStreams.hex("dd00a060b28ddca8bc5a21a49e306f67"), 8, owner, StorageClass.STANDARD),
(ObjectMetadata) new BucketListObjectMetadata("apps/7", dateService
.iso8601DateParse("2009-05-07T18:27:10.000Z"), "\"8cd06eca6e819a927b07a285d750b100\"",
CryptoStreams.hex("8cd06eca6e819a927b07a285d750b100"), 8, owner, StorageClass.STANDARD),
(ObjectMetadata) new BucketListObjectMetadata("apps/8", dateService
.iso8601DateParse("2009-05-07T18:27:10.000Z"), "\"174495094d0633b92cbe46603eee6bad\"",
CryptoStreams.hex("174495094d0633b92cbe46603eee6bad"), 8, owner, StorageClass.STANDARD),
(ObjectMetadata) new BucketListObjectMetadata("apps/9", dateService
.iso8601DateParse("2009-05-07T18:27:10.000Z"), "\"cd8a19b26fea8a827276df0ad11c580d\"",
CryptoStreams.hex("cd8a19b26fea8a827276df0ad11c580d"), 8, owner, StorageClass.STANDARD)),
"apps/", null, null, 1000, null, false, new TreeSet<String>());
"ferncam");
String bucket = "adriancole.org.jclouds.aws.s3.amazons3testdelimiter";
ListBucketResponse expected = new ListBucketResponseImpl(bucket, ImmutableList.<ObjectMetadata> of(
new ObjectMetadataBuilder().key("apps/0").bucket(bucket).uri(URI.create("http://bucket.com/apps/0"))
.lastModified(dateService.iso8601DateParse("2009-05-07T18:27:08.000Z")).eTag(
"\"c82e6a0025c31c5de5947fda62ac51ab\"").owner(owner).contentMD5(
CryptoStreams.hex("c82e6a0025c31c5de5947fda62ac51ab")).contentLength(8l).build(),
new ObjectMetadataBuilder().key("apps/1").bucket(bucket).uri(URI.create("http://bucket.com/apps/1"))
.lastModified(dateService.iso8601DateParse("2009-05-07T18:27:09.000Z")).eTag(
"\"944fab2c5a9a6bacf07db5e688310d7a\"").owner(owner).contentMD5(
CryptoStreams.hex("944fab2c5a9a6bacf07db5e688310d7a")).contentLength(8l).build(),
new ObjectMetadataBuilder().key("apps/2").bucket(bucket).uri(URI.create("http://bucket.com/apps/2"))
.lastModified(dateService.iso8601DateParse("2009-05-07T18:27:09.000Z")).eTag(
"\"a227b8888045c8fd159fb495214000f0\"").owner(owner).contentMD5(
CryptoStreams.hex("a227b8888045c8fd159fb495214000f0")).contentLength(8l).build(),
new ObjectMetadataBuilder().key("apps/3").bucket(bucket).uri(URI.create("http://bucket.com/apps/3"))
.lastModified(dateService.iso8601DateParse("2009-05-07T18:27:09.000Z")).eTag(
"\"c9caa76c3dec53e2a192608ce73eef03\"").owner(owner).contentMD5(
CryptoStreams.hex("c9caa76c3dec53e2a192608ce73eef03")).contentLength(8l).build(),
new ObjectMetadataBuilder().key("apps/4").bucket(bucket).uri(URI.create("http://bucket.com/apps/4"))
.lastModified(dateService.iso8601DateParse("2009-05-07T18:27:09.000Z")).eTag(
"\"1ce5d0dcc6154a647ea90c7bdf82a224\"").owner(owner).contentMD5(
CryptoStreams.hex("1ce5d0dcc6154a647ea90c7bdf82a224")).contentLength(8l).build(),
new ObjectMetadataBuilder().key("apps/5").bucket(bucket).uri(URI.create("http://bucket.com/apps/5"))
.lastModified(dateService.iso8601DateParse("2009-05-07T18:27:09.000Z")).eTag(
"\"79433524d87462ee05708a8ef894ed55\"").owner(owner).contentMD5(
CryptoStreams.hex("79433524d87462ee05708a8ef894ed55")).contentLength(8l).build(),
new ObjectMetadataBuilder().key("apps/6").bucket(bucket).uri(URI.create("http://bucket.com/apps/6"))
.lastModified(dateService.iso8601DateParse("2009-05-07T18:27:10.000Z")).eTag(
"\"dd00a060b28ddca8bc5a21a49e306f67\"").owner(owner).contentMD5(
CryptoStreams.hex("dd00a060b28ddca8bc5a21a49e306f67")).contentLength(8l).build(),
new ObjectMetadataBuilder().key("apps/7").bucket(bucket).uri(URI.create("http://bucket.com/apps/7"))
.lastModified(dateService.iso8601DateParse("2009-05-07T18:27:10.000Z")).eTag(
"\"8cd06eca6e819a927b07a285d750b100\"").owner(owner).contentMD5(
CryptoStreams.hex("8cd06eca6e819a927b07a285d750b100")).contentLength(8l).build(),
new ObjectMetadataBuilder().key("apps/8").bucket(bucket).uri(URI.create("http://bucket.com/apps/8"))
.lastModified(dateService.iso8601DateParse("2009-05-07T18:27:10.000Z")).eTag(
"\"174495094d0633b92cbe46603eee6bad\"").owner(owner).contentMD5(
CryptoStreams.hex("174495094d0633b92cbe46603eee6bad")).contentLength(8l).build(),
new ObjectMetadataBuilder().key("apps/9").bucket(bucket).uri(URI.create("http://bucket.com/apps/9"))
.lastModified(dateService.iso8601DateParse("2009-05-07T18:27:10.000Z")).eTag(
"\"cd8a19b26fea8a827276df0ad11c580d\"").owner(owner).contentMD5(
CryptoStreams.hex("cd8a19b26fea8a827276df0ad11c580d")).contentLength(8l).build()),
"apps/", null, null, 1000, null, false, new TreeSet<String>());
ListBucketResponse result = (ListBucketResponse) factory.create(injector.getInstance(ListBucketHandler.class))
.parse(is);
assertEquals(result, expected);
assertEquals(result.toString(), expected.toString());
}
ParseSax<ListBucketResponse> createParser() {
ParseSax<ListBucketResponse> parser = (ParseSax<ListBucketResponse>) factory.create(injector
.getInstance(ListBucketHandler.class));
return parser;
return factory.create(injector.getInstance(ListBucketHandler.class)).setContext(
HttpRequest.builder().method("GET").endpoint(URI.create("http://bucket.com")).build());
}
@Test
public void testListMyBucketsWithDelimiterSlashAndCommonPrefixesAppsSlash() throws HttpException {
ListBucketResponse bucket = createParser().parse(
Strings2.toInputStream(listBucketWithSlashDelimiterAndCommonPrefixApps));
Strings2.toInputStream(listBucketWithSlashDelimiterAndCommonPrefixApps));
assertEquals(bucket.getCommonPrefixes().iterator().next(), "apps/");
assertEquals(bucket.getDelimiter(), "/");
assert bucket.getMarker() == null;

View File

@ -23,6 +23,7 @@ import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.Callable;
@ -30,16 +31,19 @@ import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.PerformanceTest;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.config.SaxParserModule;
import org.jclouds.s3.domain.BucketMetadata;
import org.jclouds.s3.domain.CanonicalUser;
import org.jclouds.s3.domain.ListBucketResponse;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.s3.domain.ObjectMetadata.StorageClass;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.HttpException;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.config.SaxParserModule;
import org.jclouds.util.Strings2;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
@ -49,13 +53,14 @@ import org.xml.sax.SAXException;
import com.google.common.collect.Iterables;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.sun.jersey.api.uri.UriBuilderImpl;
/**
* Tests parsing of S3 responses
*
* @author Adrian Cole
*/
//NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "performance", sequential = true, timeOut = 2 * 60 * 1000, testName = "S3ParserTest")
public class S3ParserTest extends PerformanceTest {
Injector injector = null;
@ -63,7 +68,12 @@ public class S3ParserTest extends PerformanceTest {
@BeforeTest
protected void setUpInjector() {
injector = Guice.createInjector(new SaxParserModule());
injector = Guice.createInjector(new SaxParserModule() {
public void configure() {
super.configure();
bind(UriBuilder.class).to(UriBuilderImpl.class);
}
});
factory = injector.getInstance(ParseSax.Factory.class);
assert factory != null;
}
@ -140,7 +150,8 @@ public class S3ParserTest extends PerformanceTest {
}
private ListBucketResponse runParseListContainerResult() throws HttpException {
return (ListBucketResponse) factory.create(injector.getInstance(ListBucketHandler.class)).parse(
return (ListBucketResponse) factory.create(injector.getInstance(ListBucketHandler.class)).setContext(
HttpRequest.builder().method("GET").endpoint(URI.create("http://bucket.com")).build()).parse(
Strings2.toInputStream(listContainerResult));
}

View File

@ -39,6 +39,7 @@ import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils;
@ -82,14 +83,14 @@ public class SwiftAsyncBlobStore extends BaseAsyncBlobStore {
private final Provider<FetchBlobMetadata> fetchBlobMetadataProvider;
@Inject
SwiftAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations, CommonSwiftClient sync, CommonSwiftAsyncClient async,
ContainerToResourceMetadata container2ResourceMd,
BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob, BlobToObject blob2Object,
ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider) {
protected SwiftAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations, CommonSwiftClient sync,
CommonSwiftAsyncClient async, ContainerToResourceMetadata container2ResourceMd,
BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob, BlobToObject blob2Object,
ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider) {
super(context, blobUtils, service, defaultLocation, locations);
this.sync = sync;
this.async = async;
@ -109,11 +110,12 @@ public class SwiftAsyncBlobStore extends BaseAsyncBlobStore {
@Override
public ListenableFuture<PageSet<? extends StorageMetadata>> list() {
return Futures.compose(async.listContainers(),
new Function<Set<ContainerMetadata>, org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>>() {
public org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata> apply(Set<ContainerMetadata> from) {
return new PageSetImpl<StorageMetadata>(Iterables.transform(from, container2ResourceMd), null);
}
}, service);
new Function<Set<ContainerMetadata>, org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>>() {
public org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata> apply(
Set<ContainerMetadata> from) {
return new PageSetImpl<StorageMetadata>(Iterables.transform(from, container2ResourceMd), null);
}
}, service);
}
/**
@ -144,12 +146,12 @@ public class SwiftAsyncBlobStore extends BaseAsyncBlobStore {
@Override
public ListenableFuture<PageSet<? extends StorageMetadata>> list(String container, ListContainerOptions options) {
org.jclouds.openstack.swift.options.ListContainerOptions httpOptions = container2ContainerListOptions
.apply(options);
.apply(options);
ListenableFuture<PageSet<ObjectInfo>> returnVal = async.listObjects(container, httpOptions);
ListenableFuture<PageSet<? extends StorageMetadata>> list = Futures.compose(returnVal, container2ResourceList,
service);
service);
return options.isDetailed() ? Futures.compose(list, fetchBlobMetadataProvider.get().setContainerName(container),
service) : list;
service) : list;
}
/**
@ -176,14 +178,14 @@ public class SwiftAsyncBlobStore extends BaseAsyncBlobStore {
@Override
public ListenableFuture<BlobMetadata> blobMetadata(String container, String key) {
return Futures.compose(async.getObjectInfo(container, key),
new Function<MutableObjectInfoWithMetadata, BlobMetadata>() {
new Function<MutableObjectInfoWithMetadata, BlobMetadata>() {
@Override
public BlobMetadata apply(MutableObjectInfoWithMetadata from) {
return object2BlobMd.apply(from);
}
@Override
public BlobMetadata apply(MutableObjectInfoWithMetadata from) {
return object2BlobMd.apply(from);
}
}, service);
}, service);
}
/**
@ -239,4 +241,11 @@ public class SwiftAsyncBlobStore extends BaseAsyncBlobStore {
return putBlob(container, blob);
}
@Override
public ListenableFuture<Boolean> createContainerInLocation(Location location, String container,
CreateContainerOptions options) {
if (options.isPublicRead())
throw new UnsupportedOperationException("publicRead");
return createContainerInLocation(location, container);
}
}

View File

@ -36,6 +36,7 @@ import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils;
@ -72,7 +73,7 @@ public class SwiftBlobStore extends BaseBlobStore {
private final Provider<FetchBlobMetadata> fetchBlobMetadataProvider;
@Inject
SwiftBlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
protected SwiftBlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations, CommonSwiftClient sync,
ContainerToResourceMetadata container2ResourceMd,
BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
@ -226,4 +227,11 @@ public class SwiftBlobStore extends BaseBlobStore {
sync.deleteContainerIfEmpty(container);
return !sync.containerExists(container);
}
@Override
public boolean createContainerInLocation(Location location, String container, CreateContainerOptions options) {
if (options.isPublicRead())
throw new UnsupportedOperationException("publicRead");
return createContainerInLocation(location, container);
}
}

View File

@ -54,8 +54,9 @@ public class ObjectToBlobMetadata implements Function<ObjectInfo, MutableBlobMet
if (from.getHash() != null)
to.setETag(CryptoStreams.hex(from.getHash()));
to.setName(from.getName());
if (from.getBytes() != null)
to.getContentMetadata().setContentLength(from.getBytes());
to.setContainer(from.getContainer());
to.setUri(from.getUri());
to.getContentMetadata().setContentLength(from.getBytes());
if (from.getLastModified() != null)
to.setLastModified(from.getLastModified());
if (from instanceof MutableObjectInfoWithMetadata)

View File

@ -19,6 +19,7 @@
package org.jclouds.openstack.swift.domain;
import java.net.URI;
import java.util.Date;
import java.util.Map;
@ -44,6 +45,10 @@ public interface MutableObjectInfoWithMetadata extends ObjectInfo {
void setContentType(String contentType);
void setContainer(String container);
void setUri(URI uri);
Map<String, String> getMetadata();
}

View File

@ -19,6 +19,7 @@
package org.jclouds.openstack.swift.domain;
import java.net.URI;
import java.util.Date;
/**
@ -28,6 +29,8 @@ import java.util.Date;
*/
public interface ObjectInfo extends Comparable<ObjectInfo> {
URI getUri();
String getName();
byte[] getHash();
@ -38,4 +41,6 @@ public interface ObjectInfo extends Comparable<ObjectInfo> {
Date getLastModified();
String getContainer();
}

View File

@ -19,6 +19,7 @@
package org.jclouds.openstack.swift.domain.internal;
import java.net.URI;
import java.util.Date;
import java.util.Map;
@ -63,7 +64,8 @@ public class DelegatingMutableObjectInfoWithMetadata extends BaseMutableContentM
@Override
public void setContentLength(Long bytes) {
delegate.setBytes(bytes);
if (bytes != null)
delegate.setBytes(bytes);
}
@Override
@ -107,7 +109,7 @@ public class DelegatingMutableObjectInfoWithMetadata extends BaseMutableContentM
@Override
public Long getBytes() {
return delegate.getBytes();
return delegate.getBytes();
}
@Override
@ -129,4 +131,24 @@ public class DelegatingMutableObjectInfoWithMetadata extends BaseMutableContentM
public int compareTo(ObjectInfo o) {
return delegate.compareTo(o);
}
@Override
public void setContainer(String container) {
delegate.setContainer(container);
}
@Override
public String getContainer() {
return delegate.getContainer();
}
@Override
public void setUri(URI uri) {
delegate.setUri(uri);
}
@Override
public URI getUri() {
return delegate.getUri();
}
}

View File

@ -19,6 +19,7 @@
package org.jclouds.openstack.swift.domain.internal;
import java.net.URI;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
@ -37,44 +38,82 @@ import com.google.common.collect.Maps;
*/
public class MutableObjectInfoWithMetadataImpl implements MutableObjectInfoWithMetadata {
private String name;
private String container;
private URI uri;
private Long bytes;
private byte[] hash;
private String contentType = MediaType.APPLICATION_OCTET_STREAM;
private Date lastModified;
private final Map<String, String> metadata = Maps.newHashMap();
private final Map<String, String> metadata = Maps.newLinkedHashMap();
/**
* {@inheritDoc}
*/
@Override
public Map<String, String> getMetadata() {
return metadata;
}
/**
* {@inheritDoc}
*/
@Override
public void setBytes(Long bytes) {
this.bytes = bytes;
}
/**
* {@inheritDoc}
*/
@Override
public void setContentType(String contentType) {
this.contentType = contentType;
}
/**
* {@inheritDoc}
*/
@Override
public void setHash(byte[] hash) {
this.hash = hash;
}
/**
* {@inheritDoc}
*/
@Override
public void setName(String name) {
this.name = name;
}
/**
* {@inheritDoc}
*/
@Override
public Long getBytes() {
return bytes;
}
/**
* {@inheritDoc}
*/
@Override
public String getContentType() {
return contentType;
}
/**
* {@inheritDoc}
*/
@Override
public byte[] getHash() {
return hash;
}
/**
* {@inheritDoc}
*/
@Override
public Date getLastModified() {
return lastModified;
}
@ -83,11 +122,7 @@ public class MutableObjectInfoWithMetadataImpl implements MutableObjectInfoWithM
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((bytes == null) ? 0 : bytes.hashCode());
result = prime * result + ((contentType == null) ? 0 : contentType.hashCode());
result = prime * result + Arrays.hashCode(hash);
result = prime * result + ((lastModified == null) ? 0 : lastModified.hashCode());
result = prime * result + ((metadata == null) ? 0 : metadata.hashCode());
result = prime * result + ((container == null) ? 0 : container.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@ -101,27 +136,10 @@ public class MutableObjectInfoWithMetadataImpl implements MutableObjectInfoWithM
if (getClass() != obj.getClass())
return false;
MutableObjectInfoWithMetadataImpl other = (MutableObjectInfoWithMetadataImpl) obj;
if (bytes == null) {
if (other.bytes != null)
if (container == null) {
if (other.container != null)
return false;
} else if (!bytes.equals(other.bytes))
return false;
if (contentType == null) {
if (other.contentType != null)
return false;
} else if (!contentType.equals(other.contentType))
return false;
if (!Arrays.equals(hash, other.hash))
return false;
if (lastModified == null) {
if (other.lastModified != null)
return false;
} else if (!lastModified.equals(other.lastModified))
return false;
if (metadata == null) {
if (other.metadata != null)
return false;
} else if (!metadata.equals(other.metadata))
} else if (!container.equals(other.container))
return false;
if (name == null) {
if (other.name != null)
@ -131,16 +149,60 @@ public class MutableObjectInfoWithMetadataImpl implements MutableObjectInfoWithM
return true;
}
/**
* {@inheritDoc}
*/
@Override
public String getName() {
return name;
}
/**
* {@inheritDoc}
*/
@Override
public int compareTo(ObjectInfo o) {
return (this == o) ? 0 : getName().compareTo(o.getName());
}
/**
* {@inheritDoc}
*/
@Override
public void setLastModified(Date lastModified) {
this.lastModified = lastModified;
}
/**
* {@inheritDoc}
*/
@Override
public String getContainer() {
return container;
}
/**
* {@inheritDoc}
*/
@Override
public void setContainer(String container) {
this.container = container;
}
@Override
public void setUri(URI uri) {
this.uri = uri;
}
@Override
public URI getUri() {
return uri;
}
@Override
public String toString() {
return String.format("[name=%s, container=%s, uri=%s, bytes=%s, contentType=%s, lastModified=%s, hash=%s]", name,
container, uri, bytes, contentType, lastModified, Arrays.toString(hash));
}
}

View File

@ -19,56 +19,159 @@
package org.jclouds.openstack.swift.domain.internal;
import java.net.URI;
import java.util.Arrays;
import java.util.Date;
import org.jclouds.openstack.swift.domain.ObjectInfo;
import com.google.gson.annotations.SerializedName;
public class ObjectInfoImpl implements ObjectInfo {
String name;
byte[] hash;
long bytes;
String content_type;
Date last_modified;
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String name;
private String container;
private URI uri;
private byte[] hash;
private Long bytes;
private String contentType;
private Date lastModified;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder container(String container) {
this.container = container;
return this;
}
public Builder uri(URI uri) {
this.uri = uri;
return this;
}
public Builder hash(byte[] hash) {
this.hash = hash;
return this;
}
public Builder bytes(Long bytes) {
this.bytes = bytes;
return this;
}
public Builder contentType(String contentType) {
this.contentType = contentType;
return this;
}
public Builder lastModified(Date lastModified) {
this.lastModified = lastModified;
return this;
}
public ObjectInfoImpl build() {
return new ObjectInfoImpl(name, uri, container, hash, bytes, contentType, lastModified);
}
public Builder fromObjectInfo(ObjectInfo in) {
return name(in.getName()).container(in.getContainer()).uri(uri).hash(in.getHash()).bytes(in.getBytes())
.contentType(in.getContentType()).lastModified(in.getLastModified());
}
}
private String name;
private String container;
private URI uri;
private byte[] hash;
private Long bytes;
@SerializedName("content_type")
private String contentType;
@SerializedName("last_modified")
private Date lastModified;
public ObjectInfoImpl(String name, URI uri, String container, byte[] hash, Long bytes, String contentType,
Date lastModified) {
this.name = name;
this.container = container;
this.uri = uri;
this.hash = hash;
this.bytes = bytes;
this.contentType = contentType;
this.lastModified = lastModified;
}
ObjectInfoImpl() {
}
public int compareTo(ObjectInfoImpl o) {
return (this == o) ? 0 : name.compareTo(o.name);
/**
* {@inheritDoc}
*/
@Override
public String getName() {
return name;
}
public Long getBytes() {
return bytes;
/**
* {@inheritDoc}
*/
@Override
public String getContainer() {
return container;
}
public String getContentType() {
return content_type;
/**
* {@inheritDoc}
*/
@Override
public URI getUri() {
return uri;
}
/**
* {@inheritDoc}
*/
@Override
public byte[] getHash() {
return hash;
}
public Date getLastModified() {
return last_modified;
/**
* {@inheritDoc}
*/
@Override
public Long getBytes() {
return bytes;
}
public String getName() {
return name;
/**
* {@inheritDoc}
*/
@Override
public String getContentType() {
return contentType;
}
/**
* {@inheritDoc}
*/
@Override
public Date getLastModified() {
return lastModified;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (bytes ^ (bytes >>> 32));
result = prime * result
+ ((content_type == null) ? 0 : content_type.hashCode());
result = prime * result + Arrays.hashCode(hash);
result = prime * result
+ ((last_modified == null) ? 0 : last_modified.hashCode());
result = prime * result + ((container == null) ? 0 : container.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@ -82,19 +185,10 @@ public class ObjectInfoImpl implements ObjectInfo {
if (getClass() != obj.getClass())
return false;
ObjectInfoImpl other = (ObjectInfoImpl) obj;
if (bytes != other.bytes)
return false;
if (content_type == null) {
if (other.content_type != null)
if (container == null) {
if (other.container != null)
return false;
} else if (!content_type.equals(other.content_type))
return false;
if (!Arrays.equals(hash, other.hash))
return false;
if (last_modified == null) {
if (other.last_modified != null)
return false;
} else if (!last_modified.equals(other.last_modified))
} else if (!container.equals(other.container))
return false;
if (name == null) {
if (other.name != null)
@ -104,15 +198,19 @@ public class ObjectInfoImpl implements ObjectInfo {
return true;
}
public int compareTo(ObjectInfo o) {
return (this == o) ? 0 : getName().compareTo(o.getName());
@Override
public String toString() {
return String.format("[name=%s, container=%s, uri=%s, bytes=%s, contentType=%s, lastModified=%s, hash=%s]", name,
container, uri, bytes, contentType, lastModified, Arrays.toString(hash));
}
public Builder toBuilder() {
return builder().fromObjectInfo(this);
}
@Override
public String toString() {
return "ObjectInfoImpl [bytes=" + bytes + ", content_flavor="
+ content_type + ", hash=" + Arrays.asList(hash)
+ ", last_modified=" + last_modified.getTime() + ", name=" + name
+ "]";
public int compareTo(ObjectInfo o) {
return name.compareTo(o.getName());
}
}

View File

@ -19,6 +19,7 @@
package org.jclouds.openstack.swift.functions;
import static com.google.common.base.Preconditions.checkArgument;
import static org.jclouds.http.HttpUtils.attemptToParseSizeAndRangeFromHeaders;
import javax.inject.Inject;
@ -31,6 +32,7 @@ import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.swift.blobstore.functions.ResourceToObjectInfo;
import org.jclouds.openstack.swift.domain.MutableObjectInfoWithMetadata;
import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Function;
@ -43,6 +45,7 @@ public class ParseObjectInfoFromHeaders implements Function<HttpResponse, Mutabl
InvocationContext<ParseObjectInfoFromHeaders> {
private final ParseSystemAndUserMetadataFromHeaders blobMetadataParser;
private final ResourceToObjectInfo blobToObjectInfo;
private String container;
@Inject
public ParseObjectInfoFromHeaders(ParseSystemAndUserMetadataFromHeaders blobMetadataParser,
@ -58,6 +61,8 @@ public class ParseObjectInfoFromHeaders implements Function<HttpResponse, Mutabl
BlobMetadata base = blobMetadataParser.apply(from);
MutableObjectInfoWithMetadata to = blobToObjectInfo.apply(base);
to.setBytes(attemptToParseSizeAndRangeFromHeaders(from));
to.setContainer(container);
to.setUri(base.getUri());
String eTagHeader = from.getFirstHeaderOrNull("Etag");
if (eTagHeader != null) {
to.setHash(CryptoStreams.hex(eTagHeader));
@ -68,6 +73,12 @@ public class ParseObjectInfoFromHeaders implements Function<HttpResponse, Mutabl
@Override
public ParseObjectInfoFromHeaders setContext(HttpRequest request) {
blobMetadataParser.setContext(request);
checkArgument(request instanceof GeneratedHttpRequest<?>, "note this handler requires a GeneratedHttpRequest");
return setContainer(GeneratedHttpRequest.class.cast(request).getArgs().get(0).toString());
}
private ParseObjectInfoFromHeaders setContainer(String container) {
this.container = container;
return this;
}

View File

@ -28,6 +28,8 @@ import java.lang.reflect.Type;
import java.util.SortedSet;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.internal.PageSetImpl;
@ -51,14 +53,18 @@ import com.google.inject.TypeLiteral;
*
* @author Adrian Cole
*/
public class ParseObjectInfoListFromJsonResponse extends ParseJson<PageSet<ObjectInfo>> implements InvocationContext<ParseObjectInfoListFromJsonResponse> {
public class ParseObjectInfoListFromJsonResponse extends ParseJson<PageSet<ObjectInfo>> implements
InvocationContext<ParseObjectInfoListFromJsonResponse> {
private final Provider<UriBuilder> uriBuilders;
private GeneratedHttpRequest<?> request;
private String container;
@Inject
public ParseObjectInfoListFromJsonResponse(Json json) {
public ParseObjectInfoListFromJsonResponse(Json json, Provider<UriBuilder> uriBuilders) {
super(json, new TypeLiteral<PageSet<ObjectInfo>>() {
});
this.uriBuilders = uriBuilders;
}
public PageSet<ObjectInfo> apply(InputStream stream) {
@ -66,7 +72,7 @@ public class ParseObjectInfoListFromJsonResponse extends ParseJson<PageSet<Objec
checkState(request.getArgs() != null, "request.getArgs() should be initialized at this point");
checkArgument(request.getArgs().get(0) instanceof String, "arg[0] must be a container name");
checkArgument(request.getArgs().get(1) instanceof ListContainerOptions[],
"arg[1] must be an array of ListContainerOptions");
"arg[1] must be an array of ListContainerOptions");
ListContainerOptions[] optionsList = (ListContainerOptions[]) request.getArgs().get(1);
ListContainerOptions options = optionsList.length > 0 ? optionsList[0] : ListContainerOptions.NONE;
Type listType = new TypeToken<SortedSet<ObjectInfoImpl>>() {
@ -75,11 +81,13 @@ public class ParseObjectInfoListFromJsonResponse extends ParseJson<PageSet<Objec
try {
SortedSet<ObjectInfoImpl> list = apply(stream, listType);
SortedSet<ObjectInfo> returnVal = Sets.newTreeSet(Iterables.transform(list,
new Function<ObjectInfoImpl, ObjectInfo>() {
public ObjectInfo apply(ObjectInfoImpl from) {
return from;
}
}));
new Function<ObjectInfoImpl, ObjectInfo>() {
public ObjectInfo apply(ObjectInfoImpl from) {
return from.toBuilder().container(container).uri(
uriBuilders.get().uri(request.getEndpoint()).path(from.getName()).replaceQuery("")
.build()).build();
}
}));
boolean truncated = options.getMaxResults() == returnVal.size();
String marker = truncated ? returnVal.last().getName() : null;
return new PageSetImpl<ObjectInfo>(returnVal, marker);
@ -92,6 +100,11 @@ public class ParseObjectInfoListFromJsonResponse extends ParseJson<PageSet<Objec
public ParseObjectInfoListFromJsonResponse setContext(HttpRequest request) {
checkArgument(request instanceof GeneratedHttpRequest<?>, "note this handler requires a GeneratedHttpRequest");
this.request = (GeneratedHttpRequest<?>) request;
return setContainer(GeneratedHttpRequest.class.cast(request).getArgs().get(0).toString());
}
private ParseObjectInfoListFromJsonResponse setContainer(String container) {
this.container = container;
return this;
}
}

View File

@ -25,8 +25,11 @@ import static org.easymock.classextension.EasyMock.replay;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI;
import java.util.Set;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.crypto.CryptoStreams;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.json.config.GsonModule;
@ -39,10 +42,11 @@ import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.sun.jersey.api.uri.UriBuilderImpl;
/**
* Tests behavior of {@code ParseObjectInfoListFromJsonResponse}
@ -57,34 +61,31 @@ public class ParseObjectInfoListFromJsonResponseTest {
@Override
protected void configure() {
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
bind(UriBuilder.class).to(UriBuilderImpl.class);
}
}, new GsonModule());
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/test_list_container.json");
Set<ObjectInfo> expects = Sets.newLinkedHashSet();
ObjectInfoImpl one = i.getInstance(ObjectInfoImpl.class);
one.name = "test_obj_1";
one.hash = CryptoStreams.hex("4281c348eaf83e70ddce0e07221c3d28");
one.bytes = 14l;
one.content_type = "application/octet-stream";
one.last_modified = new SimpleDateFormatDateService().iso8601DateParse("2009-02-03T05:26:32.612Z");
expects.add(one);
ObjectInfoImpl two = i.getInstance(ObjectInfoImpl.class);
two.name = ("test_obj_2");
two.hash = CryptoStreams.hex("b039efe731ad111bc1b0ef221c3849d0");
two.bytes = (64l);
two.content_type = ("application/octet-stream");
two.last_modified = (new SimpleDateFormatDateService().iso8601DateParse("2009-02-03T05:26:32.612Z"));
expects.add(two);
Set<ObjectInfo> expects = ImmutableSet.<ObjectInfo> of(ObjectInfoImpl.builder().container("container").name(
"test_obj_1").uri(URI.create("http://localhost/foo/test_obj_1")).hash(
CryptoStreams.hex("4281c348eaf83e70ddce0e07221c3d28")).bytes(14l)
.contentType("application/octet-stream").lastModified(
new SimpleDateFormatDateService().iso8601DateParse("2009-02-03T05:26:32.612Z")).build(),
ObjectInfoImpl.builder().container("container").name("test_obj_2").uri(
URI.create("http://localhost/foo/test_obj_2")).hash(
CryptoStreams.hex("b039efe731ad111bc1b0ef221c3849d0")).bytes(64l).contentType(
"application/octet-stream").lastModified(
new SimpleDateFormatDateService().iso8601DateParse("2009-02-03T05:26:32.612Z")).build());
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
ListContainerOptions options = new ListContainerOptions();
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/foo")).atLeastOnce();
expect(request.getArgs()).andReturn(
ImmutableList.<Object> of("containter", new ListContainerOptions[] { options })).atLeastOnce();
ImmutableList.<Object> of("container", new ListContainerOptions[] { options })).atLeastOnce();
replay(request);
ParseObjectInfoListFromJsonResponse parser = i.getInstance(ParseObjectInfoListFromJsonResponse.class);
parser.setContext(request);
assertEquals(parser.apply(is), expects);
assertEquals(parser.apply(is).toString(), expects.toString());
}
}

View File

@ -28,6 +28,7 @@ import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.GetOptions;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.domain.Location;
@ -77,6 +78,12 @@ public interface AsyncBlobStore {
*/
ListenableFuture<Boolean> createContainerInLocation(@Nullable Location location, String container);
/**
* @see BlobStore#createContainerInLocation(Location,String,CreateContainerOptions)
*/
ListenableFuture<Boolean> createContainerInLocation(@Nullable Location location, String container,
CreateContainerOptions options);
/**
* @see BlobStore#list(String)
*/

View File

@ -28,6 +28,7 @@ import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.GetOptions;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.domain.Location;
@ -100,6 +101,14 @@ public interface BlobStore {
*/
boolean createContainerInLocation(@Nullable Location location, String container);
/**
*
* @param options
* controls default access control
* @see #createContainerInLocation(Location,String)
*/
boolean createContainerInLocation(@Nullable Location location, String container, CreateContainerOptions options);
/**
* Lists all resources in a container non-recursive.
*

View File

@ -50,10 +50,10 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
@ -61,21 +61,24 @@ import java.util.concurrent.ExecutorService;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.Constants;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.MutableBlobMetadata;
import org.jclouds.blobstore.domain.MutableStorageMetadata;
import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.blobstore.domain.internal.MutableStorageMetadataImpl;
import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.HttpGetOptionsListToGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.GetOptions;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.IfDirectoryReturnNameStrategy;
@ -91,6 +94,7 @@ import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.options.HttpRequestOptions;
import org.jclouds.io.ContentMetadata;
import org.jclouds.io.MutableContentMetadata;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
@ -117,6 +121,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
protected final DateService dateService;
protected final Crypto crypto;
protected final ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs;
protected final Provider<UriBuilder> uriBuilders;
protected final ConcurrentMap<String, Location> containerToLocation;
protected final HttpGetOptionsListToGetOptions httpGetOptionsConverter;
protected final IfDirectoryReturnNameStrategy ifDirectoryReturnName;
@ -124,16 +129,18 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
@Inject
protected TransientAsyncBlobStore(BlobStoreContext context, DateService dateService, Crypto crypto,
ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs,
ConcurrentMap<String, Location> containerToLocation, HttpGetOptionsListToGetOptions httpGetOptionsConverter,
IfDirectoryReturnNameStrategy ifDirectoryReturnName, Factory blobFactory, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations) {
ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs, Provider<UriBuilder> uriBuilders,
ConcurrentMap<String, Location> containerToLocation,
HttpGetOptionsListToGetOptions httpGetOptionsConverter,
IfDirectoryReturnNameStrategy ifDirectoryReturnName, Factory blobFactory, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations) {
super(context, blobUtils, service, defaultLocation, locations);
this.blobFactory = blobFactory;
this.dateService = dateService;
this.crypto = crypto;
this.containerToBlobs = containerToBlobs;
this.uriBuilders = uriBuilders;
this.containerToLocation = containerToLocation;
this.httpGetOptionsConverter = httpGetOptionsConverter;
this.ifDirectoryReturnName = ifDirectoryReturnName;
@ -152,21 +159,21 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
return immediateFailedFuture(cnfe(container));
SortedSet<StorageMetadata> contents = newTreeSet(transform(realContents.keySet(),
new Function<String, StorageMetadata>() {
public StorageMetadata apply(String key) {
Blob oldBlob = realContents.get(key);
checkState(oldBlob != null, "blob " + key + " is not present although it was in the list of "
+ container);
checkState(oldBlob.getMetadata() != null, "blob " + container + "/" + key + " has no metadata");
MutableBlobMetadata md = copy(oldBlob.getMetadata());
String directoryName = ifDirectoryReturnName.execute(md);
if (directoryName != null) {
md.setName(directoryName);
md.setType(StorageType.RELATIVE_PATH);
new Function<String, StorageMetadata>() {
public StorageMetadata apply(String key) {
Blob oldBlob = realContents.get(key);
checkState(oldBlob != null, "blob " + key + " is not present although it was in the list of "
+ container);
checkState(oldBlob.getMetadata() != null, "blob " + container + "/" + key + " has no metadata");
MutableBlobMetadata md = copy(oldBlob.getMetadata());
String directoryName = ifDirectoryReturnName.execute(md);
if (directoryName != null) {
md.setName(directoryName);
md.setType(StorageType.RELATIVE_PATH);
}
return md;
}
return md;
}
}));
}));
if (options.getMarker() != null) {
final String finalMarker = options.getMarker();
@ -210,15 +217,15 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
contents = newTreeSet(filter(contents, new DelimiterFilter(prefix != null ? prefix : null, delimiter)));
Iterables.<StorageMetadata> addAll(contents,
transform(commonPrefixes, new Function<String, StorageMetadata>() {
public StorageMetadata apply(String o) {
MutableStorageMetadata md = new MutableStorageMetadataImpl();
md.setType(StorageType.RELATIVE_PATH);
md.setName(o);
return md;
}
}));
Iterables.<StorageMetadata> addAll(contents, transform(commonPrefixes,
new Function<String, StorageMetadata>() {
public StorageMetadata apply(String o) {
MutableStorageMetadata md = new MutableStorageMetadataImpl();
md.setType(StorageType.RELATIVE_PATH);
md.setName(o);
return md;
}
}));
}
// trim metadata, if the response isn't supposed to be detailed.
@ -229,13 +236,13 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
}
return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(contents,
marker));
marker));
}
private ContainerNotFoundException cnfe(final String name) {
return new ContainerNotFoundException(name, String.format("container %s not in %s", name, getContainerToBlobs()
.keySet()));
.keySet()));
}
public static MutableBlobMetadata copy(MutableBlobMetadata in) {
@ -333,15 +340,15 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
@Override
public ListenableFuture<PageSet<? extends StorageMetadata>> list() {
return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(transform(
getContainerToBlobs().keySet(), new Function<String, StorageMetadata>() {
public StorageMetadata apply(String name) {
MutableStorageMetadata cmd = create();
cmd.setName(name);
cmd.setType(StorageType.CONTAINER);
cmd.setLocation(getContainerToLocation().get(name));
return cmd;
}
}), null));
getContainerToBlobs().keySet(), new Function<String, StorageMetadata>() {
public StorageMetadata apply(String name) {
MutableStorageMetadata cmd = create();
cmd.setName(name);
cmd.setType(StorageType.CONTAINER);
cmd.setLocation(getContainerToLocation().get(name));
return cmd;
}
}), null));
}
protected MutableStorageMetadata create() {
@ -365,7 +372,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
*/
public ListenableFuture<Void> createContainerInLocationIfAbsent(final Location location, final String name) {
ConcurrentMap<String, Blob> container = getContainerToBlobs().putIfAbsent(name,
new ConcurrentHashMap<String, Blob>());
new ConcurrentHashMap<String, Blob>());
if (container == null) {
getContainerToLocation().put(name, location != null ? location : defaultLocation.get());
return immediateFuture((Void) null);
@ -495,7 +502,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
new IllegalStateException("containerName not found: " + containerName);
}
Blob blob = createUpdatedCopyOfBlob(in);
Blob blob = createUpdatedCopyOfBlobInContainer(containerName, in);
container.put(blob.getMetadata().getName(), blob);
@ -508,22 +515,22 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
new IllegalStateException("containerName not found: " + containerName);
}
Blob blob = createUpdatedCopyOfBlob(in);
Blob blob = createUpdatedCopyOfBlobInContainer(containerName, in);
Blob old = container.put(blob.getMetadata().getName(), blob);
return immediateFuture(old);
}
protected Blob createUpdatedCopyOfBlob(Blob in) {
protected Blob createUpdatedCopyOfBlobInContainer(String containerName, Blob in) {
checkNotNull(in, "blob");
checkNotNull(in.getPayload(), "blob.payload");
ByteArrayPayload payload = (in.getPayload() instanceof ByteArrayPayload) ? ByteArrayPayload.class.cast(in
.getPayload()) : null;
.getPayload()) : null;
if (payload == null)
payload = (in.getPayload() instanceof DelegatingPayload) ? (DelegatingPayload.class.cast(in.getPayload())
.getDelegate() instanceof ByteArrayPayload) ? ByteArrayPayload.class.cast(DelegatingPayload.class.cast(
in.getPayload()).getDelegate()) : null : null;
.getDelegate() instanceof ByteArrayPayload) ? ByteArrayPayload.class.cast(DelegatingPayload.class
.cast(in.getPayload()).getDelegate()) : null : null;
try {
if (payload == null || !(payload instanceof ByteArrayPayload)) {
MutableContentMetadata oldMd = in.getPayload().getContentMetadata();
@ -540,12 +547,15 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
}
Blob blob = blobFactory.create(copy(in.getMetadata()));
blob.setPayload(payload);
blob.getMetadata().setContainer(containerName);
blob.getMetadata().setUri(
uriBuilders.get().scheme("mem").host(containerName).path(in.getMetadata().getName()).build());
blob.getMetadata().setLastModified(new Date());
String eTag = CryptoStreams.hex(payload.getContentMetadata().getContentMD5());
blob.getMetadata().setETag(eTag);
// Set HTTP headers to match metadata
blob.getAllHeaders().replaceValues(HttpHeaders.LAST_MODIFIED,
Collections.singleton(dateService.rfc822DateFormat(blob.getMetadata().getLastModified())));
Collections.singleton(dateService.rfc822DateFormat(blob.getMetadata().getLastModified())));
blob.getAllHeaders().replaceValues(HttpHeaders.ETAG, Collections.singleton(eTag));
copyPayloadHeadersToBlob(payload, blob);
blob.getAllHeaders().putAll(Multimaps.forMap(blob.getMetadata().getUserMetadata()));
@ -593,7 +603,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
if (object.getMetadata().getLastModified().before(modifiedSince)) {
HttpResponse response = new HttpResponse(304, null, null);
return immediateFailedFuture(new HttpResponseException(String.format("%1$s is before %2$s", object
.getMetadata().getLastModified(), modifiedSince), null, response));
.getMetadata().getLastModified(), modifiedSince), null, response));
}
}
@ -602,7 +612,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
if (object.getMetadata().getLastModified().after(unmodifiedSince)) {
HttpResponse response = new HttpResponse(412, null, null);
return immediateFailedFuture(new HttpResponseException(String.format("%1$s is after %2$s", object
.getMetadata().getLastModified(), unmodifiedSince), null, response));
.getMetadata().getLastModified(), unmodifiedSince), null, response));
}
}
Blob returnVal = copyBlob(object);
@ -633,7 +643,10 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
}
}
ContentMetadata cmd = returnVal.getPayload().getContentMetadata();
returnVal.setPayload(out.toByteArray());
HttpUtils.copy(cmd, returnVal.getPayload().getContentMetadata());
returnVal.getPayload().getContentMetadata().setContentLength(new Long(out.toByteArray().length));
}
checkNotNull(returnVal.getPayload(), "payload " + returnVal);
return immediateFuture(returnVal);
@ -681,4 +694,12 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
return putBlob(container, blob);
}
@Override
public ListenableFuture<Boolean> createContainerInLocation(Location location, String container,
CreateContainerOptions options) {
if (options.isPublicRead())
throw new UnsupportedOperationException("publicRead");
return createContainerInLocation(location, container);
}
}

View File

@ -19,6 +19,10 @@
package org.jclouds.blobstore.domain;
import java.net.URI;
import javax.annotation.Nullable;
import org.jclouds.blobstore.domain.internal.BlobMetadataImpl;
import org.jclouds.io.ContentMetadata;
@ -31,5 +35,20 @@ import com.google.inject.ImplementedBy;
*/
@ImplementedBy(BlobMetadataImpl.class)
public interface BlobMetadata extends StorageMetadata {
/**
* If the blob is publicly readable, what is the URI one can access it at.
*
* @return uri, or null, if not readable
*/
@Nullable
URI getPublicUri();
/**
*
* @return the container holding this blob
*/
@Nullable
String getContainer();
ContentMetadata getContentMetadata();
}

View File

@ -19,6 +19,10 @@
package org.jclouds.blobstore.domain;
import java.net.URI;
import javax.annotation.Nullable;
import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
import org.jclouds.io.MutableContentMetadata;
@ -31,8 +35,24 @@ import com.google.inject.ImplementedBy;
*/
@ImplementedBy(MutableBlobMetadataImpl.class)
public interface MutableBlobMetadata extends BlobMetadata, MutableStorageMetadata {
/**
* {@inheritDoc}
*/
@Override
MutableContentMetadata getContentMetadata();
/**
* @see BlobMetadata#getContentMetadata
*/
void setContentMetadata(MutableContentMetadata md);
/**
* @see BlobMetadata#getPublicUri
*/
void setPublicUri(@Nullable URI publicUri);
/**
* @see BlobMetadata#getContainer
*/
void setContainer(@Nullable String container);
}

View File

@ -42,14 +42,35 @@ import org.jclouds.io.ContentMetadata;
public class BlobMetadataImpl extends StorageMetadataImpl implements Serializable, BlobMetadata {
/** The serialVersionUID */
private static final long serialVersionUID = -5932618957134612231L;
private final URI publicUri;
private final String container;
private final ContentMetadata contentMetadata;
public BlobMetadataImpl(String id, String name, @Nullable Location location, URI uri, String eTag,
Date lastModified, Map<String, String> userMetadata, ContentMetadata contentMetadata) {
Date lastModified, Map<String, String> userMetadata, @Nullable URI publicUri, @Nullable String container,
ContentMetadata contentMetadata) {
super(StorageType.BLOB, id, name, location, uri, eTag, lastModified, userMetadata);
this.publicUri = publicUri;
this.container = container;
this.contentMetadata = checkNotNull(contentMetadata, "contentMetadata");
}
/**
* {@inheritDoc}
*/
@Override
public URI getPublicUri() {
return publicUri;
}
/**
* {@inheritDoc}
*/
@Override
public String getContainer() {
return container;
}
/**
* {@inheritDoc}
*/

View File

@ -19,6 +19,8 @@
package org.jclouds.blobstore.domain.internal;
import java.net.URI;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.MutableBlobMetadata;
@ -36,9 +38,10 @@ public class MutableBlobMetadataImpl extends MutableStorageMetadataImpl implemen
/** The serialVersionUID */
private static final long serialVersionUID = -5932618957134612231L;
private MutableContentMetadata contentMetadata;
private URI publicUri;
private String container;
public MutableBlobMetadataImpl() {
super();
this.setType(StorageType.BLOB);
this.contentMetadata = new BaseMutableContentMetadata();
}
@ -47,6 +50,8 @@ public class MutableBlobMetadataImpl extends MutableStorageMetadataImpl implemen
super(from);
this.contentMetadata = new BaseMutableContentMetadata();
HttpUtils.copy(from.getContentMetadata(), this.contentMetadata);
this.publicUri = from.getPublicUri();
this.container = from.getContainer();
}
/**
@ -65,4 +70,36 @@ public class MutableBlobMetadataImpl extends MutableStorageMetadataImpl implemen
this.contentMetadata = contentMetadata;
}
/**
* {@inheritDoc}
*/
@Override
public void setPublicUri(URI publicUri) {
this.publicUri = publicUri;
}
/**
* {@inheritDoc}
*/
@Override
public URI getPublicUri() {
return publicUri;
}
/**
* {@inheritDoc}
*/
@Override
public String getContainer() {
return container;
}
/**
* {@inheritDoc}
*/
@Override
public void setContainer(String container) {
this.container = container;
}
}

View File

@ -25,6 +25,7 @@ import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
import static org.jclouds.blobstore.util.BlobStoreUtils.getNameFor;
import java.net.URI;
import java.util.Map.Entry;
import javax.inject.Inject;
@ -54,6 +55,7 @@ public class ParseSystemAndUserMetadataFromHeaders implements Function<HttpRespo
private final Provider<MutableBlobMetadata> metadataFactory;
private String name;
private URI endpoint;
@Inject
public ParseSystemAndUserMetadataFromHeaders(Provider<MutableBlobMetadata> metadataFactory, DateService dateParser,
@ -69,6 +71,7 @@ public class ParseSystemAndUserMetadataFromHeaders implements Function<HttpRespo
MutableBlobMetadata to = metadataFactory.get();
to.setName(name);
to.setUri(endpoint);
if (from.getPayload() != null)
HttpUtils.copy(from.getPayload().getContentMetadata(), to.getContentMetadata());
addETagTo(from, to);
@ -115,6 +118,7 @@ public class ParseSystemAndUserMetadataFromHeaders implements Function<HttpRespo
}
public ParseSystemAndUserMetadataFromHeaders setContext(HttpRequest request) {
this.endpoint = request.getEndpoint();
checkArgument(request instanceof GeneratedHttpRequest<?>, "note this handler requires a GeneratedHttpRequest");
return setName(getNameFor(GeneratedHttpRequest.class.cast(request)));
}

View File

@ -0,0 +1,114 @@
/**
*
* 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.options;
/**
* Contains options supported in the list container operation. <h2>
* Usage</h2> The recommended way to instantiate a CreateOptions object is to statically import
* CreateContainerOptions.* and invoke a static creation method followed by an instance mutator (if
* needed):
* <p/>
* <code>
* import static org.jclouds.blobstore.options.CreateContainerOptions.Builder.*
* <p/>
* BlobStore connection = // get connection
* Future<CreateResponse<ResourceMetadata>> list = connection.list("container",inDirectory("home/users").maxResults(1000));
* <code>
*
* @author Adrian Cole
*/
public class CreateContainerOptions implements Cloneable {
public static final ImmutableCreateContainerOptions NONE = new ImmutableCreateContainerOptions(
new CreateContainerOptions());
private boolean publicRead;
public CreateContainerOptions() {
}
CreateContainerOptions(boolean publicRead) {
this.publicRead = publicRead;
}
public static class ImmutableCreateContainerOptions extends CreateContainerOptions {
private final CreateContainerOptions delegate;
public ImmutableCreateContainerOptions(CreateContainerOptions delegate) {
this.delegate = delegate;
}
@Override
public boolean isPublicRead() {
return delegate.isPublicRead();
}
@Override
public CreateContainerOptions publicRead() {
throw new UnsupportedOperationException();
}
@Override
public CreateContainerOptions clone() {
return delegate.clone();
}
@Override
public String toString() {
return delegate.toString();
}
}
public boolean isPublicRead() {
return publicRead;
}
/**
* return a listing of all objects inside the store, publicReadly.
*/
public CreateContainerOptions publicRead() {
// checkArgument(path == null, "path and publicRead combination currently not supported");
this.publicRead = true;
return this;
}
public static class Builder {
/**
* @see CreateContainerOptions#publicRead()
*/
public static CreateContainerOptions publicRead() {
CreateContainerOptions options = new CreateContainerOptions();
return options.publicRead();
}
}
@Override
public CreateContainerOptions clone() {
return new CreateContainerOptions(publicRead);
}
@Override
public String toString() {
return "[publicRead=" + publicRead + "]";
}
}

View File

@ -49,11 +49,11 @@ import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobBuilder.PayloadBlobBuilder;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.blobstore.domain.BlobBuilder.PayloadBlobBuilder;
import org.jclouds.concurrent.Futures;
import org.jclouds.crypto.Crypto;
import org.jclouds.crypto.CryptoStreams;
@ -99,7 +99,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
@SuppressWarnings("unchecked")
public static InputSupplier<InputStream> getTestDataSupplier() throws IOException {
byte[] oneConstitution = ByteStreams.toByteArray(new GZIPInputStream(BaseJettyTest.class
.getResourceAsStream("/const.txt.gz")));
.getResourceAsStream("/const.txt.gz")));
InputSupplier<ByteArrayInputStream> constitutionSupplier = ByteStreams.newInputStreamSupplier(oneConstitution);
InputSupplier<InputStream> temp = ByteStreams.join(constitutionSupplier);
@ -114,178 +114,181 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
@Test(groups = { "integration", "live" })
public void testBigFileGets() throws InterruptedException, IOException {
final String expectedContentDisposition = "attachment; filename=constit.txt";
String containerName = getContainerName();
final String container = getContainerName();
try {
String key = "constitution.txt";
final String name = "constitution.txt";
uploadConstitution(containerName, key, expectedContentDisposition);
uploadConstitution(container, name, expectedContentDisposition);
Map<Integer, Future<?>> responses = Maps.newHashMap();
for (int i = 0; i < 10; i++) {
responses.put(i,
Futures.compose(context.getAsyncBlobStore().getBlob(containerName, key), new Function<Blob, Void>() {
responses.put(i, Futures.compose(context.getAsyncBlobStore().getBlob(container, name),
new Function<Blob, Void>() {
@Override
public Void apply(Blob from) {
try {
assertEquals(CryptoStreams.md5(from.getPayload()), oneHundredOneConstitutionsMD5);
checkContentDisposition(from, expectedContentDisposition);
} catch (IOException e) {
Throwables.propagate(e);
@Override
public Void apply(Blob from) {
try {
validateMetadata(from.getMetadata(), container, name);
assertEquals(CryptoStreams.md5(from.getPayload()), oneHundredOneConstitutionsMD5);
checkContentDisposition(from, expectedContentDisposition);
} catch (IOException e) {
Throwables.propagate(e);
}
return null;
}
return null;
}
}, this.exec));
}, this.exec));
}
Map<Integer, Exception> exceptions = awaitCompletion(responses, exec, 30000l, Logger.CONSOLE,
"get constitution");
"get constitution");
assert exceptions.size() == 0 : exceptions;
} finally {
returnContainer(containerName);
returnContainer(container);
}
}
private void uploadConstitution(String containerName, String key, String contentDisposition) throws IOException {
private void uploadConstitution(String container, String name, String contentDisposition) throws IOException {
context.getBlobStore().putBlob(
containerName,
context.getBlobStore().blobBuilder(key).payload(oneHundredOneConstitutions.getInput())
.contentType("text/plain").contentMD5(oneHundredOneConstitutionsMD5)
.contentLength(oneHundredOneConstitutionsLength).contentDisposition(contentDisposition).build());
container,
context.getBlobStore().blobBuilder(name).payload(oneHundredOneConstitutions.getInput()).contentType(
"text/plain").contentMD5(oneHundredOneConstitutionsMD5).contentLength(
oneHundredOneConstitutionsLength).contentDisposition(contentDisposition).build());
}
@Test(groups = { "integration", "live" })
public void testGetIfModifiedSince() throws InterruptedException {
String containerName = getContainerName();
String container = getContainerName();
try {
String key = "apples";
String name = "apples";
Date before = new Date(System.currentTimeMillis() - 1000);
// first create the blob
addObjectAndValidateContent(containerName, key);
addObjectAndValidateContent(container, name);
// now, modify it
addObjectAndValidateContent(containerName, key);
addObjectAndValidateContent(container, name);
Date after = new Date(System.currentTimeMillis() + 1000);
context.getBlobStore().getBlob(containerName, key, ifModifiedSince(before));
validateContent(containerName, key);
context.getBlobStore().getBlob(container, name, ifModifiedSince(before));
validateContent(container, name);
try {
context.getBlobStore().getBlob(containerName, key, ifModifiedSince(after));
validateContent(containerName, key);
context.getBlobStore().getBlob(container, name, ifModifiedSince(after));
validateContent(container, name);
} catch (HttpResponseException ex) {
assertEquals(ex.getResponse().getStatusCode(), 304);
}
} finally {
returnContainer(containerName);
returnContainer(container);
}
}
@Test(groups = { "integration", "live" })
public void testGetIfUnmodifiedSince() throws InterruptedException {
String containerName = getContainerName();
String container = getContainerName();
try {
String key = "apples";
String name = "apples";
Date before = new Date(System.currentTimeMillis() - 1000);
addObjectAndValidateContent(containerName, key);
addObjectAndValidateContent(container, name);
Date after = new Date(System.currentTimeMillis() + 1000);
context.getBlobStore().getBlob(containerName, key, ifUnmodifiedSince(after));
validateContent(containerName, key);
context.getBlobStore().getBlob(container, name, ifUnmodifiedSince(after));
validateContent(container, name);
try {
context.getBlobStore().getBlob(containerName, key, ifUnmodifiedSince(before));
validateContent(containerName, key);
context.getBlobStore().getBlob(container, name, ifUnmodifiedSince(before));
validateContent(container, name);
} catch (HttpResponseException ex) {
assertEquals(ex.getResponse().getStatusCode(), 412);
}
} finally {
returnContainer(containerName);
returnContainer(container);
}
}
@Test(groups = { "integration", "live" })
public void testGetIfMatch() throws InterruptedException, UnsupportedEncodingException {
String containerName = getContainerName();
String container = getContainerName();
try {
String key = "apples";
String name = "apples";
String goodETag = addObjectAndValidateContent(containerName, key);
String goodETag = addObjectAndValidateContent(container, name);
context.getBlobStore().getBlob(containerName, key, ifETagMatches(goodETag));
validateContent(containerName, key);
context.getBlobStore().getBlob(container, name, ifETagMatches(goodETag));
validateContent(container, name);
try {
context.getBlobStore().getBlob(containerName, key, ifETagMatches("powerfrisbee"));
validateContent(containerName, key);
context.getBlobStore().getBlob(container, name, ifETagMatches("powerfrisbee"));
validateContent(container, name);
} catch (HttpResponseException ex) {
assertEquals(ex.getResponse().getStatusCode(), 412);
}
} finally {
returnContainer(containerName);
returnContainer(container);
}
}
@Test(groups = { "integration", "live" })
public void testGetIfNoneMatch() throws InterruptedException, UnsupportedEncodingException {
String containerName = getContainerName();
String container = getContainerName();
try {
String key = "apples";
String name = "apples";
String goodETag = addObjectAndValidateContent(containerName, key);
String goodETag = addObjectAndValidateContent(container, name);
context.getBlobStore().getBlob(containerName, key, ifETagDoesntMatch("powerfrisbee"));
validateContent(containerName, key);
context.getBlobStore().getBlob(container, name, ifETagDoesntMatch("powerfrisbee"));
validateContent(container, name);
try {
context.getBlobStore().getBlob(containerName, key, ifETagDoesntMatch(goodETag));
validateContent(containerName, key);
context.getBlobStore().getBlob(container, name, ifETagDoesntMatch(goodETag));
validateContent(container, name);
} catch (HttpResponseException ex) {
assertEquals(ex.getResponse().getStatusCode(), 304);
}
} finally {
returnContainer(containerName);
returnContainer(container);
}
}
@Test(groups = { "integration", "live" })
public void testGetRange() throws InterruptedException, IOException {
String containerName = getContainerName();
String container = getContainerName();
try {
String key = "apples";
String name = "apples";
addObjectAndValidateContent(containerName, key);
Blob blob1 = context.getBlobStore().getBlob(containerName, key, range(0, 5));
addObjectAndValidateContent(container, name);
Blob blob1 = context.getBlobStore().getBlob(container, name, range(0, 5));
validateMetadata(blob1.getMetadata(), container, name);
assertEquals(getContentAsStringOrNullAndClose(blob1), TEST_STRING.substring(0, 6));
Blob blob2 = context.getBlobStore().getBlob(containerName, key, range(6, TEST_STRING.length()));
Blob blob2 = context.getBlobStore().getBlob(container, name, range(6, TEST_STRING.length()));
validateMetadata(blob2.getMetadata(), container, name);
assertEquals(getContentAsStringOrNullAndClose(blob2), TEST_STRING.substring(6, TEST_STRING.length()));
} finally {
returnContainer(containerName);
returnContainer(container);
}
}
@Test(groups = { "integration", "live" })
public void testGetTwoRanges() throws InterruptedException, IOException {
String containerName = getContainerName();
String container = getContainerName();
try {
String key = "apples";
addObjectAndValidateContent(containerName, key);
Blob blob = context.getBlobStore().getBlob(containerName, key, range(0, 5).range(6, TEST_STRING.length()));
String name = "apples";
addObjectAndValidateContent(container, name);
Blob blob = context.getBlobStore().getBlob(container, name, range(0, 5).range(6, TEST_STRING.length()));
validateMetadata(blob.getMetadata(), container, name);
assertEquals(getContentAsStringOrNullAndClose(blob), TEST_STRING);
} finally {
returnContainer(containerName);
returnContainer(container);
}
}
@ -293,13 +296,13 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
// public void testGetTail() throws InterruptedException, ExecutionException,
// TimeoutException,
// IOException {
// String containerName = getContainerName();
// String container = getContainerName();
// try {
//
// String key = "apples";
// String name = "apples";
//
// addObjectAndValidateContent(containerName, key);
// Blob blob = context.getBlobStore().getBlob(containerName, key,
// addObjectAndValidateContent(container, name);
// Blob blob = context.getBlobStore().getBlob(container, name,
// tail(5)).get(30,
// TimeUnit.SECONDS);
// assertEquals(BlobStoreUtils.getContentAsStringAndClose(blob), TEST_STRING
@ -307,7 +310,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
// assertEquals(blob.getContentLength(), 5);
// assertEquals(blob.getMetadata().getSize(), TEST_STRING.length());
// } finally {
// returnContainer(containerName);
// returnContainer(container);
// }
// }
@ -316,12 +319,12 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
// ExecutionException,
// TimeoutException,
// IOException {
// String containerName = getContainerName();
// String container = getContainerName();
// try {
// String key = "apples";
// String name = "apples";
//
// addObjectAndValidateContent(containerName, key);
// Blob blob = context.getBlobStore().getBlob(containerName, key,
// addObjectAndValidateContent(container, name);
// Blob blob = context.getBlobStore().getBlob(container, name,
// startAt(5)).get(30,
// TimeUnit.SECONDS);
// assertEquals(BlobStoreUtils.getContentAsStringAndClose(blob),
@ -330,71 +333,69 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
// assertEquals(blob.getContentLength(), TEST_STRING.length() - 5);
// assertEquals(blob.getMetadata().getSize(), TEST_STRING.length());
// } finally {
// returnContainer(containerName);
// returnContainer(container);
// }
// }
private String addObjectAndValidateContent(String sourcecontainerName, String sourceKey) throws InterruptedException {
String eTag = addBlobToContainer(sourcecontainerName, sourceKey);
validateContent(sourcecontainerName, sourceKey);
private String addObjectAndValidateContent(String sourcecontainer, String sourceKey) throws InterruptedException {
String eTag = addBlobToContainer(sourcecontainer, sourceKey);
validateContent(sourcecontainer, sourceKey);
return eTag;
}
@Test(groups = { "integration", "live" })
public void deleteObjectNotFound() throws InterruptedException {
String containerName = getContainerName();
String key = "test";
String container = getContainerName();
String name = "test";
try {
context.getBlobStore().removeBlob(containerName, key);
context.getBlobStore().removeBlob(container, name);
} finally {
returnContainer(containerName);
returnContainer(container);
}
}
@Test(groups = { "integration", "live" })
public void blobNotFound() throws InterruptedException {
String containerName = getContainerName();
String key = "test";
String container = getContainerName();
String name = "test";
try {
assert !context.getBlobStore().blobExists(containerName, key);
assert !context.getBlobStore().blobExists(container, name);
} finally {
returnContainer(containerName);
returnContainer(container);
}
}
@DataProvider(name = "delete")
public Object[][] createData() {
return new Object[][] { { "normal" }, { "sp ace" }, { "qu?stion" }, { "unic₪de" }, { "path/foo" },
{ "colon:" }, { "asteri*k" }, { "quote\"" }, { "{great<r}" }, { "lesst>en" }, { "p|pe" } };
return new Object[][] { { "normal" }, { "sp ace" }, { "qu?stion" }, { "unic₪de" }, { "path/foo" }, { "colon:" },
{ "asteri*k" }, { "quote\"" }, { "{great<r}" }, { "lesst>en" }, { "p|pe" } };
}
@Test(groups = { "integration", "live" }, dataProvider = "delete")
public void deleteObject(String key) throws InterruptedException {
String containerName = getContainerName();
public void deleteObject(String name) throws InterruptedException {
String container = getContainerName();
try {
addBlobToContainer(containerName, key, key, MediaType.TEXT_PLAIN);
context.getBlobStore().removeBlob(containerName, key);
assertContainerEmptyDeleting(containerName, key);
addBlobToContainer(container, name, name, MediaType.TEXT_PLAIN);
context.getBlobStore().removeBlob(container, name);
assertContainerEmptyDeleting(container, name);
} finally {
returnContainer(containerName);
returnContainer(container);
}
}
private void assertContainerEmptyDeleting(String containerName, String key) {
Iterable<? extends StorageMetadata> listing = Iterables.filter(context.getBlobStore().list(containerName),
new Predicate<StorageMetadata>() {
private void assertContainerEmptyDeleting(String container, String name) {
Iterable<? extends StorageMetadata> listing = Iterables.filter(context.getBlobStore().list(container),
new Predicate<StorageMetadata>() {
@Override
public boolean apply(StorageMetadata input) {
return input.getType() == StorageType.BLOB;
}
@Override
public boolean apply(StorageMetadata input) {
return input.getType() == StorageType.BLOB;
}
});
assertEquals(
Iterables.size(listing),
0,
String.format("deleting %s, we still have %s blobs left in container %s, using encoding %s", key,
Iterables.size(listing), containerName, LOCAL_ENCODING));
});
assertEquals(Iterables.size(listing), 0, String.format(
"deleting %s, we still have %s blobs left in container %s, using encoding %s", name, Iterables
.size(listing), container, LOCAL_ENCODING));
}
@Test(groups = { "integration", "live" })
@ -414,60 +415,63 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
String realObject = Strings2.toStringAndClose(new FileInputStream("pom.xml"));
return new Object[][] { { "file", "text/xml", new File("pom.xml"), realObject },
{ "string", "text/xml", realObject, realObject },
{ "bytes", "application/octet-stream", realObject.getBytes(), realObject } };
{ "string", "text/xml", realObject, realObject },
{ "bytes", "application/octet-stream", realObject.getBytes(), realObject } };
}
@Test(groups = { "integration", "live" }, dataProvider = "putTests")
public void testPutObject(String key, String type, Object content, Object realObject) throws InterruptedException,
IOException {
PayloadBlobBuilder blobBuilder = context.getBlobStore().blobBuilder(key).payload(Payloads.newPayload(content))
.contentType(type);
public void testPutObject(String name, String type, Object content, Object realObject) throws InterruptedException,
IOException {
PayloadBlobBuilder blobBuilder = context.getBlobStore().blobBuilder(name).payload(Payloads.newPayload(content))
.contentType(type);
addContentMetadata(blobBuilder);
if (content instanceof InputStream) {
blobBuilder.calculateMD5();
}
Blob blob = blobBuilder.build();
String containerName = getContainerName();
String container = getContainerName();
try {
assertNotNull(context.getBlobStore().putBlob(containerName, blob));
blob = context.getBlobStore().getBlob(containerName, blob.getMetadata().getName());
assertNotNull(context.getBlobStore().putBlob(container, blob));
blob = context.getBlobStore().getBlob(container, blob.getMetadata().getName());
validateMetadata(blob.getMetadata(), container, name);
checkContentMetadata(blob);
String returnedString = getContentAsStringOrNullAndClose(blob);
assertEquals(returnedString, realObject);
PageSet<? extends StorageMetadata> set = context.getBlobStore().list(containerName);
PageSet<? extends StorageMetadata> set = context.getBlobStore().list(container);
assert set.size() == 1 : set;
} finally {
returnContainer(containerName);
returnContainer(container);
}
}
@Test(groups = { "integration", "live" })
public void testPutObjectStream() throws InterruptedException, IOException, ExecutionException {
PayloadBlobBuilder blobBuilder = context.getBlobStore().blobBuilder("streaming").payload(new StreamingPayload(new WriteTo() {
@Override
public void writeTo(OutputStream outstream) throws IOException {
outstream.write("foo".getBytes());
}
}));
PayloadBlobBuilder blobBuilder = context.getBlobStore().blobBuilder("streaming").payload(
new StreamingPayload(new WriteTo() {
@Override
public void writeTo(OutputStream outstream) throws IOException {
outstream.write("foo".getBytes());
}
}));
addContentMetadata(blobBuilder);
Blob blob = blobBuilder.build();
String containerName = getContainerName();
String container = getContainerName();
try {
assertNotNull(context.getBlobStore().putBlob(containerName, blob));
assertNotNull(context.getBlobStore().putBlob(container, blob));
blob = context.getBlobStore().getBlob(containerName, blob.getMetadata().getName());
blob = context.getBlobStore().getBlob(container, blob.getMetadata().getName());
String returnedString = getContentAsStringOrNullAndClose(blob);
assertEquals(returnedString, "foo");
validateMetadata(blob.getMetadata(), container, blob.getMetadata().getName());
checkContentMetadata(blob);
PageSet<? extends StorageMetadata> set = context.getBlobStore().list(containerName);
PageSet<? extends StorageMetadata> set = context.getBlobStore().list(container);
assert set.size() == 1 : set;
} finally {
returnContainer(containerName);
returnContainer(container);
}
}
@ -487,31 +491,31 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
protected void checkContentType(Blob blob, String contentType) {
assert blob.getPayload().getContentMetadata().getContentType().startsWith(contentType) : blob.getPayload()
.getContentMetadata().getContentType();
.getContentMetadata().getContentType();
assert blob.getMetadata().getContentMetadata().getContentType().startsWith(contentType) : blob.getMetadata()
.getContentMetadata().getContentType();
.getContentMetadata().getContentType();
}
protected void checkContentDisposition(Blob blob, String contentDisposition) {
assert blob.getPayload().getContentMetadata().getContentDisposition().startsWith(contentDisposition) : blob
.getPayload().getContentMetadata().getContentDisposition();
.getPayload().getContentMetadata().getContentDisposition();
assert blob.getMetadata().getContentMetadata().getContentDisposition().startsWith(contentDisposition) : blob
.getMetadata().getContentMetadata().getContentDisposition();
.getMetadata().getContentMetadata().getContentDisposition();
}
protected void checkContentEncoding(Blob blob, String contentEncoding) {
assert (blob.getPayload().getContentMetadata().getContentEncoding().indexOf(contentEncoding) != -1) : blob
.getPayload().getContentMetadata().getContentEncoding();
.getPayload().getContentMetadata().getContentEncoding();
assert (blob.getMetadata().getContentMetadata().getContentEncoding().indexOf(contentEncoding) != -1) : blob
.getMetadata().getContentMetadata().getContentEncoding();
.getMetadata().getContentMetadata().getContentEncoding();
}
protected void checkContentLanguage(Blob blob, String contentLanguage) {
assert blob.getPayload().getContentMetadata().getContentLanguage().startsWith(contentLanguage) : blob
.getPayload().getContentMetadata().getContentLanguage();
.getPayload().getContentMetadata().getContentLanguage();
assert blob.getMetadata().getContentMetadata().getContentLanguage().startsWith(contentLanguage) : blob
.getMetadata().getContentMetadata().getContentLanguage();
.getMetadata().getContentMetadata().getContentLanguage();
}
protected volatile static Crypto crypto;
@ -527,40 +531,41 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
@Test(groups = { "integration", "live" })
public void testMetadata() throws InterruptedException, IOException {
String key = "hello";
String name = "hello";
// NOTE all metadata in jclouds comes out as lowercase, in an effort to
// normalize the
// providers.
Blob blob = context.getBlobStore().blobBuilder(key).userMetadata(ImmutableMap.of("Adrian", "powderpuff"))
.payload(TEST_STRING).contentType(MediaType.TEXT_PLAIN).calculateMD5().build();
String containerName = getContainerName();
Blob blob = context.getBlobStore().blobBuilder(name).userMetadata(ImmutableMap.of("Adrian", "powderpuff"))
.payload(TEST_STRING).contentType(MediaType.TEXT_PLAIN).calculateMD5().build();
String container = getContainerName();
try {
assertNull(context.getBlobStore().blobMetadata(containerName, "powderpuff"));
assertNull(context.getBlobStore().blobMetadata(container, "powderpuff"));
addBlobToContainer(containerName, blob);
Blob newObject = validateContent(containerName, key);
addBlobToContainer(container, blob);
Blob newObject = validateContent(container, name);
BlobMetadata metadata = newObject.getMetadata();
validateMetadata(metadata);
validateMetadata(context.getBlobStore().blobMetadata(containerName, key));
validateMetadata(metadata, container, name);
validateMetadata(context.getBlobStore().blobMetadata(container, name));
// write 2 items with the same key to ensure that provider doesn't
// write 2 items with the same name to ensure that provider doesn't
// accept dupes
blob.getMetadata().getUserMetadata().put("Adrian", "wonderpuff");
blob.getMetadata().getUserMetadata().put("Adrian", "powderpuff");
addBlobToContainer(containerName, blob);
validateMetadata(context.getBlobStore().blobMetadata(containerName, key));
addBlobToContainer(container, blob);
validateMetadata(context.getBlobStore().blobMetadata(container, name));
} finally {
returnContainer(containerName);
returnContainer(container);
}
}
protected void validateMetadata(BlobMetadata metadata) throws IOException {
assert metadata.getContentMetadata().getContentType().startsWith("text/plain") : metadata.getContentMetadata()
.getContentType();
.getContentType();
assertEquals(metadata.getContentMetadata().getContentLength(), new Long(TEST_STRING.length()));
assertEquals(metadata.getUserMetadata().get("adrian"), "powderpuff");
checkMD5(metadata);

View File

@ -20,6 +20,7 @@
package org.jclouds.blobstore.integration.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.propagateIfPossible;
import static org.jclouds.blobstore.util.BlobStoreUtils.getContentAsStringOrNullAndClose;
import static org.testng.Assert.assertEquals;
@ -40,6 +41,7 @@ import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.attr.ConsistencyModel;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
@ -62,13 +64,13 @@ public class BaseBlobStoreIntegrationTest {
protected static final String TEST_STRING = String.format(XML_STRING_FORMAT, "apple");
protected Map<String, String> fiveStrings = ImmutableMap.of("one", String.format(XML_STRING_FORMAT, "apple"), "two",
String.format(XML_STRING_FORMAT, "bear"), "three", String.format(XML_STRING_FORMAT, "candy"), "four",
String.format(XML_STRING_FORMAT, "dogma"), "five", String.format(XML_STRING_FORMAT, "emma"));
String.format(XML_STRING_FORMAT, "bear"), "three", String.format(XML_STRING_FORMAT, "candy"), "four",
String.format(XML_STRING_FORMAT, "dogma"), "five", String.format(XML_STRING_FORMAT, "emma"));
protected Map<String, String> fiveStringsUnderPath = ImmutableMap.of("path/1",
String.format(XML_STRING_FORMAT, "apple"), "path/2", String.format(XML_STRING_FORMAT, "bear"), "path/3",
String.format(XML_STRING_FORMAT, "candy"), "path/4", String.format(XML_STRING_FORMAT, "dogma"), "path/5",
String.format(XML_STRING_FORMAT, "emma"));
protected Map<String, String> fiveStringsUnderPath = ImmutableMap.of("path/1", String.format(XML_STRING_FORMAT,
"apple"), "path/2", String.format(XML_STRING_FORMAT, "bear"), "path/3", String.format(XML_STRING_FORMAT,
"candy"), "path/4", String.format(XML_STRING_FORMAT, "dogma"), "path/5", String.format(XML_STRING_FORMAT,
"emma"));
public static long INCONSISTENCY_WINDOW = 10000;
protected static volatile AtomicInteger containerIndex = new AtomicInteger(0);
@ -92,7 +94,7 @@ public class BaseBlobStoreIntegrationTest {
@SuppressWarnings("unchecked")
private BlobStoreContext getCloudResources(ITestContext testContext) throws ClassNotFoundException,
InstantiationException, IllegalAccessException, Exception {
InstantiationException, IllegalAccessException, Exception {
String initializerClass = checkNotNull(System.getProperty("test.initializer"), "test.initializer");
Class<BaseTestInitializer> clazz = (Class<BaseTestInitializer>) Class.forName(initializerClass);
BaseTestInitializer initializer = clazz.newInstance();
@ -125,7 +127,7 @@ public class BaseBlobStoreIntegrationTest {
private static volatile boolean initialized = false;
protected void createContainersSharedByAllThreads(BlobStoreContext context, ITestContext testContext)
throws Exception {
throws Exception {
while (!initialized) {
synchronized (BaseBlobStoreIntegrationTest.class) {
if (!initialized) {
@ -176,12 +178,12 @@ public class BaseBlobStoreIntegrationTest {
try {
for (int i = 0; i < 2; i++) {
Iterable<? extends StorageMetadata> testContainers = Iterables.filter(context.getBlobStore().list(),
new Predicate<StorageMetadata>() {
public boolean apply(StorageMetadata input) {
return (input.getType() == StorageType.CONTAINER || input.getType() == StorageType.FOLDER)
&& input.getName().startsWith(CONTAINER_PREFIX.toLowerCase());
}
});
new Predicate<StorageMetadata>() {
public boolean apply(StorageMetadata input) {
return (input.getType() == StorageType.CONTAINER || input.getType() == StorageType.FOLDER)
&& input.getName().startsWith(CONTAINER_PREFIX.toLowerCase());
}
});
for (StorageMetadata container : testContainers) {
deleteContainerOrWarnIfUnable(context, container.getName());
}
@ -202,7 +204,7 @@ public class BaseBlobStoreIntegrationTest {
* we will try up to the inconsistency window to see if the assertion completes.
*/
protected static void assertConsistencyAware(BlobStoreContext context, Runnable assertion)
throws InterruptedException {
throws InterruptedException {
if (context.getConsistencyModel() == ConsistencyModel.STRICT) {
assertion.run();
return;
@ -228,7 +230,7 @@ public class BaseBlobStoreIntegrationTest {
}
protected static void createContainerAndEnsureEmpty(BlobStoreContext context, final String containerName)
throws InterruptedException {
throws InterruptedException {
context.getBlobStore().createContainerInLocation(null, containerName);
if (context.getConsistencyModel() == ConsistencyModel.EVENTUAL)
Thread.sleep(1000);
@ -250,8 +252,8 @@ public class BaseBlobStoreIntegrationTest {
protected void add5BlobsUnderPathAnd5UnderRootToContainer(String sourceContainer) {
for (Entry<String, String> entry : Iterables.concat(fiveStrings.entrySet(), fiveStringsUnderPath.entrySet())) {
Blob sourceObject = context.getBlobStore().blobBuilder(entry.getKey()).payload(entry.getValue())
.contentType("text/xml").build();
Blob sourceObject = context.getBlobStore().blobBuilder(entry.getKey()).payload(entry.getValue()).contentType(
"text/xml").build();
addBlobToContainer(sourceContainer, sourceObject);
}
}
@ -260,10 +262,18 @@ public class BaseBlobStoreIntegrationTest {
return context.getBlobStore().putBlob(sourceContainer, object);
}
protected Blob validateContent(String sourceContainer, String key) throws InterruptedException {
assertConsistencyAwareContainerSize(sourceContainer, 1);
Blob newObject = context.getBlobStore().getBlob(sourceContainer, key);
protected <T extends BlobMetadata> T validateMetadata(T md, String container, String name) {
assertEquals(md.getName(), name);
assertEquals(md.getContainer(), container);
assert md.getUri() != null;
return md;
}
protected Blob validateContent(String container, String name) throws InterruptedException {
assertConsistencyAwareContainerSize(container, 1);
Blob newObject = context.getBlobStore().getBlob(container, name);
assert newObject != null;
validateMetadata(newObject.getMetadata(), container, name);
try {
assertEquals(getContentAsStringOrNullAndClose(newObject), TEST_STRING);
} catch (IOException e) {
@ -273,19 +283,19 @@ public class BaseBlobStoreIntegrationTest {
}
protected void assertConsistencyAwareContainerSize(final String containerName, final int count)
throws InterruptedException {
throws InterruptedException {
assertConsistencyAware(new Runnable() {
public void run() {
try {
assert context.getBlobStore().countBlobs(containerName) == count : String.format(
"expected only %d values in %s: %s", count, containerName, Sets.newHashSet(Iterables.transform(
context.getBlobStore().list(containerName), new Function<StorageMetadata, String>() {
"expected only %d values in %s: %s", count, containerName, Sets.newHashSet(Iterables.transform(
context.getBlobStore().list(containerName), new Function<StorageMetadata, String>() {
public String apply(StorageMetadata from) {
return from.getName();
}
public String apply(StorageMetadata from) {
return from.getName();
}
})));
})));
} catch (Exception e) {
Throwables.propagateIfPossible(e);
}
@ -334,6 +344,19 @@ public class BaseBlobStoreIntegrationTest {
}
}
protected void assertNotExists(final String containerName) throws InterruptedException {
assertConsistencyAware(new Runnable() {
public void run() {
try {
assert !context.getBlobStore().containerExists(containerName) : "container " + containerName
+ " still exists";
} catch (Exception e) {
propagateIfPossible(e);
}
}
});
}
/**
* abandon old container name instead of waiting for the container to be created.
*

View File

@ -295,19 +295,6 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
}
}
private void assertNotExists(final String containerName) throws InterruptedException {
assertConsistencyAware(new Runnable() {
public void run() {
try {
assert !context.getBlobStore().containerExists(containerName) : "container " + containerName
+ " still exists";
} catch (Exception e) {
propagateIfPossible(e);
}
}
});
}
@Test(groups = { "integration", "live" })
public void testListContainer() throws InterruptedException, ExecutionException, TimeoutException,
UnsupportedEncodingException {

View File

@ -19,10 +19,40 @@
package org.jclouds.blobstore.integration.internal;
import static org.jclouds.blobstore.options.CreateContainerOptions.Builder.publicRead;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.net.MalformedURLException;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.util.Strings2;
import org.testng.annotations.Test;
/**
*
* @author Adrian Cole
*/
public class BaseContainerLiveTest extends BaseBlobStoreIntegrationTest {
@Test(groups = { "live" })
public void testPublicAccess() throws InterruptedException, MalformedURLException, IOException {
final String containerName = getScratchContainerName();
try {
context.getBlobStore().createContainerInLocation(null, containerName, publicRead());
assertConsistencyAwareContainerSize(containerName, 0);
context.getBlobStore().putBlob(containerName,
context.getBlobStore().blobBuilder("hello").payload(TEST_STRING).build());
assertConsistencyAwareContainerSize(containerName, 1);
BlobMetadata metadata = context.getBlobStore().blobMetadata(containerName, "hello");
assertEquals(Strings2.toStringAndClose(metadata.getPublicUri().toURL().openStream()), TEST_STRING);
} finally {
// this container is now public, so we can't reuse it directly
recycleContainer(containerName);
}
}
}

View File

@ -19,6 +19,8 @@
package org.jclouds.http.functions;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.http.functions.config.SaxParserModule;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
@ -26,6 +28,7 @@ import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.sun.jersey.api.uri.UriBuilderImpl;
/**
*
@ -39,7 +42,12 @@ public class BaseHandlerTest {
@BeforeTest
protected void setUpInjector() {
injector = Guice.createInjector(new SaxParserModule());
injector = Guice.createInjector(new SaxParserModule() {
public void configure() {
super.configure();
bind(UriBuilder.class).to(UriBuilderImpl.class);
}
});
factory = injector.getInstance(ParseSax.Factory.class);
assert factory != null;
}

View File

@ -19,6 +19,7 @@
package org.jclouds.aws.s3.blobstore;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@ -30,7 +31,6 @@ import org.jclouds.Constants;
import org.jclouds.aws.s3.AWSS3AsyncClient;
import org.jclouds.aws.s3.AWSS3Client;
import org.jclouds.aws.s3.blobstore.strategy.AsyncMultipartUploadStrategy;
import org.jclouds.aws.s3.blobstore.strategy.MultipartUploadStrategy;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
@ -45,9 +45,9 @@ import org.jclouds.s3.blobstore.functions.BucketToResourceMetadata;
import org.jclouds.s3.blobstore.functions.ContainerToBucketListOptions;
import org.jclouds.s3.blobstore.functions.ObjectToBlob;
import org.jclouds.s3.blobstore.functions.ObjectToBlobMetadata;
import org.jclouds.s3.domain.AccessControlList;
import com.google.common.base.Supplier;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
/**
@ -60,16 +60,16 @@ public class AWSS3AsyncBlobStore extends S3AsyncBlobStore {
@Inject
public AWSS3AsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations, AWSS3AsyncClient async, AWSS3Client sync,
BucketToResourceMetadata bucket2ResourceMd, ContainerToBucketListOptions container2BucketListOptions,
BucketToResourceList bucket2ResourceList, ObjectToBlob object2Blob,
BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider,
Provider<AsyncMultipartUploadStrategy> multipartUploadStrategy) {
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations, AWSS3AsyncClient async, AWSS3Client sync,
BucketToResourceMetadata bucket2ResourceMd, ContainerToBucketListOptions container2BucketListOptions,
BucketToResourceList bucket2ResourceList, ObjectToBlob object2Blob,
BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider, Map<String, AccessControlList> bucketAcls,
Provider<AsyncMultipartUploadStrategy> multipartUploadStrategy) {
super(context, blobUtils, service, defaultLocation, locations, async, sync, bucket2ResourceMd,
container2BucketListOptions, bucket2ResourceList, object2Blob, blob2ObjectGetOptions, blob2Object,
object2BlobMd, fetchBlobMetadataProvider);
container2BucketListOptions, bucket2ResourceList, object2Blob, blob2ObjectGetOptions, blob2Object,
object2BlobMd, fetchBlobMetadataProvider, bucketAcls);
this.multipartUploadStrategy = multipartUploadStrategy;
}

View File

@ -19,6 +19,7 @@
package org.jclouds.aws.s3.blobstore;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
@ -40,6 +41,7 @@ import org.jclouds.s3.blobstore.functions.BucketToResourceMetadata;
import org.jclouds.s3.blobstore.functions.ContainerToBucketListOptions;
import org.jclouds.s3.blobstore.functions.ObjectToBlob;
import org.jclouds.s3.blobstore.functions.ObjectToBlobMetadata;
import org.jclouds.s3.domain.AccessControlList;
import com.google.common.base.Supplier;
@ -54,14 +56,15 @@ public class AWSS3BlobStore extends S3BlobStore {
@Inject
AWSS3BlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations, AWSS3Client sync,
BucketToResourceMetadata bucket2ResourceMd, ContainerToBucketListOptions container2BucketListOptions,
BucketToResourceList bucket2ResourceList, ObjectToBlob object2Blob,
BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider, Provider<MultipartUploadStrategy> multipartUploadStrategy) {
@Memoized Supplier<Set<? extends Location>> locations, AWSS3Client sync,
BucketToResourceMetadata bucket2ResourceMd, ContainerToBucketListOptions container2BucketListOptions,
BucketToResourceList bucket2ResourceList, ObjectToBlob object2Blob,
BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider, Map<String, AccessControlList> bucketAcls,
Provider<MultipartUploadStrategy> multipartUploadStrategy) {
super(context, blobUtils, defaultLocation, locations, sync, bucket2ResourceMd, container2BucketListOptions,
bucket2ResourceList, object2Blob, blob2ObjectGetOptions, blob2Object, object2BlobMd,
fetchBlobMetadataProvider);
bucket2ResourceList, object2Blob, blob2ObjectGetOptions, blob2Object, object2BlobMd,
fetchBlobMetadataProvider, bucketAcls);
this.multipartUploadStrategy = multipartUploadStrategy;
}

View File

@ -19,22 +19,13 @@
package org.jclouds.aws.s3.blobstore.integration;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import org.jclouds.blobstore.integration.internal.BaseBlobIntegrationTest;
import org.jclouds.s3.blobstore.integration.S3BlobIntegrationLiveTest;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = "live", testName = "AWSS3BlobIntegrationLiveTest")
public class AWSS3BlobIntegrationLiveTest extends BaseBlobIntegrationTest {
@Override
@Test(expectedExceptions = IllegalArgumentException.class)
public void testPutObjectStream() throws InterruptedException, IOException, ExecutionException {
super.testPutObjectStream();
}
@Test(groups = "live", testName = "AWSS3BlobIntegrationLiveTest")
public class AWSS3BlobIntegrationLiveTest extends S3BlobIntegrationLiveTest {
}

View File

@ -19,13 +19,13 @@
package org.jclouds.aws.s3.blobstore.integration;
import org.jclouds.blobstore.integration.internal.BaseBlobLiveTest;
import org.jclouds.s3.blobstore.integration.S3BlobLiveTest;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = "live", testName = "AWSS3BlobLiveTest")
public class AWSS3BlobLiveTest extends BaseBlobLiveTest {
@Test(groups = "live", testName = "AWSS3BlobLiveTest")
public class AWSS3BlobLiveTest extends S3BlobLiveTest {
}

View File

@ -19,13 +19,13 @@
package org.jclouds.aws.s3.blobstore.integration;
import org.jclouds.blobstore.integration.internal.BaseBlobMapIntegrationTest;
import org.jclouds.s3.blobstore.integration.S3BlobMapIntegrationLiveTest;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = "live", testName = "AWSS3BlobMapIntegrationLiveTest")
public class AWSS3BlobMapIntegrationLiveTest extends BaseBlobMapIntegrationTest {
@Test(groups = "live", testName = "AWSS3BlobMapIntegrationLiveTest")
public class AWSS3BlobMapIntegrationLiveTest extends S3BlobMapIntegrationLiveTest {
}

View File

@ -19,14 +19,14 @@
package org.jclouds.aws.s3.blobstore.integration;
import org.jclouds.blobstore.integration.internal.BaseBlobSignerLiveTest;
import org.jclouds.s3.blobstore.integration.S3BlobSignerLiveTest;
import org.testng.annotations.Test;
/**
*
* @author Adrian Cole
*/
@Test(groups = "live", testName = "AWSS3BlobSignerLiveTest")
public class AWSS3BlobSignerLiveTest extends BaseBlobSignerLiveTest {
@Test(groups = "live", testName = "AWSS3BlobSignerLiveTest")
public class AWSS3BlobSignerLiveTest extends S3BlobSignerLiveTest {
}

View File

@ -19,13 +19,13 @@
package org.jclouds.aws.s3.blobstore.integration;
import org.jclouds.blobstore.integration.internal.BaseContainerIntegrationTest;
import org.jclouds.s3.blobstore.integration.S3ContainerIntegrationLiveTest;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = "live", testName = "AWSS3ContainerIntegrationLiveTest")
public class AWSS3ContainerIntegrationLiveTest extends BaseContainerIntegrationTest {
public class AWSS3ContainerIntegrationLiveTest extends S3ContainerIntegrationLiveTest {
}

View File

@ -19,13 +19,13 @@
package org.jclouds.aws.s3.blobstore.integration;
import org.jclouds.blobstore.integration.internal.BaseContainerLiveTest;
import org.jclouds.s3.blobstore.integration.S3ContainerLiveTest;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = "live", testName = "AWSS3ContainerLiveTest")
public class AWSS3ContainerLiveTest extends BaseContainerLiveTest {
@Test(groups = "live", testName = "AWSS3ContainerLiveTest")
public class AWSS3ContainerLiveTest extends S3ContainerLiveTest {
}

View File

@ -19,13 +19,13 @@
package org.jclouds.aws.s3.blobstore.integration;
import org.jclouds.blobstore.integration.internal.BaseInputStreamMapIntegrationTest;
import org.jclouds.s3.blobstore.integration.S3InputStreamMapIntegrationLiveTest;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = "live", testName = "AWSS3InputStreamMapIntegrationLiveTest")
public class AWSS3InputStreamMapIntegrationLiveTest extends BaseInputStreamMapIntegrationTest {
public class AWSS3InputStreamMapIntegrationLiveTest extends S3InputStreamMapIntegrationLiveTest {
}

View File

@ -29,24 +29,26 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.azure.storage.domain.BoundedSet;
import org.jclouds.azure.storage.filters.SharedKeyLiteAuthentication;
import org.jclouds.azure.storage.options.ListOptions;
import org.jclouds.azure.storage.reference.AzureStorageHeaders;
import org.jclouds.azureblob.binders.BindAzureBlobMetadataToRequest;
import org.jclouds.azureblob.domain.BlobProperties;
import org.jclouds.azureblob.domain.ContainerProperties;
import org.jclouds.azureblob.domain.ListBlobsResponse;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.functions.BlobName;
import org.jclouds.azureblob.functions.ParseBlobFromHeadersAndHttpContent;
import org.jclouds.azureblob.functions.ParseBlobPropertiesFromHeaders;
import org.jclouds.azureblob.functions.ParseContainerPropertiesFromHeaders;
import org.jclouds.azureblob.functions.ParsePublicAccessHeader;
import org.jclouds.azureblob.functions.ReturnFalseIfContainerAlreadyExists;
import org.jclouds.azureblob.options.CreateContainerOptions;
import org.jclouds.azureblob.options.ListBlobsOptions;
import org.jclouds.azureblob.predicates.validators.ContainerNameValidator;
import org.jclouds.azureblob.xml.AccountNameEnumerationResultsHandler;
import org.jclouds.azureblob.xml.ContainerNameEnumerationResultsHandler;
import org.jclouds.azure.storage.domain.BoundedSet;
import org.jclouds.azure.storage.filters.SharedKeyLiteAuthentication;
import org.jclouds.azure.storage.options.ListOptions;
import org.jclouds.azure.storage.reference.AzureStorageHeaders;
import org.jclouds.blobstore.binders.BindMapToHeadersWithPrefix;
import org.jclouds.blobstore.functions.ReturnFalseOnContainerNotFound;
import org.jclouds.blobstore.functions.ReturnFalseOnKeyNotFound;
@ -95,8 +97,7 @@ public interface AzureBlobAsyncClient {
@GET
@XMLResponseParser(AccountNameEnumerationResultsHandler.class)
@QueryParams(keys = "comp", values = "list")
ListenableFuture<? extends BoundedSet<ContainerProperties>> listContainers(
ListOptions... listOptions);
ListenableFuture<? extends BoundedSet<ContainerProperties>> listContainers(ListOptions... listOptions);
/**
* @see AzureBlobClient#createContainer
@ -109,6 +110,17 @@ public interface AzureBlobAsyncClient {
@PathParam("container") @ParamValidators( { ContainerNameValidator.class }) String container,
CreateContainerOptions... options);
/**
* @see AzureBlobClient#getPublicAccessForContainer
*/
@HEAD
@Path("{container}")
@QueryParams(keys = { "restype", "comp" }, values = { "container", "acl" })
@ResponseParser(ParsePublicAccessHeader.class)
@ExceptionParser(ReturnNullOnContainerNotFound.class)
ListenableFuture<PublicAccess> getPublicAccessForContainer(
@PathParam("container") @ParamValidators( { ContainerNameValidator.class }) String container);
/**
* @see AzureBlobClient#getContainerProperties
*/
@ -238,8 +250,7 @@ public interface AzureBlobAsyncClient {
@QueryParams(keys = { "comp" }, values = { "metadata" })
ListenableFuture<Void> setBlobMetadata(
@PathParam("container") @ParamValidators( { ContainerNameValidator.class }) String container,
@PathParam("name") String name,
@BinderParam(BindMapToHeadersWithPrefix.class) Map<String, String> metadata);
@PathParam("name") String name, @BinderParam(BindMapToHeadersWithPrefix.class) Map<String, String> metadata);
/**
* @see AzureBlobClient#deleteBlob

View File

@ -21,29 +21,28 @@ package org.jclouds.azureblob;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.jclouds.azure.storage.domain.BoundedSet;
import org.jclouds.azure.storage.options.ListOptions;
import org.jclouds.azureblob.domain.BlobProperties;
import org.jclouds.azureblob.domain.ContainerProperties;
import org.jclouds.azureblob.domain.ListBlobsResponse;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.options.CreateContainerOptions;
import org.jclouds.azureblob.options.ListBlobsOptions;
import org.jclouds.azure.storage.domain.BoundedSet;
import org.jclouds.azure.storage.options.ListOptions;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.concurrent.Timeout;
import org.jclouds.http.options.GetOptions;
import com.google.inject.Provides;
import java.util.concurrent.Future;
/**
* Provides access to Azure Blob via their REST API.
* <p/>
* All commands return a Future of the result from Azure Blob. Any exceptions incurred
* during processing will be wrapped in an {@link ExecutionException} as documented in
* {@link Future#get()}.
* All commands return a Future of the result from Azure Blob. Any exceptions incurred during
* processing will be wrapped in an {@link ExecutionException} as documented in {@link Future#get()}.
*
* @see <a href="http://msdn.microsoft.com/en-us/library/dd135733.aspx" />
* @author Adrian Cole
@ -131,6 +130,14 @@ public interface AzureBlobClient {
*/
boolean createRootContainer(CreateContainerOptions... options);
/**
*
*
* @param container
* @return whether data in the container may be accessed publicly and the level of access
*/
PublicAccess getPublicAccessForContainer(String container);
/**
* The Delete Container operation marks the specified container for deletion. The container and
* any blobs contained within it are later deleted during garbage collection. <h4>Remarks</h4>
@ -214,8 +221,7 @@ public interface AzureBlobClient {
* properties.
*/
@Timeout(duration = 10 * 64, timeUnit = TimeUnit.MINUTES)
org.jclouds.azureblob.domain.AzureBlob getBlob(String container, String name,
GetOptions... options);
org.jclouds.azureblob.domain.AzureBlob getBlob(String container, String name, GetOptions... options);
/**
* The Get Blob Properties operation returns all user-defined metadata, standard HTTP properties,

View File

@ -42,6 +42,7 @@ import org.jclouds.azureblob.domain.AzureBlob;
import org.jclouds.azureblob.domain.BlobProperties;
import org.jclouds.azureblob.domain.ContainerProperties;
import org.jclouds.azureblob.domain.ListBlobsResponse;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.options.ListBlobsOptions;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob;
@ -51,6 +52,7 @@ import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.collect.Memoized;
@ -79,18 +81,18 @@ public class AzureAsyncBlobStore extends BaseAsyncBlobStore {
@Inject
AzureAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations, AzureBlobAsyncClient async,
ContainerToResourceMetadata container2ResourceMd,
ListOptionsToListBlobsOptions blobStore2AzureContainerListOptions,
ListBlobsResponseToResourceList azure2BlobStoreResourceList, AzureBlobToBlob azureBlob2Blob,
BlobToAzureBlob blob2AzureBlob, BlobPropertiesToBlobMetadata blob2BlobMd,
BlobToHttpGetOptions blob2ObjectGetOptions) {
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations, AzureBlobAsyncClient async,
ContainerToResourceMetadata container2ResourceMd,
ListOptionsToListBlobsOptions blobStore2AzureContainerListOptions,
ListBlobsResponseToResourceList azure2BlobStoreResourceList, AzureBlobToBlob azureBlob2Blob,
BlobToAzureBlob blob2AzureBlob, BlobPropertiesToBlobMetadata blob2BlobMd,
BlobToHttpGetOptions blob2ObjectGetOptions) {
super(context, blobUtils, service, defaultLocation, locations);
this.async = checkNotNull(async, "async");
this.container2ResourceMd = checkNotNull(container2ResourceMd, "container2ResourceMd");
this.blobStore2AzureContainerListOptions = checkNotNull(blobStore2AzureContainerListOptions,
"blobStore2AzureContainerListOptions");
"blobStore2AzureContainerListOptions");
this.azure2BlobStoreResourceList = checkNotNull(azure2BlobStoreResourceList, "azure2BlobStoreResourceList");
this.azureBlob2Blob = checkNotNull(azureBlob2Blob, "azureBlob2Blob");
this.blob2AzureBlob = checkNotNull(blob2AzureBlob, "blob2AzureBlob");
@ -105,15 +107,15 @@ public class AzureAsyncBlobStore extends BaseAsyncBlobStore {
@Override
public ListenableFuture<org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>> list() {
return Futures
.compose(
async.listContainers(includeMetadata()),
new Function<BoundedSet<ContainerProperties>, org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>>() {
public org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata> apply(
BoundedSet<ContainerProperties> from) {
return new PageSetImpl<StorageMetadata>(Iterables.transform(from, container2ResourceMd), from
.getNextMarker());
}
}, service);
.compose(
async.listContainers(includeMetadata()),
new Function<BoundedSet<ContainerProperties>, org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>>() {
public org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata> apply(
BoundedSet<ContainerProperties> from) {
return new PageSetImpl<StorageMetadata>(Iterables.transform(from, container2ResourceMd),
from.getNextMarker());
}
}, service);
}
/**
@ -248,4 +250,12 @@ public class AzureAsyncBlobStore extends BaseAsyncBlobStore {
return putBlob(container, blob);
}
@Override
public ListenableFuture<Boolean> createContainerInLocation(Location location, String container,
CreateContainerOptions options) {
org.jclouds.azureblob.options.CreateContainerOptions createContainerOptions = new org.jclouds.azureblob.options.CreateContainerOptions();
if (options.isPublicRead())
createContainerOptions.withPublicAccess(PublicAccess.CONTAINER);
return async.createContainer(container, createContainerOptions);
}
}

View File

@ -27,6 +27,7 @@ import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.azure.storage.domain.BoundedSet;
import org.jclouds.azureblob.AzureBlobClient;
import org.jclouds.azureblob.blobstore.functions.AzureBlobToBlob;
import org.jclouds.azureblob.blobstore.functions.BlobPropertiesToBlobMetadata;
@ -35,8 +36,8 @@ import org.jclouds.azureblob.blobstore.functions.ContainerToResourceMetadata;
import org.jclouds.azureblob.blobstore.functions.ListBlobsResponseToResourceList;
import org.jclouds.azureblob.blobstore.functions.ListOptionsToListBlobsOptions;
import org.jclouds.azureblob.domain.ContainerProperties;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.options.ListBlobsOptions;
import org.jclouds.azure.storage.domain.BoundedSet;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
@ -45,6 +46,7 @@ import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.collect.Memoized;
@ -236,4 +238,11 @@ public class AzureBlobStore extends BaseBlobStore {
throw new UnsupportedOperationException("please use deleteContainer");
}
@Override
public boolean createContainerInLocation(Location location, String container, CreateContainerOptions options) {
org.jclouds.azureblob.options.CreateContainerOptions createContainerOptions = new org.jclouds.azureblob.options.CreateContainerOptions();
if (options.isPublicRead())
createContainerOptions.withPublicAccess(PublicAccess.CONTAINER);
return sync.createContainer(container, createContainerOptions);
}
}

View File

@ -19,12 +19,18 @@
package org.jclouds.azureblob.blobstore.config;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.inject.Singleton;
import org.jclouds.azureblob.AzureBlobAsyncClient;
import org.jclouds.azureblob.AzureBlobClient;
import org.jclouds.azureblob.blobstore.AzureAsyncBlobStore;
import org.jclouds.azureblob.blobstore.AzureBlobRequestSigner;
import org.jclouds.azureblob.blobstore.AzureBlobStore;
import org.jclouds.azureblob.blobstore.strategy.FindMD5InBlobProperties;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.blobstore.AsyncBlobStore;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.BlobStore;
@ -35,7 +41,10 @@ import org.jclouds.blobstore.internal.BlobStoreContextImpl;
import org.jclouds.blobstore.strategy.ContainsValueInListStrategy;
import org.jclouds.location.config.JustProviderLocationModule;
import com.google.common.base.Function;
import com.google.common.collect.MapMaker;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
@ -59,4 +68,19 @@ public class AzureBlobStoreContextModule extends AbstractModule {
bind(BlobRequestSigner.class).to(AzureBlobRequestSigner.class);
}
@Provides
@Singleton
protected Map<String, PublicAccess> containerAcls(final AzureBlobClient client) {
return new MapMaker().expireAfterWrite(30, TimeUnit.SECONDS).makeComputingMap(
new Function<String, PublicAccess>() {
public PublicAccess apply(String container) {
return client.getPublicAccessForContainer(container);
}
@Override
public String toString() {
return "getPublicAccessForContainer()";
}
});
}
}

View File

@ -42,6 +42,7 @@ public class BlobMetadataToBlobProperties implements Function<BlobMetadata, Muta
HttpUtils.copy(from.getContentMetadata(), to.getContentMetadata());
to.setETag(from.getETag());
to.setName(from.getName());
to.setUrl(from.getUri());
to.setLastModified(from.getLastModified());
if (from.getUserMetadata() != null) {
for (Entry<String, String> entry : from.getUserMetadata().entrySet())

View File

@ -21,10 +21,13 @@ package org.jclouds.azureblob.blobstore.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.azureblob.domain.BlobProperties;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.blobstore.domain.MutableBlobMetadata;
import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
@ -39,10 +42,13 @@ import com.google.common.base.Function;
@Singleton
public class BlobPropertiesToBlobMetadata implements Function<BlobProperties, MutableBlobMetadata> {
private final IfDirectoryReturnNameStrategy ifDirectoryReturnName;
private final Map<String, PublicAccess> containerAcls;
@Inject
public BlobPropertiesToBlobMetadata(IfDirectoryReturnNameStrategy ifDirectoryReturnName) {
public BlobPropertiesToBlobMetadata(IfDirectoryReturnNameStrategy ifDirectoryReturnName,
Map<String, PublicAccess> containerAcls) {
this.ifDirectoryReturnName = checkNotNull(ifDirectoryReturnName, "ifDirectoryReturnName");
this.containerAcls = checkNotNull(containerAcls, "containerAcls");
}
public MutableBlobMetadata apply(BlobProperties from) {
@ -54,6 +60,15 @@ public class BlobPropertiesToBlobMetadata implements Function<BlobProperties, Mu
to.setETag(from.getETag());
to.setLastModified(from.getLastModified());
to.setName(from.getName());
to.setContainer(from.getContainer());
to.setUri(from.getUrl());
try {
PublicAccess containerAcl = containerAcls.get(from.getContainer());
if (containerAcl != null && containerAcl != PublicAccess.PRIVATE)
to.setPublicUri(from.getUrl());
} catch (NullPointerException e) {
// MapMaker cannot return null, but a call to get acls can
}
String directoryName = ifDirectoryReturnName.execute(to);
if (directoryName != null) {
to.setName(directoryName);

View File

@ -45,6 +45,8 @@ public interface BlobProperties extends Comparable<BlobProperties> {
String getName();
String getContainer();
Date getLastModified();
String getETag();

View File

@ -44,7 +44,11 @@ public interface MutableBlobProperties extends BlobProperties {
* @see ListableContainerProperties#getName
*/
void setName(String name);
/**
* @see ListableContainerProperties#getContainer
*/
void setContainer(String container);
/**
* @see ListableContainerProperties#getLastModified
*/

View File

@ -0,0 +1,47 @@
/**
*
* 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.azureblob.domain;
/**
* Indicates whether data in the container may be accessed publicly and the level of access.
*
* @author Adrian Cole
*
* @see <a href="http://msdn.microsoft.com/en-us/library/dd179469.aspx"/>
*/
public enum PublicAccess {
/**
* Indicates full public read access for container and blob data. Clients can enumerate blobs
* within the container via anonymous request, but cannot enumerate containers within the storage
* account.
*/
CONTAINER,
/**
* Indicates public read access for blobs. Blob data within this container can be read via
* anonymous request, but container data is not available. Clients cannot enumerate blobs within
* the container via anonymous request.
*/
BLOB,
/**
* the container is private to the account owner.
*/
PRIVATE;
}

View File

@ -47,6 +47,7 @@ public class BlobPropertiesImpl implements Serializable, BlobProperties {
private static final long serialVersionUID = -4648755473986695062L;
private final BlobType type;
private final String name;
private final String container;
private final URI url;
private final Date lastModified;
private final String eTag;
@ -54,12 +55,13 @@ public class BlobPropertiesImpl implements Serializable, BlobProperties {
private final LeaseStatus leaseStatus;
private final BaseImmutableContentMetadata contentMetadata;
public BlobPropertiesImpl(BlobType type, String name, URI url, Date lastModified, String eTag, long size,
String contentType, @Nullable byte[] contentMD5, @Nullable String contentMetadata,
public BlobPropertiesImpl(BlobType type, String name, String container, URI url, Date lastModified, String eTag,
long size, String contentType, @Nullable byte[] contentMD5, @Nullable String contentMetadata,
@Nullable String contentLanguage, LeaseStatus leaseStatus, Map<String, String> metadata) {
this.type = checkNotNull(type, "type");
this.leaseStatus = checkNotNull(leaseStatus, "leaseStatus");
this.name = checkNotNull(name, "name");
this.container = checkNotNull(container, "container");
this.url = checkNotNull(url, "url");
this.lastModified = checkNotNull(lastModified, "lastModified");
this.eTag = checkNotNull(eTag, "eTag");
@ -84,6 +86,14 @@ public class BlobPropertiesImpl implements Serializable, BlobProperties {
return name;
}
/**
*{@inheritDoc}
*/
@Override
public String getContainer() {
return container;
}
/**
*{@inheritDoc}
*/
@ -144,13 +154,6 @@ public class BlobPropertiesImpl implements Serializable, BlobProperties {
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((contentMetadata == null) ? 0 : contentMetadata.hashCode());
result = prime * result + ((eTag == null) ? 0 : eTag.hashCode());
result = prime * result + ((lastModified == null) ? 0 : lastModified.hashCode());
result = prime * result + ((leaseStatus == null) ? 0 : leaseStatus.hashCode());
result = prime * result + ((metadata == null) ? 0 : metadata.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
result = prime * result + ((url == null) ? 0 : url.hashCode());
return result;
}
@ -164,41 +167,6 @@ public class BlobPropertiesImpl implements Serializable, BlobProperties {
if (getClass() != obj.getClass())
return false;
BlobPropertiesImpl other = (BlobPropertiesImpl) obj;
if (contentMetadata == null) {
if (other.contentMetadata != null)
return false;
} else if (!contentMetadata.equals(other.contentMetadata))
return false;
if (eTag == null) {
if (other.eTag != null)
return false;
} else if (!eTag.equals(other.eTag))
return false;
if (lastModified == null) {
if (other.lastModified != null)
return false;
} else if (!lastModified.equals(other.lastModified))
return false;
if (leaseStatus == null) {
if (other.leaseStatus != null)
return false;
} else if (!leaseStatus.equals(other.leaseStatus))
return false;
if (metadata == null) {
if (other.metadata != null)
return false;
} else if (!metadata.equals(other.metadata))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (type == null) {
if (other.type != null)
return false;
} else if (!type.equals(other.type))
return false;
if (url == null) {
if (other.url != null)
return false;
@ -209,8 +177,9 @@ public class BlobPropertiesImpl implements Serializable, BlobProperties {
@Override
public String toString() {
return "[name=" + name + ", type=" + type + ", contentMetadata=" + contentMetadata + ", eTag=" + eTag
+ ", lastModified=" + lastModified + "]";
return String
.format(
"[name=%s, container=%s, url=%s, contentMetadata=%s, eTag=%s, lastModified=%s, leaseStatus=%s, metadata=%s, type=%s]",
name, container, url, contentMetadata, eTag, lastModified, leaseStatus, metadata, type);
}
}

View File

@ -48,6 +48,7 @@ public class MutableBlobPropertiesImpl implements Serializable, MutableBlobPrope
private LeaseStatus leaseStatus = LeaseStatus.UNLOCKED;
private String name;
private String container;
private URI url;
private Date lastModified;
private String eTag;
@ -61,12 +62,19 @@ public class MutableBlobPropertiesImpl implements Serializable, MutableBlobPrope
public MutableBlobPropertiesImpl(BlobProperties from) {
this.contentMetadata = new BaseMutableContentMetadata();
this.name = from.getName();
this.container = from.getContainer();
this.url = from.getUrl();
this.lastModified = from.getLastModified();
this.eTag = from.getETag();
this.metadata.putAll(from.getMetadata());
HttpUtils.copy(from.getContentMetadata(), this.contentMetadata);
}
/**
*{@inheritDoc}
*/
@Override
public BlobType getType() {
return type;
}
@ -161,12 +169,6 @@ public class MutableBlobPropertiesImpl implements Serializable, MutableBlobPrope
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((contentMetadata == null) ? 0 : contentMetadata.hashCode());
result = prime * result + ((eTag == null) ? 0 : eTag.hashCode());
result = prime * result + ((lastModified == null) ? 0 : lastModified.hashCode());
result = prime * result + ((metadata == null) ? 0 : metadata.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
result = prime * result + ((url == null) ? 0 : url.hashCode());
return result;
}
@ -180,36 +182,6 @@ public class MutableBlobPropertiesImpl implements Serializable, MutableBlobPrope
if (getClass() != obj.getClass())
return false;
MutableBlobPropertiesImpl other = (MutableBlobPropertiesImpl) obj;
if (contentMetadata == null) {
if (other.contentMetadata != null)
return false;
} else if (!contentMetadata.equals(other.contentMetadata))
return false;
if (eTag == null) {
if (other.eTag != null)
return false;
} else if (!eTag.equals(other.eTag))
return false;
if (lastModified == null) {
if (other.lastModified != null)
return false;
} else if (!lastModified.equals(other.lastModified))
return false;
if (metadata == null) {
if (other.metadata != null)
return false;
} else if (!metadata.equals(other.metadata))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (type == null) {
if (other.type != null)
return false;
} else if (!type.equals(other.type))
return false;
if (url == null) {
if (other.url != null)
return false;
@ -220,7 +192,10 @@ public class MutableBlobPropertiesImpl implements Serializable, MutableBlobPrope
@Override
public String toString() {
return "[name=" + name + ", type=" + type + ", lastModified=" + lastModified + "]";
return String
.format(
"[name=%s, container=%s, url=%s, contentMetadata=%s, eTag=%s, lastModified=%s, leaseStatus=%s, metadata=%s, type=%s]",
name, container, url, contentMetadata, eTag, lastModified, leaseStatus, metadata, type);
}
/**
@ -239,5 +214,20 @@ public class MutableBlobPropertiesImpl implements Serializable, MutableBlobPrope
this.contentMetadata = contentMetadata;
}
/**
*{@inheritDoc}
*/
@Override
public String getContainer() {
return container;
}
/**
*{@inheritDoc}
*/
@Override
public void setContainer(String container) {
this.container = container;
}
}

View File

@ -19,6 +19,8 @@
package org.jclouds.azureblob.functions;
import static com.google.common.base.Preconditions.checkArgument;
import javax.inject.Inject;
import org.jclouds.azureblob.blobstore.functions.BlobMetadataToBlobProperties;
@ -28,6 +30,7 @@ import org.jclouds.blobstore.functions.ParseSystemAndUserMetadataFromHeaders;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Function;
@ -42,6 +45,7 @@ public class ParseBlobPropertiesFromHeaders implements Function<HttpResponse, Mu
InvocationContext<ParseBlobPropertiesFromHeaders> {
private final ParseSystemAndUserMetadataFromHeaders blobMetadataParser;
private final BlobMetadataToBlobProperties blobToBlobProperties;
private String container;
@Inject
public ParseBlobPropertiesFromHeaders(ParseSystemAndUserMetadataFromHeaders blobMetadataParser,
@ -56,13 +60,20 @@ public class ParseBlobPropertiesFromHeaders implements Function<HttpResponse, Mu
public MutableBlobProperties apply(HttpResponse from) {
BlobMetadata base = blobMetadataParser.apply(from);
MutableBlobProperties to = blobToBlobProperties.apply(base);
to.setContainer(container);
return to;
}
@Override
public ParseBlobPropertiesFromHeaders setContext(HttpRequest request) {
checkArgument(request instanceof GeneratedHttpRequest<?>, "note this handler requires a GeneratedHttpRequest");
blobMetadataParser.setContext(request);
return this;
return setContainer(GeneratedHttpRequest.class.cast(request).getArgs().get(0).toString());
}
private ParseBlobPropertiesFromHeaders setContainer(String container) {
this.container = container;
return this;
}
}

View File

@ -0,0 +1,28 @@
package org.jclouds.azureblob.functions;
import static org.jclouds.http.HttpUtils.releasePayload;
import javax.inject.Singleton;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.http.HttpResponse;
import com.google.common.base.Function;
/**
*
* @author Adrian Cole
*/
@Singleton
public class ParsePublicAccessHeader implements Function<HttpResponse, PublicAccess> {
public PublicAccess apply(HttpResponse from) {
releasePayload(from);
String access = from.getFirstHeaderOrNull("x-ms-blob-public-access");
if (access == null) {
return PublicAccess.PRIVATE;
}
return PublicAccess.valueOf(access.toUpperCase());
}
}

View File

@ -20,6 +20,7 @@
package org.jclouds.azureblob.options;
import org.jclouds.azure.storage.options.CreateOptions;
import org.jclouds.azureblob.domain.PublicAccess;
import com.google.common.collect.Multimap;
@ -34,7 +35,7 @@ import com.google.common.collect.Multimap;
* import org.jclouds.azureblob.AzureBlobClient;
* <p/>
* AzureBlobClient connection = // get connection
* boolean createdWithPublicAcl = connection.createContainer("containerName", withPublicAcl());
* boolean createdWithPublicAccess = connection.createContainer("containerName", withPublicAccess(PublicAccess.BLOB));
* <code> *
*
* @see <a href="http://msdn.microsoft.com/en-us/library/dd179466.aspx" />
@ -51,19 +52,20 @@ public class CreateContainerOptions extends CreateOptions {
/**
* Indicates whether a container may be accessed publicly
*/
public CreateContainerOptions withPublicAcl() {
this.headers.put("x-ms-prop-publicaccess", "true");
public CreateContainerOptions withPublicAccess(PublicAccess access) {
if (access != PublicAccess.PRIVATE)
this.headers.put("x-ms-blob-public-access", access.name().toLowerCase());
return this;
}
public static class Builder {
/**
* @see CreateContainerOptions#withPublicAcl()
* @see CreateContainerOptions#withPublicAccess
*/
public static CreateContainerOptions withPublicAcl() {
public static CreateContainerOptions withPublicAccess(PublicAccess access) {
CreateContainerOptions options = new CreateContainerOptions();
return options.withPublicAcl();
return options.withPublicAccess(access);
}
/**

View File

@ -130,9 +130,10 @@ public class ContainerNameEnumerationResultsHandler extends ParseSax.HandlerWith
} else if (qName.equals("LeaseStatus")) {
currentLeaseStatus = LeaseStatus.fromValue(currentText.toString().trim());
} else if (qName.equals("Blob")) {
BlobProperties md = new BlobPropertiesImpl(currentBlobType, currentName, currentUrl, currentLastModified,
currentETag, currentSize, currentContentType, currentContentMD5, currentContentEncoding,
currentContentLanguage, currentLeaseStatus, currentMetadata);
BlobProperties md = new BlobPropertiesImpl(currentBlobType, currentName, containerUrl.getPath().replace("/",
""), currentUrl, currentLastModified, currentETag, currentSize, currentContentType,
currentContentMD5, currentContentEncoding, currentContentLanguage, currentLeaseStatus,
currentMetadata);
blobMetadata.add(md);
currentBlobType = null;
currentName = null;

View File

@ -19,8 +19,8 @@
package org.jclouds.azureblob;
import static org.jclouds.azureblob.options.CreateContainerOptions.Builder.withPublicAcl;
import static org.jclouds.azure.storage.options.ListOptions.Builder.maxResults;
import static org.jclouds.azureblob.options.CreateContainerOptions.Builder.withPublicAccess;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
@ -28,15 +28,17 @@ import java.lang.reflect.Method;
import java.util.Map;
import java.util.Properties;
import org.jclouds.azure.storage.filters.SharedKeyLiteAuthentication;
import org.jclouds.azure.storage.options.ListOptions;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.functions.ParseBlobFromHeadersAndHttpContent;
import org.jclouds.azureblob.functions.ParseContainerPropertiesFromHeaders;
import org.jclouds.azureblob.functions.ParsePublicAccessHeader;
import org.jclouds.azureblob.functions.ReturnFalseIfContainerAlreadyExists;
import org.jclouds.azureblob.options.CreateContainerOptions;
import org.jclouds.azureblob.options.ListBlobsOptions;
import org.jclouds.azureblob.xml.AccountNameEnumerationResultsHandler;
import org.jclouds.azureblob.xml.ContainerNameEnumerationResultsHandler;
import org.jclouds.azure.storage.filters.SharedKeyLiteAuthentication;
import org.jclouds.azure.storage.options.ListOptions;
import org.jclouds.blobstore.functions.ReturnNullOnContainerNotFound;
import org.jclouds.blobstore.functions.ReturnNullOnKeyNotFound;
import org.jclouds.http.HttpRequest;
@ -125,13 +127,13 @@ public class AzureBlobAsyncClientTest extends RestClientTest<AzureBlobAsyncClien
public void testCreateContainerOptions() throws SecurityException, NoSuchMethodException, IOException {
Method method = AzureBlobAsyncClient.class.getMethod("createContainer", String.class,
CreateContainerOptions[].class);
HttpRequest request = processor.createRequest(method, "container", withPublicAcl().withMetadata(
ImmutableMultimap.of("foo", "bar")));
HttpRequest request = processor.createRequest(method, "container", withPublicAccess(PublicAccess.BLOB)
.withMetadata(ImmutableMultimap.of("foo", "bar")));
assertRequestLineEquals(request,
"PUT https://identity.blob.core.windows.net/container?restype=container HTTP/1.1");
assertNonPayloadHeadersEqual(request,
"x-ms-meta-foo: bar\nx-ms-prop-publicaccess: true\nx-ms-version: 2009-09-19\n");
"x-ms-blob-public-access: blob\nx-ms-meta-foo: bar\nx-ms-version: 2009-09-19\n");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ReturnTrueIf2xx.class);
@ -168,12 +170,12 @@ public class AzureBlobAsyncClientTest extends RestClientTest<AzureBlobAsyncClien
public void testCreateRootContainerOptions() throws SecurityException, NoSuchMethodException, IOException {
Method method = AzureBlobAsyncClient.class.getMethod("createRootContainer", CreateContainerOptions[].class);
HttpRequest request = processor.createRequest(method, withPublicAcl().withMetadata(
HttpRequest request = processor.createRequest(method, withPublicAccess(PublicAccess.BLOB).withMetadata(
ImmutableMultimap.of("foo", "bar")));
assertRequestLineEquals(request, "PUT https://identity.blob.core.windows.net/$root?restype=container HTTP/1.1");
assertNonPayloadHeadersEqual(request,
"x-ms-meta-foo: bar\nx-ms-prop-publicaccess: true\nx-ms-version: 2009-09-19\n");
"x-ms-blob-public-access: blob\nx-ms-meta-foo: bar\nx-ms-version: 2009-09-19\n");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ReturnTrueIf2xx.class);
@ -223,6 +225,20 @@ public class AzureBlobAsyncClientTest extends RestClientTest<AzureBlobAsyncClien
assertExceptionParserClassEquals(method, ReturnNullOnContainerNotFound.class);
}
public void testGetPublicAccessForContainer() throws SecurityException, NoSuchMethodException, IOException {
Method method = AzureBlobAsyncClient.class.getMethod("getPublicAccessForContainer", String.class);
HttpRequest request = processor.createRequest(method, "container");
assertRequestLineEquals(request,
"HEAD https://identity.blob.core.windows.net/container?restype=container&comp=acl HTTP/1.1");
assertNonPayloadHeadersEqual(request, "x-ms-version: 2009-09-19\n");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ParsePublicAccessHeader.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnNullOnContainerNotFound.class);
}
public void testSetResourceMetadata() throws SecurityException, NoSuchMethodException, IOException {
Method method = AzureBlobAsyncClient.class.getMethod("setResourceMetadata", String.class, Map.class);
HttpRequest request = processor.createRequest(method,

View File

@ -21,7 +21,7 @@ package org.jclouds.azureblob;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.azureblob.options.CreateContainerOptions.Builder.withMetadata;
import static org.jclouds.azureblob.options.CreateContainerOptions.Builder.withPublicAcl;
import static org.jclouds.azureblob.options.CreateContainerOptions.Builder.withPublicAccess;
import static org.jclouds.azure.storage.options.ListOptions.Builder.includeMetadata;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
@ -39,6 +39,7 @@ import org.jclouds.azureblob.domain.AzureBlob;
import org.jclouds.azureblob.domain.BlobProperties;
import org.jclouds.azureblob.domain.ContainerProperties;
import org.jclouds.azureblob.domain.ListBlobsResponse;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.options.ListBlobsOptions;
import org.jclouds.azure.storage.domain.BoundedSet;
import org.jclouds.azure.storage.options.ListOptions;
@ -151,7 +152,7 @@ public class AzureBlobClientLiveTest {
while (!created) {
publicContainer = containerPrefix + new SecureRandom().nextInt();
try {
created = client.createContainer(publicContainer, withPublicAcl());
created = client.createContainer(publicContainer, withPublicAccess(PublicAccess.BLOB));
} catch (UndeclaredThrowableException e) {
HttpResponseException htpe = (HttpResponseException) e.getCause().getCause();
if (htpe.getResponse().getStatusCode() == 409)

View File

@ -22,6 +22,7 @@ package org.jclouds.azureblob.options;
import static org.testng.Assert.assertEquals;
import org.jclouds.azure.storage.reference.AzureStorageHeaders;
import org.jclouds.azureblob.domain.PublicAccess;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
@ -35,16 +36,16 @@ import com.google.common.collect.ImmutableMultimap;
@Test(groups = "unit")
public class CreateContainerOptionsTest {
public void testPublicAcl() {
CreateContainerOptions options = new CreateContainerOptions().withPublicAcl();
assertEquals(ImmutableList.of("true"), options.buildRequestHeaders().get(
"x-ms-prop-publicaccess"));
public void testPublicAccess() {
CreateContainerOptions options = new CreateContainerOptions().withPublicAccess(PublicAccess.BLOB);
assertEquals(ImmutableList.of("blob"), options.buildRequestHeaders().get(
"x-ms-blob-public-access"));
}
public void testPublicAclStatic() {
CreateContainerOptions options = CreateContainerOptions.Builder.withPublicAcl();
assertEquals(ImmutableList.of("true"), options.buildRequestHeaders().get(
"x-ms-prop-publicaccess"));
public void testPublicAccessStatic() {
CreateContainerOptions options = CreateContainerOptions.Builder.withPublicAccess(PublicAccess.BLOB);
assertEquals(ImmutableList.of("blob"), options.buildRequestHeaders().get(
"x-ms-blob-public-access"));
}
public void testMetadata() {

View File

@ -37,6 +37,7 @@ import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
/**
@ -59,47 +60,47 @@ public class ContainerNameEnumerationResultsHandlerTest extends BaseHandlerTest
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/test_list_blobs.xml");
Set<BlobProperties> contents = Sets.newTreeSet();
contents.add(new BlobPropertiesImpl(BlobType.BLOCK_BLOB, "blob1.txt", URI
.create("http://myaccount.blob.core.windows.net/mycontainer/blob1.txt"), dateService
.rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"), "0x8CAE7D55D050B8B", 8, "text/plain; charset=UTF-8",
null, null, null, LeaseStatus.UNLOCKED, ImmutableMap.<String, String> of()));
contents.add(new BlobPropertiesImpl(BlobType.BLOCK_BLOB, "blob2.txt", URI
.create("http://myaccount.blob.core.windows.net/mycontainer/blob2.txt"), dateService
.rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"), "0x8CAE7D55CF6C339", 14, "text/plain; charset=UTF-8",
null, null, null, LeaseStatus.UNLOCKED, ImmutableMap.<String, String> of()));
contents.add(new BlobPropertiesImpl(BlobType.PAGE_BLOB, "newblob1.txt", URI
.create("http://myaccount.blob.core.windows.net/mycontainer/newblob1.txt"), dateService
.rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"), "0x8CAE7D55CF6C339", 25, "text/plain; charset=UTF-8",
null, null, null, LeaseStatus.UNLOCKED, ImmutableMap.<String, String> of()));
Set<BlobProperties> contents = ImmutableSet.<BlobProperties> of(
new BlobPropertiesImpl(BlobType.BLOCK_BLOB, "blob1.txt", "mycontainer", URI
.create("http://myaccount.blob.core.windows.net/mycontainer/blob1.txt"), dateService
.rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"), "0x8CAE7D55D050B8B", 8,
"text/plain; charset=UTF-8", null, null, null, LeaseStatus.UNLOCKED, ImmutableMap
.<String, String> of()), new BlobPropertiesImpl(BlobType.BLOCK_BLOB, "blob2.txt",
"mycontainer", URI.create("http://myaccount.blob.core.windows.net/mycontainer/blob2.txt"),
dateService.rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"), "0x8CAE7D55CF6C339", 14,
"text/plain; charset=UTF-8", null, null, null, LeaseStatus.UNLOCKED, ImmutableMap
.<String, String> of()), new BlobPropertiesImpl(BlobType.PAGE_BLOB, "newblob1.txt",
"mycontainer", URI.create("http://myaccount.blob.core.windows.net/mycontainer/newblob1.txt"),
dateService.rfc822DateParse("Thu, 18 Sep 2008 18:41:57 GMT"), "0x8CAE7D55CF6C339", 25,
"text/plain; charset=UTF-8", null, null, null, LeaseStatus.UNLOCKED, ImmutableMap
.<String, String> of()));
ListBlobsResponse list = new HashSetListBlobsResponse(contents,
URI.create("http://myaccount.blob.core.windows.net/mycontainer"),
ListBlobsResponse list = new HashSetListBlobsResponse(contents, URI
.create("http://myaccount.blob.core.windows.net/mycontainer"),
"myfolder/", null, 4, "newblob2.txt", "/", Sets.<String> newTreeSet());
"myfolder/", null, 4, "newblob2.txt", "/", Sets.<String> newTreeSet());
ListBlobsResponse result = (ListBlobsResponse) factory.create(
injector.getInstance(ContainerNameEnumerationResultsHandler.class)).parse(is);
injector.getInstance(ContainerNameEnumerationResultsHandler.class)).parse(is);
assertEquals(result, list);
}
public void testOptions() {
InputStream is = getClass().getResourceAsStream("/test_list_blobs_options.xml");
Set<BlobProperties> contents = Sets.newTreeSet();
contents.add(new BlobPropertiesImpl(BlobType.BLOCK_BLOB, "a", URI
.create("https://jclouds.blob.core.windows.net/adriancole-blobstore3/a"), dateService
.rfc822DateParse("Sat, 30 Jan 2010 17:46:15 GMT"), "0x8CC6FEB41736428", 8, "application/octet-stream",
null, null, null, LeaseStatus.UNLOCKED, ImmutableMap.<String, String> of()));
Set<BlobProperties> contents = ImmutableSet.<BlobProperties> of(new BlobPropertiesImpl(BlobType.BLOCK_BLOB, "a",
"adriancole-blobstore3", URI.create("https://jclouds.blob.core.windows.net/adriancole-blobstore3/a"),
dateService.rfc822DateParse("Sat, 30 Jan 2010 17:46:15 GMT"), "0x8CC6FEB41736428", 8,
"application/octet-stream", null, null, null, LeaseStatus.UNLOCKED, ImmutableMap.<String, String> of()));
ListBlobsResponse list = new HashSetListBlobsResponse(contents,
URI.create("https://jclouds.blob.core.windows.net/adriancole-blobstore3"),
ListBlobsResponse list = new HashSetListBlobsResponse(contents, URI
.create("https://jclouds.blob.core.windows.net/adriancole-blobstore3"),
null, null, 1, "2!68!MDAwMDA2IWFwcGxlcyEwMDAwMjghOTk5OS0xMi0zMVQyMzo1OTo1OS45OTk5OTk5WiE-", "/",
Sets.<String> newTreeSet());
null, null, 1, "2!68!MDAwMDA2IWFwcGxlcyEwMDAwMjghOTk5OS0xMi0zMVQyMzo1OTo1OS45OTk5OTk5WiE-", "/", Sets
.<String> newTreeSet());
ListBlobsResponse result = (ListBlobsResponse) factory.create(
injector.getInstance(ContainerNameEnumerationResultsHandler.class)).parse(is);
injector.getInstance(ContainerNameEnumerationResultsHandler.class)).parse(is);
assertEquals(result, list);
}