mirror of https://github.com/apache/jclouds.git
Issue 323: started work on async client
This commit is contained in:
parent
089c232fd1
commit
360343020a
|
@ -67,6 +67,7 @@ import org.jclouds.encryption.EncryptionService;
|
|||
import org.jclouds.io.Payload;
|
||||
import org.jclouds.io.Payloads;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.logging.internal.Wire;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Predicate;
|
||||
|
@ -548,4 +549,17 @@ public class HttpUtils {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void checkRequestHasContentLengthOrChunkedEncoding(HttpRequest request, String message) {
|
||||
boolean chunked = "chunked".equals(request.getFirstHeaderOrNull("Transfer-Encoding"));
|
||||
checkArgument(request.getPayload() == null || chunked || request.getPayload().getContentLength() != null, message);
|
||||
}
|
||||
|
||||
public static void wirePayloadIfEnabled(Wire wire, HttpRequest request) {
|
||||
if (request.getPayload() != null && wire.enabled()) {
|
||||
wire.output(request);
|
||||
checkRequestHasContentLengthOrChunkedEncoding(request,
|
||||
"After wiring, the request has neither chunked encoding nor content length: " + request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,11 @@
|
|||
*/
|
||||
package org.jclouds.http.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.io.ByteStreams.copy;
|
||||
import static org.jclouds.concurrent.ConcurrentUtils.makeListenable;
|
||||
import static org.jclouds.http.HttpUtils.checkRequestHasContentLengthOrChunkedEncoding;
|
||||
import static org.jclouds.http.HttpUtils.wirePayloadIfEnabled;
|
||||
import static org.jclouds.util.Utils.getFirstThrowableOfType;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -45,7 +47,6 @@ import org.jclouds.http.IOExceptionRetryHandler;
|
|||
import org.jclouds.http.handlers.DelegatingErrorHandler;
|
||||
import org.jclouds.http.handlers.DelegatingRetryHandler;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.io.NullOutputStream;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
@ -73,9 +74,9 @@ public abstract class BaseHttpCommandExecutorService<Q> implements HttpCommandEx
|
|||
|
||||
@Inject
|
||||
protected BaseHttpCommandExecutorService(HttpUtils utils, EncryptionService encryptionService,
|
||||
@Named(Constants.PROPERTY_IO_WORKER_THREADS) ExecutorService ioWorkerExecutor,
|
||||
DelegatingRetryHandler retryHandler, IOExceptionRetryHandler ioRetryHandler,
|
||||
DelegatingErrorHandler errorHandler, HttpWire wire) {
|
||||
@Named(Constants.PROPERTY_IO_WORKER_THREADS) ExecutorService ioWorkerExecutor,
|
||||
DelegatingRetryHandler retryHandler, IOExceptionRetryHandler ioRetryHandler,
|
||||
DelegatingErrorHandler errorHandler, HttpWire wire) {
|
||||
this.utils = utils;
|
||||
this.encryptionService = encryptionService;
|
||||
this.retryHandler = retryHandler;
|
||||
|
@ -125,16 +126,8 @@ public abstract class BaseHttpCommandExecutorService<Q> implements HttpCommandEx
|
|||
public ListenableFuture<HttpResponse> submit(HttpCommand command) {
|
||||
HttpRequest request = command.getRequest();
|
||||
checkRequestHasContentLengthOrChunkedEncoding(request,
|
||||
"if the request has a payload, it must be set to chunked encoding or specify a content length: "
|
||||
+ request);
|
||||
return makeListenable(ioWorkerExecutor.submit(new HttpResponseCallable(command)),
|
||||
ioWorkerExecutor);
|
||||
}
|
||||
|
||||
private void checkRequestHasContentLengthOrChunkedEncoding(HttpRequest request, String message) {
|
||||
boolean chunked = "chunked".equals(request.getFirstHeaderOrNull("Transfer-Encoding"));
|
||||
checkArgument(request.getPayload() == null || chunked
|
||||
|| request.getPayload().getContentLength() != null, message);
|
||||
"if the request has a payload, it must be set to chunked encoding or specify a content length: " + request);
|
||||
return makeListenable(ioWorkerExecutor.submit(new HttpResponseCallable(command)), ioWorkerExecutor);
|
||||
}
|
||||
|
||||
public class HttpResponseCallable implements Callable<HttpResponse> {
|
||||
|
@ -155,16 +148,14 @@ public abstract class BaseHttpCommandExecutorService<Q> implements HttpCommandEx
|
|||
filter.filter(request);
|
||||
}
|
||||
checkRequestHasContentLengthOrChunkedEncoding(request,
|
||||
"After filtering, the request has niether chunked encoding nor content length: "
|
||||
+ request);
|
||||
"After filtering, the request has niether chunked encoding nor content length: " + request);
|
||||
logger.debug("Sending request %s: %s", request.hashCode(), request.getRequestLine());
|
||||
wirePayloadIfEnabled(request);
|
||||
wirePayloadIfEnabled(wire, request);
|
||||
nativeRequest = convert(request);
|
||||
utils.logRequest(headerLog, request, ">>");
|
||||
response = invoke(nativeRequest);
|
||||
|
||||
logger.debug("Receiving response %s: %s", request.hashCode(), response
|
||||
.getStatusLine());
|
||||
logger.debug("Receiving response %s: %s", request.hashCode(), response.getStatusLine());
|
||||
utils.logResponse(headerLog, response, "<<");
|
||||
if (response.getPayload() != null && wire.enabled())
|
||||
wire.input(response);
|
||||
|
@ -178,12 +169,12 @@ public abstract class BaseHttpCommandExecutorService<Q> implements HttpCommandEx
|
|||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
IOException ioe = Utils.getFirstThrowableOfType(e, IOException.class);
|
||||
IOException ioe = getFirstThrowableOfType(e, IOException.class);
|
||||
if (ioe != null && ioRetryHandler.shouldRetryRequest(command, ioe)) {
|
||||
continue;
|
||||
} else {
|
||||
command.setException(new HttpResponseException(e.getMessage() + " connecting to "
|
||||
+ command.getRequest().getRequestLine(), command, null, e));
|
||||
+ command.getRequest().getRequestLine(), command, null, e));
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
|
@ -195,15 +186,6 @@ public abstract class BaseHttpCommandExecutorService<Q> implements HttpCommandEx
|
|||
return response;
|
||||
}
|
||||
|
||||
private void wirePayloadIfEnabled(HttpRequest request) {
|
||||
if (request.getPayload() != null && wire.enabled()) {
|
||||
wire.output(request);
|
||||
checkRequestHasContentLengthOrChunkedEncoding(request,
|
||||
"After wiring, the request has neither chunked encoding nor content length: "
|
||||
+ request);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldContinue(HttpResponse response) {
|
||||
boolean shouldContinue = false;
|
||||
if (retryHandler.shouldRetryRequest(command, response)) {
|
||||
|
|
|
@ -1,91 +1,103 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
<!--
|
||||
|
||||
|
||||
Copyright (C) 2009 Cloud Conscious, LLC.
|
||||
<info@cloudconscious.com>
|
||||
Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
|
||||
====================================================================
|
||||
Licensed 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
|
||||
====================================================================
|
||||
Licensed 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.
|
||||
====================================================================
|
||||
-->
|
||||
http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
applicable law or agreed to in writing, software distributed under the
|
||||
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied. See the License for
|
||||
the specific language governing permissions and limitations under the
|
||||
License.
|
||||
====================================================================
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-extensions-project</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-gae</artifactId>
|
||||
<name>jclouds Google App Engine Components</name>
|
||||
<description>Google App Engine Components</description>
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-extensions-project</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-gae</artifactId>
|
||||
<name>jclouds Google App Engine Components</name>
|
||||
<description>Google App Engine Components</description>
|
||||
|
||||
<scm>
|
||||
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk</connection>
|
||||
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk</developerConnection>
|
||||
<url>http://jclouds.googlecode.com/svn/trunk</url>
|
||||
</scm>
|
||||
<scm>
|
||||
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk</connection>
|
||||
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk</developerConnection>
|
||||
<url>http://jclouds.googlecode.com/svn/trunk</url>
|
||||
</scm>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-joda</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.appengine</groupId>
|
||||
<artifactId>appengine-api</artifactId>
|
||||
<version>1.3.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.appengine</groupId>
|
||||
<artifactId>appengine-api-stubs</artifactId>
|
||||
<version>1.3.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.appengine</groupId>
|
||||
<artifactId>appengine-testing</artifactId>
|
||||
<version>1.3.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.appengine</groupId>
|
||||
<artifactId>appengine-local-runtime</artifactId>
|
||||
<version>1.3.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
<!--
|
||||
<exclusions> <exclusion>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty</artifactId> </exclusion>
|
||||
</exclusions>
|
||||
-->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-servlet_2.5_spec</artifactId>
|
||||
<version>1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-joda</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.appengine</groupId>
|
||||
<artifactId>appengine-api</artifactId>
|
||||
<version>1.3.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.appengine</groupId>
|
||||
<artifactId>appengine-api-stubs</artifactId>
|
||||
<version>1.3.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.appengine</groupId>
|
||||
<artifactId>appengine-testing</artifactId>
|
||||
<version>1.3.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.appengine</groupId>
|
||||
<artifactId>appengine-local-runtime</artifactId>
|
||||
<version>1.3.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
<!--
|
||||
<exclusions> <exclusion> <groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty</artifactId> </exclusion> </exclusions>
|
||||
-->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-servlet_2.5_spec</artifactId>
|
||||
<version>1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<!--
|
||||
gae runs two tests, this should prevent them from executing on the
|
||||
same tcp port
|
||||
-->
|
||||
<threadCount>1</threadCount>
|
||||
<parallel>classes</parallel>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
@ -18,24 +18,46 @@
|
|||
*/
|
||||
package org.jclouds.gae;
|
||||
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
import static com.google.common.util.concurrent.Futures.compose;
|
||||
import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
|
||||
import static org.jclouds.http.HttpUtils.checkRequestHasContentLengthOrChunkedEncoding;
|
||||
import static org.jclouds.http.HttpUtils.wirePayloadIfEnabled;
|
||||
import static org.jclouds.util.Utils.getFirstThrowableOfType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.Constants;
|
||||
import org.jclouds.concurrent.ConcurrentUtils;
|
||||
import org.jclouds.concurrent.SingleThreaded;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpCommandExecutorService;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpRequestFilter;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.http.IOExceptionRetryHandler;
|
||||
import org.jclouds.http.handlers.DelegatingErrorHandler;
|
||||
import org.jclouds.http.handlers.DelegatingRetryHandler;
|
||||
import org.jclouds.http.internal.HttpWire;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.appengine.api.urlfetch.HTTPRequest;
|
||||
import com.google.appengine.api.urlfetch.HTTPResponse;
|
||||
import com.google.appengine.api.urlfetch.URLFetchService;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Google App Engine version of {@link HttpCommandExecutorService} using their fetchAsync call
|
||||
* Google App Engine version of {@link HttpCommandExecutorService} using their
|
||||
* fetchAsync call
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
|
@ -46,22 +68,105 @@ public class AsyncGaeHttpCommandExecutorService implements HttpCommandExecutorSe
|
|||
private final URLFetchService urlFetchService;
|
||||
private final ConvertToGaeRequest convertToGaeRequest;
|
||||
private final ConvertToJcloudsResponse convertToJcloudsResponse;
|
||||
private final DelegatingRetryHandler retryHandler;
|
||||
private final IOExceptionRetryHandler ioRetryHandler;
|
||||
private final DelegatingErrorHandler errorHandler;
|
||||
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
@Resource
|
||||
@Named(Constants.LOGGER_HTTP_HEADERS)
|
||||
protected Logger headerLog = Logger.NULL;
|
||||
protected final HttpWire wire;
|
||||
protected final HttpUtils utils;
|
||||
|
||||
@Inject
|
||||
public AsyncGaeHttpCommandExecutorService(URLFetchService urlFetchService,
|
||||
ConvertToGaeRequest convertToGaeRequest,
|
||||
ConvertToJcloudsResponse convertToJcloudsResponse) {
|
||||
public AsyncGaeHttpCommandExecutorService(URLFetchService urlFetchService, ConvertToGaeRequest convertToGaeRequest,
|
||||
ConvertToJcloudsResponse convertToJcloudsResponse, DelegatingRetryHandler retryHandler,
|
||||
IOExceptionRetryHandler ioRetryHandler, DelegatingErrorHandler errorHandler, HttpUtils utils, HttpWire wire) {
|
||||
this.urlFetchService = urlFetchService;
|
||||
this.convertToGaeRequest = convertToGaeRequest;
|
||||
this.convertToJcloudsResponse = convertToJcloudsResponse;
|
||||
this.retryHandler = retryHandler;
|
||||
this.ioRetryHandler = ioRetryHandler;
|
||||
this.errorHandler = errorHandler;
|
||||
this.utils = utils;
|
||||
this.wire = wire;
|
||||
}
|
||||
|
||||
public HTTPRequest filterLogAndConvertRe(HttpRequest request) {
|
||||
|
||||
for (HttpRequestFilter filter : request.getFilters()) {
|
||||
filter.filter(request);
|
||||
}
|
||||
checkRequestHasContentLengthOrChunkedEncoding(request,
|
||||
"After filtering, the request has niether chunked encoding nor content length: " + request);
|
||||
logger.debug("Sending request %s: %s", request.hashCode(), request.getRequestLine());
|
||||
wirePayloadIfEnabled(wire, request);
|
||||
HTTPRequest nativeRequest = convertToGaeRequest.apply(request);
|
||||
utils.logRequest(headerLog, request, ">>");
|
||||
return nativeRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<HttpResponse> submit(HttpCommand command) {
|
||||
// TODO: this needs to handle retrying and filtering
|
||||
return Futures.compose(ConcurrentUtils.makeListenable(urlFetchService
|
||||
.fetchAsync(convertToGaeRequest.apply(command.getRequest())), sameThreadExecutor()),
|
||||
convertToJcloudsResponse);
|
||||
public ListenableFuture<HttpResponse> submit(final HttpCommand command) {
|
||||
|
||||
HTTPRequest nativeRequest = filterLogAndConvertRe(command.getRequest());
|
||||
|
||||
Future<HTTPResponse> future = urlFetchService.fetchAsync(nativeRequest);
|
||||
Future<HttpResponse> response = compose(future, convertToJcloudsResponse);
|
||||
|
||||
return compose(ConcurrentUtils.makeListenable(response, sameThreadExecutor()),
|
||||
new Function<HttpResponse, HttpResponse>() {
|
||||
|
||||
@Override
|
||||
public HttpResponse apply(HttpResponse response) {
|
||||
try {
|
||||
logger.debug("Receiving response %s: %s", command.getRequest().hashCode(), response
|
||||
.getStatusLine());
|
||||
utils.logResponse(headerLog, response, "<<");
|
||||
if (response.getPayload() != null && wire.enabled())
|
||||
wire.input(response);
|
||||
int statusCode = response.getStatusCode();
|
||||
if (statusCode >= 300) {
|
||||
if (shouldContinue(response))
|
||||
return submit(command).get();
|
||||
else
|
||||
return response;
|
||||
}
|
||||
return response;
|
||||
} catch (Exception e) {
|
||||
IOException ioe = getFirstThrowableOfType(e, IOException.class);
|
||||
if (ioe != null && ioRetryHandler.shouldRetryRequest(command, ioe)) {
|
||||
try {
|
||||
return submit(command).get();
|
||||
} catch (Exception e1) {
|
||||
command.setException(e1);
|
||||
return response;
|
||||
}
|
||||
} else {
|
||||
command.setException(new HttpResponseException(e.getMessage() + " connecting to "
|
||||
+ command.getRequest().getRequestLine(), command, null, e));
|
||||
return response;
|
||||
}
|
||||
} finally {
|
||||
if (command.getException() != null)
|
||||
propagate(command.getException());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldContinue(HttpResponse response) {
|
||||
boolean shouldContinue = false;
|
||||
if (retryHandler.shouldRetryRequest(command, response)) {
|
||||
shouldContinue = true;
|
||||
} else {
|
||||
errorHandler.handleError(command, response);
|
||||
}
|
||||
return shouldContinue;
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.gae.config;
|
||||
|
||||
import org.jclouds.concurrent.SingleThreaded;
|
||||
import org.jclouds.concurrent.config.ConfiguresExecutorService;
|
||||
import org.jclouds.gae.AsyncGaeHttpCommandExecutorService;
|
||||
import org.jclouds.http.HttpCommandExecutorService;
|
||||
import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
|
||||
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* Configures {@link AsyncGaeHttpCommandExecutorService}.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@ConfiguresHttpCommandExecutorService
|
||||
@ConfiguresExecutorService
|
||||
@SingleThreaded
|
||||
public class AsyncGoogleAppEngineConfigurationModule extends GoogleAppEngineConfigurationModule {
|
||||
|
||||
public AsyncGoogleAppEngineConfigurationModule() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected HttpCommandExecutorService providerHttpCommandExecutorService(Injector injector) {
|
||||
return injector.getInstance(AsyncGaeHttpCommandExecutorService.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -20,6 +20,8 @@ package org.jclouds.gae.config;
|
|||
|
||||
import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.concurrent.SingleThreaded;
|
||||
import org.jclouds.concurrent.config.ConfiguresExecutorService;
|
||||
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||
|
@ -32,6 +34,7 @@ import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
|
|||
|
||||
import com.google.appengine.api.urlfetch.URLFetchService;
|
||||
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
|
@ -52,9 +55,13 @@ public class GoogleAppEngineConfigurationModule extends ExecutorServiceModule {
|
|||
protected void configure() {
|
||||
super.configure();
|
||||
install(new JodaDateServiceModule());
|
||||
bind(HttpCommandExecutorService.class).to(GaeHttpCommandExecutorService.class);
|
||||
bind(TransformingHttpCommandExecutorService.class).to(
|
||||
TransformingHttpCommandExecutorServiceImpl.class);
|
||||
bind(TransformingHttpCommandExecutorService.class).to(TransformingHttpCommandExecutorServiceImpl.class);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
protected HttpCommandExecutorService providerHttpCommandExecutorService(Injector injector) {
|
||||
return injector.getInstance(GaeHttpCommandExecutorService.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed 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.gae;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.gae.config.AsyncGoogleAppEngineConfigurationModule;
|
||||
import org.jclouds.http.BaseHttpCommandExecutorServiceIntegrationTest;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
|
||||
import com.google.appengine.tools.development.testing.LocalURLFetchServiceTestConfig;
|
||||
import com.google.inject.Module;
|
||||
|
||||
/**
|
||||
*
|
||||
* Integration test for the URLFetchService
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(threadPoolSize = 10, groups = "integration", sequential = true)
|
||||
public class AsyncGaeHttpCommandExecutorServiceIntegrationTest extends BaseHttpCommandExecutorServiceIntegrationTest {
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testKillRobotSlowly() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testKillRobotSlowly();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testPostAsInputStream() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testPostAsInputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(dependsOnMethods = "testPostAsInputStream")
|
||||
public void testPostResults() {
|
||||
// GAE converts everything to byte arrays and so failures are not gonna
|
||||
// happen
|
||||
assertEquals(postFailures.get(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testPostBinder() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testPostBinder();
|
||||
}
|
||||
|
||||
@BeforeMethod
|
||||
void setupApiProxy() {
|
||||
new LocalServiceTestHelper(new LocalURLFetchServiceTestConfig()).setUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testGetAndParseSax() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetAndParseSax();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testGetString() throws MalformedURLException, ExecutionException, InterruptedException, TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000, dataProvider = "gets")
|
||||
public void testGetStringSynch(String path) throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetStringSynch(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testGetStringRedirect() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetStringRedirect();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testGetException() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetException();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testGetStringPermanentRedirect() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetStringPermanentRedirect();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testGetSynchException() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetSynchException();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testPost() throws MalformedURLException, ExecutionException, InterruptedException, TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testPost();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testPut() throws MalformedURLException, ExecutionException, InterruptedException, TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testPut();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testPutRedirect() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testPutRedirect();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testGetStringWithHeader() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetStringWithHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testHead() throws MalformedURLException, ExecutionException, InterruptedException, TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testHead();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testRequestFilter() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testRequestFilter();
|
||||
}
|
||||
|
||||
protected Module createConnectionModule() {
|
||||
return new AsyncGoogleAppEngineConfigurationModule();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConnectionProperties(Properties props) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(enabled = false)
|
||||
public void testGetBigFile() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
// disabled since test data is too big
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(enabled = false)
|
||||
public void testUploadBigFile() throws IOException {
|
||||
// disabled since test data is too big
|
||||
}
|
||||
|
||||
}
|
|
@ -41,22 +41,21 @@ import com.google.inject.Module;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test
|
||||
public class GaeHttpCommandExecutorServiceIntegrationTest extends
|
||||
BaseHttpCommandExecutorServiceIntegrationTest {
|
||||
@Test(threadPoolSize = 10, groups = "integration", sequential = true)
|
||||
public class GaeHttpCommandExecutorServiceIntegrationTestDisabled extends BaseHttpCommandExecutorServiceIntegrationTest {
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testKillRobotSlowly() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException, TimeoutException {
|
||||
public void testKillRobotSlowly() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testKillRobotSlowly();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testPostAsInputStream() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException, TimeoutException {
|
||||
public void testPostAsInputStream() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testPostAsInputStream();
|
||||
}
|
||||
|
@ -64,14 +63,15 @@ public class GaeHttpCommandExecutorServiceIntegrationTest extends
|
|||
@Override
|
||||
@Test(dependsOnMethods = "testPostAsInputStream")
|
||||
public void testPostResults() {
|
||||
// GAE converts everything to byte arrays and so failures are not gonna happen
|
||||
// GAE converts everything to byte arrays and so failures are not gonna
|
||||
// happen
|
||||
assertEquals(postFailures.get(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testPostBinder() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException, TimeoutException {
|
||||
public void testPostBinder() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testPostBinder();
|
||||
}
|
||||
|
@ -83,108 +83,104 @@ public class GaeHttpCommandExecutorServiceIntegrationTest extends
|
|||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testGetAndParseSax() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException, TimeoutException {
|
||||
public void testGetAndParseSax() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetAndParseSax();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testGetString() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException, TimeoutException {
|
||||
public void testGetString() throws MalformedURLException, ExecutionException, InterruptedException, TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000, dataProvider = "gets")
|
||||
public void testGetStringSynch(String path) throws MalformedURLException, ExecutionException,
|
||||
InterruptedException, TimeoutException {
|
||||
public void testGetStringSynch(String path) throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetStringSynch(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testGetStringRedirect() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException, TimeoutException {
|
||||
public void testGetStringRedirect() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetStringRedirect();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testGetException() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException, TimeoutException {
|
||||
public void testGetException() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetException();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testGetStringPermanentRedirect() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException, TimeoutException {
|
||||
public void testGetStringPermanentRedirect() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetStringPermanentRedirect();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testGetSynchException() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException, TimeoutException {
|
||||
public void testGetSynchException() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetSynchException();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testPost() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
public void testPost() throws MalformedURLException, ExecutionException, InterruptedException, TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testPost();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testPut() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
public void testPut() throws MalformedURLException, ExecutionException, InterruptedException, TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testPut();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testPutRedirect() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException, TimeoutException {
|
||||
public void testPutRedirect() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testPutRedirect();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testGetStringWithHeader() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException, TimeoutException {
|
||||
public void testGetStringWithHeader() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testGetStringWithHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testHead() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
public void testHead() throws MalformedURLException, ExecutionException, InterruptedException, TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testHead();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(invocationCount = 50, timeOut = 3000)
|
||||
public void testRequestFilter() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException, TimeoutException {
|
||||
public void testRequestFilter() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
setupApiProxy();
|
||||
super.testRequestFilter();
|
||||
}
|
||||
|
||||
|
||||
protected Module createConnectionModule() {
|
||||
return new GoogleAppEngineConfigurationModule();
|
||||
}
|
||||
|
@ -195,8 +191,8 @@ public class GaeHttpCommandExecutorServiceIntegrationTest extends
|
|||
|
||||
@Override
|
||||
@Test(enabled = false)
|
||||
public void testGetBigFile() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException, TimeoutException {
|
||||
public void testGetBigFile() throws MalformedURLException, ExecutionException, InterruptedException,
|
||||
TimeoutException {
|
||||
// disabled since test data is too big
|
||||
}
|
||||
|
Loading…
Reference in New Issue