You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicemix.apache.org by gn...@apache.org on 2008/08/25 16:00:35 UTC

svn commit: r688728 - in /servicemix/components/bindings/servicemix-http/trunk: ./ src/main/java/org/apache/servicemix/http/ src/main/java/org/apache/servicemix/http/endpoints/ src/test/java/org/apache/servicemix/http/

Author: gnodet
Date: Mon Aug 25 07:00:35 2008
New Revision: 688728

URL: http://svn.apache.org/viewvc?rev=688728&view=rev
Log:
SM-1522: The http provider endpoint does not support SSL and proxies

Modified:
    servicemix/components/bindings/servicemix-http/trunk/pom.xml
    servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/HttpComponent.java
    servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/HttpConfiguration.java
    servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/HttpEndpoint.java
    servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/endpoints/HttpProviderEndpoint.java
    servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/endpoints/HttpSoapProviderEndpoint.java
    servicemix/components/bindings/servicemix-http/trunk/src/test/java/org/apache/servicemix/http/ProviderEndpointTest.java

Modified: servicemix/components/bindings/servicemix-http/trunk/pom.xml
URL: http://svn.apache.org/viewvc/servicemix/components/bindings/servicemix-http/trunk/pom.xml?rev=688728&r1=688727&r2=688728&view=diff
==============================================================================
--- servicemix/components/bindings/servicemix-http/trunk/pom.xml (original)
+++ servicemix/components/bindings/servicemix-http/trunk/pom.xml Mon Aug 25 07:00:35 2008
@@ -42,7 +42,7 @@
     <previous.releases>3.1.2,3.2,3.2.1</previous.releases>
     <servicemix-version>3.2.1</servicemix-version>
     <servicemix-shared-version>4.0-SNAPSHOT</servicemix-shared-version>
-    <jetty-version>6.1.11</jetty-version>
+    <jetty-version>6.1.12rc1</jetty-version>
     <activemq-version>5.1.0</activemq-version>
 
     <servicemix.osgi.import>

Modified: servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/HttpComponent.java
URL: http://svn.apache.org/viewvc/servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/HttpComponent.java?rev=688728&r1=688727&r2=688728&view=diff
==============================================================================
--- servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/HttpComponent.java (original)
+++ servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/HttpComponent.java Mon Aug 25 07:00:35 2008
@@ -40,7 +40,7 @@
 import org.apache.servicemix.http.endpoints.HttpProviderEndpoint;
 import org.apache.servicemix.http.jetty.JCLLogger;
 import org.apache.servicemix.http.jetty.JettyContextManager;
-import org.mortbay.thread.BoundedThreadPool;
+import org.mortbay.thread.QueuedThreadPool;
 
 /**
  * an HTTP JBI component
@@ -171,10 +171,10 @@
         return connectionPool;
     }
 
-    public org.mortbay.jetty.client.HttpClient getNewJettyClient(HttpComponent comp) throws Exception {
+    public org.mortbay.jetty.client.HttpClient createNewJettyClient() throws Exception {
         org.mortbay.jetty.client.HttpClient tempClient = new org.mortbay.jetty.client.HttpClient();
-        BoundedThreadPool btp = new BoundedThreadPool();
-        btp.setMaxThreads(comp.getConfiguration().getJettyClientThreadPoolSize());
+        QueuedThreadPool btp = new QueuedThreadPool();
+        btp.setMaxThreads(getConfiguration().getJettyClientThreadPoolSize());
         tempClient.setThreadPool(btp);
         tempClient.setConnectorType(org.mortbay.jetty.client.HttpClient.CONNECTOR_SELECT_CHANNEL);
         tempClient.start();
@@ -259,7 +259,7 @@
         }
         // Create connectionPool
         if (connectionPool == null) {
-            connectionPool = getNewJettyClient(this);
+            connectionPool = createNewJettyClient();
         }
         // Create serverManager
         if (configuration.isManaged()) {

Modified: servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/HttpConfiguration.java
URL: http://svn.apache.org/viewvc/servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/HttpConfiguration.java?rev=688728&r1=688727&r2=688728&view=diff
==============================================================================
--- servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/HttpConfiguration.java (original)
+++ servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/HttpConfiguration.java Mon Aug 25 07:00:35 2008
@@ -74,7 +74,6 @@
      * HttpProviderEndpoints to jetty client per HttpProviderEndpoint. It's
      * default value is false.
      */
-
     private boolean jettyClientPerProvider;
 
     /**

Modified: servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/HttpEndpoint.java
URL: http://svn.apache.org/viewvc/servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/HttpEndpoint.java?rev=688728&r1=688727&r2=688728&view=diff
==============================================================================
--- servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/HttpEndpoint.java (original)
+++ servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/HttpEndpoint.java Mon Aug 25 07:00:35 2008
@@ -75,13 +75,12 @@
      * Specifies if the HTTP provider processor copies the HTTP headers from the HTTP response into the JBI exchange. If the headers
      * will be used for a new HTTP reuquest, setting this to <code>true</code> leads to an error.
      * 
-     * @param wantHeadersFromHttpIntoExchange <code>true</code> if the HTTP headers will be copied into the exchange
+     * @param wantContentTypeHeaderFromExchangeIntoHttpRequest <code>true</code> if the HTTP headers will be copied into the exchange
      * @org.apache.xbean.Property description="Specifies if the HTTP provider will copy the HTTP request headers into the JBI
      *                            exchange. The default is <code>false</code>. This value overrides the value set for the component
      *                            using the <code>configuration</code> element."
      */
-    public void setWantContentTypeHeaderFromExchangeIntoHttpRequest(
-                                                                    boolean wantContentTypeHeaderFromExchangeIntoHttpRequest) {
+    public void setWantContentTypeHeaderFromExchangeIntoHttpRequest(boolean wantContentTypeHeaderFromExchangeIntoHttpRequest) {
         this.wantContentTypeHeaderFromExchangeIntoHttpRequest = wantContentTypeHeaderFromExchangeIntoHttpRequest;
     }
 
@@ -170,7 +169,7 @@
     /**
      * Sets the URI to which an endpoint sends requests.
      * 
-     * @param locationURI a string representing the URI
+     * @param locationUri a string representing the URI
      * @org.apache.xbean.Property description="the URI to which a provider endpoint sends requests"
      */
     public void setLocationURI(String locationUri) {

Modified: servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/endpoints/HttpProviderEndpoint.java
URL: http://svn.apache.org/viewvc/servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/endpoints/HttpProviderEndpoint.java?rev=688728&r1=688727&r2=688728&view=diff
==============================================================================
--- servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/endpoints/HttpProviderEndpoint.java (original)
+++ servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/endpoints/HttpProviderEndpoint.java Mon Aug 25 07:00:35 2008
@@ -17,6 +17,11 @@
 package org.apache.servicemix.http.endpoints;
 
 import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.SecureRandom;
 
 import javax.jbi.messaging.ExchangeStatus;
 import javax.jbi.messaging.MessageExchange;
@@ -24,18 +29,29 @@
 import javax.jbi.servicedesc.ServiceEndpoint;
 import javax.jbi.management.DeploymentException;
 import javax.xml.namespace.QName;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
 
 import org.apache.servicemix.common.JbiConstants;
 import org.apache.servicemix.common.DefaultComponent;
 import org.apache.servicemix.common.ServiceUnit;
+import org.apache.servicemix.common.security.KeystoreManager;
 import org.apache.servicemix.common.endpoints.ProviderEndpoint;
 import org.apache.servicemix.http.HttpComponent;
 import org.apache.servicemix.http.HttpEndpointType;
+import org.apache.servicemix.http.HttpConfiguration;
+import org.apache.servicemix.http.SslParameters;
 import org.apache.servicemix.http.jetty.SmxHttpExchange;
 import org.mortbay.jetty.client.HttpClient;
+import org.mortbay.jetty.client.security.ProxyAuthorization;
+import org.mortbay.thread.QueuedThreadPool;
+import org.mortbay.resource.Resource;
 
 /**
- * a plain HTTP provider. This type of endpoint can be used to send non-SOAP requests to HTTP endpoints.
+ * A plain HTTP provider. This type of endpoint can be used to send non-SOAP requests to HTTP endpoints.
  * 
  * @author gnodet
  * @since 3.2
@@ -43,12 +59,19 @@
  */
 public class HttpProviderEndpoint extends ProviderEndpoint implements HttpEndpointType {
 
-    // private SslParameters ssl;
     // private BasicAuthCredentials basicAuthentication;
     private HttpProviderMarshaler marshaler;
     private String locationURI;
     private int clientSoTimeout = 60000;
     private HttpClient jettyClient;
+    private boolean ownClient = false;
+
+    private String proxyHost;
+    private int proxyPort = 80;
+    private String proxyUsername;
+    private String proxyPassword;
+
+    private SslParameters ssl;
 
     public HttpProviderEndpoint() {
         super();
@@ -92,13 +115,83 @@
      * Sets the class used to marshal messages.
      * 
      * @param marshaler the marshaler to set
-     * @org.apache.xbean.Property description="the bean used to marshal HTTP messages. The deafult is a
+     * @org.apache.xbean.Property description="the bean used to marshal HTTP messages. The default is a
      *                            <code>DefaultHttpProviderMarshaler</code>."
      */
     public void setMarshaler(HttpProviderMarshaler marshaler) {
         this.marshaler = marshaler;
     }
 
+    public String getProxyHost() {
+        return proxyHost;
+    }
+
+    /**
+     * Sets the host name of the HTTP proxy used
+     *
+     * @param proxyHost the host name of the HTTP proxy
+     * @org.apache.xbean.Property description="the host name of the HTTP proxy"
+     */
+    public void setProxyHost(String proxyHost) {
+        this.proxyHost = proxyHost;
+    }
+
+    public int getProxyPort() {
+        return proxyPort;
+    }
+
+    /**
+     * Sets the host port of the HTTP proxy used (defaults to 80)
+     *
+     * @param proxyPort the host name of the HTTP proxy
+     * @org.apache.xbean.Property description="the host port of the HTTP proxy (defaults to 80)"
+     */
+    public void setProxyPort(int proxyPort) {
+        this.proxyPort = proxyPort;
+    }
+
+    public String getProxyUsername() {
+        return proxyUsername;
+    }
+
+    /**
+     * Sets the user name for the HTTP proxy authentication
+     *
+     * @param proxyUsername the user name for the HTTP proxy authentication
+     * @org.apache.xbean.Property description="the user name for the HTTP proxy authentication"
+     */
+    public void setProxyUsername(String proxyUsername) {
+        this.proxyUsername = proxyUsername;
+    }
+
+    public String getProxyPassword() {
+        return proxyPassword;
+    }
+
+    /**
+     * Sets the password for the HTTP proxy authentication
+     *
+     * @param proxyPassword the password for the HTTP proxy authentication
+     * @org.apache.xbean.Property description="the password for the HTTP proxy authentication"
+     */
+    public void setProxyPassword(String proxyPassword) {
+        this.proxyPassword = proxyPassword;
+    }
+
+    public SslParameters getSsl() {
+        return ssl;
+    }
+
+    /**
+     * Sets the SSL parameters
+     *
+     * @param ssl the SSL parameters
+     * @org.apache.xbean.Property description="the SSL parameters"
+     */
+    public void setSsl(SslParameters ssl) {
+        this.ssl = ssl;
+    }
+
     public void process(MessageExchange exchange) throws Exception {
         if (exchange.getStatus() == ExchangeStatus.ACTIVE) {
             NormalizedMessage nm = exchange.getMessage("in");
@@ -111,6 +204,15 @@
         }
     }
 
+
+    public void stop() throws Exception {
+        if (ownClient && jettyClient != null) {
+            jettyClient.stop();
+            jettyClient = null;
+        }
+        super.stop();
+    }
+
     protected void handle(SmxHttpExchange httpExchange, MessageExchange exchange) throws IOException {
         try {
             marshaler.handleResponse(exchange, httpExchange);
@@ -126,7 +228,7 @@
                 send(exchange);
             }
         } catch (Exception e) {
-            throw (IOException)new IOException(e.getMessage()).initCause(e);
+            throw (IOException) new IOException(e.getMessage()).initCause(e);
         }
     }
 
@@ -134,7 +236,7 @@
         try {
             Exception e;
             if (throwable instanceof Exception) {
-                e = (Exception)throwable;
+                e = (Exception) throwable;
             } else {
                 e = new Exception(throwable);
             }
@@ -147,38 +249,33 @@
 
     protected org.mortbay.jetty.client.HttpClient getConnectionPool() throws Exception {
         if (jettyClient == null) {
-            HttpComponent comp = (HttpComponent)getServiceUnit().getComponent();
-            if (comp.getConfiguration().isJettyClientPerProvider()) {
-                jettyClient = comp.getNewJettyClient(comp);
+            HttpComponent comp = (HttpComponent) getServiceUnit().getComponent();
+            if (comp.getConfiguration().isJettyClientPerProvider() || proxyHost != null || ssl != null) {
+                ownClient = true;
+                jettyClient = new SSLManagedHttpClient();
+                jettyClient.setThreadPool(new QueuedThreadPool(getConfiguration().getJettyClientThreadPoolSize()));
+                jettyClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
+                if (proxyHost != null) {
+                    jettyClient.setProxy(new InetSocketAddress(proxyHost, proxyPort));
+                    if (proxyUsername != null) {
+                        jettyClient.setProxyAuthentication(new ProxyAuthorization(proxyUsername, proxyPassword));
+                    }
+                }
+                jettyClient.setSoTimeout(getClientSoTimeout());
+                jettyClient.start();
             } else {
+                ownClient = false;
                 // return shared client
                 jettyClient = comp.getConnectionPool();
             }
+        }
+        if (!ownClient) {
+            // Always reset the SO timeout, in case the client is shared
             jettyClient.setSoTimeout(getClientSoTimeout());
         }
         return jettyClient;
     }
 
-    protected class Exchange extends SmxHttpExchange {
-        MessageExchange jbiExchange;
-
-        public Exchange(MessageExchange jbiExchange) {
-            this.jbiExchange = jbiExchange;
-        }
-
-        protected void onResponseComplete() throws IOException {
-            handle(this, jbiExchange);
-        }
-
-        protected void onConnectionFailed(Throwable throwable) {
-            handleConnectionFailed(throwable, jbiExchange);
-        }
-
-        protected void onException(Throwable throwable) {
-            throw new RuntimeException(throwable);
-        }
-    }
-
     public int getClientSoTimeout() {
         return clientSoTimeout;
     }
@@ -204,4 +301,84 @@
         }
     }
 
+    private HttpConfiguration getConfiguration() {
+        return ((HttpComponent) getServiceUnit().getComponent()).getConfiguration();
+    }
+
+    protected class Exchange extends SmxHttpExchange {
+        MessageExchange jbiExchange;
+
+        public Exchange(MessageExchange jbiExchange) {
+            this.jbiExchange = jbiExchange;
+        }
+
+        protected void onResponseComplete() throws IOException {
+            handle(this, jbiExchange);
+        }
+
+        protected void onConnectionFailed(Throwable throwable) {
+            handleConnectionFailed(throwable, jbiExchange);
+        }
+
+        protected void onException(Throwable throwable) {
+            throw new RuntimeException(throwable);
+        }
+    }
+
+    protected class SSLManagedHttpClient extends HttpClient {
+
+        protected SSLContext getSSLContext() throws IOException {
+            if (ssl.getKeyStore() != null) {
+                return getStrictSSLContext();
+            } else {
+                return getLooseSSLContext();
+            }
+        }
+
+        protected SSLContext getStrictSSLContext() throws IOException {
+            try {
+                if (ssl.isManaged()) {
+                    KeystoreManager keystoreMgr = KeystoreManager.Proxy.create(getConfiguration().getKeystoreManager());
+                    return keystoreMgr.createSSLContext(ssl.getProvider(), ssl.getProtocol(),
+                                                        ssl.getKeyManagerFactoryAlgorithm(), ssl.getKeyStore(),
+                                                        ssl.getKeyAlias(), ssl.getTrustStore());
+                } else {
+                    if (ssl.getTrustStore() == null) {
+                        ssl.setTrustStore(ssl.getKeyStore());
+                        ssl.setTrustStoreType(ssl.getKeyStoreType());
+                        ssl.setTrustManagerFactoryAlgorithm(ssl.getKeyManagerFactoryAlgorithm());
+                    }
+
+                    KeyManager[] keyManagers;
+                    TrustManager[] trustManagers;
+
+                    InputStream keystoreInputStream = Resource.newResource(ssl.getKeyStore()).getInputStream();
+                    KeyStore keyStore = KeyStore.getInstance(ssl.getKeyStoreType());
+                    keyStore.load(keystoreInputStream, ssl.getKeyStorePassword() == null ? null : ssl.getKeyStorePassword().toString().toCharArray());
+
+                    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(ssl.getKeyManagerFactoryAlgorithm());
+                    keyManagerFactory.init(keyStore, ssl.getKeyPassword() == null ? null : ssl.getKeyPassword().toString().toCharArray());
+                    keyManagers = keyManagerFactory.getKeyManagers();
+
+                    InputStream truststoreInputStream = Resource.newResource(ssl.getTrustStore()).getInputStream();
+                    KeyStore trustStore = KeyStore.getInstance(ssl.getTrustStoreType());
+                    trustStore.load(truststoreInputStream, ssl.getTrustStorePassword() == null ? null : ssl.getTrustStorePassword().toString().toCharArray());
+
+                    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(ssl.getTrustManagerFactoryAlgorithm());
+                    trustManagerFactory.init(trustStore);
+                    trustManagers = trustManagerFactory.getTrustManagers();
+
+                    SSLContext context = ssl.getProvider() == null
+                                                    ? SSLContext.getInstance(ssl.getProtocol())
+                                                    : SSLContext.getInstance(ssl.getProtocol(), ssl.getProvider());
+                    context.init(keyManagers, trustManagers, new SecureRandom());
+                    return context;
+                }
+            } catch (GeneralSecurityException e) {
+                throw (IOException) new IOException("Unable to create SSL context").initCause(e);
+            }
+        }
+
+    }
+
 }

Modified: servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/endpoints/HttpSoapProviderEndpoint.java
URL: http://svn.apache.org/viewvc/servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/endpoints/HttpSoapProviderEndpoint.java?rev=688728&r1=688727&r2=688728&view=diff
==============================================================================
--- servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/endpoints/HttpSoapProviderEndpoint.java (original)
+++ servicemix/components/bindings/servicemix-http/trunk/src/main/java/org/apache/servicemix/http/endpoints/HttpSoapProviderEndpoint.java Mon Aug 25 07:00:35 2008
@@ -46,7 +46,7 @@
 import org.xml.sax.InputSource;
 
 /**
- * an HTTP provider endpoint optimized to work with SOAP messages. This type of endpoint requires the use of WSDL.
+ * An HTTP provider endpoint optimized to work with SOAP messages. This type of endpoint requires the use of WSDL.
  * 
  * @author gnodet
  * @since 3.2

Modified: servicemix/components/bindings/servicemix-http/trunk/src/test/java/org/apache/servicemix/http/ProviderEndpointTest.java
URL: http://svn.apache.org/viewvc/servicemix/components/bindings/servicemix-http/trunk/src/test/java/org/apache/servicemix/http/ProviderEndpointTest.java?rev=688728&r1=688727&r2=688728&view=diff
==============================================================================
--- servicemix/components/bindings/servicemix-http/trunk/src/test/java/org/apache/servicemix/http/ProviderEndpointTest.java (original)
+++ servicemix/components/bindings/servicemix-http/trunk/src/test/java/org/apache/servicemix/http/ProviderEndpointTest.java Mon Aug 25 07:00:35 2008
@@ -19,6 +19,9 @@
 import javax.jbi.messaging.InOut;
 import javax.jbi.messaging.ExchangeStatus;
 import javax.xml.namespace.QName;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.ServletContext;
 
 import junit.framework.TestCase;
 
@@ -32,11 +35,17 @@
 import org.apache.servicemix.jbi.jaxp.SourceTransformer;
 import org.apache.servicemix.jbi.jaxp.StringSource;
 import org.springframework.core.io.ClassPathResource;
+import org.mortbay.proxy.AsyncProxyServlet;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.Handler;
+import org.mortbay.jetty.servlet.ServletHandler;
+import org.mortbay.jetty.nio.SelectChannelConnector;
 
 public class ProviderEndpointTest extends TestCase {
 
     protected JBIContainer container;
     protected SourceTransformer transformer = new SourceTransformer();
+    protected Server proxy;
 
     protected void setUp() throws Exception {
         container = new JBIContainer();
@@ -50,6 +59,9 @@
         if (container != null) {
             container.shutDown();
         }
+        if (proxy != null) {
+            proxy.stop();
+        }
     }
 
     public void testNonSoap() throws Exception {
@@ -258,4 +270,59 @@
         client.sendSync(me);
         assertEquals(ExchangeStatus.ERROR, me.getStatus());
     }
+
+    public void testProxy() throws Exception {
+        EchoComponent echo = new EchoComponent();
+        echo.setService(new QName("http://servicemix.apache.org/samples/wsdl-first", "PersonService"));
+        echo.setEndpoint("service");
+        container.activateComponent(echo, "echo");
+
+        HttpComponent http = new HttpComponent();
+
+        HttpConsumerEndpoint ep0 = new HttpConsumerEndpoint();
+        ep0.setService(new QName("http://servicemix.apache.org/samples/wsdl-first", "PersonService"));
+        ep0.setEndpoint("consumer");
+        ep0.setTargetService(new QName("http://servicemix.apache.org/samples/wsdl-first", "PersonService"));
+        ep0.setTargetEndpoint("service");
+        ep0.setLocationURI("http://localhost:8192/person/");
+
+        HttpProviderEndpoint ep1 = new HttpProviderEndpoint();
+        ep1.setService(new QName("http://servicemix.apache.org/samples/wsdl-first", "PersonService"));
+        ep1.setEndpoint("provider");
+        ep1.setLocationURI("http://localhost:8192/person/");
+        ep1.setProxyHost("localhost");
+        ep1.setProxyPort(8193);
+
+        http.setEndpoints(new HttpEndpointType[] {ep0, ep1 });
+        container.activateComponent(http, "http");
+        container.start();
+
+        proxy = new Server();
+        SelectChannelConnector connector = new SelectChannelConnector();
+        connector.setHost("localhost");
+        connector.setPort(8193);
+        proxy.addConnector(connector);
+        ServletHandler handler = new ServletHandler();
+        handler.addServletWithMapping(AsyncProxyServlet.class, "/");
+        proxy.addHandler(handler);
+        proxy.start();
+
+        ServiceMixClient client = new DefaultServiceMixClient(container);
+        InOut me = client.createInOutExchange();
+        me.setService(new QName("http://servicemix.apache.org/samples/wsdl-first", "PersonService"));
+        me.setOperation(new QName("http://servicemix.apache.org/samples/wsdl-first", "GetPerson"));
+        me.getInMessage().setContent(new StringSource(
+                                "<jbi:message xmlns:jbi=\"http://java.sun.com/xml/ns/jbi/wsdl-11-wrapper\""
+                             +  "             xmlns:msg=\"http://servicemix.apache.org/samples/wsdl-first/types\" "
+                             +  "             name=\"Hello\" "
+                             +  "             type=\"msg:HelloRequest\" "
+                             +  "             version=\"1.0\">"
+                             +  "  <jbi:part>"
+                             +  "    <msg:GetPerson><msg:personId>id</msg:personId></msg:GetPerson>"
+                             +  "  </jbi:part>"
+                             +  "</jbi:message>"));
+        client.sendSync(me);
+
+        System.err.println(new SourceTransformer().contentToString(me.getOutMessage()));
+    }
 }