From c526245f6de45f24c78745ef4c33f4e336ea3606 Mon Sep 17 00:00:00 2001 From: rfeng Date: Sun, 30 Sep 2012 15:12:41 +0000 Subject: Enhance the http client configuration to make it customizable git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1392033 13f79535-47bb-0310-9956-ffa450edef68 --- .../binding/jsonrpc/provider/JsonRpcInvoker.java | 73 ++++++++++---------- .../binding/rest/provider/RESTBindingInvoker.java | 37 +++++++--- ....tuscany.sca.host.http.client.HttpClientFactory | 17 +++++ .../trunk/modules/core-spi/META-INF/MANIFEST.MF | 3 +- .../trunk/modules/host-http/META-INF/MANIFEST.MF | 1 + .../sca/host/http/client/HttpClientFactory.java | 80 +++++++++++++++++++--- 6 files changed, 157 insertions(+), 54 deletions(-) create mode 100644 sca-java-2.x/trunk/modules/binding-rest-runtime/src/test/resources/META-INF/services/org.apache.tuscany.sca.host.http.client.HttpClientFactory diff --git a/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JsonRpcInvoker.java b/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JsonRpcInvoker.java index ca21599b14..e4374af233 100644 --- a/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JsonRpcInvoker.java +++ b/sca-java-2.x/trunk/modules/binding-jsonrpc-runtime/src/main/java/org/apache/tuscany/sca/binding/jsonrpc/provider/JsonRpcInvoker.java @@ -122,52 +122,55 @@ public class JsonRpcInvoker implements Invoker, DataExchangeSemantics { response = httpClient.execute(post); - if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { - //success + try { + if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { + //success - entity = response.getEntity(); - String entityResponse = EntityUtils.toString(entity); - entity.consumeContent(); - if (!db.equals(JSONDataBinding.NAME)) { - ObjectNode jsonResponse = (ObjectNode)JacksonHelper.MAPPER.readTree(entityResponse); + entity = response.getEntity(); + String entityResponse = EntityUtils.toString(entity); + // entity.consumeContent(); + if (!db.equals(JSONDataBinding.NAME)) { + ObjectNode jsonResponse = (ObjectNode)JacksonHelper.MAPPER.readTree(entityResponse); - if (jsonResponse.has("error") && jsonResponse.get("error") != NullNode.instance) { - processException(jsonResponse); - } - DataType> outputType = operation.getOutputType(); - DataType returnType = - (outputType != null && !outputType.getLogical().isEmpty()) ? outputType.getLogical().get(0) - : null; - - if (returnType == null) { - msg.setBody(null); - return msg; - } + if (jsonResponse.has("error") && jsonResponse.get("error") != NullNode.instance) { + processException(jsonResponse); + } + DataType> outputType = operation.getOutputType(); + DataType returnType = + (outputType != null && !outputType.getLogical().isEmpty()) ? outputType.getLogical().get(0) + : null; - //check requestId - if (!requestId.equalsIgnoreCase(jsonResponse.get("id").getTextValue())) { - throw new ServiceRuntimeException("Invalid response id:" + requestId); - } + if (returnType == null) { + msg.setBody(null); + return msg; + } - JsonNode rawResult = jsonResponse.get("result"); + //check requestId + if (!requestId.equalsIgnoreCase(jsonResponse.get("id").getTextValue())) { + throw new ServiceRuntimeException("Invalid response id:" + requestId); + } - Class returnClass = returnType.getPhysical(); - Type genericReturnType = returnType.getGenericType(); + JsonNode rawResult = jsonResponse.get("result"); - ObjectMapper mapper = createObjectMapper(returnClass); - String json = mapper.writeValueAsString(rawResult); + Class returnClass = returnType.getPhysical(); + Type genericReturnType = returnType.getGenericType(); - Object body = mapper.readValue(json, TypeFactory.type(genericReturnType)); + ObjectMapper mapper = createObjectMapper(returnClass); + String json = mapper.writeValueAsString(rawResult); + + Object body = mapper.readValue(json, TypeFactory.type(genericReturnType)); + + msg.setBody(body); + } else { + msg.setBody(entityResponse); + } - msg.setBody(body); } else { - msg.setBody(entityResponse); + throw new ServiceRuntimeException("Abnormal HTTP response: " + response.getStatusLine().toString()); } - - } else { + } finally { // Consume the content so the connection can be released - response.getEntity().consumeContent(); - throw new ServiceRuntimeException("Abnormal HTTP response: " + response.getStatusLine().toString()); + EntityUtils.consumeQuietly(response.getEntity()); } } catch (RuntimeException e) { throw e; diff --git a/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingInvoker.java b/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingInvoker.java index 9988b34344..b6c7312edc 100644 --- a/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingInvoker.java +++ b/sca-java-2.x/trunk/modules/binding-rest-runtime/src/main/java/org/apache/tuscany/sca/binding/rest/provider/RESTBindingInvoker.java @@ -19,6 +19,7 @@ package org.apache.tuscany.sca.binding.rest.provider; +import java.io.UnsupportedEncodingException; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.net.URI; @@ -38,7 +39,6 @@ import javax.ws.rs.DELETE; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.HEAD; -import javax.ws.rs.HeaderParam; import javax.ws.rs.HttpMethod; import javax.ws.rs.MatrixParam; import javax.ws.rs.OPTIONS; @@ -55,6 +55,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.UriBuilder; import org.apache.http.client.HttpClient; +import org.apache.http.entity.StringEntity; import org.apache.tuscany.sca.assembly.EndpointReference; import org.apache.tuscany.sca.assembly.WireFormat; import org.apache.tuscany.sca.binding.rest.RESTBinding; @@ -71,6 +72,8 @@ import org.apache.wink.client.ApacheHttpClientConfig; import org.apache.wink.client.ClientConfig; import org.apache.wink.client.Resource; import org.apache.wink.client.RestClient; +import org.apache.wink.client.ClientWebException; +import org.apache.wink.client.ClientResponse; import org.apache.wink.client.handlers.BasicAuthSecurityHandler; /** @@ -85,7 +88,11 @@ public class RESTBindingInvoker implements Invoker { private String httpMethod; private Class responseType; - public RESTBindingInvoker(ExtensionPointRegistry registry, EndpointReference endpointReference, RESTBinding binding, Operation operation, HttpClient httpClient) { + public RESTBindingInvoker(ExtensionPointRegistry registry, + EndpointReference endpointReference, + RESTBinding binding, + Operation operation, + HttpClient httpClient) { super(); this.registry = registry; this.endpointReference = endpointReference; @@ -134,10 +141,10 @@ public class RESTBindingInvoker implements Invoker { } }); - + config.readTimeout(binding.getReadTimeout()); RestClient client = new RestClient(config); - + // Default to GET for RPC httpMethod = HttpMethod.GET; @@ -224,10 +231,10 @@ public class RESTBindingInvoker implements Invoker { cookieParams.put(cookieParam.value(), args[i]); } - if(getAnnotation(annotations, Context.class) != null) { + if (getAnnotation(annotations, Context.class) != null) { isEntity = false; } - + if (isEntity) { entity = args[i]; } @@ -271,8 +278,22 @@ public class RESTBindingInvoker implements Invoker { } } - Object result = resource.invoke(httpMethod, responseType, entity); - msg.setBody(result); + try { + Object result = resource.invoke(httpMethod, responseType, entity); + msg.setBody(result); + } catch (ClientWebException e) { + ClientResponse clientResponse = e.getResponse(); + // Consume the entity + String error = clientResponse.getEntity(String.class); + StringEntity stringEntity; + try { + stringEntity = error == null ? null : new StringEntity(error); + clientResponse.setEntity(stringEntity); + } catch (UnsupportedEncodingException e1) { + // Ignore + } + throw e; + } return msg; } diff --git a/sca-java-2.x/trunk/modules/binding-rest-runtime/src/test/resources/META-INF/services/org.apache.tuscany.sca.host.http.client.HttpClientFactory b/sca-java-2.x/trunk/modules/binding-rest-runtime/src/test/resources/META-INF/services/org.apache.tuscany.sca.host.http.client.HttpClientFactory new file mode 100644 index 0000000000..97202a143b --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-rest-runtime/src/test/resources/META-INF/services/org.apache.tuscany.sca.host.http.client.HttpClientFactory @@ -0,0 +1,17 @@ +# 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. +org.apache.tuscany.sca.host.http.client.HttpClientFactory;soTimeout = 30000,connectionTimeout = 60000,staleCheckingEnabled = false,timeToLive = 30,maxPerRoute = 16,maxTotal = 256,sslHostVerificationEnabled = false diff --git a/sca-java-2.x/trunk/modules/core-spi/META-INF/MANIFEST.MF b/sca-java-2.x/trunk/modules/core-spi/META-INF/MANIFEST.MF index a8e20c2d47..ab8cb51701 100644 --- a/sca-java-2.x/trunk/modules/core-spi/META-INF/MANIFEST.MF +++ b/sca-java-2.x/trunk/modules/core-spi/META-INF/MANIFEST.MF @@ -46,7 +46,8 @@ Import-Package: org.apache.tuscany.sca.assembly;version="2.0.0", org.apache.tuscany.sca.provider;version="2.0.0", org.apache.tuscany.sca.runtime;version="2.0.0", org.apache.tuscany.sca.work;version="2.0.0", - org.oasisopen.sca;version="2.0.0" + org.oasisopen.sca;version="2.0.0", + org.oasisopen.sca.annotation;version="2.0.0" Bundle-SymbolicName: org.apache.tuscany.sca.core.spi Bundle-DocURL: http://www.apache.org/ Bundle-RequiredExecutionEnvironment: J2SE-1.5,JavaSE-1.6 diff --git a/sca-java-2.x/trunk/modules/host-http/META-INF/MANIFEST.MF b/sca-java-2.x/trunk/modules/host-http/META-INF/MANIFEST.MF index 2621509ce4..0e04353e8a 100644 --- a/sca-java-2.x/trunk/modules/host-http/META-INF/MANIFEST.MF +++ b/sca-java-2.x/trunk/modules/host-http/META-INF/MANIFEST.MF @@ -22,6 +22,7 @@ Import-Package: javax.servlet, org.apache.http.conn.params;resolution:=optional, org.apache.http.conn.scheme;resolution:=optional, org.apache.http.conn.ssl;resolution:=optional, + org.apache.http.impl;resolution:=optional, org.apache.http.impl.client;resolution:=optional, org.apache.http.impl.conn;resolution:=optional, org.apache.http.impl.conn.tsccm;resolution:=optional, diff --git a/sca-java-2.x/trunk/modules/host-http/src/main/java/org/apache/tuscany/sca/host/http/client/HttpClientFactory.java b/sca-java-2.x/trunk/modules/host-http/src/main/java/org/apache/tuscany/sca/host/http/client/HttpClientFactory.java index 339d2f433e..53b24a2f11 100644 --- a/sca-java-2.x/trunk/modules/host-http/src/main/java/org/apache/tuscany/sca/host/http/client/HttpClientFactory.java +++ b/sca-java-2.x/trunk/modules/host-http/src/main/java/org/apache/tuscany/sca/host/http/client/HttpClientFactory.java @@ -19,10 +19,17 @@ package org.apache.tuscany.sca.host.http.client; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.apache.http.ConnectionReuseStrategy; +import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; +import org.apache.http.conn.ConnectionKeepAliveStrategy; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLInitializationException; import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.impl.NoConnectionReuseStrategy; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.PoolingClientConnectionManager; import org.apache.http.impl.conn.SchemeRegistryFactory; @@ -30,6 +37,7 @@ import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; +import org.apache.http.protocol.HttpContext; import org.apache.tuscany.sca.core.ExtensionPointRegistry; import org.apache.tuscany.sca.core.LifeCycleListener; import org.apache.tuscany.sca.core.UtilityExtensionPoint; @@ -38,6 +46,13 @@ import org.apache.tuscany.sca.core.UtilityExtensionPoint; * @version $Rev$ $Date$ */ public class HttpClientFactory implements LifeCycleListener { + private int soTimeout = 30000; + private int connectionTimeout = 60000; + private boolean staleCheckingEnabled = false; + private long timeToLive = 60; // seconds + private int maxPerRoute = 256; + private int maxTotal = 1024; + private boolean sslHostVerificationEnabled = false; private HttpClient httpClient; @@ -46,12 +61,50 @@ public class HttpClientFactory implements LifeCycleListener { return utilities.getUtility(HttpClientFactory.class); } + public HttpClientFactory() { + + } + + public HttpClientFactory(ExtensionPointRegistry registry, Map attributes) { + if (attributes != null) { + String val = attributes.get("soTimeout"); + if (val != null) { + this.soTimeout = Integer.parseInt(val); + } + val = attributes.get("connectionTimeout"); + if (val != null) { + this.connectionTimeout = Integer.parseInt(val); + } + val = attributes.get("staleCheckingEnabled"); + if (val != null) { + this.staleCheckingEnabled = Boolean.parseBoolean(val); + } + val = attributes.get("timeToLive"); + if (val != null) { + this.timeToLive = Long.parseLong(val); + } + val = attributes.get("sslHostVerificationEnabled"); + if (val != null) { + this.sslHostVerificationEnabled = Boolean.parseBoolean(val); + } + val = attributes.get("maxTotal"); + if (val != null) { + this.maxTotal = Integer.parseInt(val); + } + val = attributes.get("maxPerRoute"); + if (val != null) { + this.maxPerRoute = Integer.parseInt(val); + } + } + } + public HttpClient createHttpClient() { HttpParams defaultParameters = new BasicHttpParams(); HttpProtocolParams.setContentCharset(defaultParameters, "UTF-8"); - HttpConnectionParams.setConnectionTimeout(defaultParameters, 60000); - HttpConnectionParams.setSoTimeout(defaultParameters, 60000); + HttpConnectionParams.setConnectionTimeout(defaultParameters, connectionTimeout); + HttpConnectionParams.setSoTimeout(defaultParameters, soTimeout); + HttpConnectionParams.setStaleCheckingEnabled(defaultParameters, staleCheckingEnabled); // See https://issues.apache.org/jira/browse/HTTPCLIENT-1138 SchemeRegistry supportedSchemes = null; @@ -62,17 +115,24 @@ public class HttpClientFactory implements LifeCycleListener { supportedSchemes = SchemeRegistryFactory.createDefault(); } - // FIXME: By pass host name verification - SSLSocketFactory socketFactory = (SSLSocketFactory)supportedSchemes.getScheme("https").getSchemeSocketFactory(); - socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + if (!sslHostVerificationEnabled) { + // FIXME: By pass host name verification + SSLSocketFactory socketFactory = + (SSLSocketFactory)supportedSchemes.getScheme("https").getSchemeSocketFactory(); + socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + } PoolingClientConnectionManager connectionManager = - new PoolingClientConnectionManager(supportedSchemes); + new PoolingClientConnectionManager(supportedSchemes, timeToLive, TimeUnit.SECONDS); - connectionManager.setDefaultMaxPerRoute(256); - connectionManager.setMaxTotal(1024); - - return new DefaultHttpClient(connectionManager, defaultParameters); + connectionManager.setDefaultMaxPerRoute(maxPerRoute); + connectionManager.setMaxTotal(maxTotal); + + DefaultHttpClient client = new DefaultHttpClient(connectionManager, defaultParameters); + if (timeToLive <= 0) { + client.setReuseStrategy(new NoConnectionReuseStrategy()); + } + return client; } @Override -- cgit v1.2.3