Hi!

I've made some additions/changes to get Commons HttpClient working correctly
with Apache XML-RPC which I think can be helpful for others as well.

1) Updated the CommonsXmlRpcTransport class (which I think should be renamed
CommonsHttpClientXmlRpcTransport)
2) Added a new factory class (CommonsHttpClientXmlRpcTransportFactory). The
factory class can have default values set for url, basic auth, (read) timeout
and connection factory class. Setting these will cause the
CommonsXmlRpcTransport created using createTransport to have these default
setting.

I've have add different versions of constructors for convenice (e.g. URL vs
host
+ port, auth vs username + password). I am not familiar on whether you like
these or not - feel free to remove some of them.

Attached file are:

 - the brand new factory class CommonsHttpClientXmlRpcTransportFactory
 - the updated CommonsXmlRpcTransport (I moved some instance variable
declarations so that they're all together)
 - a diff -u version of CommonsXmlRpcTransport (NOTE: I just realized that I
did
not do the diff against CVS version - it's against the 2.0 version. If this is
a
problem let me know.)

Regards,
Jimisola

BACKGROUND

I could not get the XML-RPC library to work with HttpClient.

My code:

XmlRpcClient xmlRpcClient = new XmlRpcClient(new
URL("http://localhost:8080/RPC2";),
DefaultXmlRpcTransportFactory.createTransportFactory("org.apache.xmlrpc.DefaultXmlRpcTransportFactory",
new Properties()));

causes the following exception to be thrown:

Exception in thread "main" org.apache.xmlrpc.XmlRpcClientException: Transport
Factory constructor not found:
org.apache.xmlrpc.DefaultXmlRpcTransportFactory(java.util.Properties
properties)
at
org.apache.xmlrpc.DefaultXmlRpcTransportFactory.createTransportFactory(DefaultXmlRpcTransportFactory.java:104)
at other._TestXmlRpcTimeoutClient.main(_TestXmlRpcTimeoutClient.java:31)
Caused by: java.lang.NoSuchMethodException:
org.apache.xmlrpc.DefaultXmlRpcTransportFactory.<init>(java.util.Properties)
at java.lang.Class.getConstructor0(Class.java:1937)
at java.lang.Class.getConstructor(Class.java:1027)
at
org.apache.xmlrpc.DefaultXmlRpcTransportFactory.createTransportFactory(DefaultXmlRpcTransportFactory.java:82)
.. 1 more

Reason:

org.apache.xmlrpc.DefaultXmlRpcTransportFactory does not have a constructor
with
signature:

Class [] CONSTRUCTOR_SIGNATURE = new Class [] { Properties.class };

I've followed the code from beginning and as far as I can see the code can't
work with Commons HttpClient due to 1) missing constructor and 2)
CommonsXmlRpcTransport is NOT USED ANYWHERE.


1. XmlRpcClient(URL, XmlRpcTransportFactory)
2. XmlRpcTransPortFactory: SunSSLTransportFactory,
DefaultXmlRpcTransportFactory
3. DefaultXmlRpcTransportFactory: does not refer to CommonsXmlRpcTransport and
seems to be missing proper constuctor (see exception above)
/**
 * 
 */
package org.apache.xmlrpc;

import java.net.MalformedURLException;
import java.net.URL;

import org.apache.commons.httpclient.HttpClient;

public class CommonsHttpClientXmlRpcTransportFactory implements XmlRpcTransportFactory
{
	// default properties for new common http-client http transports
	protected URL url;
	protected String auth;
	protected Integer timeout = null;
	protected Integer connectionTimeout = null; 
	
	public CommonsHttpClientXmlRpcTransportFactory(String hostname, int port) throws MalformedURLException
	{
		this(new URL("http://"; + hostname + ':' + port + "/RPC2"));
	}

	public CommonsHttpClientXmlRpcTransportFactory(String hostname, int port, String username, String password) throws MalformedURLException
	{
		this(new URL("http://"; + hostname + ':' + port + "/RPC2"), username, password);
	}
	
	public CommonsHttpClientXmlRpcTransportFactory(String hostname, int port, String auth) throws MalformedURLException
	{
		this(new URL("http://"; + hostname + ':' + port + "/RPC2"), auth);
	}
	
	public CommonsHttpClientXmlRpcTransportFactory(URL url)
	{
		this(url, null);
	}

	public CommonsHttpClientXmlRpcTransportFactory(URL url, String username, String password)
	{
		this.url = url;
		this.setBasicAuthentication(username, password);
	}
	
	/**
	 *
	 * @param url
	 * @param auth the <username>:<password> formed string used for basic authentication
	 */
	public CommonsHttpClientXmlRpcTransportFactory(URL url, String auth)
	{
		this.url = url;
		this.auth = auth;
	}
	
	public XmlRpcTransport createTransport () throws XmlRpcClientException
	{
		HttpClient client = new HttpClient();

		CommonsXmlRpcTransport transport = new CommonsXmlRpcTransport(this.url, client);
	
		// set basic authentication if auth (username and password) is set
		if (this.auth != null)
		{
			transport.setBasicAuthentication(this.auth);
		}

		// set timeout if set
		if (this.timeout != null)
		{
			transport.setTimeout(this.timeout.intValue());
		}

		// set connection timeout if set
		if (this.connectionTimeout != null)
		{
			transport.setConnectionTimeout(this.connectionTimeout.intValue());
		}
		
		return transport;
	}

	
	/**
	 * Sets Authentication for this client. This will be sent as Basic
	 * Authentication header to the server as described in
	 * <a href="http://www.ietf.org/rfc/rfc2617.txt";>
	 * http://www.ietf.org/rfc/rfc2617.txt</a>.
	 */
	public void setBasicAuthentication(String auth)
	{
		this.auth = auth;
	}
	
	/**
	 * Sets Authentication for this client. This will be sent as Basic
	 * Authentication header to the server as described in
	 * <a href="http://www.ietf.org/rfc/rfc2617.txt";>
	 * http://www.ietf.org/rfc/rfc2617.txt</a>.
	 */
	public void setBasicAuthentication(String username, String password)
	{
		this.auth = username + ":" + password;
	}
	
    /**
     * Sets the socket timeout (<tt>SO_TIMEOUT</tt>) in milliseconds which is the timeout for waiting for data. A timeout value of zero is interpreted as an infinite timeout.
     *
     * @param newTimeoutInMilliSeconds timeout in milliseconds (ms)
     * @see org.apache.commons.httpclient.HttpClient#setTimeout
     */
    public void setTimeout(int newTimeoutInMilliSeconds)
    {
    	this.timeout = new Integer(newTimeoutInMilliSeconds);
    }

    /**
     * Sets the timeout until a connection is etablished. A timeout value of zero means the timeout is not used. The default value is zero.
     *
     * @param newConnectionTimeoutInMilliSeconds timeout in milliseconds (ms)
     * @see org.apache.commons.httpclient.HttpClient#setConnectionTimeout
     */
    public void setConnectionTimeout(int newConnectionTimeoutInMilliSeconds)
    {
    	this.connectionTimeout = new Integer(newConnectionTimeoutInMilliSeconds);
    }
	
	public void setProperty(String propertyName, Object value)
	{
		if (TRANSPORT_AUTH.equals(propertyName))
		{
			auth = (String) value;
		}
		else if (TRANSPORT_URL.equals(propertyName))
		{
			url = (URL) value;
		}
	}
}
/*
 * Copyright 1999,2005 The Apache Software Foundation.
 * 
 * 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.apache.xmlrpc;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.methods.PostMethod;

/**
 * Implementor of the XmlRpcTransport interface using the Apache
 * Commons HttpClient library v2.0 available at
 * http://jakarta.apache.org/commons/httpclient/
 *
 * Note: <b>Currently this transport is not thread safe</b>
 *
 * @author <a href="mailto:[EMAIL PROTECTED]">Ryan Hoegg</a>
 * @version $Id: //depot/lt/iso/jimisola/main/lib/src/modified/xmlrpc-2.0/src/java/org/apache/xmlrpc/CommonsXmlRpcTransport.java#1 $
 * @since 2.0
 */
public class CommonsXmlRpcTransport implements XmlRpcTransport 
{
    protected PostMethod method;

    private URL url;
    private HttpClient client;
    private final Header userAgentHeader = new Header("User-Agent", XmlRpc.version);
    private boolean http11 = false; // defaults to HTTP 1.0
    private boolean gzip = false;
    private boolean rgzip = false;
    private Credentials creds;

    /** Creates a new instance of CommonsXmlRpcTransport */
    public CommonsXmlRpcTransport(URL url, HttpClient client) 
    {
        this.url = url;
        
        if (client == null) 
        {
            HttpClient newClient = new HttpClient();
            this.client = newClient;
        } 
        else 
        {
            this.client = client;
        }
    }
    
    public CommonsXmlRpcTransport(URL url) 
    {
        this(url, null);
    }
    
    public InputStream sendXmlRpc(byte[] request) throws IOException, XmlRpcClientException 
    {
        method = new PostMethod(url.toString());
        method.setHttp11(http11);
        method.setRequestHeader(new Header("Content-Type", "text/xml"));
        
        if (rgzip)
        	method.setRequestHeader(new Header("Content-Encoding", "gzip"));
        
        if (gzip)
        	method.setRequestHeader(new Header("Accept-Encoding", "gzip"));
                
        method.setRequestHeader(userAgentHeader);

        if (rgzip)
        {
        	ByteArrayOutputStream lBo = new ByteArrayOutputStream();
        	GZIPOutputStream lGzo = new GZIPOutputStream(lBo);
        	lGzo.write(request);
        	lGzo.finish();        	
        	lGzo.close();        	
        	byte[] lArray = lBo.toByteArray();
        	method.setRequestBody(new ByteArrayInputStream(lArray));
        	method.setRequestContentLength(-1);
        }
        else
        	method.setRequestBody(new ByteArrayInputStream(request));
        
        URI hostURI = new URI(url.toString());
        HostConfiguration hostConfig = new HostConfiguration();
        hostConfig.setHost(hostURI);
        client.executeMethod(hostConfig, method);

        boolean lgzipo = false;
        
        Header lHeader = method.getResponseHeader( "Content-Encoding" );
        if ( lHeader != null ) {
            String lValue = lHeader.getValue();
            if ( lValue != null )
        		lgzipo = (lValue.indexOf( "gzip" ) >= 0);
        }

        if (lgzipo)
        	return( new GZIPInputStream( method.getResponseBodyAsStream() ) );
        else
        	return method.getResponseBodyAsStream();
    }
    
    /**
     * Make use of HTTP 1.1 
     * 
     * @param http11 HTTP 1.1 will be used if http11 is true
     */
    public void setHttp11(boolean http11) 
    {
        this.http11 = http11;
    }
    
    /**
     * Transport make use of the 'Accept-Encoding: gzip', so compliant HTTP servers
     * could return HTTP reply compressed with gzip 
     *   
     * @param gzip  Gzip compression will be used if gzip is true
     */
    public void setGzip(boolean gzip) {
        this.gzip = gzip;
    }
    
    /**
     * Transport make use of the 'Content-Encoding: gzip' and send HTTP request
     * compressed with gzip : works only with some compliant HTTP servers like Apache 2.x
     * using SetInputFilter DEFLATE.
     *   
     * @param gzip  Compress request with gzip if gzip is true
     */
    public void setRGzip(boolean gzip) {
        this.rgzip = gzip;
    }
    
    /**
     * Set the UserAgent for this client
     * 
     * @param userAgent
     */
    public void setUserAgent(String userAgent) 
    {
        userAgentHeader.setValue(userAgent);
    }

    /**
     * Sets Authentication for this client, very basic for now user/password
     * 
     * @param user
     * @param password
     */
    public void setBasicAuthentication(String user, String password)
    {
        creds = new UsernamePasswordCredentials(user, password);
        client.getState().setCredentials(null, null, creds);
    }
    
    /**
     * Sets Authentication for this client, very basic for now user/password
     *
     * @param auth the <username>:<password> formed string used for basic authentication
     */
    public void setBasicAuthentication(String auth)
    {
        creds = new UsernamePasswordCredentials(auth);
        client.getState().setCredentials(null, null, creds);
    }

    /**
     * Sets the socket timeout (<tt>SO_TIMEOUT</tt>) in milliseconds which is the timeout for waiting for data. A timeout value of zero is interpreted as an infinite timeout.
     *
     * @param newTimeoutInMilliSeconds timeout in milliseconds (ms)
     * @see org.apache.commons.httpclient.HttpClient#setTimeout
     */
    public void setTimeout(int newTimeoutInMilliSeconds)
    {
    	client.setTimeout(newTimeoutInMilliSeconds);
    }

    /**
     * Sets the timeout until a connection is etablished. A timeout value of zero means the timeout is not used. The default value is zero.
     *
     * @param newConnectionTimeoutInMilliSeconds timeout in milliseconds (ms)
     * @see org.apache.commons.httpclient.HttpClient#setConnectionTimeout
     */
    public void setConnectionTimeout(int newConnectionTimeoutInMilliSeconds)
    {
    	client.setConnectionTimeout(newConnectionTimeoutInMilliSeconds);
    }
        
    /**
     * Releases connection resources.
     *
     * @exception XmlRpcClientException
     */
    public void endClientRequest()
        throws XmlRpcClientException
    {
        method.releaseConnection();
    }
}

Reply via email to