You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ad...@apache.org on 2014/10/04 07:14:43 UTC
[2/3] JCLOUDS-40 unasync azureblob;
plus fold otherwise unused azure-common into it.
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6843e0cb/providers/azureblob/src/main/java/org/jclouds/azure/storage/AzureStorageResponseException.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azure/storage/AzureStorageResponseException.java b/providers/azureblob/src/main/java/org/jclouds/azure/storage/AzureStorageResponseException.java
new file mode 100644
index 0000000..744de08
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azure/storage/AzureStorageResponseException.java
@@ -0,0 +1,72 @@
+/*
+ * 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.azure.storage;
+
+import org.jclouds.azure.storage.domain.AzureStorageError;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+
+/**
+ * Encapsulates an Error from Azure Storage Services.
+ *
+ * @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingRESTError.html" />
+ * @see AzureStorageError
+ * @see org.jclouds.aws.handlers.ParseAzureStorageErrorFromXmlContent
+ */
+public class AzureStorageResponseException extends HttpResponseException {
+
+ private AzureStorageError error = new AzureStorageError();
+
+ public AzureStorageResponseException(HttpCommand command, HttpResponse response, AzureStorageError error) {
+ super(String.format("command %s failed with code %s, error: %s", command.toString(), response
+ .getStatusCode(), error.toString()), command, response);
+ this.setError(error);
+
+ }
+
+ public AzureStorageResponseException(HttpCommand command, HttpResponse response, AzureStorageError error,
+ Throwable cause) {
+ super(String.format("command %1$s failed with error: %2$s", command.toString(), error
+ .toString()), command, response, cause);
+ this.setError(error);
+
+ }
+
+ public AzureStorageResponseException(String message, HttpCommand command, HttpResponse response,
+ AzureStorageError error) {
+ super(message, command, response);
+ this.setError(error);
+
+ }
+
+ public AzureStorageResponseException(String message, HttpCommand command, HttpResponse response,
+ AzureStorageError error, Throwable cause) {
+ super(message, command, response, cause);
+ this.setError(error);
+
+ }
+
+ public void setError(AzureStorageError error) {
+ this.error = error;
+ }
+
+ public AzureStorageError getError() {
+ return error;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6843e0cb/providers/azureblob/src/main/java/org/jclouds/azure/storage/domain/AzureStorageError.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azure/storage/domain/AzureStorageError.java b/providers/azureblob/src/main/java/org/jclouds/azure/storage/domain/AzureStorageError.java
new file mode 100644
index 0000000..9843fb9
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azure/storage/domain/AzureStorageError.java
@@ -0,0 +1,114 @@
+/*
+ * 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.azure.storage.domain;
+
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+
+/**
+ * When an Azure Storage request is in error, the client receives an error response.
+ *
+ * @see <a href="http://msdn.microsoft.com/en-us/library/dd573365.aspx" />
+ */
+public class AzureStorageError {
+ private String code;
+ private String message;
+ private String requestId;
+ private Map<String, String> details = Maps.newHashMap();
+ private String stringSigned;
+ private String signature;
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("AzureError");
+ sb.append("{requestId='").append(requestId).append('\'');
+ if (code != null)
+ sb.append(", code='").append(code).append('\'');
+ if (message != null)
+ sb.append(", message='").append(message).append('\'');
+ if (stringSigned != null)
+ sb.append(", stringSigned='").append(stringSigned).append('\'');
+ if (getSignature() != null)
+ sb.append(", signature='").append(getSignature()).append('\'');
+ if (details.size() != 0)
+ sb.append(", context='").append(details.toString()).append('\'').append('}');
+ return sb.toString();
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setRequestId(String requestId) {
+ this.requestId = requestId;
+ }
+
+ /**
+ * If a request is consistently failing and you have verified that the request is properly
+ * formulated, you may use this value to report the error to Microsoft. In your report, include
+ * the value of x-ms-request-id, the approximate time that the request was made, the storage
+ * service against which the request was made, and the type of operation that the request
+ * attempted
+ */
+ public String getRequestId() {
+ return requestId;
+ }
+
+ public void setStringSigned(String stringSigned) {
+ this.stringSigned = stringSigned;
+ }
+
+ /**
+ * @return what jclouds signed before sending the request.
+ */
+ public String getStringSigned() {
+ return stringSigned;
+ }
+
+ public void setDetails(Map<String, String> context) {
+ this.details = context;
+ }
+
+ /**
+ * @return additional details surrounding the error.
+ */
+ public Map<String, String> getDetails() {
+ return details;
+ }
+
+ public void setSignature(String signature) {
+ this.signature = signature;
+ }
+
+ public String getSignature() {
+ return signature;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6843e0cb/providers/azureblob/src/main/java/org/jclouds/azure/storage/domain/BoundedSet.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azure/storage/domain/BoundedSet.java b/providers/azureblob/src/main/java/org/jclouds/azure/storage/domain/BoundedSet.java
new file mode 100644
index 0000000..8778ae6
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azure/storage/domain/BoundedSet.java
@@ -0,0 +1,33 @@
+/*
+ * 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.azure.storage.domain;
+
+import java.net.URI;
+import java.util.Set;
+
+public interface BoundedSet<T> extends Set<T> {
+ URI getUrl();
+
+ String getPrefix();
+
+ String getMarker();
+
+ int getMaxResults();
+
+ String getNextMarker();
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6843e0cb/providers/azureblob/src/main/java/org/jclouds/azure/storage/domain/internal/BoundedHashSet.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azure/storage/domain/internal/BoundedHashSet.java b/providers/azureblob/src/main/java/org/jclouds/azure/storage/domain/internal/BoundedHashSet.java
new file mode 100644
index 0000000..b9767ec
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azure/storage/domain/internal/BoundedHashSet.java
@@ -0,0 +1,64 @@
+/*
+ * 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.azure.storage.domain.internal;
+
+import java.net.URI;
+import java.util.HashSet;
+
+import org.jclouds.azure.storage.domain.BoundedSet;
+
+import com.google.common.collect.Iterables;
+
+public class BoundedHashSet<T> extends HashSet<T> implements BoundedSet<T> {
+
+ protected final URI url;
+ protected final String prefix;
+ protected final String marker;
+ protected final Integer maxResults;
+ protected final String nextMarker;
+
+ public BoundedHashSet(Iterable<T> contents, URI url, String prefix, String marker,
+ Integer maxResults, String nextMarker) {
+ Iterables.addAll(this, contents);
+ this.url = url;
+ this.prefix = prefix;
+ this.nextMarker = nextMarker;
+ this.maxResults = maxResults;
+ this.marker = marker;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public String getMarker() {
+ return marker;
+ }
+
+ public int getMaxResults() {
+ return maxResults;
+ }
+
+ public String getNextMarker() {
+ return nextMarker;
+ }
+
+ public URI getUrl() {
+ return url;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6843e0cb/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java b/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java
new file mode 100644
index 0000000..8e56390
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azure/storage/filters/SharedKeyLiteAuthentication.java
@@ -0,0 +1,207 @@
+/*
+ * 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.azure.storage.filters;
+
+import static com.google.common.io.BaseEncoding.base64;
+import static com.google.common.io.ByteStreams.readBytes;
+import static org.jclouds.crypto.Macs.asByteProcessor;
+import static org.jclouds.util.Patterns.NEWLINE_PATTERN;
+import static org.jclouds.util.Strings2.toInputStream;
+
+import java.util.Collection;
+import java.util.Set;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.jclouds.Constants;
+import org.jclouds.crypto.Crypto;
+import org.jclouds.date.TimeStamp;
+import org.jclouds.domain.Credentials;
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpRequestFilter;
+import org.jclouds.http.HttpUtils;
+import org.jclouds.http.internal.SignatureWire;
+import org.jclouds.logging.Logger;
+import org.jclouds.util.Strings2;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Strings;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.Sets;
+import com.google.common.io.ByteProcessor;
+import com.google.common.net.HttpHeaders;
+
+/**
+ * Signs the Azure Storage request.
+ *
+ * @see <a href= "http://msdn.microsoft.com/en-us/library/dd179428.aspx" />
+ */
+@Singleton
+public class SharedKeyLiteAuthentication implements HttpRequestFilter {
+ private static final Collection<String> FIRST_HEADERS_TO_SIGN = ImmutableList.of(HttpHeaders.DATE);
+
+ private final SignatureWire signatureWire;
+ private final Supplier<Credentials> creds;
+ private final Provider<String> timeStampProvider;
+ private final Crypto crypto;
+ private final HttpUtils utils;
+
+ @Resource
+ @Named(Constants.LOGGER_SIGNATURE)
+ Logger signatureLog = Logger.NULL;
+
+ @Inject
+ public SharedKeyLiteAuthentication(SignatureWire signatureWire,
+ @org.jclouds.location.Provider Supplier<Credentials> creds, @TimeStamp Provider<String> timeStampProvider,
+ Crypto crypto, HttpUtils utils) {
+ this.crypto = crypto;
+ this.utils = utils;
+ this.signatureWire = signatureWire;
+ this.creds = creds;
+ this.timeStampProvider = timeStampProvider;
+ }
+
+ public HttpRequest filter(HttpRequest request) throws HttpException {
+ request = replaceDateHeader(request);
+ String signature = calculateSignature(createStringToSign(request));
+ request = replaceAuthorizationHeader(request, signature);
+ utils.logRequest(signatureLog, request, "<<");
+ return request;
+ }
+
+ HttpRequest replaceAuthorizationHeader(HttpRequest request, String signature) {
+ return request.toBuilder()
+ .replaceHeader(HttpHeaders.AUTHORIZATION, "SharedKeyLite " + creds.get().identity + ":" + signature)
+ .build();
+ }
+
+ HttpRequest replaceDateHeader(HttpRequest request) {
+ Builder<String, String> builder = ImmutableMap.builder();
+ String date = timeStampProvider.get();
+ builder.put(HttpHeaders.DATE, date);
+ request = request.toBuilder().replaceHeaders(Multimaps.forMap(builder.build())).build();
+ return request;
+ }
+
+ public String createStringToSign(HttpRequest request) {
+ utils.logRequest(signatureLog, request, ">>");
+ StringBuilder buffer = new StringBuilder();
+ // re-sign the request
+ appendMethod(request, buffer);
+ appendPayloadMetadata(request, buffer);
+ appendHttpHeaders(request, buffer);
+ appendCanonicalizedHeaders(request, buffer);
+ appendCanonicalizedResource(request, buffer);
+ if (signatureWire.enabled())
+ signatureWire.output(buffer.toString());
+ return buffer.toString();
+ }
+
+ private void appendPayloadMetadata(HttpRequest request, StringBuilder buffer) {
+ buffer.append(
+ HttpUtils.nullToEmpty(request.getPayload() == null ? null : request.getPayload().getContentMetadata()
+ .getContentMD5())).append("\n");
+ buffer.append(
+ Strings.nullToEmpty(request.getPayload() == null ? null : request.getPayload().getContentMetadata()
+ .getContentType())).append("\n");
+ }
+
+ private String calculateSignature(String toSign) throws HttpException {
+ String signature = signString(toSign);
+ if (signatureWire.enabled())
+ signatureWire.input(Strings2.toInputStream(signature));
+ return signature;
+ }
+
+ public String signString(String toSign) {
+ try {
+ ByteProcessor<byte[]> hmacSHA256 = asByteProcessor(crypto.hmacSHA256(base64().decode(creds.get().credential)));
+ return base64().encode(readBytes(toInputStream(toSign), hmacSHA256));
+ } catch (Exception e) {
+ throw new HttpException("error signing request", e);
+ }
+ }
+
+ private void appendMethod(HttpRequest request, StringBuilder toSign) {
+ toSign.append(request.getMethod()).append("\n");
+ }
+
+ private void appendCanonicalizedHeaders(HttpRequest request, StringBuilder toSign) {
+ // TreeSet == Sort the headers alphabetically.
+ Set<String> headers = Sets.newTreeSet(request.getHeaders().keySet());
+ for (String header : headers) {
+ if (header.startsWith("x-ms-")) {
+ toSign.append(header.toLowerCase()).append(":");
+ for (String value : request.getHeaders().get(header)) {
+ toSign.append(NEWLINE_PATTERN.matcher(value).replaceAll("")).append(",");
+ }
+ toSign.deleteCharAt(toSign.lastIndexOf(","));
+ toSign.append("\n");
+ }
+ }
+ }
+
+ private void appendHttpHeaders(HttpRequest request, StringBuilder toSign) {
+ for (String header : FIRST_HEADERS_TO_SIGN)
+ toSign.append(HttpUtils.nullToEmpty(request.getHeaders().get(header))).append("\n");
+ }
+
+ @VisibleForTesting
+ void appendCanonicalizedResource(HttpRequest request, StringBuilder toSign) {
+ // 1. Beginning with an empty string (""), append a forward slash (/), followed by the name of
+ // the identity that owns the resource being accessed.
+ toSign.append("/").append(creds.get().identity);
+ appendUriPath(request, toSign);
+ }
+
+ @VisibleForTesting
+ void appendUriPath(HttpRequest request, StringBuilder toSign) {
+ // 2. Append the resource's encoded URI path
+ toSign.append(request.getEndpoint().getRawPath());
+
+ // If the request URI addresses a component of the
+ // resource, append the appropriate query string. The query string should include the question
+ // mark and the comp parameter (for example, ?comp=metadata). No other parameters should be
+ // included on the query string.
+ if (request.getEndpoint().getQuery() != null) {
+ StringBuilder paramsToSign = new StringBuilder("?");
+
+ String[] params = request.getEndpoint().getQuery().split("&");
+ for (String param : params) {
+ String[] paramNameAndValue = param.split("=");
+
+ if ("comp".equals(paramNameAndValue[0])) {
+ paramsToSign.append(param);
+ }
+ }
+
+ if (paramsToSign.length() > 1) {
+ toSign.append(paramsToSign);
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6843e0cb/providers/azureblob/src/main/java/org/jclouds/azure/storage/handlers/AzureStorageClientErrorRetryHandler.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azure/storage/handlers/AzureStorageClientErrorRetryHandler.java b/providers/azureblob/src/main/java/org/jclouds/azure/storage/handlers/AzureStorageClientErrorRetryHandler.java
new file mode 100644
index 0000000..fadc772
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azure/storage/handlers/AzureStorageClientErrorRetryHandler.java
@@ -0,0 +1,89 @@
+/*
+ * 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.azure.storage.handlers;
+
+import java.io.ByteArrayInputStream;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+
+import org.jclouds.Constants;
+import org.jclouds.azure.storage.domain.AzureStorageError;
+import org.jclouds.azure.storage.util.AzureStorageUtils;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpRetryHandler;
+import org.jclouds.http.HttpUtils;
+import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
+import org.jclouds.logging.Logger;
+
+import com.google.inject.Inject;
+
+/**
+ * Handles Retryable responses with error codes in the 4xx range
+ */
+public class AzureStorageClientErrorRetryHandler implements HttpRetryHandler {
+
+ @Inject(optional = true)
+ @Named(Constants.PROPERTY_MAX_RETRIES)
+ private int retryCountLimit = 5;
+
+ private final AzureStorageUtils utils;
+ private final BackoffLimitedRetryHandler backoffHandler;
+
+ @Resource
+ protected Logger logger = Logger.NULL;
+
+ @Inject
+ public AzureStorageClientErrorRetryHandler(BackoffLimitedRetryHandler backoffHandler,
+ AzureStorageUtils utils) {
+ this.backoffHandler = backoffHandler;
+ this.utils = utils;
+ }
+
+ public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
+ byte[] content = HttpUtils.closeClientButKeepContentStream(response);
+ command.incrementFailureCount();
+ if (!command.isReplayable()) {
+ logger.warn("Cannot retry after server error, command is not replayable: %1$s", command);
+ return false;
+ } else if (command.getFailureCount() > retryCountLimit) {
+ logger.warn(
+ "Cannot retry after server error, command has exceeded retry limit %1$d: %2$s",
+ retryCountLimit, command);
+ return false;
+ } else if (response.getStatusCode() == 409) {
+ // Content can be null in the case of HEAD requests
+ if (content != null) {
+ try {
+ AzureStorageError error = utils.parseAzureStorageErrorFromContent(command, response,
+ new ByteArrayInputStream(content));
+ if ("ContainerBeingDeleted".equals(error.getCode())) {
+ backoffHandler.imposeBackoffExponentialDelay(100L, 3, retryCountLimit, command
+ .getFailureCount(), command.toString());
+ return true;
+ }
+ } catch (HttpException e) {
+ logger.warn(e, "error parsing response: %s", new String(content));
+ }
+ }
+ }
+ return false;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6843e0cb/providers/azureblob/src/main/java/org/jclouds/azure/storage/handlers/ParseAzureStorageErrorFromXmlContent.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azure/storage/handlers/ParseAzureStorageErrorFromXmlContent.java b/providers/azureblob/src/main/java/org/jclouds/azure/storage/handlers/ParseAzureStorageErrorFromXmlContent.java
new file mode 100644
index 0000000..ece8176
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azure/storage/handlers/ParseAzureStorageErrorFromXmlContent.java
@@ -0,0 +1,115 @@
+/*
+ * 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.azure.storage.handlers;
+
+import static org.jclouds.http.HttpUtils.releasePayload;
+
+import java.io.IOException;
+import java.util.regex.Pattern;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+
+import org.jclouds.azure.storage.AzureStorageResponseException;
+import org.jclouds.azure.storage.domain.AzureStorageError;
+import org.jclouds.azure.storage.util.AzureStorageUtils;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.jclouds.util.Strings2;
+
+/**
+ * This will parse and set an appropriate exception on the command object.
+ *
+ * @see AzureStorageError
+ */
+public class ParseAzureStorageErrorFromXmlContent implements HttpErrorHandler {
+ @Resource
+ protected Logger logger = Logger.NULL;
+
+ private final AzureStorageUtils utils;
+
+ @Inject
+ public ParseAzureStorageErrorFromXmlContent(AzureStorageUtils utils) {
+ this.utils = utils;
+ }
+
+ public static final Pattern CONTAINER_PATH = Pattern.compile("^[/]?([^/]+)$");
+ public static final Pattern CONTAINER_KEY_PATH = Pattern.compile("^[/]?([^/]+)/(.*)$");
+
+ public void handleError(HttpCommand command, HttpResponse response) {
+ Exception exception = new HttpResponseException(command, response);
+ String message = null;
+ AzureStorageError error = null;
+ try {
+ if (response.getPayload() != null) {
+ String contentType = response.getPayload().getContentMetadata().getContentType();
+ if (contentType != null && (contentType.indexOf("xml") != -1 || contentType.indexOf("unknown") != -1)
+ && !Long.valueOf(0).equals(response.getPayload().getContentMetadata().getContentLength())) {
+ try {
+ error = utils.parseAzureStorageErrorFromContent(command, response, response.getPayload().getInput());
+ if (error != null) {
+ message = error.getMessage();
+ exception = new AzureStorageResponseException(command, response, error);
+ }
+ } catch (RuntimeException e) {
+ try {
+ message = Strings2.toStringAndClose(response.getPayload().openStream());
+ exception = new HttpResponseException(command, response, message);
+ } catch (IOException e1) {
+ }
+ }
+ } else {
+ try {
+ message = Strings2.toStringAndClose(response.getPayload().openStream());
+ exception = new HttpResponseException(command, response, message);
+ } catch (IOException e) {
+ }
+ }
+ }
+ message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
+ response.getStatusLine());
+ exception = refineException(command, response, exception, error, message);
+ } finally {
+ releasePayload(response);
+ command.setException(exception);
+ }
+ }
+
+ protected Exception refineException(HttpCommand command, HttpResponse response, Exception exception,
+ AzureStorageError error, String message) {
+ switch (response.getStatusCode()) {
+ case 401:
+ exception = new AuthorizationException(message, exception);
+ break;
+ case 404:
+ if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
+ exception = new ResourceNotFoundException(message, exception);
+ }
+ break;
+ case 411:
+ exception = new IllegalArgumentException(message);
+ break;
+ }
+ return exception;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6843e0cb/providers/azureblob/src/main/java/org/jclouds/azure/storage/options/CreateOptions.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azure/storage/options/CreateOptions.java b/providers/azureblob/src/main/java/org/jclouds/azure/storage/options/CreateOptions.java
new file mode 100644
index 0000000..20fd7f8
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azure/storage/options/CreateOptions.java
@@ -0,0 +1,74 @@
+/*
+ * 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.azure.storage.options;
+
+import java.util.Map.Entry;
+
+import org.jclouds.azure.storage.reference.AzureStorageHeaders;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import com.google.common.collect.Multimap;
+
+/**
+ * Contains common options supported in the REST API for the Create operation. <h2>
+ * Usage</h2> The recommended way to instantiate a CreateOptions object is to statically import
+ * CreateOptions.* and invoke a static creation method followed by an instance mutator (if
+ * needed):
+ * <p/>
+ * <code>
+ * import static CreateOptions.Builder.*
+ * import org.jclouds.azure.storage.queue.AzureQueueClient;
+ * <p/>
+ * AzureQueueClient connection = // get connection
+ * Multimap<String,String> metadata = // ...
+ * boolean createdWithPublicAcl = connection.createQueue("containerName", withMetadata(metadata));
+ * <code> *
+ *
+ * @see <a href="http://msdn.microsoft.com/en-us/library/dd179466.aspx" />
+ */
+public class CreateOptions extends BaseHttpRequestOptions {
+ public static final CreateOptions NONE = new CreateOptions();
+
+ /**
+ * A name-value pair to associate with the container as metadata.
+ *
+ * Note that these are stored at the server under the prefix: x-ms-meta-
+ */
+ public CreateOptions withMetadata(Multimap<String, String> metadata) {
+ for (Entry<String, String> entry : metadata.entries()) {
+ if (entry.getKey().startsWith(AzureStorageHeaders.USER_METADATA_PREFIX))
+ headers.put(entry.getKey(), entry.getValue());
+ else
+ headers
+ .put(AzureStorageHeaders.USER_METADATA_PREFIX + entry.getKey(), entry
+ .getValue());
+ }
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @see CreateOptions#withMetadata(Multimap<String, String>)
+ */
+ public static CreateOptions withMetadata(Multimap<String, String> metadata) {
+ CreateOptions options = new CreateOptions();
+ return options.withMetadata(metadata);
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6843e0cb/providers/azureblob/src/main/java/org/jclouds/azure/storage/options/ListOptions.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azure/storage/options/ListOptions.java b/providers/azureblob/src/main/java/org/jclouds/azure/storage/options/ListOptions.java
new file mode 100644
index 0000000..fba5f39
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azure/storage/options/ListOptions.java
@@ -0,0 +1,131 @@
+/*
+ * 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.azure.storage.options;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Options used to control paginated results (aka list commands).
+ *
+ * @see <a href="http://msdn.microsoft.com/en-us/library/dd179466.aspx" />
+ */
+public class ListOptions extends BaseHttpRequestOptions {
+ public static final ListOptions NONE = new ListOptions();
+
+ /**
+ * Include this parameter to specify that the container's metadata be returned as part of the
+ * response body.
+ *
+ * Note that metadata requested with this parameter must be stored in accordance with the naming
+ * restrictions imposed by the 2009-09-19 version of the Blob service. Beginning with this
+ * version, all metadata names must adhere to the naming conventions for C# identifiers.
+ */
+ public ListOptions includeMetadata() {
+ this.queryParameters.replaceValues("include", ImmutableSet.of("metadata"));
+ return this;
+ }
+
+ public boolean getIncludeMetadata() {
+ return getFirstQueryOrNull("include").equals("metadata");
+ }
+
+ /**
+ * Filters the results to return only objects whose name begins with the specified prefix.
+ */
+ public ListOptions prefix(String prefix) {
+ this.queryParameters.put("prefix", checkNotNull(prefix, "prefix"));
+ return this;
+ }
+
+ public String getPrefix() {
+ return getFirstQueryOrNull("prefix");
+ }
+
+ /**
+ * A string value that identifies the portion of the list to be returned with the next list
+ * operation. The operation returns a marker value within the response body if the list returned
+ * was not complete. The marker value may then be used in a subsequent call to request the next
+ * set of list items.
+ * <p/>
+ * The marker value is opaque to the client.
+ */
+ public ListOptions marker(String marker) {
+ this.queryParameters.put("marker", checkNotNull(marker, "marker"));
+ return this;
+ }
+
+ public String getMarker() {
+ return getFirstQueryOrNull("marker");
+ }
+
+ /**
+ * Specifies the maximum number of containers to return. If maxresults is not specified, the
+ * server will return up to 5,000 items. If the parameter is set to a value greater than 5,000,
+ * the server will return a Bad Request (400) error
+ */
+ public ListOptions maxResults(int maxresults) {
+ checkState(maxresults >= 0, "maxresults must be >= 0");
+ checkState(maxresults <= 10000, "maxresults must be <= 5000");
+ queryParameters.put("maxresults", Integer.toString(maxresults));
+ return this;
+ }
+
+ public Integer getMaxResults() {
+ String maxresults = getFirstQueryOrNull("maxresults");
+ return (maxresults != null) ? Integer.valueOf(maxresults) : null;
+ }
+
+ public static class Builder {
+ /**
+ * @see ListOptions#includeMetadata()
+ */
+ public static ListOptions includeMetadata() {
+ ListOptions options = new ListOptions();
+ return options.includeMetadata();
+ }
+
+ /**
+ * @see ListOptions#prefix(String)
+ */
+ public static ListOptions prefix(String prefix) {
+ ListOptions options = new ListOptions();
+ return options.prefix(prefix);
+ }
+
+ /**
+ * @see ListOptions#marker(String)
+ */
+ public static ListOptions marker(String marker) {
+ ListOptions options = new ListOptions();
+ return options.marker(marker);
+ }
+
+ /**
+ * @see ListOptions#maxResults(long)
+ */
+ public static ListOptions maxResults(int maxKeys) {
+ ListOptions options = new ListOptions();
+ return options.maxResults(maxKeys);
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6843e0cb/providers/azureblob/src/main/java/org/jclouds/azure/storage/reference/AzureStorageHeaders.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azure/storage/reference/AzureStorageHeaders.java b/providers/azureblob/src/main/java/org/jclouds/azure/storage/reference/AzureStorageHeaders.java
new file mode 100644
index 0000000..a51fa54
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azure/storage/reference/AzureStorageHeaders.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.azure.storage.reference;
+
+/**
+ * Additional headers specified by Azure Storage REST API.
+ *
+ * @see <a href="http://msdn.microsoft.com/en-us/library/dd179357.aspx" />
+ */
+public interface AzureStorageHeaders {
+
+ public static final String USER_METADATA_PREFIX = "x-ms-meta-";
+ public static final String REQUEST_ID = "x-ms-request-id";
+ public static final String VERSION = "x-ms-version";
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6843e0cb/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/AzureStorageUtils.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/AzureStorageUtils.java b/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/AzureStorageUtils.java
new file mode 100644
index 0000000..bf62ff82a
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azure/storage/util/AzureStorageUtils.java
@@ -0,0 +1,59 @@
+/*
+ * 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.azure.storage.util;
+
+import java.io.InputStream;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+import org.jclouds.azure.storage.domain.AzureStorageError;
+import org.jclouds.azure.storage.filters.SharedKeyLiteAuthentication;
+import org.jclouds.azure.storage.reference.AzureStorageHeaders;
+import org.jclouds.azure.storage.xml.ErrorHandler;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseSax;
+
+/**
+ * Encryption, Hashing, and IO Utilities needed to sign and verify Azure Storage requests and
+ * responses.
+ */
+public class AzureStorageUtils {
+
+ @Inject
+ SharedKeyLiteAuthentication signer;
+
+ @Inject
+ ParseSax.Factory factory;
+
+ @Inject
+ Provider<ErrorHandler> errorHandlerProvider;
+
+ public AzureStorageError parseAzureStorageErrorFromContent(HttpCommand command,
+ HttpResponse response, InputStream content) throws HttpException {
+ AzureStorageError error = factory.create(errorHandlerProvider.get()).parse(content);
+ error.setRequestId(response.getFirstHeaderOrNull(AzureStorageHeaders.REQUEST_ID));
+ if ("AuthenticationFailed".equals(error.getCode())) {
+ error.setStringSigned(signer.createStringToSign(command.getCurrentRequest()));
+ error.setSignature(signer.signString(error.getStringSigned()));
+ }
+ return error;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6843e0cb/providers/azureblob/src/main/java/org/jclouds/azure/storage/xml/ErrorHandler.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azure/storage/xml/ErrorHandler.java b/providers/azureblob/src/main/java/org/jclouds/azure/storage/xml/ErrorHandler.java
new file mode 100644
index 0000000..9ea9bb1
--- /dev/null
+++ b/providers/azureblob/src/main/java/org/jclouds/azure/storage/xml/ErrorHandler.java
@@ -0,0 +1,53 @@
+/*
+ * 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.azure.storage.xml;
+
+import org.jclouds.azure.storage.domain.AzureStorageError;
+import org.jclouds.http.functions.ParseSax;
+
+/**
+ * Parses the error from the Amazon S3 REST API.
+ *
+ * @see <a
+ * href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?UsingRESTError.html"
+ * />
+ */
+public class ErrorHandler extends ParseSax.HandlerWithResult<AzureStorageError> {
+
+ private AzureStorageError error = new AzureStorageError();
+ private StringBuilder currentText = new StringBuilder();
+
+ public AzureStorageError getResult() {
+ return error;
+ }
+
+ public void endElement(String uri, String name, String qName) {
+
+ if (qName.equals("Code")) {
+ error.setCode(currentText.toString().trim());
+ } else if (qName.equals("Message")) {
+ error.setMessage(currentText.toString().trim());
+ } else if (!qName.equals("Error")) {
+ error.getDetails().put(qName, currentText.toString());
+ }
+ currentText = new StringBuilder();
+ }
+
+ public void characters(char ch[], int start, int length) {
+ currentText.append(ch, start, length);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6843e0cb/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobApiMetadata.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobApiMetadata.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobApiMetadata.java
index c498f26..7798865 100644
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobApiMetadata.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobApiMetadata.java
@@ -23,28 +23,15 @@ import java.net.URI;
import java.util.Properties;
import org.jclouds.azureblob.blobstore.config.AzureBlobStoreContextModule;
-import org.jclouds.azureblob.config.AzureBlobRestClientModule;
+import org.jclouds.azureblob.config.AzureBlobHttpApiModule;
import org.jclouds.blobstore.BlobStoreContext;
-import org.jclouds.rest.internal.BaseRestApiMetadata;
+import org.jclouds.rest.internal.BaseHttpApiMetadata;
import com.google.common.collect.ImmutableSet;
-import com.google.common.reflect.TypeToken;
import com.google.inject.Module;
-/**
- * Implementation of {@link ApiMetadata} for Microsoft Azure Blob Service API
- */
-public class AzureBlobApiMetadata extends BaseRestApiMetadata {
+public class AzureBlobApiMetadata extends BaseHttpApiMetadata {
- /**
- * @deprecated please use {@code org.jclouds.ContextBuilder#buildApi(AzureBlobClient.class)} as
- * {@link AzureBlobAsyncClient} interface will be removed in jclouds 1.7.
- */
- @Deprecated
- public static final TypeToken<org.jclouds.rest.RestContext<AzureBlobClient, AzureBlobAsyncClient>> CONTEXT_TOKEN = new TypeToken<org.jclouds.rest.RestContext<AzureBlobClient, AzureBlobAsyncClient>>() {
- private static final long serialVersionUID = 1L;
- };
-
private static Builder builder() {
return new Builder();
}
@@ -63,15 +50,14 @@ public class AzureBlobApiMetadata extends BaseRestApiMetadata {
}
public static Properties defaultProperties() {
- Properties properties = BaseRestApiMetadata.defaultProperties();
+ Properties properties = BaseHttpApiMetadata.defaultProperties();
properties.setProperty(PROPERTY_USER_METADATA_PREFIX, "x-ms-meta-");
return properties;
}
- public static class Builder extends BaseRestApiMetadata.Builder<Builder> {
- @SuppressWarnings("deprecation")
+ public static class Builder extends BaseHttpApiMetadata.Builder<AzureBlobClient, Builder> {
protected Builder() {
- super(AzureBlobClient.class, AzureBlobAsyncClient.class);
+ super(AzureBlobClient.class);
id("azureblob")
.name("Microsoft Azure Blob Service API")
.identityName("Account Name")
@@ -81,7 +67,7 @@ public class AzureBlobApiMetadata extends BaseRestApiMetadata {
.documentation(URI.create("http://msdn.microsoft.com/en-us/library/dd135733.aspx"))
.defaultProperties(AzureBlobApiMetadata.defaultProperties())
.view(typeToken(BlobStoreContext.class))
- .defaultModules(ImmutableSet.<Class<? extends Module>>of(AzureBlobRestClientModule.class, AzureBlobStoreContextModule.class));
+ .defaultModules(ImmutableSet.<Class<? extends Module>>of(AzureBlobHttpApiModule.class, AzureBlobStoreContextModule.class));
}
@Override
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6843e0cb/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobAsyncClient.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobAsyncClient.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobAsyncClient.java
deleted file mode 100644
index f862689..0000000
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobAsyncClient.java
+++ /dev/null
@@ -1,328 +0,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.
- */
-package org.jclouds.azureblob;
-
-import static com.google.common.net.HttpHeaders.EXPECT;
-
-import java.util.List;
-import java.util.Map;
-
-import javax.inject.Named;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.HEAD;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.QueryParam;
-
-import org.jclouds.Fallbacks.TrueOnNotFoundOr404;
-import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
-import org.jclouds.azure.storage.domain.BoundedSet;
-import org.jclouds.azure.storage.filters.SharedKeyLiteAuthentication;
-import org.jclouds.azure.storage.options.ListOptions;
-import org.jclouds.azure.storage.reference.AzureStorageHeaders;
-import org.jclouds.azureblob.AzureBlobFallbacks.FalseIfContainerAlreadyExists;
-import org.jclouds.azureblob.binders.BindAzureBlobMetadataToRequest;
-import org.jclouds.azureblob.binders.BindAzureBlocksToRequest;
-import org.jclouds.azureblob.domain.BlobProperties;
-import org.jclouds.azureblob.domain.ContainerProperties;
-import org.jclouds.azureblob.domain.ListBlobBlocksResponse;
-import org.jclouds.azureblob.domain.ListBlobsResponse;
-import org.jclouds.azureblob.domain.PublicAccess;
-import org.jclouds.azureblob.functions.BlobName;
-import org.jclouds.azureblob.functions.ParseBlobFromHeadersAndHttpContent;
-import org.jclouds.azureblob.functions.ParseBlobPropertiesFromHeaders;
-import org.jclouds.azureblob.functions.ParseContainerPropertiesFromHeaders;
-import org.jclouds.azureblob.functions.ParsePublicAccessHeader;
-import org.jclouds.azureblob.options.CreateContainerOptions;
-import org.jclouds.azureblob.options.ListBlobsOptions;
-import org.jclouds.azureblob.predicates.validators.BlockIdValidator;
-import org.jclouds.azureblob.predicates.validators.ContainerNameValidator;
-import org.jclouds.azureblob.xml.AccountNameEnumerationResultsHandler;
-import org.jclouds.azureblob.xml.BlobBlocksResultsHandler;
-import org.jclouds.azureblob.xml.ContainerNameEnumerationResultsHandler;
-import org.jclouds.blobstore.BlobStoreFallbacks.FalseOnContainerNotFound;
-import org.jclouds.blobstore.BlobStoreFallbacks.FalseOnKeyNotFound;
-import org.jclouds.blobstore.BlobStoreFallbacks.NullOnContainerNotFound;
-import org.jclouds.blobstore.BlobStoreFallbacks.NullOnKeyNotFound;
-import org.jclouds.blobstore.binders.BindMapToHeadersWithPrefix;
-import org.jclouds.http.functions.ParseETagHeader;
-import org.jclouds.http.options.GetOptions;
-import org.jclouds.io.Payload;
-import org.jclouds.rest.annotations.BinderParam;
-import org.jclouds.rest.annotations.Fallback;
-import org.jclouds.rest.annotations.Headers;
-import org.jclouds.rest.annotations.ParamParser;
-import org.jclouds.rest.annotations.ParamValidators;
-import org.jclouds.rest.annotations.QueryParams;
-import org.jclouds.rest.annotations.RequestFilters;
-import org.jclouds.rest.annotations.ResponseParser;
-import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.annotations.XMLResponseParser;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.inject.Provides;
-
-/**
- * Provides asynchronous access to Azure Blob via their REST API.
- * <p/>
- * All commands return a ListenableFuture of the result from Azure Blob. Any exceptions incurred
- * during processing will be backend in an {@link ExecutionException} as documented in
- * {@link ListenableFuture#get()}.
- *
- * @see <a href="http://msdn.microsoft.com/en-us/library/dd135733.aspx" />
- * @see AzureBlobClient
- * @deprecated please use {@code org.jclouds.ContextBuilder#buildApi(AzureBlobClient.class)} as
- * {@link AzureBlobAsyncClient} interface will be removed in jclouds 1.7.
- */
-@Deprecated
-@RequestFilters(SharedKeyLiteAuthentication.class)
-@Headers(keys = AzureStorageHeaders.VERSION, values = "2009-09-19")
-@SkipEncoding({ '/', '$' })
-@Path("/")
-public interface AzureBlobAsyncClient {
- @Provides
- org.jclouds.azureblob.domain.AzureBlob newBlob();
-
- /**
- * @see AzureBlobClient#listContainers
- */
- @Named("ListContainers")
- @GET
- @XMLResponseParser(AccountNameEnumerationResultsHandler.class)
- @QueryParams(keys = "comp", values = "list")
- ListenableFuture<? extends BoundedSet<ContainerProperties>> listContainers(ListOptions... listOptions);
-
- /**
- * @see AzureBlobClient#createContainer
- */
- @Named("CreateContainer")
- @PUT
- @Path("{container}")
- @Fallback(FalseIfContainerAlreadyExists.class)
- @QueryParams(keys = "restype", values = "container")
- ListenableFuture<Boolean> createContainer(
- @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
- CreateContainerOptions... options);
-
- /**
- * @see AzureBlobClient#getPublicAccessForContainer
- */
- @Named("GetContainerACL")
- @HEAD
- @Path("{container}")
- @QueryParams(keys = { "restype", "comp" }, values = { "container", "acl" })
- @ResponseParser(ParsePublicAccessHeader.class)
- @Fallback(NullOnContainerNotFound.class)
- ListenableFuture<PublicAccess> getPublicAccessForContainer(
- @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container);
-
- /**
- * @see AzureBlobClient#getContainerProperties
- */
- @Named("GetContainerProperties")
- @HEAD
- @Path("{container}")
- @QueryParams(keys = "restype", values = "container")
- @ResponseParser(ParseContainerPropertiesFromHeaders.class)
- @Fallback(NullOnContainerNotFound.class)
- ListenableFuture<ContainerProperties> getContainerProperties(
- @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container);
-
- /**
- * @see AzureBlobClient#containerExists
- */
- @Named("GetContainerProperties")
- @HEAD
- @Path("{container}")
- @QueryParams(keys = "restype", values = "container")
- @Fallback(FalseOnContainerNotFound.class)
- ListenableFuture<Boolean> containerExists(
- @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container);
-
- /**
- * @see AzureBlobClient#setResourceMetadata
- */
- @Named("SetContainerMetadata")
- @PUT
- @Path("{container}")
- @QueryParams(keys = { "restype", "comp" }, values = { "container", "metadata" })
- ListenableFuture<Void> setResourceMetadata(
- @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
- @BinderParam(BindMapToHeadersWithPrefix.class) Map<String, String> metadata);
-
- /**
- * @see AzureBlobClient#deleteContainer
- */
- @Named("DeleteContainer")
- @DELETE
- @Path("{container}")
- @Fallback(VoidOnNotFoundOr404.class)
- @QueryParams(keys = "restype", values = "container")
- ListenableFuture<Void> deleteContainer(
- @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container);
-
- /**
- * @see AzureBlobClient#createRootContainer
- */
- @Named("CreateContainer")
- @PUT
- @Path("$root")
- @Fallback(FalseIfContainerAlreadyExists.class)
- @QueryParams(keys = "restype", values = "container")
- ListenableFuture<Boolean> createRootContainer(CreateContainerOptions... options);
-
- /**
- * @see AzureBlobClient#deleteRootContainer
- */
- @Named("DeleteContainer")
- @DELETE
- @Path("$root")
- @Fallback(TrueOnNotFoundOr404.class)
- @QueryParams(keys = "restype", values = "container")
- ListenableFuture<Void> deleteRootContainer();
-
- /**
- * @see AzureBlobClient#listBlobs(String, ListBlobsOptions[])
- */
- @Named("ListBlobs")
- @GET
- @XMLResponseParser(ContainerNameEnumerationResultsHandler.class)
- @Path("{container}")
- @QueryParams(keys = { "restype", "comp" }, values = { "container", "list" })
- ListenableFuture<ListBlobsResponse> listBlobs(
- @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
- ListBlobsOptions... options);
-
- /**
- * @see AzureBlobClient#listBlobs(ListBlobsOptions[])
- */
- @Named("ListBlobs")
- @GET
- @XMLResponseParser(ContainerNameEnumerationResultsHandler.class)
- @Path("$root")
- @QueryParams(keys = { "restype", "comp" }, values = { "container", "list" })
- ListenableFuture<ListBlobsResponse> listBlobs(ListBlobsOptions... options);
-
- /**
- * @see AzureBlobClient#putBlob
- */
- @Named("PutBlob")
- @PUT
- @Path("{container}/{name}")
- @Headers(keys = EXPECT, values = "100-continue")
- @ResponseParser(ParseETagHeader.class)
- ListenableFuture<String> putBlob(
- @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
- @PathParam("name") @ParamParser(BlobName.class) @BinderParam(BindAzureBlobMetadataToRequest.class) org.jclouds.azureblob.domain.AzureBlob object);
-
- /**
- * @see AzureBlobClient#getBlob
- */
- @Named("GetBlob")
- @GET
- @ResponseParser(ParseBlobFromHeadersAndHttpContent.class)
- @Fallback(NullOnKeyNotFound.class)
- @Path("{container}/{name}")
- ListenableFuture<org.jclouds.azureblob.domain.AzureBlob> getBlob(
- @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
- @PathParam("name") String name, GetOptions... options);
-
- /**
- * @see AzureBlobClient#getBlobProperties
- */
- @Named("GetBlobProperties")
- @HEAD
- @ResponseParser(ParseBlobPropertiesFromHeaders.class)
- @Fallback(NullOnKeyNotFound.class)
- @Path("{container}/{name}")
- ListenableFuture<BlobProperties> getBlobProperties(
- @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
- @PathParam("name") String name);
-
- /**
- * @see AzureBlobClient#blobExists
- *
- */
- @Named("GetBlobProperties")
- @HEAD
- @Fallback(FalseOnKeyNotFound.class)
- @Path("{container}/{name}")
- ListenableFuture<Boolean> blobExists(
- @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
- @PathParam("name") String name);
-
- /**
- * @see AzureBlobClient#setBlobMetadata
- */
- @Named("SetBlobMetadata")
- @PUT
- @Path("{container}/{name}")
- @QueryParams(keys = { "comp" }, values = { "metadata" })
- ListenableFuture<Void> setBlobMetadata(
- @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
- @PathParam("name") String name, @BinderParam(BindMapToHeadersWithPrefix.class) Map<String, String> metadata);
-
- /**
- * @see AzureBlobClient#deleteBlob
- */
- @Named("DeleteBlob")
- @DELETE
- @Fallback(VoidOnNotFoundOr404.class)
- @Path("{container}/{name}")
- ListenableFuture<Void> deleteBlob(
- @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
- @PathParam("name") String name);
-
-
- /**
- * @see AzureBlobClient#putBlock
- */
- @Named("PutBlock")
- @PUT
- @Path("{container}/{name}")
- @QueryParams(keys = { "comp" }, values = { "block" })
- ListenableFuture<Void> putBlock(@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
- @PathParam("name") String name,
- @QueryParam("blockid") @ParamValidators(BlockIdValidator.class) String blockId, Payload part);
-
-
- /**
- * @see AzureBlobClient#putBlockList
- */
- @Named("PutBlockList")
- @PUT
- @Path("{container}/{name}")
- @ResponseParser(ParseETagHeader.class)
- @QueryParams(keys = { "comp" }, values = { "blocklist" })
- ListenableFuture<String> putBlockList(@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
- @PathParam("name") String name,
- @BinderParam(BindAzureBlocksToRequest.class) List<String> blockIdList);
-
- /**
- * @see AzureBlobClient#getBlockList
- */
- @Named("GetBlockList")
- @GET
- @Path("{container}/{name}")
- @XMLResponseParser(BlobBlocksResultsHandler.class)
- @QueryParams(keys = { "comp" }, values = { "blocklist" })
- ListenableFuture<ListBlobBlocksResponse> getBlockList(@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
- @PathParam("name") String name);
-
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/6843e0cb/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobClient.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobClient.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobClient.java
index 4d78ebb..790a0f4 100644
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobClient.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/AzureBlobClient.java
@@ -16,32 +16,75 @@
*/
package org.jclouds.azureblob;
+import static com.google.common.net.HttpHeaders.EXPECT;
+import static org.jclouds.Fallbacks.TrueOnNotFoundOr404;
+import static org.jclouds.Fallbacks.VoidOnNotFoundOr404;
+import static org.jclouds.azureblob.AzureBlobFallbacks.FalseIfContainerAlreadyExists;
+import static org.jclouds.blobstore.BlobStoreFallbacks.FalseOnContainerNotFound;
+import static org.jclouds.blobstore.BlobStoreFallbacks.FalseOnKeyNotFound;
+import static org.jclouds.blobstore.BlobStoreFallbacks.NullOnContainerNotFound;
+import static org.jclouds.blobstore.BlobStoreFallbacks.NullOnKeyNotFound;
+
+import java.io.Closeable;
import java.util.List;
import java.util.Map;
+
+import javax.inject.Named;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HEAD;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.QueryParam;
+
import org.jclouds.azure.storage.domain.BoundedSet;
+import org.jclouds.azure.storage.filters.SharedKeyLiteAuthentication;
import org.jclouds.azure.storage.options.ListOptions;
+import org.jclouds.azure.storage.reference.AzureStorageHeaders;
+import org.jclouds.azureblob.binders.BindAzureBlobMetadataToRequest;
+import org.jclouds.azureblob.binders.BindAzureBlocksToRequest;
import org.jclouds.azureblob.domain.AzureBlob;
import org.jclouds.azureblob.domain.BlobProperties;
import org.jclouds.azureblob.domain.ContainerProperties;
import org.jclouds.azureblob.domain.ListBlobBlocksResponse;
import org.jclouds.azureblob.domain.ListBlobsResponse;
import org.jclouds.azureblob.domain.PublicAccess;
+import org.jclouds.azureblob.functions.BlobName;
+import org.jclouds.azureblob.functions.ParseBlobFromHeadersAndHttpContent;
+import org.jclouds.azureblob.functions.ParseBlobPropertiesFromHeaders;
+import org.jclouds.azureblob.functions.ParseContainerPropertiesFromHeaders;
+import org.jclouds.azureblob.functions.ParsePublicAccessHeader;
import org.jclouds.azureblob.options.CreateContainerOptions;
import org.jclouds.azureblob.options.ListBlobsOptions;
+import org.jclouds.azureblob.predicates.validators.BlockIdValidator;
+import org.jclouds.azureblob.predicates.validators.ContainerNameValidator;
+import org.jclouds.azureblob.xml.AccountNameEnumerationResultsHandler;
+import org.jclouds.azureblob.xml.BlobBlocksResultsHandler;
+import org.jclouds.azureblob.xml.ContainerNameEnumerationResultsHandler;
+import org.jclouds.blobstore.binders.BindMapToHeadersWithPrefix;
+import org.jclouds.http.functions.ParseETagHeader;
import org.jclouds.http.options.GetOptions;
+import org.jclouds.io.Payload;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.Headers;
+import org.jclouds.rest.annotations.ParamParser;
+import org.jclouds.rest.annotations.ParamValidators;
+import org.jclouds.rest.annotations.QueryParams;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SkipEncoding;
+import org.jclouds.rest.annotations.XMLResponseParser;
import com.google.inject.Provides;
-import org.jclouds.io.Payload;
-/**
- * Provides access to Azure Blob via their REST API.
- * <p/>
- * All commands return a Future of the result from Azure Blob. Any exceptions incurred during
- * processing will be backend in an {@link ExecutionException} as documented in {@link Future#get()}.
- *
- * @see <a href="http://msdn.microsoft.com/en-us/library/dd135733.aspx" />
- */
-public interface AzureBlobClient {
+/** Provides access to Azure Blob via their REST API. */
+@RequestFilters(SharedKeyLiteAuthentication.class)
+@Headers(keys = AzureStorageHeaders.VERSION, values = "{jclouds.api-version}")
+@SkipEncoding({ '/', '$' })
+@Path("/")
+public interface AzureBlobClient extends Closeable {
@Provides
AzureBlob newBlob();
@@ -54,8 +97,13 @@ public interface AzureBlobClient {
* controls the number or type of results requested
* @see ListOptions
*/
+ @Named("ListContainers")
+ @GET
+ @XMLResponseParser(AccountNameEnumerationResultsHandler.class)
+ @QueryParams(keys = "comp", values = "list")
BoundedSet<ContainerProperties> listContainers(ListOptions... listOptions);
+
/**
* The Create Container operation creates a new container under the specified identity. If the
* container with the same name already exists, the operation fails.
@@ -68,18 +116,38 @@ public interface AzureBlobClient {
* @see CreateContainerOptions
*
*/
- boolean createContainer(String container, CreateContainerOptions... options);
+ @Named("CreateContainer")
+ @PUT
+ @Path("{container}")
+ @Fallback(FalseIfContainerAlreadyExists.class)
+ @QueryParams(keys = "restype", values = "container")
+ boolean createContainer(@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
+ CreateContainerOptions... options);
+
/**
* The Get Container Properties operation returns all user-defined metadata and system properties
* for the specified container. The data returned does not include the container's list of blobs.
*/
- ContainerProperties getContainerProperties(String container);
+ @Named("GetContainerProperties")
+ @HEAD
+ @Path("{container}")
+ @QueryParams(keys = "restype", values = "container")
+ @ResponseParser(ParseContainerPropertiesFromHeaders.class)
+ @Fallback(NullOnContainerNotFound.class)
+ ContainerProperties getContainerProperties(
+ @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container);
+
/**
* Issues a HEAD command to determine if the container exists or not.
*/
- boolean containerExists(String container);
+ @Named("GetContainerProperties")
+ @HEAD
+ @Path("{container}")
+ @QueryParams(keys = "restype", values = "container")
+ @Fallback(FalseOnContainerNotFound.class)
+ boolean containerExists(@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container);
/**
* The Set Container Metadata operation sets one or more user-defined name/value pairs for the
@@ -93,7 +161,14 @@ public interface AzureBlobClient {
* <p/>
* Calling Set Container Metadata updates the ETag for the container.
*/
- void setResourceMetadata(String container, Map<String, String> metadata);
+ @Named("SetContainerMetadata")
+ @PUT
+ @Path("{container}")
+ @QueryParams(keys = { "restype", "comp" }, values = { "container", "metadata" })
+ void setResourceMetadata(
+ @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
+ @BinderParam(BindMapToHeadersWithPrefix.class) Map<String, String> metadata);
+
/**
* The Delete Container operation marks the specified container for deletion. The container and
@@ -108,7 +183,12 @@ public interface AzureBlobClient {
* 404 (Not Found) while the container is being deleted.
*
*/
- void deleteContainer(String container);
+ @Named("DeleteContainer")
+ @DELETE
+ @Path("{container}")
+ @Fallback(VoidOnNotFoundOr404.class)
+ @QueryParams(keys = "restype", values = "container")
+ void deleteContainer(@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container);
/**
* The root container is a default container that may be inferred from a URL requesting a blob
@@ -121,15 +201,25 @@ public interface AzureBlobClient {
* @see CreateContainerOptions
*
*/
+ @Named("CreateContainer")
+ @PUT
+ @Path("$root")
+ @Fallback(FalseIfContainerAlreadyExists.class)
+ @QueryParams(keys = "restype", values = "container")
boolean createRootContainer(CreateContainerOptions... options);
/**
- *
- *
- * @param container
- * @return whether data in the container may be accessed publicly and the level of access
+ * Returns whether data in the container may be accessed publicly and the level of access
*/
- PublicAccess getPublicAccessForContainer(String container);
+ @Named("GetContainerACL")
+ @HEAD
+ @Path("{container}")
+ @QueryParams(keys = { "restype", "comp" }, values = { "container", "acl" })
+ @ResponseParser(ParsePublicAccessHeader.class)
+ @Fallback(NullOnContainerNotFound.class)
+ PublicAccess getPublicAccessForContainer(
+ @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container);
+
/**
* The Delete Container operation marks the specified container for deletion. The container and
@@ -142,9 +232,14 @@ public interface AzureBlobClient {
* operations, including operations on any blobs under the container, will fail with status code
* 404 (Not Found) while the container is being deleted.
*
- * @see deleteContainer(String)
- * @see createRootContainer(CreateContainerOptions)
+ * @see #deleteContainer(String)
+ * @see #createRootContainer(CreateContainerOptions...)
*/
+ @Named("DeleteContainer")
+ @DELETE
+ @Path("$root")
+ @Fallback(TrueOnNotFoundOr404.class)
+ @QueryParams(keys = "restype", values = "container")
void deleteRootContainer();
/**
@@ -182,8 +277,20 @@ public interface AzureBlobClient {
* <p/>
* Blobs are listed in alphabetical order in the response body.
*/
- ListBlobsResponse listBlobs(String container, ListBlobsOptions... options);
+ @Named("ListBlobs")
+ @GET
+ @XMLResponseParser(ContainerNameEnumerationResultsHandler.class)
+ @Path("{container}")
+ @QueryParams(keys = { "restype", "comp" }, values = { "container", "list" })
+ ListBlobsResponse listBlobs(@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
+ ListBlobsOptions... options);
+
+ @Named("ListBlobs")
+ @GET
+ @XMLResponseParser(ContainerNameEnumerationResultsHandler.class)
+ @Path("$root")
+ @QueryParams(keys = { "restype", "comp" }, values = { "container", "list" })
ListBlobsResponse listBlobs(ListBlobsOptions... options);
/**
@@ -201,57 +308,107 @@ public interface AzureBlobClient {
* (Request Payload Too Large). The Blob service also returns additional information about the
* error in the response, including the maximum blob size permitted in bytes.
*/
- String putBlob(String container, AzureBlob object);
+ @Named("PutBlob")
+ @PUT
+ @Path("{container}/{name}")
+ @Headers(keys = EXPECT, values = "100-continue")
+ @ResponseParser(ParseETagHeader.class)
+ String putBlob(@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
+ @PathParam("name") @ParamParser(BlobName.class) @BinderParam(BindAzureBlobMetadataToRequest.class)
+ AzureBlob object);
+
/**
* The Get Blob operation reads or downloads a blob from the system, including its metadata and
* properties.
*/
- AzureBlob getBlob(String container, String name, GetOptions... options);
+ @Named("GetBlob")
+ @GET
+ @ResponseParser(ParseBlobFromHeadersAndHttpContent.class)
+ @Fallback(NullOnKeyNotFound.class)
+ @Path("{container}/{name}")
+ AzureBlob getBlob(@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
+ @PathParam("name") String name, GetOptions... options);
/**
* The Put Block operation creates a block blob on Azure which can be later assembled into
* a single, large blob object with the Put Block List operation.
- *
- * @see <a href="http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx">Put Blob</a>
*/
- void putBlock(String container, String name, String blockId, Payload object);
+ @Named("PutBlock")
+ @PUT
+ @Path("{container}/{name}")
+ @QueryParams(keys = { "comp" }, values = { "block" })
+ void putBlock(@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
+ @PathParam("name") String name,
+ @QueryParam("blockid") @ParamValidators(BlockIdValidator.class) String blockId, Payload part);
/**
* The Put Block List assembles a list of blocks previously uploaded with Put Block into a single
* blob. Blocks are either already committed to a blob or uncommitted. The blocks ids passed here
* are searched for first in the uncommitted block list; then committed using the "latest" strategy.
- *
- * @see <a href="http://msdn.microsoft.com/en-us/library/windowsazure/dd179467.aspx">Put Block List</a>
*/
- String putBlockList(String container, String name, List<String> blockIdList);
+ @Named("PutBlockList")
+ @PUT
+ @Path("{container}/{name}")
+ @ResponseParser(ParseETagHeader.class)
+ @QueryParams(keys = { "comp" }, values = { "blocklist" })
+ String putBlockList(@PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
+ @PathParam("name") String name,
+ @BinderParam(BindAzureBlocksToRequest.class) List<String> blockIdList);
+
+ @Named("GetBlockList")
+ @GET
+ @Path("{container}/{name}")
+ @XMLResponseParser(BlobBlocksResultsHandler.class)
+ @QueryParams(keys = { "comp" }, values = { "blocklist" })
+ ListBlobBlocksResponse getBlockList(
+ @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
+ @PathParam("name") String name);
- /**
- * Get Block ID List for a blob
- *
- * @see <a href="http://msdn.microsoft.com/en-us/library/windowsazure/dd179400.aspx">Get Block List</a>
- */
- ListBlobBlocksResponse getBlockList(String container, String name);
/**
* The Get Blob Properties operation returns all user-defined metadata, standard HTTP properties,
* and system properties for the blob. It does not return the content of the blob.
*/
- BlobProperties getBlobProperties(String container, String name);
+ @Named("GetBlobProperties")
+ @HEAD
+ @ResponseParser(ParseBlobPropertiesFromHeaders.class)
+ @Fallback(NullOnKeyNotFound.class)
+ @Path("{container}/{name}")
+ BlobProperties getBlobProperties(
+ @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
+ @PathParam("name") String name);
- void setBlobMetadata(String container, String name, Map<String, String> metadata);
+
+ @Named("SetBlobMetadata")
+ @PUT
+ @Path("{container}/{name}")
+ @QueryParams(keys = { "comp" }, values = { "metadata" })
+ void setBlobMetadata(
+ @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
+ @PathParam("name") String name, @BinderParam(BindMapToHeadersWithPrefix.class) Map<String, String> metadata);
/**
* The Delete Blob operation marks the specified blob for deletion. The blob is later deleted
* during garbage collection.
*/
- void deleteBlob(String container, String name);
-
+ @Named("DeleteBlob")
+ @DELETE
+ @Fallback(VoidOnNotFoundOr404.class)
+ @Path("{container}/{name}")
+ void deleteBlob(
+ @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
+ @PathParam("name") String name);
/**
- * @throws ContainerNotFoundException
- * if the container is not present.
+ * @throws org.jclouds.blobstore.ContainerNotFoundException if the container is not present.
*/
- boolean blobExists(String container, String name);
+ @Named("GetBlobProperties")
+ @HEAD
+ @Fallback(FalseOnKeyNotFound.class)
+ @Path("{container}/{name}")
+ boolean blobExists(
+ @PathParam("container") @ParamValidators(ContainerNameValidator.class) String container,
+ @PathParam("name") String name);
}