View Javadoc

1   package org.apache.continuum.distributed.commons.utils;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import com.atlassian.xmlrpc.Binder;
23  import com.atlassian.xmlrpc.BinderTypeFactory;
24  import com.atlassian.xmlrpc.BindingException;
25  import com.atlassian.xmlrpc.ConnectionInfo;
26  import com.atlassian.xmlrpc.ServiceObject;
27  import com.atlassian.xmlrpc.XmlRpcClientProvider;
28  import com.atlassian.xmlrpc.XmlRpcInvocationHandler;
29  import org.apache.commons.httpclient.HttpClient;
30  import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
31  import org.apache.xmlrpc.XmlRpcException;
32  import org.apache.xmlrpc.client.XmlRpcClient;
33  import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
34  import org.apache.xmlrpc.client.XmlRpcCommonsTransportFactory;
35  
36  import java.lang.reflect.Proxy;
37  import java.net.URL;
38  import java.util.Vector;
39  
40  /**
41   * Used to bind the given XML-RPC service to an instance of
42   * the given interface type.
43   *
44   * This implementation uses the Apache XML-RPC client.
45   *
46   * This is derived from ApacheBinder from the atlassian-xmlrpc-binder project. In this version, we customise the
47   * transport used for better connection management. It is thread-safe and should be reused.
48   *
49   * @author <a href="mailto:james@atlassian.com">James William Dumay</a>
50   */
51  public class ContinuumXmlRpcBinder
52      implements Binder
53  {
54      private final HttpClient httpClient;
55  
56      private static ContinuumXmlRpcBinder binder = new ContinuumXmlRpcBinder();
57  
58      private ContinuumXmlRpcBinder()
59      {
60          this.httpClient = new HttpClient( new MultiThreadedHttpConnectionManager() );
61      }
62  
63      public <T> T bind( Class<T> bindClass, URL url )
64          throws BindingException
65      {
66          return bind( bindClass, url, new ConnectionInfo() );
67      }
68  
69      public <T> T bind( Class<T> bindClass, URL url, ConnectionInfo connectionInfo )
70          throws BindingException
71      {
72          if ( !bindClass.isInterface() )
73          {
74              throw new BindingException( "Class " + bindClass.getName() + "is not an interface" );
75          }
76          ServiceObject serviceObject = bindClass.getAnnotation( ServiceObject.class );
77          if ( serviceObject == null )
78          {
79              throw new BindingException( "Could not find ServiceObject annotation on " + bindClass.getName() );
80          }
81          final XmlRpcClient client = getXmlRpcClient( url, connectionInfo );
82  
83          XmlRpcInvocationHandler handler = new XmlRpcInvocationHandler( new XmlRpcClientProvider()
84          {
85              public Object execute( String serviceName, String methodName, Vector arguments )
86                  throws BindingException
87              {
88                  try
89                  {
90                      return client.execute( serviceName + "." + methodName, arguments );
91                  }
92                  catch ( XmlRpcException e )
93                  {
94                      throw new BindingException( e );
95                  }
96              }
97          } );
98  
99          return (T) Proxy.newProxyInstance( getClass().getClassLoader(), new Class[]{bindClass}, handler );
100     }
101 
102     private XmlRpcClient getXmlRpcClient( URL url, ConnectionInfo connectionInfo )
103     {
104         XmlRpcClientConfigImpl clientConfig = new XmlRpcClientConfigImpl();
105         clientConfig.setServerURL( url );
106         clientConfig.setEnabledForExceptions( true );
107 
108         if ( connectionInfo != null )
109         {
110             clientConfig.setBasicUserName( connectionInfo.getUsername() );
111             clientConfig.setBasicPassword( connectionInfo.getPassword() );
112             clientConfig.setBasicEncoding( connectionInfo.getEncoding() );
113             clientConfig.setGzipCompressing( connectionInfo.isGzip() );
114             clientConfig.setGzipRequesting( connectionInfo.isGzip() );
115             clientConfig.setReplyTimeout( connectionInfo.getTimeout() );
116             clientConfig.setConnectionTimeout( connectionInfo.getTimeout() );
117             clientConfig.setTimeZone( connectionInfo.getTimeZone() );
118         }
119 
120         final XmlRpcClient client = new XmlRpcClient();
121         client.setTypeFactory( new BinderTypeFactory( client ) );
122         XmlRpcCommonsTransportFactory factory = new XmlRpcCommonsTransportFactory( client );
123         // Alternative - use simple connection manager, but make sure it closes the connection each time
124         // This would be set here since it would not be thread-safe
125 //        factory.setHttpClient( new HttpClient( new SimpleHttpConnectionManager( true ) ) );
126         factory.setHttpClient( httpClient );
127         client.setConfig( clientConfig );
128         return client;
129     }
130 
131     public static ContinuumXmlRpcBinder getInstance()
132     {
133         return binder;
134     }
135 }