View Javadoc

1   /**
2    *
3    * Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
4    *
5    * ====================================================================
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   * ====================================================================
18   */
19  package org.jclouds.azure.storage.handlers;
20  
21  import java.io.ByteArrayInputStream;
22  
23  import javax.annotation.Resource;
24  import javax.inject.Named;
25  
26  import org.jclouds.Constants;
27  import org.jclouds.azure.storage.domain.AzureStorageError;
28  import org.jclouds.azure.storage.util.AzureStorageUtils;
29  import org.jclouds.http.HttpCommand;
30  import org.jclouds.http.HttpException;
31  import org.jclouds.http.HttpResponse;
32  import org.jclouds.http.HttpRetryHandler;
33  import org.jclouds.http.HttpUtils;
34  import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
35  import org.jclouds.logging.Logger;
36  
37  import com.google.inject.Inject;
38  
39  /**
40   * Handles Retryable responses with error codes in the 4xx range
41   * 
42   * @author Adrian Cole
43   */
44  public class AzureStorageClientErrorRetryHandler implements HttpRetryHandler {
45  
46     @Inject(optional = true)
47     @Named(Constants.PROPERTY_MAX_RETRIES)
48     private int retryCountLimit = 5;
49  
50     private final AzureStorageUtils utils;
51     private final BackoffLimitedRetryHandler backoffHandler;
52  
53     @Resource
54     protected Logger logger = Logger.NULL;
55  
56     @Inject
57     public AzureStorageClientErrorRetryHandler(BackoffLimitedRetryHandler backoffHandler,
58              AzureStorageUtils utils) {
59        this.backoffHandler = backoffHandler;
60        this.utils = utils;
61     }
62  
63     public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
64        byte[] content = HttpUtils.closeClientButKeepContentStream(response);
65        command.incrementFailureCount();
66        if (!command.isReplayable()) {
67           logger.warn("Cannot retry after server error, command is not replayable: %1$s", command);
68           return false;
69        } else if (command.getFailureCount() > retryCountLimit) {
70           logger.warn(
71                    "Cannot retry after server error, command has exceeded retry limit %1$d: %2$s",
72                    retryCountLimit, command);
73           return false;
74        } else if (response.getStatusCode() == 409) {
75           // Content can be null in the case of HEAD requests
76           if (content != null) {
77              try {
78                 AzureStorageError error = utils.parseAzureStorageErrorFromContent(command, response,
79                          new ByteArrayInputStream(content));
80                 if ("ContainerBeingDeleted".equals(error.getCode())) {
81                    backoffHandler.imposeBackoffExponentialDelay(100L, 3, retryCountLimit, command
82                             .getFailureCount(), command.toString());
83                    return true;
84                 }
85              } catch (HttpException e) {
86                 logger.warn(e, "error parsing response: %s", new String(content));
87              }
88           }
89        }
90        return false;
91     }
92  
93  }