JCLOUDS-423 - Adds support for Rackspace Cloud Files API - Added support for CloudFilesApi/CDNApi - Added mock/live tests - Refactored listFirstPage() and listAt() API methods to list() and listWithOptions(…) - General Swift API cleanup: docs and tests - Added support for Internal URL - Updated JavaDocs and domain objects. - Added support for Cloud Files US
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/CopyObjectException.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/CopyObjectException.java
index 9258662..a958b66 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/CopyObjectException.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/CopyObjectException.java
@@ -22,11 +22,11 @@
/**
* Thrown when an object cannot be copied.
- *
- * @see {@link SwiftErrorHandler#handleError(HttpCommand, HttpResponse)}
*
* @author Everett Toews
* @author Jeremy Daggett
+ *
+ * @see {@link SwiftErrorHandler#handleError(HttpCommand, HttpResponse)}
*/
public class CopyObjectException extends ResourceNotFoundException {
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApi.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApi.java
index 57ebc9c..3e48b2c 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApi.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApi.java
@@ -36,10 +36,13 @@
import com.google.inject.Provides;
/**
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content">api
- * doc</a>
+ * Provides access to the OpenStack Object Storage (Swift) API.
+ * <p/>
+ * OpenStack Object Storage is an object-based storage system that stores content and metadata
+ * as objects. You create, modify, and get objects and metadata using this API.
+ *
* @author Adrian Cole
+ * @author Jeremy Daggett
* @author Zack Shoylev
*/
public interface SwiftApi extends Closeable {
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApiMetadata.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApiMetadata.java
index 7b25ae3..b7957ce 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApiMetadata.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/SwiftApiMetadata.java
@@ -23,6 +23,7 @@
import java.net.URI;
import java.util.Properties;
+import org.jclouds.apis.ApiMetadata;
import org.jclouds.openstack.keystone.v2_0.config.AuthenticationApiModule;
import org.jclouds.openstack.keystone.v2_0.config.CredentialTypes;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule;
@@ -33,16 +34,18 @@
import org.jclouds.openstack.swift.v1.config.SwiftHttpApiModule;
import org.jclouds.openstack.swift.v1.config.SwiftTypeAdapters;
import org.jclouds.openstack.v2_0.ServiceType;
+import org.jclouds.providers.ProviderMetadata;
import org.jclouds.rest.internal.BaseHttpApiMetadata;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
/**
- * Implementation of {@link ApiMetadata} for Swift 1.0 API
+ * Implementation of {@link ApiMetadata} for the Swift API.
*
* @author Adrian Cole
* @author Zack Shoylev
+ * @author Jeremy Daggett
*/
public class SwiftApiMetadata extends BaseHttpApiMetadata<SwiftApi> {
@@ -74,8 +77,8 @@
.identityName("${tenantName}:${userName} or ${userName}, if your keystone supports a default tenant")
.credentialName("${password}")
.documentation(URI.create("http://docs.openstack.org/api/openstack-object-storage/1.0/content/ch_object-storage-dev-overview.html"))
- .version("1.0")
- .endpointName("KeyStone base url ending in /v2.0/")
+ .version("1")
+ .endpointName("Keystone base url ending in /v2.0/")
.defaultEndpoint("http://localhost:5000/v2.0/")
.defaultProperties(SwiftApiMetadata.defaultProperties())
.view(typeToken(RegionScopedBlobStoreContext.class))
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/TemporaryUrlSigner.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/TemporaryUrlSigner.java
index 7a3cf8b..c6d6030 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/TemporaryUrlSigner.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/TemporaryUrlSigner.java
@@ -35,10 +35,6 @@
/**
* Use this utility to create temporary urls.
- *
- * @see <a
- * href="http://docs.openstack.org/trunk/config-reference/content/object-storage-tempurl.html">Temporary
- * URL Documentation</a>
*/
public class TemporaryUrlSigner {
@@ -82,12 +78,12 @@
@Override
public String get() {
- return api.get().temporaryUrlKey().orNull();
+ return api.get().getTemporaryUrlKey().orNull();
}
@Override
public String toString() {
- return format("get().temporaryUrlKey() using %s", api);
+ return format("get().getTemporaryUrlKey() using %s", api);
}
}
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/binders/BindMetadataToHeaders.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/binders/BindMetadataToHeaders.java
index 8af9f9f..4dabc68 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/binders/BindMetadataToHeaders.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/binders/BindMetadataToHeaders.java
@@ -16,6 +16,10 @@
*/
package org.jclouds.openstack.swift.v1.binders;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_METADATA_PREFIX;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_METADATA_PREFIX;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.OBJECT_METADATA_PREFIX;
+
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -48,45 +52,42 @@
* HTTP response headers keys are known to be case-insensitive, but this
* practice of mixing up case will prevent metadata keys such as those in
* Turkish from working.
- *
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/create-update-account-metadata.html">documentation</a>
*/
public class BindMetadataToHeaders implements Binder {
public static class BindAccountMetadataToHeaders extends BindMetadataToHeaders {
BindAccountMetadataToHeaders() {
- super("x-account-meta-");
+ super(ACCOUNT_METADATA_PREFIX);
}
}
public static class BindRemoveAccountMetadataToHeaders extends BindMetadataToHeaders.ForRemoval {
BindRemoveAccountMetadataToHeaders() {
- super("x-account-meta-");
+ super(ACCOUNT_METADATA_PREFIX);
}
}
public static class BindContainerMetadataToHeaders extends BindMetadataToHeaders {
BindContainerMetadataToHeaders() {
- super("x-container-meta-");
+ super(CONTAINER_METADATA_PREFIX);
}
}
public static class BindRemoveContainerMetadataToHeaders extends BindMetadataToHeaders.ForRemoval {
BindRemoveContainerMetadataToHeaders() {
- super("x-container-meta-");
+ super(CONTAINER_METADATA_PREFIX);
}
}
public static class BindObjectMetadataToHeaders extends BindMetadataToHeaders {
BindObjectMetadataToHeaders() {
- super("x-object-meta-");
+ super(OBJECT_METADATA_PREFIX);
}
}
public static class BindRemoveObjectMetadataToHeaders extends BindMetadataToHeaders.ForRemoval {
BindRemoveObjectMetadataToHeaders() {
- super("x-object-meta-");
+ super(OBJECT_METADATA_PREFIX);
}
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedSwiftBlobStore.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedSwiftBlobStore.java
index 5aa926f..480034a 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedSwiftBlobStore.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedSwiftBlobStore.java
@@ -110,7 +110,7 @@
@Override
public PageSet<? extends StorageMetadata> list() {
// TODO: there may eventually be >10k containers..
- FluentIterable<StorageMetadata> containers = api.containerApiInRegion(region.getId()).listFirstPage()
+ FluentIterable<StorageMetadata> containers = api.containerApiInRegion(region.getId()).list()
.transform(toResourceMetadata);
return new PageSetImpl<StorageMetadata>(containers, null);
}
@@ -153,7 +153,7 @@
containerCache.put(container, Optional.<Container> absent());
return new PageSetImpl<StorageMetadata>(ImmutableList.<StorageMetadata> of(), null);
} else {
- containerCache.put(container, Optional.of(objects.container()));
+ containerCache.put(container, Optional.of(objects.getContainer()));
List<? extends StorageMetadata> list = transform(objects, toBlobMetadata(container));
int limit = Optional.fromNullable(options.getMaxResults()).or(10000);
String marker = list.size() == limit ? list.get(limit - 1).getName() : null;
@@ -214,8 +214,8 @@
return null;
}
Blob blob = new BlobImpl(toBlobMetadata(container).apply(object));
- blob.setPayload(object.payload());
- blob.setAllHeaders(object.headers());
+ blob.setPayload(object.getPayload());
+ blob.setAllHeaders(object.getHeaders());
return blob;
}
@@ -236,13 +236,13 @@
@Override
public boolean directoryExists(String containerName, String directory) {
- return api.objectApiInRegionForContainer(region.getId(), containerName) //
+ return api.objectApiInRegionForContainer(region.getId(), containerName)
.head(directory) != null;
}
@Override
public void createDirectory(String containerName, String directory) {
- api.objectApiInRegionForContainer(region.getId(), containerName) //
+ api.objectApiInRegionForContainer(region.getId(), containerName)
.replace(directory, directoryPayload, ImmutableMap.<String, String> of());
}
@@ -261,7 +261,7 @@
public long countBlobs(String containerName) {
Container container = api.containerApiInRegion(region.getId()).get(containerName);
// undefined if container doesn't exist, so default to zero
- return container != null ? container.objectCount() : 0;
+ return container != null ? container.getObjectCount() : 0;
}
@Override
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/functions/ToBlobMetadata.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/functions/ToBlobMetadata.java
index eda42aa..5a0ee17 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/functions/ToBlobMetadata.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/functions/ToBlobMetadata.java
@@ -43,17 +43,17 @@
if (from == null)
return null;
MutableBlobMetadata to = new MutableBlobMetadataImpl();
- to.setContainer(container.name());
- if (container.anybodyRead().isPresent()) {
- to.setPublicUri(from.uri());
+ to.setContainer(container.getName());
+ if (container.getAnybodyRead().isPresent()) {
+ to.setPublicUri(from.getUri());
}
- to.setUri(from.uri());
- to.setETag(from.etag());
- to.setName(from.name());
- to.setLastModified(from.lastModified());
- to.setContentMetadata(from.payload().getContentMetadata());
- to.getContentMetadata().setContentMD5(base16().lowerCase().decode(from.etag()));
- to.setUserMetadata(from.metadata());
+ to.setUri(from.getUri());
+ to.setETag(from.getEtag());
+ to.setName(from.getName());
+ to.setLastModified(from.getLastModified());
+ to.setContentMetadata(from.getPayload().getContentMetadata());
+ to.getContentMetadata().setContentMD5(base16().lowerCase().decode(from.getEtag()));
+ to.setUserMetadata(from.getMetadata());
String directoryName = ifDirectoryReturnName.execute(to);
if (directoryName != null) {
to.setName(directoryName);
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/functions/ToResourceMetadata.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/functions/ToResourceMetadata.java
index 0384388..bc5e186 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/functions/ToResourceMetadata.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/functions/ToResourceMetadata.java
@@ -35,10 +35,10 @@
@Override
public StorageMetadata apply(Container from) {
MutableStorageMetadata to = new MutableStorageMetadataImpl();
- to.setName(from.name());
+ to.setName(from.getName());
to.setLocation(region);
to.setType(StorageType.CONTAINER);
- to.setUserMetadata(from.metadata());
+ to.setUserMetadata(from.getMetadata());
return to;
}
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/BaseSwiftHttpApiModule.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/BaseSwiftHttpApiModule.java
new file mode 100644
index 0000000..d6d8b6a
--- /dev/null
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/BaseSwiftHttpApiModule.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.openstack.swift.v1.config;
+
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.annotation.ClientError;
+import org.jclouds.http.annotation.Redirection;
+import org.jclouds.http.annotation.ServerError;
+import org.jclouds.openstack.swift.v1.SwiftApi;
+import org.jclouds.openstack.swift.v1.handlers.SwiftErrorHandler;
+import org.jclouds.rest.ConfiguresHttpApi;
+import org.jclouds.rest.config.HttpApiModule;
+
+@ConfiguresHttpApi
+public abstract class BaseSwiftHttpApiModule<A extends SwiftApi> extends HttpApiModule<A> {
+
+ protected BaseSwiftHttpApiModule(Class<A> api) {
+ super(api);
+ }
+
+ @Override
+ protected void configure() {
+ super.configure();
+ }
+
+ @Override
+ protected void bindErrorHandlers() {
+ bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(SwiftErrorHandler.class);
+ bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(SwiftErrorHandler.class);
+ bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(SwiftErrorHandler.class);
+ }
+}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftHttpApiModule.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftHttpApiModule.java
index 37e4b2d..cb93760 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftHttpApiModule.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftHttpApiModule.java
@@ -15,25 +15,18 @@
* limitations under the License.
*/
package org.jclouds.openstack.swift.v1.config;
-import org.jclouds.http.HttpErrorHandler;
-import org.jclouds.http.annotation.ClientError;
-import org.jclouds.http.annotation.Redirection;
-import org.jclouds.http.annotation.ServerError;
import org.jclouds.openstack.swift.v1.SwiftApi;
-import org.jclouds.openstack.swift.v1.handlers.SwiftErrorHandler;
import org.jclouds.rest.ConfiguresHttpApi;
-import org.jclouds.rest.config.HttpApiModule;
@ConfiguresHttpApi
-public class SwiftHttpApiModule extends HttpApiModule<SwiftApi> {
-
+public class SwiftHttpApiModule extends BaseSwiftHttpApiModule<SwiftApi> {
+
public SwiftHttpApiModule() {
- }
+ super(SwiftApi.class);
+ }
@Override
- protected void bindErrorHandlers() {
- bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(SwiftErrorHandler.class);
- bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(SwiftErrorHandler.class);
- bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(SwiftErrorHandler.class);
+ protected void configure() {
+ super.configure();
}
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdapters.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdapters.java
index f556142..4eafdb6 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdapters.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdapters.java
@@ -43,8 +43,8 @@
@Provides
public Map<Type, Object> provideCustomAdapterBindings() {
- return ImmutableMap.<Type, Object> builder() //
- .put(ExtractArchiveResponse.class, new ExtractArchiveResponseAdapter()) //
+ return ImmutableMap.<Type, Object> builder()
+ .put(ExtractArchiveResponse.class, new ExtractArchiveResponseAdapter())
.put(BulkDeleteResponse.class, new BulkDeleteResponseAdapter()).build();
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Account.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Account.java
index a3857f0..c8e760a 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Account.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Account.java
@@ -23,15 +23,19 @@
import java.util.Map;
import java.util.Map.Entry;
+import org.jclouds.openstack.swift.v1.features.AccountApi;
+
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
/**
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/retrieve-account-metadata.html">api
- * doc</a>
+ * Represents an Account in OpenStack Object Storage.
+ *
+ * @author Jeremy Daggett
+ *
+ * @see AccountApi
*/
public class Account {
@@ -48,27 +52,42 @@
this.metadata = checkNotNull(metadata, "metadata");
}
- public long containerCount() {
+ /**
+ * @return The count of containers for this account.
+ */
+ public long getContainerCount() {
return containerCount;
}
- public long objectCount() {
+ /**
+ * @return The count of objects for this account.
+ */
+ public long getObjectCount() {
return objectCount;
}
- public long bytesUsed() {
+ /**
+ * @return The number of bytes used by this account.
+ */
+ public long getBytesUsed() {
return bytesUsed;
}
- public Optional<String> temporaryUrlKey() {
+ /**
+ * @return The {@link Optional<String>} temporary URL key for this account.
+ */
+ public Optional<String> getTemporaryUrlKey() {
return Optional.fromNullable(metadata.get("temp-url-key"));
}
/**
+ * <h3>NOTE</h3>
* In current swift implementations, headers keys are lower-cased. This means
* characters such as turkish will probably not work out well.
+ *
+ * @return a {@code Map<String, String>} containing the account metadata.
*/
- public Map<String, String> metadata() {
+ public Map<String, String> getMetadata() {
return metadata;
}
@@ -79,10 +98,10 @@
}
if (object instanceof Account) {
Account that = Account.class.cast(object);
- return equal(containerCount(), that.containerCount()) //
- && equal(objectCount(), that.objectCount()) //
- && equal(bytesUsed(), that.bytesUsed()) //
- && equal(metadata(), that.metadata());
+ return equal(getContainerCount(), that.getContainerCount())
+ && equal(getObjectCount(), that.getObjectCount())
+ && equal(getBytesUsed(), that.getBytesUsed())
+ && equal(getMetadata(), that.getMetadata());
} else {
return false;
}
@@ -90,7 +109,7 @@
@Override
public int hashCode() {
- return Objects.hashCode(containerCount(), objectCount(), bytesUsed());
+ return Objects.hashCode(getContainerCount(), getObjectCount(), getBytesUsed(), getMetadata());
}
@Override
@@ -99,11 +118,11 @@
}
protected ToStringHelper string() {
- return toStringHelper("") //
- .add("containerCount", containerCount()) //
- .add("objectCount", objectCount()) //
- .add("bytesUsed", bytesUsed()) //
- .add("metadata", metadata());
+ return toStringHelper("")
+ .add("containerCount", getContainerCount())
+ .add("objectCount", getObjectCount())
+ .add("bytesUsed", getBytesUsed())
+ .add("metadata", getMetadata());
}
public static Builder builder() {
@@ -121,7 +140,9 @@
protected Map<String, String> metadata = ImmutableMap.of();
/**
- * @see Account#containerCount()
+ * @param containerCount the count of containers for this account.
+ *
+ * @see Account#getContainerCount()
*/
public Builder containerCount(long containerCount) {
this.containerCount = containerCount;
@@ -129,7 +150,9 @@
}
/**
- * @see Account#objectCount()
+ * @param objectCount the count of objects for this account.
+ *
+ * @see Account#getObjectCount()
*/
public Builder objectCount(long objectCount) {
this.objectCount = objectCount;
@@ -137,7 +160,9 @@
}
/**
- * @see Account#bytesUsed()
+ * @param bytesUsed the number of bytes used by this account.
+ *
+ * @see Account#getBytesUsed()
*/
public Builder bytesUsed(long bytesUsed) {
this.bytesUsed = bytesUsed;
@@ -145,10 +170,13 @@
}
/**
- * Will lower-case all metadata keys due to a swift implementation
+ * <h3>NOTE</h3>
+ * This method will lower-case all metadata keys due to a Swift implementation
* decision.
*
- * @see Account#metadata()
+ * @param metadata the metadata for this account.
+ *
+ * @see Account#getMetadata()
*/
public Builder metadata(Map<String, String> metadata) {
ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String> builder();
@@ -164,10 +192,10 @@
}
public Builder fromContainer(Account from) {
- return containerCount(from.containerCount())//
- .objectCount(from.objectCount())//
- .bytesUsed(from.bytesUsed()) //
- .metadata(from.metadata());
+ return containerCount(from.getContainerCount())
+ .objectCount(from.getObjectCount())
+ .bytesUsed(from.getBytesUsed())
+ .metadata(from.getMetadata());
}
}
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/BulkDeleteResponse.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/BulkDeleteResponse.java
index c96a66f..1f841e9 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/BulkDeleteResponse.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/BulkDeleteResponse.java
@@ -22,12 +22,16 @@
import java.util.Map;
+import org.jclouds.openstack.swift.v1.features.BulkApi;
+
import com.google.common.base.Objects;
/**
- * @see <a
- * href="http://docs.openstack.org/developer/swift/misc.html#module-swift.common.middleware.bulk">
- * Swift Bulk Middleware</a>
+ * Represents a response from a Bulk Delete request.
+ *
+ * @author Jeremy Daggett
+ *
+ * @see BulkApi
*/
public class BulkDeleteResponse {
public static BulkDeleteResponse create(int deleted, int notFound, Map<String, String> errors) {
@@ -44,18 +48,25 @@
this.errors = checkNotNull(errors, "errors");
}
- /** number of files deleted. */
- public int deleted() {
+ /**
+ * @return The number of files deleted.
+ * */
+ public int getDeleted() {
return deleted;
}
- /** number of files not found. */
- public int notFound() {
+ /**
+ * @return The number of files not found.
+ */
+ public int getNotFound() {
return notFound;
}
- /** For each path that failed to delete, a corresponding error response. */
- public Map<String, String> errors() {
+ /**
+ * @return a {@code Map<String, String>} containing each path that failed
+ * to be deleted and its corresponding error response.
+ */
+ public Map<String, String> getErrors() {
return errors;
}
@@ -66,9 +77,9 @@
}
if (object instanceof BulkDeleteResponse) {
BulkDeleteResponse that = BulkDeleteResponse.class.cast(object);
- return equal(deleted(), that.deleted()) //
- && equal(notFound(), that.notFound()) //
- && equal(errors(), that.errors());
+ return equal(getDeleted(), that.getDeleted())
+ && equal(getNotFound(), that.getNotFound())
+ && equal(getErrors(), that.getErrors());
} else {
return false;
}
@@ -76,14 +87,14 @@
@Override
public int hashCode() {
- return Objects.hashCode(deleted(), notFound(), errors());
+ return Objects.hashCode(getDeleted(), getNotFound(), getErrors());
}
@Override
public String toString() {
- return toStringHelper("") //
- .add("deleted", deleted()) //
- .add("notFound", notFound()) //
- .add("errors", errors()).toString();
+ return toStringHelper("")
+ .add("deleted", getDeleted())
+ .add("notFound", getNotFound())
+ .add("errors", getErrors()).toString();
}
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Container.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Container.java
index e75f710..9b23705 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Container.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Container.java
@@ -24,6 +24,8 @@
import java.util.Map;
import java.util.Map.Entry;
+import org.jclouds.openstack.swift.v1.features.ContainerApi;
+import org.jclouds.openstack.swift.v1.options.CreateContainerOptions;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
@@ -31,9 +33,12 @@
import com.google.common.collect.ImmutableMap;
/**
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/s_listcontainers.html">api
- * doc</a>
+ * Represents a Container in OpenStack Object Storage.
+ *
+ * @author Adrian Cole
+ * @author Jeremy Daggett
+ *
+ * @see ContainerApi
*/
public class Container implements Comparable<Container> {
@@ -53,38 +58,46 @@
this.metadata = metadata == null ? ImmutableMap.<String, String> of() : metadata;
}
- public String name() {
+ /**
+ * @return The name of this container.
+ */
+ public String getName() {
return name;
}
- public long objectCount() {
+ /**
+ * @return The count of objects for this container.
+ */
+ public long getObjectCount() {
return objectCount;
}
- public long bytesUsed() {
+ /**
+ * @return The number of bytes used by this container.
+ */
+ public long getBytesUsed() {
return bytesUsed;
}
/**
- * Absent except in {@link ContainerApi#get(String) GetContainer} commands.
+ * Absent except in {@link ContainerApi#get(String) Get Container} commands.
*
- * When present, designates that the container is publicly readable.
+ * @return true if this container is publicly readable, false otherwise.
*
* @see CreateContainerOptions#anybodyRead()
*/
- public Optional<Boolean> anybodyRead() {
+ public Optional<Boolean> getAnybodyRead() {
return anybodyRead;
}
/**
- * Empty except in {@link ContainerApi#get(String) GetContainer} commands.
- *
- * <h3>Note</h3>
- *
+ * <h3>NOTE</h3>
* In current swift implementations, headers keys are lower-cased. This means
* characters such as turkish will probably not work out well.
+ *
+ * @return a {@code Map<String, String>} containing this container's metadata.
*/
- public Map<String, String> metadata() {
+ public Map<String, String> getMetadata() {
return metadata;
}
@@ -95,10 +108,10 @@
}
if (object instanceof Container) {
final Container that = Container.class.cast(object);
- return equal(name(), that.name()) //
- && equal(objectCount(), that.objectCount()) //
- && equal(bytesUsed(), that.bytesUsed()) //
- && equal(metadata(), that.metadata());
+ return equal(getName(), that.getName())
+ && equal(getObjectCount(), that.getObjectCount())
+ && equal(getBytesUsed(), that.getBytesUsed())
+ && equal(getMetadata(), that.getMetadata());
} else {
return false;
}
@@ -106,7 +119,7 @@
@Override
public int hashCode() {
- return Objects.hashCode(name(), objectCount(), bytesUsed(), anybodyRead(), metadata());
+ return Objects.hashCode(getName(), getObjectCount(), getBytesUsed(), getAnybodyRead(), getMetadata());
}
@Override
@@ -115,12 +128,12 @@
}
protected ToStringHelper string() {
- return toStringHelper("").omitNullValues() //
- .add("name", name()) //
- .add("objectCount", objectCount()) //
- .add("bytesUsed", bytesUsed()) //
- .add("anybodyRead", anybodyRead().orNull()) //
- .add("metadata", metadata());
+ return toStringHelper("").omitNullValues()
+ .add("name", getName())
+ .add("objectCount", getObjectCount())
+ .add("bytesUsed", getBytesUsed())
+ .add("anybodyRead", getAnybodyRead().orNull())
+ .add("metadata", getMetadata());
}
@Override
@@ -129,7 +142,7 @@
return 1;
if (this == that)
return 0;
- return this.name().compareTo(that.name());
+ return this.getName().compareTo(that.getName());
}
public static Builder builder() {
@@ -148,7 +161,7 @@
protected Map<String, String> metadata = ImmutableMap.of();
/**
- * @see Container#name()
+ * @see Container#getName()
*/
public Builder name(String name) {
this.name = checkNotNull(name, "name");
@@ -156,7 +169,7 @@
}
/**
- * @see Container#objectCount()
+ * @see Container#getObjectCount()
*/
public Builder objectCount(long objectCount) {
this.objectCount = objectCount;
@@ -164,7 +177,7 @@
}
/**
- * @see Container#bytesUsed()
+ * @see Container#getBytesUsed()
*/
public Builder bytesUsed(long bytesUsed) {
this.bytesUsed = bytesUsed;
@@ -172,7 +185,7 @@
}
/**
- * @see Container#anybodyRead()
+ * @see Container#getAnybodyRead()
*/
public Builder anybodyRead(Boolean anybodyRead) {
this.anybodyRead = Optional.fromNullable(anybodyRead);
@@ -180,10 +193,10 @@
}
/**
- * Will lower-case all metadata keys due to a swift implementation
- * decision.
+ * <h3>NOTE</h3>
+ * This method will lower-case all metadata keys.
*
- * @see Container#metadata()
+ * @see Container#getMetadata()
*/
public Builder metadata(Map<String, String> metadata) {
ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String> builder();
@@ -199,11 +212,11 @@
}
public Builder fromContainer(Container from) {
- return name(from.name()) //
- .objectCount(from.objectCount()) //
- .bytesUsed(from.bytesUsed()) //
- .anybodyRead(from.anybodyRead().orNull()) //
- .metadata(from.metadata());
+ return name(from.getName())
+ .objectCount(from.getObjectCount())
+ .bytesUsed(from.getBytesUsed())
+ .anybodyRead(from.getAnybodyRead().orNull())
+ .metadata(from.getMetadata());
}
}
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/ExtractArchiveResponse.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/ExtractArchiveResponse.java
index 5644377..e656174 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/ExtractArchiveResponse.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/ExtractArchiveResponse.java
@@ -22,12 +22,16 @@
import java.util.Map;
+import org.jclouds.openstack.swift.v1.features.BulkApi;
+
import com.google.common.base.Objects;
/**
- * @see <a
- * href="http://docs.openstack.org/developer/swift/misc.html#module-swift.common.middleware.bulk">
- * Swift Bulk Middleware</a>
+ * Represents a response from an Extract Archive request.
+ *
+ * @author Jeremy Daggett
+ *
+ * @see BulkApi
*/
public class ExtractArchiveResponse {
public static ExtractArchiveResponse create(int created, Map<String, String> errors) {
@@ -42,13 +46,18 @@
this.errors = checkNotNull(errors, "errors");
}
- /** number of files created. */
- public int created() {
+ /**
+ * @return The number of files created.
+ */
+ public int getCreated() {
return created;
}
- /** For each path that failed to create, a corresponding error response. */
- public Map<String, String> errors() {
+ /**
+ * @return a {@code Map<String, String>} containing each path that failed
+ * to be created and its corresponding error response.
+ */
+ public Map<String, String> getErrors() {
return errors;
}
@@ -59,8 +68,8 @@
}
if (object instanceof ExtractArchiveResponse) {
ExtractArchiveResponse that = ExtractArchiveResponse.class.cast(object);
- return equal(created(), that.created()) //
- && equal(errors(), that.errors());
+ return equal(getCreated(), that.getCreated())
+ && equal(getErrors(), that.getErrors());
} else {
return false;
}
@@ -68,13 +77,13 @@
@Override
public int hashCode() {
- return Objects.hashCode(created(), errors());
+ return Objects.hashCode(getCreated(), getErrors());
}
@Override
public String toString() {
- return toStringHelper("") //
- .add("created", created()) //
- .add("errors", errors()).toString();
+ return toStringHelper("")
+ .add("created", getCreated())
+ .add("errors", getErrors()).toString();
}
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/ObjectList.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/ObjectList.java
index 350e8e1..c7977c1 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/ObjectList.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/ObjectList.java
@@ -20,8 +20,19 @@
import java.util.List;
+import org.jclouds.openstack.swift.v1.features.ObjectApi;
+
import com.google.common.collect.ForwardingList;
+/**
+ * Represents a list of objects in a container.
+ *
+ * @author Jeremy Daggett
+ *
+ * @see Container
+ * @see SwiftObject
+ * @see ObjectApi#list()
+ */
public class ObjectList extends ForwardingList<SwiftObject> {
public static ObjectList create(List<SwiftObject> objects, Container container) {
@@ -36,7 +47,10 @@
this.container = checkNotNull(container, "container");
}
- public Container container() {
+ /**
+ * @return the parent {@link Container} the objects reside in.
+ */
+ public Container getContainer() {
return container;
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Segment.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Segment.java
index 3d24b05..d144c5c 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Segment.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Segment.java
@@ -20,14 +20,17 @@
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
+import org.jclouds.openstack.swift.v1.features.StaticLargeObjectApi;
+
import com.google.common.base.Objects;
/**
- * One piece of a multi-part upload.
+ * Represents a single segment of a multi-part upload.
*
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/static-large-objects.html">api
- * doc</a>
+ * @author Adrian Cole
+ * @author Jeremy Daggett
+ *
+ * @see StaticLargeObjectApi
*/
public class Segment {
@@ -42,22 +45,23 @@
}
/**
- * {@code /container/objectName} which corresponds to the path of
- * {@link SwiftObject#uri()}.
+ * @return The container and object name in the format: {@code <container-name>/<object-name>}
*/
- public String path() {
+ public String getPath() {
return path;
}
/**
- * Corresponds to the {@code ETag} header of the response, and is usually the
- * MD5 checksum of the object
+ * @return The ETag of the content of the segment object.
*/
- public String etag() {
+ public String getEtag() {
return etag;
}
- public long sizeBytes() {
+ /**
+ * @return The size of the segment object.
+ */
+ public long getSizeBytes() {
return size_bytes;
}
@@ -68,9 +72,9 @@
}
if (object instanceof Segment) {
Segment that = Segment.class.cast(object);
- return equal(path(), that.path()) //
- && equal(etag(), that.etag()) //
- && equal(sizeBytes(), that.sizeBytes());
+ return equal(getPath(), that.getPath())
+ && equal(getEtag(), that.getEtag())
+ && equal(getSizeBytes(), that.getSizeBytes());
} else {
return false;
}
@@ -78,15 +82,15 @@
@Override
public int hashCode() {
- return Objects.hashCode(path(), etag(), sizeBytes());
+ return Objects.hashCode(getPath(), getEtag(), getSizeBytes());
}
@Override
public String toString() {
- return toStringHelper("") //
- .add("path", path()) //
- .add("etag", etag()) //
- .add("sizeBytes", sizeBytes()).toString();
+ return toStringHelper("")
+ .add("path", getPath())
+ .add("etag", getEtag())
+ .add("sizeBytes", getSizeBytes()).toString();
}
public static Builder builder() {
@@ -99,7 +103,7 @@
protected long sizeBytes;
/**
- * @see Segment#path()
+ * @see Segment#getPath()
*/
public Builder path(String path) {
this.path = path;
@@ -107,7 +111,7 @@
}
/**
- * @see Segment#etag()
+ * @see Segment#getEtag()
*/
public Builder etag(String etag) {
this.etag = etag;
@@ -115,7 +119,7 @@
}
/**
- * @see Segment#sizeBytes()
+ * @see Segment#getSizeBytes()
*/
public Builder sizeBytes(long sizeBytes) {
this.sizeBytes = sizeBytes;
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/SwiftObject.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/SwiftObject.java
index 923e6c2..953a4f5 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/SwiftObject.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/SwiftObject.java
@@ -26,6 +26,7 @@
import java.util.Map.Entry;
import org.jclouds.io.Payload;
+import org.jclouds.openstack.swift.v1.features.ObjectApi;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
@@ -34,9 +35,12 @@
import com.google.common.collect.Multimap;
/**
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/retrieve-object.html">api
- * doc</a>
+ * Represents an object in OpenStack Object Storage.
+ *
+ * @author Adrian Cole
+ * @author Jeremy Daggett
+ *
+ * @see ObjectApi
*/
public class SwiftObject implements Comparable<SwiftObject> {
@@ -59,52 +63,62 @@
this.payload = checkNotNull(payload, "payload of %s", name);
}
- public String name() {
+ /**
+ * @return The name of this object.
+ */
+ public String getName() {
return name;
}
/**
- * http location of the object, accessible if its container is
- * {@link CreateContainerOptions#publicRead}.
+ * @return The {@link URI} for this object.
*/
- public URI uri() {
+ public URI getUri() {
return uri;
}
/**
- * Corresponds to the {@code ETag} header of the response, and is usually the
- * MD5 checksum of the object
+ * @return The ETag of the content of this object.
*/
- public String etag() {
+ public String getEtag() {
return etag;
}
- public Date lastModified() {
+ /**
+ * @return The {@link Date} that this object was last modified.
+ */
+ public Date getLastModified() {
return lastModified;
}
- public Multimap<String, String> headers() {
+ /**
+ * @return The HTTP headers for this object.
+ */
+ public Multimap<String, String> getHeaders() {
return headers;
}
/**
- * Empty except in {@link ObjectApi#head(String) GetObjectMetadata} or
- * {@link ObjectApi#get(String) GetObject} commands.
- *
- * <h3>Note</h3>
- *
+ * <h3>NOTE</h3>
* In current swift implementations, headers keys are lower-cased. This means
* characters such as turkish will probably not work out well.
+ *
+ * @return a {@code Map<String, String>} containing this object's metadata. The map is empty
+ * except in {@link ObjectApi#head(String) GetObjectMetadata} or
+ * {@link ObjectApi#get(String) GetObject} commands.
*/
- public Map<String, String> metadata() {
+ public Map<String, String> getMetadata() {
return metadata;
}
/**
- * Only has a {@link Payload#getInput()} when retrieved via the
+ * <h3>NOTE</h3>
+ * The object will only have a {@link Payload#getInput()} when retrieved via the
* {@link ObjectApi#get(String) GetObject} command.
+ *
+ * @return The {@link Payload} for this object.
*/
- public Payload payload() {
+ public Payload getPayload() {
return payload;
}
@@ -115,9 +129,9 @@
}
if (object instanceof SwiftObject) {
final SwiftObject that = SwiftObject.class.cast(object);
- return equal(name(), that.name()) //
- && equal(uri(), that.uri()) //
- && equal(etag(), that.etag());
+ return equal(getName(), that.getName())
+ && equal(getUri(), that.getUri())
+ && equal(getEtag(), that.getEtag());
} else {
return false;
}
@@ -125,7 +139,7 @@
@Override
public int hashCode() {
- return Objects.hashCode(name(), uri(), etag());
+ return Objects.hashCode(getName(), getUri(), getEtag());
}
@Override
@@ -134,12 +148,12 @@
}
protected ToStringHelper string() {
- return toStringHelper("") //
- .add("name", name()) //
- .add("uri", uri()) //
- .add("etag", etag()) //
- .add("lastModified", lastModified()) //
- .add("metadata", metadata());
+ return toStringHelper("")
+ .add("name", getName())
+ .add("uri", getUri())
+ .add("etag", getEtag())
+ .add("lastModified", getLastModified())
+ .add("metadata", getMetadata());
}
@Override
@@ -148,7 +162,7 @@
return 1;
if (this == that)
return 0;
- return this.name().compareTo(that.name());
+ return this.getName().compareTo(that.getName());
}
public static Builder builder() {
@@ -169,7 +183,7 @@
protected Map<String, String> metadata = ImmutableMap.of();
/**
- * @see SwiftObject#name()
+ * @see SwiftObject#getName()
*/
public Builder name(String name) {
this.name = checkNotNull(name, "name");
@@ -177,7 +191,7 @@
}
/**
- * @see SwiftObject#uri()
+ * @see SwiftObject#getUri()
*/
public Builder uri(URI uri) {
this.uri = checkNotNull(uri, "uri");
@@ -185,7 +199,7 @@
}
/**
- * @see SwiftObject#etag()
+ * @see SwiftObject#getEtag()
*/
public Builder etag(String etag) {
this.etag = etag;
@@ -193,7 +207,7 @@
}
/**
- * @see SwiftObject#lastModified()
+ * @see SwiftObject#getLastModified()
*/
public Builder lastModified(Date lastModified) {
this.lastModified = lastModified;
@@ -201,13 +215,16 @@
}
/**
- * @see SwiftObject#payload()
+ * @see SwiftObject#getPayload()
*/
public Builder payload(Payload payload) {
this.payload = payload;
return this;
}
+ /**
+ * @see SwiftObject#getHeaders()
+ */
public Builder headers(Multimap<String, String> headers) {
this.headers = headers;
return this;
@@ -217,7 +234,7 @@
* Will lower-case all metadata keys due to a swift implementation
* decision.
*
- * @see SwiftObject#metadata()
+ * @see SwiftObject#getMetadata()
*/
public Builder metadata(Map<String, String> metadata) {
ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String> builder();
@@ -233,13 +250,13 @@
}
public Builder fromObject(SwiftObject from) {
- return name(from.name()) //
- .uri(from.uri()) //
- .etag(from.etag()) //
- .lastModified(from.lastModified()) //
- .headers(from.headers()) //
- .metadata(from.metadata()) //
- .payload(from.payload());
+ return name(from.getName())
+ .uri(from.getUri())
+ .etag(from.getEtag())
+ .lastModified(from.getLastModified())
+ .headers(from.getHeaders())
+ .metadata(from.getMetadata())
+ .payload(from.getPayload());
}
}
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountApi.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountApi.java
index 9736112..57f9ef0 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountApi.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountApi.java
@@ -17,6 +17,7 @@
package org.jclouds.openstack.swift.v1.features;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_TEMPORARY_URL_KEY;
import java.util.Map;
@@ -39,16 +40,15 @@
import org.jclouds.rest.annotations.ResponseParser;
/**
- * Provides access to the Swift Account API.
+ * Provides access to the Swift Account API features.
*
* <p/>
* Account metadata prefixed with {@code X-Account-Meta-} will be converted
* appropriately using a binder/parser.
*
+ * @author Jeremy Daggett
+ *
* @see {@link Account}
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/storage-account-services.html">
- * Storage Account Services API</a>
*/
@RequestFilters(AuthenticateRequest.class)
@Consumes(APPLICATION_JSON)
@@ -57,70 +57,51 @@
/**
* Gets the {@link Account}.
*
- * @return the Account.
- *
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/retrieve-account-metadata.html">
- * Get Account Metadata API</a>
+ * @return The {@link Account} object.
*/
- @Named("GetAccount")
+ @Named("account:get")
@HEAD
@ResponseParser(ParseAccountFromHeaders.class)
@Path("/")
Account get();
/**
- * Creates or updates the Account metadata.
+ * Creates or updates the {@link Account} metadata.
*
- * @param metadata
- * the Account metadata to create or update.
+ * @param metadata the metadata to create or update.
*
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/create-update-account-metadata.html">
- * Create or Update Account Metadata API</a>
- *
- * @return <code>true</code> if the Account Metadata was successfully created
- * or updated, false if not.
+ * @return {@code true} if the metadata was successfully created or updated,
+ * {@code false} if not.
*/
- @Named("UpdateAccountMetadata")
+ @Named("account:updateMetadata")
@POST
@Fallback(FalseOnNotFoundOr404.class)
@Path("/")
boolean updateMetadata(@BinderParam(BindAccountMetadataToHeaders.class) Map<String, String> metadata);
/**
- * Replaces the {@link Account#temporaryUrlKey()}.
+ * Replaces the temporary URL key for the {@link Account}.
*
- * @param metadata
- * the Account metadata to create or update.
+ * @param temporaryUrlKey the temporary URL key to update.
*
- * @see <a
- * href="http://docs.openstack.org/trunk/config-reference/content/object-storage-tempurl.html">
- * Temporary URL Documentation</a>
- *
- * @return <code>true</code> if the Temporary URL Key was successfully created
- * or updated, false if not.
+ * @return {@code true} if the temporary URL key was successfully updated,
+ * {@code false} if not.
*/
- @Named("UpdateAccountMetadata")
+ @Named("account:updateTemporaryUrlKey")
@POST
@Fallback(FalseOnNotFoundOr404.class)
@Path("/")
- boolean updateTemporaryUrlKey(@HeaderParam("X-Account-Meta-Temp-URL-Key") String temporaryUrlKey);
+ boolean updateTemporaryUrlKey(@HeaderParam(ACCOUNT_TEMPORARY_URL_KEY) String temporaryUrlKey);
/**
- * Deletes Account metadata.
+ * Deletes metadata from the {@link Account}.
*
- * @param metadata
- * the Account metadata to delete.
+ * @param metadata the metadata to delete.
*
- * @return <code>true</code> if the Account Metadata was successfully
- * deleted, false if not.
- *
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/delete-account-metadata.html">
- * Delete Account Metadata API</a>
+ * @return {@code true} if the metadata was successfully deleted,
+ * {@code false} if not.
*/
- @Named("DeleteAccountMetadata")
+ @Named("account:deleteMetadata")
@POST
@Fallback(FalseOnNotFoundOr404.class)
@Path("/")
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/BulkApi.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/BulkApi.java
index 60eb851..ba5825e 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/BulkApi.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/BulkApi.java
@@ -46,15 +46,8 @@
/**
* Provides access to the Swift Bulk API.
*
- * <h3>Note</h3>
- *
- * As of the Grizzly release, these operations occur <a
- * href="https://blueprints.launchpad.net/swift/+spec/concurrent-bulk">serially
- * on the backend</a>.
- *
- * @see <a
- * href="http://docs.openstack.org/developer/swift/misc.html#module-swift.common.middleware.bulk">
- * Swift Bulk Middleware</a>
+ * @author Adrian Cole
+ * @author Jeremy Daggett
*/
@RequestFilters(AuthenticateRequest.class)
@Consumes(APPLICATION_JSON)
@@ -64,15 +57,15 @@
* Extracts a tar archive at the path specified as {@code path}.
*
* @param path
- * path to extract under, if not empty string.
+ * the path to extract under.
* @param tar
- * valid tar archive
+ * a valid tar archive.
* @param format
* one of {@code tar}, {@code tar.gz}, or {@code tar.bz2}
*
- * @return {@link BulkDeleteResponse#errors()} are empty on success.
+ * @return {@link BulkDeleteResponse#getErrors()} are empty on success.
*/
- @Named("ExtractArchive")
+ @Named("bulk:extractArchive")
@PUT
@Path("/{path}")
ExtractArchiveResponse extractArchive(@PathParam("path") String path,
@@ -85,9 +78,9 @@
* format of {@code container}, for an empty container, or
* {@code container/object} for an object.
*
- * @return {@link BulkDeleteResponse#errors()} are empty on success.
+ * @return {@link BulkDeleteResponse#getErrors()} are empty on success.
*/
- @Named("BulkDelete")
+ @Named("bulk:delete")
@DELETE
@Path("/")
@QueryParams(keys = "bulk-delete")
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerApi.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerApi.java
index d9438fa..e698e2f 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerApi.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerApi.java
@@ -29,7 +29,6 @@
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
-import javax.ws.rs.QueryParam;
import org.jclouds.Fallbacks.EmptyFluentIterableOnNotFoundOr404;
import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
@@ -42,6 +41,7 @@
import org.jclouds.openstack.swift.v1.functions.FalseOnAccepted;
import org.jclouds.openstack.swift.v1.functions.ParseContainerFromHeaders;
import org.jclouds.openstack.swift.v1.options.CreateContainerOptions;
+import org.jclouds.openstack.swift.v1.options.ListContainerOptions;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.QueryParams;
@@ -51,13 +51,11 @@
import com.google.common.collect.FluentIterable;
/**
- * Storage Container Services
+ * Provides access to the Swift Container API features.
*
* @author Adrian Cole
* @author Zack Shoylev
- * @see <a href=
- * "http://docs.openstack.org/api/openstack-object-storage/1.0/content/storage-container-services.html"
- * >api doc</a>
+ * @author Jeremy Daggett
*/
@RequestFilters(AuthenticateRequest.class)
@Consumes(APPLICATION_JSON)
@@ -66,46 +64,41 @@
/**
* Lists up to 10,000 containers.
*
- * @return a list of existing storage containers ordered by name.
+ * @return a list of {@link Container containers} ordered by name.
*/
- @Named("ListContainers")
+ @Named("container:list")
@GET
@QueryParams(keys = "format", values = "json")
@Fallback(EmptyFluentIterableOnNotFoundOr404.class)
@Path("/")
- FluentIterable<Container> listFirstPage();
+ FluentIterable<Container> list();
/**
- * Lists up to 10,000 containers, starting at {@code marker}
+ * Lists containers with the supplied {@link ListContainerOptions}.
*
- * @param marker
- * lexicographic position to start list.
+ * @param options
+ * the options to control the output list.
*
- * @return a list of existing storage containers ordered by name.
+ * @return a list of {@link Container containers} ordered by name.
*/
- @Named("ListContainers")
+ @Named("container:list")
@GET
@QueryParams(keys = "format", values = "json")
@Fallback(EmptyFluentIterableOnNotFoundOr404.class)
@Path("/")
- FluentIterable<Container> listAt(@QueryParam("marker") String marker);
+ FluentIterable<Container> list(ListContainerOptions options);
/**
* Creates a container, if not already present.
*
* @param containerName
- * corresponds to {@link Container#name()}.
+ * corresponds to {@link Container#getName()}.
* @param options
- * configuration such as <a href=
- * "http://docs.openstack.org/api/openstack-object-storage/1.0/content/special-metadata-acls.html"
- * >public read access</a>.
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/create-container.html">
- * Create Container API</a>
+ * the options to use when creating the container.
*
- * @return <code>false</code> if the container already existed.
+ * @return {@code true} if the container was created, {@code false} if the container already existed.
*/
- @Named("CreateContainer")
+ @Named("container:createIfAbsent")
@PUT
@ResponseParser(FalseOnAccepted.class)
@Path("/{containerName}")
@@ -115,14 +108,11 @@
* Gets the {@link Container}.
*
* @param containerName
- * corresponds to {@link Container#name()}.
- * @return the Container or null, if not found.
+ * corresponds to {@link Container#getName()}.
*
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/retrieve-Container-metadata.html">
- * Get Container Metadata API</a>
+ * @return the {@link Container}, or {@code null} if not found.
*/
- @Named("GetContainer")
+ @Named("container:get")
@HEAD
@ResponseParser(ParseContainerFromHeaders.class)
@Fallback(NullOnNotFoundOr404.class)
@@ -131,21 +121,17 @@
Container get(@PathParam("containerName") String containerName);
/**
- * Creates or updates the Container metadata.
+ * Creates or updates the {@link Container} metadata.
*
* @param containerName
- * corresponds to {@link Container#name()}.
+ * the container name corresponding to {@link Container#getName()}.
* @param metadata
- * the Container metadata to create or update.
+ * the container metadata to create or update.
*
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/Update_Container_Metadata-d1e1900.html">
- * Create or Update Container Metadata API</a>
- *
- * @return <code>true</code> if the Container Metadata was successfully
- * created or updated, false if not.
+ * @return {@code true} if the container metadata was successfully created or updated,
+ * {@code false} if not.
*/
- @Named("UpdateContainerMetadata")
+ @Named("container:updateMetadata")
@POST
@Fallback(FalseOnNotFoundOr404.class)
@Path("/{containerName}")
@@ -153,21 +139,17 @@
@BinderParam(BindContainerMetadataToHeaders.class) Map<String, String> metadata);
/**
- * Deletes Container metadata.
+ * Deletes {@link Container} metadata.
*
* @param containerName
- * corresponds to {@link Container#name()}.
+ * corresponds to {@link Container#getName()}.
* @param metadata
- * the Container metadata to delete.
+ * the container metadata to delete.
*
- * @return <code>true</code> if the Container Metadata was successfully
- * deleted, false if not.
- *
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/delete-container-metadata.html">
- * Delete Container Metadata API</a>
+ * @return {@code true} if the container metadata was successfully deleted,
+ * {@code false} if not.
*/
- @Named("DeleteContainerMetadata")
+ @Named("container:deleteMetadata")
@POST
@Fallback(FalseOnNotFoundOr404.class)
@Path("/{containerName}")
@@ -175,19 +157,16 @@
@BinderParam(BindRemoveContainerMetadataToHeaders.class) Map<String, String> metadata);
/**
- * Deletes a container, if empty.
+ * Deletes a {@link Container}, if empty.
*
* @param containerName
- * corresponds to {@link Container#name()}.
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/delete-container.html">
- * Delete Container API</a>
+ * corresponds to {@link Container#getName()}.
*
- * @return <code>false</code> if the container was not present.
- * @throws IllegalStateException
- * when the container wasn't empty.
+ * @return {@code false} if the container was not present.
+ *
+ * @throws IllegalStateException if the container was not empty.
*/
- @Named("DeleteContainer")
+ @Named("container:deleteIfEmpty")
@DELETE
@Fallback(FalseOnNotFoundOr404.class)
@Path("/{containerName}")
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ObjectApi.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ObjectApi.java
index 374bfa6..97c38b0 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ObjectApi.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ObjectApi.java
@@ -57,9 +57,10 @@
import org.jclouds.rest.annotations.ResponseParser;
/**
- * @see <a href=
- * "http://docs.openstack.org/api/openstack-object-storage/1.0/content/storage-object-services.html"
- * >api doc</a>
+ * Provides access to the Swift Object API features.
+ *
+ * @author Adrian Cole
+ * @author Jeremy Daggett
*/
@RequestFilters(AuthenticateRequest.class)
@Consumes(APPLICATION_JSON)
@@ -68,12 +69,12 @@
/**
* Lists up to 10,000 objects.
*
- * @param options
- * options to control the output list.
- *
- * @return an {@link ObjectList} of {@link SwiftObject} ordered by name or null.
+ * @param options
+ * the {@link ListContainerOptions} for controlling the returned list.
+ *
+ * @return an {@link ObjectList} of {@link SwiftObject} ordered by name or {@code null}.
*/
- @Named("ListObjects")
+ @Named("object:list")
@GET
@QueryParams(keys = "format", values = "json")
@ResponseParser(ParseObjectListFromResponse.class)
@@ -83,21 +84,18 @@
ObjectList list(ListContainerOptions options);
/**
- * Creates or updates an object.
+ * Creates or updates a {@link SwiftObject}.
*
* @param objectName
- * corresponds to {@link SwiftObject#name()}.
+ * corresponds to {@link SwiftObject#getName()}.
* @param payload
- * corresponds to {@link SwiftObject#payload()}.
+ * corresponds to {@link SwiftObject#getPayload()}.
* @param metadata
- * corresponds to {@link SwiftObject#metadata()}.
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/create-update-object.html">
- * Create or Update Object API</a>
+ * corresponds to {@link SwiftObject#getMetadata()}.
*
- * @return {@link SwiftObject#etag()} of the object.
+ * @return {@link SwiftObject#getEtag()} of the object.
*/
- @Named("CreateOrUpdateObject")
+ @Named("object:replace")
@PUT
@ResponseParser(ETagHeader.class)
@Path("/{objectName}")
@@ -105,18 +103,14 @@
@BinderParam(BindObjectMetadataToHeaders.class) Map<String, String> metadata);
/**
- * Gets the {@link SwiftObject} metadata without its
- * {@link Payload#getInput() body}.
+ * Gets the {@link SwiftObject} metadata without its {@link Payload#getInput() body}.
*
* @param objectName
- * corresponds to {@link SwiftObject#name()}.
- * @return the {@link SwiftObject} or null, if not found.
+ * corresponds to {@link SwiftObject#getName()}.
*
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/retrieve-object-metadata.html">
- * Get Object Metadata API</a>
+ * @return the {@link SwiftObject} or {@code null}, if not found.
*/
- @Named("GetObjectMetadata")
+ @Named("object:head")
@HEAD
@ResponseParser(ParseObjectFromResponse.class)
@Fallback(NullOnNotFoundOr404.class)
@@ -128,17 +122,13 @@
* Gets the {@link SwiftObject} including its {@link Payload#getInput() body}.
*
* @param objectName
- * corresponds to {@link SwiftObject#name()}.
+ * corresponds to {@link SwiftObject#getName()}.
* @param options
* options to control the download.
*
- * @return the Object or null, if not found.
- *
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/retrieve-object.html">
- * Get Object API</a>
+ * @return the {@link SwiftObject} or {@code null}, if not found.
*/
- @Named("GetObject")
+ @Named("object:get")
@GET
@ResponseParser(ParseObjectFromResponse.class)
@Fallback(NullOnNotFoundOr404.class)
@@ -150,18 +140,14 @@
* Creates or updates the metadata for a {@link SwiftObject}.
*
* @param objectName
- * corresponds to {@link SwiftObject#name()}.
+ * corresponds to {@link SwiftObject#getName()}.
* @param metadata
* the metadata to create or update.
*
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/Update_Container_Metadata-d1e1900.html">
- * Create or Update Object Metadata API</a>
- *
- * @return {@code true} if the metadata was successfully created
- * or updated, false if not.
+ * @return {@code true} if the metadata was successfully created or updated,
+ * {@code false} if not.
*/
- @Named("UpdateObjectMetadata")
+ @Named("object:updateMetadata")
@POST
@Fallback(FalseOnNotFoundOr404.class)
@Path("/{objectName}")
@@ -172,17 +158,14 @@
* Deletes the metadata from a {@link SwiftObject}.
*
* @param objectName
- * corresponds to {@link SwiftObject#name()}.
+ * corresponds to {@link SwiftObject#getName()}.
* @param metadata
- * corresponds to {@link SwiftObject#metadata()}.
+ * corresponds to {@link SwiftObject#getMetadata()}.
*
- * @return {@code true} if the metadata was successfully deleted, false if not.
- *
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/delete-object-metadata.html">
- * Delete Object Metadata API</a>
+ * @return {@code true} if the metadata was successfully deleted,
+ * {@code false} if not.
*/
- @Named("DeleteObjectMetadata")
+ @Named("object:deleteMetadata")
@POST
@Fallback(FalseOnNotFoundOr404.class)
@Path("/{objectName}")
@@ -193,20 +176,19 @@
* Deletes an object, if present.
*
* @param objectName
- * corresponds to {@link SwiftObject#name()}.
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/delete-object.html">
- * Delete Object API</a>
+ * corresponds to {@link SwiftObject#getName()}.
*/
- @Named("DeleteObject")
+ @Named("object:delete")
@DELETE
@Fallback(VoidOnNotFoundOr404.class)
@Path("/{objectName}")
void delete(@PathParam("objectName") String objectName);
/**
- * Copies an object from one container to another. Please note that this
- * is a server side copy.
+ * Copies an object from one container to another.
+ *
+ * <h3>NOTE</h3>
+ * This is a server side copy.
*
* @param destinationObject
* the destination object name.
@@ -214,15 +196,12 @@
* the source container name.
* @param sourceObject
* the source object name.
- * @return {@code true} if the object was successfully copied, false if not.
*
- * @throws CopyObjectException if the source or destination container do not exist
+ * @return {@code true} if the object was successfully copied, {@code false} if not.
*
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/copy-object.html">
- * Copy Object API</a>
+ * @throws CopyObjectException if the source or destination container do not exist.
*/
- @Named("CopyObject")
+ @Named("object:copy")
@PUT
@Path("/{destinationObject}")
@Headers(keys = OBJECT_COPY_FROM, values = "/{sourceContainer}/{sourceObject}")
@@ -230,5 +209,4 @@
boolean copy(@PathParam("destinationObject") String destinationObject,
@PathParam("sourceContainer") String sourceContainer,
@PathParam("sourceObject") String sourceObject);
-
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/StaticLargeObjectApi.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/StaticLargeObjectApi.java
index 8b6637f..b884f30 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/StaticLargeObjectApi.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/StaticLargeObjectApi.java
@@ -32,6 +32,7 @@
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.openstack.swift.v1.binders.BindMetadataToHeaders.BindObjectMetadataToHeaders;
import org.jclouds.openstack.swift.v1.domain.Segment;
+import org.jclouds.openstack.swift.v1.domain.SwiftObject;
import org.jclouds.openstack.swift.v1.functions.ETagHeader;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.Fallback;
@@ -41,9 +42,10 @@
import org.jclouds.rest.binders.BindToJsonPayload;
/**
- * @see <a
- * href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/static-large-objects.html">
- * Static Large Objects API</a>
+ * Provides access to the Swift Static Large Object API features.
+ *
+ * @author Adrian Cole
+ * @author Jeremy Daggett
*/
@RequestFilters(AuthenticateRequest.class)
@Consumes(APPLICATION_JSON)
@@ -53,16 +55,16 @@
* Creates or updates a static large object's manifest.
*
* @param objectName
- * corresponds to {@link SwiftObject#name()}.
+ * corresponds to {@link SwiftObject#getName()}.
* @param segments
* ordered parts which will be concatenated upon download.
* @param metadata
- * corresponds to {@link SwiftObject#metadata()}.
+ * corresponds to {@link SwiftObject#getMetadata()}.
*
- * @return {@link SwiftObject#etag()} of the object, which is the MD5
+ * @return {@link SwiftObject#getEtag()} of the object, which is the MD5
* checksum of the concatenated ETag values of the {@code segments}.
*/
- @Named("CreateOrUpdateStaticLargeObjectManifest")
+ @Named("staticLargeObject:replaceManifest")
@PUT
@ResponseParser(ETagHeader.class)
@Path("/{objectName}")
@@ -75,9 +77,9 @@
* Deletes a static large object, if present, including all of its segments.
*
* @param objectName
- * corresponds to {@link SwiftObject#name()}.
+ * corresponds to {@link SwiftObject#getName()}.
*/
- @Named("DeleteStaticLargeObject")
+ @Named("staticLargeObject:delete")
@DELETE
@Fallback(VoidOnNotFoundOr404.class)
@Path("/{objectName}")
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/EntriesWithoutMetaPrefix.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/EntriesWithoutMetaPrefix.java
index 06f0eaf..27e3741 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/EntriesWithoutMetaPrefix.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/EntriesWithoutMetaPrefix.java
@@ -29,9 +29,7 @@
* @param from
* a {@link Multimap} containing the prefixed headers.
*
- * @return the extracted {@code Metadata} without the prefixed keys.
- *
- * @see {@link SwiftResource#metadata()}
+ * @return the extracted metadata without the prefixed keys.
*/
enum EntriesWithoutMetaPrefix implements Function<Multimap<String, String>, Map<String, String>> {
INSTANCE;
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountFromHeaders.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountFromHeaders.java
index f31cbac..9debe67 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountFromHeaders.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountFromHeaders.java
@@ -16,6 +16,10 @@
*/
package org.jclouds.openstack.swift.v1.functions;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_BYTES_USED;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_CONTAINER_COUNT;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_OBJECT_COUNT;
+
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.swift.v1.domain.Account;
@@ -25,10 +29,10 @@
@Override
public Account apply(HttpResponse from) {
- return Account.builder() //
- .bytesUsed(Long.parseLong(from.getFirstHeaderOrNull("X-Account-Bytes-Used"))) //
- .containerCount(Long.parseLong(from.getFirstHeaderOrNull("X-Account-Container-Count"))) //
- .objectCount(Long.parseLong(from.getFirstHeaderOrNull("X-Account-Object-Count"))) //
+ return Account.builder()
+ .bytesUsed(Long.parseLong(from.getFirstHeaderOrNull(ACCOUNT_BYTES_USED)))
+ .containerCount(Long.parseLong(from.getFirstHeaderOrNull(ACCOUNT_CONTAINER_COUNT)))
+ .objectCount(Long.parseLong(from.getFirstHeaderOrNull(ACCOUNT_OBJECT_COUNT)))
.metadata(EntriesWithoutMetaPrefix.INSTANCE.apply(from.getHeaders())).build();
}
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseContainerFromHeaders.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseContainerFromHeaders.java
index 5fb3c9f..d616351 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseContainerFromHeaders.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseContainerFromHeaders.java
@@ -16,6 +16,11 @@
*/
package org.jclouds.openstack.swift.v1.functions;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_ACL_ANYBODY_READ;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_BYTES_USED;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_OBJECT_COUNT;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_READ;
+
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.swift.v1.domain.Container;
@@ -31,12 +36,14 @@
@Override
public Container apply(HttpResponse from) {
- return Container.builder() //
- .name(name) //
- .bytesUsed(Long.parseLong(from.getFirstHeaderOrNull("X-Container-Bytes-Used"))) //
- .objectCount(Long.parseLong(from.getFirstHeaderOrNull("X-Container-Object-Count"))) //
- .anybodyRead(".r:*,.rlistings".equals(from.getFirstHeaderOrNull("X-Container-Read"))) //
+ Container c =
+ Container.builder()
+ .name(name)
+ .bytesUsed(Long.parseLong(from.getFirstHeaderOrNull(CONTAINER_BYTES_USED)))
+ .objectCount(Long.parseLong(from.getFirstHeaderOrNull(CONTAINER_OBJECT_COUNT)))
+ .anybodyRead(CONTAINER_ACL_ANYBODY_READ.equals(from.getFirstHeaderOrNull(CONTAINER_READ)))
.metadata(EntriesWithoutMetaPrefix.INSTANCE.apply(from.getHeaders())).build();
+ return c;
}
@Override
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java
index 158aa6d..6c1ac9e 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java
@@ -46,12 +46,12 @@
@Override
public SwiftObject apply(HttpResponse from) {
- return SwiftObject.builder() //
- .uri(URI.create(uri)) //
- .name(name) //
- .etag(from.getFirstHeaderOrNull(ETAG)) //
- .payload(from.getPayload()) //
- .lastModified(dates.rfc822DateParse(from.getFirstHeaderOrNull(LAST_MODIFIED))) //
+ return SwiftObject.builder()
+ .uri(URI.create(uri))
+ .name(name)
+ .etag(from.getFirstHeaderOrNull(ETAG))
+ .payload(from.getPayload())
+ .lastModified(dates.rfc822DateParse(from.getFirstHeaderOrNull(LAST_MODIFIED)))
.headers(from.getHeaders())
.metadata(EntriesWithoutMetaPrefix.INSTANCE.apply(from.getHeaders())).build();
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java
index 5cfa562..0b58e8b 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java
@@ -74,11 +74,11 @@
@Override
public SwiftObject apply(InternalObject input) {
- return SwiftObject.builder() //
- .uri(URI.create(String.format("%s%s", containerUri, input.name))) //
- .name(input.name) //
- .etag(input.hash) //
- .payload(payload(input.bytes, input.content_type)) //
+ return SwiftObject.builder()
+ .uri(URI.create(String.format("%s%s", containerUri, input.name)))
+ .name(input.name)
+ .etag(input.hash)
+ .payload(payload(input.bytes, input.content_type))
.lastModified(input.last_modified).build();
}
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java
index 2fe469e..2bde41c 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java
@@ -30,6 +30,7 @@
import org.jclouds.openstack.swift.v1.CopyObjectException;
import org.jclouds.openstack.swift.v1.reference.SwiftHeaders;
import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.InsufficientResourcesException;
// TODO: is there error spec someplace? let's type errors, etc.
public class SwiftErrorHandler implements HttpErrorHandler {
@@ -81,6 +82,9 @@
case 409:
exception = new IllegalStateException(exception.getMessage(), exception);
break;
+ case 413:
+ exception = new InsufficientResourcesException(exception.getMessage(), exception);
+ break;
}
command.setException(exception);
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/CreateContainerOptions.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/CreateContainerOptions.java
index fc8f9c8..cef386a 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/CreateContainerOptions.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/CreateContainerOptions.java
@@ -16,22 +16,29 @@
*/
package org.jclouds.openstack.swift.v1.options;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_ACL_ANYBODY_READ;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_METADATA_PREFIX;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_READ;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_VERSIONS_LOCATION;
+
import java.util.Map;
import org.jclouds.http.options.BaseHttpRequestOptions;
import org.jclouds.openstack.swift.v1.binders.BindMetadataToHeaders;
+import org.jclouds.openstack.swift.v1.domain.Container;
+import org.jclouds.openstack.swift.v1.features.ContainerApi;
/**
- * Options available to <a href=
- * "http://docs.openstack.org/api/openstack-object-storage/1.0/content/create-container.html"
- * >create a container</a>.
+ * Options for creating a {@link Container}.
*
- * @see ContainerApi#createIfAbsent
+ * @see ContainerApi#createIfAbsent(String, CreateContainerOptions)
*/
public class CreateContainerOptions extends BaseHttpRequestOptions {
public static final CreateContainerOptions NONE = new CreateContainerOptions();
- /** corresponds to {@link Container#metadata()} */
+ /**
+ * Sets the metadata on a container at creation.
+ */
public CreateContainerOptions metadata(Map<String, String> metadata) {
if (!metadata.isEmpty()) {
this.headers.putAll(bindMetadataToHeaders.toHeaders(metadata));
@@ -39,26 +46,48 @@
return this;
}
- /** Sets the ACL the container so that anybody can read it. */
+ /**
+ * Sets the public ACL on the container so that anybody can read it.
+ */
public CreateContainerOptions anybodyRead() {
- this.headers.put("x-container-read", ".r:*,.rlistings");
+ this.headers.put(CONTAINER_READ, CONTAINER_ACL_ANYBODY_READ);
+ return this;
+ }
+
+ /**
+ * Sets the container that will contain object versions.
+ */
+ public CreateContainerOptions versionsLocation(String containerName) {
+ this.headers.put(CONTAINER_VERSIONS_LOCATION, containerName);
return this;
}
public static class Builder {
- /** @see CreateContainerOptions#anybodyRead */
+ /**
+ * @see CreateContainerOptions#anybodyRead
+ */
public static CreateContainerOptions anybodyRead() {
CreateContainerOptions options = new CreateContainerOptions();
return options.anybodyRead();
}
- /** @see CreateContainerOptions#metadata */
+ /**
+ * @see CreateContainerOptions#metadata
+ */
public static CreateContainerOptions metadata(Map<String, String> metadata) {
CreateContainerOptions options = new CreateContainerOptions();
return options.metadata(metadata);
}
+
+ /**
+ * @see CreateContainerOptions#versionsLocation
+ */
+ public static CreateContainerOptions versionsLocation(String containerName) {
+ CreateContainerOptions options = new CreateContainerOptions();
+ return options.versionsLocation(containerName);
+ }
}
- private static final BindMetadataToHeaders bindMetadataToHeaders = new BindMetadataToHeaders("x-container-meta-");
+ private static final BindMetadataToHeaders bindMetadataToHeaders = new BindMetadataToHeaders(CONTAINER_METADATA_PREFIX);
}
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/ListContainerOptions.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/ListContainerOptions.java
index 3373455..e1003e4 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/ListContainerOptions.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/ListContainerOptions.java
@@ -20,18 +20,19 @@
import static com.google.common.base.Preconditions.checkState;
import org.jclouds.http.options.BaseHttpRequestOptions;
+import org.jclouds.openstack.swift.v1.features.ContainerApi;
/**
- * Options available for <a href=
- * "http://docs.openstack.org/api/openstack-object-storage/1.0/content/list-objects.html"
- * >listing objects</a>.
+ * Options for listing containers.
*
- * @see ObjectApi#list
+ * @see ContainerApi#list(ListContainerOptions)
*/
public class ListContainerOptions extends BaseHttpRequestOptions {
public static final ListContainerOptions NONE = new ListContainerOptions();
- /** list operation returns no more than this amount. */
+ /**
+ * list operation returns no more than this amount.
+ */
public ListContainerOptions limit(int limit) {
checkState(limit >= 0, "limit must be >= 0");
checkState(limit <= 10000, "limit must be <= 10000");
@@ -39,31 +40,41 @@
return this;
}
- /** object names greater in value than the specified marker are returned. */
+ /**
+ * object names greater in value than the specified marker are returned.
+ */
public ListContainerOptions marker(String marker) {
queryParameters.put("marker", checkNotNull(marker, "marker"));
return this;
}
- /** object names less in value than the specified marker are returned. */
+ /**
+ * object names less in value than the specified marker are returned.
+ */
public ListContainerOptions endMarker(String endMarker) {
queryParameters.put("end_marker", checkNotNull(endMarker, "endMarker"));
return this;
}
- /** object names beginning with this substring are returned. */
+ /**
+ * object names beginning with this substring are returned.
+ */
public ListContainerOptions prefix(String prefix) {
queryParameters.put("prefix", checkNotNull(prefix, "prefix"));
return this;
}
- /** object names nested in the container are returned. */
+ /**
+ * object names nested in the container are returned.
+ */
public ListContainerOptions delimiter(char delimiter) {
queryParameters.put("delimiter", Character.toString(delimiter));
return this;
}
- /** object names nested in the pseudo path are returned. */
+ /**
+ * object names nested in the pseudo path are returned.
+ */
public ListContainerOptions path(String path) {
queryParameters.put("path", checkNotNull(path, "path"));
return this;
@@ -71,37 +82,49 @@
public static class Builder {
- /** @see ListContainerOptions#limit */
+ /**
+ * @see ListContainerOptions#limit
+ */
public static ListContainerOptions limit(int limit) {
ListContainerOptions options = new ListContainerOptions();
return options.limit(limit);
}
- /** @see ListContainerOptions#marker */
+ /**
+ * @see ListContainerOptions#marker
+ */
public static ListContainerOptions marker(String marker) {
ListContainerOptions options = new ListContainerOptions();
return options.marker(marker);
}
- /** @see ListContainerOptions#endMarker */
+ /**
+ * @see ListContainerOptions#endMarker
+ */
public static ListContainerOptions endMarker(String endMarker) {
ListContainerOptions options = new ListContainerOptions();
return options.endMarker(endMarker);
}
- /** @see ListContainerOptions#prefix */
+ /**
+ * @see ListContainerOptions#prefix
+ */
public static ListContainerOptions prefix(String prefix) {
ListContainerOptions options = new ListContainerOptions();
return options.prefix(prefix);
}
- /** @see ListContainerOptions#delimiter */
+ /**
+ * @see ListContainerOptions#delimiter
+ */
public static ListContainerOptions delimiter(char delimiter) {
ListContainerOptions options = new ListContainerOptions();
return options.delimiter(delimiter);
}
- /** @see ListContainerOptions#path */
+ /**
+ * @see ListContainerOptions#path
+ */
public static ListContainerOptions path(String path) {
ListContainerOptions options = new ListContainerOptions();
return options.path(path);
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/reference/SwiftHeaders.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/reference/SwiftHeaders.java
index e0c9348..d8bcd5c 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/reference/SwiftHeaders.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/reference/SwiftHeaders.java
@@ -22,30 +22,62 @@
* @author Jeremy Daggett
*/
public interface SwiftHeaders {
+
+ // Common Metadata Prefixes
+ String ACCOUNT_METADATA_PREFIX = "X-Account-Meta-";
+ String CONTAINER_METADATA_PREFIX = "X-Container-Meta-";
+ String OBJECT_METADATA_PREFIX = "X-Object-Meta-";
+ String USER_METADATA_PREFIX = OBJECT_METADATA_PREFIX;
+
+ // Metadata Removal Prefixes
+ String ACCOUNT_REMOVE_METADATA_PREFIX = "X-Remove-Account-Meta-";
+ String CONTAINER_REMOVE_METADATA_PREFIX = "X-Remove-Container-Meta-";
+ String OBJECT_REMOVE_METADATA_PREFIX = "X-Remove-Object-Meta-";
+
+ // TempURL
+ String ACCOUNT_TEMPORARY_URL_KEY = ACCOUNT_METADATA_PREFIX + "Temp-Url-Key";
+ String ACCOUNT_TEMPORARY_URL_KEY_2 = ACCOUNT_TEMPORARY_URL_KEY + "-2";
- String USER_METADATA_PREFIX = "X-Object-Meta-";
-
- String ACCOUNT_TEMPORARY_URL_KEY = "X-Account-Meta-Temp-Url-Key";
+ // Account Headers
String ACCOUNT_BYTES_USED = "X-Account-Bytes-Used";
String ACCOUNT_CONTAINER_COUNT = "X-Account-Container-Count";
+ String ACCOUNT_OBJECT_COUNT = "X-Account-Object-Count";
+ // Container Headers
String CONTAINER_BYTES_USED = "X-Container-Bytes-Used";
String CONTAINER_OBJECT_COUNT = "X-Container-Object-Count";
- String CONTAINER_METADATA_PREFIX = "X-Container-Meta-";
- String CONTAINER_DELETE_METADATA_PREFIX = "X-Remove-Container-Meta-";
+ // Public access - not supported in all Swift Impls
String CONTAINER_READ = "X-Container-Read";
String CONTAINER_WRITE = "X-Container-Write";
+ String CONTAINER_ACL_ANYBODY_READ = ".r:*,.rlistings";
- String CONTAINER_WEB_INDEX = "X-Container-Meta-Web-Index";
- String CONTAINER_WEB_ERROR = "X-Container-Meta-Web-Error";
- String CONTAINER_WEB_LISTINGS = "X-Container-Meta-Web-Listings";
- String CONTAINER_WEB_LISTINGS_CSS = "X-Container-Meta-Web-Listings-CSS";
-
+ // CORS
+ String CONTAINER_ACCESS_CONTROL_ALLOW_ORIGIN = CONTAINER_METADATA_PREFIX + "Access-Control-Allow-Origin";
+ String CONTAINER_ACCESS_CONTROL_MAX_AGE = CONTAINER_METADATA_PREFIX + "Access-Control-Max-Age";
+ String CONTAINER_ACCESS_CONTROL_EXPOSE_HEADERS = CONTAINER_METADATA_PREFIX + "Access-Control-Expose-Headers";
+
+ // Container Quota
+ String CONTAINER_QUOTA_BYTES = CONTAINER_METADATA_PREFIX + "Quota-Bytes";
+ String CONTAINER_QUOTA_COUNT = CONTAINER_METADATA_PREFIX + "Quota-Count";
+
+ // Container Sync
+ String CONTAINER_SYNC_KEY = "X-Container-Sync-Key";
+ String CONTAINER_SYNC_TO = "X-Container-Sync-To";
+
+ // Versioning
+ String CONTAINER_VERSIONS_LOCATION = "X-Versions-Location";
+
+ // Misc functionality
+ String CONTAINER_WEB_MODE = "X-Web-Mode";
+
String OBJECT_COPY_FROM = "X-Copy-From";
String OBJECT_DELETE_AFTER = "X-Delete-After";
String OBJECT_DELETE_AT = "X-Delete-At";
+ String OBJECT_MANIFEST = "X-Object-Manifest";
/** Get the newest version of the object for GET and HEAD requests */
String OBJECT_NEWEST = "X-Newest";
- String OBJECT_VERSIONS_LOCATION = "X-Versions-Location";
+
+ // Static Large Object
+ String STATIC_LARGE_OBJECT = "X-Static-Large-Object";
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerLiveTest.java
index 733563c..9a00c14 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerLiveTest.java
@@ -38,7 +38,7 @@
import com.google.common.collect.ImmutableMap;
@Test(groups = "live", testName = "TemporaryUrlSignerLiveTest")
-public class TemporaryUrlSignerLiveTest extends BaseSwiftApiLiveTest {
+public class TemporaryUrlSignerLiveTest extends BaseSwiftApiLiveTest<SwiftApi> {
private String name = getClass().getSimpleName();
private String containerName = getClass().getSimpleName() + "Container";
@@ -48,10 +48,10 @@
SwiftObject object = api.objectApiInRegionForContainer(regionId, containerName).head(name);
long expires = System.currentTimeMillis() / 1000 + 5;
- String signature = TemporaryUrlSigner.checkApiEvery(api.accountApiInRegion(regionId), 5) //
- .sign("GET", object.uri().getPath(), expires);
+ String signature = TemporaryUrlSigner.checkApiEvery(api.accountApiInRegion(regionId), 5)
+ .sign("GET", object.getUri().getPath(), expires);
- URI signed = URI.create(format("%s?temp_url_sig=%s&temp_url_expires=%s", object.uri(), signature, expires));
+ URI signed = URI.create(format("%s?temp_url_sig=%s&temp_url_expires=%s", object.getUri(), signature, expires));
InputStream publicStream = signed.toURL().openStream();
assertEquals(Strings2.toStringAndClose(publicStream), "swifty");
@@ -74,7 +74,7 @@
for (String regionId : api.configuredRegions()) {
api.accountApiInRegion(regionId).updateTemporaryUrlKey(key);
api.containerApiInRegion(regionId).createIfAbsent(containerName, CreateContainerOptions.NONE);
- api.objectApiInRegionForContainer(regionId, containerName) //
+ api.objectApiInRegionForContainer(regionId, containerName)
.replace(name, newStringPayload("swifty"), ImmutableMap.<String, String> of());
}
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerMockTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerMockTest.java
index 0f856ba..6744fb6 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerMockTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerMockTest.java
@@ -16,6 +16,7 @@
*/
package org.jclouds.openstack.swift.v1;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_TEMPORARY_URL_KEY;
import static org.jclouds.openstack.swift.v1.features.AccountApiMockTest.accountResponse;
import static org.testng.Assert.assertEquals;
@@ -25,7 +26,7 @@
import com.squareup.okhttp.mockwebserver.MockResponse;
import com.squareup.okhttp.mockwebserver.MockWebServer;
-@Test
+@Test(groups = "unit", testName = "TemporaryUrlSignerMockTest")
public class TemporaryUrlSignerMockTest extends BaseOpenStackMockTest<SwiftApi> {
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "accountApi")
@@ -36,7 +37,7 @@
public void whenAccountApiHasKey() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
- server.enqueue(addCommonHeaders(accountResponse().addHeader("X-Account-Meta-Temp-URL-Key", "mykey")));
+ server.enqueue(addCommonHeaders(accountResponse().addHeader(ACCOUNT_TEMPORARY_URL_KEY, "mykey")));
try {
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobIntegrationLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobIntegrationLiveTest.java
index 39f0a0f..6d26100 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobIntegrationLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobIntegrationLiveTest.java
@@ -26,8 +26,9 @@
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
-@Test(groups = "live")
+@Test(groups = "live", testName = "SwiftBlobIntegrationLiveTest")
public class SwiftBlobIntegrationLiveTest extends BaseBlobIntegrationTest {
+
public SwiftBlobIntegrationLiveTest() {
provider = "openstack-swift";
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobLiveTest.java
index f7b6b00..d9996bf 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobLiveTest.java
@@ -23,8 +23,9 @@
import org.jclouds.blobstore.integration.internal.BaseBlobLiveTest;
import org.testng.annotations.Test;
-@Test(groups = "live")
+@Test(groups = "live", testName = "SwiftBlobLiveTest")
public class SwiftBlobLiveTest extends BaseBlobLiveTest {
+
public SwiftBlobLiveTest() {
provider = "openstack-swift";
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobSignerLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobSignerLiveTest.java
index 36fc024..9dd603f 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobSignerLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobSignerLiveTest.java
@@ -23,8 +23,9 @@
import org.jclouds.blobstore.integration.internal.BaseBlobSignerLiveTest;
import org.testng.annotations.Test;
-@Test(groups = "live")
+@Test(groups = "live", testName = "SwiftBlobSignerLiveTest")
public class SwiftBlobSignerLiveTest extends BaseBlobSignerLiveTest {
+
public SwiftBlobSignerLiveTest() {
provider = "openstack-swift";
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerIntegrationLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerIntegrationLiveTest.java
index 4e682f8..d954867 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerIntegrationLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerIntegrationLiveTest.java
@@ -24,8 +24,9 @@
import org.jclouds.blobstore.integration.internal.BaseContainerIntegrationTest;
import org.testng.annotations.Test;
-@Test(groups = "live")
+@Test(groups = "live", testName = "SwiftContainerIntegrationLiveTest")
public class SwiftContainerIntegrationLiveTest extends BaseContainerIntegrationTest {
+
public SwiftContainerIntegrationLiveTest() {
provider = "openstack-swift";
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerLiveTest.java
index 8f5ab6c..9bd85d6 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerLiveTest.java
@@ -23,8 +23,9 @@
import org.jclouds.blobstore.integration.internal.BaseContainerLiveTest;
import org.testng.annotations.Test;
-@Test(groups = "live")
+@Test(groups = "live", testName = "SwiftContainerLiveTest")
public class SwiftContainerLiveTest extends BaseContainerLiveTest {
+
public SwiftContainerLiveTest() {
provider = "openstack-swift";
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftServiceIntegrationLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftServiceIntegrationLiveTest.java
index fa9a734..1da1a68 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftServiceIntegrationLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftServiceIntegrationLiveTest.java
@@ -23,8 +23,9 @@
import org.jclouds.blobstore.integration.internal.BaseServiceIntegrationTest;
import org.testng.annotations.Test;
-@Test(groups = "live")
+@Test(groups = "live", testName = "SwiftServiceIntegrationLiveTest")
public class SwiftServiceIntegrationLiveTest extends BaseServiceIntegrationTest {
+
public SwiftServiceIntegrationLiveTest() {
provider = "openstack-swift";
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdaptersTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdaptersTest.java
index 30edc8f..e4225fc 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdaptersTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdaptersTest.java
@@ -30,32 +30,32 @@
@Test
public class SwiftTypeAdaptersTest {
- Gson gson = new GsonBuilder() //
- .registerTypeAdapter(ExtractArchiveResponse.class, new ExtractArchiveResponseAdapter()) //
- .registerTypeAdapter(BulkDeleteResponse.class, new BulkDeleteResponseAdapter()) //
+ Gson gson = new GsonBuilder()
+ .registerTypeAdapter(ExtractArchiveResponse.class, new ExtractArchiveResponseAdapter())
+ .registerTypeAdapter(BulkDeleteResponse.class, new BulkDeleteResponseAdapter())
.create();
public void extractArchiveWithoutErrors() {
- assertEquals(gson.fromJson("" //
- + "{\n" //
- + " \"Response Status\": \"201 Created\",\n" //
- + " \"Response Body\": \"\",\n" //
- + " \"Errors\": [],\n" //
- + " \"Number Files Created\": 10\n" //
+ assertEquals(gson.fromJson(""
+ + "{\n"
+ + " \"Response Status\": \"201 Created\",\n"
+ + " \"Response Body\": \"\",\n"
+ + " \"Errors\": [],\n"
+ + " \"Number Files Created\": 10\n"
+ "}", ExtractArchiveResponse.class), ExtractArchiveResponse.create(10, ImmutableMap.<String, String> of()));
}
public void extractArchiveWithErrorsAndDecodesPaths() {
assertEquals(
- gson.fromJson("" //
- + "{\n" //
- + " \"Response Status\": \"201 Created\",\n" //
- + " \"Response Body\": \"\",\n" //
- + " \"Errors\": [\n" //
- + " [\"/v1/12345678912345/mycontainer/home/xx%3Cyy\", \"400 Bad Request\"],\n" //
- + " [\"/v1/12345678912345/mycontainer/../image.gif\", \"400 Bad Request\"]\n" //
- + " ],\n" //
- + " \"Number Files Created\": 8\n" //
+ gson.fromJson(""
+ + "{\n"
+ + " \"Response Status\": \"201 Created\",\n"
+ + " \"Response Body\": \"\",\n"
+ + " \"Errors\": [\n"
+ + " [\"/v1/12345678912345/mycontainer/home/xx%3Cyy\", \"400 Bad Request\"],\n"
+ + " [\"/v1/12345678912345/mycontainer/../image.gif\", \"400 Bad Request\"]\n"
+ + " ],\n"
+ + " \"Number Files Created\": 8\n"
+ "}", ExtractArchiveResponse.class),
ExtractArchiveResponse.create(
8,
@@ -65,25 +65,25 @@
}
public void bulkDeleteWithoutErrors() {
- assertEquals(gson.fromJson("" //
- + "{\n" //
- + " \"Response Status\": \"200 OK\",\n" //
- + " \"Response Body\": \"\",\n" //
- + " \"Errors\": [],\n" //
- + " \"Number Not Found\": 1,\n" //
- + " \"Number Deleted\": 9\n" //
+ assertEquals(gson.fromJson(""
+ + "{\n"
+ + " \"Response Status\": \"200 OK\",\n"
+ + " \"Response Body\": \"\",\n"
+ + " \"Errors\": [],\n"
+ + " \"Number Not Found\": 1,\n"
+ + " \"Number Deleted\": 9\n"
+ "}", BulkDeleteResponse.class), BulkDeleteResponse.create(9, 1, ImmutableMap.<String, String> of()));
}
public void bulkDeleteWithErrorsAndDecodesPaths() {
- assertEquals(gson.fromJson("" //
- + "{\n" //
- + " \"Response Status\": \"400 Bad Request\",\n" //
- + " \"Response Body\": \"\",\n" //
- + " \"Errors\": [\n" //
- + " [\"/v1/12345678912345/Not%20Empty\", \"409 Conflict\"]" //
- + " ],\n" //
- + " \"Number Deleted\": 0\n" //
+ assertEquals(gson.fromJson(""
+ + "{\n"
+ + " \"Response Status\": \"400 Bad Request\",\n"
+ + " \"Response Body\": \"\",\n"
+ + " \"Errors\": [\n"
+ + " [\"/v1/12345678912345/Not%20Empty\", \"409 Conflict\"]"
+ + " ],\n"
+ + " \"Number Deleted\": 0\n"
+ "}", BulkDeleteResponse.class),
BulkDeleteResponse.create(0, 0, ImmutableMap.of("/v1/12345678912345/Not Empty", "409 Conflict")));
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java
index 31eff6e..4359a71 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java
@@ -24,6 +24,7 @@
import java.util.Map;
import java.util.Map.Entry;
+import org.jclouds.openstack.swift.v1.SwiftApi;
import org.jclouds.openstack.swift.v1.domain.Account;
import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest;
import org.testng.annotations.Test;
@@ -31,21 +32,21 @@
import com.google.common.collect.ImmutableMap;
@Test(groups = "live", testName = "AccountApiLiveTest")
-public class AccountApiLiveTest extends BaseSwiftApiLiveTest {
+public class AccountApiLiveTest extends BaseSwiftApiLiveTest<SwiftApi> {
- public void get() throws Exception {
+ public void testGet() throws Exception {
for (String regionId : regions) {
AccountApi accountApi = api.accountApiInRegion(regionId);
Account account = accountApi.get();
assertNotNull(account);
- assertTrue(account.containerCount() >= 0);
- assertTrue(account.objectCount() >= 0);
- assertTrue(account.bytesUsed() >= 0);
+ assertTrue(account.getContainerCount() >= 0);
+ assertTrue(account.getObjectCount() >= 0);
+ assertTrue(account.getBytesUsed() >= 0);
}
}
- public void updateMetadata() throws Exception {
+ public void testUpdateMetadata() throws Exception {
for (String regionId : regions) {
AccountApi accountApi = api.accountApiInRegion(regionId);
@@ -57,7 +58,7 @@
}
}
- public void deleteMetadata() throws Exception {
+ public void testDeleteMetadata() throws Exception {
for (String regionId : regions) {
AccountApi accountApi = api.accountApiInRegion(regionId);
@@ -70,7 +71,7 @@
Account account = accountApi.get();
for (Entry<String, String> entry : meta.entrySet()) {
// note keys are returned in lower-case!
- assertFalse(account.metadata().containsKey(entry.getKey().toLowerCase()));
+ assertFalse(account.getMetadata().containsKey(entry.getKey().toLowerCase()));
}
}
}
@@ -79,7 +80,7 @@
Account account = accountApi.get();
for (Entry<String, String> entry : meta.entrySet()) {
// note keys are returned in lower-case!
- assertEquals(account.metadata().get(entry.getKey().toLowerCase()), entry.getValue(), //
+ assertEquals(account.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue(),
account + " didn't have metadata: " + entry);
}
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiMockTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiMockTest.java
index 2c5a9b2..f7e9125 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiMockTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiMockTest.java
@@ -16,6 +16,12 @@
*/
package org.jclouds.openstack.swift.v1.features;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_BYTES_USED;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_CONTAINER_COUNT;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_METADATA_PREFIX;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_OBJECT_COUNT;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_REMOVE_METADATA_PREFIX;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_TEMPORARY_URL_KEY;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
@@ -35,32 +41,31 @@
/**
* @author Jeremy Daggett
*/
-@Test
+@Test(groups = "unit", testName = "AccountApiMockTest")
public class AccountApiMockTest extends BaseOpenStackMockTest<SwiftApi> {
/** upper-cases first char, and lower-cases rest!! **/
public void getKnowingServerMessesWithMetadataKeyCaseFormat() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
- server.enqueue(addCommonHeaders(accountResponse() //
+ server.enqueue(addCommonHeaders(accountResponse()
// note silly casing
- .addHeader("X-Account-Meta-Apiname", "swift") //
- .addHeader("X-Account-Meta-Apiversion", "v1.1")));
+ .addHeader(ACCOUNT_METADATA_PREFIX + "Apiname", "swift")
+ .addHeader(ACCOUNT_METADATA_PREFIX + "Apiversion", "v1.1")));
try {
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
Account account = api.accountApiInRegion("DFW").get();
- assertEquals(account.containerCount(), 3l);
- assertEquals(account.objectCount(), 42l);
- assertEquals(account.bytesUsed(), 323479l);
+ assertEquals(account.getContainerCount(), 3l);
+ assertEquals(account.getObjectCount(), 42l);
+ assertEquals(account.getBytesUsed(), 323479l);
for (Entry<String, String> entry : metadata.entrySet()) {
- assertEquals(account.metadata().get(entry.getKey().toLowerCase()), entry.getValue());
+ assertEquals(account.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue());
}
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
- assertEquals(server.takeRequest().getRequestLine(),
- "HEAD /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/ HTTP/1.1");
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "HEAD", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/");
} finally {
server.shutdown();
}
@@ -69,21 +74,21 @@
public void updateMetadata() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
- server.enqueue(addCommonHeaders(accountResponse() //
- .addHeader("X-Account-Meta-ApiName", "swift") //
- .addHeader("X-Account-Meta-ApiVersion", "v1.1")));
+ server.enqueue(addCommonHeaders(accountResponse()
+ .addHeader(ACCOUNT_METADATA_PREFIX + "ApiName", "swift")
+ .addHeader(ACCOUNT_METADATA_PREFIX + "ApiVersion", "v1.1")));
try {
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
assertTrue(api.accountApiInRegion("DFW").updateMetadata(metadata));
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+ assertAuthentication(server);
+
RecordedRequest replaceRequest = server.takeRequest();
- assertEquals(replaceRequest.getRequestLine(),
- "POST /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/ HTTP/1.1");
+ assertRequest(replaceRequest,"POST", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/");
for (Entry<String, String> entry : metadata.entrySet()) {
- assertEquals(replaceRequest.getHeader("x-account-meta-" + entry.getKey().toLowerCase()), entry.getValue());
+ assertEquals(replaceRequest.getHeader(ACCOUNT_METADATA_PREFIX + entry.getKey().toLowerCase()), entry.getValue());
}
} finally {
server.shutdown();
@@ -100,11 +105,11 @@
assertTrue(api.accountApiInRegion("DFW").updateTemporaryUrlKey("foobar"));
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+ assertAuthentication(server);
+
RecordedRequest replaceRequest = server.takeRequest();
- assertEquals(replaceRequest.getRequestLine(),
- "POST /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/ HTTP/1.1");
- assertEquals(replaceRequest.getHeader("X-Account-Meta-Temp-URL-Key"), "foobar");
+ assertRequest(replaceRequest, "POST", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/");
+ assertEquals(replaceRequest.getHeader(ACCOUNT_TEMPORARY_URL_KEY), "foobar");
} finally {
server.shutdown();
}
@@ -125,7 +130,7 @@
assertEquals(deleteRequest.getRequestLine(),
"POST /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/ HTTP/1.1");
for (String key : metadata.keySet()) {
- assertEquals(deleteRequest.getHeader("x-remove-account-meta-" + key.toLowerCase()), "ignored");
+ assertEquals(deleteRequest.getHeader(ACCOUNT_REMOVE_METADATA_PREFIX + key.toLowerCase()), "ignored");
}
} finally {
server.shutdown();
@@ -135,9 +140,9 @@
private static final Map<String, String> metadata = ImmutableMap.of("ApiName", "swift", "ApiVersion", "v1.1");
public static MockResponse accountResponse() {
- return new MockResponse() //
- .addHeader("X-Account-Container-Count", "3") //
- .addHeader("X-Account-Object-Count", "42") //
- .addHeader("X-Account-Bytes-Used", "323479");
+ return new MockResponse()
+ .addHeader(ACCOUNT_CONTAINER_COUNT, "3")
+ .addHeader(ACCOUNT_OBJECT_COUNT, "42")
+ .addHeader(ACCOUNT_BYTES_USED, "323479");
}
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiLiveTest.java
index 39341fd..fa8e6b6 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiLiveTest.java
@@ -28,6 +28,7 @@
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.exporter.TarGzExporter;
import org.jclouds.io.Payloads;
+import org.jclouds.openstack.swift.v1.SwiftApi;
import org.jclouds.openstack.swift.v1.domain.BulkDeleteResponse;
import org.jclouds.openstack.swift.v1.domain.ExtractArchiveResponse;
import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest;
@@ -42,46 +43,46 @@
import com.google.common.io.ByteStreams;
@Test(groups = "live", testName = "BulkApiLiveTest")
-public class BulkApiLiveTest extends BaseSwiftApiLiveTest {
+public class BulkApiLiveTest extends BaseSwiftApiLiveTest<SwiftApi> {
static final int OBJECT_COUNT = 10;
private String containerName = getClass().getSimpleName();
- public void notPresentWhenDeleting() throws Exception {
+ public void testNotPresentWhenDeleting() throws Exception {
for (String regionId : regions) {
BulkDeleteResponse deleteResponse = api.bulkApiInRegion(regionId).bulkDelete(
ImmutableList.of(UUID.randomUUID().toString()));
- assertEquals(deleteResponse.deleted(), 0);
- assertEquals(deleteResponse.notFound(), 1);
- assertTrue(deleteResponse.errors().isEmpty());
+ assertEquals(deleteResponse.getDeleted(), 0);
+ assertEquals(deleteResponse.getNotFound(), 1);
+ assertTrue(deleteResponse.getErrors().isEmpty());
}
}
- public void extractArchive() throws Exception {
+ public void testExtractArchive() throws Exception {
for (String regionId : regions) {
ExtractArchiveResponse extractResponse = api.bulkApiInRegion(regionId).extractArchive(containerName,
Payloads.newPayload(tarGz), "tar.gz");
- assertEquals(extractResponse.created(), OBJECT_COUNT);
- assertTrue(extractResponse.errors().isEmpty());
- assertEquals(api.containerApiInRegion(regionId).get(containerName).objectCount(), OBJECT_COUNT);
+ assertEquals(extractResponse.getCreated(), OBJECT_COUNT);
+ assertTrue(extractResponse.getErrors().isEmpty());
+ assertEquals(api.containerApiInRegion(regionId).get(containerName).getObjectCount(), OBJECT_COUNT);
// repeat the command
extractResponse = api.bulkApiInRegion(regionId).extractArchive(containerName, Payloads.newPayload(tarGz),
"tar.gz");
- assertEquals(extractResponse.created(), OBJECT_COUNT);
- assertTrue(extractResponse.errors().isEmpty());
+ assertEquals(extractResponse.getCreated(), OBJECT_COUNT);
+ assertTrue(extractResponse.getErrors().isEmpty());
}
}
- @Test(dependsOnMethods = "extractArchive")
- public void bulkDelete() throws Exception {
+ @Test(dependsOnMethods = "testExtractArchive")
+ public void testBulkDelete() throws Exception {
for (String regionId : regions) {
BulkDeleteResponse deleteResponse = api.bulkApiInRegion(regionId).bulkDelete(paths);
- assertEquals(deleteResponse.deleted(), OBJECT_COUNT);
- assertEquals(deleteResponse.notFound(), 0);
- assertTrue(deleteResponse.errors().isEmpty());
- assertEquals(api.containerApiInRegion(regionId).get(containerName).objectCount(), 0);
+ assertEquals(deleteResponse.getDeleted(), OBJECT_COUNT);
+ assertEquals(deleteResponse.getNotFound(), 0);
+ assertTrue(deleteResponse.getErrors().isEmpty());
+ assertEquals(api.containerApiInRegion(regionId).get(containerName).getObjectCount(), 0);
}
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiMockTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiMockTest.java
index 69ce5a1..5b4c200 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiMockTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiMockTest.java
@@ -34,11 +34,10 @@
import com.squareup.okhttp.mockwebserver.MockWebServer;
import com.squareup.okhttp.mockwebserver.RecordedRequest;
-// TODO: cannot yet test bulk delete offline
-@Test
+@Test(groups = "unit", testName = "BulkApiMockTest")
public class BulkApiMockTest extends BaseOpenStackMockTest<SwiftApi> {
- public void extractArchive() throws Exception {
+ public void testExtractArchive() throws Exception {
GenericArchive files = ShrinkWrap.create(GenericArchive.class, "files.tar.gz");
StringAsset content = new StringAsset("foo");
for (int i = 0; i < 10; i++) {
@@ -54,14 +53,13 @@
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
ExtractArchiveResponse response = api.bulkApiInRegion("DFW").extractArchive("myContainer",
newByteArrayPayload(tarGz), "tar.gz");
- assertEquals(response.created(), 10);
- assertTrue(response.errors().isEmpty());
+ assertEquals(response.getCreated(), 10);
+ assertTrue(response.getErrors().isEmpty());
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+ assertAuthentication(server);
RecordedRequest extractRequest = server.takeRequest();
- assertEquals(extractRequest.getRequestLine(),
- "PUT /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer?extract-archive=tar.gz HTTP/1.1");
+ assertRequest(extractRequest, "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer?extract-archive=tar.gz");
assertEquals(extractRequest.getBody(), tarGz);
} finally {
server.shutdown();
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java
index e28ca8e..31ff231 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java
@@ -24,9 +24,11 @@
import java.util.Map;
import java.util.Map.Entry;
+import org.jclouds.openstack.swift.v1.SwiftApi;
import org.jclouds.openstack.swift.v1.domain.Container;
import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest;
import org.jclouds.openstack.swift.v1.options.CreateContainerOptions;
+import org.jclouds.openstack.swift.v1.options.ListContainerOptions;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -36,71 +38,70 @@
/**
* @author Adrian Cole
+ * @author Jeremy Daggett
*/
@Test(groups = "live", testName = "ContainerApiLiveTest")
-public class ContainerApiLiveTest extends BaseSwiftApiLiveTest {
+public class ContainerApiLiveTest extends BaseSwiftApiLiveTest<SwiftApi> {
private String name = getClass().getSimpleName();
- @Test
- public void list() throws Exception {
+ public void testList() throws Exception {
for (String regionId : regions) {
ContainerApi containerApi = api.containerApiInRegion(regionId);
- FluentIterable<Container> response = containerApi.listFirstPage();
+ FluentIterable<Container> response = containerApi.list();
assertNotNull(response);
for (Container container : response) {
- assertNotNull(container.name());
- assertTrue(container.objectCount() >= 0);
- assertTrue(container.bytesUsed() >= 0);
+ assertNotNull(container.getName());
+ assertTrue(container.getObjectCount() >= 0);
+ assertTrue(container.getBytesUsed() >= 0);
}
}
}
- public void get() throws Exception {
- for (String regionId : regions) {
- Container container = api.containerApiInRegion(regionId).get(name);
- assertEquals(container.name(), name);
- assertTrue(container.objectCount() == 0);
- assertTrue(container.bytesUsed() == 0);
- }
- }
-
- public void listAt() throws Exception {
+ public void testListWithOptions() throws Exception {
String lexicographicallyBeforeName = name.substring(0, name.length() - 1);
for (String regionId : regions) {
- Container container = api.containerApiInRegion(regionId).listAt(lexicographicallyBeforeName).get(0);
- assertEquals(container.name(), name);
- assertTrue(container.objectCount() == 0);
- assertTrue(container.bytesUsed() == 0);
+ ListContainerOptions options = ListContainerOptions.Builder.marker(lexicographicallyBeforeName);
+ Container container = api.containerApiInRegion(regionId).list(options).get(0);
+ assertEquals(container.getName(), name);
+ assertTrue(container.getObjectCount() == 0);
+ assertTrue(container.getBytesUsed() == 0);
+ }
+ }
+
+ public void testGet() throws Exception {
+ for (String regionId : regions) {
+ Container container = api.containerApiInRegion(regionId).get(name);
+ assertEquals(container.getName(), name);
+ assertTrue(container.getObjectCount() == 0);
+ assertTrue(container.getBytesUsed() == 0);
}
}
- public void updateMetadata() throws Exception {
+ public void testUpdateMetadata() throws Exception {
+ Map<String, String> meta = ImmutableMap.of("MyAdd1", "foo", "MyAdd2", "bar");
+
for (String regionId : regions) {
ContainerApi containerApi = api.containerApiInRegion(regionId);
-
- Map<String, String> meta = ImmutableMap.of("MyAdd1", "foo", "MyAdd2", "bar");
-
assertTrue(containerApi.updateMetadata(name, meta));
-
containerHasMetadata(containerApi, name, meta);
}
}
- public void deleteMetadata() throws Exception {
+ public void testDeleteMetadata() throws Exception {
+ Map<String, String> meta = ImmutableMap.of("MyDelete1", "foo", "MyDelete2", "bar");
+
for (String regionId : regions) {
ContainerApi containerApi = api.containerApiInRegion(regionId);
-
- Map<String, String> meta = ImmutableMap.of("MyDelete1", "foo", "MyDelete2", "bar");
-
+ // update
assertTrue(containerApi.updateMetadata(name, meta));
containerHasMetadata(containerApi, name, meta);
-
+ // delete
assertTrue(containerApi.deleteMetadata(name, meta));
Container container = containerApi.get(name);
for (Entry<String, String> entry : meta.entrySet()) {
// note keys are returned in lower-case!
- assertFalse(container.metadata().containsKey(entry.getKey().toLowerCase()));
+ assertFalse(container.getMetadata().containsKey(entry.getKey().toLowerCase()));
}
}
}
@@ -109,7 +110,7 @@
Container container = containerApi.get(name);
for (Entry<String, String> entry : meta.entrySet()) {
// note keys are returned in lower-case!
- assertEquals(container.metadata().get(entry.getKey().toLowerCase()), entry.getValue(), //
+ assertEquals(container.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue(),
container + " didn't have metadata: " + entry);
}
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiMockTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiMockTest.java
index b52122d..752b4b7 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiMockTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiMockTest.java
@@ -17,8 +17,15 @@
package org.jclouds.openstack.swift.v1.features;
import static org.jclouds.openstack.swift.v1.options.CreateContainerOptions.Builder.anybodyRead;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_ACL_ANYBODY_READ;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_BYTES_USED;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_METADATA_PREFIX;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_OBJECT_COUNT;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_READ;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_REMOVE_METADATA_PREFIX;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.util.Map;
@@ -26,8 +33,9 @@
import org.jclouds.openstack.swift.v1.SwiftApi;
import org.jclouds.openstack.swift.v1.domain.Container;
-import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest;
import org.jclouds.openstack.swift.v1.options.CreateContainerOptions;
+import org.jclouds.openstack.swift.v1.options.ListContainerOptions;
+import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
@@ -36,70 +44,65 @@
import com.squareup.okhttp.mockwebserver.MockWebServer;
import com.squareup.okhttp.mockwebserver.RecordedRequest;
-@Test
+@Test(groups = "unit", testName = "ContainerApiMockTest")
public class ContainerApiMockTest extends BaseOpenStackMockTest<SwiftApi> {
-
- String containerList = "" //
- + "[\n" //
- + " {\"name\":\"test_container_1\", \"count\":2, \"bytes\":78},\n" //
- + " {\"name\":\"test_container_2\", \"count\":1, \"bytes\":17}\n" //
- + "]";
-
- public void listFirstPage() throws Exception {
+
+ public void testList() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
- server.enqueue(addCommonHeaders(new MockResponse().setBody(containerList)));
+ server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/container_list.json"))));
try {
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
- ImmutableList<Container> containers = api.containerApiInRegion("DFW").listFirstPage().toList();
- assertEquals(containers, ImmutableList.of(//
- Container.builder() //
- .name("test_container_1") //
- .objectCount(2) //
- .bytesUsed(78).build(), //
- Container.builder() //
- .name("test_container_2") //
- .objectCount(1) //
+ ImmutableList<Container> containers = api.containerApiInRegion("DFW").list().toList();
+ assertEquals(containers, ImmutableList.of(
+ Container.builder()
+ .name("test_container_1")
+ .objectCount(2)
+ .bytesUsed(78).build(),
+ Container.builder()
+ .name("test_container_2")
+ .objectCount(1)
.bytesUsed(17).build()));
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
- assertEquals(server.takeRequest().getRequestLine(),
- "GET /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/?format=json HTTP/1.1");
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "GET", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/?format=json");
} finally {
server.shutdown();
}
}
- public void listAt() throws Exception {
+ public void testListWithOptions() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
- server.enqueue(addCommonHeaders(new MockResponse().setBody(containerList)));
+ server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/container_list.json"))));
+ ListContainerOptions options = ListContainerOptions.Builder.marker("test");
+ assertNotNull(options);
+
try {
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
- ImmutableList<Container> containers = api.containerApiInRegion("DFW").listAt("test").toList();
- assertEquals(containers, ImmutableList.of(//
- Container.builder() //
- .name("test_container_1") //
- .objectCount(2) //
- .bytesUsed(78).build(), //
- Container.builder() //
- .name("test_container_2") //
- .objectCount(1) //
+ ImmutableList<Container> containers = api.containerApiInRegion("DFW").list(options).toList();
+ assertEquals(containers, ImmutableList.of(
+ Container.builder()
+ .name("test_container_1")
+ .objectCount(2)
+ .bytesUsed(78).build(),
+ Container.builder()
+ .name("test_container_2")
+ .objectCount(1)
.bytesUsed(17).build()));
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
- assertEquals(server.takeRequest().getRequestLine(),
- "GET /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/?format=json&marker=test HTTP/1.1");
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "GET", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/?format=json&marker=test");
} finally {
server.shutdown();
}
}
- public void createIfAbsent() throws Exception {
+ public void testCreateIfAbsent() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201)));
@@ -109,16 +112,14 @@
assertTrue(api.containerApiInRegion("DFW").createIfAbsent("myContainer", CreateContainerOptions.NONE));
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
- RecordedRequest createRequest = server.takeRequest();
- assertEquals(createRequest.getRequestLine(),
- "PUT /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer HTTP/1.1");
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer");
} finally {
server.shutdown();
}
}
- public void createWithOptions() throws Exception {
+ public void testCreateWithOptions() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201)));
@@ -128,20 +129,22 @@
assertTrue(api.containerApiInRegion("DFW").createIfAbsent("myContainer", anybodyRead().metadata(metadata)));
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+ assertAuthentication(server);
+
RecordedRequest createRequest = server.takeRequest();
- assertEquals(createRequest.getRequestLine(),
- "PUT /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer HTTP/1.1");
- assertEquals(createRequest.getHeader("x-container-read"), ".r:*,.rlistings");
+ assertRequest(createRequest, "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer");
+
+ assertEquals(createRequest.getHeader(CONTAINER_READ), CONTAINER_ACL_ANYBODY_READ);
+
for (Entry<String, String> entry : metadata.entrySet()) {
- assertEquals(createRequest.getHeader("x-container-meta-" + entry.getKey().toLowerCase()), entry.getValue());
+ assertEquals(createRequest.getHeader(CONTAINER_METADATA_PREFIX + entry.getKey().toLowerCase()), entry.getValue());
}
} finally {
server.shutdown();
}
}
- public void alreadyCreated() throws Exception {
+ public void testAlreadyCreated() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(202)));
@@ -151,38 +154,35 @@
assertFalse(api.containerApiInRegion("DFW").createIfAbsent("myContainer", CreateContainerOptions.NONE));
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
- RecordedRequest createRequest = server.takeRequest();
- assertEquals(createRequest.getRequestLine(),
- "PUT /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer HTTP/1.1");
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer");
} finally {
server.shutdown();
}
}
/** upper-cases first char, and lower-cases rest!! **/
- public void getKnowingServerMessesWithMetadataKeyCaseFormat() throws Exception {
+ public void testGetKnowingServerMessesWithMetadataKeyCaseFormat() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
- server.enqueue(addCommonHeaders(containerResponse() //
+ server.enqueue(addCommonHeaders(containerResponse()
// note silly casing
- .addHeader("X-Container-Meta-Apiname", "swift") //
- .addHeader("X-Container-Meta-Apiversion", "v1.1")));
+ .addHeader(CONTAINER_METADATA_PREFIX + "Apiname", "swift")
+ .addHeader(CONTAINER_METADATA_PREFIX + "Apiversion", "v1.1")));
try {
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
Container container = api.containerApiInRegion("DFW").get("myContainer");
- assertEquals(container.name(), "myContainer");
- assertEquals(container.objectCount(), 42l);
- assertEquals(container.bytesUsed(), 323479l);
- for (Entry<String, String> entry : container.metadata().entrySet()) {
- assertEquals(container.metadata().get(entry.getKey().toLowerCase()), entry.getValue());
+ assertEquals(container.getName(), "myContainer");
+ assertEquals(container.getObjectCount(), 42l);
+ assertEquals(container.getBytesUsed(), 323479l);
+ for (Entry<String, String> entry : container.getMetadata().entrySet()) {
+ assertEquals(container.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue());
}
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
- assertEquals(server.takeRequest().getRequestLine(),
- "HEAD /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer HTTP/1.1");
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "HEAD", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer");
} finally {
server.shutdown();
}
@@ -191,9 +191,9 @@
public void updateMetadata() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
- server.enqueue(addCommonHeaders(containerResponse() //
- .addHeader("X-Container-Meta-ApiName", "swift") //
- .addHeader("X-Container-Meta-ApiVersion", "v1.1")));
+ server.enqueue(addCommonHeaders(containerResponse()
+ .addHeader(CONTAINER_METADATA_PREFIX + "ApiName", "swift")
+ .addHeader(CONTAINER_METADATA_PREFIX + "ApiVersion", "v1.1")));
try {
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
@@ -205,7 +205,7 @@
assertEquals(replaceRequest.getRequestLine(),
"POST /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer HTTP/1.1");
for (Entry<String, String> entry : metadata.entrySet()) {
- assertEquals(replaceRequest.getHeader("x-container-meta-" + entry.getKey().toLowerCase()), entry.getValue());
+ assertEquals(replaceRequest.getHeader(CONTAINER_METADATA_PREFIX + entry.getKey().toLowerCase()), entry.getValue());
}
} finally {
server.shutdown();
@@ -227,7 +227,7 @@
assertEquals(deleteRequest.getRequestLine(),
"POST /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer HTTP/1.1");
for (String key : metadata.keySet()) {
- assertEquals(deleteRequest.getHeader("x-remove-container-meta-" + key.toLowerCase()), "ignored");
+ assertEquals(deleteRequest.getHeader(CONTAINER_REMOVE_METADATA_PREFIX + key.toLowerCase()), "ignored");
}
} finally {
server.shutdown();
@@ -295,8 +295,8 @@
private static final Map<String, String> metadata = ImmutableMap.of("ApiName", "swift", "ApiVersion", "v1.1");
public static MockResponse containerResponse() {
- return new MockResponse() //
- .addHeader("X-Container-Object-Count", "42") //
- .addHeader("X-Container-Bytes-Used", "323479");
+ return new MockResponse()
+ .addHeader(CONTAINER_OBJECT_COUNT, "42")
+ .addHeader(CONTAINER_BYTES_USED, "323479");
}
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/CreatePublicContainerLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/CreatePublicContainerLiveTest.java
index f6251d0..6f921ef 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/CreatePublicContainerLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/CreatePublicContainerLiveTest.java
@@ -19,19 +19,20 @@
import static org.jclouds.openstack.swift.v1.options.CreateContainerOptions.Builder.anybodyRead;
import static org.testng.Assert.assertTrue;
+import org.jclouds.openstack.swift.v1.SwiftApi;
import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
@Test(groups = "live", testName = "CreatePublicContainerLiveTest")
-public class CreatePublicContainerLiveTest extends BaseSwiftApiLiveTest {
+public class CreatePublicContainerLiveTest extends BaseSwiftApiLiveTest<SwiftApi> {
private String name = getClass().getSimpleName();
- public void anybodyReadUpdatesMetadata() throws Exception {
+ public void testAnybodyReadUpdatesMetadata() throws Exception {
for (String regionId : api.configuredRegions()) {
api.containerApiInRegion(regionId).createIfAbsent(name, anybodyRead());
- assertTrue(api.containerApiInRegion(regionId).get(name).anybodyRead().get());
+ assertTrue(api.containerApiInRegion(regionId).get(name).getAnybodyRead().get());
}
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiLiveTest.java
index 4559983..db835fd 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiLiveTest.java
@@ -35,6 +35,7 @@
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import org.jclouds.openstack.swift.v1.CopyObjectException;
+import org.jclouds.openstack.swift.v1.SwiftApi;
import org.jclouds.openstack.swift.v1.domain.ObjectList;
import org.jclouds.openstack.swift.v1.domain.SwiftObject;
import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest;
@@ -48,18 +49,22 @@
import com.google.common.collect.ImmutableMap;
/**
+ * Provides live tests for the {@link ObjectApi}.
+ *
* @author Adrian Cole
+ * @author Jeremy Daggett
*/
-@Test(groups = "live", testName = "ObjectApiLiveTest")
-public class ObjectApiLiveTest extends BaseSwiftApiLiveTest {
+@Test(groups = "live", testName = "ObjectApiLiveTest", singleThreaded = true)
+public class ObjectApiLiveTest extends BaseSwiftApiLiveTest<SwiftApi> {
+
private String name = getClass().getSimpleName();
private String containerName = getClass().getSimpleName() + "Container";
- public void copyObject() throws Exception {
- for (String regionId : regions) {
+ public void testCopyObject() throws Exception {
+ for (String regionId : regions) {
// source
String sourceContainer = "src" + containerName;
- String sourceObject = "original.txt";
+ String sourceObjectName = "original.txt";
String badSource = "badSource";
// destination
@@ -81,29 +86,29 @@
ObjectApi destApi = api.objectApiInRegionForContainer(regionId, destinationContainer);
// Create source object
- assertNotNull(srcApi.replace(sourceObject, data, ImmutableMap.<String, String> of()));
- SwiftObject object = srcApi.get(sourceObject, GetOptions.NONE);
- checkObject(object);
+ assertNotNull(srcApi.replace(sourceObjectName, data, ImmutableMap.<String, String> of()));
+ SwiftObject sourceObject = srcApi.get(sourceObjectName, GetOptions.NONE);
+ checkObject(sourceObject);
// Create the destination object
assertNotNull(destApi.replace(destinationObject, data, ImmutableMap.<String, String> of()));
- object = destApi.get(destinationObject, GetOptions.NONE);
- checkObject(destApi.get(destinationObject, GetOptions.NONE));
+ SwiftObject object = destApi.get(destinationObject, GetOptions.NONE);
+ checkObject(object);
// check the copy operation
- assertTrue(destApi.copy(destinationObject, sourceContainer, sourceObject));
+ assertTrue(destApi.copy(destinationObject, sourceContainer, sourceObjectName));
assertNotNull(destApi.head(destinationObject));
// now get a real SwiftObject
SwiftObject destSwiftObject = destApi.get(destinationObject, GetOptions.NONE);
- assertEquals(Strings2.toString(destSwiftObject.payload()), stringPayload);
+ assertEquals(Strings2.toString(destSwiftObject.getPayload()), stringPayload);
// test exception thrown on bad source name
try {
- destApi.copy(destinationObject, badSource, sourceObject);
+ destApi.copy(destinationObject, badSource, sourceObjectName);
fail("Expected CopyObjectException");
- } catch (CopyObjectException e) {
- assertEquals(e.getSourcePath(), "/" + badSource + "/" + sourceObject);
+ } catch (CopyObjectException e) {
+ assertEquals(e.getSourcePath(), "/" + badSource + "/" + sourceObjectName);
assertEquals(e.getDestinationPath(), destinationPath);
}
@@ -115,11 +120,11 @@
}
}
- public void list() throws Exception {
+ public void testList() throws Exception {
for (String regionId : regions) {
ObjectApi objectApi = api.objectApiInRegionForContainer(regionId, containerName);
- ObjectList response = objectApi.list(new ListContainerOptions());
- assertEquals(response.container(), api.containerApiInRegion(regionId).get(containerName));
+ ObjectList response = objectApi.list(ListContainerOptions.NONE);
+ assertEquals(response.getContainer(), api.containerApiInRegion(regionId).get(containerName));
assertNotNull(response);
for (SwiftObject object : response) {
checkObject(object);
@@ -127,97 +132,81 @@
}
}
- static void checkObject(SwiftObject object) {
- assertNotNull(object.name());
- assertNotNull(object.uri());
- assertNotNull(object.etag());
- assertTrue(object.lastModified().getTime() <= System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(5));
- assertNotNull(object.payload().getContentMetadata().getContentLength());
- assertNotNull(object.payload().getContentMetadata().getContentType());
- }
-
- public void metadata() throws Exception {
+ public void testMetadata() throws Exception {
for (String regionId : regions) {
SwiftObject object = api.objectApiInRegionForContainer(regionId, containerName).head(name);
- assertEquals(object.name(), name);
+ assertEquals(object.getName(), name);
checkObject(object);
- assertEquals(toStringAndClose(object.payload().getInput()), "");
+ assertEquals(toStringAndClose(object.getPayload().getInput()), "");
}
}
- public void get() throws Exception {
+ public void testUpdateMetadata() throws Exception {
+ for (String regionId : regions) {
+ ObjectApi objectApi = api.objectApiInRegionForContainer(regionId, containerName);
+
+ Map<String, String> meta = ImmutableMap.of("MyAdd1", "foo", "MyAdd2", "bar");
+ assertTrue(objectApi.updateMetadata(name, meta));
+
+ SwiftObject object = objectApi.head(name);
+ for (Entry<String, String> entry : meta.entrySet()) {
+ // note keys are returned in lower-case!
+ assertEquals(object.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue(),
+ object + " didn't have metadata: " + entry);
+ }
+ }
+ }
+
+ public void testGet() throws Exception {
for (String regionId : regions) {
SwiftObject object = api.objectApiInRegionForContainer(regionId, containerName).get(name, GetOptions.NONE);
- assertEquals(object.name(), name);
+ assertEquals(object.getName(), name);
checkObject(object);
- assertEquals(toStringAndClose(object.payload().getInput()), "swifty");
+ assertEquals(toStringAndClose(object.getPayload().getInput()), "swifty");
}
}
- public void privateByDefault() throws Exception {
+ public void testPrivateByDefault() throws Exception {
for (String regionId : regions) {
SwiftObject object = api.objectApiInRegionForContainer(regionId, containerName).head(name);
try {
- object.uri().toURL().openStream();
+ object.getUri().toURL().openStream();
fail("shouldn't be able to access " + object);
} catch (IOException expected) {
}
}
}
- public void getOptions() throws Exception {
+ public void testGetOptions() throws Exception {
for (String regionId : regions) {
SwiftObject object = api.objectApiInRegionForContainer(regionId, containerName).get(name, tail(1));
- assertEquals(object.name(), name);
+ assertEquals(object.getName(), name);
checkObject(object);
- assertEquals(toStringAndClose(object.payload().getInput()), "y");
+ assertEquals(toStringAndClose(object.getPayload().getInput()), "y");
}
}
- public void listOptions() throws Exception {
+ public void testListOptions() throws Exception {
String lexicographicallyBeforeName = name.substring(0, name.length() - 1);
for (String regionId : regions) {
SwiftObject object = api.objectApiInRegionForContainer(regionId, containerName)
.list(marker(lexicographicallyBeforeName)).get(0);
- assertEquals(object.name(), name);
+ assertEquals(object.getName(), name);
checkObject(object);
}
}
- public void updateMetadata() throws Exception {
- for (String regionId : regions) {
- ObjectApi objectApi = api.objectApiInRegionForContainer(regionId, containerName);
-
- Map<String, String> meta = ImmutableMap.of("MyAdd1", "foo", "MyAdd2", "bar");
- assertTrue(objectApi.updateMetadata(name, meta));
- containerHasMetadata(objectApi, name, meta);
- }
- }
-
- public void deleteMetadata() throws Exception {
+ public void testDeleteMetadata() throws Exception {
for (String regionId : regions) {
ObjectApi objectApi = api.objectApiInRegionForContainer(regionId, containerName);
Map<String, String> meta = ImmutableMap.of("MyDelete1", "foo", "MyDelete2", "bar");
-
+
assertTrue(objectApi.updateMetadata(name, meta));
- containerHasMetadata(objectApi, name, meta);
-
+ assertFalse(objectApi.head(name).getMetadata().isEmpty());
+
assertTrue(objectApi.deleteMetadata(name, meta));
- SwiftObject object = objectApi.head(name);
- for (Entry<String, String> entry : meta.entrySet()) {
- // note keys are returned in lower-case!
- assertFalse(object.metadata().containsKey(entry.getKey().toLowerCase()));
- }
- }
- }
-
- static void containerHasMetadata(ObjectApi objectApi, String name, Map<String, String> meta) {
- SwiftObject object = objectApi.head(name);
- for (Entry<String, String> entry : meta.entrySet()) {
- // note keys are returned in lower-case!
- assertEquals(object.metadata().get(entry.getKey().toLowerCase()), entry.getValue(), //
- object + " didn't have metadata: " + entry);
+ assertTrue(objectApi.head(name).getMetadata().isEmpty());
}
}
@@ -240,6 +229,16 @@
api.objectApiInRegionForContainer(regionId, containerName).delete(name);
api.containerApiInRegion(regionId).deleteIfEmpty(containerName);
}
+
super.tearDown();
}
+
+ static void checkObject(SwiftObject object) {
+ assertNotNull(object.getName());
+ assertNotNull(object.getUri());
+ assertNotNull(object.getEtag());
+ assertTrue(object.getLastModified().getTime() <= System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(5));
+ assertNotNull(object.getPayload().getContentMetadata().getContentLength());
+ assertNotNull(object.getPayload().getContentMetadata().getContentType());
+ }
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiMockTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiMockTest.java
index 7ceb21a..d44e308 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiMockTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiMockTest.java
@@ -22,7 +22,10 @@
import static org.jclouds.io.Payloads.newStringPayload;
import static org.jclouds.openstack.swift.v1.features.ContainerApiMockTest.containerResponse;
import static org.jclouds.openstack.swift.v1.options.ListContainerOptions.Builder.marker;
-import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.OBJECT_COPY_FROM;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_ACL_ANYBODY_READ;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_READ;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.OBJECT_METADATA_PREFIX;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.OBJECT_REMOVE_METADATA_PREFIX;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
@@ -31,12 +34,6 @@
import java.util.Map;
import java.util.Map.Entry;
-import javax.inject.Named;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-
-import org.jclouds.blobstore.BlobStoreFallbacks.FalseOnContainerNotFound;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
@@ -47,8 +44,6 @@
import org.jclouds.openstack.swift.v1.options.ListContainerOptions;
import org.jclouds.openstack.swift.v1.reference.SwiftHeaders;
import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest;
-import org.jclouds.rest.annotations.Fallback;
-import org.jclouds.rest.annotations.Headers;
import org.jclouds.util.Strings2;
import org.testng.annotations.Test;
@@ -58,68 +53,59 @@
import com.squareup.okhttp.mockwebserver.MockWebServer;
import com.squareup.okhttp.mockwebserver.RecordedRequest;
-@Test
+/**
+ * Provides mock tests for the {@link ObjectApi}.
+ *
+ * @author Adrian Cole
+ * @author Jeremy Daggett
+ */
+@Test(groups = "unit", testName = "ObjectApiMockTest")
public class ObjectApiMockTest extends BaseOpenStackMockTest<SwiftApi> {
SimpleDateFormatDateService dates = new SimpleDateFormatDateService();
- String objectList = "" //
- + "[\n" //
- + " {\"name\":\"test_obj_1\",\n" //
- + " \"hash\":\"4281c348eaf83e70ddce0e07221c3d28\",\n" //
- + " \"bytes\":14,\n" //
- + " \"content_type\":\"application\\/octet-stream\",\n" //
- + " \"last_modified\":\"2009-02-03T05:26:32.612278\"},\n" //
- + " {\"name\":\"test_obj_2\",\n" //
- + " \"hash\":\"b039efe731ad111bc1b0ef221c3849d0\",\n" //
- + " \"bytes\":64,\n" //
- + " \"content_type\":\"application\\/octet-stream\",\n" //
- + " \"last_modified\":\"2009-02-03T05:26:32.612278\"},\n" //
- + "]";
-
protected ImmutableList<SwiftObject> parsedObjectsForUrl(String baseUri) {
baseUri += "v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer";
- return ImmutableList.of(//
- SwiftObject.builder() //
- .name("test_obj_1") //
- .uri(URI.create(baseUri + "/test_obj_1")) //
- .etag("4281c348eaf83e70ddce0e07221c3d28") //
- .payload(payload(14, "application/octet-stream")) //
- .lastModified(dates.iso8601DateParse("2009-02-03T05:26:32.612278")).build(), //
- SwiftObject.builder() //
- .name("test_obj_2") //
- .uri(URI.create(baseUri + "/test_obj_2")) //
- .etag("b039efe731ad111bc1b0ef221c3849d0") //
- .payload(payload(64l, "application/octet-stream")) //
+ return ImmutableList.of(
+ SwiftObject.builder()
+ .name("test_obj_1")
+ .uri(URI.create(baseUri + "/test_obj_1"))
+ .etag("4281c348eaf83e70ddce0e07221c3d28")
+ .payload(payload(14, "application/octet-stream"))
+ .lastModified(dates.iso8601DateParse("2009-02-03T05:26:32.612278")).build(),
+ SwiftObject.builder()
+ .name("test_obj_2")
+ .uri(URI.create(baseUri + "/test_obj_2"))
+ .etag("b039efe731ad111bc1b0ef221c3849d0")
+ .payload(payload(64l, "application/octet-stream"))
.lastModified(dates.iso8601DateParse("2009-02-03T05:26:32.612278")).build());
}
- public void list() throws Exception {
+ public void testList() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
- server.enqueue(addCommonHeaders(containerResponse() //
- .addHeader("X-Container-Read", ".r:*,.rlistings") //
- .setBody(objectList)));
+ server.enqueue(addCommonHeaders(containerResponse()
+ .addHeader(CONTAINER_READ, CONTAINER_ACL_ANYBODY_READ)
+ .setBody(stringFromResource("/object_list.json"))));
try {
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
ObjectList objects = api.objectApiInRegionForContainer("DFW", "myContainer").list(new ListContainerOptions());
assertEquals(objects, parsedObjectsForUrl(server.getUrl("/").toString()));
- assertEquals(objects.container().name(), "myContainer");
- assertTrue(objects.container().anybodyRead().get());
+ assertEquals(objects.getContainer().getName(), "myContainer");
+ assertTrue(objects.getContainer().getAnybodyRead().get());
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
- assertEquals(server.takeRequest().getRequestLine(),
- "GET /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/?format=json HTTP/1.1");
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "GET", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/?format=json");
} finally {
server.shutdown();
}
}
- public void listOptions() throws Exception {
+ public void testListOptions() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
- server.enqueue(addCommonHeaders(containerResponse().setBody(objectList)));
+ server.enqueue(addCommonHeaders(containerResponse().setBody(stringFromResource("/object_list.json"))));
try {
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
@@ -127,19 +113,18 @@
assertEquals(objects, parsedObjectsForUrl(server.getUrl("/").toString()));
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
- assertEquals(server.takeRequest().getRequestLine(),
- "GET /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/?format=json&marker=test HTTP/1.1");
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "GET", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/?format=json&marker=test");
} finally {
server.shutdown();
}
}
- public void replace() throws Exception {
+ public void testReplace() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
- server.enqueue(addCommonHeaders(new MockResponse() //
- .setResponseCode(201) //
+ server.enqueue(addCommonHeaders(new MockResponse()
+ .setResponseCode(201)
.addHeader("ETag", "d9f5eb4bba4e2f2f046e54611bc8196b")));
try {
@@ -149,13 +134,13 @@
newStringPayload("swifty"), metadata), "d9f5eb4bba4e2f2f046e54611bc8196b");
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+ assertAuthentication(server);
RecordedRequest replace = server.takeRequest();
- assertEquals(replace.getRequestLine(),
- "PUT /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject HTTP/1.1");
+ assertRequest(replace, "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject");
+
assertEquals(new String(replace.getBody()), "swifty");
for (Entry<String, String> entry : metadata.entrySet()) {
- assertEquals(replace.getHeader("x-object-meta-" + entry.getKey().toLowerCase()), entry.getValue());
+ assertEquals(replace.getHeader(OBJECT_METADATA_PREFIX + entry.getKey().toLowerCase()), entry.getValue());
}
} finally {
server.shutdown();
@@ -163,31 +148,30 @@
}
/** upper-cases first char, and lower-cases rest!! **/
- public void headKnowingServerMessesWithMetadataKeyCaseFormat() throws Exception {
+ public void testHeadKnowingServerMessesWithMetadataKeyCaseFormat() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
- server.enqueue(addCommonHeaders(objectResponse() //
+ server.enqueue(addCommonHeaders(objectResponse()
// note silly casing
- .addHeader("X-Object-Meta-Apiname", "swift") //
- .addHeader("X-Object-Meta-Apiversion", "v1.1")));
+ .addHeader(OBJECT_METADATA_PREFIX + "Apiname", "swift")
+ .addHeader(OBJECT_METADATA_PREFIX + "Apiversion", "v1.1")));
try {
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
SwiftObject object = api.objectApiInRegionForContainer("DFW", "myContainer").head("myObject");
- assertEquals(object.name(), "myObject");
- assertEquals(object.etag(), "8a964ee2a5e88be344f36c22562a6486");
- assertEquals(object.lastModified(), dates.rfc822DateParse("Fri, 12 Jun 2010 13:40:18 GMT"));
- for (Entry<String, String> entry : object.metadata().entrySet()) {
- assertEquals(object.metadata().get(entry.getKey().toLowerCase()), entry.getValue());
+ assertEquals(object.getName(), "myObject");
+ assertEquals(object.getEtag(), "8a964ee2a5e88be344f36c22562a6486");
+ assertEquals(object.getLastModified(), dates.rfc822DateParse("Fri, 12 Jun 2010 13:40:18 GMT"));
+ for (Entry<String, String> entry : object.getMetadata().entrySet()) {
+ assertEquals(object.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue());
}
- assertEquals(object.payload().getContentMetadata().getContentLength(), new Long(4));
- assertEquals(object.payload().getContentMetadata().getContentType(), "text/plain; charset=UTF-8");
- assertEquals(Strings2.toStringAndClose(object.payload().getInput()), "");
+ assertEquals(object.getPayload().getContentMetadata().getContentLength(), new Long(4));
+ assertEquals(object.getPayload().getContentMetadata().getContentType(), "text/plain; charset=UTF-8");
+ assertEquals(Strings2.toStringAndClose(object.getPayload().getInput()), "");
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
- assertEquals(server.takeRequest().getRequestLine(),
- "HEAD /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject HTTP/1.1");
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "HEAD", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject");
} finally {
server.shutdown();
}
@@ -196,24 +180,24 @@
public void get() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
- server.enqueue(addCommonHeaders(objectResponse() //
+ server.enqueue(addCommonHeaders(objectResponse()
// note silly casing
- .addHeader("X-Object-Meta-Apiname", "swift") //
- .addHeader("X-Object-Meta-Apiversion", "v1.1")));
+ .addHeader(OBJECT_METADATA_PREFIX + "Apiname", "swift")
+ .addHeader(OBJECT_METADATA_PREFIX + "Apiversion", "v1.1")));
try {
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
SwiftObject object = api.objectApiInRegionForContainer("DFW", "myContainer").get("myObject", tail(1));
- assertEquals(object.name(), "myObject");
- assertEquals(object.etag(), "8a964ee2a5e88be344f36c22562a6486");
- assertEquals(object.lastModified(), dates.rfc822DateParse("Fri, 12 Jun 2010 13:40:18 GMT"));
- for (Entry<String, String> entry : object.metadata().entrySet()) {
- assertEquals(object.metadata().get(entry.getKey().toLowerCase()), entry.getValue());
+ assertEquals(object.getName(), "myObject");
+ assertEquals(object.getEtag(), "8a964ee2a5e88be344f36c22562a6486");
+ assertEquals(object.getLastModified(), dates.rfc822DateParse("Fri, 12 Jun 2010 13:40:18 GMT"));
+ for (Entry<String, String> entry : object.getMetadata().entrySet()) {
+ assertEquals(object.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue());
}
- assertEquals(object.payload().getContentMetadata().getContentLength(), new Long(4));
- assertEquals(object.payload().getContentMetadata().getContentType(), "text/plain; charset=UTF-8");
+ assertEquals(object.getPayload().getContentMetadata().getContentLength(), new Long(4));
+ assertEquals(object.getPayload().getContentMetadata().getContentType(), "text/plain; charset=UTF-8");
// note MWS doesn't process Range header at the moment
- assertEquals(Strings2.toStringAndClose(object.payload().getInput()), "ABCD");
+ assertEquals(Strings2.toStringAndClose(object.getPayload().getInput()), "ABCD");
assertEquals(server.getRequestCount(), 2);
assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
@@ -229,9 +213,9 @@
public void updateMetadata() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
- server.enqueue(addCommonHeaders(objectResponse() //
- .addHeader("X-Object-Meta-ApiName", "swift") //
- .addHeader("X-Object-Meta-ApiVersion", "v1.1")));
+ server.enqueue(addCommonHeaders(objectResponse()
+ .addHeader(OBJECT_METADATA_PREFIX + "ApiName", "swift")
+ .addHeader(OBJECT_METADATA_PREFIX + "ApiVersion", "v1.1")));
try {
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
@@ -243,7 +227,7 @@
assertEquals(replaceRequest.getRequestLine(),
"POST /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject HTTP/1.1");
for (Entry<String, String> entry : metadata.entrySet()) {
- assertEquals(replaceRequest.getHeader("x-object-meta-" + entry.getKey().toLowerCase()), entry.getValue());
+ assertEquals(replaceRequest.getHeader(OBJECT_METADATA_PREFIX + entry.getKey().toLowerCase()), entry.getValue());
}
} finally {
server.shutdown();
@@ -265,7 +249,7 @@
assertEquals(deleteRequest.getRequestLine(),
"POST /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject HTTP/1.1");
for (String key : metadata.keySet()) {
- assertEquals(deleteRequest.getHeader("x-remove-object-meta-" + key.toLowerCase()), "ignored");
+ assertEquals(deleteRequest.getHeader(OBJECT_REMOVE_METADATA_PREFIX + key.toLowerCase()), "ignored");
}
} finally {
server.shutdown();
@@ -350,12 +334,12 @@
private static final Map<String, String> metadata = ImmutableMap.of("ApiName", "swift", "ApiVersion", "v1.1");
public static MockResponse objectResponse() {
- return new MockResponse() //
- .addHeader("Last-Modified", "Fri, 12 Jun 2010 13:40:18 GMT") //
- .addHeader("ETag", "8a964ee2a5e88be344f36c22562a6486") //
+ return new MockResponse()
+ .addHeader("Last-Modified", "Fri, 12 Jun 2010 13:40:18 GMT")
+ .addHeader("ETag", "8a964ee2a5e88be344f36c22562a6486")
// TODO: MWS doesn't allow you to return content length w/o content
// on HEAD!
- .setBody("ABCD".getBytes(US_ASCII)) //
+ .setBody("ABCD".getBytes(US_ASCII))
.addHeader("Content-Length", "4").addHeader("Content-Type", "text/plain; charset=UTF-8");
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/StaticLargeObjectApiLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/StaticLargeObjectApiLiveTest.java
index eb08f76..aa6f434 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/StaticLargeObjectApiLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/StaticLargeObjectApiLiveTest.java
@@ -19,12 +19,12 @@
import static java.lang.String.format;
import static org.jclouds.io.Payloads.newPayload;
import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotEquals;
import static org.testng.Assert.assertNotNull;
import java.util.List;
import java.util.UUID;
+import org.jclouds.openstack.swift.v1.SwiftApi;
import org.jclouds.openstack.swift.v1.domain.Segment;
import org.jclouds.openstack.swift.v1.domain.SwiftObject;
import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest;
@@ -37,20 +37,20 @@
import com.google.common.collect.ImmutableMap;
@Test(groups = "live", testName = "StaticLargeObjectApiLiveTest")
-public class StaticLargeObjectApiLiveTest extends BaseSwiftApiLiveTest {
+public class StaticLargeObjectApiLiveTest extends BaseSwiftApiLiveTest<SwiftApi> {
private String name = getClass().getSimpleName();
private String containerName = getClass().getSimpleName() + "Container";
private byte[] megOf1s;
private byte[] megOf2s;
- public void notPresentWhenDeleting() throws Exception {
+ public void testNotPresentWhenDeleting() throws Exception {
for (String regionId : regions) {
api.staticLargeObjectApiInRegionForContainer(regionId, containerName).delete(UUID.randomUUID().toString());
}
}
- public void replaceManifest() throws Exception {
+ public void testReplaceManifest() throws Exception {
for (String regionId : regions) {
ObjectApi objectApi = api.objectApiInRegionForContainer(regionId, containerName);
String etag1s = objectApi.replace(name + "/1", newPayload(megOf1s), ImmutableMap.<String, String> of());
@@ -74,23 +74,29 @@
assertNotNull(etagOfEtags);
SwiftObject bigObject = api.objectApiInRegionForContainer(regionId, containerName).head(name);
- assertNotEquals(bigObject.etag(), etagOfEtags);
- assertEquals(bigObject.payload().getContentMetadata().getContentLength(), new Long(2 * 1024 * 1024));
- assertEquals(bigObject.metadata(), ImmutableMap.of("myfoo", "Bar"));
+ assertEquals(bigObject.getEtag(), etagOfEtags);
+ assertEquals(bigObject.getPayload().getContentMetadata().getContentLength(), new Long(2 * 1024 * 1024));
+ assertEquals(bigObject.getMetadata(), ImmutableMap.of("myfoo", "Bar"));
// segments are visible
- assertEquals(api.containerApiInRegion(regionId).get(containerName).objectCount(), 3);
+ assertEquals(api.containerApiInRegion(regionId).get(containerName).getObjectCount(), 3);
}
}
- @Test(dependsOnMethods = "replaceManifest")
- public void delete() throws Exception {
+ @Test(dependsOnMethods = "testReplaceManifest")
+ public void testDelete() throws Exception {
for (String regionId : regions) {
api.staticLargeObjectApiInRegionForContainer(regionId, containerName).delete(name);
- assertEquals(api.containerApiInRegion(regionId).get(containerName).objectCount(), 0);
+ assertEquals(api.containerApiInRegion(regionId).get(containerName).getObjectCount(), 0);
}
}
+ protected void assertMegabyteAndETagMatches(String regionId, String name, String etag1s) {
+ SwiftObject object1s = api.objectApiInRegionForContainer(regionId, containerName).head(name);
+ assertEquals(object1s.getEtag(), etag1s);
+ assertEquals(object1s.getPayload().getContentMetadata().getContentLength(), new Long(1024 * 1024));
+ }
+
@Override
@BeforeClass(groups = "live")
public void setup() {
@@ -119,10 +125,4 @@
}
super.tearDown();
}
-
- protected void assertMegabyteAndETagMatches(String regionId, String name, String etag1s) {
- SwiftObject object1s = api.objectApiInRegionForContainer(regionId, containerName).head(name);
- assertEquals(object1s.etag(), etag1s);
- assertEquals(object1s.payload().getContentMetadata().getContentLength(), new Long(1024 * 1024));
- }
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/StaticLargeObjectApiMockTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/StaticLargeObjectApiMockTest.java
index 4da10a9..a10c340 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/StaticLargeObjectApiMockTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/StaticLargeObjectApiMockTest.java
@@ -16,6 +16,7 @@
*/
package org.jclouds.openstack.swift.v1.features;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.OBJECT_METADATA_PREFIX;
import static org.testng.Assert.assertEquals;
import org.jclouds.openstack.swift.v1.SwiftApi;
@@ -30,10 +31,10 @@
import com.squareup.okhttp.mockwebserver.MockWebServer;
import com.squareup.okhttp.mockwebserver.RecordedRequest;
-@Test
+@Test(groups = "unit", testName = "StaticLargeObjectApiMockTest")
public class StaticLargeObjectApiMockTest extends BaseOpenStackMockTest<SwiftApi> {
- public void replaceManifest() throws Exception {
+ public void testReplaceManifest() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
server.enqueue(addCommonHeaders(new MockResponse().addHeader(HttpHeaders.ETAG, "\"abcd\"")));
@@ -54,11 +55,11 @@
ImmutableMap.of("MyFoo", "Bar")), "abcd");
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+ assertAuthentication(server);
+
RecordedRequest replaceRequest = server.takeRequest();
- assertEquals(replaceRequest.getRequestLine(),
- "PUT /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject?multipart-manifest=put HTTP/1.1");
- assertEquals(replaceRequest.getHeader("x-object-meta-myfoo"), "Bar");
+ assertRequest(replaceRequest, "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject?multipart-manifest=put");
+ assertEquals(replaceRequest.getHeader(OBJECT_METADATA_PREFIX + "myfoo"), "Bar");
assertEquals(
new String(replaceRequest.getBody()),
"[{\"path\":\"/mycontainer/objseg1\",\"etag\":\"0228c7926b8b642dfb29554cd1f00963\",\"size_bytes\":1468006}," +
@@ -69,7 +70,7 @@
}
}
- public void delete() throws Exception {
+ public void testDelete() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(204)));
@@ -79,16 +80,15 @@
api.staticLargeObjectApiInRegionForContainer("DFW", "myContainer").delete("myObject");
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
- RecordedRequest deleteRequest = server.takeRequest();
- assertEquals(deleteRequest.getRequestLine(),
- "DELETE /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject?multipart-manifest=delete HTTP/1.1");
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "DELETE", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject?multipart-manifest=delete");
+
} finally {
server.shutdown();
}
}
- public void alreadyDeleted() throws Exception {
+ public void testAlreadyDeleted() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
@@ -98,10 +98,8 @@
api.staticLargeObjectApiInRegionForContainer("DFW", "myContainer").delete("myObject");
assertEquals(server.getRequestCount(), 2);
- assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
- RecordedRequest deleteRequest = server.takeRequest();
- assertEquals(deleteRequest.getRequestLine(),
- "DELETE /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject?multipart-manifest=delete HTTP/1.1");
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "DELETE", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject?multipart-manifest=delete");
} finally {
server.shutdown();
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/UrlEncodeAndJoinOnNewlineTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/UrlEncodeAndJoinOnNewlineTest.java
index a45386b..c811571 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/UrlEncodeAndJoinOnNewlineTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/UrlEncodeAndJoinOnNewlineTest.java
@@ -24,7 +24,7 @@
import com.google.common.collect.ImmutableList;
-@Test
+@Test(groups = "unit", testName = "UrlEncodeAndJoinOnNewlineTest")
public class UrlEncodeAndJoinOnNewlineTest {
UrlEncodeAndJoinOnNewline binder = new UrlEncodeAndJoinOnNewline();
@@ -38,8 +38,7 @@
.add("/v1/12345678912345/mycontainer/home/xx<yy")
.add("/v1/12345678912345/mycontainer/../image.gif").build());
- assertEquals(request.getPayload().getRawContent(), "" //
- + "/v1/12345678912345/mycontainer/home/xx%3Cyy\n" //
+ assertEquals(request.getPayload().getRawContent(), "/v1/12345678912345/mycontainer/home/xx%3Cyy\n"
+ "/v1/12345678912345/mycontainer/../image.gif");
}
}
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftApiLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftApiLiveTest.java
index 239177c..6be7907 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftApiLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/internal/BaseSwiftApiLiveTest.java
@@ -21,6 +21,7 @@
import java.util.List;
import java.util.Properties;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
import org.jclouds.apis.BaseApiLiveTest;
import org.jclouds.location.reference.LocationConstants;
@@ -31,19 +32,22 @@
import org.jclouds.openstack.swift.v1.domain.SwiftObject;
import org.jclouds.openstack.swift.v1.options.ListContainerOptions;
import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Uninterruptibles;
-public class BaseSwiftApiLiveTest extends BaseApiLiveTest<SwiftApi> {
+@Test(groups = "live", testName = "BaseSwiftApiLiveTest")
+public abstract class BaseSwiftApiLiveTest<A extends SwiftApi> extends BaseApiLiveTest<A> {
protected Set<String> regions;
- public BaseSwiftApiLiveTest() {
+ protected BaseSwiftApiLiveTest() {
provider = "openstack-swift";
}
-
+
@Override
@BeforeClass(groups = "live")
public void setup() {
@@ -55,7 +59,7 @@
regions = api.configuredRegions();
}
}
-
+
@Override
protected Properties setupProperties() {
Properties props = super.setupProperties();
@@ -65,18 +69,20 @@
}
protected void deleteAllObjectsInContainer(String regionId, final String containerName) {
+ Uninterruptibles.sleepUninterruptibly(10, TimeUnit.SECONDS);
+
ObjectList objects = api.objectApiInRegionForContainer(regionId, containerName).list(new ListContainerOptions());
if (objects == null) {
return;
}
List<String> pathsToDelete = Lists.transform(objects, new Function<SwiftObject, String>() {
public String apply(SwiftObject input) {
- return containerName + "/" + input.name();
+ return containerName + "/" + input.getName();
}
});
if (!pathsToDelete.isEmpty()) {
BulkDeleteResponse response = api.bulkApiInRegion(regionId).bulkDelete(pathsToDelete);
- checkState(response.errors().isEmpty(), "Errors deleting paths %s: %s", pathsToDelete, response);
+ checkState(response.getErrors().isEmpty(), "Errors deleting paths %s: %s", pathsToDelete, response);
}
}
}
diff --git a/openstack-swift/src/test/resources/container_list.json b/openstack-swift/src/test/resources/container_list.json
new file mode 100644
index 0000000..554f5de
--- /dev/null
+++ b/openstack-swift/src/test/resources/container_list.json
@@ -0,0 +1,12 @@
+[
+ {
+ "name": "test_container_1",
+ "count": 2,
+ "bytes": 78
+ },
+ {
+ "name": "test_container_2",
+ "count": 1,
+ "bytes": 17
+ }
+]
diff --git a/openstack-swift/src/test/resources/object_list.json b/openstack-swift/src/test/resources/object_list.json
new file mode 100644
index 0000000..9cac144
--- /dev/null
+++ b/openstack-swift/src/test/resources/object_list.json
@@ -0,0 +1,16 @@
+[
+ {
+ "name": "test_obj_1",
+ "hash": "4281c348eaf83e70ddce0e07221c3d28",
+ "bytes": 14,
+ "content_type": "application/octet-stream",
+ "last_modified": "2009-02-03T05:26:32.612278"
+ },
+ {
+ "name": "test_obj_2",
+ "hash": "b039efe731ad111bc1b0ef221c3849d0",
+ "bytes": 64,
+ "content_type": "application/octet-stream",
+ "last_modified": "2009-02-03T05:26:32.612278"
+ }
+]
diff --git a/pom.xml b/pom.xml
index 1f900d6..b888796 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,6 +63,8 @@
<module>rackspace-cloudqueues-uk</module>
<module>rackspace-cloudbigdata</module>
<module>rackspace-cloudbigdata-us</module>
+ <module>rackspace-cloudfiles</module>
+ <module>rackspace-cloudfiles-us</module>
</modules>
<build>
diff --git a/rackspace-cloudfiles-us/README.md b/rackspace-cloudfiles-us/README.md
new file mode 100644
index 0000000..25ded8c
--- /dev/null
+++ b/rackspace-cloudfiles-us/README.md
@@ -0,0 +1,20 @@
+Rackspace Cloud Files US
+========================
+
+The new Rackspace Cloud Files US multi-region based provider.
+
+This new "rackspace-cloudfiles-us" provider supercedes the jclouds "cloudfiles-us" provider, which will eventually be deprecated.
+
+With this multi-region support, each BlobStore can be isolated to a specific region:
+
+ RegionScopedBlobStoreContext ctx =
+ contextBuilder.buildView(RegionScopedBlobStoreContext.class);
+
+ Set<String> regionIds = ctx.configuredRegions();
+
+ // isolated to a specific region
+ BlobStore dfwBlobStore = ctx.blobStoreInRegion("DFW");
+ BlobStore iadBlobStore = ctx.blobStoreInRegion("IAD");
+
+Production ready?
+No
diff --git a/rackspace-cloudfiles-us/pom.xml b/rackspace-cloudfiles-us/pom.xml
new file mode 100644
index 0000000..b882ed3
--- /dev/null
+++ b/rackspace-cloudfiles-us/pom.xml
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.jclouds</groupId>
+ <artifactId>jclouds-project</artifactId>
+ <version>1.8.0-SNAPSHOT</version>
+ </parent>
+
+ <!-- TODO: when out of labs, switch to org.jclouds.provider -->
+ <groupId>org.apache.jclouds.labs</groupId>
+ <artifactId>rackspace-cloudfiles-us</artifactId>
+ <version>1.8.0-SNAPSHOT</version>
+ <name>jclouds Rackspace Cloud Files US provider</name>
+ <description>OpenStack Object Storage implementation targeted to Rackspace Cloud Files US</description>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <!-- identity endpoint -->
+ <test.rackspace-cloudfiles-us.endpoint>https://identity.api.rackspacecloud.com/v2.0/</test.rackspace-cloudfiles-us.endpoint>
+ <test.rackspace-cloudfiles-us.api-version>1</test.rackspace-cloudfiles-us.api-version>
+ <test.rackspace-cloudfiles-us.build-version />
+ <test.rackspace-cloudfiles-us.identity>${test.rackspace-us.identity}</test.rackspace-cloudfiles-us.identity>
+ <test.rackspace-cloudfiles-us.credential>${test.rackspace-us.credential}</test.rackspace-cloudfiles-us.credential>
+ <jclouds.osgi.export>org.jclouds.rackspace.cloudfiles.us*;version="${project.version}"</jclouds.osgi.export>
+ <jclouds.osgi.import>
+ org.jclouds.rest.internal;version="${jclouds.version}",
+ org.jclouds.labs*;version="${project.version}",
+ org.jclouds*;version="${jclouds.version}",
+ *
+ </jclouds.osgi.import>
+ </properties>
+
+ <repositories>
+ <repository>
+ <id>apache-snapshots</id>
+ <url>https://repository.apache.org/content/repositories/snapshots</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.jclouds.labs</groupId>
+ <artifactId>openstack-swift</artifactId>
+ <version>${project.parent.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.labs</groupId>
+ <artifactId>openstack-swift</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.labs</groupId>
+ <artifactId>rackspace-cloudfiles</artifactId>
+ <version>${project.parent.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.labs</groupId>
+ <artifactId>rackspace-cloudfiles</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.api</groupId>
+ <artifactId>openstack-keystone</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.api</groupId>
+ <artifactId>openstack-keystone</artifactId>
+ <version>${project.parent.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds</groupId>
+ <artifactId>jclouds-blobstore</artifactId>
+ <version>${project.parent.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds</groupId>
+ <artifactId>jclouds-core</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds</groupId>
+ <artifactId>jclouds-core</artifactId>
+ <version>${project.parent.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.driver</groupId>
+ <artifactId>jclouds-slf4j</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.api</groupId>
+ <artifactId>rackspace-cloudidentity</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>live</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>integration</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <forkCount>5</forkCount>
+ <reuseForks>true</reuseForks>
+ <parallel>classes</parallel>
+ <systemPropertyVariables>
+ <test.rackspace-cloudfiles-us.endpoint>${test.rackspace-cloudfiles-us.endpoint}</test.rackspace-cloudfiles-us.endpoint>
+ <test.rackspace-cloudfiles-us.api-version>${test.rackspace-cloudfiles-us.api-version}</test.rackspace-cloudfiles-us.api-version>
+ <test.rackspace-cloudfiles-us.build-version>${test.rackspace-cloudfiles-us.build-version}</test.rackspace-cloudfiles-us.build-version>
+ <test.rackspace-cloudfiles-us.identity>${test.rackspace-cloudfiles-us.identity}</test.rackspace-cloudfiles-us.identity>
+ <test.rackspace-cloudfiles-us.credential>${test.rackspace-cloudfiles-us.credential}</test.rackspace-cloudfiles-us.credential>
+ <jclouds.blobstore.httpstream.url>${jclouds.blobstore.httpstream.url}</jclouds.blobstore.httpstream.url>
+ <jclouds.blobstore.httpstream.md5>${jclouds.blobstore.httpstream.md5}</jclouds.blobstore.httpstream.md5>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/rackspace-cloudfiles-us/src/main/java/org/jclouds/rackspace/cloudfiles/us/CloudFilesUSProviderMetadata.java b/rackspace-cloudfiles-us/src/main/java/org/jclouds/rackspace/cloudfiles/us/CloudFilesUSProviderMetadata.java
new file mode 100644
index 0000000..beb9521
--- /dev/null
+++ b/rackspace-cloudfiles-us/src/main/java/org/jclouds/rackspace/cloudfiles/us/CloudFilesUSProviderMetadata.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.us;
+
+import static org.jclouds.location.reference.LocationConstants.ISO3166_CODES;
+import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGION;
+import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS;
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
+import static org.jclouds.reflect.Reflection2.typeToken;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.RegionModule;
+import org.jclouds.openstack.swift.v1.blobstore.RegionScopedBlobStoreContext;
+import org.jclouds.openstack.swift.v1.blobstore.config.SignUsingTemporaryUrls;
+import org.jclouds.openstack.swift.v1.blobstore.config.SwiftBlobStoreContextModule;
+import org.jclouds.openstack.swift.v1.config.SwiftTypeAdapters;
+import org.jclouds.openstack.v2_0.ServiceType;
+import org.jclouds.providers.ProviderMetadata;
+import org.jclouds.providers.internal.BaseProviderMetadata;
+import org.jclouds.rackspace.cloudfiles.v1.CloudFilesApiMetadata;
+import org.jclouds.rackspace.cloudfiles.v1.config.CloudFilesHttpApiModule;
+import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityAuthenticationApiModule;
+import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityAuthenticationModule;
+import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityCredentialTypes;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+/**
+ * Implementation of {@link ProviderMetadata} for Rackspace Cloud Files US regions.
+ *
+ * @author Jeremy Daggett
+ */
+public class CloudFilesUSProviderMetadata extends BaseProviderMetadata {
+
+ /**
+ * @return The Builder object.
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public Builder toBuilder() {
+ return builder().fromProviderMetadata(this);
+ }
+
+ /**
+ * Provider constructor.
+ */
+ public CloudFilesUSProviderMetadata() {
+ this(new Builder());
+ }
+
+ /**
+ * @param builder the Builder for the provider.
+ */
+ protected CloudFilesUSProviderMetadata(Builder builder) {
+ super(builder);
+ }
+
+ /**
+ * @return a {@link Properties} object containing the default provider properties.
+ */
+ public static Properties defaultProperties() {
+ Properties properties = new Properties();
+ properties.setProperty(CREDENTIAL_TYPE, CloudIdentityCredentialTypes.API_KEY_CREDENTIALS);
+ properties.setProperty(SERVICE_TYPE, ServiceType.OBJECT_STORE);
+
+ properties.setProperty(PROPERTY_REGIONS, "ORD,DFW,IAD,SYD,HKG");
+ properties.setProperty(PROPERTY_REGION + ".ORD." + ISO3166_CODES, "US-IL");
+ properties.setProperty(PROPERTY_REGION + ".DFW." + ISO3166_CODES, "US-TX");
+ properties.setProperty(PROPERTY_REGION + ".IAD." + ISO3166_CODES, "US-VA");
+ properties.setProperty(PROPERTY_REGION + ".SYD." + ISO3166_CODES, "AU-NSW");
+ properties.setProperty(PROPERTY_REGION + ".HKG." + ISO3166_CODES, "HK");
+
+ return properties;
+ }
+
+ /**
+ * Builder pattern class.
+ */
+ public static class Builder extends BaseProviderMetadata.Builder {
+
+ protected Builder() {
+ id("rackspace-cloudfiles-us")
+ .name("Rackspace Cloud Files US")
+ .apiMetadata(new CloudFilesApiMetadata().toBuilder()
+ .identityName("${userName}")
+ .credentialName("${apiKey}")
+ .defaultEndpoint("https://identity.api.rackspacecloud.com/v2.0/")
+ .documentation(URI.create("http://docs.rackspace.com/files/api/v1/cf-devguide/content/index.html"))
+ .endpointName("Rackspace Cloud Identity service URL ending in /v2.0/")
+ .version("1.0")
+ .view(typeToken(RegionScopedBlobStoreContext.class))
+ .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
+ .add(CloudIdentityAuthenticationApiModule.class)
+ .add(CloudIdentityAuthenticationModule.class)
+ .add(RegionModule.class)
+ .add(SwiftTypeAdapters.class)
+ .add(CloudFilesHttpApiModule.class)
+ .add(SwiftBlobStoreContextModule.class)
+ .add(SignUsingTemporaryUrls.class)
+ .build())
+ .build())
+ .homepage(URI.create("http://www.rackspace.com/cloud/files"))
+ .console(URI.create("https://mycloud.rackspace.com"))
+ .linkedServices("rackspace-autoscale-us", "rackspace-cloudblockstorage-us",
+ "rackspace-clouddatabases-us", "rackspace-clouddns-us",
+ "rackspace-cloudidentity", "rackspace-cloudloadbalancers-us",
+ "rackspace-cloudqueues-us")
+ .iso3166Codes("US-IL", "US-TX", "US-VA", "AU-NSW", "HK")
+ .defaultProperties(CloudFilesUSProviderMetadata.defaultProperties());
+
+ }
+
+ @Override
+ public CloudFilesUSProviderMetadata build() {
+ return new CloudFilesUSProviderMetadata(this);
+ }
+
+ @Override
+ public Builder fromProviderMetadata(ProviderMetadata in) {
+ super.fromProviderMetadata(in);
+ return this;
+ }
+ }
+}
diff --git a/rackspace-cloudfiles-us/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata b/rackspace-cloudfiles-us/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
new file mode 100644
index 0000000..cf4c3b4
--- /dev/null
+++ b/rackspace-cloudfiles-us/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+org.jclouds.rackspace.cloudfiles.us.CloudFilesUSProviderMetadata
diff --git a/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/CloudFilesUSProviderTest.java b/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/CloudFilesUSProviderTest.java
new file mode 100644
index 0000000..05d036a
--- /dev/null
+++ b/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/CloudFilesUSProviderTest.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.us;
+
+import org.jclouds.providers.internal.BaseProviderMetadataTest;
+import org.jclouds.rackspace.cloudfiles.us.CloudFilesUSProviderMetadata;
+import org.jclouds.rackspace.cloudfiles.v1.CloudFilesApiMetadata;
+import org.testng.annotations.Test;
+
+@Test(groups = "unit", testName = "CloudFilesUSProviderTest")
+public class CloudFilesUSProviderTest extends BaseProviderMetadataTest {
+ public CloudFilesUSProviderTest() {
+ super(new CloudFilesUSProviderMetadata(), new CloudFilesApiMetadata());
+ }
+}
diff --git a/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSBlobIntegrationLiveTest.java b/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSBlobIntegrationLiveTest.java
new file mode 100644
index 0000000..b684e89
--- /dev/null
+++ b/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSBlobIntegrationLiveTest.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.us.blobstore.integration;
+
+import org.jclouds.rackspace.cloudfiles.v1.blobstore.integration.CloudFilesBlobIntegrationLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudFilesUSBlobIntegrationLiveTest")
+public class CloudFilesUSBlobIntegrationLiveTest extends CloudFilesBlobIntegrationLiveTest {
+ public CloudFilesUSBlobIntegrationLiveTest() {
+ provider = "rackspace-cloudfiles-us";
+ }
+}
diff --git a/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSBlobLiveTest.java b/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSBlobLiveTest.java
new file mode 100644
index 0000000..8eb5385
--- /dev/null
+++ b/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSBlobLiveTest.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.us.blobstore.integration;
+
+import org.jclouds.rackspace.cloudfiles.v1.blobstore.integration.CloudFilesBlobLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudFilesUSBlobLiveTest")
+public class CloudFilesUSBlobLiveTest extends CloudFilesBlobLiveTest {
+ public CloudFilesUSBlobLiveTest() {
+ provider = "rackspace-cloudfiles-us";
+ }
+}
diff --git a/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSBlobSignerLiveTest.java b/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSBlobSignerLiveTest.java
new file mode 100644
index 0000000..5255de2
--- /dev/null
+++ b/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSBlobSignerLiveTest.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.us.blobstore.integration;
+
+import org.jclouds.rackspace.cloudfiles.v1.blobstore.integration.CloudFilesBlobSignerLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudFilesUSBlobSignerLiveTest")
+public class CloudFilesUSBlobSignerLiveTest extends CloudFilesBlobSignerLiveTest {
+ public CloudFilesUSBlobSignerLiveTest() {
+ provider = "rackspace-cloudfiles-us";
+ }
+}
diff --git a/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSContainerIntegrationLiveTest.java b/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSContainerIntegrationLiveTest.java
new file mode 100644
index 0000000..2fe511e
--- /dev/null
+++ b/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSContainerIntegrationLiveTest.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.us.blobstore.integration;
+
+import org.jclouds.rackspace.cloudfiles.v1.blobstore.integration.CloudFilesContainerIntegrationLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudFilesUSContainerIntegrationLiveTest")
+public class CloudFilesUSContainerIntegrationLiveTest extends CloudFilesContainerIntegrationLiveTest {
+ public CloudFilesUSContainerIntegrationLiveTest() {
+ provider = "rackspace-cloudfiles-us";
+ }
+}
diff --git a/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSContainerLiveTest.java b/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSContainerLiveTest.java
new file mode 100644
index 0000000..44daffd
--- /dev/null
+++ b/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSContainerLiveTest.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.us.blobstore.integration;
+
+import org.jclouds.rackspace.cloudfiles.v1.blobstore.integration.CloudFilesContainerLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudFilesUSContainerLiveTest")
+public class CloudFilesUSContainerLiveTest extends CloudFilesContainerLiveTest {
+ public CloudFilesUSContainerLiveTest() {
+ provider = "rackspace-cloudfiles-us";
+ }
+}
diff --git a/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSServiceIntegrationLiveTest.java b/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSServiceIntegrationLiveTest.java
new file mode 100644
index 0000000..698b733
--- /dev/null
+++ b/rackspace-cloudfiles-us/src/test/java/org/jclouds/rackspace/cloudfiles/us/blobstore/integration/CloudFilesUSServiceIntegrationLiveTest.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.us.blobstore.integration;
+
+import java.util.Set;
+
+import org.jclouds.rackspace.cloudfiles.v1.blobstore.integration.CloudFilesServiceIntegrationLiveTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+@Test(groups = "live", testName = "CloudFilesUSServiceIntegrationLiveTest")
+public class CloudFilesUSServiceIntegrationLiveTest extends CloudFilesServiceIntegrationLiveTest {
+ public CloudFilesUSServiceIntegrationLiveTest() {
+ provider = "rackspace-cloudfiles-us";
+ }
+
+ @Override
+ protected Set<String> getIso3166Codes() {
+ return ImmutableSet.<String> of("US-IL", "US-TX", "US-VA", "AU-NSW", "HK");
+ }
+}
diff --git a/rackspace-cloudfiles-us/src/test/resources/logback.xml b/rackspace-cloudfiles-us/src/test/resources/logback.xml
new file mode 100644
index 0000000..ce891f1
--- /dev/null
+++ b/rackspace-cloudfiles-us/src/test/resources/logback.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+
+-->
+<configuration scan="false">
+ <appender name="FILE" class="ch.qos.logback.core.FileAppender">
+ <file>target/test-data/jclouds.log</file>
+
+ <encoder>
+ <Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
+ </encoder>
+ </appender>
+
+ <appender name="WIREFILE" class="ch.qos.logback.core.FileAppender">
+ <file>target/test-data/jclouds-wire.log</file>
+
+ <encoder>
+ <Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
+ </encoder>
+ </appender>
+
+ <appender name="BLOBSTOREFILE" class="ch.qos.logback.core.FileAppender">
+ <file>target/test-data/jclouds-blobstore.log</file>
+
+ <encoder>
+ <Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
+ </encoder>
+ </appender>
+
+ <root>
+ <level value="warn" />
+ </root>
+
+ <logger name="org.jclouds">
+ <level value="DEBUG" />
+ <appender-ref ref="FILE" />
+ </logger>
+
+<!--
+ <logger name="jclouds.wire">
+ <level value="DEBUG" />
+ <appender-ref ref="WIREFILE" />
+ </logger>
+-->
+
+ <logger name="jclouds.headers">
+ <level value="DEBUG" />
+ <appender-ref ref="WIREFILE" />
+ </logger>
+
+ <logger name="jclouds.blobstore">
+ <level value="DEBUG" />
+ <appender-ref ref="BLOBSTOREFILE" />
+ </logger>
+
+</configuration>
diff --git a/rackspace-cloudfiles/README.md b/rackspace-cloudfiles/README.md
new file mode 100644
index 0000000..1142323
--- /dev/null
+++ b/rackspace-cloudfiles/README.md
@@ -0,0 +1,20 @@
+Rackspace Cloud Files
+==========================
+
+The new Rackspace Cloud Files multi-region based service API.
+
+This new "rackspace-cloudfiles" API supercedes the jclouds "cloudfiles" API, which will eventually be deprecated.
+
+With this multi-region support, each BlobStore can be isolated to a specific region:
+
+ RegionScopedBlobStoreContext ctx =
+ contextBuilder.buildView(RegionScopedBlobStoreContext.class);
+
+ Set<String> regionIds = ctx.configuredRegions();
+
+ // isolated to a specific region
+ BlobStore dfwBlobStore = ctx.blobStoreInRegion("DFW");
+ BlobStore iadBlobStore = ctx.blobStoreInRegion("IAD");
+
+Production ready?
+No
diff --git a/rackspace-cloudfiles/pom.xml b/rackspace-cloudfiles/pom.xml
new file mode 100644
index 0000000..59662c9
--- /dev/null
+++ b/rackspace-cloudfiles/pom.xml
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.jclouds</groupId>
+ <artifactId>jclouds-project</artifactId>
+ <version>1.8.0-SNAPSHOT</version>
+ </parent>
+
+ <!-- TODO: when out of labs, switch to org.jclouds.api -->
+ <groupId>org.apache.jclouds.labs</groupId>
+ <artifactId>rackspace-cloudfiles</artifactId>
+ <version>1.8.0-SNAPSHOT</version>
+ <name>jclouds rackspace-cloudfiles api</name>
+ <description>jclouds components to access Rackspace Cloud Files</description>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <!-- identity endpoint -->
+ <test.rackspace-cloudfiles.endpoint>https://identity.api.rackspacecloud.com/v2.0/</test.rackspace-cloudfiles.endpoint>
+ <test.rackspace-cloudfiles.api-version>1</test.rackspace-cloudfiles.api-version>
+ <test.rackspace-cloudfiles.build-version />
+ <test.rackspace-cloudfiles.identity>FIXME_IDENTITY</test.rackspace-cloudfiles.identity>
+ <test.rackspace-cloudfiles.credential>FIXME_CREDENTIALS</test.rackspace-cloudfiles.credential>
+ <jclouds.osgi.export>org.jclouds.rackspace.cloudfiles.v1*;version="${project.version}"</jclouds.osgi.export>
+ <jclouds.osgi.import>org.jclouds*;version="${jclouds.version}",*</jclouds.osgi.import>
+ </properties>
+
+ <repositories>
+ <repository>
+ <id>apache-snapshots</id>
+ <url>https://repository.apache.org/content/repositories/snapshots</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.jclouds.labs</groupId>
+ <artifactId>openstack-swift</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.labs</groupId>
+ <artifactId>openstack-swift</artifactId>
+ <version>${project.parent.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.api</groupId>
+ <artifactId>openstack-keystone</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.api</groupId>
+ <artifactId>openstack-keystone</artifactId>
+ <version>${project.parent.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.api</groupId>
+ <artifactId>rackspace-cloudidentity</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds</groupId>
+ <artifactId>jclouds-core</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds</groupId>
+ <artifactId>jclouds-core</artifactId>
+ <version>${project.parent.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds</groupId>
+ <artifactId>jclouds-blobstore</artifactId>
+ <version>${project.parent.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.shrinkwrap</groupId>
+ <artifactId>shrinkwrap-depchain</artifactId>
+ <version>1.2.0</version>
+ <type>pom</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jclouds.driver</groupId>
+ <artifactId>jclouds-slf4j</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.squareup.okhttp</groupId>
+ <artifactId>mockwebserver</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>live</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>integration</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <forkCount>5</forkCount>
+ <reuseForks>true</reuseForks>
+ <parallel>classes</parallel>
+ <systemPropertyVariables>
+ <test.rackspace-cloudfiles.endpoint>${test.rackspace-cloudfiles.endpoint}</test.rackspace-cloudfiles.endpoint>
+ <test.rackspace-cloudfiles.api-version>${test.rackspace-cloudfiles.api-version}</test.rackspace-cloudfiles.api-version>
+ <test.rackspace-cloudfiles.build-version>${test.rackspace-cloudfiles.build-version}</test.rackspace-cloudfiles.build-version>
+ <test.rackspace-cloudfiles.identity>${test.rackspace-cloudfiles.identity}</test.rackspace-cloudfiles.identity>
+ <test.rackspace-cloudfiles.credential>${test.rackspace-cloudfiles.credential}</test.rackspace-cloudfiles.credential>
+ <jclouds.blobstore.httpstream.url>${jclouds.blobstore.httpstream.url}</jclouds.blobstore.httpstream.url>
+ <jclouds.blobstore.httpstream.md5>${jclouds.blobstore.httpstream.md5}</jclouds.blobstore.httpstream.md5>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/CloudFilesApi.java b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/CloudFilesApi.java
new file mode 100644
index 0000000..19667d7
--- /dev/null
+++ b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/CloudFilesApi.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.openstack.swift.v1.SwiftApi;
+import org.jclouds.rackspace.cloudfiles.v1.features.CDNApi;
+import org.jclouds.rackspace.cloudfiles.v1.functions.RegionToCDNEndpoint;
+import org.jclouds.rest.annotations.Delegate;
+import org.jclouds.rest.annotations.EndpointParam;
+
+/**
+ * Rackspace Cloud Files is an affordable, redundant, scalable, and dynamic storage service
+ * offering. The core storage system is designed to provide a secure, network-accessible way to
+ * store an unlimited number of files. Each file can be as large as 5 gigabytes.
+ * <p/>
+ * Additionally, Cloud Files provides a simple yet powerful way to publish and distribute content
+ * behind a Content Distribution Network.
+ *
+ * @author Jeremy Daggett
+ *
+ * @see CDNApi
+ * @see SwiftApi
+ */
+public interface CloudFilesApi extends SwiftApi {
+
+ /**
+ * Provides access to Cloud Files CDN features.
+ *
+ * @param region the region to access the CDN API.
+ *
+ * @return the {@link CDNApi} for the specified region.
+ */
+ @Delegate
+ CDNApi cdnApiInRegion(@EndpointParam(parser = RegionToCDNEndpoint.class) @Nullable String region);
+}
diff --git a/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/CloudFilesApiMetadata.java b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/CloudFilesApiMetadata.java
new file mode 100644
index 0000000..d28b40f
--- /dev/null
+++ b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/CloudFilesApiMetadata.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1;
+
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
+import static org.jclouds.reflect.Reflection2.typeToken;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.apis.ApiMetadata;
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.RegionModule;
+import org.jclouds.openstack.swift.v1.SwiftApiMetadata;
+import org.jclouds.openstack.swift.v1.blobstore.RegionScopedBlobStoreContext;
+import org.jclouds.openstack.swift.v1.blobstore.config.SignUsingTemporaryUrls;
+import org.jclouds.openstack.swift.v1.blobstore.config.SwiftBlobStoreContextModule;
+import org.jclouds.openstack.swift.v1.config.SwiftTypeAdapters;
+import org.jclouds.openstack.v2_0.ServiceType;
+import org.jclouds.rackspace.cloudfiles.v1.config.CloudFilesHttpApiModule;
+import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityAuthenticationApiModule;
+import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityAuthenticationModule;
+import org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityCredentialTypes;
+import org.jclouds.rest.internal.BaseHttpApiMetadata;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+/**
+ * Implementation of {@link ApiMetadata} for Cloud Files.
+ *
+ * @author Jeremy Daggett
+ */
+public class CloudFilesApiMetadata extends BaseHttpApiMetadata<CloudFilesApi> {
+
+ @Override
+ public Builder toBuilder() {
+ return new Builder().fromApiMetadata(this);
+ }
+
+ public CloudFilesApiMetadata() {
+ this(new Builder());
+ }
+
+ protected CloudFilesApiMetadata(Builder builder) {
+ super(builder);
+ }
+
+ public static Properties defaultProperties() {
+ Properties properties = SwiftApiMetadata.defaultProperties();
+ properties.setProperty(CREDENTIAL_TYPE, CloudIdentityCredentialTypes.API_KEY_CREDENTIALS);
+ properties.setProperty(SERVICE_TYPE, ServiceType.OBJECT_STORE);
+ return properties;
+ }
+
+ public static class Builder extends BaseHttpApiMetadata.Builder<CloudFilesApi, Builder> {
+
+ protected Builder() {
+ id("rackspace-cloudfiles")
+ .name("Rackspace Cloud Files API")
+ .identityName("${userName}")
+ .credentialName("${apiKey}")
+ .documentation(URI.create("http://docs.rackspace.com/files/api/v1/cf-devguide/content/index.html"))
+ .version("1.0")
+ .endpointName("Rackspace Cloud Identity service URL ending in /v2.0/")
+ .defaultEndpoint("https://identity.api.rackspacecloud.com/v2.0/")
+ .defaultProperties(CloudFilesApiMetadata.defaultProperties())
+ .view(typeToken(RegionScopedBlobStoreContext.class))
+ .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
+ .add(CloudIdentityAuthenticationApiModule.class)
+ .add(CloudIdentityAuthenticationModule.class)
+ .add(RegionModule.class)
+ .add(SwiftTypeAdapters.class)
+ .add(CloudFilesHttpApiModule.class)
+ .add(SwiftBlobStoreContextModule.class)
+ .add(SignUsingTemporaryUrls.class)
+ .build());
+ }
+
+ @Override
+ public CloudFilesApiMetadata build() {
+ return new CloudFilesApiMetadata(this);
+ }
+
+ @Override
+ protected Builder self() {
+ return this;
+ }
+ }
+}
diff --git a/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/binders/BindCDNPurgeEmailAddressesToHeaders.java b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/binders/BindCDNPurgeEmailAddressesToHeaders.java
new file mode 100644
index 0000000..c23f068
--- /dev/null
+++ b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/binders/BindCDNPurgeEmailAddressesToHeaders.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.binders;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rackspace.cloudfiles.v1.features.CDNApi;
+import org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders;
+import org.jclouds.rest.Binder;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMultimap;
+
+/**
+ * Binds a list of email addresses to request headers.
+ *
+ * @see {@link CDNApi#purgeObject(String, String, Iterable)}
+ *
+ * @author Jeremy Daggett
+ */
+@Singleton
+public class BindCDNPurgeEmailAddressesToHeaders implements Binder {
+ @SuppressWarnings("unchecked")
+ @Override
+ public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+ checkArgument(checkNotNull(input, "input") instanceof Iterable<?>, "this binder is only valid for Iterable!");
+ checkNotNull(request, "request");
+
+ Iterable<String> emails = (Iterable<String>) input;
+ String emailCSV = Joiner.on(", ").join((List<String>) emails);
+ ImmutableMultimap<String, String> headers =
+ ImmutableMultimap.<String, String> of(CloudFilesHeaders.CDN_PURGE_OBJECT_EMAIL, emailCSV);
+
+ return (R) request.toBuilder().replaceHeaders(headers).build();
+ }
+}
diff --git a/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/config/CloudFilesHttpApiModule.java b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/config/CloudFilesHttpApiModule.java
new file mode 100644
index 0000000..092fec9
--- /dev/null
+++ b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/config/CloudFilesHttpApiModule.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.config;
+
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.annotation.ClientError;
+import org.jclouds.http.annotation.Redirection;
+import org.jclouds.http.annotation.ServerError;
+import org.jclouds.openstack.swift.v1.SwiftApi;
+import org.jclouds.openstack.swift.v1.config.BaseSwiftHttpApiModule;
+import org.jclouds.rackspace.cloudfiles.v1.CloudFilesApi;
+import org.jclouds.rackspace.cloudfiles.v1.handlers.CloudFilesErrorHandler;
+import org.jclouds.rest.ConfiguresHttpApi;
+
+import com.google.inject.Scopes;
+
+@ConfiguresHttpApi
+public class CloudFilesHttpApiModule extends BaseSwiftHttpApiModule<CloudFilesApi> {
+
+ public CloudFilesHttpApiModule() {
+ super(CloudFilesApi.class);
+ }
+
+ @Override
+ protected void configure() {
+ super.configure();
+ bind(SwiftApi.class).to(CloudFilesApi.class).in(Scopes.SINGLETON);
+ }
+
+ @Override
+ protected void bindErrorHandlers() {
+ bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(CloudFilesErrorHandler.class);
+ bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(CloudFilesErrorHandler.class);
+ bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(CloudFilesErrorHandler.class);
+ }
+}
diff --git a/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/domain/CDNContainer.java b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/domain/CDNContainer.java
new file mode 100644
index 0000000..590bccb
--- /dev/null
+++ b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/domain/CDNContainer.java
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.domain;
+
+import static com.google.common.base.Objects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+import java.net.URI;
+
+import javax.inject.Named;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+
+/**
+ * Represents a CDN Container in Rackspace Cloud Files.
+ *
+ * @author Jeremy Daggett
+ */
+public class CDNContainer implements Comparable<CDNContainer> {
+
+ private String name;
+ @Named("cdn_enabled")
+ private boolean enabled;
+ @Named("log_retention")
+ private boolean logRetention;
+ private int ttl;
+ @Named("cdn_uri")
+ private URI uri;
+ @Named("cdn_ssl_uri")
+ private URI sslUri;
+ @Named("cdn_streaming_uri")
+ private URI streamingUri;
+ @Named("cdn_ios_uri")
+ private URI iosUri;
+
+ @ConstructorProperties({ "name", "cdn_enabled", "log_retention", "ttl", "cdn_uri", "cdn_ssl_uri", "cdn_streaming_uri", "cdn_ios_uri"})
+ public CDNContainer(String name, boolean enabled, boolean logRetention, int ttl, URI uri, URI sslUri, URI streamingUri, URI iosUri) {
+ this.name = checkNotNull(name, "name required");
+ this.enabled = enabled;
+ this.logRetention = logRetention;
+ this.ttl = ttl;
+ this.uri = checkNotNull(uri, "uri required");
+ this.sslUri = checkNotNull(sslUri, "sslUri required");
+ this.streamingUri = checkNotNull(streamingUri, "streamingUri required");
+ this.iosUri = checkNotNull(iosUri, "iosUri required");
+ }
+
+ /**
+ * <h3>NOTE</h3>
+ * The container name is not available from HEAD CDN responses and will be null.
+ *
+ * @return The name of this CDN container.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @return {@code true} if the container is CDN enabled, {@code false} if not.
+ */
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ /**
+ * @return {@code true} if the logs will be retained for this CDN container, {@code false} if not.
+ */
+ public boolean isLogRetentionEnabled() {
+ return logRetention;
+ }
+
+ /**
+ * @return the TTL for this CDN container.
+ */
+ public int getTtl() {
+ return ttl;
+ }
+
+ /**
+ * @return the {@link URI} for this CDN container.
+ */
+ public URI getUri() {
+ return uri;
+ }
+
+ /**
+ * @return the SSL {@link URI} for this CDN container.
+ */
+ public URI getSslUri() {
+ return sslUri;
+ }
+
+ /**
+ * @return the streaming {@link URI} for this CDN container.
+ */
+ public URI getStreamingUri() {
+ return streamingUri;
+ }
+
+ /**
+ * @return the iOS {@link URI} for this CDN container.
+ */
+ public URI getIosUri() {
+ return iosUri;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null || getClass() != obj.getClass()) return false;
+ CDNContainer that = CDNContainer.class.cast(obj);
+ return Objects.equal(this.name, that.name)
+ && Objects.equal(this.enabled, that.enabled)
+ && Objects.equal(this.logRetention, that.logRetention)
+ && Objects.equal(this.ttl, that.ttl)
+ && Objects.equal(this.uri, that.uri)
+ && Objects.equal(this.sslUri, that.sslUri)
+ && Objects.equal(this.streamingUri, that.streamingUri)
+ && Objects.equal(this.iosUri, that.iosUri);
+ }
+
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(getName(), isEnabled(), isLogRetentionEnabled(), getTtl(), getUri(), getSslUri(), getStreamingUri(), getIosUri());
+ }
+
+ @Override
+ public String toString() {
+ return string().toString();
+ }
+
+ protected ToStringHelper string() {
+ return toStringHelper("").omitNullValues()
+ .add("name", getName())
+ .add("enabled", isEnabled())
+ .add("logRetention", isLogRetentionEnabled())
+ .add("ttl", getTtl())
+ .add("uri", getUri())
+ .add("sslUri", getSslUri())
+ .add("streamingUri", getStreamingUri())
+ .add("iosUri", getIosUri());
+ }
+
+ @Override
+ public int compareTo(CDNContainer that) {
+ if (that == null)
+ return 1;
+ if (this == that)
+ return 0;
+ return this.getName().compareTo(that.getName());
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private String name;
+ private boolean enabled;
+ private boolean logRetention;
+ private int ttl;
+ private URI uri;
+ private URI sslUri;
+ private URI streamingUri;
+ private URI iosUri;
+
+ /**
+ * @see CDNContainer#getName()
+ */
+ public Builder name(String name) {
+ this.name = checkNotNull(name, "name");
+ return this;
+ }
+
+ /**
+ * @see CDNContainer#isEnabled()
+ */
+ public Builder enabled(boolean enabled) {
+ this.enabled = enabled;
+ return this;
+ }
+
+ /**
+ * @see CDNContainer#isLogRetentionEnabled()
+ */
+ public Builder logRetention(boolean logRetention) {
+ this.logRetention = logRetention;
+ return this;
+ }
+
+ /**
+ * @see CDNContainer#getTtl()
+ */
+ public Builder ttl(int ttl) {
+ this.ttl = ttl;
+ return this;
+ }
+
+ /**
+ * @see CDNContainer#getUri()
+ */
+ public Builder uri(URI uri) {
+ this.uri = uri;
+ return this;
+ }
+
+ /**
+ * @see CDNContainer#getSslUri()
+ */
+ public Builder sslUri(URI sslUri) {
+ this.sslUri = sslUri;
+ return this;
+ }
+
+ /**
+ * @see CDNContainer#getStreamingUri()
+ */
+ public Builder streamingUri(URI streamingUri) {
+ this.streamingUri = streamingUri;
+ return this;
+ }
+
+ /**
+ * @see CDNContainer#getIosUri()
+ */
+ public Builder iosUri(URI iosUri) {
+ this.iosUri = iosUri;
+ return this;
+ }
+
+ public CDNContainer build() {
+ return new CDNContainer(name, enabled, logRetention, ttl, uri, sslUri, streamingUri, iosUri);
+ }
+
+ public Builder fromContainer(CDNContainer from) {
+ return name(from.getName())
+ .enabled(from.isEnabled())
+ .logRetention(from.isLogRetentionEnabled())
+ .ttl(from.getTtl())
+ .uri(from.getUri())
+ .sslUri(from.getSslUri())
+ .streamingUri(from.getStreamingUri())
+ .iosUri(from.getIosUri());
+ }
+ }
+}
diff --git a/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/features/CDNApi.java b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/features/CDNApi.java
new file mode 100644
index 0000000..326b951
--- /dev/null
+++ b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/features/CDNApi.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.features;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_ENABLED;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_TTL;
+
+import java.io.Closeable;
+import java.net.URI;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HEAD;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+
+import org.jclouds.Fallbacks.EmptyFluentIterableOnNotFoundOr404;
+import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.swift.v1.options.ListContainerOptions;
+import org.jclouds.rackspace.cloudfiles.v1.CloudFilesApi;
+import org.jclouds.rackspace.cloudfiles.v1.binders.BindCDNPurgeEmailAddressesToHeaders;
+import org.jclouds.rackspace.cloudfiles.v1.domain.CDNContainer;
+import org.jclouds.rackspace.cloudfiles.v1.functions.ParseCDNContainerFromHeaders;
+import org.jclouds.rackspace.cloudfiles.v1.functions.ParseCDNContainerURIFromHeaders;
+import org.jclouds.rackspace.cloudfiles.v1.options.UpdateCDNContainerOptions;
+import org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.Headers;
+import org.jclouds.rest.annotations.QueryParams;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+
+import com.google.common.collect.FluentIterable;
+/**
+ * Provides access to the Rackspace Cloud Files CDN API features.
+ *
+ * <h3>NOTE</h3>
+ * Before a container can be CDN enabled, it must exist in the storage system.
+ * To CDN enable the container, perform PUT request against it using the <code>publicURL</code>
+ * noted in the service catalog for Cloud Files during Authentication and set the
+ * <code>X-CDN-Enabled</code> header to <code>true</code>.
+ *
+ * @author Jeremy Daggett
+ *
+ * @see {@link CloudFilesApi#cdnApiInRegion(String)}
+ */
+@RequestFilters(AuthenticateRequest.class)
+@Consumes(APPLICATION_JSON)
+public interface CDNApi extends Closeable {
+
+ /**
+ * Lists up to 10,000 CDN containers.
+ *
+ * @return a list of CDN enabled containers ordered by name.
+ */
+ @Named("cdn:list")
+ @GET
+ @QueryParams(keys = {"format", "enabled_only"}, values = {"json", "true"})
+ @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
+ @Path("/")
+ FluentIterable<CDNContainer> list();
+
+ /**
+ * Lists CDN containers, with the given options.
+ *
+ * @param options
+ * the options to control output.
+ *
+ * @return a list of CDN enabled containers ordered by name.
+ */
+ @Named("cdn:list")
+ @GET
+ @QueryParams(keys = {"format", "enabled_only"}, values = {"json", "true"})
+ @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
+ @Path("/")
+ FluentIterable<CDNContainer> list(ListContainerOptions options);
+
+ /**
+ * Gets the specified CDN Container.
+ *
+ * @param containerName
+ * the name of the CDN Container
+ *
+ * @return the CDNContainer or null, if not found.
+ */
+ @Named("cdn:get")
+ @HEAD
+ @ResponseParser(ParseCDNContainerFromHeaders.class)
+ @Fallback(NullOnNotFoundOr404.class)
+ @Path("/{container}")
+ @Nullable
+ CDNContainer get(@PathParam("container") String containerName);
+
+ /**
+ * Enables the {@link CDNContainer}.
+ *
+ * @param containerName
+ * corresponds to {@link CDNContainer#getName()}.
+ *
+ * @return the CDN container {@link URI} or {@code null}, if not found.
+ */
+ @Named("cdn:enable")
+ @PUT
+ @ResponseParser(ParseCDNContainerURIFromHeaders.class)
+ @Fallback(NullOnNotFoundOr404.class)
+ @Path("/{containerName}")
+ @Headers(keys = CDN_ENABLED, values = "true")
+ @Nullable
+ URI enable(@PathParam("containerName") String containerName);
+
+ /**
+ * Enables the {@link CDNContainer} with a TTL.
+ *
+ * @param containerName
+ * corresponds to {@link CDNContainer#name()}.
+ * @param ttl
+ * the TTL for the CDN Container.
+ *
+ * @return the CDN container {@link URI} or {@code null}, if not found.
+ */
+ @Named("cdn:enable")
+ @PUT
+ @ResponseParser(ParseCDNContainerURIFromHeaders.class)
+ @Fallback(NullOnNotFoundOr404.class)
+ @Path("/{containerName}")
+ @Headers(keys = CDN_ENABLED, values = "true")
+ @Nullable
+ URI enable(@PathParam("containerName") String containerName,
+ @HeaderParam(CDN_TTL) int ttl);
+
+ /**
+ * Disables the {@link CDNContainer}.
+ *
+ * @param containerName
+ * corresponds to {@link CDNContainer#name()}.
+ *
+ * @return {@code true} if the container was disabled, {@code false} if not.
+ */
+ @Named("cdn:disable")
+ @PUT
+ @Fallback(FalseOnNotFoundOr404.class)
+ @Path("/{containerName}")
+ @Headers(keys = CDN_ENABLED, values = "False")
+ boolean disable(@PathParam("containerName") String containerName);
+
+ /**
+ * Purges an object from the CDN.
+ *
+ * @param containerName
+ * corresponds to {@link CDNContainer#name()}.
+ * @param objectName
+ * the object in the {@link CDNContainer} to purge.
+ * @param emails
+ * the email addresses to notify after purging.
+ *
+ * @return {@code true} if the object was successfully purged, {@code false} if not.
+ */
+ @Named("cdn:purge")
+ @DELETE
+ @Fallback(FalseOnNotFoundOr404.class)
+ @Path("/{containerName}/{objectName}")
+ @Headers(keys = CloudFilesHeaders.CDN_PURGE_OBJECT_EMAIL, values = "{email}")
+ boolean purgeObject(@PathParam("containerName") String containerName,
+ @PathParam("objectName") String objectName,
+ @BinderParam(BindCDNPurgeEmailAddressesToHeaders.class) Iterable<String> emails);
+
+ /**
+ * Updates a CDN container with the supplied {@link UpdateCDNContainerOptions} options.
+ *
+ * @param containerName
+ * corresponds to {@link CDNContainer#name()}.
+ *
+ * @param options
+ * the {@link UpdateCDNContainerOptions} options.
+ */
+ @Named("cdn:update")
+ @POST
+ @Fallback(FalseOnNotFoundOr404.class)
+ @Path("/{containerName}")
+ boolean update(@PathParam("containerName") String containerName, UpdateCDNContainerOptions options);
+}
diff --git a/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/functions/ParseCDNContainerFromHeaders.java b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/functions/ParseCDNContainerFromHeaders.java
new file mode 100644
index 0000000..e551ab1
--- /dev/null
+++ b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/functions/ParseCDNContainerFromHeaders.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.functions;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Lists.newArrayList;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_ENABLED;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_IOS_URI;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_LOG_RETENTION;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_SSL_URI;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_STREAMING_URI;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_TTL;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_URI;
+
+import java.net.URI;
+import java.util.List;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.rackspace.cloudfiles.v1.domain.CDNContainer;
+import org.jclouds.rest.InvocationContext;
+
+import com.google.common.base.Function;
+import com.google.common.base.Splitter;
+
+/**
+ * Parses the {@link CDNContainer} from the response headers.
+ *
+ * @author Jeremy Daggett
+ *
+ */
+public class ParseCDNContainerFromHeaders implements Function<HttpResponse, CDNContainer>,
+ InvocationContext<ParseCDNContainerFromHeaders> {
+
+ private HttpRequest request;
+
+ /**
+ * parses the http response headers to create a new {@link CDNContainer} object.
+ */
+ public CDNContainer apply(final HttpResponse from) {
+ String uri = checkNotNull(from.getFirstHeaderOrNull(CDN_URI), CDN_URI);
+ String sslUri = checkNotNull(from.getFirstHeaderOrNull(CDN_SSL_URI), CDN_SSL_URI);
+ String streamingUri = checkNotNull(from.getFirstHeaderOrNull(CDN_STREAMING_URI), CDN_STREAMING_URI);
+ String iosUri = checkNotNull(from.getFirstHeaderOrNull(CDN_IOS_URI), CDN_IOS_URI);
+ String enabled = checkNotNull(from.getFirstHeaderOrNull(CDN_ENABLED), CDN_ENABLED);
+ String logRetention = checkNotNull(from.getFirstHeaderOrNull(CDN_LOG_RETENTION), CDN_LOG_RETENTION);
+ String ttl = checkNotNull(from.getFirstHeaderOrNull(CDN_TTL), CDN_TTL);
+
+ // just need the name from the path
+ List<String> parts = newArrayList(Splitter.on('/').split(request.getEndpoint().getPath()));
+ checkArgument(parts.size() > 0);
+
+ return CDNContainer.builder().name(parts.get(parts.size() - 1))
+ .enabled(Boolean.parseBoolean(enabled))
+ .logRetention(Boolean.parseBoolean(logRetention))
+ .ttl(Integer.parseInt(ttl))
+ .uri(URI.create(uri))
+ .sslUri(URI.create(sslUri))
+ .streamingUri(URI.create(streamingUri))
+ .iosUri(URI.create(iosUri))
+ .build();
+ }
+
+ @Override
+ public ParseCDNContainerFromHeaders setContext(HttpRequest request) {
+ this.request = request;
+ return this;
+ }
+}
diff --git a/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/functions/ParseCDNContainerURIFromHeaders.java b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/functions/ParseCDNContainerURIFromHeaders.java
new file mode 100644
index 0000000..4a29f60
--- /dev/null
+++ b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/functions/ParseCDNContainerURIFromHeaders.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.net.URI;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.rackspace.cloudfiles.v1.domain.CDNContainer;
+import org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders;
+
+import com.google.common.base.Function;
+
+/**
+ * Parses the {@link CDNContainer} from the response headers.
+ *
+ * @author Jeremy Daggett
+ *
+ */
+public class ParseCDNContainerURIFromHeaders implements Function<HttpResponse, URI> {
+
+ /**
+ * parses the http response headers to provide the CDN URI string.
+ */
+ public URI apply(final HttpResponse from) {
+ String cdnUri = checkNotNull(from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_URI),
+ CloudFilesHeaders.CDN_URI);
+ return URI.create(cdnUri);
+ }
+}
diff --git a/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/functions/RegionToCDNEndpoint.java b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/functions/RegionToCDNEndpoint.java
new file mode 100644
index 0000000..3b5361a
--- /dev/null
+++ b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/functions/RegionToCDNEndpoint.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.functions;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.net.URI;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.location.functions.RegionToEndpoint;
+import org.jclouds.location.suppliers.RegionIdToURISupplier;
+import org.jclouds.rackspace.cloudfiles.v1.CloudFilesApi;
+import org.jclouds.rackspace.cloudfiles.v1.features.CDNApi;
+import org.jclouds.rackspace.cloudidentity.v2_0.ServiceType;
+import org.jclouds.rest.annotations.ApiVersion;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+
+/**
+ * This class ensures that the correct Cloud Files CDN endpoint is retrieved from the endpoint
+ * supplier. The CDN API should never be instantiated directly, but rather accessed through the
+ * {@link CloudFilesApi#cdnApiInRegion(String)} API.
+ * <p/>
+ * <h3>NOTE</h3>
+ * The Cloud Files Service Type will always default to OpenStack Object Storage ("object-storage").
+ * <p/>
+ *
+ * @author Jeremy Daggett
+ *
+ * @see CloudFilesApi#cdnApiInRegion(String)
+ * @see CDNApi
+ * @see RegionToEndpoint
+ * @see org.jclouds.openstack.v2_0.ServiceType#OBJECT_STORE
+ * @see org.jclouds.rackspace.cloudidentity.v2_0.ServiceType#OBJECT_CDN
+ * @see <a
+ * href="http://docs.rackspace.com/files/api/v1/cf-devguide/content/Service-Access-Endpoints-d1e003.html">
+ * Service Access Endpoints</a>
+ */
+@Singleton
+public class RegionToCDNEndpoint implements Function<Object, URI> {
+
+ private final Supplier<Map<String, Supplier<URI>>> endpointsSupplier;
+
+ @Inject
+ public RegionToCDNEndpoint(@ApiVersion final String apiVersion, final RegionIdToURISupplier.Factory factory) {
+ this.endpointsSupplier = factory.createForApiTypeAndVersion(ServiceType.OBJECT_CDN, apiVersion);
+ }
+
+ public URI apply(@Nullable Object from) {
+ checkArgument(from != null && from instanceof String, "you must specify a region, as a String argument");
+ Map<String, Supplier<URI>> regionToEndpoint = endpointsSupplier.get();
+ checkState(regionToEndpoint.size() > 0, "no region name to endpoint mappings configured!");
+ checkArgument(regionToEndpoint.containsKey(from),
+ "requested location %s, which is not in the configured locations: %s", from, regionToEndpoint);
+ return regionToEndpoint.get(from).get();
+ }
+}
diff --git a/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/handlers/CloudFilesErrorHandler.java b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/handlers/CloudFilesErrorHandler.java
new file mode 100644
index 0000000..1e69b23
--- /dev/null
+++ b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/handlers/CloudFilesErrorHandler.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.handlers;
+
+import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.jclouds.blobstore.ContainerNotFoundException;
+import org.jclouds.blobstore.KeyNotFoundException;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.openstack.swift.v1.CopyObjectException;
+import org.jclouds.openstack.swift.v1.reference.SwiftHeaders;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.InsufficientResourcesException;
+
+// TODO: is there error spec someplace? let's type errors, etc.
+public class CloudFilesErrorHandler implements HttpErrorHandler {
+ public static final String PREFIX = "^/v[0-9][^/]*/[a-zA-Z]+_[^/]+/";
+ public static final Pattern CONTAINER_PATH = Pattern.compile(PREFIX + "([^/]+)$");
+ public static final Pattern CONTAINER_KEY_PATH = Pattern.compile(PREFIX + "([^/]+)/(.*)");
+
+ public void handleError(HttpCommand command, HttpResponse response) {
+ // it is important to always read fully and close streams
+ byte[] data = closeClientButKeepContentStream(response);
+ String message = data != null ? new String(data) : null;
+
+ Exception exception = message != null ? new HttpResponseException(command, response, message)
+ : new HttpResponseException(command, response);
+ message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
+ response.getStatusLine());
+ switch (response.getStatusCode()) {
+ case 401:
+ exception = new AuthorizationException(exception.getMessage(), exception);
+ break;
+ case 404:
+ Exception oldException = exception;
+ String sourcePath = command.getCurrentRequest().getFirstHeaderOrNull(SwiftHeaders.OBJECT_COPY_FROM);
+ if (sourcePath != null) {
+ // the path returned here is in the form "/v1/tenant-id/destContainer/destObject"
+ String path = command.getCurrentRequest().getEndpoint().getPath();
+ int startOfDestinationPath = path.lastIndexOf("/", path.lastIndexOf("/") - 1);
+ // get the "/destContainer/destObject" portion of the path
+ String destinationPath = path.substring(startOfDestinationPath);
+
+ exception = new CopyObjectException(sourcePath, destinationPath, message);
+ exception.initCause(oldException);
+ } else if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
+ String path = command.getCurrentRequest().getEndpoint().getPath();
+ Matcher matcher = CONTAINER_PATH.matcher(path);
+
+ if (matcher.find()) {
+ exception = new ContainerNotFoundException(matcher.group(1), message);
+ exception.initCause(oldException);
+ } else {
+ matcher = CONTAINER_KEY_PATH.matcher(path);
+ if (matcher.find()) {
+ exception = new KeyNotFoundException(matcher.group(1), matcher.group(2), message);
+ exception.initCause(oldException);
+ }
+ }
+ }
+ break;
+ case 409:
+ exception = new IllegalStateException(exception.getMessage(), exception);
+ break;
+ case 413:
+ exception = new InsufficientResourcesException(exception.getMessage(), exception);
+ break;
+ }
+ command.setException(exception);
+ }
+}
diff --git a/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/options/UpdateCDNContainerOptions.java b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/options/UpdateCDNContainerOptions.java
new file mode 100644
index 0000000..d044657
--- /dev/null
+++ b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/options/UpdateCDNContainerOptions.java
@@ -0,0 +1,163 @@
+/*
+
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.options;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_ENABLED;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_LOG_RETENTION;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_TTL;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_TTL_MAX;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_TTL_MIN;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Contains options supported in the REST API for updating CDN containers.
+ *
+ * <a href=
+ * "http://docs.rackspace.com/files/api/v1/cf-devguide/content/Update_CDN-Enabled_Container_Metadata-d1e2787.html">
+ * Update CDN container</a>.
+ *
+ * @author Jeremy Daggett
+ */
+public class UpdateCDNContainerOptions extends BaseHttpRequestOptions {
+ public static final UpdateCDNContainerOptions NONE = new UpdateCDNContainerOptions();
+
+ /**
+ * Updates TTL
+ */
+ public UpdateCDNContainerOptions ttl(int ttl) {
+ checkState(ttl >= Integer.valueOf(CDN_TTL_MIN), "ttl must be >= " + CDN_TTL_MIN);
+ checkState(ttl <= Integer.valueOf(CDN_TTL_MAX), "ttl must be <= " + CDN_TTL_MAX);
+ headers.put(CDN_TTL, Integer.toString(ttl));
+ return this;
+ }
+
+ /**
+ * Enables or disables log retention
+ */
+ public UpdateCDNContainerOptions logRetention(boolean logRetention) {
+ headers.put(CDN_LOG_RETENTION, Boolean.toString(logRetention));
+ return this;
+ }
+
+ /**
+ * Enables or disables the CDN Container
+ * API to enable disable - is this necessary?
+ */
+ public UpdateCDNContainerOptions enabled(boolean enabled) {
+ headers.put(CDN_ENABLED, Boolean.toString(enabled));
+ return this;
+ }
+
+ /**
+ * Sets the index page for the Static Website.
+ */
+ public UpdateCDNContainerOptions staticWebsiteIndexPage(String indexPage) {
+ checkNotNull(indexPage, "index page cannot be null");
+ headers.put("indexPage", indexPage);
+ return this;
+ }
+
+ /**
+ * Sets the error page for the Static Website.
+ */
+ public UpdateCDNContainerOptions staticWebsiteErrorPage(String errorPage) {
+ checkNotNull(errorPage, "error page cannot be null");
+ headers.put("errorPage", errorPage);
+ return this;
+ }
+
+ /**
+ * Enables or disables listings for the Static Website.
+ */
+ public UpdateCDNContainerOptions staticWebsiteListings(boolean listings) {
+ headers.put("enableListings", Boolean.toString(listings));
+ return this;
+ }
+
+ /**
+ * Sets the CSS pages for the Static Website.
+ */
+ public UpdateCDNContainerOptions staticWebsiteListingsCSS(String listingsCSS) {
+ checkNotNull(listingsCSS, "listingsCSS page cannot be null");
+ headers.put("limit", listingsCSS);
+ return this;
+ }
+
+ public static class Builder {
+ /** @see UpdateCDNContainerOptions#ttl */
+ public static UpdateCDNContainerOptions ttl(int ttl) {
+ UpdateCDNContainerOptions options = new UpdateCDNContainerOptions();
+ return options.ttl(ttl);
+ }
+
+ /**
+ * @see UpdateCDNContainerOptions#logRetention
+ */
+ public static UpdateCDNContainerOptions logRetention(boolean logRetention) {
+ UpdateCDNContainerOptions options = new UpdateCDNContainerOptions();
+ return options.logRetention(logRetention);
+ }
+
+ /**
+ * @see UpdateCDNContainerOptions#enabled
+ */
+ public static UpdateCDNContainerOptions enabled(boolean enabled) {
+ UpdateCDNContainerOptions options = new UpdateCDNContainerOptions();
+ return options.enabled(enabled);
+ }
+
+ /**
+ * @see UpdateCDNContainerOptions#staticWebsiteIndexPage
+ */
+ public static UpdateCDNContainerOptions staticWebsiteIndexPage(String indexPage) {
+ UpdateCDNContainerOptions options = new UpdateCDNContainerOptions();
+ return options.staticWebsiteIndexPage(indexPage);
+ }
+
+ /**
+ * @see UpdateCDNContainerOptions#staticWebsiteErrorPage
+ */
+ public static UpdateCDNContainerOptions staticWebsiteErrorPage(String errorPage) {
+ UpdateCDNContainerOptions options = new UpdateCDNContainerOptions();
+ return options.staticWebsiteErrorPage(errorPage);
+ }
+
+ /**
+ * @see UpdateCDNContainerOptions#staticWebsiteListings
+ */
+ public static UpdateCDNContainerOptions staticWebsiteListings(boolean enabled) {
+ UpdateCDNContainerOptions options = new UpdateCDNContainerOptions();
+ return options.staticWebsiteListings(enabled);
+ }
+
+ /**
+ * @see UpdateCDNContainerOptions#staticWebsiteListingsCSS
+ */
+ public static UpdateCDNContainerOptions staticWebsiteListingsCSS(String cssPage) {
+ UpdateCDNContainerOptions options = new UpdateCDNContainerOptions();
+ return options.staticWebsiteListingsCSS(cssPage);
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+}
diff --git a/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/reference/CloudFilesHeaders.java b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/reference/CloudFilesHeaders.java
new file mode 100644
index 0000000..7247700
--- /dev/null
+++ b/rackspace-cloudfiles/src/main/java/org/jclouds/rackspace/cloudfiles/v1/reference/CloudFilesHeaders.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.reference;
+
+import org.jclouds.openstack.swift.v1.reference.SwiftHeaders;
+
+/**
+ * Additional headers specified by Rackspace Cloud Files CDN.
+ *
+ * @see <a
+ * href="http://docs.rackspace.com/files/api/v1/cf-devguide/content/index.html">
+ * Cloud Files API</a>
+ *
+ * @author Jeremy Daggett
+ */
+public interface CloudFilesHeaders extends SwiftHeaders {
+ // Access logs
+ String CONTAINER_ACCESS_LOG_DELIVERY = CONTAINER_METADATA_PREFIX + "Access-Log-Delivery";
+
+ // Common CDN Headers
+ String CDN_ENABLED = "X-Cdn-Enabled";
+ String CDN_LOG_RETENTION = "X-Log-Retention";
+ String CDN_TTL = "X-Ttl";
+ String CDN_URI = "X-Cdn-Uri";
+ String CDN_SSL_URI = "X-Cdn-Ssl-Uri";
+ String CDN_STREAMING_URI = "X-Cdn-Streaming-Uri";
+ String CDN_IOS_URI = "X-Cdn-Ios-Uri";
+
+ // CDN TTL Limits
+ int CDN_TTL_MIN = 900;
+ int CDN_TTL_MAX = 31536000;
+ int CDN_TTL_DEFAULT = 259200;
+
+ // CDN Purge
+ String CDN_PURGE_OBJECT_EMAIL = "X-Purge-Email";
+ String CDN_PURGE_OBJECT_FAILED = "X-Purge-Failed-Reason";
+
+ // CDN Static Web
+ String STATIC_WEB_INDEX = CONTAINER_METADATA_PREFIX + "Web-Index";
+ String STATIC_WEB_DIRECTORY_TYPE = CONTAINER_METADATA_PREFIX + "Web-Directory-Type";
+ String STATIC_WEB_ERROR = CONTAINER_METADATA_PREFIX + "Web-Error";
+ String STATIC_WEB_LISTINGS = CONTAINER_METADATA_PREFIX + "Web-Listings";
+ String STATIC_WEB_LISTINGS_CSS = CONTAINER_METADATA_PREFIX + "Web-Listings-CSS";
+}
diff --git a/rackspace-cloudfiles/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/rackspace-cloudfiles/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
new file mode 100644
index 0000000..9be2b32
--- /dev/null
+++ b/rackspace-cloudfiles/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+org.jclouds.rackspace.cloudfiles.v1.CloudFilesApiMetadata
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/CloudFilesApiLiveTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/CloudFilesApiLiveTest.java
new file mode 100644
index 0000000..666059f
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/CloudFilesApiLiveTest.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1;
+
+import org.jclouds.rackspace.cloudfiles.v1.internal.BaseCloudFilesApiLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * Tests behavior of {@code CloudFilesApi}
+ *
+ * @author Jeremy Daggett
+ */
+@Test(groups = "live", testName = "CloudFilesApiLiveTest")
+public class CloudFilesApiLiveTest extends BaseCloudFilesApiLiveTest {
+
+}
\ No newline at end of file
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/CloudFilesApiMetadataTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/CloudFilesApiMetadataTest.java
new file mode 100644
index 0000000..5c32f1c
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/CloudFilesApiMetadataTest.java
@@ -0,0 +1,35 @@
+package org.jclouds.rackspace.cloudfiles.v1;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+import org.jclouds.View;
+import org.jclouds.apis.internal.BaseApiMetadataTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.reflect.TypeToken;
+
+/**
+ *
+ * @author Jeremy Daggett
+ */
+@Test(groups = "unit", testName = "CloudFilesApiMetadataTest")
+public class CloudFilesApiMetadataTest extends BaseApiMetadataTest {
+ public CloudFilesApiMetadataTest() {
+ super(new CloudFilesApiMetadata(), ImmutableSet.<TypeToken<? extends View>> of());
+ }
+}
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/binders/BindCDNPurgeEmailAddressesToHeadersMockTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/binders/BindCDNPurgeEmailAddressesToHeadersMockTest.java
new file mode 100644
index 0000000..5c7e2b0
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/binders/BindCDNPurgeEmailAddressesToHeadersMockTest.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.binders;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest;
+import org.jclouds.rackspace.cloudfiles.v1.CloudFilesApi;
+import org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Tests behavior of {@code BindCDNPurgeEmailAddressesToHeaders}
+ *
+ * @author Jeremy Daggett
+ */
+@Test(groups = "unit", testName = "BindCDNPurgeEmailAddressesToHeadersMockTest")
+public class BindCDNPurgeEmailAddressesToHeadersMockTest extends BaseOpenStackMockTest<CloudFilesApi> {
+
+ BindCDNPurgeEmailAddressesToHeaders binder = new BindCDNPurgeEmailAddressesToHeaders();
+
+ public void testEmailBind() throws Exception {
+ List<String> emails = ImmutableList.of("foo@bar.com", "bar@foo.com");
+
+ HttpRequest request = purgeRequest();
+
+ HttpRequest actualRequest = binder.bindToRequest(request, emails);
+
+ HttpRequest expectedRequest = HttpRequest.builder()
+ .method("DELETE")
+ .endpoint("https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_XXXXXX/")
+ .addHeader(CloudFilesHeaders.CDN_PURGE_OBJECT_EMAIL, "foo@bar.com, bar@foo.com")
+ .build();
+
+ assertEquals(actualRequest, expectedRequest);
+
+ }
+
+ @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "input")
+ public void testNullList() {
+ HttpRequest request = purgeRequest();
+ binder.bindToRequest(request, null);
+ }
+
+ @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "request")
+ public void testNullRequest() {
+ List<String> emails = ImmutableList.of("foo@bar.com", "bar@foo.com");
+ binder.bindToRequest(null, emails);
+ }
+
+ private static final HttpRequest purgeRequest() {
+ return HttpRequest.builder()
+ .method("DELETE")
+ .endpoint("https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_XXXXXX/")
+ .build();
+ }
+}
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/CloudFilesRegionScopedBlobStoreContextLiveTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/CloudFilesRegionScopedBlobStoreContextLiveTest.java
new file mode 100644
index 0000000..bc35b3a
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/CloudFilesRegionScopedBlobStoreContextLiveTest.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.blobstore;
+
+import static org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityCredentialTypes.API_KEY_CREDENTIALS;
+
+import java.util.Properties;
+
+import org.jclouds.openstack.swift.v1.blobstore.RegionScopedBlobStoreContextLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live")
+public class CloudFilesRegionScopedBlobStoreContextLiveTest extends RegionScopedBlobStoreContextLiveTest {
+
+ public CloudFilesRegionScopedBlobStoreContextLiveTest() {
+ provider = "rackspace-cloudfiles";
+ }
+
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ setIfTestSystemPropertyPresent(props, API_KEY_CREDENTIALS);
+ return props;
+ }
+}
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesBlobIntegrationLiveTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesBlobIntegrationLiveTest.java
new file mode 100644
index 0000000..58ed73b
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesBlobIntegrationLiveTest.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.blobstore.integration;
+
+import static org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityCredentialTypes.API_KEY_CREDENTIALS;
+
+import java.util.Properties;
+
+import org.jclouds.openstack.swift.v1.blobstore.integration.SwiftBlobIntegrationLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudFilesBlobIntegrationLiveTest")
+public class CloudFilesBlobIntegrationLiveTest extends SwiftBlobIntegrationLiveTest {
+
+ public CloudFilesBlobIntegrationLiveTest() {
+ provider = "rackspace-cloudfiles";
+ }
+
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ setIfTestSystemPropertyPresent(props, API_KEY_CREDENTIALS);
+ return props;
+ }
+}
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesBlobLiveTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesBlobLiveTest.java
new file mode 100644
index 0000000..87519d5
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesBlobLiveTest.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.blobstore.integration;
+
+import static org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityCredentialTypes.API_KEY_CREDENTIALS;
+
+import java.util.Properties;
+
+import org.jclouds.openstack.swift.v1.blobstore.integration.SwiftBlobLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudFilesBlobLiveTest")
+public class CloudFilesBlobLiveTest extends SwiftBlobLiveTest {
+
+ public CloudFilesBlobLiveTest() {
+ provider = "rackspace-cloudfiles";
+ }
+
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ setIfTestSystemPropertyPresent(props, API_KEY_CREDENTIALS);
+ return props;
+ }
+}
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesBlobSignerLiveTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesBlobSignerLiveTest.java
new file mode 100644
index 0000000..dea68f2
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesBlobSignerLiveTest.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.blobstore.integration;
+
+import static org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityCredentialTypes.API_KEY_CREDENTIALS;
+
+import java.util.Properties;
+
+import org.jclouds.openstack.swift.v1.blobstore.integration.SwiftBlobSignerLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudFilesBlobSignerLiveTest")
+public class CloudFilesBlobSignerLiveTest extends SwiftBlobSignerLiveTest {
+
+ public CloudFilesBlobSignerLiveTest() {
+ provider = "rackspace-cloudfiles";
+ }
+
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ setIfTestSystemPropertyPresent(props, API_KEY_CREDENTIALS);
+ return props;
+ }
+}
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesContainerIntegrationLiveTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesContainerIntegrationLiveTest.java
new file mode 100644
index 0000000..ba99a75
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesContainerIntegrationLiveTest.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.blobstore.integration;
+
+import static org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityCredentialTypes.API_KEY_CREDENTIALS;
+
+import java.util.Properties;
+
+import org.jclouds.openstack.swift.v1.blobstore.integration.SwiftContainerIntegrationLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudFilesContainerIntegrationLiveTest")
+public class CloudFilesContainerIntegrationLiveTest extends SwiftContainerIntegrationLiveTest {
+
+ public CloudFilesContainerIntegrationLiveTest() {
+ provider = "rackspace-cloudfiles";
+ }
+
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ setIfTestSystemPropertyPresent(props, API_KEY_CREDENTIALS);
+ return props;
+ }
+}
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesContainerLiveTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesContainerLiveTest.java
new file mode 100644
index 0000000..98ab003
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesContainerLiveTest.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.blobstore.integration;
+
+import static org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityCredentialTypes.API_KEY_CREDENTIALS;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Properties;
+
+import org.jclouds.openstack.swift.v1.blobstore.integration.SwiftContainerLiveTest;
+import org.testng.SkipException;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudFilesContainerLiveTest")
+public class CloudFilesContainerLiveTest extends SwiftContainerLiveTest {
+
+ public CloudFilesContainerLiveTest() {
+ provider = "rackspace-cloudfiles";
+ }
+
+ @Override
+ public void testPublicAccess() throws InterruptedException, MalformedURLException, IOException {
+ throw new SkipException("public access only supported through CDN");
+ }
+
+ @Override
+ public void testPublicAccessInNonDefaultLocationWithBigBlob() throws InterruptedException, MalformedURLException, IOException {
+ throw new SkipException("public access only supported through CDN");
+ }
+
+ public void testPublicAccessInNonDefaultLocation() throws InterruptedException, MalformedURLException, IOException {
+ throw new SkipException("public access only supported through CDN");
+ }
+
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ setIfTestSystemPropertyPresent(props, API_KEY_CREDENTIALS);
+ return props;
+ }
+}
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesServiceIntegrationLiveTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesServiceIntegrationLiveTest.java
new file mode 100644
index 0000000..66b4b64
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/blobstore/integration/CloudFilesServiceIntegrationLiveTest.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.blobstore.integration;
+
+import static org.jclouds.rackspace.cloudidentity.v2_0.config.CloudIdentityCredentialTypes.API_KEY_CREDENTIALS;
+
+import java.util.Properties;
+
+import org.jclouds.openstack.swift.v1.blobstore.integration.SwiftServiceIntegrationLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudFilesServiceIntegrationLiveTest")
+public class CloudFilesServiceIntegrationLiveTest extends SwiftServiceIntegrationLiveTest {
+
+ public CloudFilesServiceIntegrationLiveTest() {
+ provider = "rackspace-cloudfiles";
+ }
+
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ setIfTestSystemPropertyPresent(props, API_KEY_CREDENTIALS);
+ return props;
+ }
+}
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesAccountApiLiveTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesAccountApiLiveTest.java
new file mode 100644
index 0000000..297ae7d
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesAccountApiLiveTest.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.features;
+
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.openstack.swift.v1.domain.Account;
+import org.jclouds.openstack.swift.v1.features.AccountApiLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudFilesAccountApiLiveTest")
+public class CloudFilesAccountApiLiveTest extends AccountApiLiveTest {
+
+ public CloudFilesAccountApiLiveTest() {
+ provider = "rackspace-cloudfiles";
+ }
+
+ public void testUrlKeyExists() throws Exception {
+ for (String regionId : regions) {
+ Account account = api.accountApiInRegion(regionId).get();
+ assertTrue(account.getTemporaryUrlKey().isPresent());
+ }
+ }
+}
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesBulkApiLiveTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesBulkApiLiveTest.java
new file mode 100644
index 0000000..331ab85
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesBulkApiLiveTest.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.features;
+
+import org.jclouds.openstack.swift.v1.features.BulkApiLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudFilesBulkApiLiveTest")
+public class CloudFilesBulkApiLiveTest extends BulkApiLiveTest {
+
+ public CloudFilesBulkApiLiveTest() {
+ provider = "rackspace-cloudfiles";
+ }
+}
\ No newline at end of file
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesCDNApiLiveTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesCDNApiLiveTest.java
new file mode 100644
index 0000000..fe299ba
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesCDNApiLiveTest.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.features;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+
+import org.jclouds.openstack.swift.v1.options.CreateContainerOptions;
+import org.jclouds.openstack.swift.v1.options.ListContainerOptions;
+import org.jclouds.rackspace.cloudfiles.v1.domain.CDNContainer;
+import org.jclouds.rackspace.cloudfiles.v1.internal.BaseCloudFilesApiLiveTest;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * @author Jeremy Daggett
+ */
+@Test(groups = "live", testName = "CloudFilesCDNApiLiveTest")
+public class CloudFilesCDNApiLiveTest extends BaseCloudFilesApiLiveTest {
+
+ private String name = getClass().getSimpleName();
+
+ public CloudFilesCDNApiLiveTest() {
+ super();
+ }
+
+ public void testList() throws Exception {
+ for (String regionId : regions) {
+ CDNApi cdnApi = api.cdnApiInRegion(regionId);
+
+ List<CDNContainer> cdnResponse = cdnApi.list().toList();
+ assertNotNull(cdnResponse);
+ for (CDNContainer cdnContainer : cdnResponse) {
+ assertNotNull(cdnContainer.getName());
+ assertTrue(cdnContainer.isEnabled());
+ assertNotNull(cdnContainer.isLogRetentionEnabled());
+ assertNotNull(cdnContainer.getTtl());
+ assertNotNull(cdnContainer.getUri());
+ assertNotNull(cdnContainer.getSslUri());
+ assertNotNull(cdnContainer.getStreamingUri());
+ assertNotNull(cdnContainer.getIosUri());
+ }
+ }
+ }
+
+ public void testListWithOptions() throws Exception {
+ String lexicographicallyBeforeName = name.substring(0, name.length() - 1);
+ for (String regionId : regions) {
+ ListContainerOptions options = ListContainerOptions.Builder.marker(lexicographicallyBeforeName);
+ CDNContainer cdnContainer = api.cdnApiInRegion(regionId).list(options).get(0);
+
+ assertNotNull(cdnContainer.getName());
+ assertTrue(cdnContainer.isEnabled());
+ assertNotNull(cdnContainer.isLogRetentionEnabled());
+ assertNotNull(cdnContainer.getTtl());
+ assertNotNull(cdnContainer.getUri());
+ assertNotNull(cdnContainer.getSslUri());
+ assertNotNull(cdnContainer.getStreamingUri());
+ assertNotNull(cdnContainer.getIosUri());
+ }
+ }
+
+ public void testGet() throws Exception {
+ for (String regionId : regions) {
+ CDNContainer cdnContainer = api.cdnApiInRegion(regionId).get(name);
+ assertNotNull(cdnContainer);
+ }
+ }
+
+ @BeforeClass(groups = "live")
+ public void setup() {
+ super.setup();
+ for (String regionId : regions) {
+ api.containerApiInRegion(regionId).createIfAbsent(name, CreateContainerOptions.NONE);
+ api.cdnApiInRegion(regionId).enable(name);
+ }
+ }
+
+ @Override
+ @AfterClass(groups = "live")
+ public void tearDown() {
+ for (String regionId : regions) {
+ api.cdnApiInRegion(regionId).disable(name);
+ api.containerApiInRegion(regionId).deleteIfEmpty(name);
+ }
+ super.tearDown();
+ }
+}
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesCDNApiMockTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesCDNApiMockTest.java
new file mode 100644
index 0000000..916496e
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesCDNApiMockTest.java
@@ -0,0 +1,381 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.features;
+
+import static com.google.common.base.Charsets.US_ASCII;
+import static javax.ws.rs.core.HttpHeaders.CONTENT_LENGTH;
+import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
+import static javax.ws.rs.core.HttpHeaders.ETAG;
+import static javax.ws.rs.core.HttpHeaders.LAST_MODIFIED;
+import static org.jclouds.rackspace.cloudfiles.v1.options.UpdateCDNContainerOptions.Builder.enabled;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_ENABLED;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_IOS_URI;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_LOG_RETENTION;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_SSL_URI;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_STREAMING_URI;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_TTL;
+import static org.jclouds.rackspace.cloudfiles.v1.reference.CloudFilesHeaders.CDN_URI;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.net.URI;
+import java.util.List;
+
+import org.jclouds.io.Payload;
+import org.jclouds.io.Payloads;
+import org.jclouds.openstack.swift.v1.options.ListContainerOptions;
+import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest;
+import org.jclouds.rackspace.cloudfiles.v1.CloudFilesApi;
+import org.jclouds.rackspace.cloudfiles.v1.domain.CDNContainer;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+
+@Test(groups = "unit", testName = "CloudFilesCDNApiMockTest")
+public class CloudFilesCDNApiMockTest extends BaseOpenStackMockTest<CloudFilesApi> {
+
+ List<String> emails = ImmutableList.of("foo@bar.com", "bar@foo.com");
+
+ public void testList() throws Exception {
+ MockWebServer server = mockOpenStackServer();
+ server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+ server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/cdn_container_list.json"))));
+
+ try {
+ CloudFilesApi api = api(server.getUrl("/").toString(), "rackspace-cloudfiles");
+ CDNApi cdnApi = api.cdnApiInRegion("DFW");
+
+ ImmutableList<CDNContainer> cdnContainers = cdnApi.list().toList();
+
+ assertEquals(cdnContainers, mockContainers);
+
+ assertEquals(server.getRequestCount(), 2);
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "GET", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/?format=json&enabled_only=true");
+ } finally {
+ server.shutdown();
+ }
+ }
+
+ public void testListWithOptions() throws Exception {
+ MockWebServer server = mockOpenStackServer();
+ server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+ server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/cdn_container_list_at.json"))));
+
+ try {
+ CloudFilesApi api = api(server.getUrl("/").toString(), "rackspace-cloudfiles");
+ ListContainerOptions options = ListContainerOptions.Builder.marker("cdn-container-3");
+ ImmutableList<CDNContainer> containers = api.cdnApiInRegion("DFW").list(options).toList();
+
+ for(CDNContainer container : containers) {
+ checkCDNContainer(container);
+ }
+
+ assertEquals(containers, mockContainers.subList(2, mockContainers.size()));
+
+ assertEquals(server.getRequestCount(), 2);
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "GET", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/?format=json&enabled_only=true&marker=cdn-container-3");
+ } finally {
+ server.shutdown();
+ }
+ }
+
+ public void testEnableAndDisable() throws Exception {
+ MockWebServer server = mockOpenStackServer();
+ server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+ server.enqueue(addCommonHeaders(enabledResponse().setResponseCode(201)));
+ server.enqueue(addCommonHeaders(enabledResponse().setResponseCode(201)));
+ server.enqueue(addCommonHeaders(disabledResponse().setResponseCode(201)));
+
+ try {
+ CloudFilesApi api = api(server.getUrl("/").toString(), "rackspace-cloudfiles");
+ CDNApi cdnApi = api.cdnApiInRegion("DFW");
+
+ // enable a CDN Container
+ URI enabledContainer = cdnApi.enable("container-1");
+ assertNotNull(enabledContainer);
+
+ // ensure that it is disabled
+ assertTrue(cdnApi.disable("container-1"));
+
+ // get the container from the CDN and ensure that it is disabled
+ CDNContainer disabledContainer = cdnApi.get("container-1");
+ checkCDNContainer(disabledContainer);
+ assertFalse(disabledContainer.isEnabled());
+
+ assertEquals(server.getRequestCount(), 4);
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/container-1");
+ assertRequest(server.takeRequest(), "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/container-1");
+ assertRequest(server.takeRequest(), "HEAD", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/container-1");
+ } finally {
+ server.shutdown();
+ }
+ }
+
+ public void testEnableWithTTL() throws Exception {
+ MockWebServer server = mockOpenStackServer();
+ server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+ server.enqueue(addCommonHeaders(enabledResponse().setResponseCode(201)));
+
+ try {
+ CloudFilesApi api = api(server.getUrl("/").toString(), "rackspace-cloudfiles");
+ CDNApi cdnApi = api.cdnApiInRegion("DFW");
+
+ // enable a CDN Container with a TTL
+ URI enabledContainer = cdnApi.enable("container-1", 777777);
+ assertNotNull(enabledContainer);
+
+ assertEquals(server.getRequestCount(), 2);
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/container-1");
+ } finally {
+ server.shutdown();
+ }
+ }
+
+ public void testGet() throws Exception {
+ MockWebServer server = mockOpenStackServer();
+ server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+ server.enqueue(addCommonHeaders(enabledResponse().setResponseCode(201)));
+
+ try {
+ CloudFilesApi api = api(server.getUrl("/").toString(), "rackspace-cloudfiles");
+ CDNApi cdnApi = api.cdnApiInRegion("DFW");
+
+ CDNContainer cdnContainer = cdnApi.get("container-1");
+ checkCDNContainer(cdnContainer);
+ assertEquals(mockCDNContainer, cdnContainer);
+
+ assertEquals(server.getRequestCount(), 2);
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "HEAD", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/container-1");
+ } finally {
+ server.shutdown();
+ }
+ }
+
+ public void testGetFail() throws Exception {
+ MockWebServer server = mockOpenStackServer();
+ server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+ server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+ try {
+ CloudFilesApi api = api(server.getUrl("/").toString(), "rackspace-cloudfiles");
+ CDNApi cdnApi = api.cdnApiInRegion("DFW");
+
+ CDNContainer cdnContainer = cdnApi.get("container-1");
+
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "HEAD", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/container-1");
+ assertNull(cdnContainer);
+ } finally {
+ server.shutdown();
+ }
+ }
+
+ public void testPurgeObject() throws Exception {
+ MockWebServer server = mockOpenStackServer();
+ server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+ server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201)));
+
+ try {
+ CloudFilesApi api = api(server.getUrl("/").toString(), "rackspace-cloudfiles");
+ CDNApi cdnApi = api.cdnApiInRegion("DFW");
+
+ // purge the object
+ assertTrue(cdnApi.purgeObject("myContainer", "myObject", emails));
+
+ assertEquals(server.getRequestCount(), 2);
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "DELETE", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject");
+ } finally {
+ server.shutdown();
+ }
+ }
+
+ public void testUpdate() throws Exception {
+ MockWebServer server = mockOpenStackServer();
+ server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")).setResponseCode(200))); //POST
+ server.enqueue(addCommonHeaders(enabledResponse().setResponseCode(200)));
+ server.enqueue(addCommonHeaders(updatedResponse().setResponseCode(204)));
+ server.enqueue(addCommonHeaders(updatedResponse().setResponseCode(200)));
+
+ try {
+ CloudFilesApi api = api(server.getUrl("/").toString(), "rackspace-cloudfiles");
+ CDNApi cdnApi = api.cdnApiInRegion("DFW");
+
+ CDNContainer cdnContainer = cdnApi.get("container-1");
+ checkCDNContainer(cdnContainer);
+
+ // update the CDN Container
+ assertTrue(cdnApi.update("container-1", enabled(false).logRetention(true).ttl(7654321)));
+
+ cdnContainer = cdnApi.get("container-1");
+ checkCDNContainer(cdnContainer);
+
+ CDNContainer updatedContainer = CDNContainer.builder()
+ .name("container-1")
+ .enabled(false)
+ .logRetention(true)
+ .ttl(7654321)
+ .uri(URI.create("http://id-1.cdn.rackspace.com"))
+ .sslUri(URI.create("https://ssl-id-1.ssl.rackspace.com"))
+ .streamingUri(URI.create("http://streaming-id-1.stream.rackspace.com"))
+ .iosUri(URI.create("http://ios-id-1.iosr.rackspace.com"))
+ .build();
+
+ assertEquals(updatedContainer, cdnContainer);
+
+ assertEquals(server.getRequestCount(), 4);
+ assertAuthentication(server);
+ assertRequest(server.takeRequest(), "HEAD", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/container-1");
+ assertRequest(server.takeRequest(), "POST", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/container-1");
+ assertRequest(server.takeRequest(), "HEAD", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/container-1");
+ } finally {
+ server.shutdown();
+ }
+ }
+
+ private static final void checkCDNContainer(CDNContainer cdnContainer) {
+ assertNotNull(cdnContainer.getName());
+ assertNotNull(cdnContainer.isEnabled());
+ assertNotNull(cdnContainer.isLogRetentionEnabled());
+ assertNotNull(cdnContainer.getTtl());
+ assertNotNull(cdnContainer.getUri());
+ assertNotNull(cdnContainer.getSslUri());
+ assertNotNull(cdnContainer.getStreamingUri());
+ assertNotNull(cdnContainer.getIosUri());
+ }
+
+ private static final CDNContainer mockCDNContainer = CDNContainer.builder()
+ .name("container-1")
+ .enabled(true)
+ .logRetention(false)
+ .ttl(777777)
+ .uri(URI.create("http://id-1.cdn.rackspace.com"))
+ .sslUri(URI.create("https://ssl-id-1.ssl.rackspace.com"))
+ .streamingUri(URI.create("http://streaming-id-1.stream.rackspace.com"))
+ .iosUri(URI.create("http://ios-id-1.iosr.rackspace.com"))
+ .build();
+
+ private static MockResponse enabledResponse() {
+ return new MockResponse()
+ .addHeader(CDN_ENABLED, "true")
+ .addHeader(CDN_LOG_RETENTION, "false")
+ .addHeader(CDN_TTL, "777777")
+ .addHeader(CDN_URI,"http://id-1.cdn.rackspace.com")
+ .addHeader(CDN_SSL_URI, "https://ssl-id-1.ssl.rackspace.com")
+ .addHeader(CDN_STREAMING_URI, "http://streaming-id-1.stream.rackspace.com")
+ .addHeader(CDN_IOS_URI, "http://ios-id-1.iosr.rackspace.com")
+ .addHeader(CONTENT_LENGTH, "0")
+ .addHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
+ }
+
+ private static MockResponse disabledResponse() {
+ return new MockResponse()
+ .addHeader(CDN_ENABLED, "false")
+ .addHeader(CDN_LOG_RETENTION, "false")
+ .addHeader(CDN_TTL, "777777")
+ .addHeader(CDN_URI,"http://id-1.cdn.rackspace.com")
+ .addHeader(CDN_SSL_URI, "https://ssl-id-1.ssl.rackspace.com")
+ .addHeader(CDN_STREAMING_URI, "http://streaming-id-1.stream.rackspace.com")
+ .addHeader(CDN_IOS_URI, "http://ios-id-1.iosr.rackspace.com")
+ .addHeader(CONTENT_LENGTH, "0")
+ .addHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
+ }
+
+ private static MockResponse updatedResponse() {
+ return new MockResponse()
+ .addHeader(CDN_ENABLED, "false")
+ .addHeader(CDN_LOG_RETENTION, "true")
+ .addHeader(CDN_TTL, "7654321")
+ .addHeader(CDN_URI,"http://id-1.cdn.rackspace.com")
+ .addHeader(CDN_SSL_URI, "https://ssl-id-1.ssl.rackspace.com")
+ .addHeader(CDN_STREAMING_URI, "http://streaming-id-1.stream.rackspace.com")
+ .addHeader(CDN_IOS_URI, "http://ios-id-1.iosr.rackspace.com")
+ .addHeader(CONTENT_LENGTH, "0")
+ .addHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
+ }
+
+ private static final ImmutableList<CDNContainer> mockContainers = ImmutableList.of(
+ CDNContainer.builder()
+ .name("cdn-container-1")
+ .enabled(true)
+ .logRetention(false)
+ .ttl(259200)
+ .uri(URI.create("http://id-1.cdn.rackspace.com"))
+ .sslUri(URI.create("https://ssl-id-1.ssl.rackspace.com"))
+ .streamingUri(URI.create("http://streaming-id-1.stream.rackspace.com"))
+ .iosUri(URI.create("http://ios-id-1.iosr.rackspace.com"))
+ .build(),
+ CDNContainer.builder()
+ .name("cdn-container-2")
+ .enabled(true)
+ .logRetention(true)
+ .ttl(259200)
+ .uri(URI.create("http://id-2.cdn.rackspace.com"))
+ .sslUri(URI.create("https://ssl-id-2.ssl.rackspace.com"))
+ .streamingUri(URI.create("http://streaming-id-2.stream.rackspace.com"))
+ .iosUri(URI.create("http://ios-id-2.iosr.rackspace.com"))
+ .build(),
+ CDNContainer.builder()
+ .name("cdn-container-3")
+ .enabled(true)
+ .logRetention(false)
+ .ttl(259200)
+ .uri(URI.create("http://id-3.cdn.rackspace.com"))
+ .sslUri(URI.create("https://ssl-id-3.ssl.rackspace.com"))
+ .streamingUri(URI.create("http://streaming-id-3.stream.rackspace.com"))
+ .iosUri(URI.create("http://ios-id-3.iosr.rackspace.com"))
+ .build(),
+ CDNContainer.builder()
+ .name("cdn-container-4")
+ .enabled(true)
+ .logRetention(true)
+ .ttl(777777)
+ .uri(URI.create("http://id-4.cdn.rackspace.com"))
+ .sslUri(URI.create("https://ssl-id-4.ssl.rackspace.com"))
+ .streamingUri(URI.create("http://streaming-id-4.stream.rackspace.com"))
+ .iosUri(URI.create("http://ios-id-4.iosr.rackspace.com"))
+ .build());
+
+ private static MockResponse objectResponse() {
+ return new MockResponse()
+ .addHeader(LAST_MODIFIED, "Fri, 12 Jun 2010 13:40:18 GMT")
+ .addHeader(ETAG, "8a964ee2a5e88be344f36c22562a6486")
+ // TODO: MWS doesn't allow you to return content length w/o content
+ // on HEAD!
+ .setBody("ABCD".getBytes(US_ASCII))
+ .addHeader(CONTENT_LENGTH, "4").addHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
+ }
+
+ private static final byte[] NO_CONTENT = new byte[] {};
+
+ private static Payload payload(long bytes, String contentType) {
+ Payload payload = Payloads.newByteArrayPayload(NO_CONTENT);
+ payload.getContentMetadata().setContentLength(bytes);
+ payload.getContentMetadata().setContentType(contentType);
+ return payload;
+ }
+}
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesContainerApiLiveTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesContainerApiLiveTest.java
new file mode 100644
index 0000000..4db4e5a
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesContainerApiLiveTest.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.features;
+
+import org.jclouds.openstack.swift.v1.features.ContainerApiLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudFilesContainerApiLiveTest")
+public class CloudFilesContainerApiLiveTest extends ContainerApiLiveTest {
+ public CloudFilesContainerApiLiveTest() {
+ provider = "rackspace-cloudfiles";
+ }
+}
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesObjectApiLiveTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesObjectApiLiveTest.java
new file mode 100644
index 0000000..a0ffa31
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/features/CloudFilesObjectApiLiveTest.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.features;
+
+import org.jclouds.openstack.swift.v1.features.ObjectApiLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudFilesObjectApiLiveTest")
+public class CloudFilesObjectApiLiveTest extends ObjectApiLiveTest {
+ public CloudFilesObjectApiLiveTest() {
+ provider = "rackspace-cloudfiles";
+ }
+}
diff --git a/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/internal/BaseCloudFilesApiLiveTest.java b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/internal/BaseCloudFilesApiLiveTest.java
new file mode 100644
index 0000000..6586cd1
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/java/org/jclouds/rackspace/cloudfiles/v1/internal/BaseCloudFilesApiLiveTest.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.rackspace.cloudfiles.v1.internal;
+
+import static org.testng.Assert.assertNotNull;
+
+import org.jclouds.openstack.swift.v1.domain.Container;
+import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest;
+import org.jclouds.rackspace.cloudfiles.v1.CloudFilesApi;
+import org.testng.annotations.Test;
+
+/**
+ * Base class for all Cloud Files API Live tests.
+ *
+ * @author Jeremy Daggett
+ */
+@Test(groups = "live", testName = "BaseCloudFilesApiLiveTest")
+public abstract class BaseCloudFilesApiLiveTest extends BaseSwiftApiLiveTest<CloudFilesApi> {
+
+ protected BaseCloudFilesApiLiveTest() {
+ provider = "rackspace-cloudfiles";
+ }
+}
diff --git a/rackspace-cloudfiles/src/test/resources/cdn_container_list.json b/rackspace-cloudfiles/src/test/resources/cdn_container_list.json
new file mode 100644
index 0000000..4dce8db
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/resources/cdn_container_list.json
@@ -0,0 +1,42 @@
+[
+ {
+ "cdn_streaming_uri": "http://streaming-id-1.stream.rackspace.com",
+ "name": "cdn-container-1",
+ "cdn_ios_uri": "http://ios-id-1.iosr.rackspace.com",
+ "cdn_ssl_uri": "https://ssl-id-1.ssl.rackspace.com",
+ "cdn_enabled": true,
+ "ttl": 259200,
+ "log_retention": false,
+ "cdn_uri": "http://id-1.cdn.rackspace.com"
+ },
+ {
+ "cdn_streaming_uri": "http://streaming-id-2.stream.rackspace.com",
+ "name": "cdn-container-2",
+ "cdn_ios_uri": "http://ios-id-2.iosr.rackspace.com",
+ "cdn_ssl_uri": "https://ssl-id-2.ssl.rackspace.com",
+ "cdn_enabled": true,
+ "ttl": 259200,
+ "log_retention": true,
+ "cdn_uri": "http://id-2.cdn.rackspace.com"
+ },
+ {
+ "cdn_streaming_uri": "http://streaming-id-3.stream.rackspace.com",
+ "name": "cdn-container-3",
+ "cdn_ios_uri": "http://ios-id-3.iosr.rackspace.com",
+ "cdn_ssl_uri": "https://ssl-id-3.ssl.rackspace.com",
+ "cdn_enabled": true,
+ "ttl": 259200,
+ "log_retention": false,
+ "cdn_uri": "http://id-3.cdn.rackspace.com"
+ },
+ {
+ "cdn_streaming_uri": "http://streaming-id-4.stream.rackspace.com",
+ "name": "cdn-container-4",
+ "cdn_ios_uri": "http://ios-id-4.iosr.rackspace.com",
+ "cdn_ssl_uri": "https://ssl-id-4.ssl.rackspace.com",
+ "cdn_enabled": true,
+ "ttl": 777777,
+ "log_retention": true,
+ "cdn_uri": "http://id-4.cdn.rackspace.com"
+ }
+]
diff --git a/rackspace-cloudfiles/src/test/resources/cdn_container_list_at.json b/rackspace-cloudfiles/src/test/resources/cdn_container_list_at.json
new file mode 100644
index 0000000..f1fa9ee
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/resources/cdn_container_list_at.json
@@ -0,0 +1,22 @@
+[
+ {
+ "cdn_streaming_uri": "http://streaming-id-3.stream.rackspace.com",
+ "name": "cdn-container-3",
+ "cdn_ios_uri": "http://ios-id-3.iosr.rackspace.com",
+ "cdn_ssl_uri": "https://ssl-id-3.ssl.rackspace.com",
+ "cdn_enabled": true,
+ "ttl": 259200,
+ "log_retention": false,
+ "cdn_uri": "http://id-3.cdn.rackspace.com"
+ },
+ {
+ "cdn_streaming_uri": "http://streaming-id-4.stream.rackspace.com",
+ "name": "cdn-container-4",
+ "cdn_ios_uri": "http://ios-id-4.iosr.rackspace.com",
+ "cdn_ssl_uri": "https://ssl-id-4.ssl.rackspace.com",
+ "cdn_enabled": true,
+ "ttl": 777777,
+ "log_retention": true,
+ "cdn_uri": "http://id-4.cdn.rackspace.com"
+ }
+]
\ No newline at end of file
diff --git a/rackspace-cloudfiles/src/test/resources/logback.xml b/rackspace-cloudfiles/src/test/resources/logback.xml
new file mode 100644
index 0000000..ce891f1
--- /dev/null
+++ b/rackspace-cloudfiles/src/test/resources/logback.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+
+-->
+<configuration scan="false">
+ <appender name="FILE" class="ch.qos.logback.core.FileAppender">
+ <file>target/test-data/jclouds.log</file>
+
+ <encoder>
+ <Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
+ </encoder>
+ </appender>
+
+ <appender name="WIREFILE" class="ch.qos.logback.core.FileAppender">
+ <file>target/test-data/jclouds-wire.log</file>
+
+ <encoder>
+ <Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
+ </encoder>
+ </appender>
+
+ <appender name="BLOBSTOREFILE" class="ch.qos.logback.core.FileAppender">
+ <file>target/test-data/jclouds-blobstore.log</file>
+
+ <encoder>
+ <Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
+ </encoder>
+ </appender>
+
+ <root>
+ <level value="warn" />
+ </root>
+
+ <logger name="org.jclouds">
+ <level value="DEBUG" />
+ <appender-ref ref="FILE" />
+ </logger>
+
+<!--
+ <logger name="jclouds.wire">
+ <level value="DEBUG" />
+ <appender-ref ref="WIREFILE" />
+ </logger>
+-->
+
+ <logger name="jclouds.headers">
+ <level value="DEBUG" />
+ <appender-ref ref="WIREFILE" />
+ </logger>
+
+ <logger name="jclouds.blobstore">
+ <level value="DEBUG" />
+ <appender-ref ref="BLOBSTOREFILE" />
+ </logger>
+
+</configuration>