You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by an...@apache.org on 2014/10/09 00:17:14 UTC
[3/6] Import openstack-swift from labs.
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java
new file mode 100644
index 0000000..cc934e4
--- /dev/null
+++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java
@@ -0,0 +1,87 @@
+/*
+ * 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.functions;
+
+import static com.google.common.io.BaseEncoding.base16;
+import static com.google.common.net.HttpHeaders.ETAG;
+import static com.google.common.net.HttpHeaders.LAST_MODIFIED;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.OBJECT_DELETE_AT;
+
+import java.net.URI;
+import java.util.Date;
+
+import javax.inject.Inject;
+
+import org.jclouds.date.DateService;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.io.MutableContentMetadata;
+import org.jclouds.io.Payload;
+import org.jclouds.openstack.swift.v1.domain.SwiftObject;
+import org.jclouds.rest.InvocationContext;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+
+import com.google.common.base.Function;
+import com.google.common.hash.HashCode;
+
+public class ParseObjectFromResponse implements Function<HttpResponse, SwiftObject>,
+ InvocationContext<ParseObjectFromResponse> {
+ private final DateService dates;
+
+ @Inject
+ ParseObjectFromResponse(DateService dates) {
+ this.dates = dates;
+ }
+
+ private String uri;
+ private String name;
+
+ @Override
+ public SwiftObject apply(HttpResponse from) {
+
+ Payload payload = from.getPayload();
+ MutableContentMetadata contentMeta = payload.getContentMetadata();
+
+ String deleteAt = from.getFirstHeaderOrNull(OBJECT_DELETE_AT);
+ if (deleteAt != null) {
+ long fromEpoch = Long.parseLong(from.getFirstHeaderOrNull(OBJECT_DELETE_AT)) * 1000;
+ contentMeta.setExpires(new Date(fromEpoch));
+ payload.setContentMetadata(contentMeta);
+ }
+
+ String etag = from.getFirstHeaderOrNull(ETAG);
+ if (etag != null) {
+ payload.getContentMetadata().setContentMD5(HashCode.fromBytes(base16().lowerCase().decode(etag)));
+ }
+
+ return SwiftObject.builder()
+ .uri(URI.create(uri))
+ .name(name)
+ .etag(etag)
+ .payload(payload)
+ .lastModified(dates.rfc822DateParse(from.getFirstHeaderOrNull(LAST_MODIFIED)))
+ .headers(from.getHeaders())
+ .metadata(EntriesWithoutMetaPrefix.INSTANCE.apply(from.getHeaders())).build();
+ }
+
+ @Override
+ public ParseObjectFromResponse setContext(HttpRequest request) {
+ this.uri = request.getEndpoint().toString();
+ this.name = GeneratedHttpRequest.class.cast(request).getInvocation().getArgs().get(0).toString();
+ return this;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java
new file mode 100644
index 0000000..ff12e0f
--- /dev/null
+++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java
@@ -0,0 +1,113 @@
+/*
+ * 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.functions;
+
+import static com.google.common.io.BaseEncoding.base16;
+import static org.jclouds.http.Uris.uriBuilder;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.io.Payload;
+import org.jclouds.io.Payloads;
+import org.jclouds.openstack.swift.v1.domain.Container;
+import org.jclouds.openstack.swift.v1.domain.ObjectList;
+import org.jclouds.openstack.swift.v1.domain.SwiftObject;
+import org.jclouds.rest.InvocationContext;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import com.google.common.hash.HashCode;
+import com.google.common.io.ByteSource;
+
+public class ParseObjectListFromResponse implements Function<HttpResponse, ObjectList>,
+ InvocationContext<ParseObjectListFromResponse> {
+
+ private static final class InternalObject {
+ String name;
+ String hash;
+ long bytes;
+ String content_type;
+ Date last_modified;
+ Date expires;
+ }
+
+ private final ParseJson<List<InternalObject>> json;
+ private final ParseContainerFromHeaders parseContainer;
+
+ @Inject
+ ParseObjectListFromResponse(ParseJson<List<InternalObject>> json, ParseContainerFromHeaders parseContainer) {
+ this.json = json;
+ this.parseContainer = parseContainer;
+ }
+
+ private ToSwiftObject toSwiftObject;
+
+ @Override
+ public ObjectList apply(HttpResponse from) {
+ List<SwiftObject> objects = Lists.transform(json.apply(from), toSwiftObject);
+ Container container = parseContainer.apply(from);
+ return ObjectList.create(objects, container);
+ }
+
+ static class ToSwiftObject implements Function<InternalObject, SwiftObject> {
+ private final String containerUri;
+
+ ToSwiftObject(String containerUri) {
+ this.containerUri = containerUri;
+ }
+
+ @Override
+ public SwiftObject apply(InternalObject input) {
+ return SwiftObject.builder()
+ .uri(uriBuilder(containerUri).clearQuery().appendPath(input.name).build())
+ .name(input.name)
+ .etag(input.hash)
+ .payload(payload(input.bytes, input.hash, input.content_type, input.expires))
+ .lastModified(input.last_modified).build();
+ }
+ }
+
+ @Override
+ public ParseObjectListFromResponse setContext(HttpRequest request) {
+ parseContainer.name = GeneratedHttpRequest.class.cast(request).getCaller().get().getArgs().get(1).toString();
+ String containerUri = request.getEndpoint().toString();
+ int queryIndex = containerUri.indexOf('?');
+ if (queryIndex != -1) {
+ containerUri = containerUri.substring(0, queryIndex);
+ }
+ toSwiftObject = new ToSwiftObject(containerUri);
+ return this;
+ }
+
+ private static Payload payload(long bytes, String hash, String contentType, Date expires) {
+ Payload payload = Payloads.newByteSourcePayload(ByteSource.empty());
+ payload.getContentMetadata().setContentLength(bytes);
+ payload.getContentMetadata().setContentType(contentType);
+ payload.getContentMetadata().setExpires(expires);
+ if (hash != null) {
+ payload.getContentMetadata().setContentMD5(HashCode.fromBytes(base16().lowerCase().decode(hash)));
+ }
+ return payload;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.java
new file mode 100644
index 0000000..2bde41c
--- /dev/null
+++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/handlers/SwiftErrorHandler.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.openstack.swift.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 SwiftErrorHandler 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);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/CreateContainerOptions.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/CreateContainerOptions.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/CreateContainerOptions.java
new file mode 100644
index 0000000..2014f61
--- /dev/null
+++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/CreateContainerOptions.java
@@ -0,0 +1,108 @@
+/*
+ * 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.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.VERSIONS_LOCATION;
+
+import java.util.Map;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+import org.jclouds.openstack.swift.v1.binders.BindMetadataToHeaders;
+
+import com.google.common.collect.Multimap;
+
+/**
+ * Options for creating a {@link Container}
+ *
+ * @see ContainerApi#create(String, CreateContainerOptions)
+ */
+public class CreateContainerOptions extends BaseHttpRequestOptions {
+
+ public static final CreateContainerOptions NONE = new CreateContainerOptions();
+
+ /**
+ * Sets the headers on a container at creation.
+ */
+ public CreateContainerOptions headers(Multimap<String, String> headers) {
+ this.headers.putAll(headers);
+ return this;
+ }
+
+ /**
+ * Sets the metadata on a container at creation.
+ */
+ public CreateContainerOptions metadata(Map<String, String> metadata) {
+ this.headers.putAll(bindMetadataToHeaders.toHeaders(metadata));
+ return this;
+ }
+
+ /**
+ * Sets the public ACL on the container so that anybody can read it.
+ */
+ public CreateContainerOptions anybodyRead() {
+ 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(VERSIONS_LOCATION, containerName);
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @see CreateContainerOptions#anybodyRead
+ */
+ public static CreateContainerOptions anybodyRead() {
+ CreateContainerOptions options = new CreateContainerOptions();
+ return options.anybodyRead();
+ }
+
+ /**
+ * @see CreateContainerOptions#headers
+ */
+ public static CreateContainerOptions headers(Multimap<String, String> headers) {
+ CreateContainerOptions options = new CreateContainerOptions();
+ return options.headers(headers);
+ }
+
+ /**
+ * @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(CONTAINER_METADATA_PREFIX);
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/ListContainerOptions.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/ListContainerOptions.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/ListContainerOptions.java
new file mode 100644
index 0000000..8b01aae
--- /dev/null
+++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/ListContainerOptions.java
@@ -0,0 +1,132 @@
+/*
+ * 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.options;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Options for listing containers.
+ *
+ * @see ContainerApi#list(ListContainerOptions)
+ */
+public class ListContainerOptions extends BaseHttpRequestOptions {
+ public static final ListContainerOptions NONE = new ListContainerOptions();
+
+ /**
+ * 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");
+ queryParameters.put("limit", Integer.toString(limit));
+ return this;
+ }
+
+ /**
+ * 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.
+ */
+ public ListContainerOptions endMarker(String endMarker) {
+ queryParameters.put("end_marker", checkNotNull(endMarker, "endMarker"));
+ return this;
+ }
+
+ /**
+ * 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.
+ */
+ public ListContainerOptions delimiter(char delimiter) {
+ queryParameters.put("delimiter", Character.toString(delimiter));
+ return this;
+ }
+
+ /**
+ * object names nested in the pseudo path are returned.
+ */
+ public ListContainerOptions path(String path) {
+ queryParameters.put("path", checkNotNull(path, "path"));
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @see ListContainerOptions#limit
+ */
+ public static ListContainerOptions limit(int limit) {
+ ListContainerOptions options = new ListContainerOptions();
+ return options.limit(limit);
+ }
+
+ /**
+ * @see ListContainerOptions#marker
+ */
+ public static ListContainerOptions marker(String marker) {
+ ListContainerOptions options = new ListContainerOptions();
+ return options.marker(marker);
+ }
+
+ /**
+ * @see ListContainerOptions#endMarker
+ */
+ public static ListContainerOptions endMarker(String endMarker) {
+ ListContainerOptions options = new ListContainerOptions();
+ return options.endMarker(endMarker);
+ }
+
+ /**
+ * @see ListContainerOptions#prefix
+ */
+ public static ListContainerOptions prefix(String prefix) {
+ ListContainerOptions options = new ListContainerOptions();
+ return options.prefix(prefix);
+ }
+
+ /**
+ * @see ListContainerOptions#delimiter
+ */
+ public static ListContainerOptions delimiter(char delimiter) {
+ ListContainerOptions options = new ListContainerOptions();
+ return options.delimiter(delimiter);
+ }
+
+ /**
+ * @see ListContainerOptions#path
+ */
+ public static ListContainerOptions path(String path) {
+ ListContainerOptions options = new ListContainerOptions();
+ return options.path(path);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/PutOptions.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/PutOptions.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/PutOptions.java
new file mode 100644
index 0000000..d4a1ed3
--- /dev/null
+++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/PutOptions.java
@@ -0,0 +1,71 @@
+/*
+ * 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.options;
+
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.OBJECT_METADATA_PREFIX;
+
+import java.util.Map;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+import org.jclouds.openstack.swift.v1.binders.BindMetadataToHeaders;
+
+import com.google.common.collect.Multimap;
+
+/**
+ * Options for creating an Object.
+ */
+public class PutOptions extends BaseHttpRequestOptions {
+
+ public static final PutOptions NONE = new PutOptions();
+
+ /**
+ * Sets the metadata on a container at creation.
+ */
+ public PutOptions metadata(Map<String, String> metadata) {
+ this.headers.putAll(bindMetadataToHeaders.toHeaders(metadata));
+ return this;
+ }
+
+ /**
+ * Sets the headers on a container at creation.
+ */
+ public PutOptions headers(Multimap<String, String> headers) {
+ this.headers.putAll(headers);
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @see PutOptions#headers
+ */
+ public static PutOptions headers(Multimap<String, String> headers) {
+ PutOptions options = new PutOptions();
+ return options.headers(headers);
+ }
+
+ /**
+ * @see PutOptions#metadata
+ */
+ public static PutOptions metadata(Map<String, String> metadata) {
+ PutOptions options = new PutOptions();
+ return options.metadata(metadata);
+ }
+ }
+
+ private static final BindMetadataToHeaders bindMetadataToHeaders = new BindMetadataToHeaders(OBJECT_METADATA_PREFIX);
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/UpdateContainerOptions.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/UpdateContainerOptions.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/UpdateContainerOptions.java
new file mode 100644
index 0000000..f74b7fe
--- /dev/null
+++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/options/UpdateContainerOptions.java
@@ -0,0 +1,107 @@
+/*
+ * 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.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.VERSIONS_LOCATION;
+
+import java.util.Map;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+import org.jclouds.openstack.swift.v1.binders.BindMetadataToHeaders;
+
+import com.google.common.collect.Multimap;
+
+/**
+ * Options for updating a {@link Container}.
+ *
+ * @see org.jclouds.openstack.swift.v1.features.ContainerApi#update(String, UpdateContainerOptions)
+ */
+public class UpdateContainerOptions extends BaseHttpRequestOptions {
+ public static final UpdateContainerOptions NONE = new UpdateContainerOptions();
+
+ /**
+ * Sets the headers on a container at creation.
+ */
+ public UpdateContainerOptions headers(Multimap<String, String> headers) {
+ this.headers.putAll(headers);
+ return this;
+ }
+
+ /**
+ * Sets the metadata on a container at creation.
+ */
+ public UpdateContainerOptions metadata(Map<String, String> metadata) {
+ this.headers.putAll(bindMetadataToHeaders.toHeaders(metadata));
+ return this;
+ }
+
+ /**
+ * Sets the public ACL on the container so that anybody can read it.
+ */
+ public UpdateContainerOptions anybodyRead() {
+ this.headers.put(CONTAINER_READ, CONTAINER_ACL_ANYBODY_READ);
+ return this;
+ }
+
+ /**
+ * Sets the container that will contain object versions.
+ */
+ public UpdateContainerOptions versionsLocation(String containerName) {
+ this.headers.put(VERSIONS_LOCATION, containerName);
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @see UpdateContainerOptions#anybodyRead
+ */
+ public static UpdateContainerOptions anybodyRead() {
+ UpdateContainerOptions options = new UpdateContainerOptions();
+ return options.anybodyRead();
+ }
+
+ /**
+ * @see UpdateContainerOptions#headers
+ */
+ public static UpdateContainerOptions headers(Multimap<String, String> headers) {
+ UpdateContainerOptions options = new UpdateContainerOptions();
+ return options.headers(headers);
+ }
+
+ /**
+ * @see UpdateContainerOptions#metadata
+ */
+ public static UpdateContainerOptions metadata(Map<String, String> metadata) {
+ UpdateContainerOptions options = new UpdateContainerOptions();
+ return options.metadata(metadata);
+ }
+
+ /**
+ * @see UpdateContainerOptions#versionsLocation
+ */
+ public static UpdateContainerOptions versionsLocation(String containerName) {
+ UpdateContainerOptions options = new UpdateContainerOptions();
+ return options.versionsLocation(containerName);
+ }
+ }
+
+ private static final BindMetadataToHeaders bindMetadataToHeaders = new BindMetadataToHeaders(CONTAINER_METADATA_PREFIX);
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/reference/SwiftHeaders.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/reference/SwiftHeaders.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/reference/SwiftHeaders.java
new file mode 100644
index 0000000..caab5e7
--- /dev/null
+++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/reference/SwiftHeaders.java
@@ -0,0 +1,92 @@
+/*
+ * 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.reference;
+
+/**
+ * Common headers in Swift.
+ */
+public final class SwiftHeaders {
+
+ // Common Metadata Prefixes
+ public static final String ACCOUNT_METADATA_PREFIX = "X-Account-Meta-";
+ public static final String CONTAINER_METADATA_PREFIX = "X-Container-Meta-";
+ public static final String OBJECT_METADATA_PREFIX = "X-Object-Meta-";
+ public static final String USER_METADATA_PREFIX = OBJECT_METADATA_PREFIX;
+
+ // Metadata Removal Prefixes
+ public static final String ACCOUNT_REMOVE_METADATA_PREFIX = "X-Remove-Account-Meta-";
+ public static final String CONTAINER_REMOVE_METADATA_PREFIX = "X-Remove-Container-Meta-";
+ public static final String OBJECT_REMOVE_METADATA_PREFIX = "X-Remove-Object-Meta-";
+
+ // TempURL
+ public static final String ACCOUNT_TEMPORARY_URL_KEY = ACCOUNT_METADATA_PREFIX + "Temp-Url-Key";
+ public static final String ACCOUNT_TEMPORARY_URL_KEY_2 = ACCOUNT_TEMPORARY_URL_KEY + "-2";
+
+ // Account Headers
+ public static final String ACCOUNT_BYTES_USED = "X-Account-Bytes-Used";
+ public static final String ACCOUNT_CONTAINER_COUNT = "X-Account-Container-Count";
+ public static final String ACCOUNT_OBJECT_COUNT = "X-Account-Object-Count";
+
+ // Container Headers
+ public static final String CONTAINER_BYTES_USED = "X-Container-Bytes-Used";
+ public static final String CONTAINER_OBJECT_COUNT = "X-Container-Object-Count";
+
+ // Public access - not supported in all Swift Impls
+ public static final String CONTAINER_READ = "X-Container-Read";
+ public static final String CONTAINER_WRITE = "X-Container-Write";
+ public static final String CONTAINER_ACL_ANYBODY_READ = ".r:*,.rlistings";
+
+ // CORS
+ public static final String CONTAINER_ACCESS_CONTROL_ALLOW_ORIGIN = CONTAINER_METADATA_PREFIX + "Access-Control-Allow-Origin";
+ public static final String CONTAINER_ACCESS_CONTROL_MAX_AGE = CONTAINER_METADATA_PREFIX + "Access-Control-Max-Age";
+ public static final String CONTAINER_ACCESS_CONTROL_EXPOSE_HEADERS = CONTAINER_METADATA_PREFIX + "Access-Control-Expose-Headers";
+
+ // Container Quota
+ public static final String CONTAINER_QUOTA_BYTES = CONTAINER_METADATA_PREFIX + "Quota-Bytes";
+ public static final String CONTAINER_QUOTA_COUNT = CONTAINER_METADATA_PREFIX + "Quota-Count";
+
+ // Container Sync
+ public static final String CONTAINER_SYNC_KEY = "X-Container-Sync-Key";
+ public static final String CONTAINER_SYNC_TO = "X-Container-Sync-To";
+
+ // Versioning
+ public static final String VERSIONS_LOCATION = "X-Versions-Location";
+
+ // Misc functionality
+ public static final String CONTAINER_WEB_MODE = "X-Web-Mode";
+
+ public static final String OBJECT_COPY_FROM = "X-Copy-From";
+ public static final String OBJECT_DELETE_AFTER = "X-Delete-After";
+ public static final String OBJECT_DELETE_AT = "X-Delete-At";
+ public static final String OBJECT_MANIFEST = "X-Object-Manifest";
+ /** Get the newest version of the object for GET and HEAD requests */
+ public static final String OBJECT_NEWEST = "X-Newest";
+
+ // Static Large Object
+ public static final String STATIC_LARGE_OBJECT = "X-Static-Large-Object";
+
+ // Static Web
+ public static final String STATIC_WEB_INDEX = CONTAINER_METADATA_PREFIX + "Web-Index";
+ public static final String STATIC_WEB_DIRECTORY_TYPE = CONTAINER_METADATA_PREFIX + "Web-Directory-Type";
+ public static final String STATIC_WEB_ERROR = CONTAINER_METADATA_PREFIX + "Web-Error";
+ public static final String STATIC_WEB_LISTINGS = CONTAINER_METADATA_PREFIX + "Web-Listings";
+ public static final String STATIC_WEB_LISTINGS_CSS = CONTAINER_METADATA_PREFIX + "Web-Listings-CSS";
+
+ private SwiftHeaders() {
+ throw new AssertionError("intentionally unimplemented");
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/apis/openstack-swift/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
new file mode 100644
index 0000000..c5b8017
--- /dev/null
+++ b/apis/openstack-swift/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.openstack.swift.v1.SwiftApiMetadata
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/AuthenticationMockTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/AuthenticationMockTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/AuthenticationMockTest.java
new file mode 100644
index 0000000..8b5e895
--- /dev/null
+++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/AuthenticationMockTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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;
+
+import static com.google.common.base.Charsets.UTF_8;
+import static org.jclouds.openstack.swift.v1.features.AccountApiMockTest.accountResponse;
+import static org.testng.Assert.assertEquals;
+
+import java.util.Properties;
+
+import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import com.squareup.okhttp.mockwebserver.RecordedRequest;
+
+/**
+ * @see KeystoneProperties#CREDENTIAL_TYPE
+ */
+@Test
+public class AuthenticationMockTest extends BaseOpenStackMockTest<SwiftApi> {
+
+ @DataProvider(name = "jclouds.keystone.credential-type")
+ Object[][] credentialTypeToPostBody() {
+ Object[][] credentialTypeToPostBody = new Object[2][2];
+ credentialTypeToPostBody[0][0] = "apiAccessKeyCredentials";
+ credentialTypeToPostBody[0][1] = "{\"auth\":{\"apiAccessKeyCredentials\":{\"accessKey\":\"joe\",\"secretKey\":\"letmein\"},\"tenantName\":\"jclouds\"}}";
+ credentialTypeToPostBody[1][0] = "passwordCredentials";
+ credentialTypeToPostBody[1][1] = "{\"auth\":{\"passwordCredentials\":{\"username\":\"joe\",\"password\":\"letmein\"},\"tenantName\":\"jclouds\"}}";
+ return credentialTypeToPostBody;
+ }
+
+ @Test(dataProvider = "jclouds.keystone.credential-type")
+ public void authenticateCredentialType(String credentialType, String expectedPost) throws Exception {
+ MockWebServer server = mockOpenStackServer();
+ server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+ server.enqueue(addCommonHeaders(accountResponse()));
+
+ try {
+ Properties overrides = new Properties();
+ overrides.setProperty("jclouds.keystone.credential-type", credentialType);
+
+ SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift", overrides);
+
+ api.getAccountApi("DFW").get();
+
+ assertEquals(server.getRequestCount(), 2);
+ RecordedRequest authRequest = server.takeRequest();
+ assertEquals(authRequest.getRequestLine(), "POST /tokens HTTP/1.1");
+ assertEquals(new String(authRequest.getBody(), UTF_8), expectedPost);
+ } finally {
+ server.shutdown();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java
new file mode 100644
index 0000000..6fbe4d9
--- /dev/null
+++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftApiMetadataTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+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;
+
+@Test(groups = "unit", testName = "SwiftApiMetadataTest")
+// public class SwiftApiMetadataTest extends BaseBlobStoreApiMetadataTest {
+public class SwiftApiMetadataTest extends BaseApiMetadataTest {
+ public SwiftApiMetadataTest() {
+ super(new SwiftApiMetadata(), ImmutableSet.<TypeToken<? extends View>> of());
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java
new file mode 100644
index 0000000..703da9b
--- /dev/null
+++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/SwiftErrorHandlerTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reportMatcher;
+import static org.easymock.EasyMock.verify;
+import static org.jclouds.io.Payloads.newByteSourcePayload;
+
+import java.net.URI;
+
+import org.easymock.IArgumentMatcher;
+import org.jclouds.blobstore.ContainerNotFoundException;
+import org.jclouds.blobstore.KeyNotFoundException;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.swift.v1.handlers.SwiftErrorHandler;
+import org.testng.annotations.Test;
+
+import com.google.common.io.ByteSource;
+
+/**
+ * Tests the {@link SwiftErrorHandler}
+ */
+@Test(groups = "unit", testName = "SwiftErrorHandlerTest")
+public class SwiftErrorHandlerTest {
+
+ @Test
+ public void test404SetsKeyNotFoundExceptionMosso() {
+ assertCodeMakes("HEAD", URI
+ .create("http://host/v1/MossoCloudFS_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1/key"), 404,
+ "Not Found", "", KeyNotFoundException.class);
+ }
+
+ @Test
+ public void test404SetsKeyNotFoundExceptionSwift() {
+ assertCodeMakes("HEAD", URI
+ .create("http://67.202.39.175:8080/v1/AUTH_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1/key"),
+ 404, "Not Found", "", KeyNotFoundException.class);
+ }
+
+ @Test
+ public void test404SetsContainerNotFoundExceptionMosso() {
+ assertCodeMakes("HEAD", URI
+ .create("http://host/v1/MossoCloudFS_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1"), 404,
+ "Not Found", "", ContainerNotFoundException.class);
+ }
+
+ @Test
+ public void test404SetsContainerNotFoundExceptionSwift() {
+ assertCodeMakes("HEAD", URI
+ .create("http://67.202.39.175:8080/v1/AUTH_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1"),
+ 404, "Not Found", "", ContainerNotFoundException.class);
+ }
+
+ private void assertCodeMakes(String method, URI uri, int statusCode, String message, String content,
+ Class<? extends Exception> expected) {
+ assertCodeMakes(method, uri, statusCode, message, "text/plain", content, expected);
+ }
+
+ private void assertCodeMakes(String method, URI uri, int statusCode, String message, String contentType,
+ String content, Class<? extends Exception> expected) {
+
+ SwiftErrorHandler function = new SwiftErrorHandler();
+
+ HttpCommand command = createMock(HttpCommand.class);
+ HttpRequest request = HttpRequest.builder().method(method).endpoint(uri).build();
+ HttpResponse response = HttpResponse.builder().statusCode(statusCode).message(message)
+ .payload(newByteSourcePayload(ByteSource.wrap(content.getBytes()))).build();
+ response.getPayload().getContentMetadata().setContentType(contentType);
+
+ expect(command.getCurrentRequest()).andReturn(request).atLeastOnce();
+ command.setException(classEq(expected));
+
+ replay(command);
+
+ function.handleError(command, response);
+
+ verify(command);
+ }
+
+ public static Exception classEq(final Class<? extends Exception> in) {
+ reportMatcher(new IArgumentMatcher() {
+
+ @Override
+ public void appendTo(StringBuffer buffer) {
+ buffer.append("classEq(");
+ buffer.append(in);
+ buffer.append(")");
+ }
+
+ @Override
+ public boolean matches(Object arg) {
+ return arg.getClass() == in;
+ }
+
+ });
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerLiveTest.java
new file mode 100644
index 0000000..dd65210
--- /dev/null
+++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerLiveTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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;
+
+import static java.lang.String.format;
+import static org.jclouds.io.Payloads.newByteSourcePayload;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.UUID;
+
+import org.jclouds.openstack.swift.v1.domain.SwiftObject;
+import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest;
+import org.jclouds.util.Strings2;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.io.ByteSource;
+
+@Test(groups = "live", testName = "TemporaryUrlSignerLiveTest")
+public class TemporaryUrlSignerLiveTest extends BaseSwiftApiLiveTest<SwiftApi> {
+
+ private String name = getClass().getSimpleName();
+ private String containerName = getClass().getSimpleName() + "Container";
+
+ public void signForPublicAccess() throws Exception {
+ for (String regionId : api.getConfiguredRegions()) {
+ SwiftObject object = api.getObjectApi(regionId, containerName).get(name);
+
+ long expires = System.currentTimeMillis() / 1000 + 5;
+ String signature = TemporaryUrlSigner.checkApiEvery(api.getAccountApi(regionId), 5)
+ .sign("GET", object.getUri().getPath(), 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");
+
+ // let it expire
+ Thread.sleep(5000);
+ try {
+ signed.toURL().openStream();
+ fail("should have expired!");
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ @Override
+ @BeforeClass(groups = "live")
+ public void setup() {
+ super.setup();
+ String key = UUID.randomUUID().toString();
+ for (String regionId : api.getConfiguredRegions()) {
+ api.getAccountApi(regionId).updateTemporaryUrlKey(key);
+ api.getContainerApi(regionId).create(containerName);
+ api.getObjectApi(regionId, containerName)
+ .put(name, newByteSourcePayload(ByteSource.wrap("swifty".getBytes())));
+ }
+ }
+
+ @AfterMethod
+ @AfterClass(groups = "live")
+ public void tearDown() {
+ for (String regionId : api.getConfiguredRegions()) {
+ api.getObjectApi(regionId, containerName).delete(name);
+ api.getContainerApi(regionId).deleteIfEmpty(containerName);
+ }
+ super.tearDown();
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerMockTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerMockTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerMockTest.java
new file mode 100644
index 0000000..8f42cf3
--- /dev/null
+++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/TemporaryUrlSignerMockTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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;
+
+import static org.jclouds.openstack.swift.v1.features.AccountApiMockTest.accountResponse;
+import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_TEMPORARY_URL_KEY;
+import static org.testng.Assert.assertEquals;
+
+import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest;
+import org.testng.annotations.Test;
+
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+
+@Test(groups = "unit", testName = "TemporaryUrlSignerMockTest")
+public class TemporaryUrlSignerMockTest extends BaseOpenStackMockTest<SwiftApi> {
+
+ @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "accountApi")
+ public void whenAccountApiIsNull() {
+ TemporaryUrlSigner.checkApiEvery(null, 10000);
+ }
+
+ public void whenAccountApiHasKey() throws Exception {
+ MockWebServer server = mockOpenStackServer();
+ server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+ server.enqueue(addCommonHeaders(accountResponse().addHeader(ACCOUNT_TEMPORARY_URL_KEY, "mykey")));
+
+ try {
+ SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
+ String signature = TemporaryUrlSigner.checkApiEvery(api.getAccountApi("DFW"), 10000)
+ .sign("GET", "/v1/AUTH_account/container/object", 1323479485l);
+
+ assertEquals(signature, "d9fc2067e52b06598421664cf6610bfc8fc431f6");
+
+ 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");
+ } finally {
+ server.shutdown();
+ }
+ }
+
+ @Test(expectedExceptions = IllegalStateException.class, expectedExceptionsMessageRegExp = ".*returned a null temporaryUrlKey!")
+ public void whenAccountApiDoesntHaveKey() throws Exception {
+ MockWebServer server = mockOpenStackServer();
+ server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+ server.enqueue(addCommonHeaders(accountResponse()));
+
+ try {
+ SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
+ TemporaryUrlSigner.checkApiEvery(api.getAccountApi("DFW"), 10000)
+ .sign("GET", "/v1/AUTH_account/container/object", 1323479485l);
+ } finally {
+ 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");
+ server.shutdown();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedBlobStoreContextLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedBlobStoreContextLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedBlobStoreContextLiveTest.java
new file mode 100644
index 0000000..97f5448
--- /dev/null
+++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedBlobStoreContextLiveTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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.blobstore;
+
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+
+import java.io.IOException;
+import java.util.Properties;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ExecutionException;
+
+import org.jclouds.blobstore.BlobRequestSigner;
+import org.jclouds.blobstore.BlobStore;
+import org.jclouds.blobstore.domain.Blob;
+import org.jclouds.blobstore.domain.PageSet;
+import org.jclouds.blobstore.domain.StorageMetadata;
+import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
+import org.jclouds.domain.Location;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.io.ByteStreams2;
+import org.jclouds.io.MutableContentMetadata;
+import org.jclouds.io.Payload;
+import org.jclouds.io.Payloads;
+import org.jclouds.rest.HttpClient;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.Iterables;
+import com.google.common.io.ByteSource;
+import com.google.common.hash.Hashing;
+import com.google.common.net.MediaType;
+import com.google.common.net.HttpHeaders;
+
+@Test(groups = "live")
+public class RegionScopedBlobStoreContextLiveTest extends BaseBlobStoreIntegrationTest {
+
+ public RegionScopedBlobStoreContextLiveTest() {
+ provider = "openstack-swift";
+ }
+
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE);
+ return props;
+ }
+
+ @Test
+ public void testRegionsAreNotEmpty() {
+ assertFalse(RegionScopedBlobStoreContext.class.cast(view).getConfiguredRegions().isEmpty());
+ }
+
+ @Test
+ public void testLocationsMatch() {
+ RegionScopedBlobStoreContext ctx = RegionScopedBlobStoreContext.class.cast(view);
+ for (String regionId : ctx.getConfiguredRegions()) {
+ Set<? extends Location> locations = ctx.getBlobStore(regionId).listAssignableLocations();
+ assertEquals(locations.size(), 1, "expected one region " + regionId + " " + locations);
+ Location location = locations.iterator().next();
+ assertEquals(location.getId(), regionId, "region id " + regionId + " didn't match getId(): " + location);
+ }
+ }
+
+ @Test
+ public void testListBlobs() throws InterruptedException, ExecutionException {
+ RegionScopedBlobStoreContext ctx = RegionScopedBlobStoreContext.class.cast(view);
+ for (String regionId : ctx.getConfiguredRegions()) {
+ ctx.getBlobStore(regionId).list();
+ }
+ }
+
+ @Test
+ public void testSign() throws InterruptedException, ExecutionException,
+ IOException {
+ RegionScopedBlobStoreContext ctx = RegionScopedBlobStoreContext.class.cast(view);
+ for (String regionId : ctx.getConfiguredRegions()) {
+ BlobStore region = ctx.getBlobStore(regionId);
+ PageSet<? extends StorageMetadata> containers = region.list();
+ if (containers.isEmpty()) {
+ continue;
+ }
+ String containerName = Iterables.getLast(containers).getName();
+
+ final ByteSource input = ByteSource.wrap("str".getBytes());
+ final HttpClient client = ctx.utils().http();
+
+ // test signed put
+ String blobName = "test-" + UUID.randomUUID();
+ Blob blob2 = region.blobBuilder(blobName).forSigning()
+ .contentLength(input.size())
+ .contentMD5(input.hash(Hashing.md5()).asBytes())
+ .contentType(MediaType.OCTET_STREAM.toString()).build();
+ BlobRequestSigner signer = ctx.getSigner(regionId);
+ HttpResponse response;
+ try {
+ HttpRequest putRequest;
+ putRequest = signer.signPutBlob(containerName, blob2, 600);
+ MutableContentMetadata metadata = blob2.getMetadata()
+ .getContentMetadata();
+ HttpRequest.Builder<?> putRequestBuilder = putRequest.toBuilder()
+ .addHeader(HttpHeaders.CONTENT_TYPE,
+ metadata.getContentType());
+ putRequestBuilder.addHeader(HttpHeaders.CONTENT_LENGTH,
+ String.valueOf(input.size()));
+ putRequestBuilder.payload(input);
+ putRequest = putRequestBuilder.build();
+ Payload payload = Payloads.newPayload(input.read());
+ putRequest.setPayload(payload);
+ assertNotNull(putRequest, "regionId=" + regionId + ", container="
+ + containerName + ", blob=" + blobName);
+ response = client.invoke(putRequest);
+ if (response.getStatusCode() != 200
+ && response.getStatusCode() != 201) {
+ fail("Signed PUT expected to return 200 or 201 but returned "
+ + response.getStatusCode());
+ }
+ } catch (Exception e) {
+ fail("Failed signed put test: " + e);
+ }
+
+ // test signed get
+ try {
+ HttpRequest getRequest = signer.signGetBlob(containerName,
+ blobName);
+ assertNotNull(getRequest, "regionId=" + regionId + ", container="
+ + containerName + ", blob=" + blobName);
+ response = client.invoke(getRequest);
+ if (response.getStatusCode() != 200) {
+ fail("Signed GET expected to return 200 but returned "
+ + response.getStatusCode());
+ }
+ Payload payload = response.getPayload();
+ assertEquals(ByteStreams2.toByteArrayAndClose(payload.openStream()), input.read(),
+ "Data with signed GET not identical to what was put");
+ } catch (Exception e) {
+ fail("Failed signed GET test: " + e);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobIntegrationLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobIntegrationLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobIntegrationLiveTest.java
new file mode 100644
index 0000000..6d26100
--- /dev/null
+++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobIntegrationLiveTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.blobstore.integration;
+
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
+
+import java.util.Properties;
+
+import org.jclouds.blobstore.domain.Blob;
+import org.jclouds.blobstore.integration.internal.BaseBlobIntegrationTest;
+import org.testng.SkipException;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "SwiftBlobIntegrationLiveTest")
+public class SwiftBlobIntegrationLiveTest extends BaseBlobIntegrationTest {
+
+ public SwiftBlobIntegrationLiveTest() {
+ provider = "openstack-swift";
+ }
+
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE);
+ return props;
+ }
+
+ // Object/Container name contains forbidden chars from "<>
+ @Override
+ @DataProvider(name = "delete")
+ public Object[][] createData() {
+ return new Object[][] { { "normal" }, { "sp ace" }, { "qu?stion" }, { "unic₪de" }, { "path/foo" }, { "colon:" },
+ { "asteri*k" }, { "p|pe" } };
+ }
+
+ @Override
+ public void testGetTwoRanges() {
+ throw new SkipException("unsupported in swift");
+ }
+
+ @Override
+ public void testCreateBlobWithExpiry() throws InterruptedException {
+ throw new SkipException("unsupported in swift");
+ }
+
+ @Test(groups = { "integration", "live" })
+ public void testGetIfUnmodifiedSince() throws InterruptedException {
+ throw new SkipException("unsupported in swift");
+ }
+
+ @Override
+ protected int getIncorrectContentMD5StatusCode() {
+ return 422;
+ }
+
+ @Override
+ protected void checkContentLanguage(Blob blob, String contentLanguage) {
+ assert blob.getPayload().getContentMetadata().getContentLanguage() == null;
+ assert blob.getMetadata().getContentMetadata().getContentLanguage() == null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobLiveTest.java
new file mode 100644
index 0000000..d9996bf
--- /dev/null
+++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobLiveTest.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.openstack.swift.v1.blobstore.integration;
+
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
+
+import java.util.Properties;
+
+import org.jclouds.blobstore.integration.internal.BaseBlobLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "SwiftBlobLiveTest")
+public class SwiftBlobLiveTest extends BaseBlobLiveTest {
+
+ public SwiftBlobLiveTest() {
+ provider = "openstack-swift";
+ }
+
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE);
+ return props;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobSignerLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobSignerLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobSignerLiveTest.java
new file mode 100644
index 0000000..9dd603f
--- /dev/null
+++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftBlobSignerLiveTest.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.openstack.swift.v1.blobstore.integration;
+
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
+
+import java.util.Properties;
+
+import org.jclouds.blobstore.integration.internal.BaseBlobSignerLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "SwiftBlobSignerLiveTest")
+public class SwiftBlobSignerLiveTest extends BaseBlobSignerLiveTest {
+
+ public SwiftBlobSignerLiveTest() {
+ provider = "openstack-swift";
+ }
+
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE);
+ return props;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerIntegrationLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerIntegrationLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerIntegrationLiveTest.java
new file mode 100644
index 0000000..d954867
--- /dev/null
+++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerIntegrationLiveTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.blobstore.integration;
+
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Properties;
+
+import org.jclouds.blobstore.integration.internal.BaseContainerIntegrationTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "SwiftContainerIntegrationLiveTest")
+public class SwiftContainerIntegrationLiveTest extends BaseContainerIntegrationTest {
+
+ public SwiftContainerIntegrationLiveTest() {
+ provider = "openstack-swift";
+ }
+
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE);
+ return props;
+ }
+
+ @Override
+ public void testListRootUsesDelimiter() throws InterruptedException {
+ try {
+ super.testListRootUsesDelimiter();
+ } catch (AssertionError e) {
+ // swift doesn't have the "common prefixes" in the response that s3
+ // does. If we wanted this to pass, we'd need to create
+ // pseudo-directories implicitly, which is costly and troublesome. It
+ // is better to fail this assertion.
+ assertTrue(e.getMessage().matches(".*16.* but .*15.*"), e.getMessage());
+ // ^^ squishy regex to deal with various formats of testng messages.
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerLiveTest.java
new file mode 100644
index 0000000..9bd85d6
--- /dev/null
+++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftContainerLiveTest.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.openstack.swift.v1.blobstore.integration;
+
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
+
+import java.util.Properties;
+
+import org.jclouds.blobstore.integration.internal.BaseContainerLiveTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "SwiftContainerLiveTest")
+public class SwiftContainerLiveTest extends BaseContainerLiveTest {
+
+ public SwiftContainerLiveTest() {
+ provider = "openstack-swift";
+ }
+
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE);
+ return props;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftServiceIntegrationLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftServiceIntegrationLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftServiceIntegrationLiveTest.java
new file mode 100644
index 0000000..1da1a68
--- /dev/null
+++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/blobstore/integration/SwiftServiceIntegrationLiveTest.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.openstack.swift.v1.blobstore.integration;
+
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
+
+import java.util.Properties;
+
+import org.jclouds.blobstore.integration.internal.BaseServiceIntegrationTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "SwiftServiceIntegrationLiveTest")
+public class SwiftServiceIntegrationLiveTest extends BaseServiceIntegrationTest {
+
+ public SwiftServiceIntegrationLiveTest() {
+ provider = "openstack-swift";
+ }
+
+ @Override
+ protected Properties setupProperties() {
+ Properties props = super.setupProperties();
+ setIfTestSystemPropertyPresent(props, CREDENTIAL_TYPE);
+ return props;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdaptersTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdaptersTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdaptersTest.java
new file mode 100644
index 0000000..e4225fc
--- /dev/null
+++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/config/SwiftTypeAdaptersTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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 static org.testng.Assert.assertEquals;
+
+import org.jclouds.openstack.swift.v1.config.SwiftTypeAdapters.BulkDeleteResponseAdapter;
+import org.jclouds.openstack.swift.v1.config.SwiftTypeAdapters.ExtractArchiveResponseAdapter;
+import org.jclouds.openstack.swift.v1.domain.BulkDeleteResponse;
+import org.jclouds.openstack.swift.v1.domain.ExtractArchiveResponse;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+@Test
+public class SwiftTypeAdaptersTest {
+ 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"
+ + "}", 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"
+ + "}", ExtractArchiveResponse.class),
+ ExtractArchiveResponse.create(
+ 8,
+ ImmutableMap.<String, String> builder()
+ .put("/v1/12345678912345/mycontainer/home/xx<yy", "400 Bad Request")
+ .put("/v1/12345678912345/mycontainer/../image.gif", "400 Bad Request").build()));
+ }
+
+ 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"
+ + "}", 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"
+ + "}", BulkDeleteResponse.class),
+ BulkDeleteResponse.create(0, 0, ImmutableMap.of("/v1/12345678912345/Not Empty", "409 Conflict")));
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/8505539a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java
new file mode 100644
index 0000000..3841b33
--- /dev/null
+++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.features;
+
+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;
+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;
+
+import com.google.common.collect.ImmutableMap;
+
+@Test(groups = "live", testName = "AccountApiLiveTest")
+public class AccountApiLiveTest extends BaseSwiftApiLiveTest<SwiftApi> {
+
+ public void testGet() throws Exception {
+ for (String regionId : regions) {
+ AccountApi accountApi = api.getAccountApi(regionId);
+ Account account = accountApi.get();
+
+ assertNotNull(account);
+ assertTrue(account.getContainerCount() >= 0);
+ assertTrue(account.getObjectCount() >= 0);
+ assertTrue(account.getBytesUsed() >= 0);
+ }
+ }
+
+ public void testUpdateMetadata() throws Exception {
+ for (String regionId : regions) {
+ AccountApi accountApi = api.getAccountApi(regionId);
+
+ Map<String, String> meta = ImmutableMap.of("MyAdd1", "foo", "MyAdd2", "bar");
+
+ assertTrue(accountApi.updateMetadata(meta));
+
+ accountHasMetadata(accountApi, meta);
+ }
+ }
+
+ public void testDeleteMetadata() throws Exception {
+ for (String regionId : regions) {
+ AccountApi accountApi = api.getAccountApi(regionId);
+
+ Map<String, String> meta = ImmutableMap.of("MyDelete1", "foo", "MyDelete2", "bar");
+
+ assertTrue(accountApi.updateMetadata(meta));
+ accountHasMetadata(accountApi, meta);
+
+ assertTrue(accountApi.deleteMetadata(meta));
+ Account account = accountApi.get();
+ for (Entry<String, String> entry : meta.entrySet()) {
+ // note keys are returned in lower-case!
+ assertFalse(account.getMetadata().containsKey(entry.getKey().toLowerCase()));
+ }
+ }
+ }
+
+ static void accountHasMetadata(AccountApi accountApi, Map<String, String> meta) {
+ Account account = accountApi.get();
+ for (Entry<String, String> entry : meta.entrySet()) {
+ // note keys are returned in lower-case!
+ assertEquals(account.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue(),
+ account + " didn't have metadata: " + entry);
+ }
+ }
+}