diff --git a/aws/s3/core/src/main/java/org/jclouds/aws/s3/config/LiveS3ConnectionModule.java b/aws/s3/core/src/main/java/org/jclouds/aws/s3/config/LiveS3ConnectionModule.java index 53c987faa1..becf0acc65 100644 --- a/aws/s3/core/src/main/java/org/jclouds/aws/s3/config/LiveS3ConnectionModule.java +++ b/aws/s3/core/src/main/java/org/jclouds/aws/s3/config/LiveS3ConnectionModule.java @@ -33,15 +33,10 @@ import org.jclouds.aws.s3.filters.RequestAuthorizeSignature; import org.jclouds.aws.s3.handlers.ParseAWSErrorFromXmlContent; import org.jclouds.aws.s3.internal.LiveS3Connection; import org.jclouds.http.HttpConstants; +import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpRequestFilter; -import org.jclouds.http.HttpResponseHandler; import org.jclouds.http.HttpRetryHandler; -import org.jclouds.http.annotation.ClientErrorHandler; -import org.jclouds.http.annotation.RedirectHandler; -import org.jclouds.http.annotation.RetryHandler; -import org.jclouds.http.annotation.ServerErrorHandler; import org.jclouds.http.handlers.BackoffLimitedRetryHandler; -import org.jclouds.http.handlers.CloseContentAndSetExceptionHandler; import org.jclouds.logging.Logger; import com.google.inject.AbstractModule; @@ -73,22 +68,16 @@ public class LiveS3ConnectionModule extends AbstractModule { @Override protected void configure() { - bindResponseHandlers(); bind(S3Connection.class).to(LiveS3Connection.class).in(Scopes.SINGLETON); - bind(HttpRetryHandler.class).annotatedWith(RetryHandler.class).to( - BackoffLimitedRetryHandler.class).in(Scopes.SINGLETON); + bind(HttpRetryHandler.class).to(BackoffLimitedRetryHandler.class).in(Scopes.SINGLETON); + bindErrorHandler(); requestInjection(this); logger.info("S3 Context = %1$s://%2$s:%3$s", (isSecure ? "https" : "http"), address, port); } - protected void bindResponseHandlers() { - bind(HttpResponseHandler.class).annotatedWith(RedirectHandler.class).to( - CloseContentAndSetExceptionHandler.class).in(Scopes.SINGLETON); - bind(HttpResponseHandler.class).annotatedWith(ClientErrorHandler.class).to( - ParseAWSErrorFromXmlContent.class).in(Scopes.SINGLETON); - bind(HttpResponseHandler.class).annotatedWith(ServerErrorHandler.class).to( - ParseAWSErrorFromXmlContent.class).in(Scopes.SINGLETON); + protected void bindErrorHandler() { + bind(HttpErrorHandler.class).to(ParseAWSErrorFromXmlContent.class).in(Scopes.SINGLETON); } @Provides diff --git a/aws/s3/core/src/main/java/org/jclouds/aws/s3/handlers/ParseAWSErrorFromXmlContent.java b/aws/s3/core/src/main/java/org/jclouds/aws/s3/handlers/ParseAWSErrorFromXmlContent.java index 0e12c57716..70cc063ab5 100644 --- a/aws/s3/core/src/main/java/org/jclouds/aws/s3/handlers/ParseAWSErrorFromXmlContent.java +++ b/aws/s3/core/src/main/java/org/jclouds/aws/s3/handlers/ParseAWSErrorFromXmlContent.java @@ -35,7 +35,7 @@ import org.jclouds.aws.s3.reference.S3Headers; import org.jclouds.aws.s3.xml.S3ParserFactory; import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpResponse; -import org.jclouds.http.HttpResponseHandler; +import org.jclouds.http.HttpErrorHandler; import org.jclouds.logging.Logger; import com.google.inject.Inject; @@ -47,7 +47,7 @@ import com.google.inject.Inject; * @author Adrian Cole * */ -public class ParseAWSErrorFromXmlContent implements HttpResponseHandler { +public class ParseAWSErrorFromXmlContent implements HttpErrorHandler { @Resource protected Logger logger = Logger.NULL; diff --git a/aws/s3/core/src/test/java/org/jclouds/aws/s3/config/S3ContextModuleTest.java b/aws/s3/core/src/test/java/org/jclouds/aws/s3/config/S3ContextModuleTest.java index 8236f6bace..58da6a3c9e 100644 --- a/aws/s3/core/src/test/java/org/jclouds/aws/s3/config/S3ContextModuleTest.java +++ b/aws/s3/core/src/test/java/org/jclouds/aws/s3/config/S3ContextModuleTest.java @@ -28,15 +28,10 @@ import static org.testng.Assert.assertEquals; import org.jclouds.aws.s3.handlers.ParseAWSErrorFromXmlContent; import org.jclouds.aws.s3.reference.S3Constants; import org.jclouds.aws.s3.xml.config.S3ParserModule; -import org.jclouds.http.HttpResponseHandler; +import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpRetryHandler; -import org.jclouds.http.annotation.ClientErrorHandler; -import org.jclouds.http.annotation.RedirectHandler; -import org.jclouds.http.annotation.RetryHandler; -import org.jclouds.http.annotation.ServerErrorHandler; import org.jclouds.http.config.JavaUrlHttpFutureCommandClientModule; import org.jclouds.http.handlers.BackoffLimitedRetryHandler; -import org.jclouds.http.handlers.CloseContentAndSetExceptionHandler; import org.testng.annotations.Test; import com.google.inject.Guice; @@ -74,22 +69,10 @@ public class S3ContextModuleTest { }, new JavaUrlHttpFutureCommandClientModule()); } - private static class ClientErrorHandlerTest { - @Inject - @ClientErrorHandler - HttpResponseHandler errorHandler; - } - - @Test - void testClientErrorHandler() { - ClientErrorHandlerTest error = createInjector().getInstance(ClientErrorHandlerTest.class); - assertEquals(error.errorHandler.getClass(), ParseAWSErrorFromXmlContent.class); - } private static class ServerErrorHandlerTest { @Inject - @ServerErrorHandler - HttpResponseHandler errorHandler; + HttpErrorHandler errorHandler; } @Test @@ -98,21 +81,9 @@ public class S3ContextModuleTest { assertEquals(error.errorHandler.getClass(), ParseAWSErrorFromXmlContent.class); } - private static class RedirectHandlerTest { - @Inject - @RedirectHandler - HttpResponseHandler errorHandler; - } - - @Test - void testRedirectHandler() { - RedirectHandlerTest error = createInjector().getInstance(RedirectHandlerTest.class); - assertEquals(error.errorHandler.getClass(), CloseContentAndSetExceptionHandler.class); - } - + private static class RetryHandlerTest { @Inject - @RetryHandler HttpRetryHandler retryHandler; } diff --git a/aws/s3/extensions/suncloud/src/main/java/org/jclouds/aws/s3/suncloud/config/SunCloudS3ConnectionModule.java b/aws/s3/extensions/suncloud/src/main/java/org/jclouds/aws/s3/suncloud/config/SunCloudS3ConnectionModule.java index 4a55433b97..037fc3fc17 100644 --- a/aws/s3/extensions/suncloud/src/main/java/org/jclouds/aws/s3/suncloud/config/SunCloudS3ConnectionModule.java +++ b/aws/s3/extensions/suncloud/src/main/java/org/jclouds/aws/s3/suncloud/config/SunCloudS3ConnectionModule.java @@ -26,11 +26,7 @@ package org.jclouds.aws.s3.suncloud.config; import org.jclouds.aws.s3.config.LiveS3ConnectionModule; import org.jclouds.aws.s3.config.S3ConnectionModule; import org.jclouds.aws.s3.suncloud.handlers.ParseSunCloudS3ErrorFromXmlContent; -import org.jclouds.http.HttpResponseHandler; -import org.jclouds.http.annotation.ClientErrorHandler; -import org.jclouds.http.annotation.RedirectHandler; -import org.jclouds.http.annotation.ServerErrorHandler; -import org.jclouds.http.handlers.CloseContentAndSetExceptionHandler; +import org.jclouds.http.HttpErrorHandler; import com.google.inject.Scopes; @@ -42,13 +38,9 @@ import com.google.inject.Scopes; @S3ConnectionModule public class SunCloudS3ConnectionModule extends LiveS3ConnectionModule { - protected void bindResponseHandlers() { - bind(HttpResponseHandler.class).annotatedWith(RedirectHandler.class).to( - CloseContentAndSetExceptionHandler.class).in(Scopes.SINGLETON); - bind(HttpResponseHandler.class).annotatedWith(ClientErrorHandler.class).to( - ParseSunCloudS3ErrorFromXmlContent.class).in(Scopes.SINGLETON); - bind(HttpResponseHandler.class).annotatedWith(ServerErrorHandler.class).to( - ParseSunCloudS3ErrorFromXmlContent.class).in(Scopes.SINGLETON); + protected void bindErrorHandler() { + bind(HttpErrorHandler.class).to(ParseSunCloudS3ErrorFromXmlContent.class) + .in(Scopes.SINGLETON); } } \ No newline at end of file diff --git a/aws/s3/extensions/suncloud/src/main/java/org/jclouds/aws/s3/suncloud/handlers/ParseSunCloudS3ErrorFromXmlContent.java b/aws/s3/extensions/suncloud/src/main/java/org/jclouds/aws/s3/suncloud/handlers/ParseSunCloudS3ErrorFromXmlContent.java index c4e383c68d..cbbf4685d2 100644 --- a/aws/s3/extensions/suncloud/src/main/java/org/jclouds/aws/s3/suncloud/handlers/ParseSunCloudS3ErrorFromXmlContent.java +++ b/aws/s3/extensions/suncloud/src/main/java/org/jclouds/aws/s3/suncloud/handlers/ParseSunCloudS3ErrorFromXmlContent.java @@ -36,7 +36,7 @@ import org.jclouds.aws.s3.suncloud.domain.SunCloudS3Error; import org.jclouds.aws.s3.xml.S3ParserFactory; import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpResponse; -import org.jclouds.http.HttpResponseHandler; +import org.jclouds.http.HttpErrorHandler; import org.jclouds.logging.Logger; import org.jclouds.util.Utils; @@ -49,7 +49,7 @@ import com.google.inject.Inject; * @author Adrian Cole * */ -public class ParseSunCloudS3ErrorFromXmlContent implements HttpResponseHandler { +public class ParseSunCloudS3ErrorFromXmlContent implements HttpErrorHandler { @Resource protected Logger logger = Logger.NULL; diff --git a/core/src/main/java/org/jclouds/http/HttpResponseHandler.java b/core/src/main/java/org/jclouds/http/HttpErrorHandler.java similarity index 91% rename from core/src/main/java/org/jclouds/http/HttpResponseHandler.java rename to core/src/main/java/org/jclouds/http/HttpErrorHandler.java index 4e108f1fde..419cd0c335 100644 --- a/core/src/main/java/org/jclouds/http/HttpResponseHandler.java +++ b/core/src/main/java/org/jclouds/http/HttpErrorHandler.java @@ -28,8 +28,8 @@ package org.jclouds.http; * * @author Adrian Cole */ -public interface HttpResponseHandler { - public static final HttpResponseHandler NOOP = new HttpResponseHandler() { +public interface HttpErrorHandler { + public static final HttpErrorHandler NOOP = new HttpErrorHandler() { public void handle(HttpFutureCommand command, HttpResponse response) { } }; diff --git a/core/src/main/java/org/jclouds/http/HttpRetryHandler.java b/core/src/main/java/org/jclouds/http/HttpRetryHandler.java index 499cb4766c..9665492460 100644 --- a/core/src/main/java/org/jclouds/http/HttpRetryHandler.java +++ b/core/src/main/java/org/jclouds/http/HttpRetryHandler.java @@ -32,7 +32,7 @@ package org.jclouds.http; */ public interface HttpRetryHandler { public static final HttpRetryHandler ALWAYS_RETRY = new HttpRetryHandler() { - public boolean retryRequest(HttpFutureCommand command, HttpResponse response) + public boolean shouldRetryRequest(HttpFutureCommand command, HttpResponse response) { return true; } @@ -42,12 +42,7 @@ public interface HttpRetryHandler { * Return true if the command should be retried. This method should only be * invoked when the response has failed with a HTTP 5xx error indicating a * server-side error. - * - * @param command - * @param response - * @return - * @throws InterruptedException */ - boolean retryRequest(HttpFutureCommand command, HttpResponse response) + boolean shouldRetryRequest(HttpFutureCommand command, HttpResponse response) throws InterruptedException; } diff --git a/core/src/main/java/org/jclouds/http/annotation/ClientErrorHandler.java b/core/src/main/java/org/jclouds/http/annotation/ClientErrorHandler.java deleted file mode 100644 index 19fdb36e01..0000000000 --- a/core/src/main/java/org/jclouds/http/annotation/ClientErrorHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * - * Copyright (C) 2009 Global Cloud Specialists, Inc. - * - * ==================================================================== - * 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.http.annotation; - -import com.google.inject.BindingAnnotation; -import java.lang.annotation.Target; -import java.lang.annotation.Retention; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; - -/** - * Implies that the object can address {@link org.jclouds.http.HttpResponse}s - * that contain status code 4xx. - * - * @author Adrian Cole - */ -@BindingAnnotation -@Target( { FIELD, PARAMETER, METHOD }) -@Retention(RUNTIME) -public @interface ClientErrorHandler { -} diff --git a/core/src/main/java/org/jclouds/http/annotation/RedirectHandler.java b/core/src/main/java/org/jclouds/http/annotation/RedirectHandler.java deleted file mode 100644 index d8827bf3e1..0000000000 --- a/core/src/main/java/org/jclouds/http/annotation/RedirectHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * - * Copyright (C) 2009 Global Cloud Specialists, Inc. - * - * ==================================================================== - * 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.http.annotation; - -import com.google.inject.BindingAnnotation; -import java.lang.annotation.Target; -import java.lang.annotation.Retention; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; - -/** - * Implies that the object can address {@link org.jclouds.http.HttpResponse}s that contain status - * code 3xx. - * - * @author Adrian Cole - */ -@BindingAnnotation -@Target( { FIELD, PARAMETER, METHOD }) -@Retention(RUNTIME) -public @interface RedirectHandler { -} diff --git a/core/src/main/java/org/jclouds/http/annotation/RetryHandler.java b/core/src/main/java/org/jclouds/http/annotation/RetryHandler.java deleted file mode 100644 index 265b62dd44..0000000000 --- a/core/src/main/java/org/jclouds/http/annotation/RetryHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * - * Copyright (C) 2009 Global Cloud Specialists, Inc. - * - * ==================================================================== - * 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.http.annotation; - -import com.google.inject.BindingAnnotation; -import java.lang.annotation.Target; -import java.lang.annotation.Retention; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; - -/** - * Implies that the object can address {@link org.jclouds.http.HttpRetryHandler}s. - * - * @author James Murty - */ -@BindingAnnotation -@Target( { FIELD, PARAMETER, METHOD }) -@Retention(RUNTIME) -public @interface RetryHandler { -} diff --git a/core/src/main/java/org/jclouds/http/annotation/ServerErrorHandler.java b/core/src/main/java/org/jclouds/http/annotation/ServerErrorHandler.java deleted file mode 100644 index 92a59f4058..0000000000 --- a/core/src/main/java/org/jclouds/http/annotation/ServerErrorHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * - * Copyright (C) 2009 Global Cloud Specialists, Inc. - * - * ==================================================================== - * 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.http.annotation; - -import com.google.inject.BindingAnnotation; -import java.lang.annotation.Target; -import java.lang.annotation.Retention; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; - -/** - * Implies that the object can address {@link org.jclouds.http.HttpResponse}s that contain status - * code 5xx. - * - * @author Adrian Cole - */ -@BindingAnnotation -@Target( { FIELD, PARAMETER, METHOD }) -@Retention(RUNTIME) -public @interface ServerErrorHandler { -} diff --git a/core/src/main/java/org/jclouds/http/handlers/BackoffLimitedRetryHandler.java b/core/src/main/java/org/jclouds/http/handlers/BackoffLimitedRetryHandler.java index bcca0c889d..42a0810e86 100644 --- a/core/src/main/java/org/jclouds/http/handlers/BackoffLimitedRetryHandler.java +++ b/core/src/main/java/org/jclouds/http/handlers/BackoffLimitedRetryHandler.java @@ -67,7 +67,7 @@ public class BackoffLimitedRetryHandler implements HttpRetryHandler { this.retryCountLimit = retryCountLimit; } - public boolean retryRequest(HttpFutureCommand command, HttpResponse response) + public boolean shouldRetryRequest(HttpFutureCommand command, HttpResponse response) throws InterruptedException { IOUtils.closeQuietly(response.getContent()); diff --git a/core/src/main/java/org/jclouds/http/handlers/CloseContentAndSetExceptionHandler.java b/core/src/main/java/org/jclouds/http/handlers/CloseContentAndSetExceptionHandler.java index 9f915b3f7c..72795750e0 100644 --- a/core/src/main/java/org/jclouds/http/handlers/CloseContentAndSetExceptionHandler.java +++ b/core/src/main/java/org/jclouds/http/handlers/CloseContentAndSetExceptionHandler.java @@ -28,14 +28,14 @@ import java.io.IOException; import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponseException; -import org.jclouds.http.HttpResponseHandler; +import org.jclouds.http.HttpErrorHandler; import org.jclouds.util.Utils; /** * * @author Adrian Cole */ -public class CloseContentAndSetExceptionHandler implements HttpResponseHandler { +public class CloseContentAndSetExceptionHandler implements HttpErrorHandler { public void handle(HttpFutureCommand command, HttpResponse response) { String content; diff --git a/core/src/main/java/org/jclouds/http/internal/BaseHttpFutureCommandClient.java b/core/src/main/java/org/jclouds/http/internal/BaseHttpFutureCommandClient.java index 34e5563da5..a0e1a1c904 100644 --- a/core/src/main/java/org/jclouds/http/internal/BaseHttpFutureCommandClient.java +++ b/core/src/main/java/org/jclouds/http/internal/BaseHttpFutureCommandClient.java @@ -23,64 +23,75 @@ */ package org.jclouds.http.internal; -import java.net.URI; +import java.io.IOException; import java.util.Collections; import java.util.List; import javax.annotation.Resource; +import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpFutureCommandClient; +import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequestFilter; import org.jclouds.http.HttpResponse; -import org.jclouds.http.HttpResponseHandler; import org.jclouds.http.HttpRetryHandler; -import org.jclouds.http.annotation.ClientErrorHandler; -import org.jclouds.http.annotation.RedirectHandler; -import org.jclouds.http.annotation.RetryHandler; -import org.jclouds.http.annotation.ServerErrorHandler; import org.jclouds.http.handlers.BackoffLimitedRetryHandler; import org.jclouds.http.handlers.CloseContentAndSetExceptionHandler; import org.jclouds.logging.Logger; import com.google.inject.Inject; -public abstract class BaseHttpFutureCommandClient implements HttpFutureCommandClient { - - protected final URI target; +public abstract class BaseHttpFutureCommandClient implements HttpFutureCommandClient { @Resource protected Logger logger = Logger.NULL; @Inject(optional = true) protected List requestFilters = Collections.emptyList(); - @RedirectHandler - @Inject(optional = true) - protected HttpResponseHandler redirectHandler = new CloseContentAndSetExceptionHandler(); - @ClientErrorHandler - @Inject(optional = true) - protected HttpResponseHandler clientErrorHandler = new CloseContentAndSetExceptionHandler(); - @ServerErrorHandler - @Inject(optional = true) - protected HttpResponseHandler serverErrorHandler = new CloseContentAndSetExceptionHandler(); - @RetryHandler + @Inject(optional = true) + protected HttpErrorHandler httpErrorHandler = new CloseContentAndSetExceptionHandler(); + @Inject(optional = true) protected HttpRetryHandler httpRetryHandler = new BackoffLimitedRetryHandler(5); - @Inject - public BaseHttpFutureCommandClient(URI target) { - this.target = target; + public void submit(HttpFutureCommand command) { + HttpRequest request = command.getRequest(); + + Q nativeRequest = null; + try { + for (HttpRequestFilter filter : requestFilters) { + filter.filter(request); + } + HttpResponse response = null; + for (;;) { + logger.trace("%1$s - converting request %2$s", request.getEndPoint(), request); + nativeRequest = convert(request); + response = invoke(nativeRequest); + int statusCode = response.getStatusCode(); + if (statusCode >= 500 && httpRetryHandler.shouldRetryRequest(command, response)) + continue; + break; + } + handleResponse(command, response); + } catch (Exception e) { + command.setException(e); + } finally { + cleanup(nativeRequest); + } } + protected abstract Q convert(HttpRequest request) throws IOException; + + protected abstract HttpResponse invoke(Q nativeRequest) throws IOException; + + protected abstract void cleanup(Q nativeResponse); + protected void handleResponse(HttpFutureCommand command, HttpResponse response) { int code = response.getStatusCode(); - if (code >= 500) { - serverErrorHandler.handle(command, response); - } else if (code >= 400 && code < 500) { - clientErrorHandler.handle(command, response); - } else if (code >= 300 && code < 400) { - redirectHandler.handle(command, response); + if (code >= 300) { + httpErrorHandler.handle(command, response); } else { command.getResponseFuture().setResponse(response); command.getResponseFuture().run(); diff --git a/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpFutureCommandClient.java b/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpFutureCommandClient.java index 66eb9991c0..ae4cb7b76b 100644 --- a/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpFutureCommandClient.java +++ b/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpFutureCommandClient.java @@ -30,70 +30,36 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URI; import java.net.URL; import org.apache.commons.io.IOUtils; import org.jclouds.http.HttpConstants; -import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpFutureCommandClient; -import org.jclouds.http.HttpMethod; import org.jclouds.http.HttpRequest; -import org.jclouds.http.HttpRequestFilter; import org.jclouds.http.HttpResponse; -import com.google.inject.Inject; - /** * Basic implementation of a {@link HttpFutureCommandClient}. * * @author Adrian Cole */ -public class JavaUrlHttpFutureCommandClient extends BaseHttpFutureCommandClient { +public class JavaUrlHttpFutureCommandClient extends BaseHttpFutureCommandClient { - @Inject - public JavaUrlHttpFutureCommandClient(URI target) throws MalformedURLException { - super(target); - } - - public void submit(HttpFutureCommand command) { - HttpRequest request = command.getRequest(); - HttpURLConnection connection = null; - try { - HttpResponse response = null; - for (;;) { - for (HttpRequestFilter filter : requestFilters) { - filter.filter(request); - } - logger.trace("%1$s - converting request %2$s", target, request); - connection = openJavaConnection(request); - logger.trace("%1$s - submitting request %2$s", target, connection); - response = getResponse(connection); - logger.trace("%1$s - received response %2$s", target, response); - if (response.getStatusCode() >= 500 && httpRetryHandler.retryRequest(command, response)) - continue; - break; - } - handleResponse(command, response); - } catch (Exception e) { - command.setException(e); - } finally { - // DO NOT disconnect, as it will also close the unconsumed - // outputStream from above. - if (request.getMethod().equals(HttpMethod.HEAD)) - connection.disconnect(); - } - } - - protected HttpResponse getResponse(HttpURLConnection connection) throws IOException { + @Override + protected HttpResponse invoke(HttpURLConnection connection) throws IOException { HttpResponse response = new HttpResponse(); + if (logger.isTraceEnabled()) + logger.trace("%1$s - submitting request %2$s, headers: %3$s", connection.getURL() + .getHost(), connection.getURL(), connection.getRequestProperties()); InputStream in; try { in = connection.getInputStream(); } catch (IOException e) { in = connection.getErrorStream(); } + if (logger.isTraceEnabled()) + logger.info("%1$s - received response code %2$s, headers: %3$s", connection.getURL() + .getHost(), connection.getResponseCode(), connection.getHeaderFields()); if (in != null) { response.setContent(in); } @@ -106,8 +72,9 @@ public class JavaUrlHttpFutureCommandClient extends BaseHttpFutureCommandClient return response; } - protected HttpURLConnection openJavaConnection(HttpRequest request) throws IOException { - URL url = new URL(target.toURL(), request.getUri()); + @Override + protected HttpURLConnection convert(HttpRequest request) throws IOException { + URL url = new URL(request.getEndPoint().toURL(), request.getUri()); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setAllowUserInteraction(false); @@ -143,4 +110,14 @@ public class JavaUrlHttpFutureCommandClient extends BaseHttpFutureCommandClient } return connection; } + + /** + * Only disconnect if there is no content, as disconnecting will throw away unconsumed content. + */ + @Override + protected void cleanup(HttpURLConnection connection) { + if (connection.getContentLength() == 0) + connection.disconnect(); + } + } diff --git a/core/src/test/java/org/jclouds/http/BackoffLimitedRetryJavaIntegrationTest.java b/core/src/test/java/org/jclouds/http/BackoffLimitedRetryJavaIntegrationTest.java index 52ca15c8f9..e692f2daa7 100644 --- a/core/src/test/java/org/jclouds/http/BackoffLimitedRetryJavaIntegrationTest.java +++ b/core/src/test/java/org/jclouds/http/BackoffLimitedRetryJavaIntegrationTest.java @@ -34,7 +34,6 @@ import java.util.concurrent.ExecutionException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.jclouds.http.annotation.RetryHandler; import org.jclouds.http.commands.GetString; import org.jclouds.http.config.JavaUrlHttpFutureCommandClientModule; import org.jclouds.http.handlers.BackoffLimitedRetryHandler; diff --git a/core/src/test/java/org/jclouds/http/BaseJettyTest.java b/core/src/test/java/org/jclouds/http/BaseJettyTest.java index 57d75d0164..a6bb0bd249 100644 --- a/core/src/test/java/org/jclouds/http/BaseJettyTest.java +++ b/core/src/test/java/org/jclouds/http/BaseJettyTest.java @@ -37,6 +37,7 @@ import org.jclouds.http.commands.CommandFactory; import org.jclouds.http.commands.config.HttpCommandsModule; import org.jclouds.lifecycle.Closer; import org.jclouds.logging.jdk.config.JDKLoggingModule; +import org.jclouds.util.Utils; import org.mortbay.jetty.Handler; import org.mortbay.jetty.Request; import org.mortbay.jetty.Server; @@ -98,9 +99,17 @@ public abstract class BaseJettyTest { Handler server2Handler = new AbstractHandler() { public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException { - response.setContentType("text/xml"); - response.setStatus(HttpServletResponse.SC_OK); - response.getWriter().println(XML2); + if (request.getMethod().equals("PUT")) { + if (request.getContentLength() > 0) { + Utils.toStringAndClose(request.getInputStream()); + } else { + response.sendError(500, "no content"); + } + } else { + response.setContentType("text/xml"); + response.setStatus(HttpServletResponse.SC_OK); + response.getWriter().println(XML2); + } ((Request) request).setHandled(true); } }; diff --git a/core/src/test/java/org/jclouds/http/JavaUrlHttpFutureCommandFutureCommandClientTest.java b/core/src/test/java/org/jclouds/http/JavaUrlHttpFutureCommandClientTest.java similarity index 81% rename from core/src/test/java/org/jclouds/http/JavaUrlHttpFutureCommandFutureCommandClientTest.java rename to core/src/test/java/org/jclouds/http/JavaUrlHttpFutureCommandClientTest.java index 29d8484f5b..9671bcb466 100644 --- a/core/src/test/java/org/jclouds/http/JavaUrlHttpFutureCommandFutureCommandClientTest.java +++ b/core/src/test/java/org/jclouds/http/JavaUrlHttpFutureCommandClientTest.java @@ -31,18 +31,17 @@ import java.util.Properties; /** * // TODO: Adrian: Document this! - * + * * @author Adrian Cole */ @Test -public class JavaUrlHttpFutureCommandFutureCommandClientTest extends BaseHttpFutureCommandClientTest { - - protected Module createClientModule() { - return new JavaUrlHttpFutureCommandClientModule(); - } +public class JavaUrlHttpFutureCommandClientTest extends BaseHttpFutureCommandClientTest { + protected Module createClientModule() { + return new JavaUrlHttpFutureCommandClientModule(); + } - protected void addConnectionProperties(Properties props) { - //NONE - } + protected void addConnectionProperties(Properties props) { + // NONE + } } \ No newline at end of file diff --git a/core/src/test/java/org/jclouds/http/handlers/BackoffLimitedRetryHandlerTest.java b/core/src/test/java/org/jclouds/http/handlers/BackoffLimitedRetryHandlerTest.java index b264048e10..e52ef59f43 100644 --- a/core/src/test/java/org/jclouds/http/handlers/BackoffLimitedRetryHandlerTest.java +++ b/core/src/test/java/org/jclouds/http/handlers/BackoffLimitedRetryHandlerTest.java @@ -111,7 +111,7 @@ public class BackoffLimitedRetryHandlerTest { assertEquals(response.getContent().available(), 1); assertEquals(response.getContent().read(), 1); - handler.retryRequest(command, response); + handler.shouldRetryRequest(command, response); assertEquals(response.getContent().available(), 0); assertEquals(response.getContent().read(), -1); @@ -123,13 +123,13 @@ public class BackoffLimitedRetryHandlerTest { "uri", new ReturnStringIf200()); HttpResponse response = new HttpResponse(); - handler.retryRequest(command, response); + handler.shouldRetryRequest(command, response); assertEquals(command.getFailureCount(), 1); - handler.retryRequest(command, response); + handler.shouldRetryRequest(command, response); assertEquals(command.getFailureCount(), 2); - handler.retryRequest(command, response); + handler.shouldRetryRequest(command, response); assertEquals(command.getFailureCount(), 3); } @@ -139,17 +139,17 @@ public class BackoffLimitedRetryHandlerTest { "uri", new ReturnStringIf200()); HttpResponse response = new HttpResponse(); - assertEquals(handler.retryRequest(command, response), true); // Failure 1 + assertEquals(handler.shouldRetryRequest(command, response), true); // Failure 1 - assertEquals(handler.retryRequest(command, response), true); // Failure 2 + assertEquals(handler.shouldRetryRequest(command, response), true); // Failure 2 - assertEquals(handler.retryRequest(command, response), true); // Failure 3 + assertEquals(handler.shouldRetryRequest(command, response), true); // Failure 3 - assertEquals(handler.retryRequest(command, response), true); // Failure 4 + assertEquals(handler.shouldRetryRequest(command, response), true); // Failure 4 - assertEquals(handler.retryRequest(command, response), true); // Failure 5 + assertEquals(handler.shouldRetryRequest(command, response), true); // Failure 5 - assertEquals(handler.retryRequest(command, response), false); // Failure 6 + assertEquals(handler.shouldRetryRequest(command, response), false); // Failure 6 } } \ No newline at end of file diff --git a/extensions/gae/src/main/java/org/jclouds/gae/URLFetchServiceClient.java b/extensions/gae/src/main/java/org/jclouds/gae/URLFetchServiceClient.java index 8fd1d61d94..2d01d6fe7c 100644 --- a/extensions/gae/src/main/java/org/jclouds/gae/URLFetchServiceClient.java +++ b/extensions/gae/src/main/java/org/jclouds/gae/URLFetchServiceClient.java @@ -37,10 +37,9 @@ import java.util.List; import org.apache.commons.io.IOUtils; import org.jclouds.http.HttpConstants; -import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpFutureCommandClient; +import org.jclouds.http.HttpHeaders; import org.jclouds.http.HttpRequest; -import org.jclouds.http.HttpRequestFilter; import org.jclouds.http.HttpResponse; import org.jclouds.http.internal.BaseHttpFutureCommandClient; @@ -58,61 +57,12 @@ import com.google.inject.Inject; * * @author Adrian Cole */ -public class URLFetchServiceClient extends BaseHttpFutureCommandClient { +public class URLFetchServiceClient extends BaseHttpFutureCommandClient { private final URLFetchService urlFetchService; - private final int port; - private final boolean isSecure; @Inject - public URLFetchServiceClient(URI target, URLFetchService urlFetchService) - throws MalformedURLException { - super(target); + public URLFetchServiceClient(URLFetchService urlFetchService) throws MalformedURLException { this.urlFetchService = urlFetchService; - this.port = target.getPort(); - this.isSecure = target.getScheme().equals("https"); - } - - public void submit(HttpFutureCommand command) { - HttpRequest request = command.getRequest(); - - HTTPResponse gaeResponse = null; - try { - for (HttpRequestFilter filter : requestFilters) { - filter.filter(request); - } - HttpResponse response = null; - for (;;) { - logger.trace("%1$s - converting request %2$s", target, request); - HTTPRequest gaeRequest = convert(request); - if (logger.isTraceEnabled()) - logger.trace("%1$s - submitting request %2$s, headers: %3$s", target, gaeRequest - .getURL(), headersAsString(gaeRequest.getHeaders())); - gaeResponse = this.urlFetchService.fetch(gaeRequest); - if (logger.isTraceEnabled()) - logger.info("%1$s - received response code %2$s, headers: %3$s", target, gaeResponse - .getResponseCode(), headersAsString(gaeResponse.getHeaders())); - response = convert(gaeResponse); - int statusCode = response.getStatusCode(); - if (statusCode >= 500 && httpRetryHandler.retryRequest(command, response)) - continue; - break; - } - handleResponse(command, response); - } catch (Exception e) { - if (gaeResponse != null && gaeResponse.getContent() != null) { - logger.error(e, "error encountered during the execution: %1$s%n%2$s", gaeResponse, - new String(gaeResponse.getContent())); - } - command.setException(e); - } - } - - String headersAsString(List headers) { - StringBuilder builder = new StringBuilder(""); - for (HTTPHeader header : headers) - builder.append("[").append(header.getName()).append("=").append(header.getValue()).append( - "],"); - return builder.toString(); } /** @@ -142,7 +92,7 @@ public class URLFetchServiceClient extends BaseHttpFutureCommandClient { } @VisibleForTesting - HttpResponse convert(HTTPResponse gaeResponse) { + protected HttpResponse convert(HTTPResponse gaeResponse) { HttpResponse response = new HttpResponse(); response.setStatusCode(gaeResponse.getResponseCode()); for (HTTPHeader header : gaeResponse.getHeaders()) { @@ -155,17 +105,11 @@ public class URLFetchServiceClient extends BaseHttpFutureCommandClient { } @VisibleForTesting - HTTPRequest convert(HttpRequest request) throws IOException { - String hostHeader = request.getFirstHeaderOrNull(HttpConstants.HOST); - URL url; - // As host headers are not supported in GAE/J v1.2.1, we'll change the - // hostname of the destination to the same value as the host header - if (hostHeader != null) { - url = new URL(new URL(isSecure ? "https" : "http", hostHeader, port, "/"), request - .getUri()); - } else { - url = new URL(target.toURL(), request.getUri()); - } + protected HTTPRequest convert(HttpRequest request) throws IOException { + + convertHostHeaderToEndPoint(request); + + URL url = new URL(request.getEndPoint().toURL(), request.getUri()); FetchOptions options = disallowTruncate(); followRedirectsUnlessRequestContainsPayload(request, options); @@ -174,11 +118,8 @@ public class URLFetchServiceClient extends BaseHttpFutureCommandClient { .toString()), options); for (String header : request.getHeaders().keySet()) { - // GAE/J v1.2.1 re-writes the host header, so we'll skip it. - if (!header.equals(HttpConstants.HOST)) { - for (String value : request.getHeaders().get(header)) { - gaeRequest.addHeader(new HTTPHeader(header, value)); - } + for (String value : request.getHeaders().get(header)) { + gaeRequest.addHeader(new HTTPHeader(header, value)); } } @@ -191,6 +132,24 @@ public class URLFetchServiceClient extends BaseHttpFutureCommandClient { return gaeRequest; } + /** + * As host headers are not supported in GAE/J v1.2.1, we'll change the hostname of the + * destination to the same value as the host header + * + * @param request + */ + @VisibleForTesting + void convertHostHeaderToEndPoint(HttpRequest request) { + + String hostHeader = request.getFirstHeaderOrNull(HttpConstants.HOST); + + if (hostHeader != null) { + request.setEndPoint(URI.create(String.format("%1$s://%2$s:%3$d", request.getEndPoint() + .getScheme(), hostHeader, request.getEndPoint().getPort()))); + request.getHeaders().removeAll(HttpHeaders.HOST); + } + } + private void followRedirectsUnlessRequestContainsPayload(HttpRequest request, FetchOptions options) { if (request.getPayload() != null) @@ -198,4 +157,32 @@ public class URLFetchServiceClient extends BaseHttpFutureCommandClient { else options.followRedirects(); } + + /** + * nothing to clean up. + */ + @Override + protected void cleanup(HTTPRequest nativeRequest) { + } + + @Override + protected HttpResponse invoke(HTTPRequest request) throws IOException { + if (logger.isTraceEnabled()) + logger.trace("%1$s - submitting request %2$s, headers: %3$s", request.getURL().getHost(), + request.getURL(), headersAsString(request.getHeaders())); + HTTPResponse response = urlFetchService.fetch(request); + if (logger.isTraceEnabled()) + logger.info("%1$s - received response code %2$s, headers: %3$s", request.getURL() + .getHost(), response.getResponseCode(), headersAsString(response.getHeaders())); + return convert(response); + } + + String headersAsString(List headers) { + StringBuilder builder = new StringBuilder(""); + for (HTTPHeader header : headers) + builder.append("[").append(header.getName()).append("=").append(header.getValue()).append( + "],"); + return builder.toString(); + } + } diff --git a/extensions/gae/src/test/java/org/jclouds/gae/URLFetchServiceClientTest.java b/extensions/gae/src/test/java/org/jclouds/gae/URLFetchServiceClientTest.java index a9715019d9..c29443a628 100644 --- a/extensions/gae/src/test/java/org/jclouds/gae/URLFetchServiceClientTest.java +++ b/extensions/gae/src/test/java/org/jclouds/gae/URLFetchServiceClientTest.java @@ -64,7 +64,16 @@ public class URLFetchServiceClientTest { @BeforeTest void setupClient() throws MalformedURLException { endPoint = URI.create("http://localhost:80"); - client = new URLFetchServiceClient(endPoint, createNiceMock(URLFetchService.class)); + client = new URLFetchServiceClient(createNiceMock(URLFetchService.class)); + } + + @Test + void testConvertHostHeaderToEndPoint() { + HttpRequest request = new HttpRequest(endPoint, HttpMethod.GET, "foo"); + request.getHeaders().put(HttpHeaders.HOST, "weird"); + client.convertHostHeaderToEndPoint(request); + assertEquals(request.getEndPoint().getHost(), "weird"); + assert request.getFirstHeaderOrNull(HttpHeaders.HOST) == null; } @Test diff --git a/extensions/httpnio/src/main/java/org/jclouds/http/httpnio/pool/HttpNioFutureCommandExecutionHandler.java b/extensions/httpnio/src/main/java/org/jclouds/http/httpnio/pool/HttpNioFutureCommandExecutionHandler.java index c033012088..dafb377454 100644 --- a/extensions/httpnio/src/main/java/org/jclouds/http/httpnio/pool/HttpNioFutureCommandExecutionHandler.java +++ b/extensions/httpnio/src/main/java/org/jclouds/http/httpnio/pool/HttpNioFutureCommandExecutionHandler.java @@ -35,14 +35,10 @@ import org.apache.http.HttpResponse; import org.apache.http.nio.entity.ConsumingNHttpEntity; import org.apache.http.nio.protocol.NHttpRequestExecutionHandler; import org.apache.http.protocol.HttpContext; +import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpRequest; -import org.jclouds.http.HttpResponseHandler; import org.jclouds.http.HttpRetryHandler; -import org.jclouds.http.annotation.ClientErrorHandler; -import org.jclouds.http.annotation.RedirectHandler; -import org.jclouds.http.annotation.RetryHandler; -import org.jclouds.http.annotation.ServerErrorHandler; import org.jclouds.http.handlers.BackoffLimitedRetryHandler; import org.jclouds.http.handlers.CloseContentAndSetExceptionHandler; import org.jclouds.http.httpnio.util.HttpNioUtils; @@ -52,131 +48,114 @@ import com.google.inject.Inject; /** * // TODO: Adrian: Document this! - * + * * @author Adrian Cole */ -public class HttpNioFutureCommandExecutionHandler implements - NHttpRequestExecutionHandler { - private final ExecutorService executor; - @Resource - protected Logger logger = Logger.NULL; - private final ConsumingNHttpEntityFactory entityFactory; - private final BlockingQueue> commandQueue; +public class HttpNioFutureCommandExecutionHandler implements NHttpRequestExecutionHandler { + private final ExecutorService executor; + @Resource + protected Logger logger = Logger.NULL; + private final ConsumingNHttpEntityFactory entityFactory; + private final BlockingQueue> commandQueue; - @RedirectHandler - @Inject(optional = true) - private HttpResponseHandler redirectHandler = new CloseContentAndSetExceptionHandler(); + @Inject(optional = true) + private HttpErrorHandler serverErrorHandler = new CloseContentAndSetExceptionHandler(); - @ClientErrorHandler - @Inject(optional = true) - private HttpResponseHandler clientErrorHandler = new CloseContentAndSetExceptionHandler(); + @Inject(optional = true) + protected HttpRetryHandler httpRetryHandler = new BackoffLimitedRetryHandler(5); - @ServerErrorHandler - @Inject(optional = true) - private HttpResponseHandler serverErrorHandler = new CloseContentAndSetExceptionHandler(); + public interface ConsumingNHttpEntityFactory { + public ConsumingNHttpEntity create(HttpEntity httpEntity); + } - @RetryHandler - @Inject(optional = true) - protected HttpRetryHandler httpRetryHandler = new BackoffLimitedRetryHandler(5); + @Inject + public HttpNioFutureCommandExecutionHandler(ConsumingNHttpEntityFactory entityFactory, + ExecutorService executor, BlockingQueue> commandQueue) { + this.executor = executor; + this.entityFactory = entityFactory; + this.commandQueue = commandQueue; + } - public interface ConsumingNHttpEntityFactory { - public ConsumingNHttpEntity create(HttpEntity httpEntity); - } + public void initalizeContext(HttpContext context, Object attachment) { + } - @Inject - public HttpNioFutureCommandExecutionHandler( - ConsumingNHttpEntityFactory entityFactory, - ExecutorService executor, - BlockingQueue> commandQueue) { - this.executor = executor; - this.entityFactory = entityFactory; - this.commandQueue = commandQueue; - } + public HttpEntityEnclosingRequest submitRequest(HttpContext context) { + HttpFutureCommand command = (HttpFutureCommand) context.removeAttribute("command"); + if (command != null) { + HttpRequest object = command.getRequest(); + return HttpNioUtils.convertToApacheRequest(object); + } + return null; - public void initalizeContext(HttpContext context, Object attachment) { - } + } - public HttpEntityEnclosingRequest submitRequest(HttpContext context) { - HttpFutureCommand command = (HttpFutureCommand) context - .removeAttribute("command"); - if (command != null) { - HttpRequest object = command.getRequest(); - return HttpNioUtils.convertToApacheRequest(object); - } - return null; - - } - - public ConsumingNHttpEntity responseEntity(HttpResponse response, - HttpContext context) throws IOException { - return entityFactory.create(response.getEntity()); - } - - public void handleResponse(HttpResponse apacheResponse, HttpContext context) + public ConsumingNHttpEntity responseEntity(HttpResponse response, HttpContext context) throws IOException { - HttpNioFutureCommandConnectionHandle handle = (HttpNioFutureCommandConnectionHandle) context - .removeAttribute("command-handle"); - if (handle != null) { - try { - HttpFutureCommand command = handle.getCommand(); - org.jclouds.http.HttpResponse response = HttpNioUtils - .convertToJavaCloudsResponse(apacheResponse); + return entityFactory.create(response.getEntity()); + } - int code = response.getStatusCode(); - if (code >= 500) { - boolean retryRequest = false; - try { - retryRequest = httpRetryHandler.retryRequest(command, response); - } catch (InterruptedException ie) { - // TODO: Add interrupt exception to command and abort? - } - if (retryRequest) { - commandQueue.add(command); - } else { - this.serverErrorHandler.handle(command, response); - } - } else if (code >= 400 && code < 500) { - this.clientErrorHandler.handle(command, response); - } else if (code >= 300 && code < 400) { - this.redirectHandler.handle(command, response); - } else { - processResponse(response, command); - } - } finally { - releaseConnectionToPool(handle); + public void handleResponse(HttpResponse apacheResponse, HttpContext context) throws IOException { + HttpNioFutureCommandConnectionHandle handle = (HttpNioFutureCommandConnectionHandle) context + .removeAttribute("command-handle"); + if (handle != null) { + try { + HttpFutureCommand command = handle.getCommand(); + org.jclouds.http.HttpResponse response = HttpNioUtils + .convertToJavaCloudsResponse(apacheResponse); + + int code = response.getStatusCode(); + if (code >= 500) { + boolean retryRequest = false; + try { + retryRequest = httpRetryHandler.shouldRetryRequest(command, response); + } catch (InterruptedException ie) { + // TODO: Add interrupt exception to command and abort? + } + if (retryRequest) { + commandQueue.add(command); + } else { + serverErrorHandler.handle(command, response); + } + } else if (code >= 400 && code < 500) { + serverErrorHandler.handle(command, response); + } else if (code >= 300 && code < 400) { + serverErrorHandler.handle(command, response); + } else { + processResponse(response, command); } - } else { - throw new IllegalStateException(String.format( - "No command-handle associated with command %1$s", context)); - } - } + } finally { + releaseConnectionToPool(handle); + } + } else { + throw new IllegalStateException(String.format( + "No command-handle associated with command %1$s", context)); + } + } - protected void releaseConnectionToPool( - HttpNioFutureCommandConnectionHandle handle) { - try { - handle.release(); - } catch (InterruptedException e) { - logger.error(e, "Interrupted releasing handle %1$s", handle); - } - } + protected void releaseConnectionToPool(HttpNioFutureCommandConnectionHandle handle) { + try { + handle.release(); + } catch (InterruptedException e) { + logger.error(e, "Interrupted releasing handle %1$s", handle); + } + } - protected void processResponse(org.jclouds.http.HttpResponse response, - HttpFutureCommand command) throws IOException { - command.getResponseFuture().setResponse(response); - logger.trace("submitting response task %1$s", command - .getResponseFuture()); - executor.submit(command.getResponseFuture()); - } + protected void processResponse(org.jclouds.http.HttpResponse response, + HttpFutureCommand command) throws IOException { + command.getResponseFuture().setResponse(response); + logger.trace("submitting response task %1$s", command.getResponseFuture()); + executor.submit(command.getResponseFuture()); + } - public void finalizeContext(HttpContext context) { - HttpNioFutureCommandConnectionHandle handle = (HttpNioFutureCommandConnectionHandle) context - .removeAttribute("command-handle"); - if (handle != null) { - try { - handle.cancel(); - } catch (Exception e) { - logger.error(e, "Error cancelling handle %1$s", handle); - } - } - } + public void finalizeContext(HttpContext context) { + HttpNioFutureCommandConnectionHandle handle = (HttpNioFutureCommandConnectionHandle) context + .removeAttribute("command-handle"); + if (handle != null) { + try { + handle.cancel(); + } catch (Exception e) { + logger.error(e, "Error cancelling handle %1$s", handle); + } + } + } } \ No newline at end of file