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.domain.StorageMetadata;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore; import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata; import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
@ -258,4 +259,12 @@ public class AtmosAsyncBlobStore extends BaseAsyncBlobStore {
return putBlob(container, 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

@ -43,6 +43,7 @@ import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseBlobStore; import org.jclouds.blobstore.internal.BaseBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata; import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
@ -225,4 +226,10 @@ public class AtmosBlobStore extends BaseBlobStore {
sync.deletePath(container + "/" + key); 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.Function;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
/** /**
* @author Adrian Cole * @author Adrian Cole
@ -61,10 +61,11 @@ public class DirectoryEntryListToResourceMetadataList implements
StorageType type = from.getType() == FileType.DIRECTORY ? StorageType.FOLDER : StorageType.BLOB; StorageType type = from.getType() == FileType.DIRECTORY ? StorageType.FOLDER : StorageType.BLOB;
if (type == StorageType.FOLDER) if (type == StorageType.FOLDER)
return new StorageMetadataImpl(type, from.getObjectID(), from.getObjectName(), defaultLocation 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 else
return new BlobMetadataImpl(from.getObjectID(), from.getObjectName(), defaultLocation.get(), 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()); }), from.getToken());

View File

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

View File

@ -23,10 +23,10 @@ import java.util.List;
import java.util.Properties; import java.util.Properties;
import org.jclouds.blobstore.BlobStoreContextBuilder; 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.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule; 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.Injector;
import com.google.inject.Module; import com.google.inject.Module;
@ -44,8 +44,7 @@ import com.google.inject.Module;
* @author Adrian Cole, Andrew Newdigate * @author Adrian Cole, Andrew Newdigate
* @see CloudFilesBlobStoreContext * @see CloudFilesBlobStoreContext
*/ */
public class CloudFilesContextBuilder extends public class CloudFilesContextBuilder extends BlobStoreContextBuilder<CloudFilesClient, CloudFilesAsyncClient> {
BlobStoreContextBuilder<CloudFilesClient, CloudFilesAsyncClient> {
public CloudFilesContextBuilder(Properties props) { public CloudFilesContextBuilder(Properties props) {
super(CloudFilesClient.class, CloudFilesAsyncClient.class, props); super(CloudFilesClient.class, CloudFilesAsyncClient.class, props);
@ -53,7 +52,7 @@ public class CloudFilesContextBuilder extends
@Override @Override
protected void addContextModule(List<Module> modules) { protected void addContextModule(List<Module> modules) {
modules.add(new SwiftBlobStoreContextModule()); modules.add(new CloudFilesBlobStoreContextModule());
} }
@Override @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; import java.net.URI;
/** /**
* *
* @author James Murty * @author James Murty
@ -79,11 +78,7 @@ public class ContainerCDNMetadata implements Comparable<ContainerCDNMetadata> {
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + (cdn_enabled ? 1231 : 1237);
result = prime * result + ((cdn_uri == null) ? 0 : cdn_uri.hashCode()); 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; return result;
} }
@ -96,22 +91,11 @@ public class ContainerCDNMetadata implements Comparable<ContainerCDNMetadata> {
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
ContainerCDNMetadata other = (ContainerCDNMetadata) obj; ContainerCDNMetadata other = (ContainerCDNMetadata) obj;
if (cdn_enabled != other.cdn_enabled)
return false;
if (cdn_uri == null) { if (cdn_uri == null) {
if (other.cdn_uri != null) if (other.cdn_uri != null)
return false; return false;
} else if (!cdn_uri.equals(other.cdn_uri)) } else if (!cdn_uri.equals(other.cdn_uri))
return false; 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; return true;
} }
@ -129,8 +113,8 @@ public class ContainerCDNMetadata implements Comparable<ContainerCDNMetadata> {
@Override @Override
public String toString() { public String toString() {
return "ContainerCDNMetadata [cdn_enabled=" + cdn_enabled + ", cdn_uri=" + cdn_uri return String.format(
+ ", log_retention=" + log_retention + ", name=" + name + ", referrer_acl=" "[name=%s, cdn_uri=%s, cdn_enabled=%s, log_retention=%s, referrer_acl=%s, ttl=%s, useragent_acl=%s]",
+ referrer_acl + ", ttl=" + ttl + ", useragent_acl=" + useragent_acl + "]"; 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.net.URI;
import java.util.Set; import java.util.Set;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.cloudfiles.domain.ContainerCDNMetadata; import org.jclouds.cloudfiles.domain.ContainerCDNMetadata;
import org.jclouds.cloudfiles.options.ListCdnContainerOptions; import org.jclouds.cloudfiles.options.ListCdnContainerOptions;
import org.jclouds.http.HttpResponseException;
import org.jclouds.openstack.swift.CommonSwiftClientLiveTest; import org.jclouds.openstack.swift.CommonSwiftClientLiveTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -74,28 +72,21 @@ public class CloudFilesClientLiveTest extends CommonSwiftClientLiveTest<CloudFil
assertTrue(cdnMetadata.isCDNEnabled()); assertTrue(cdnMetadata.isCDNEnabled());
assertEquals(cdnMetadata.getCDNUri(), cdnUri); assertEquals(cdnMetadata.getCDNUri(), cdnUri);
final long initialTTL = cdnMetadata.getTTL();
cdnMetadata = getApi().getCDNMetadata(containerNameWithoutCDN);
assert cdnMetadata == null || !cdnMetadata.isCDNEnabled() : containerNameWithoutCDN
+ " should not have metadata";
try { assert getApi().getCDNMetadata("DoesNotExist") == null;
cdnMetadata = getApi().getCDNMetadata(containerNameWithoutCDN);
assert cdnMetadata == null || !cdnMetadata.isCDNEnabled() : containerNameWithoutCDN
+ " should not have metadata";
} catch (ContainerNotFoundException e) {
} catch (HttpResponseException e) {
}
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 // List CDN metadata for containers, and ensure all CDN info is
// available for enabled // available for enabled
// container // container
Set<ContainerCDNMetadata> cdnMetadataList = getApi().listCDNContainers(); Set<ContainerCDNMetadata> cdnMetadataList = getApi().listCDNContainers();
assertTrue(cdnMetadataList.size() >= 1); assertTrue(cdnMetadataList.size() >= 1);
final long initialTTL = cdnMetadata.getTTL();
assertTrue(cdnMetadataList.contains(new ContainerCDNMetadata(containerNameWithCDN, true, initialTTL, cdnUri))); assertTrue(cdnMetadataList.contains(new ContainerCDNMetadata(containerNameWithCDN, true, initialTTL, cdnUri)));
// Test listing with options // 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.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.HttpGetOptionsListToGetOptions; import org.jclouds.blobstore.functions.HttpGetOptionsListToGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore; import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.GetOptions; import org.jclouds.blobstore.options.GetOptions;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.IfDirectoryReturnNameStrategy; import org.jclouds.blobstore.strategy.IfDirectoryReturnNameStrategy;
@ -660,10 +661,17 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
String eTag = CryptoStreams.hex(object.getPayload().getContentMetadata().getContentMD5()); String eTag = CryptoStreams.hex(object.getPayload().getContentMetadata().getContentMD5());
return eTag; return eTag;
} }
@Override @Override
public ListenableFuture<String> putBlobMultipart(String container, Blob blob) { public ListenableFuture<String> putBlobMultipart(String container, Blob blob) {
return putBlob(container, 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 static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -30,19 +31,6 @@ import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.Constants; 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.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata; 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.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore; import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata; import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
@ -58,6 +47,25 @@ import org.jclouds.collect.Memoized;
import org.jclouds.concurrent.Futures; import org.jclouds.concurrent.Futures;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.http.options.GetOptions; 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.Function;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
@ -81,15 +89,16 @@ public class S3AsyncBlobStore extends BaseAsyncBlobStore {
private final BlobToObject blob2Object; private final BlobToObject blob2Object;
private final ObjectToBlobMetadata object2BlobMd; private final ObjectToBlobMetadata object2BlobMd;
private final Provider<FetchBlobMetadata> fetchBlobMetadataProvider; private final Provider<FetchBlobMetadata> fetchBlobMetadataProvider;
private final Map<String, AccessControlList> bucketAcls;
@Inject @Inject
protected S3AsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils, protected S3AsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations, S3AsyncClient async, S3Client sync, @Memoized Supplier<Set<? extends Location>> locations, S3AsyncClient async, S3Client sync,
BucketToResourceMetadata bucket2ResourceMd, ContainerToBucketListOptions container2BucketListOptions, BucketToResourceMetadata bucket2ResourceMd, ContainerToBucketListOptions container2BucketListOptions,
BucketToResourceList bucket2ResourceList, ObjectToBlob object2Blob, BucketToResourceList bucket2ResourceList, ObjectToBlob object2Blob,
BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider) { Provider<FetchBlobMetadata> fetchBlobMetadataProvider, Map<String, AccessControlList> bucketAcls) {
super(context, blobUtils, service, defaultLocation, locations); super(context, blobUtils, service, defaultLocation, locations);
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions"); this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
this.async = checkNotNull(async, "async"); this.async = checkNotNull(async, "async");
@ -101,6 +110,7 @@ public class S3AsyncBlobStore extends BaseAsyncBlobStore {
this.blob2Object = checkNotNull(blob2Object, "blob2Object"); this.blob2Object = checkNotNull(blob2Object, "blob2Object");
this.object2BlobMd = checkNotNull(object2BlobMd, "object2BlobMd"); this.object2BlobMd = checkNotNull(object2BlobMd, "object2BlobMd");
this.fetchBlobMetadataProvider = checkNotNull(fetchBlobMetadataProvider, "fetchBlobMetadataProvider"); this.fetchBlobMetadataProvider = checkNotNull(fetchBlobMetadataProvider, "fetchBlobMetadataProvider");
this.bucketAcls = checkNotNull(bucketAcls, "bucketAcls");
} }
/** /**
@ -109,11 +119,11 @@ public class S3AsyncBlobStore extends BaseAsyncBlobStore {
@Override @Override
public ListenableFuture<PageSet<? extends StorageMetadata>> list() { public ListenableFuture<PageSet<? extends StorageMetadata>> list() {
return Futures.compose(async.listOwnedBuckets(), return Futures.compose(async.listOwnedBuckets(),
new Function<Set<BucketMetadata>, org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>>() { new Function<Set<BucketMetadata>, org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>>() {
public org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata> apply(Set<BucketMetadata> from) { public org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata> apply(Set<BucketMetadata> from) {
return new PageSetImpl<StorageMetadata>(Iterables.transform(from, bucket2ResourceMd), null); return new PageSetImpl<StorageMetadata>(Iterables.transform(from, bucket2ResourceMd), null);
} }
}, service); }, service);
} }
/** /**
@ -137,8 +147,7 @@ public class S3AsyncBlobStore extends BaseAsyncBlobStore {
*/ */
@Override @Override
public ListenableFuture<Boolean> createContainerInLocation(Location location, String container) { public ListenableFuture<Boolean> createContainerInLocation(Location location, String container) {
location = location != null ? location : defaultLocation.get(); return createContainerInLocation(location, container, CreateContainerOptions.NONE);
return async.putBucketInRegion(location.getId(), container);
} }
/** /**
@ -153,9 +162,9 @@ public class S3AsyncBlobStore extends BaseAsyncBlobStore {
ListBucketOptions httpOptions = container2BucketListOptions.apply(options); ListBucketOptions httpOptions = container2BucketListOptions.apply(options);
ListenableFuture<ListBucketResponse> returnVal = async.listBucket(container, httpOptions); ListenableFuture<ListBucketResponse> returnVal = async.listBucket(container, httpOptions);
ListenableFuture<PageSet<? extends StorageMetadata>> list = Futures.compose(returnVal, bucket2ResourceList, ListenableFuture<PageSet<? extends StorageMetadata>> list = Futures.compose(returnVal, bucket2ResourceList,
service); service);
return (options.isDetailed()) ? Futures.compose(list, 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 @Override
public ListenableFuture<String> putBlob(String container, Blob blob) { 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); 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 static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Provider; import javax.inject.Provider;
import javax.inject.Singleton; 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.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata; 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.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseBlobStore; import org.jclouds.blobstore.internal.BaseBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata; import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.http.options.GetOptions; 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 org.jclouds.util.Assertions;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -72,6 +80,7 @@ public class S3BlobStore extends BaseBlobStore {
private final ObjectToBlobMetadata object2BlobMd; private final ObjectToBlobMetadata object2BlobMd;
private final BlobToHttpGetOptions blob2ObjectGetOptions; private final BlobToHttpGetOptions blob2ObjectGetOptions;
private final Provider<FetchBlobMetadata> fetchBlobMetadataProvider; private final Provider<FetchBlobMetadata> fetchBlobMetadataProvider;
private final Map<String, AccessControlList> bucketAcls;
@Inject @Inject
protected S3BlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation, protected S3BlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
@ -79,7 +88,7 @@ public class S3BlobStore extends BaseBlobStore {
BucketToResourceMetadata bucket2ResourceMd, ContainerToBucketListOptions container2BucketListOptions, BucketToResourceMetadata bucket2ResourceMd, ContainerToBucketListOptions container2BucketListOptions,
BucketToResourceList bucket2ResourceList, ObjectToBlob object2Blob, BucketToResourceList bucket2ResourceList, ObjectToBlob object2Blob,
BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions, BlobToObject blob2Object, ObjectToBlobMetadata object2BlobMd,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider) { Provider<FetchBlobMetadata> fetchBlobMetadataProvider, Map<String, AccessControlList> bucketAcls) {
super(context, blobUtils, defaultLocation, locations); super(context, blobUtils, defaultLocation, locations);
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions"); this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
this.sync = checkNotNull(sync, "sync"); this.sync = checkNotNull(sync, "sync");
@ -90,6 +99,7 @@ public class S3BlobStore extends BaseBlobStore {
this.blob2Object = checkNotNull(blob2Object, "blob2Object"); this.blob2Object = checkNotNull(blob2Object, "blob2Object");
this.object2BlobMd = checkNotNull(object2BlobMd, "object2BlobMd"); this.object2BlobMd = checkNotNull(object2BlobMd, "object2BlobMd");
this.fetchBlobMetadataProvider = checkNotNull(fetchBlobMetadataProvider, "fetchBlobMetadataProvider"); this.fetchBlobMetadataProvider = checkNotNull(fetchBlobMetadataProvider, "fetchBlobMetadataProvider");
this.bucketAcls = checkNotNull(bucketAcls, "bucketAcls");
} }
/** /**
@ -125,8 +135,7 @@ public class S3BlobStore extends BaseBlobStore {
*/ */
@Override @Override
public boolean createContainerInLocation(Location location, String container) { public boolean createContainerInLocation(Location location, String container) {
location = location != null ? location : defaultLocation.get(); return createContainerInLocation(location, container, CreateContainerOptions.NONE);
return sync.putBucketInRegion(location.getId(), container);
} }
/** /**
@ -222,7 +231,11 @@ public class S3BlobStore extends BaseBlobStore {
*/ */
@Override @Override
public String putBlob(String container, Blob blob) { 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) { protected boolean deleteAndVerifyContainerGone(final String container) {
return S3Utils.deleteAndVerifyContainerGone(sync, 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; 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.AsyncBlobStore;
import org.jclouds.blobstore.BlobRequestSigner; import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.BlobStore; 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.S3BlobRequestSigner;
import org.jclouds.s3.blobstore.S3BlobStore; import org.jclouds.s3.blobstore.S3BlobStore;
import org.jclouds.s3.blobstore.functions.LocationFromBucketLocation; import org.jclouds.s3.blobstore.functions.LocationFromBucketLocation;
import org.jclouds.s3.domain.AccessControlList;
import org.jclouds.s3.domain.BucketMetadata; import org.jclouds.s3.domain.BucketMetadata;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.MapMaker;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Scopes; import com.google.inject.Scopes;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
@ -70,5 +78,19 @@ public class S3BlobStoreContextModule extends AbstractModule {
}).to(LocationFromBucketLocation.class); }).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; package org.jclouds.s3.blobstore.functions;
import static com.google.common.base.Preconditions.checkArgument;
import java.util.Map.Entry; 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.MutableObjectMetadata;
import org.jclouds.s3.domain.internal.MutableObjectMetadataImpl; import org.jclouds.s3.domain.internal.MutableObjectMetadataImpl;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.http.HttpUtils;
import com.google.common.base.Function; import com.google.common.base.Function;
/** /**
* @author Adrian Cole * @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) { public MutableObjectMetadata apply(BlobMetadata from) {
if (from == null) if (from == null)
return null; return null;
MutableObjectMetadata to = new MutableObjectMetadataImpl(); MutableObjectMetadata to = new MutableObjectMetadataImpl();
HttpUtils.copy(from.getContentMetadata(), to.getContentMetadata()); HttpUtils.copy(from.getContentMetadata(), to.getContentMetadata());
to.setUri(from.getUri());
to.setETag(from.getETag()); to.setETag(from.getETag());
to.setKey(from.getName()); to.setKey(from.getName());
to.setBucket(bucket);
to.setLastModified(from.getLastModified()); to.setLastModified(from.getLastModified());
if (from.getUserMetadata() != null) { if (from.getUserMetadata() != null) {
for (Entry<String, String> entry : from.getUserMetadata().entrySet()) for (Entry<String, String> entry : from.getUserMetadata().entrySet())
@ -49,4 +56,16 @@ public class BlobToObjectMetadata implements Function<BlobMetadata, MutableObjec
} }
return to; 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.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.s3.domain.S3Object;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.Blob.Factory; import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.s3.domain.S3Object;
import com.google.common.base.Function; import com.google.common.base.Function;

View File

@ -19,15 +19,20 @@
package org.jclouds.s3.blobstore.functions; package org.jclouds.s3.blobstore.functions;
import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.blobstore.domain.MutableBlobMetadata; import org.jclouds.blobstore.domain.MutableBlobMetadata;
import org.jclouds.blobstore.domain.StorageType; import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl; import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
import org.jclouds.blobstore.strategy.IfDirectoryReturnNameStrategy; import org.jclouds.blobstore.strategy.IfDirectoryReturnNameStrategy;
import org.jclouds.http.HttpUtils; 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; import com.google.common.base.Function;
@ -37,10 +42,13 @@ import com.google.common.base.Function;
@Singleton @Singleton
public class ObjectToBlobMetadata implements Function<ObjectMetadata, MutableBlobMetadata> { public class ObjectToBlobMetadata implements Function<ObjectMetadata, MutableBlobMetadata> {
private final IfDirectoryReturnNameStrategy ifDirectoryReturnName; private final IfDirectoryReturnNameStrategy ifDirectoryReturnName;
private final Map<String, AccessControlList> bucketAcls;
@Inject @Inject
public ObjectToBlobMetadata(IfDirectoryReturnNameStrategy ifDirectoryReturnName) { public ObjectToBlobMetadata(IfDirectoryReturnNameStrategy ifDirectoryReturnName,
Map<String, AccessControlList> bucketAcls) {
this.ifDirectoryReturnName = ifDirectoryReturnName; this.ifDirectoryReturnName = ifDirectoryReturnName;
this.bucketAcls = bucketAcls;
} }
public MutableBlobMetadata apply(ObjectMetadata from) { public MutableBlobMetadata apply(ObjectMetadata from) {
@ -48,6 +56,15 @@ public class ObjectToBlobMetadata implements Function<ObjectMetadata, MutableBlo
return null; return null;
MutableBlobMetadata to = new MutableBlobMetadataImpl(); MutableBlobMetadata to = new MutableBlobMetadataImpl();
HttpUtils.copy(from.getContentMetadata(), to.getContentMetadata()); 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.setETag(from.getETag());
to.setName(from.getKey()); to.setName(from.getKey());
to.setLastModified(from.getLastModified()); to.setLastModified(from.getLastModified());

View File

@ -19,6 +19,7 @@
package org.jclouds.s3.domain; package org.jclouds.s3.domain;
import java.net.URI;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
@ -50,6 +51,8 @@ public interface MutableObjectMetadata extends ObjectMetadata {
*/ */
void setKey(String key); 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. * 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 * 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 setUserMetadata(Map<String, String> userMetadata);
void setUri(URI uri);
} }

View File

@ -19,6 +19,7 @@
package org.jclouds.s3.domain; package org.jclouds.s3.domain;
import java.net.URI;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
@ -50,6 +51,10 @@ public interface ObjectMetadata extends Comparable<ObjectMetadata> {
*/ */
String getKey(); String getKey();
String getBucket();
URI getUri();
/** /**
* Every bucket and object in Amazon S3 has an owner, the user that created the bucket or object. * 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 * 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; package org.jclouds.s3.domain;
import java.net.URI;
import java.util.Date;
import java.util.Map; import java.util.Map;
import org.jclouds.io.ContentMetadataBuilder; import org.jclouds.io.ContentMetadataBuilder;
@ -38,19 +40,49 @@ public class ObjectMetadataBuilder {
return new 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 String key;
private StorageClass storageClass; private String bucket;
private URI uri;
private StorageClass storageClass = StorageClass.STANDARD;
private String cacheControl; private String cacheControl;
private Date lastModified;
private String eTag;
private CanonicalUser owner;
private Map<String, String> userMetadata = ImmutableMap.of(); private Map<String, String> userMetadata = ImmutableMap.of();
public ObjectMetadataBuilder key(String key) { public ObjectMetadataBuilder key(String key) {
this.key = key; this.key = key;
return this; 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) { public ObjectMetadataBuilder storageClass(StorageClass storageClass) {
this.storageClass = storageClass; this.storageClass = storageClass;
return this; return this;
@ -98,7 +130,6 @@ public class ObjectMetadataBuilder {
public ObjectMetadataBuilder contentType(String contentType) { public ObjectMetadataBuilder contentType(String contentType) {
contentMetadataBuilder.contentType(contentType); contentMetadataBuilder.contentType(contentType);
return this; return this;
} }
public ObjectMetadata build() { public ObjectMetadata build() {
@ -106,8 +137,13 @@ public class ObjectMetadataBuilder {
toReturn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(contentMetadataBuilder.build())); toReturn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(contentMetadataBuilder.build()));
toReturn.setCacheControl(cacheControl); toReturn.setCacheControl(cacheControl);
toReturn.setKey(key); toReturn.setKey(key);
toReturn.setBucket(bucket);
toReturn.setUri(uri);
toReturn.setETag(eTag);
toReturn.setOwner(owner);
toReturn.setStorageClass(storageClass); toReturn.setStorageClass(storageClass);
toReturn.setUserMetadata(userMetadata); toReturn.setUserMetadata(userMetadata);
toReturn.setLastModified(lastModified);
return toReturn; return toReturn;
} }

View File

@ -19,16 +19,19 @@
package org.jclouds.s3.domain.internal; package org.jclouds.s3.domain.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.Serializable; import java.io.Serializable;
import java.net.URI;
import java.util.Date; import java.util.Date;
import java.util.Map; 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.ContentMetadata;
import org.jclouds.io.payloads.BaseImmutableContentMetadata; 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 * 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 static final long serialVersionUID = -4415449798024051115L;
private final String key; private final String key;
private final String bucket;
private final URI uri;
private final Date lastModified; private final Date lastModified;
private final String eTag; private final String eTag;
private final CanonicalUser owner; private final CanonicalUser owner;
private final StorageClass storageClass; private final StorageClass storageClass;
private final String cacheControl;
private final Map<String, String> userMetadata;
private final ContentMetadata contentMetadata; private final ContentMetadata contentMetadata;
public BucketListObjectMetadata(String key, Date lastModified, String eTag, byte[] md5, long contentLength, public BucketListObjectMetadata(String key, String bucket, URI uri, Date lastModified, String eTag, byte[] md5,
CanonicalUser owner, StorageClass storageClass) { long contentLength, CanonicalUser owner, StorageClass storageClass) {
this.key = key; this.key = checkNotNull(key, "key");
this.bucket = checkNotNull(bucket, "bucket");
this.uri = checkNotNull(uri, "uri");
this.lastModified = lastModified; this.lastModified = lastModified;
this.eTag = eTag; this.eTag = eTag;
this.owner = owner; this.owner = owner;
this.contentMetadata = new BaseImmutableContentMetadata(null, contentLength, md5, null, null, null); this.contentMetadata = new BaseImmutableContentMetadata(null, contentLength, md5, null, null, null);
this.storageClass = storageClass; this.storageClass = storageClass;
this.cacheControl = null;
this.userMetadata = Maps.newHashMap();
} }
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public URI getUri() {
return uri;
}
/**
*{@inheritDoc}
*/
@Override
public String getKey() { public String getKey() {
return key; return key;
} }
@ -71,6 +83,15 @@ public class BucketListObjectMetadata implements Serializable, ObjectMetadata {
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public String getBucket() {
return bucket;
}
/**
*{@inheritDoc}
*/
@Override
public CanonicalUser getOwner() { public CanonicalUser getOwner() {
return owner; return owner;
} }
@ -78,6 +99,7 @@ public class BucketListObjectMetadata implements Serializable, ObjectMetadata {
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public StorageClass getStorageClass() { public StorageClass getStorageClass() {
return storageClass; return storageClass;
} }
@ -85,13 +107,15 @@ public class BucketListObjectMetadata implements Serializable, ObjectMetadata {
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public String getCacheControl() { public String getCacheControl() {
return cacheControl; return null;
} }
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public Date getLastModified() { public Date getLastModified() {
return lastModified; return lastModified;
} }
@ -99,6 +123,7 @@ public class BucketListObjectMetadata implements Serializable, ObjectMetadata {
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public String getETag() { public String getETag() {
return eTag; return eTag;
} }
@ -106,15 +131,17 @@ public class BucketListObjectMetadata implements Serializable, ObjectMetadata {
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public int compareTo(ObjectMetadata o) { public int compareTo(ObjectMetadata o) {
return (this == o) ? 0 : getKey().compareTo(o.getKey()); return (this == o) ? 0 : getUri().compareTo(o.getUri());
} }
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public Map<String, String> getUserMetadata() { public Map<String, String> getUserMetadata() {
return userMetadata; return ImmutableMap.of();
} }
/** /**
@ -129,14 +156,7 @@ public class BucketListObjectMetadata implements Serializable, ObjectMetadata {
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + ((cacheControl == null) ? 0 : cacheControl.hashCode()); result = prime * result + ((uri == null) ? 0 : uri.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; return result;
} }
@ -149,47 +169,19 @@ public class BucketListObjectMetadata implements Serializable, ObjectMetadata {
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
BucketListObjectMetadata other = (BucketListObjectMetadata) obj; BucketListObjectMetadata other = (BucketListObjectMetadata) obj;
if (cacheControl == null) { if (uri == null) {
if (other.cacheControl != null) if (other.uri != null)
return false; return false;
} else if (!cacheControl.equals(other.cacheControl)) } else if (!uri.equals(other.uri))
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 false;
return true; 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; package org.jclouds.s3.domain.internal;
import java.io.Serializable; import java.io.Serializable;
import java.net.URI;
import java.util.Date; import java.util.Date;
import java.util.Map; 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.ContentMetadata;
import org.jclouds.io.payloads.BaseImmutableContentMetadata; 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 * Returns the metadata parsable from a bucket listing
@ -38,57 +41,68 @@ public class CopyObjectResult implements Serializable, ObjectMetadata {
/** The serialVersionUID */ /** The serialVersionUID */
private static final long serialVersionUID = -4415449798024051115L; private static final long serialVersionUID = -4415449798024051115L;
private final String key;
private final Date lastModified; private final Date lastModified;
private final String eTag; 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; private final BaseImmutableContentMetadata contentMetadata;
public CopyObjectResult(Date lastModified, String eTag) { public CopyObjectResult(Date lastModified, String eTag) {
this.key = null;
this.lastModified = lastModified; this.lastModified = lastModified;
this.eTag = eTag; this.eTag = eTag;
this.owner = null;
this.storageClass = StorageClass.STANDARD;
this.contentMetadata = new BaseImmutableContentMetadata(null, null, null, null, null, null); this.contentMetadata = new BaseImmutableContentMetadata(null, null, null, null, null, null);
this.cacheControl = null;
this.userMetadata = null;
} }
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public String getKey() { public String getKey() {
return key; return null;
} }
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public String getBucket() {
return null;
}
/**
*{@inheritDoc}
*/
@Override
public URI getUri() {
return null;
}
/**
*{@inheritDoc}
*/
@Override
public CanonicalUser getOwner() { public CanonicalUser getOwner() {
return owner; return null;
} }
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public StorageClass getStorageClass() { public StorageClass getStorageClass() {
return storageClass; return null;
} }
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public String getCacheControl() { public String getCacheControl() {
return cacheControl; return null;
} }
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public Date getLastModified() { public Date getLastModified() {
return lastModified; return lastModified;
} }
@ -96,6 +110,7 @@ public class CopyObjectResult implements Serializable, ObjectMetadata {
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public String getETag() { public String getETag() {
return eTag; return eTag;
} }
@ -103,15 +118,17 @@ public class CopyObjectResult implements Serializable, ObjectMetadata {
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public int compareTo(ObjectMetadata o) { public int compareTo(ObjectMetadata o) {
return (this == o) ? 0 : getKey().compareTo(o.getKey()); return (this == o) ? 0 : getETag().compareTo(o.getETag());
} }
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public Map<String, String> getUserMetadata() { public Map<String, String> getUserMetadata() {
return userMetadata; return ImmutableMap.of();
} }
/** /**
@ -126,14 +143,8 @@ public class CopyObjectResult implements Serializable, ObjectMetadata {
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; 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 + ((eTag == null) ? 0 : eTag.hashCode());
result = prime * result + ((key == null) ? 0 : key.hashCode());
result = prime * result + ((lastModified == null) ? 0 : lastModified.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; return result;
} }
@ -146,47 +157,22 @@ public class CopyObjectResult implements Serializable, ObjectMetadata {
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
CopyObjectResult other = (CopyObjectResult) obj; 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 (eTag == null) {
if (other.eTag != null) if (other.eTag != null)
return false; return false;
} else if (!eTag.equals(other.eTag)) } else if (!eTag.equals(other.eTag))
return false; return false;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
if (lastModified == null) { if (lastModified == null) {
if (other.lastModified != null) if (other.lastModified != null)
return false; return false;
} else if (!lastModified.equals(other.lastModified)) } else if (!lastModified.equals(other.lastModified))
return false; 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; 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; package org.jclouds.s3.domain.internal;
import java.io.Serializable; import java.io.Serializable;
import java.net.URI;
import java.util.Date; import java.util.Date;
import java.util.Map; 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.http.HttpUtils;
import org.jclouds.io.MutableContentMetadata; import org.jclouds.io.MutableContentMetadata;
import org.jclouds.io.payloads.BaseMutableContentMetadata; 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; import com.google.common.collect.Maps;
@ -43,6 +44,8 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
private static final long serialVersionUID = -4648755473986695062L; private static final long serialVersionUID = -4648755473986695062L;
private String key; private String key;
private String bucket;
private URI uri;
private Date lastModified; private Date lastModified;
private String eTag; private String eTag;
private CanonicalUser owner; private CanonicalUser owner;
@ -60,11 +63,15 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
this.storageClass = StorageClass.STANDARD; this.storageClass = StorageClass.STANDARD;
this.contentMetadata = new BaseMutableContentMetadata(); this.contentMetadata = new BaseMutableContentMetadata();
HttpUtils.copy(from.getContentMetadata(), this.contentMetadata); HttpUtils.copy(from.getContentMetadata(), this.contentMetadata);
this.key = from.getKey();
this.uri = from.getUri();
this.bucket = from.getBucket();
} }
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public String getKey() { public String getKey() {
return key; return key;
} }
@ -72,6 +79,31 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/** /**
*{@inheritDoc} *{@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() { public CanonicalUser getOwner() {
return owner; return owner;
} }
@ -79,6 +111,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public StorageClass getStorageClass() { public StorageClass getStorageClass() {
return storageClass; return storageClass;
} }
@ -86,6 +119,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public String getCacheControl() { public String getCacheControl() {
return cacheControl; return cacheControl;
} }
@ -93,6 +127,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public Date getLastModified() { public Date getLastModified() {
return lastModified; return lastModified;
} }
@ -100,6 +135,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public String getETag() { public String getETag() {
return eTag; return eTag;
} }
@ -107,6 +143,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public int compareTo(ObjectMetadata o) { public int compareTo(ObjectMetadata o) {
return (this == o) ? 0 : getKey().compareTo(o.getKey()); return (this == o) ? 0 : getKey().compareTo(o.getKey());
} }
@ -114,6 +151,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public Map<String, String> getUserMetadata() { public Map<String, String> getUserMetadata() {
return userMetadata; return userMetadata;
} }
@ -121,6 +159,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public void setCacheControl(String cacheControl) { public void setCacheControl(String cacheControl) {
this.cacheControl = cacheControl; this.cacheControl = cacheControl;
} }
@ -128,6 +167,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public void setETag(String eTag) { public void setETag(String eTag) {
this.eTag = eTag; this.eTag = eTag;
} }
@ -135,6 +175,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public void setKey(String key) { public void setKey(String key) {
this.key = key; this.key = key;
} }
@ -142,6 +183,15 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public void setBucket(String bucket) {
this.bucket = bucket;
}
/**
*{@inheritDoc}
*/
@Override
public void setLastModified(Date lastModified) { public void setLastModified(Date lastModified) {
this.lastModified = lastModified; this.lastModified = lastModified;
} }
@ -149,6 +199,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public void setOwner(CanonicalUser owner) { public void setOwner(CanonicalUser owner) {
this.owner = owner; this.owner = owner;
} }
@ -156,6 +207,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public void setStorageClass(StorageClass storageClass) { public void setStorageClass(StorageClass storageClass) {
this.storageClass = storageClass; this.storageClass = storageClass;
} }
@ -163,6 +215,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public void setUserMetadata(Map<String, String> userMetadata) { public void setUserMetadata(Map<String, String> userMetadata) {
this.userMetadata = userMetadata; this.userMetadata = userMetadata;
} }
@ -187,14 +240,7 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + ((cacheControl == null) ? 0 : cacheControl.hashCode()); result = prime * result + ((uri == null) ? 0 : uri.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; return result;
} }
@ -207,54 +253,21 @@ public class MutableObjectMetadataImpl implements Serializable, MutableObjectMet
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
MutableObjectMetadataImpl other = (MutableObjectMetadataImpl) obj; MutableObjectMetadataImpl other = (MutableObjectMetadataImpl) obj;
if (cacheControl == null) { if (uri == null) {
if (other.cacheControl != null) if (other.uri != null)
return false; return false;
} else if (!cacheControl.equals(other.cacheControl)) } else if (!uri.equals(other.uri))
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 false;
return true; return true;
} }
@Override @Override
public String toString() { public String toString() {
return "[key=" + key + ", cacheControl=" + cacheControl + ", contentMetadata=" + contentMetadata + ", eTag=" return String
+ eTag + ", lastModified=" + lastModified + ", owner=" + owner + ", storageClass=" + storageClass .format(
+ ", userMetadata=" + userMetadata + "]"; "[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); S3Object object = objectProvider.create(metadata);
object.getAllHeaders().putAll(from.getHeaders()); object.getAllHeaders().putAll(from.getHeaders());
object.setPayload(from.getPayload()); object.setPayload(from.getPayload());
return object; return object;
} }

View File

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

View File

@ -19,6 +19,8 @@
package org.jclouds.s3.xml; package org.jclouds.s3.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import java.net.URI; import java.net.URI;
import org.jclouds.http.functions.ParseSax; 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")) { else if (qName.equals("ID") || qName.equals("EmailAddress") || qName.equals("URI")) {
currentId = currentText.toString().trim(); currentId = currentOrNull(currentText);
} else if (qName.equals("DisplayName")) { } else if (qName.equals("DisplayName")) {
currentDisplayName = currentText.toString().trim(); currentDisplayName = currentOrNull(currentText);
} else if (qName.equals("Permission")) { } else if (qName.equals("Permission")) {
currentPermission = currentText.toString().trim(); currentPermission = currentOrNull(currentText);
} }
currentText = new StringBuilder(); currentText = new StringBuilder();
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -19,6 +19,8 @@
package org.jclouds.s3.xml; package org.jclouds.s3.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import org.jclouds.aws.domain.Region; import org.jclouds.aws.domain.Region;
import org.jclouds.http.functions.ParseSax; 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) { 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. * {@code US_STANDARD} is returned as "" xml documents.
*/ */
public static String fromValue(String v) { public static String fromValue(String v) {
if (v.equals("")) if (v == null || "".equals(v))
return Region.US_STANDARD; 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; return v;
} }

View File

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

View File

@ -23,6 +23,7 @@ import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.Date; import java.util.Date;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
@ -30,16 +31,19 @@ import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorCompletionService;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.PerformanceTest; 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.BucketMetadata;
import org.jclouds.s3.domain.CanonicalUser; import org.jclouds.s3.domain.CanonicalUser;
import org.jclouds.s3.domain.ListBucketResponse; import org.jclouds.s3.domain.ListBucketResponse;
import org.jclouds.s3.domain.ObjectMetadata; import org.jclouds.s3.domain.ObjectMetadata;
import org.jclouds.s3.domain.ObjectMetadata.StorageClass; 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.jclouds.util.Strings2;
import org.testng.annotations.AfterTest; import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
@ -49,13 +53,14 @@ import org.xml.sax.SAXException;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.sun.jersey.api.uri.UriBuilderImpl;
/** /**
* Tests parsing of S3 responses * Tests parsing of S3 responses
* *
* @author Adrian Cole * @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") @Test(groups = "performance", sequential = true, timeOut = 2 * 60 * 1000, testName = "S3ParserTest")
public class S3ParserTest extends PerformanceTest { public class S3ParserTest extends PerformanceTest {
Injector injector = null; Injector injector = null;
@ -63,7 +68,12 @@ public class S3ParserTest extends PerformanceTest {
@BeforeTest @BeforeTest
protected void setUpInjector() { 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); factory = injector.getInstance(ParseSax.Factory.class);
assert factory != null; assert factory != null;
} }
@ -140,7 +150,8 @@ public class S3ParserTest extends PerformanceTest {
} }
private ListBucketResponse runParseListContainerResult() throws HttpException { 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)); 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.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore; import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata; import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
@ -82,14 +83,14 @@ public class SwiftAsyncBlobStore extends BaseAsyncBlobStore {
private final Provider<FetchBlobMetadata> fetchBlobMetadataProvider; private final Provider<FetchBlobMetadata> fetchBlobMetadataProvider;
@Inject @Inject
SwiftAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils, protected SwiftAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations, CommonSwiftClient sync, CommonSwiftAsyncClient async, @Memoized Supplier<Set<? extends Location>> locations, CommonSwiftClient sync,
ContainerToResourceMetadata container2ResourceMd, CommonSwiftAsyncClient async, ContainerToResourceMetadata container2ResourceMd,
BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions, BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob, BlobToObject blob2Object, ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob, BlobToObject blob2Object,
ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions, ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions,
Provider<FetchBlobMetadata> fetchBlobMetadataProvider) { Provider<FetchBlobMetadata> fetchBlobMetadataProvider) {
super(context, blobUtils, service, defaultLocation, locations); super(context, blobUtils, service, defaultLocation, locations);
this.sync = sync; this.sync = sync;
this.async = async; this.async = async;
@ -109,11 +110,12 @@ public class SwiftAsyncBlobStore extends BaseAsyncBlobStore {
@Override @Override
public ListenableFuture<PageSet<? extends StorageMetadata>> list() { public ListenableFuture<PageSet<? extends StorageMetadata>> list() {
return Futures.compose(async.listContainers(), return Futures.compose(async.listContainers(),
new Function<Set<ContainerMetadata>, org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>>() { new Function<Set<ContainerMetadata>, org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>>() {
public org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata> apply(Set<ContainerMetadata> from) { public org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata> apply(
return new PageSetImpl<StorageMetadata>(Iterables.transform(from, container2ResourceMd), null); Set<ContainerMetadata> from) {
} return new PageSetImpl<StorageMetadata>(Iterables.transform(from, container2ResourceMd), null);
}, service); }
}, service);
} }
/** /**
@ -144,12 +146,12 @@ public class SwiftAsyncBlobStore extends BaseAsyncBlobStore {
@Override @Override
public ListenableFuture<PageSet<? extends StorageMetadata>> list(String container, ListContainerOptions options) { public ListenableFuture<PageSet<? extends StorageMetadata>> list(String container, ListContainerOptions options) {
org.jclouds.openstack.swift.options.ListContainerOptions httpOptions = container2ContainerListOptions org.jclouds.openstack.swift.options.ListContainerOptions httpOptions = container2ContainerListOptions
.apply(options); .apply(options);
ListenableFuture<PageSet<ObjectInfo>> returnVal = async.listObjects(container, httpOptions); ListenableFuture<PageSet<ObjectInfo>> returnVal = async.listObjects(container, httpOptions);
ListenableFuture<PageSet<? extends StorageMetadata>> list = Futures.compose(returnVal, container2ResourceList, ListenableFuture<PageSet<? extends StorageMetadata>> list = Futures.compose(returnVal, container2ResourceList,
service); service);
return options.isDetailed() ? Futures.compose(list, fetchBlobMetadataProvider.get().setContainerName(container), return options.isDetailed() ? Futures.compose(list, fetchBlobMetadataProvider.get().setContainerName(container),
service) : list; service) : list;
} }
/** /**
@ -176,14 +178,14 @@ public class SwiftAsyncBlobStore extends BaseAsyncBlobStore {
@Override @Override
public ListenableFuture<BlobMetadata> blobMetadata(String container, String key) { public ListenableFuture<BlobMetadata> blobMetadata(String container, String key) {
return Futures.compose(async.getObjectInfo(container, key), return Futures.compose(async.getObjectInfo(container, key),
new Function<MutableObjectInfoWithMetadata, BlobMetadata>() { new Function<MutableObjectInfoWithMetadata, BlobMetadata>() {
@Override @Override
public BlobMetadata apply(MutableObjectInfoWithMetadata from) { public BlobMetadata apply(MutableObjectInfoWithMetadata from) {
return object2BlobMd.apply(from); return object2BlobMd.apply(from);
} }
}, service); }, service);
} }
/** /**
@ -239,4 +241,11 @@ public class SwiftAsyncBlobStore extends BaseAsyncBlobStore {
return putBlob(container, 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

@ -36,6 +36,7 @@ import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.internal.PageSetImpl; import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseBlobStore; import org.jclouds.blobstore.internal.BaseBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata; import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
@ -72,7 +73,7 @@ public class SwiftBlobStore extends BaseBlobStore {
private final Provider<FetchBlobMetadata> fetchBlobMetadataProvider; private final Provider<FetchBlobMetadata> fetchBlobMetadataProvider;
@Inject @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, @Memoized Supplier<Set<? extends Location>> locations, CommonSwiftClient sync,
ContainerToResourceMetadata container2ResourceMd, ContainerToResourceMetadata container2ResourceMd,
BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions, BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
@ -226,4 +227,11 @@ public class SwiftBlobStore extends BaseBlobStore {
sync.deleteContainerIfEmpty(container); sync.deleteContainerIfEmpty(container);
return !sync.containerExists(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) if (from.getHash() != null)
to.setETag(CryptoStreams.hex(from.getHash())); to.setETag(CryptoStreams.hex(from.getHash()));
to.setName(from.getName()); to.setName(from.getName());
if (from.getBytes() != null) to.setContainer(from.getContainer());
to.getContentMetadata().setContentLength(from.getBytes()); to.setUri(from.getUri());
to.getContentMetadata().setContentLength(from.getBytes());
if (from.getLastModified() != null) if (from.getLastModified() != null)
to.setLastModified(from.getLastModified()); to.setLastModified(from.getLastModified());
if (from instanceof MutableObjectInfoWithMetadata) if (from instanceof MutableObjectInfoWithMetadata)

View File

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

View File

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

View File

@ -19,6 +19,7 @@
package org.jclouds.openstack.swift.domain.internal; package org.jclouds.openstack.swift.domain.internal;
import java.net.URI;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
@ -63,7 +64,8 @@ public class DelegatingMutableObjectInfoWithMetadata extends BaseMutableContentM
@Override @Override
public void setContentLength(Long bytes) { public void setContentLength(Long bytes) {
delegate.setBytes(bytes); if (bytes != null)
delegate.setBytes(bytes);
} }
@Override @Override
@ -107,7 +109,7 @@ public class DelegatingMutableObjectInfoWithMetadata extends BaseMutableContentM
@Override @Override
public Long getBytes() { public Long getBytes() {
return delegate.getBytes(); return delegate.getBytes();
} }
@Override @Override
@ -129,4 +131,24 @@ public class DelegatingMutableObjectInfoWithMetadata extends BaseMutableContentM
public int compareTo(ObjectInfo o) { public int compareTo(ObjectInfo o) {
return delegate.compareTo(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; package org.jclouds.openstack.swift.domain.internal;
import java.net.URI;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
@ -37,44 +38,82 @@ import com.google.common.collect.Maps;
*/ */
public class MutableObjectInfoWithMetadataImpl implements MutableObjectInfoWithMetadata { public class MutableObjectInfoWithMetadataImpl implements MutableObjectInfoWithMetadata {
private String name; private String name;
private String container;
private URI uri;
private Long bytes; private Long bytes;
private byte[] hash; private byte[] hash;
private String contentType = MediaType.APPLICATION_OCTET_STREAM; private String contentType = MediaType.APPLICATION_OCTET_STREAM;
private Date lastModified; 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() { public Map<String, String> getMetadata() {
return metadata; return metadata;
} }
/**
* {@inheritDoc}
*/
@Override
public void setBytes(Long bytes) { public void setBytes(Long bytes) {
this.bytes = bytes; this.bytes = bytes;
} }
/**
* {@inheritDoc}
*/
@Override
public void setContentType(String contentType) { public void setContentType(String contentType) {
this.contentType = contentType; this.contentType = contentType;
} }
/**
* {@inheritDoc}
*/
@Override
public void setHash(byte[] hash) { public void setHash(byte[] hash) {
this.hash = hash; this.hash = hash;
} }
/**
* {@inheritDoc}
*/
@Override
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
/**
* {@inheritDoc}
*/
@Override
public Long getBytes() { public Long getBytes() {
return bytes; return bytes;
} }
/**
* {@inheritDoc}
*/
@Override
public String getContentType() { public String getContentType() {
return contentType; return contentType;
} }
/**
* {@inheritDoc}
*/
@Override
public byte[] getHash() { public byte[] getHash() {
return hash; return hash;
} }
/**
* {@inheritDoc}
*/
@Override
public Date getLastModified() { public Date getLastModified() {
return lastModified; return lastModified;
} }
@ -83,11 +122,7 @@ public class MutableObjectInfoWithMetadataImpl implements MutableObjectInfoWithM
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + ((bytes == null) ? 0 : bytes.hashCode()); result = prime * result + ((container == null) ? 0 : container.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 + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode());
return result; return result;
} }
@ -101,27 +136,10 @@ public class MutableObjectInfoWithMetadataImpl implements MutableObjectInfoWithM
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
MutableObjectInfoWithMetadataImpl other = (MutableObjectInfoWithMetadataImpl) obj; MutableObjectInfoWithMetadataImpl other = (MutableObjectInfoWithMetadataImpl) obj;
if (bytes == null) { if (container == null) {
if (other.bytes != null) if (other.container != null)
return false; return false;
} else if (!bytes.equals(other.bytes)) } else if (!container.equals(other.container))
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))
return false; return false;
if (name == null) { if (name == null) {
if (other.name != null) if (other.name != null)
@ -131,16 +149,60 @@ public class MutableObjectInfoWithMetadataImpl implements MutableObjectInfoWithM
return true; return true;
} }
/**
* {@inheritDoc}
*/
@Override
public String getName() { public String getName() {
return name; return name;
} }
/**
* {@inheritDoc}
*/
@Override
public int compareTo(ObjectInfo o) { public int compareTo(ObjectInfo o) {
return (this == o) ? 0 : getName().compareTo(o.getName()); return (this == o) ? 0 : getName().compareTo(o.getName());
} }
/**
* {@inheritDoc}
*/
@Override
public void setLastModified(Date lastModified) { public void setLastModified(Date lastModified) {
this.lastModified = 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; package org.jclouds.openstack.swift.domain.internal;
import java.net.URI;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import org.jclouds.openstack.swift.domain.ObjectInfo; import org.jclouds.openstack.swift.domain.ObjectInfo;
import com.google.gson.annotations.SerializedName;
public class ObjectInfoImpl implements ObjectInfo { public class ObjectInfoImpl implements ObjectInfo {
String name; public static Builder builder() {
byte[] hash; return new Builder();
long bytes; }
String content_type;
Date last_modified; 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() { 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() { public byte[] getHash() {
return hash; 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 @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + (int) (bytes ^ (bytes >>> 32)); result = prime * result + ((container == null) ? 0 : container.hashCode());
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 + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode());
return result; return result;
} }
@ -82,19 +185,10 @@ public class ObjectInfoImpl implements ObjectInfo {
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
ObjectInfoImpl other = (ObjectInfoImpl) obj; ObjectInfoImpl other = (ObjectInfoImpl) obj;
if (bytes != other.bytes) if (container == null) {
return false; if (other.container != null)
if (content_type == null) {
if (other.content_type != null)
return false; return false;
} else if (!content_type.equals(other.content_type)) } else if (!container.equals(other.container))
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))
return false; return false;
if (name == null) { if (name == null) {
if (other.name != null) if (other.name != null)
@ -104,15 +198,19 @@ public class ObjectInfoImpl implements ObjectInfo {
return true; return true;
} }
public int compareTo(ObjectInfo o) { @Override
return (this == o) ? 0 : getName().compareTo(o.getName()); 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 @Override
public String toString() { public int compareTo(ObjectInfo o) {
return "ObjectInfoImpl [bytes=" + bytes + ", content_flavor=" return name.compareTo(o.getName());
+ content_type + ", hash=" + Arrays.asList(hash)
+ ", last_modified=" + last_modified.getTime() + ", name=" + name
+ "]";
} }
} }

View File

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

View File

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

View File

@ -25,8 +25,11 @@ import static org.easymock.classextension.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
import java.net.URI;
import java.util.Set; import java.util.Set;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.crypto.CryptoStreams; import org.jclouds.crypto.CryptoStreams;
import org.jclouds.date.internal.SimpleDateFormatDateService; import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.json.config.GsonModule; import org.jclouds.json.config.GsonModule;
@ -39,10 +42,11 @@ import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList; 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.AbstractModule;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.sun.jersey.api.uri.UriBuilderImpl;
/** /**
* Tests behavior of {@code ParseObjectInfoListFromJsonResponse} * Tests behavior of {@code ParseObjectInfoListFromJsonResponse}
@ -57,34 +61,31 @@ public class ParseObjectInfoListFromJsonResponseTest {
@Override @Override
protected void configure() { protected void configure() {
bind(DateAdapter.class).to(Iso8601DateAdapter.class); bind(DateAdapter.class).to(Iso8601DateAdapter.class);
bind(UriBuilder.class).to(UriBuilderImpl.class);
} }
}, new GsonModule()); }, new GsonModule());
public void testApplyInputStream() { public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/test_list_container.json"); InputStream is = getClass().getResourceAsStream("/test_list_container.json");
Set<ObjectInfo> expects = Sets.newLinkedHashSet(); Set<ObjectInfo> expects = ImmutableSet.<ObjectInfo> of(ObjectInfoImpl.builder().container("container").name(
ObjectInfoImpl one = i.getInstance(ObjectInfoImpl.class); "test_obj_1").uri(URI.create("http://localhost/foo/test_obj_1")).hash(
one.name = "test_obj_1"; CryptoStreams.hex("4281c348eaf83e70ddce0e07221c3d28")).bytes(14l)
one.hash = CryptoStreams.hex("4281c348eaf83e70ddce0e07221c3d28"); .contentType("application/octet-stream").lastModified(
one.bytes = 14l; new SimpleDateFormatDateService().iso8601DateParse("2009-02-03T05:26:32.612Z")).build(),
one.content_type = "application/octet-stream"; ObjectInfoImpl.builder().container("container").name("test_obj_2").uri(
one.last_modified = new SimpleDateFormatDateService().iso8601DateParse("2009-02-03T05:26:32.612Z"); URI.create("http://localhost/foo/test_obj_2")).hash(
expects.add(one); CryptoStreams.hex("b039efe731ad111bc1b0ef221c3849d0")).bytes(64l).contentType(
ObjectInfoImpl two = i.getInstance(ObjectInfoImpl.class); "application/octet-stream").lastModified(
two.name = ("test_obj_2"); new SimpleDateFormatDateService().iso8601DateParse("2009-02-03T05:26:32.612Z")).build());
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);
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
ListContainerOptions options = new ListContainerOptions(); ListContainerOptions options = new ListContainerOptions();
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/foo")).atLeastOnce();
expect(request.getArgs()).andReturn( expect(request.getArgs()).andReturn(
ImmutableList.<Object> of("containter", new ListContainerOptions[] { options })).atLeastOnce(); ImmutableList.<Object> of("container", new ListContainerOptions[] { options })).atLeastOnce();
replay(request); replay(request);
ParseObjectInfoListFromJsonResponse parser = i.getInstance(ParseObjectInfoListFromJsonResponse.class); ParseObjectInfoListFromJsonResponse parser = i.getInstance(ParseObjectInfoListFromJsonResponse.class);
parser.setContext(request); 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.BlobMetadata;
import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.GetOptions; import org.jclouds.blobstore.options.GetOptions;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
@ -77,6 +78,12 @@ public interface AsyncBlobStore {
*/ */
ListenableFuture<Boolean> createContainerInLocation(@Nullable Location location, String container); 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) * @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.BlobMetadata;
import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.GetOptions; import org.jclouds.blobstore.options.GetOptions;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
@ -100,6 +101,14 @@ public interface BlobStore {
*/ */
boolean createContainerInLocation(@Nullable Location location, String container); 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. * 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.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -61,21 +61,24 @@ import java.util.concurrent.ExecutorService;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Provider;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.blobstore.domain.BlobMetadata; import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.MutableBlobMetadata; import org.jclouds.blobstore.domain.MutableBlobMetadata;
import org.jclouds.blobstore.domain.MutableStorageMetadata; import org.jclouds.blobstore.domain.MutableStorageMetadata;
import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.StorageType; import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.blobstore.domain.internal.MutableStorageMetadataImpl; import org.jclouds.blobstore.domain.internal.MutableStorageMetadataImpl;
import org.jclouds.blobstore.domain.internal.PageSetImpl; import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.HttpGetOptionsListToGetOptions; import org.jclouds.blobstore.functions.HttpGetOptionsListToGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore; import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.GetOptions; import org.jclouds.blobstore.options.GetOptions;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.strategy.IfDirectoryReturnNameStrategy; import org.jclouds.blobstore.strategy.IfDirectoryReturnNameStrategy;
@ -91,6 +94,7 @@ import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
import org.jclouds.http.options.HttpRequestOptions; import org.jclouds.http.options.HttpRequestOptions;
import org.jclouds.io.ContentMetadata;
import org.jclouds.io.MutableContentMetadata; import org.jclouds.io.MutableContentMetadata;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
import org.jclouds.io.Payloads; import org.jclouds.io.Payloads;
@ -117,6 +121,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
protected final DateService dateService; protected final DateService dateService;
protected final Crypto crypto; protected final Crypto crypto;
protected final ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs; protected final ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs;
protected final Provider<UriBuilder> uriBuilders;
protected final ConcurrentMap<String, Location> containerToLocation; protected final ConcurrentMap<String, Location> containerToLocation;
protected final HttpGetOptionsListToGetOptions httpGetOptionsConverter; protected final HttpGetOptionsListToGetOptions httpGetOptionsConverter;
protected final IfDirectoryReturnNameStrategy ifDirectoryReturnName; protected final IfDirectoryReturnNameStrategy ifDirectoryReturnName;
@ -124,16 +129,18 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
@Inject @Inject
protected TransientAsyncBlobStore(BlobStoreContext context, DateService dateService, Crypto crypto, protected TransientAsyncBlobStore(BlobStoreContext context, DateService dateService, Crypto crypto,
ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs, ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs, Provider<UriBuilder> uriBuilders,
ConcurrentMap<String, Location> containerToLocation, HttpGetOptionsListToGetOptions httpGetOptionsConverter, ConcurrentMap<String, Location> containerToLocation,
IfDirectoryReturnNameStrategy ifDirectoryReturnName, Factory blobFactory, BlobUtils blobUtils, HttpGetOptionsListToGetOptions httpGetOptionsConverter,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation, IfDirectoryReturnNameStrategy ifDirectoryReturnName, Factory blobFactory, BlobUtils blobUtils,
@Memoized Supplier<Set<? extends Location>> locations) { @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations) {
super(context, blobUtils, service, defaultLocation, locations); super(context, blobUtils, service, defaultLocation, locations);
this.blobFactory = blobFactory; this.blobFactory = blobFactory;
this.dateService = dateService; this.dateService = dateService;
this.crypto = crypto; this.crypto = crypto;
this.containerToBlobs = containerToBlobs; this.containerToBlobs = containerToBlobs;
this.uriBuilders = uriBuilders;
this.containerToLocation = containerToLocation; this.containerToLocation = containerToLocation;
this.httpGetOptionsConverter = httpGetOptionsConverter; this.httpGetOptionsConverter = httpGetOptionsConverter;
this.ifDirectoryReturnName = ifDirectoryReturnName; this.ifDirectoryReturnName = ifDirectoryReturnName;
@ -152,21 +159,21 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
return immediateFailedFuture(cnfe(container)); return immediateFailedFuture(cnfe(container));
SortedSet<StorageMetadata> contents = newTreeSet(transform(realContents.keySet(), SortedSet<StorageMetadata> contents = newTreeSet(transform(realContents.keySet(),
new Function<String, StorageMetadata>() { new Function<String, StorageMetadata>() {
public StorageMetadata apply(String key) { public StorageMetadata apply(String key) {
Blob oldBlob = realContents.get(key); Blob oldBlob = realContents.get(key);
checkState(oldBlob != null, "blob " + key + " is not present although it was in the list of " checkState(oldBlob != null, "blob " + key + " is not present although it was in the list of "
+ container); + container);
checkState(oldBlob.getMetadata() != null, "blob " + container + "/" + key + " has no metadata"); checkState(oldBlob.getMetadata() != null, "blob " + container + "/" + key + " has no metadata");
MutableBlobMetadata md = copy(oldBlob.getMetadata()); MutableBlobMetadata md = copy(oldBlob.getMetadata());
String directoryName = ifDirectoryReturnName.execute(md); String directoryName = ifDirectoryReturnName.execute(md);
if (directoryName != null) { if (directoryName != null) {
md.setName(directoryName); md.setName(directoryName);
md.setType(StorageType.RELATIVE_PATH); md.setType(StorageType.RELATIVE_PATH);
}
return md;
} }
return md; }));
}
}));
if (options.getMarker() != null) { if (options.getMarker() != null) {
final String finalMarker = options.getMarker(); 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))); contents = newTreeSet(filter(contents, new DelimiterFilter(prefix != null ? prefix : null, delimiter)));
Iterables.<StorageMetadata> addAll(contents, Iterables.<StorageMetadata> addAll(contents, transform(commonPrefixes,
transform(commonPrefixes, new Function<String, StorageMetadata>() { new Function<String, StorageMetadata>() {
public StorageMetadata apply(String o) { public StorageMetadata apply(String o) {
MutableStorageMetadata md = new MutableStorageMetadataImpl(); MutableStorageMetadata md = new MutableStorageMetadataImpl();
md.setType(StorageType.RELATIVE_PATH); md.setType(StorageType.RELATIVE_PATH);
md.setName(o); md.setName(o);
return md; return md;
} }
})); }));
} }
// trim metadata, if the response isn't supposed to be detailed. // 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, return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(contents,
marker)); marker));
} }
private ContainerNotFoundException cnfe(final String name) { private ContainerNotFoundException cnfe(final String name) {
return new ContainerNotFoundException(name, String.format("container %s not in %s", name, getContainerToBlobs() return new ContainerNotFoundException(name, String.format("container %s not in %s", name, getContainerToBlobs()
.keySet())); .keySet()));
} }
public static MutableBlobMetadata copy(MutableBlobMetadata in) { public static MutableBlobMetadata copy(MutableBlobMetadata in) {
@ -333,15 +340,15 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
@Override @Override
public ListenableFuture<PageSet<? extends StorageMetadata>> list() { public ListenableFuture<PageSet<? extends StorageMetadata>> list() {
return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(transform( return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(transform(
getContainerToBlobs().keySet(), new Function<String, StorageMetadata>() { getContainerToBlobs().keySet(), new Function<String, StorageMetadata>() {
public StorageMetadata apply(String name) { public StorageMetadata apply(String name) {
MutableStorageMetadata cmd = create(); MutableStorageMetadata cmd = create();
cmd.setName(name); cmd.setName(name);
cmd.setType(StorageType.CONTAINER); cmd.setType(StorageType.CONTAINER);
cmd.setLocation(getContainerToLocation().get(name)); cmd.setLocation(getContainerToLocation().get(name));
return cmd; return cmd;
} }
}), null)); }), null));
} }
protected MutableStorageMetadata create() { protected MutableStorageMetadata create() {
@ -365,7 +372,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
*/ */
public ListenableFuture<Void> createContainerInLocationIfAbsent(final Location location, final String name) { public ListenableFuture<Void> createContainerInLocationIfAbsent(final Location location, final String name) {
ConcurrentMap<String, Blob> container = getContainerToBlobs().putIfAbsent(name, ConcurrentMap<String, Blob> container = getContainerToBlobs().putIfAbsent(name,
new ConcurrentHashMap<String, Blob>()); new ConcurrentHashMap<String, Blob>());
if (container == null) { if (container == null) {
getContainerToLocation().put(name, location != null ? location : defaultLocation.get()); getContainerToLocation().put(name, location != null ? location : defaultLocation.get());
return immediateFuture((Void) null); return immediateFuture((Void) null);
@ -495,7 +502,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
new IllegalStateException("containerName not found: " + containerName); new IllegalStateException("containerName not found: " + containerName);
} }
Blob blob = createUpdatedCopyOfBlob(in); Blob blob = createUpdatedCopyOfBlobInContainer(containerName, in);
container.put(blob.getMetadata().getName(), blob); container.put(blob.getMetadata().getName(), blob);
@ -508,22 +515,22 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
new IllegalStateException("containerName not found: " + containerName); new IllegalStateException("containerName not found: " + containerName);
} }
Blob blob = createUpdatedCopyOfBlob(in); Blob blob = createUpdatedCopyOfBlobInContainer(containerName, in);
Blob old = container.put(blob.getMetadata().getName(), blob); Blob old = container.put(blob.getMetadata().getName(), blob);
return immediateFuture(old); return immediateFuture(old);
} }
protected Blob createUpdatedCopyOfBlob(Blob in) { protected Blob createUpdatedCopyOfBlobInContainer(String containerName, Blob in) {
checkNotNull(in, "blob"); checkNotNull(in, "blob");
checkNotNull(in.getPayload(), "blob.payload"); checkNotNull(in.getPayload(), "blob.payload");
ByteArrayPayload payload = (in.getPayload() instanceof ByteArrayPayload) ? ByteArrayPayload.class.cast(in ByteArrayPayload payload = (in.getPayload() instanceof ByteArrayPayload) ? ByteArrayPayload.class.cast(in
.getPayload()) : null; .getPayload()) : null;
if (payload == null) if (payload == null)
payload = (in.getPayload() instanceof DelegatingPayload) ? (DelegatingPayload.class.cast(in.getPayload()) payload = (in.getPayload() instanceof DelegatingPayload) ? (DelegatingPayload.class.cast(in.getPayload())
.getDelegate() instanceof ByteArrayPayload) ? ByteArrayPayload.class.cast(DelegatingPayload.class.cast( .getDelegate() instanceof ByteArrayPayload) ? ByteArrayPayload.class.cast(DelegatingPayload.class
in.getPayload()).getDelegate()) : null : null; .cast(in.getPayload()).getDelegate()) : null : null;
try { try {
if (payload == null || !(payload instanceof ByteArrayPayload)) { if (payload == null || !(payload instanceof ByteArrayPayload)) {
MutableContentMetadata oldMd = in.getPayload().getContentMetadata(); MutableContentMetadata oldMd = in.getPayload().getContentMetadata();
@ -540,12 +547,15 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
} }
Blob blob = blobFactory.create(copy(in.getMetadata())); Blob blob = blobFactory.create(copy(in.getMetadata()));
blob.setPayload(payload); 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()); blob.getMetadata().setLastModified(new Date());
String eTag = CryptoStreams.hex(payload.getContentMetadata().getContentMD5()); String eTag = CryptoStreams.hex(payload.getContentMetadata().getContentMD5());
blob.getMetadata().setETag(eTag); blob.getMetadata().setETag(eTag);
// Set HTTP headers to match metadata // Set HTTP headers to match metadata
blob.getAllHeaders().replaceValues(HttpHeaders.LAST_MODIFIED, 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)); blob.getAllHeaders().replaceValues(HttpHeaders.ETAG, Collections.singleton(eTag));
copyPayloadHeadersToBlob(payload, blob); copyPayloadHeadersToBlob(payload, blob);
blob.getAllHeaders().putAll(Multimaps.forMap(blob.getMetadata().getUserMetadata())); blob.getAllHeaders().putAll(Multimaps.forMap(blob.getMetadata().getUserMetadata()));
@ -593,7 +603,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
if (object.getMetadata().getLastModified().before(modifiedSince)) { if (object.getMetadata().getLastModified().before(modifiedSince)) {
HttpResponse response = new HttpResponse(304, null, null); HttpResponse response = new HttpResponse(304, null, null);
return immediateFailedFuture(new HttpResponseException(String.format("%1$s is before %2$s", object 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)) { if (object.getMetadata().getLastModified().after(unmodifiedSince)) {
HttpResponse response = new HttpResponse(412, null, null); HttpResponse response = new HttpResponse(412, null, null);
return immediateFailedFuture(new HttpResponseException(String.format("%1$s is after %2$s", object 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); Blob returnVal = copyBlob(object);
@ -633,7 +643,10 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
} }
} }
ContentMetadata cmd = returnVal.getPayload().getContentMetadata();
returnVal.setPayload(out.toByteArray()); returnVal.setPayload(out.toByteArray());
HttpUtils.copy(cmd, returnVal.getPayload().getContentMetadata());
returnVal.getPayload().getContentMetadata().setContentLength(new Long(out.toByteArray().length));
} }
checkNotNull(returnVal.getPayload(), "payload " + returnVal); checkNotNull(returnVal.getPayload(), "payload " + returnVal);
return immediateFuture(returnVal); return immediateFuture(returnVal);
@ -681,4 +694,12 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
return putBlob(container, 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

@ -19,6 +19,10 @@
package org.jclouds.blobstore.domain; package org.jclouds.blobstore.domain;
import java.net.URI;
import javax.annotation.Nullable;
import org.jclouds.blobstore.domain.internal.BlobMetadataImpl; import org.jclouds.blobstore.domain.internal.BlobMetadataImpl;
import org.jclouds.io.ContentMetadata; import org.jclouds.io.ContentMetadata;
@ -31,5 +35,20 @@ import com.google.inject.ImplementedBy;
*/ */
@ImplementedBy(BlobMetadataImpl.class) @ImplementedBy(BlobMetadataImpl.class)
public interface BlobMetadata extends StorageMetadata { 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(); ContentMetadata getContentMetadata();
} }

View File

@ -19,6 +19,10 @@
package org.jclouds.blobstore.domain; package org.jclouds.blobstore.domain;
import java.net.URI;
import javax.annotation.Nullable;
import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl; import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
import org.jclouds.io.MutableContentMetadata; import org.jclouds.io.MutableContentMetadata;
@ -31,8 +35,24 @@ import com.google.inject.ImplementedBy;
*/ */
@ImplementedBy(MutableBlobMetadataImpl.class) @ImplementedBy(MutableBlobMetadataImpl.class)
public interface MutableBlobMetadata extends BlobMetadata, MutableStorageMetadata { public interface MutableBlobMetadata extends BlobMetadata, MutableStorageMetadata {
/**
* {@inheritDoc}
*/
@Override
MutableContentMetadata getContentMetadata(); MutableContentMetadata getContentMetadata();
/**
* @see BlobMetadata#getContentMetadata
*/
void setContentMetadata(MutableContentMetadata md); 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 { public class BlobMetadataImpl extends StorageMetadataImpl implements Serializable, BlobMetadata {
/** The serialVersionUID */ /** The serialVersionUID */
private static final long serialVersionUID = -5932618957134612231L; private static final long serialVersionUID = -5932618957134612231L;
private final URI publicUri;
private final String container;
private final ContentMetadata contentMetadata; private final ContentMetadata contentMetadata;
public BlobMetadataImpl(String id, String name, @Nullable Location location, URI uri, String eTag, 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); super(StorageType.BLOB, id, name, location, uri, eTag, lastModified, userMetadata);
this.publicUri = publicUri;
this.container = container;
this.contentMetadata = checkNotNull(contentMetadata, "contentMetadata"); this.contentMetadata = checkNotNull(contentMetadata, "contentMetadata");
} }
/**
* {@inheritDoc}
*/
@Override
public URI getPublicUri() {
return publicUri;
}
/**
* {@inheritDoc}
*/
@Override
public String getContainer() {
return container;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */

View File

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

View File

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

View File

@ -19,10 +19,40 @@
package org.jclouds.blobstore.integration.internal; 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 * @author Adrian Cole
*/ */
public class BaseContainerLiveTest extends BaseBlobStoreIntegrationTest { 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; package org.jclouds.http.functions;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.http.functions.config.SaxParserModule; import org.jclouds.http.functions.config.SaxParserModule;
import org.testng.annotations.AfterTest; import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
@ -26,6 +28,7 @@ import org.testng.annotations.Test;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.sun.jersey.api.uri.UriBuilderImpl;
/** /**
* *
@ -39,7 +42,12 @@ public class BaseHandlerTest {
@BeforeTest @BeforeTest
protected void setUpInjector() { 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); factory = injector.getInstance(ParseSax.Factory.class);
assert factory != null; assert factory != null;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -19,13 +19,13 @@
package org.jclouds.aws.s3.blobstore.integration; 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; import org.testng.annotations.Test;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "live", testName = "AWSS3InputStreamMapIntegrationLiveTest") @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.Path;
import javax.ws.rs.PathParam; 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.binders.BindAzureBlobMetadataToRequest;
import org.jclouds.azureblob.domain.BlobProperties; import org.jclouds.azureblob.domain.BlobProperties;
import org.jclouds.azureblob.domain.ContainerProperties; import org.jclouds.azureblob.domain.ContainerProperties;
import org.jclouds.azureblob.domain.ListBlobsResponse; import org.jclouds.azureblob.domain.ListBlobsResponse;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.functions.BlobName; import org.jclouds.azureblob.functions.BlobName;
import org.jclouds.azureblob.functions.ParseBlobFromHeadersAndHttpContent; import org.jclouds.azureblob.functions.ParseBlobFromHeadersAndHttpContent;
import org.jclouds.azureblob.functions.ParseBlobPropertiesFromHeaders; import org.jclouds.azureblob.functions.ParseBlobPropertiesFromHeaders;
import org.jclouds.azureblob.functions.ParseContainerPropertiesFromHeaders; import org.jclouds.azureblob.functions.ParseContainerPropertiesFromHeaders;
import org.jclouds.azureblob.functions.ParsePublicAccessHeader;
import org.jclouds.azureblob.functions.ReturnFalseIfContainerAlreadyExists; import org.jclouds.azureblob.functions.ReturnFalseIfContainerAlreadyExists;
import org.jclouds.azureblob.options.CreateContainerOptions; import org.jclouds.azureblob.options.CreateContainerOptions;
import org.jclouds.azureblob.options.ListBlobsOptions; import org.jclouds.azureblob.options.ListBlobsOptions;
import org.jclouds.azureblob.predicates.validators.ContainerNameValidator; import org.jclouds.azureblob.predicates.validators.ContainerNameValidator;
import org.jclouds.azureblob.xml.AccountNameEnumerationResultsHandler; import org.jclouds.azureblob.xml.AccountNameEnumerationResultsHandler;
import org.jclouds.azureblob.xml.ContainerNameEnumerationResultsHandler; 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.binders.BindMapToHeadersWithPrefix;
import org.jclouds.blobstore.functions.ReturnFalseOnContainerNotFound; import org.jclouds.blobstore.functions.ReturnFalseOnContainerNotFound;
import org.jclouds.blobstore.functions.ReturnFalseOnKeyNotFound; import org.jclouds.blobstore.functions.ReturnFalseOnKeyNotFound;
@ -95,8 +97,7 @@ public interface AzureBlobAsyncClient {
@GET @GET
@XMLResponseParser(AccountNameEnumerationResultsHandler.class) @XMLResponseParser(AccountNameEnumerationResultsHandler.class)
@QueryParams(keys = "comp", values = "list") @QueryParams(keys = "comp", values = "list")
ListenableFuture<? extends BoundedSet<ContainerProperties>> listContainers( ListenableFuture<? extends BoundedSet<ContainerProperties>> listContainers(ListOptions... listOptions);
ListOptions... listOptions);
/** /**
* @see AzureBlobClient#createContainer * @see AzureBlobClient#createContainer
@ -109,6 +110,17 @@ public interface AzureBlobAsyncClient {
@PathParam("container") @ParamValidators( { ContainerNameValidator.class }) String container, @PathParam("container") @ParamValidators( { ContainerNameValidator.class }) String container,
CreateContainerOptions... options); 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 * @see AzureBlobClient#getContainerProperties
*/ */
@ -238,8 +250,7 @@ public interface AzureBlobAsyncClient {
@QueryParams(keys = { "comp" }, values = { "metadata" }) @QueryParams(keys = { "comp" }, values = { "metadata" })
ListenableFuture<Void> setBlobMetadata( ListenableFuture<Void> setBlobMetadata(
@PathParam("container") @ParamValidators( { ContainerNameValidator.class }) String container, @PathParam("container") @ParamValidators( { ContainerNameValidator.class }) String container,
@PathParam("name") String name, @PathParam("name") String name, @BinderParam(BindMapToHeadersWithPrefix.class) Map<String, String> metadata);
@BinderParam(BindMapToHeadersWithPrefix.class) Map<String, String> metadata);
/** /**
* @see AzureBlobClient#deleteBlob * @see AzureBlobClient#deleteBlob

View File

@ -21,29 +21,28 @@ package org.jclouds.azureblob;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; 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.BlobProperties;
import org.jclouds.azureblob.domain.ContainerProperties; import org.jclouds.azureblob.domain.ContainerProperties;
import org.jclouds.azureblob.domain.ListBlobsResponse; import org.jclouds.azureblob.domain.ListBlobsResponse;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.options.CreateContainerOptions; import org.jclouds.azureblob.options.CreateContainerOptions;
import org.jclouds.azureblob.options.ListBlobsOptions; 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.blobstore.ContainerNotFoundException;
import org.jclouds.concurrent.Timeout; import org.jclouds.concurrent.Timeout;
import org.jclouds.http.options.GetOptions; import org.jclouds.http.options.GetOptions;
import com.google.inject.Provides; import com.google.inject.Provides;
import java.util.concurrent.Future;
/** /**
* Provides access to Azure Blob via their REST API. * Provides access to Azure Blob via their REST API.
* <p/> * <p/>
* All commands return a Future of the result from Azure Blob. Any exceptions incurred * All commands return a Future of the result from Azure Blob. Any exceptions incurred during
* during processing will be wrapped in an {@link ExecutionException} as documented in * processing will be wrapped in an {@link ExecutionException} as documented in {@link Future#get()}.
* {@link Future#get()}.
* *
* @see <a href="http://msdn.microsoft.com/en-us/library/dd135733.aspx" /> * @see <a href="http://msdn.microsoft.com/en-us/library/dd135733.aspx" />
* @author Adrian Cole * @author Adrian Cole
@ -131,6 +130,14 @@ public interface AzureBlobClient {
*/ */
boolean createRootContainer(CreateContainerOptions... options); 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 * 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> * any blobs contained within it are later deleted during garbage collection. <h4>Remarks</h4>
@ -214,8 +221,7 @@ public interface AzureBlobClient {
* properties. * properties.
*/ */
@Timeout(duration = 10 * 64, timeUnit = TimeUnit.MINUTES) @Timeout(duration = 10 * 64, timeUnit = TimeUnit.MINUTES)
org.jclouds.azureblob.domain.AzureBlob getBlob(String container, String name, org.jclouds.azureblob.domain.AzureBlob getBlob(String container, String name, GetOptions... options);
GetOptions... options);
/** /**
* The Get Blob Properties operation returns all user-defined metadata, standard HTTP properties, * 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.BlobProperties;
import org.jclouds.azureblob.domain.ContainerProperties; import org.jclouds.azureblob.domain.ContainerProperties;
import org.jclouds.azureblob.domain.ListBlobsResponse; import org.jclouds.azureblob.domain.ListBlobsResponse;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.options.ListBlobsOptions; import org.jclouds.azureblob.options.ListBlobsOptions;
import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob; 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.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseAsyncBlobStore; import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
@ -79,18 +81,18 @@ public class AzureAsyncBlobStore extends BaseAsyncBlobStore {
@Inject @Inject
AzureAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils, AzureAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
@Memoized Supplier<Set<? extends Location>> locations, AzureBlobAsyncClient async, @Memoized Supplier<Set<? extends Location>> locations, AzureBlobAsyncClient async,
ContainerToResourceMetadata container2ResourceMd, ContainerToResourceMetadata container2ResourceMd,
ListOptionsToListBlobsOptions blobStore2AzureContainerListOptions, ListOptionsToListBlobsOptions blobStore2AzureContainerListOptions,
ListBlobsResponseToResourceList azure2BlobStoreResourceList, AzureBlobToBlob azureBlob2Blob, ListBlobsResponseToResourceList azure2BlobStoreResourceList, AzureBlobToBlob azureBlob2Blob,
BlobToAzureBlob blob2AzureBlob, BlobPropertiesToBlobMetadata blob2BlobMd, BlobToAzureBlob blob2AzureBlob, BlobPropertiesToBlobMetadata blob2BlobMd,
BlobToHttpGetOptions blob2ObjectGetOptions) { BlobToHttpGetOptions blob2ObjectGetOptions) {
super(context, blobUtils, service, defaultLocation, locations); super(context, blobUtils, service, defaultLocation, locations);
this.async = checkNotNull(async, "async"); this.async = checkNotNull(async, "async");
this.container2ResourceMd = checkNotNull(container2ResourceMd, "container2ResourceMd"); this.container2ResourceMd = checkNotNull(container2ResourceMd, "container2ResourceMd");
this.blobStore2AzureContainerListOptions = checkNotNull(blobStore2AzureContainerListOptions, this.blobStore2AzureContainerListOptions = checkNotNull(blobStore2AzureContainerListOptions,
"blobStore2AzureContainerListOptions"); "blobStore2AzureContainerListOptions");
this.azure2BlobStoreResourceList = checkNotNull(azure2BlobStoreResourceList, "azure2BlobStoreResourceList"); this.azure2BlobStoreResourceList = checkNotNull(azure2BlobStoreResourceList, "azure2BlobStoreResourceList");
this.azureBlob2Blob = checkNotNull(azureBlob2Blob, "azureBlob2Blob"); this.azureBlob2Blob = checkNotNull(azureBlob2Blob, "azureBlob2Blob");
this.blob2AzureBlob = checkNotNull(blob2AzureBlob, "blob2AzureBlob"); this.blob2AzureBlob = checkNotNull(blob2AzureBlob, "blob2AzureBlob");
@ -105,15 +107,15 @@ public class AzureAsyncBlobStore extends BaseAsyncBlobStore {
@Override @Override
public ListenableFuture<org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>> list() { public ListenableFuture<org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>> list() {
return Futures return Futures
.compose( .compose(
async.listContainers(includeMetadata()), async.listContainers(includeMetadata()),
new Function<BoundedSet<ContainerProperties>, org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>>() { new Function<BoundedSet<ContainerProperties>, org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>>() {
public org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata> apply( public org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata> apply(
BoundedSet<ContainerProperties> from) { BoundedSet<ContainerProperties> from) {
return new PageSetImpl<StorageMetadata>(Iterables.transform(from, container2ResourceMd), from return new PageSetImpl<StorageMetadata>(Iterables.transform(from, container2ResourceMd),
.getNextMarker()); from.getNextMarker());
} }
}, service); }, service);
} }
/** /**
@ -248,4 +250,12 @@ public class AzureAsyncBlobStore extends BaseAsyncBlobStore {
return putBlob(container, blob); 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.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.azure.storage.domain.BoundedSet;
import org.jclouds.azureblob.AzureBlobClient; import org.jclouds.azureblob.AzureBlobClient;
import org.jclouds.azureblob.blobstore.functions.AzureBlobToBlob; import org.jclouds.azureblob.blobstore.functions.AzureBlobToBlob;
import org.jclouds.azureblob.blobstore.functions.BlobPropertiesToBlobMetadata; 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.ListBlobsResponseToResourceList;
import org.jclouds.azureblob.blobstore.functions.ListOptionsToListBlobsOptions; import org.jclouds.azureblob.blobstore.functions.ListOptionsToListBlobsOptions;
import org.jclouds.azureblob.domain.ContainerProperties; import org.jclouds.azureblob.domain.ContainerProperties;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.options.ListBlobsOptions; import org.jclouds.azureblob.options.ListBlobsOptions;
import org.jclouds.azure.storage.domain.BoundedSet;
import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata; 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.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseBlobStore; import org.jclouds.blobstore.internal.BaseBlobStore;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.ListContainerOptions; import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
@ -236,4 +238,11 @@ public class AzureBlobStore extends BaseBlobStore {
throw new UnsupportedOperationException("please use deleteContainer"); 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; 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.AzureBlobAsyncClient;
import org.jclouds.azureblob.AzureBlobClient; import org.jclouds.azureblob.AzureBlobClient;
import org.jclouds.azureblob.blobstore.AzureAsyncBlobStore; import org.jclouds.azureblob.blobstore.AzureAsyncBlobStore;
import org.jclouds.azureblob.blobstore.AzureBlobRequestSigner; import org.jclouds.azureblob.blobstore.AzureBlobRequestSigner;
import org.jclouds.azureblob.blobstore.AzureBlobStore; import org.jclouds.azureblob.blobstore.AzureBlobStore;
import org.jclouds.azureblob.blobstore.strategy.FindMD5InBlobProperties; import org.jclouds.azureblob.blobstore.strategy.FindMD5InBlobProperties;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.blobstore.AsyncBlobStore; import org.jclouds.blobstore.AsyncBlobStore;
import org.jclouds.blobstore.BlobRequestSigner; import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
@ -35,7 +41,10 @@ import org.jclouds.blobstore.internal.BlobStoreContextImpl;
import org.jclouds.blobstore.strategy.ContainsValueInListStrategy; import org.jclouds.blobstore.strategy.ContainsValueInListStrategy;
import org.jclouds.location.config.JustProviderLocationModule; 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.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Scopes; import com.google.inject.Scopes;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
@ -59,4 +68,19 @@ public class AzureBlobStoreContextModule extends AbstractModule {
bind(BlobRequestSigner.class).to(AzureBlobRequestSigner.class); 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()); HttpUtils.copy(from.getContentMetadata(), to.getContentMetadata());
to.setETag(from.getETag()); to.setETag(from.getETag());
to.setName(from.getName()); to.setName(from.getName());
to.setUrl(from.getUri());
to.setLastModified(from.getLastModified()); to.setLastModified(from.getLastModified());
if (from.getUserMetadata() != null) { if (from.getUserMetadata() != null) {
for (Entry<String, String> entry : from.getUserMetadata().entrySet()) 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 static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.azureblob.domain.BlobProperties; import org.jclouds.azureblob.domain.BlobProperties;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.blobstore.domain.MutableBlobMetadata; import org.jclouds.blobstore.domain.MutableBlobMetadata;
import org.jclouds.blobstore.domain.StorageType; import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl; import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
@ -39,10 +42,13 @@ import com.google.common.base.Function;
@Singleton @Singleton
public class BlobPropertiesToBlobMetadata implements Function<BlobProperties, MutableBlobMetadata> { public class BlobPropertiesToBlobMetadata implements Function<BlobProperties, MutableBlobMetadata> {
private final IfDirectoryReturnNameStrategy ifDirectoryReturnName; private final IfDirectoryReturnNameStrategy ifDirectoryReturnName;
private final Map<String, PublicAccess> containerAcls;
@Inject @Inject
public BlobPropertiesToBlobMetadata(IfDirectoryReturnNameStrategy ifDirectoryReturnName) { public BlobPropertiesToBlobMetadata(IfDirectoryReturnNameStrategy ifDirectoryReturnName,
Map<String, PublicAccess> containerAcls) {
this.ifDirectoryReturnName = checkNotNull(ifDirectoryReturnName, "ifDirectoryReturnName"); this.ifDirectoryReturnName = checkNotNull(ifDirectoryReturnName, "ifDirectoryReturnName");
this.containerAcls = checkNotNull(containerAcls, "containerAcls");
} }
public MutableBlobMetadata apply(BlobProperties from) { public MutableBlobMetadata apply(BlobProperties from) {
@ -54,6 +60,15 @@ public class BlobPropertiesToBlobMetadata implements Function<BlobProperties, Mu
to.setETag(from.getETag()); to.setETag(from.getETag());
to.setLastModified(from.getLastModified()); to.setLastModified(from.getLastModified());
to.setName(from.getName()); 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); String directoryName = ifDirectoryReturnName.execute(to);
if (directoryName != null) { if (directoryName != null) {
to.setName(directoryName); to.setName(directoryName);

View File

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

View File

@ -44,7 +44,11 @@ public interface MutableBlobProperties extends BlobProperties {
* @see ListableContainerProperties#getName * @see ListableContainerProperties#getName
*/ */
void setName(String name); void setName(String name);
/**
* @see ListableContainerProperties#getContainer
*/
void setContainer(String container);
/** /**
* @see ListableContainerProperties#getLastModified * @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 static final long serialVersionUID = -4648755473986695062L;
private final BlobType type; private final BlobType type;
private final String name; private final String name;
private final String container;
private final URI url; private final URI url;
private final Date lastModified; private final Date lastModified;
private final String eTag; private final String eTag;
@ -54,12 +55,13 @@ public class BlobPropertiesImpl implements Serializable, BlobProperties {
private final LeaseStatus leaseStatus; private final LeaseStatus leaseStatus;
private final BaseImmutableContentMetadata contentMetadata; private final BaseImmutableContentMetadata contentMetadata;
public BlobPropertiesImpl(BlobType type, String name, URI url, Date lastModified, String eTag, long size, public BlobPropertiesImpl(BlobType type, String name, String container, URI url, Date lastModified, String eTag,
String contentType, @Nullable byte[] contentMD5, @Nullable String contentMetadata, long size, String contentType, @Nullable byte[] contentMD5, @Nullable String contentMetadata,
@Nullable String contentLanguage, LeaseStatus leaseStatus, Map<String, String> metadata) { @Nullable String contentLanguage, LeaseStatus leaseStatus, Map<String, String> metadata) {
this.type = checkNotNull(type, "type"); this.type = checkNotNull(type, "type");
this.leaseStatus = checkNotNull(leaseStatus, "leaseStatus"); this.leaseStatus = checkNotNull(leaseStatus, "leaseStatus");
this.name = checkNotNull(name, "name"); this.name = checkNotNull(name, "name");
this.container = checkNotNull(container, "container");
this.url = checkNotNull(url, "url"); this.url = checkNotNull(url, "url");
this.lastModified = checkNotNull(lastModified, "lastModified"); this.lastModified = checkNotNull(lastModified, "lastModified");
this.eTag = checkNotNull(eTag, "eTag"); this.eTag = checkNotNull(eTag, "eTag");
@ -84,6 +86,14 @@ public class BlobPropertiesImpl implements Serializable, BlobProperties {
return name; return name;
} }
/**
*{@inheritDoc}
*/
@Override
public String getContainer() {
return container;
}
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@ -144,13 +154,6 @@ public class BlobPropertiesImpl implements Serializable, BlobProperties {
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; 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()); result = prime * result + ((url == null) ? 0 : url.hashCode());
return result; return result;
} }
@ -164,41 +167,6 @@ public class BlobPropertiesImpl implements Serializable, BlobProperties {
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
BlobPropertiesImpl other = (BlobPropertiesImpl) obj; 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 (url == null) {
if (other.url != null) if (other.url != null)
return false; return false;
@ -209,8 +177,9 @@ public class BlobPropertiesImpl implements Serializable, BlobProperties {
@Override @Override
public String toString() { public String toString() {
return "[name=" + name + ", type=" + type + ", contentMetadata=" + contentMetadata + ", eTag=" + eTag return String
+ ", lastModified=" + lastModified + "]"; .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 LeaseStatus leaseStatus = LeaseStatus.UNLOCKED;
private String name; private String name;
private String container;
private URI url; private URI url;
private Date lastModified; private Date lastModified;
private String eTag; private String eTag;
@ -61,12 +62,19 @@ public class MutableBlobPropertiesImpl implements Serializable, MutableBlobPrope
public MutableBlobPropertiesImpl(BlobProperties from) { public MutableBlobPropertiesImpl(BlobProperties from) {
this.contentMetadata = new BaseMutableContentMetadata(); 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); HttpUtils.copy(from.getContentMetadata(), this.contentMetadata);
} }
/** /**
*{@inheritDoc} *{@inheritDoc}
*/ */
@Override
public BlobType getType() { public BlobType getType() {
return type; return type;
} }
@ -161,12 +169,6 @@ public class MutableBlobPropertiesImpl implements Serializable, MutableBlobPrope
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; 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()); result = prime * result + ((url == null) ? 0 : url.hashCode());
return result; return result;
} }
@ -180,36 +182,6 @@ public class MutableBlobPropertiesImpl implements Serializable, MutableBlobPrope
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
MutableBlobPropertiesImpl other = (MutableBlobPropertiesImpl) obj; 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 (url == null) {
if (other.url != null) if (other.url != null)
return false; return false;
@ -220,7 +192,10 @@ public class MutableBlobPropertiesImpl implements Serializable, MutableBlobPrope
@Override @Override
public String toString() { 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; 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; package org.jclouds.azureblob.functions;
import static com.google.common.base.Preconditions.checkArgument;
import javax.inject.Inject; import javax.inject.Inject;
import org.jclouds.azureblob.blobstore.functions.BlobMetadataToBlobProperties; 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.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -42,6 +45,7 @@ public class ParseBlobPropertiesFromHeaders implements Function<HttpResponse, Mu
InvocationContext<ParseBlobPropertiesFromHeaders> { InvocationContext<ParseBlobPropertiesFromHeaders> {
private final ParseSystemAndUserMetadataFromHeaders blobMetadataParser; private final ParseSystemAndUserMetadataFromHeaders blobMetadataParser;
private final BlobMetadataToBlobProperties blobToBlobProperties; private final BlobMetadataToBlobProperties blobToBlobProperties;
private String container;
@Inject @Inject
public ParseBlobPropertiesFromHeaders(ParseSystemAndUserMetadataFromHeaders blobMetadataParser, public ParseBlobPropertiesFromHeaders(ParseSystemAndUserMetadataFromHeaders blobMetadataParser,
@ -56,13 +60,20 @@ public class ParseBlobPropertiesFromHeaders implements Function<HttpResponse, Mu
public MutableBlobProperties apply(HttpResponse from) { public MutableBlobProperties apply(HttpResponse from) {
BlobMetadata base = blobMetadataParser.apply(from); BlobMetadata base = blobMetadataParser.apply(from);
MutableBlobProperties to = blobToBlobProperties.apply(base); MutableBlobProperties to = blobToBlobProperties.apply(base);
to.setContainer(container);
return to; return to;
} }
@Override @Override
public ParseBlobPropertiesFromHeaders setContext(HttpRequest request) { public ParseBlobPropertiesFromHeaders setContext(HttpRequest request) {
checkArgument(request instanceof GeneratedHttpRequest<?>, "note this handler requires a GeneratedHttpRequest");
blobMetadataParser.setContext(request); 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; package org.jclouds.azureblob.options;
import org.jclouds.azure.storage.options.CreateOptions; import org.jclouds.azure.storage.options.CreateOptions;
import org.jclouds.azureblob.domain.PublicAccess;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
@ -34,7 +35,7 @@ import com.google.common.collect.Multimap;
* import org.jclouds.azureblob.AzureBlobClient; * import org.jclouds.azureblob.AzureBlobClient;
* <p/> * <p/>
* AzureBlobClient connection = // get connection * AzureBlobClient connection = // get connection
* boolean createdWithPublicAcl = connection.createContainer("containerName", withPublicAcl()); * boolean createdWithPublicAccess = connection.createContainer("containerName", withPublicAccess(PublicAccess.BLOB));
* <code> * * <code> *
* *
* @see <a href="http://msdn.microsoft.com/en-us/library/dd179466.aspx" /> * @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 * Indicates whether a container may be accessed publicly
*/ */
public CreateContainerOptions withPublicAcl() { public CreateContainerOptions withPublicAccess(PublicAccess access) {
this.headers.put("x-ms-prop-publicaccess", "true"); if (access != PublicAccess.PRIVATE)
this.headers.put("x-ms-blob-public-access", access.name().toLowerCase());
return this; return this;
} }
public static class Builder { public static class Builder {
/** /**
* @see CreateContainerOptions#withPublicAcl() * @see CreateContainerOptions#withPublicAccess
*/ */
public static CreateContainerOptions withPublicAcl() { public static CreateContainerOptions withPublicAccess(PublicAccess access) {
CreateContainerOptions options = new CreateContainerOptions(); 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")) { } else if (qName.equals("LeaseStatus")) {
currentLeaseStatus = LeaseStatus.fromValue(currentText.toString().trim()); currentLeaseStatus = LeaseStatus.fromValue(currentText.toString().trim());
} else if (qName.equals("Blob")) { } else if (qName.equals("Blob")) {
BlobProperties md = new BlobPropertiesImpl(currentBlobType, currentName, currentUrl, currentLastModified, BlobProperties md = new BlobPropertiesImpl(currentBlobType, currentName, containerUrl.getPath().replace("/",
currentETag, currentSize, currentContentType, currentContentMD5, currentContentEncoding, ""), currentUrl, currentLastModified, currentETag, currentSize, currentContentType,
currentContentLanguage, currentLeaseStatus, currentMetadata); currentContentMD5, currentContentEncoding, currentContentLanguage, currentLeaseStatus,
currentMetadata);
blobMetadata.add(md); blobMetadata.add(md);
currentBlobType = null; currentBlobType = null;
currentName = null; currentName = null;

View File

@ -19,8 +19,8 @@
package org.jclouds.azureblob; 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.azure.storage.options.ListOptions.Builder.maxResults;
import static org.jclouds.azureblob.options.CreateContainerOptions.Builder.withPublicAccess;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
@ -28,15 +28,17 @@ import java.lang.reflect.Method;
import java.util.Map; import java.util.Map;
import java.util.Properties; 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.ParseBlobFromHeadersAndHttpContent;
import org.jclouds.azureblob.functions.ParseContainerPropertiesFromHeaders; import org.jclouds.azureblob.functions.ParseContainerPropertiesFromHeaders;
import org.jclouds.azureblob.functions.ParsePublicAccessHeader;
import org.jclouds.azureblob.functions.ReturnFalseIfContainerAlreadyExists; import org.jclouds.azureblob.functions.ReturnFalseIfContainerAlreadyExists;
import org.jclouds.azureblob.options.CreateContainerOptions; import org.jclouds.azureblob.options.CreateContainerOptions;
import org.jclouds.azureblob.options.ListBlobsOptions; import org.jclouds.azureblob.options.ListBlobsOptions;
import org.jclouds.azureblob.xml.AccountNameEnumerationResultsHandler; import org.jclouds.azureblob.xml.AccountNameEnumerationResultsHandler;
import org.jclouds.azureblob.xml.ContainerNameEnumerationResultsHandler; 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.ReturnNullOnContainerNotFound;
import org.jclouds.blobstore.functions.ReturnNullOnKeyNotFound; import org.jclouds.blobstore.functions.ReturnNullOnKeyNotFound;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
@ -125,13 +127,13 @@ public class AzureBlobAsyncClientTest extends RestClientTest<AzureBlobAsyncClien
public void testCreateContainerOptions() throws SecurityException, NoSuchMethodException, IOException { public void testCreateContainerOptions() throws SecurityException, NoSuchMethodException, IOException {
Method method = AzureBlobAsyncClient.class.getMethod("createContainer", String.class, Method method = AzureBlobAsyncClient.class.getMethod("createContainer", String.class,
CreateContainerOptions[].class); CreateContainerOptions[].class);
HttpRequest request = processor.createRequest(method, "container", withPublicAcl().withMetadata( HttpRequest request = processor.createRequest(method, "container", withPublicAccess(PublicAccess.BLOB)
ImmutableMultimap.of("foo", "bar"))); .withMetadata(ImmutableMultimap.of("foo", "bar")));
assertRequestLineEquals(request, assertRequestLineEquals(request,
"PUT https://identity.blob.core.windows.net/container?restype=container HTTP/1.1"); "PUT https://identity.blob.core.windows.net/container?restype=container HTTP/1.1");
assertNonPayloadHeadersEqual(request, 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); assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ReturnTrueIf2xx.class); assertResponseParserClassEquals(method, request, ReturnTrueIf2xx.class);
@ -168,12 +170,12 @@ public class AzureBlobAsyncClientTest extends RestClientTest<AzureBlobAsyncClien
public void testCreateRootContainerOptions() throws SecurityException, NoSuchMethodException, IOException { public void testCreateRootContainerOptions() throws SecurityException, NoSuchMethodException, IOException {
Method method = AzureBlobAsyncClient.class.getMethod("createRootContainer", CreateContainerOptions[].class); 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"))); ImmutableMultimap.of("foo", "bar")));
assertRequestLineEquals(request, "PUT https://identity.blob.core.windows.net/$root?restype=container HTTP/1.1"); assertRequestLineEquals(request, "PUT https://identity.blob.core.windows.net/$root?restype=container HTTP/1.1");
assertNonPayloadHeadersEqual(request, 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); assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ReturnTrueIf2xx.class); assertResponseParserClassEquals(method, request, ReturnTrueIf2xx.class);
@ -223,6 +225,20 @@ public class AzureBlobAsyncClientTest extends RestClientTest<AzureBlobAsyncClien
assertExceptionParserClassEquals(method, ReturnNullOnContainerNotFound.class); 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 { public void testSetResourceMetadata() throws SecurityException, NoSuchMethodException, IOException {
Method method = AzureBlobAsyncClient.class.getMethod("setResourceMetadata", String.class, Map.class); Method method = AzureBlobAsyncClient.class.getMethod("setResourceMetadata", String.class, Map.class);
HttpRequest request = processor.createRequest(method, 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 com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.azureblob.options.CreateContainerOptions.Builder.withMetadata; 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.jclouds.azure.storage.options.ListOptions.Builder.includeMetadata;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue; 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.BlobProperties;
import org.jclouds.azureblob.domain.ContainerProperties; import org.jclouds.azureblob.domain.ContainerProperties;
import org.jclouds.azureblob.domain.ListBlobsResponse; import org.jclouds.azureblob.domain.ListBlobsResponse;
import org.jclouds.azureblob.domain.PublicAccess;
import org.jclouds.azureblob.options.ListBlobsOptions; import org.jclouds.azureblob.options.ListBlobsOptions;
import org.jclouds.azure.storage.domain.BoundedSet; import org.jclouds.azure.storage.domain.BoundedSet;
import org.jclouds.azure.storage.options.ListOptions; import org.jclouds.azure.storage.options.ListOptions;
@ -151,7 +152,7 @@ public class AzureBlobClientLiveTest {
while (!created) { while (!created) {
publicContainer = containerPrefix + new SecureRandom().nextInt(); publicContainer = containerPrefix + new SecureRandom().nextInt();
try { try {
created = client.createContainer(publicContainer, withPublicAcl()); created = client.createContainer(publicContainer, withPublicAccess(PublicAccess.BLOB));
} catch (UndeclaredThrowableException e) { } catch (UndeclaredThrowableException e) {
HttpResponseException htpe = (HttpResponseException) e.getCause().getCause(); HttpResponseException htpe = (HttpResponseException) e.getCause().getCause();
if (htpe.getResponse().getStatusCode() == 409) if (htpe.getResponse().getStatusCode() == 409)

View File

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

View File

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