Issue 199: updated to ning 1.0.0

This commit is contained in:
Adrian Cole 2010-07-06 14:18:32 -07:00
parent c8b3240d04
commit 611297a262
5 changed files with 218 additions and 306 deletions

View File

@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
<!--
Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
Copyright (C) 2010 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
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.
====================================================================
-->
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">
<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>
<artifactId>jclouds-extensions-project</artifactId>
@ -40,10 +40,16 @@
<dependencies>
<dependency>
<groupId>com.ning</groupId>
<artifactId>async-http-client</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<groupId>com.ning</groupId>
<artifactId>async-http-client</artifactId>
<version>1.0.0</version>
<exclusions>
<exclusion> <!-- we use guava -->
<groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>

View File

@ -20,196 +20,177 @@
package org.jclouds.http.ning;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.inject.Singleton;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.HttpHeaders;
import com.google.common.annotations.VisibleForTesting;
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.Payload;
import org.jclouds.http.handlers.DelegatingErrorHandler;
import org.jclouds.http.handlers.DelegatingRetryHandler;
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closeables;
import com.google.common.util.concurrent.AbstractFuture;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.ning.http.client.*;
import java.io.InputStream;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.ning.http.collection.Pair;
import org.jclouds.http.*;
import com.google.inject.Inject;
import org.jclouds.http.handlers.DelegatingErrorHandler;
import org.jclouds.http.handlers.DelegatingRetryHandler;
import org.jclouds.http.payloads.ByteArrayPayload;
import org.jclouds.http.payloads.FilePayload;
import org.jclouds.http.payloads.InputStreamPayload;
import org.jclouds.http.payloads.StringPayload;
import org.jclouds.util.Utils;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.Request;
import com.ning.http.client.Response;
import com.ning.http.client.Request.EntityWriter;
/**
* Todo Write me
*
*
* @author Sam Tunnicliffe
* @author Adrian Cole
*/
public class NingHttpCommandExecutorService implements HttpCommandExecutorService {
public static final String USER_AGENT = "jclouds/1.0 ning http/1.0.0";
public static final String USER_AGENT = "jclouds/1.0 ning http/1.0.0";
private final AsyncHttpClient client;
private final ConvertToNingRequest convertToNingRequest;
private final ConvertToJCloudsResponse convertToJCloudsResponse;
private final DelegatingRetryHandler retryHandler;
private final DelegatingErrorHandler errorHandler;
private final AsyncHttpClient client;
private final ConvertToNingRequest convertToNingRequest;
private final ConvertToJCloudsResponse convertToJCloudsResponse;
private final DelegatingRetryHandler retryHandler;
private final DelegatingErrorHandler errorHandler;
@Inject
public NingHttpCommandExecutorService(AsyncHttpClient client,
ConvertToNingRequest convertToNingRequest,
ConvertToJCloudsResponse convertToJCloudsResponse,
DelegatingRetryHandler retryHandler,
DelegatingErrorHandler errorHandler) {
this.client = client;
this.convertToNingRequest = convertToNingRequest;
this.convertToJCloudsResponse = convertToJCloudsResponse;
this.retryHandler = retryHandler;
this.errorHandler = errorHandler;
}
@Inject
public NingHttpCommandExecutorService(AsyncHttpClient client,
ConvertToNingRequest convertToNingRequest,
ConvertToJCloudsResponse convertToJCloudsResponse, DelegatingRetryHandler retryHandler,
DelegatingErrorHandler errorHandler) {
this.client = client;
this.convertToNingRequest = convertToNingRequest;
this.convertToJCloudsResponse = convertToJCloudsResponse;
this.retryHandler = retryHandler;
this.errorHandler = errorHandler;
}
@Override
public ListenableFuture<HttpResponse> submit(HttpCommand command) {
try {
for(;;) {
Future<Response> responseF = client.executeRequest(convertToNingRequest.apply(command.getRequest()));
final HttpResponse httpResponse = convertToJCloudsResponse.apply(responseF.get());
int statusCode = httpResponse.getStatusCode();
if (statusCode >= 300) {
if (retryHandler.shouldRetryRequest(command, httpResponse)) {
continue;
} else {
errorHandler.handleError(command, httpResponse);
return wrapAsFuture(httpResponse);
}
} else {
return wrapAsFuture(httpResponse);
}
}
} catch(IOException e) {
throw Throwables.propagate(e);
} catch(InterruptedException e) {
throw Throwables.propagate(e);
} catch(ExecutionException e) {
throw Throwables.propagate(e);
}
}
private ListenableFuture<HttpResponse> wrapAsFuture(final HttpResponse httpResponse) {
return Futures.makeListenable(new AbstractFuture<HttpResponse>() {
@Override
public HttpResponse get() throws InterruptedException, ExecutionException {
return httpResponse;
}
});
}
@Singleton
public static class ConvertToNingRequest implements Function<HttpRequest, Request> {
public Request apply(HttpRequest request) {
for (HttpRequestFilter filter : request.getFilters()) {
filter.filter(request);
}
AsyncHttpClient client = new AsyncHttpClient();
AsyncHttpClient.BoundRequestBuilder nativeRequestBuilder;
String endpoint = request.getEndpoint().toASCIIString();
if (request.getMethod().equals(HttpMethod.HEAD)) {
nativeRequestBuilder = client.prepareHead(endpoint);
} else if (request.getMethod().equals(HttpMethod.GET)) {
nativeRequestBuilder = client.prepareGet(endpoint);
} else if (request.getMethod().equals(HttpMethod.DELETE)) {
nativeRequestBuilder = client.prepareDelete(endpoint);
} else if (request.getMethod().equals(HttpMethod.PUT)) {
nativeRequestBuilder = client.preparePut(endpoint);
} else if (request.getMethod().equals(HttpMethod.POST)) {
nativeRequestBuilder = client.preparePost(endpoint);
@Override
public ListenableFuture<HttpResponse> submit(HttpCommand command) {
try {
for (;;) {
Future<Response> responseF = client.executeRequest(convertToNingRequest.apply(command
.getRequest()));
final HttpResponse httpResponse = convertToJCloudsResponse.apply(responseF.get());
int statusCode = httpResponse.getStatusCode();
if (statusCode >= 300) {
if (retryHandler.shouldRetryRequest(command, httpResponse)) {
continue;
} else {
errorHandler.handleError(command, httpResponse);
return wrapAsFuture(httpResponse);
}
} else {
throw new UnsupportedOperationException(request.getMethod());
}
Payload payload = request.getPayload();
if(payload != null) {
//changeRequestContentToBytes(request);
setPayload(nativeRequestBuilder, payload);
} else {
nativeRequestBuilder.addHeader(HttpHeaders.CONTENT_LENGTH, "0");
return wrapAsFuture(httpResponse);
}
}
nativeRequestBuilder.addHeader(HttpHeaders.USER_AGENT, USER_AGENT);
for (String header : request.getHeaders().keySet()) {
for (String value : request.getHeaders().get(header)) {
nativeRequestBuilder.addHeader(header, value);
}
}
} catch (IOException e) {
throw Throwables.propagate(e);
} catch (InterruptedException e) {
throw Throwables.propagate(e);
} catch (ExecutionException e) {
throw Throwables.propagate(e);
}
}
return nativeRequestBuilder.build();
}
private ListenableFuture<HttpResponse> wrapAsFuture(final HttpResponse httpResponse) {
return Futures.makeListenable(new AbstractFuture<HttpResponse>() {
@Override
public HttpResponse get() throws InterruptedException, ExecutionException {
return httpResponse;
}
});
}
@VisibleForTesting
void changeRequestContentToBytes(HttpRequest request) {
Payload content = request.getPayload();
if (content == null || content instanceof ByteArrayPayload) {
//just return
} else if (content instanceof StringPayload) {
String string = ((StringPayload) content).getRawContent();
request.setPayload(string.getBytes());
} else if (content instanceof InputStreamPayload || content instanceof FilePayload) {
InputStream i = content.getContent();
try {
try {
request.setPayload(ByteStreams.toByteArray(i));
} catch (IOException e) {
throw Throwables.propagate(e);
}
} finally {
Closeables.closeQuietly(i);
}
} else {
throw new UnsupportedOperationException("Content not supported " + content.getClass());
}
}
@Singleton
public static class ConvertToNingRequest implements Function<HttpRequest, Request> {
void setPayload(AsyncHttpClient.BoundRequestBuilder requestBuilder, Payload payload) {
try {
requestBuilder.setBody(ByteStreams.toByteArray(payload.getContent()));
} catch(IOException e) {
throw Throwables.propagate(e);
}
}
}
private static class PayloadEntityWriter implements EntityWriter {
private final Payload payload;
@Singleton
public static class ConvertToJCloudsResponse implements Function<Response, HttpResponse> {
public HttpResponse apply(Response nativeResponse) {
HttpResponse response = new HttpResponse();
response.setStatusCode(nativeResponse.getStatusCode());
for (Pair<String, String> header : nativeResponse.getHeaders()) {
response.getHeaders().put(header.getFirst(), header.getSecond());
public PayloadEntityWriter(Payload payload) {
this.payload = payload;
}
@Override
public void writeEntity(OutputStream out) throws IOException {
payload.writeTo(out);
}
}
public Request apply(HttpRequest request) {
for (HttpRequestFilter filter : request.getFilters()) {
filter.filter(request);
}
AsyncHttpClient client = new AsyncHttpClient();
AsyncHttpClient.BoundRequestBuilder nativeRequestBuilder;
String endpoint = request.getEndpoint().toASCIIString();
if (request.getMethod().equals(HttpMethod.HEAD)) {
nativeRequestBuilder = client.prepareHead(endpoint);
} else if (request.getMethod().equals(HttpMethod.GET)) {
nativeRequestBuilder = client.prepareGet(endpoint);
} else if (request.getMethod().equals(HttpMethod.DELETE)) {
nativeRequestBuilder = client.prepareDelete(endpoint);
} else if (request.getMethod().equals(HttpMethod.PUT)) {
nativeRequestBuilder = client.preparePut(endpoint);
} else if (request.getMethod().equals(HttpMethod.POST)) {
nativeRequestBuilder = client.preparePost(endpoint);
} else {
throw new UnsupportedOperationException(request.getMethod());
}
Payload payload = request.getPayload();
if (payload != null) {
setPayload(nativeRequestBuilder, payload);
} else {
nativeRequestBuilder.addHeader(HttpHeaders.CONTENT_LENGTH, "0");
}
nativeRequestBuilder.addHeader(HttpHeaders.USER_AGENT, USER_AGENT);
for (String header : request.getHeaders().keySet()) {
for (String value : request.getHeaders().get(header)) {
nativeRequestBuilder.addHeader(header, value);
}
try {
String responseBody = nativeResponse.getResponseBody();
if(responseBody != null) {
response.setContent(Utils.toInputStream(responseBody));
}
} catch(IOException e) {
throw Throwables.propagate(e);
}
return response;
}
}
}
return nativeRequestBuilder.build();
}
void setPayload(AsyncHttpClient.BoundRequestBuilder requestBuilder, Payload payload) {
requestBuilder.setBody(new PayloadEntityWriter(payload));
}
}
@Singleton
public static class ConvertToJCloudsResponse implements Function<Response, HttpResponse> {
public HttpResponse apply(Response nativeResponse) {
HttpResponse response = new HttpResponse();
response.setStatusCode(nativeResponse.getStatusCode());
for (Entry<String, List<String>> header : nativeResponse.getHeaders()) {
response.getHeaders().putAll(header.getKey(), header.getValue());
}
try {
response.setContent(nativeResponse.getResponseBodyAsStream());
} catch (IOException e) {
throw Throwables.propagate(e);
}
return response;
}
}
}

View File

@ -18,19 +18,19 @@
*/
package org.jclouds.http.ning.config;
import com.google.inject.Provides;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.AsyncHttpClientConfig;
import javax.inject.Singleton;
import org.jclouds.http.HttpCommandExecutorService;
import org.jclouds.http.TransformingHttpCommandExecutorService;
import org.jclouds.http.TransformingHttpCommandExecutorServiceImpl;
import org.jclouds.http.ning.NingHttpCommandExecutorService;
import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
import org.jclouds.http.ning.NingHttpCommandExecutorService;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import javax.inject.Singleton;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.AsyncHttpClientConfig;
/**
* Configures {@link NingHttpCommandExecutorService}.
@ -51,94 +51,10 @@ public class NingHttpCommandExecutorServiceModule extends AbstractModule {
@Singleton
@Provides
AsyncHttpClient provideNingClient() {
AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().
setFollowRedirects(true).
build();
return new AsyncHttpClient(config);
AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setFollowRedirects(true)
.build();
return new AsyncHttpClient(config);
}
//
// @Singleton
// @Provides
// HttpParams newBasicHttpParams(HttpUtils utils) {
// BasicHttpParams params = new BasicHttpParams();
//
// params.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
// .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, true)
// .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true).setParameter(
// CoreProtocolPNames.ORIGIN_SERVER, "jclouds/1.0");
//
// if (utils.getConnectionTimeout() > 0) {
// params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, utils
// .getConnectionTimeout());
// }
//
// if (utils.getSocketOpenTimeout() > 0) {
// params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, utils.getSocketOpenTimeout());
// }
//
// if (utils.getMaxConnections() > 0)
// ConnManagerParams.setMaxTotalConnections(params, utils.getMaxConnections());
//
// if (utils.getMaxConnectionsPerHost() > 0) {
// ConnPerRoute connectionsPerRoute = new ConnPerRouteBean(utils.getMaxConnectionsPerHost());
// ConnManagerParams.setMaxConnectionsPerRoute(params, connectionsPerRoute);
// }
// HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
// return params;
// }
//
// @Singleton
// @Provides
// X509HostnameVerifier newHostnameVerifier(HttpUtils utils) {
// return utils.relaxHostname() ? SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
// : SSLSocketFactory.STRICT_HOSTNAME_VERIFIER;
// }
//
// @Singleton
// @Provides
// ClientConnectionManager newClientConnectionManager(HttpParams params,
// X509HostnameVerifier verifier, Closer closer) throws NoSuchAlgorithmException,
// KeyManagementException {
//
// SchemeRegistry schemeRegistry = new SchemeRegistry();
//
// Scheme http = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);
// SSLContext context = SSLContext.getInstance("TLS");
//
// context.init(null, null, null);
// SSLSocketFactory sf = new SSLSocketFactory(context);
// sf.setHostnameVerifier(verifier);
//
// Scheme https = new Scheme("https", sf, 443);
//
// SchemeRegistry sr = new SchemeRegistry();
// sr.register(http);
// sr.register(https);
//
// schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
// final ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
// closer.addToClose(new Closeable() {
// @Override
// public void close() throws IOException {
// cm.shutdown();
// }
// });
// return cm;
// }
//
// @Provides
// @Singleton
// HttpClient newDefaultHttpClient(HttpUtils utils, BasicHttpParams params,
// ClientConnectionManager cm) {
// DefaultHttpClient client = new DefaultHttpClient(cm, params);
// if (utils.useSystemProxies()) {
// ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner(client
// .getConnectionManager().getSchemeRegistry(), ProxySelector.getDefault());
// client.setRoutePlanner(routePlanner);
// }
// return client;
// }
protected void bindClient() {
bind(HttpCommandExecutorService.class).to(NingHttpCommandExecutorService.class).in(

View File

@ -18,9 +18,11 @@
*/
package org.jclouds.http.ning;
import static org.jclouds.Constants.PROPERTY_CONNECTION_TIMEOUT;
import static org.jclouds.Constants.PROPERTY_IO_WORKER_THREADS;
import static org.jclouds.Constants.*;
import static org.jclouds.Constants.PROPERTY_MAX_CONNECTIONS_PER_CONTEXT;
import static org.jclouds.Constants.PROPERTY_MAX_CONNECTIONS_PER_HOST;
import static org.jclouds.Constants.PROPERTY_SO_TIMEOUT;
import static org.jclouds.Constants.PROPERTY_USER_THREADS;
import static org.testng.Assert.assertEquals;
@ -28,13 +30,9 @@ import java.net.MalformedURLException;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import com.google.common.collect.ImmutableMap;
import org.jclouds.http.BaseHttpCommandExecutorServiceIntegrationTest;
import org.jclouds.http.ning.config.NingHttpCommandExecutorServiceModule;
import org.jclouds.http.options.GetOptions;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@ -42,36 +40,46 @@ import com.google.inject.Module;
/**
* Tests the functionality of the {@link ApacheHCHttpCommandExecutorService}
*
*
* @author Adrian Cole
*/
@Test
public class NingHttpCommandExecutorServiceTest extends BaseHttpCommandExecutorServiceIntegrationTest {
static {
System.setProperty("http.conn-manager.timeout", 1000 + "");
}
public class NingHttpCommandExecutorServiceTest extends
BaseHttpCommandExecutorServiceIntegrationTest {
static {
System.setProperty("http.conn-manager.timeout", 1000 + "");
}
protected Module createConnectionModule() {
return new NingHttpCommandExecutorServiceModule();
}
@DataProvider(name = "gets")
@Override
// ning doesn't support spaces
public Object[][] createData() {
return new Object[][] { { "object" }, { "/path" }, { "unic₪de" }, { "qu?stion" } };
}
protected void addConnectionProperties(Properties props) {
props.setProperty(PROPERTY_MAX_CONNECTIONS_PER_CONTEXT, 20 + "");
props.setProperty(PROPERTY_MAX_CONNECTIONS_PER_HOST, 0 + "");
props.setProperty(PROPERTY_CONNECTION_TIMEOUT, 100 + "");
props.setProperty(PROPERTY_SO_TIMEOUT, 100 + "");
props.setProperty(PROPERTY_IO_WORKER_THREADS, 3 + "");
props.setProperty(PROPERTY_USER_THREADS, 0 + "");
}
protected Module createConnectionModule() {
return new NingHttpCommandExecutorServiceModule();
}
@Test(invocationCount = 1, timeOut = 50000)
public void testSpaceInUri() throws MalformedURLException, ExecutionException,
protected void addConnectionProperties(Properties props) {
props.setProperty(PROPERTY_MAX_CONNECTIONS_PER_CONTEXT, 20 + "");
props.setProperty(PROPERTY_MAX_CONNECTIONS_PER_HOST, 0 + "");
props.setProperty(PROPERTY_CONNECTION_TIMEOUT, 100 + "");
props.setProperty(PROPERTY_SO_TIMEOUT, 100 + "");
props.setProperty(PROPERTY_IO_WORKER_THREADS, 3 + "");
props.setProperty(PROPERTY_USER_THREADS, 0 + "");
}
// ning doesn't support spaces
@Test(invocationCount = 1, expectedExceptions = RuntimeException.class)
public void testSpaceInUri() throws MalformedURLException, ExecutionException,
InterruptedException, TimeoutException {
assertEquals(client.synch("sp ace").trim(), XML);
}
assertEquals(client.synch("sp ace").trim(), XML);
}
@Override
public void testGetBigFile() throws MalformedURLException, ExecutionException, InterruptedException, TimeoutException {
//don't run it
}
@Override
public void testGetBigFile() throws MalformedURLException, ExecutionException,
InterruptedException, TimeoutException {
// don't run it
}
}

View File

@ -34,6 +34,7 @@
<modules>
<module>gae</module>
<module>apachehc</module>
<module>ning</module>
<module>joda</module>
<module>bouncycastle</module>
<module>log4j</module>