Hi, all,

JIC: if somebody requires to use XmlRpm from behind a authorization-enabled 
proxy (as I do), the attached file contains class, providing such 
functionality.

The rest should be self-explanatory.

-- 
.....A
Alexei Matiouchkine
Engineer @ Business Link International
+7 (812) 3351508

======================================================================
NOTICE: The information contained in this electronic mail message 
        is confidential and intended only for certain recipients.  
        If you are not an intended recipient, you are hereby notified
        that any disclosure, reproduction, distribution or other 
        use of this communication and any attachments is strictly 
        prohibited.  If you have received this communication in error, 
        please notify the sender by reply transmission and delete the 
        message without copying or disclosing it.
======================================================================
package org.apache.xmlrpc;

/* ************************************************************************ *\
 *                                                                          *
 *  Copyright (c) 2005, Alexei Matiouchkine                                 *
 *  All rights reserved.                                                    *
 *                                                                          *
 *  Redistribution and use in source and binary forms, with or without      *
 *  modification, are permitted provided that the following conditions are  *
 *  met:                                                                    *
 *                                                                          *
 *   O  Redistributions of source code must retain the above copyright      *
 *      notice, this list of conditions and the following disclaimer.       *
 *                                                                          *
 *   O  Redistributions in binary form must reproduce the above             *
 *      copyright notice, this list of conditions and the following         *
 *      disclaimer in the documentation and/or other materials provided     *
 *      with the distribution.                                              *
 *                                                                          *
 *   O  Neither the name of the Chronicle Development Team nor the          *
 *      names of its contributors may be used to endorse or promote         *
 *      products derived from this software without specific prior          *
 *      written permission.                                                 *
 *                                                                          *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS     *
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT       *
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR   *
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR   *
 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,   *
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,     *
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR      *
 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  *
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING    *
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS      *
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.            *
 *                                                                          *
 *  This software is not designed or intended for use in on-line control    *
 *  of aircraft, air traffic, aircraft navigation or aircraft               *
 *  communications; or in the design, construction, operation or            *
 *  maintenance of any nuclear facility. Licensee represents and warrants   *
 *  that it will not use or redistribute the Software for such purposes.    *
 *                                                                          *
\* ************************************************************************ */

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.Thread;
import java.net.Authenticator;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.SocketAddress;
import java.net.URL;
import java.net.URLConnection;
import java.util.EmptyStackException;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Vector;


/**
 * Implementation of Apache's [EMAIL PROTECTED] org.apache.xmlrpc.XmlRpcClient} with
 *      support for authorization required proxies.
 *
 * @author <a href="mailto:[EMAIL PROTECTED]">Alexei Matiouchkine</a>
 * @version $Version: $
 * @since 1.3
 *
 * @see org.apache.xmlrpc.XmlRpcClient#Worker
 *
 */

public class XmlRpcProxyClient extends XmlRpcClient {
    /** proxy authentication holder */
    protected String proxyAuth;
    /** remote authentication holder */
    protected String auth;
    /** proxy host */
    protected String proxyHost;
    /** proxy port */
    protected int proxyPort = 0;
    
    /** 
     * Construct a XML-RPC client with this URL.
     *  
     * @param url the remote RPC server's address
     */
    public XmlRpcProxyClient (URL url) {
        super(url);
    }

    /** 
     * Construct a XML-RPC client for the URL represented by this String.
     *
     * @param url the remote RPC server's address, represented by string
     * @throws MalformedURLException if the string does not represent valid url
     */
    public XmlRpcProxyClient (String url) throws MalformedURLException {
        super(url);
    }
   
    /** 
     * Construct a XML-RPC client for the specified hostname and port.
     *
     * @param hostname the remote RPC host's name, represented by string
     * @param port the remote port where the RPC server listens
     * @throws MalformedURLException if the string does not represent valid url
     */
    public XmlRpcProxyClient (String hostname, int port) throws MalformedURLException {
        super("http://"; + hostname + ':' + port + "/RPC2");
    }
  
    public String getProxyHost() {
      return proxyHost != null ? proxyHost : System.getProperty("http.proxyHost");
    }

    public void setProxyHost(String proxyHost) {
      this.proxyHost = proxyHost;
    }

    public int getProxyPort() {
      return proxyPort != 0 ? proxyPort : Integer.parseInt(System.getProperty("http.proxyPort"));
    }

    public void setProxyPort(int proxyPort) {
      this.proxyPort = proxyPort;
    }
    
    /**
     * Sets Proxy-Authentication for this client.
     * @param proxyUser the name of the user to auth against proxy
     * @param proxyPass the password to auth against proxy
     */
    public void setProxyAuthentication(final String proxyUser, final String proxyPass) {
      this.proxyAuth = ((proxyUser == null || proxyPass == null)  ?
          null : new String(Base64.encode((proxyUser + ':' + proxyPass).getBytes())).trim());

      Authenticator.setDefault(new Authenticator() {
        protected PasswordAuthentication getPasswordAuthentication(){
          return getProxyAuthentication() == null ? null : new PasswordAuthentication(proxyUser, proxyPass.toCharArray());
        }
      });
      
    }
    
    /**
     * Retrieves Proxy-Authentication for this client.
     * @return the base64-encoded authentication information
     */
    public String getProxyAuthentication() {
      return this.proxyAuth;
    }
    
    /**
     * 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(final String user, final String password) {
      setBasicAuthentication ((user == null || password == null)  ?
          null : new String(Base64.encode((user + ':' + password).getBytes())).trim());
    }
    
    /**
     * Retrieves Authentication for this client.
     * @return the base64-encoded authentication information
     */
    public String getBasicAuthentication() {
      return this.auth;
    }
    
    /**
     * Sets Authentication for this client.
     * @param auth the base64-encoded authentication information
     */
    public void setBasicAuthentication(final String auth) {
      this.auth = auth;
    }
    
    /**
     *
     * @param async request for async worker, if <code>true</code>; 
     *        <code>false</code> otherwise
     * @return the worker instance from stack, or newly created instance 
     *        if the stack is empty
     * @throws IOException if there is no more available resources for
     *        worker threads
     */
    synchronized Worker getWorker(boolean async) throws IOException {
        try {
            Worker w = (Worker) pool.pop();
            if (async) {
                asyncWorkers += 1;
            } else {
                workers += 1;
            }
            return w;
        } catch(EmptyStackException x) {
            if (workers < XmlRpc.getMaxThreads()) {
                if (async) {
                    asyncWorkers += 1;
                } else {
                    workers += 1;
                }
                return new ProxyWorker();
            }
            throw new IOException("XML-RPC System overload");
        }
    }
    
    /**
     * Proxy worker reimplements the [EMAIL PROTECTED] org.apache.xmlrpc.XmlRpcClient#Worker}
     *    connection stuff to append proxy authentication.
     */
    protected class ProxyWorker extends XmlRpcClient.Worker {
        /** Generic constructor. */
        public ProxyWorker() {
            super();
        }

        /** Execute an XML-RPC call. */
        Object execute(String method, Vector params) throws XmlRpcException, IOException {
            fault = false;
            long now = 0;

            if (XmlRpc.debug) {
                System.out.println("Client calling procedure '" + method
                        + "' with parameters " + params);
                now = System.currentTimeMillis();
            }

            try {
                ByteArrayOutputStream bout = new ByteArrayOutputStream();

                if (buffer == null) {
                    buffer = new ByteArrayOutputStream();
                } else {
                    buffer.reset();
                }

                XmlWriter writer = new XmlWriter(buffer, encoding);
                writeRequest(writer, method, params);
                writer.flush();
                byte[] request = buffer.toByteArray();

                URLConnection con;
                
                if (getProxyHost() != null) {
                  Proxy.Type proxyType = Proxy.Type.HTTP;
                  SocketAddress proxyAddress = new java.net.InetSocketAddress(proxyHost, proxyPort);
                  Proxy proxy = new Proxy(proxyType, proxyAddress);
                  con = url.openConnection(proxy);
                } else {
                  con = url.openConnection();
                }
                
                con.setDoInput(true);
                con.setDoOutput(true);
                con.setUseCaches(false);
                con.setAllowUserInteraction(false);
                con.setRequestProperty("Content-Length", Integer.toString(request.length));
                con.setRequestProperty("Content-Type", "text/xml");
                // This is probably superfluous, but not dangerous
                if (getProxyHost() != null && proxyAuth != null) { 
                  con.setRequestProperty("Proxy-Authorization", "Basic " + proxyAuth);
                }
                if (auth != null) {
                    con.setRequestProperty("Authorization", "Basic " + auth);
                }
                OutputStream out = con.getOutputStream();
                out.write(request);
                out.flush();
                out.close();
                InputStream in = con.getInputStream();
                parse(in);
            } catch(Exception x) {
                if (XmlRpc.debug) {
                    x.printStackTrace();
                }
                throw new IOException(x.getMessage());
            }

            if (fault) {
                // generate an XmlRpcException
                XmlRpcException exception = null;
                try {
                    Hashtable f = (Hashtable) result;
                    String faultString =(String) f.get("faultString");
                    int faultCode = Integer.parseInt(
                            f.get("faultCode").toString());
                    exception = new XmlRpcException(faultCode,
                            faultString.trim());
                } catch(Exception x) {
                    throw new XmlRpcException(0, "Invalid fault response");
                }
                throw exception;
            }
            if (XmlRpc.debug) {
                System.out.println("Spent " + (System.currentTimeMillis() - now)
                        + " in request");
            }
            return result;
        }
    } // end of inner class Worker
    
    /** Just for testing */
    public static void main (String args[]) throws Exception {
        // XmlRpc.setDebug (true);
        try {
            String url = args[0];
            String method = args[1];
            Vector v = new Vector ();
            for (int i=2; i<args.length; i++) try {
                v.addElement (new Integer (Integer.parseInt (args[i])));
            } catch (NumberFormatException nfx) {
                v.addElement (args[i]);
            }
            XmlRpcProxyClient client = new XmlRpcProxyClient (url);
            try {
                System.err.println (client.execute (method, v));
            } catch (Exception ex) {
                System.err.println ("Error: " + ex.getMessage());
            }
        } catch (Exception x) {
            System.err.println (x);
            System.err.println ("Usage: java " +
                                XmlRpcProxyClient.class.getName() +
                                " <url> <method> [args]");
            System.err.println ("Arguments are sent as integers or strings.");
        }
    }

}

/**
 * $Log: $
 */

Attachment: pgpgYXkWPoYY4.pgp
Description: PGP signature

Reply via email to