/********************************************************************************* * TotalCross Software Development Kit * * Copyright (C) 2001 Apache Software License * * Copyright (C) 2001-2012 SuperWaba Ltda. * * All Rights Reserved * * * * This library and virtual machine is distributed in the hope that it will * * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * * * This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 * * A copy of this license is located in file license.txt at the root of this * * SDK or can be downloaded here: * * http://www.gnu.org/licenses/lgpl-3.0.txt * * * *********************************************************************************/ package totalcross.xml.rpc; /* * The Apache Software License, Version 1.1 Copyright (c) 2001 The Apache Software Foundation. All rights reserved. * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the * following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. 2. 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. 3. The end-user documentation included with the redistribution, if any, must include the following * acknowledgment: "This product includes software developed by the Apache Software Foundation * (http://www.apache.org/)." Alternately, this acknowledgment may appear in the software itself, if and wherever such * third-party acknowledgments normally appear. 4. The names "XML-RPC" and "Apache Software Foundation" must not be used * to endorse or promote products derived from this software without prior written permission. For written permission, * please contact apache@apache.org. 5. Products derived from this software may not be called "Apache", nor may "Apache" * appear in their name, without prior written permission of the Apache Software Foundation. THIS SOFTWARE IS PROVIDED * ''AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION * OR ITS 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 * consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see <http://www.apache.org/>. */ import totalcross.io.IOException; import totalcross.net.Base64; import totalcross.net.UnknownHostException; import totalcross.sys.Time; import totalcross.ui.html.TagDereferencer; import totalcross.util.*; import totalcross.xml.SyntaxException; import totalcross.xml.XmlReader; /** * Handles XML-RPCs to a server. This object cannot be reused. * * @version March 2006 * @author Added to SuperWaba by Guich (THIS FILE HAS BEEN HEAVILY CHANGED BY GUICH) * @author Maintained by Nimkathana (<a href="http://www.nimkathana.com">www.nimkathana.com</a>) * @author Original by IOP GmbH (<a href="http://www.iop.de">www.iop.de</a>) */ public class XmlRpcClient extends XmlReader { private StandardHttpClient httpClient; protected XmlRpcContentHandler xmlHandler; private XmlWriter writer; /** * @param hostname * The server address to connect to * @param port * The port on the server to connect to * @param uri * The connecting URI. Defaults to "/RPC2" * @throws XmlRpcException * If the connection to the server was unsuccessful */ public XmlRpcClient(String hostname, int port, String uri) throws XmlRpcException, UnknownHostException { this(new StandardHttpClient(hostname, port, uri)); } /** * Creates a xmlrpc client with compression if the given flag is true. */ public XmlRpcClient(String hostname, int port, String uri, boolean doCompression) throws XmlRpcException, UnknownHostException { this(doCompression ? new CompressedHttpClient(hostname, port, uri) : new StandardHttpClient(hostname, port, uri)); } public XmlRpcClient(String hostname, int port, String uri, int openTimeout, int readTimeout, int writeTimeout, boolean doCompression) throws XmlRpcException, UnknownHostException { this(doCompression ? new CompressedHttpClient(hostname, port, uri, openTimeout, readTimeout, writeTimeout) : new StandardHttpClient(hostname, port, uri, openTimeout, readTimeout, writeTimeout)); } public XmlRpcClient(StandardHttpClient httpClient) throws XmlRpcException, UnknownHostException { this.httpClient = httpClient; xmlHandler = new XmlRpcContentHandler(); setContentHandler(xmlHandler); writer = new XmlWriter(); } /** * Generates an XML-RPC request and sends it to the server. Parses the result * and returns the corresponding Java object. * * @param method * The remote procedure to call * @param params * The parameters to the corresponding <code>method</code> * @throws XmlRpcException * If the remote procedure call was unsuccessful * @throws IOException */ public Object execute(String method, Vector params) throws XmlRpcException, IOException { writer.reset(); writeRequest(method, params); byte[] writerBytes = writer.getBytes(); byte[] response = httpClient.executeReturnBytes(writerBytes); // parse the response try { parse(response, 0, response.length); } catch (SyntaxException e) { throw new XmlRpcException(e.getMessage()); } // httpClient keepalive is always false if XmlRpc.keepalive is false if (!httpClient.keepAlive) httpClient.closeConnection(); Object result = xmlHandler.result; if (xmlHandler.faultOccured) { // this is an XML-RPC-level problem, i.e. the server reported an error. // throw a XmlRpcException. Hashtable f = (Hashtable) result; //flsobral@tc123_29: fixed handling of faultString and faultCode Object temp = f.get("faultString"); String faultString = temp instanceof String ? (String) temp : temp.toString(); temp = f.get("faultCode"); String faultCode = temp instanceof String ? (String) temp : temp.toString(); throw new XmlRpcException(faultCode + ": " + faultString.trim()); } return result; } protected int getTagCode(byte[] b, int offset, int count) { int hash = TagDereferencer.hashCode(b, offset, count); try {return XmlRpcValue.tag2code.get(hash);} catch (ElementNotFoundException e) {return -1;} } /* * Generate an XML-RPC request from a method name and a parameter vector. */ private void writeRequest(String method, Vector params) { XmlWriter writer = this.writer; writer.startElement("methodCall"); writer.startElement("methodName"); writer.write(method); writer.endElement("methodName"); writer.startElement("params"); int n = params.size(); for (int i = 0; i < n; i++) { writer.startElement("param"); writeObject(params.items[i]); writer.endElement("param"); } writer.endElement("params"); writer.endElement("methodCall"); } /** * Writes the XML representation of a supported Java object to the XML writer. * * @param what * The object to write */ protected void writeObject(Object what) { XmlWriter writer = this.writer; writer.startElement("value"); if (what == null) { throw new RuntimeException("null value not supported by XML-RPC"); } else if (what instanceof String) { writer.chardata(what.toString()); } else if (what instanceof Properties.Value) // handles: int, double, long, boolean { Properties.Value val = (Properties.Value)what; writer.startElement(val.typeStr); writer.write(what.toString()); writer.endElement(val.typeStr); } else if (what instanceof byte[]) { writer.startElement("base64"); writer.write(Base64.encode((byte[]) what)); writer.endElement("base64"); } else if (what instanceof Vector) { writer.startElement("array"); writer.startElement("data"); Vector v = (Vector) what; int n = v.size(); for (int i = 0; i < n; i++) writeObject(v.items[i]); writer.endElement("data"); writer.endElement("array"); } else if (what instanceof Hashtable) { writer.startElement("struct"); Hashtable h = (Hashtable) what; Vector keys = h.getKeys(); Vector vals = h.getValues(); int n = keys.size(); for (int i = 0; i < n; i++) { Object nextkey = keys.items[i]; Object nextval = vals.items[i]; writer.startElement("member"); writer.startElement("name"); writer.write(nextkey.toString()); writer.endElement("name"); writeObject(nextval); writer.endElement("member"); } writer.endElement("struct"); } else if (what instanceof Time) { writer.startElement("dateTime.iso8601"); Time dateTime = (Time) what; writer.write(dateTime.toIso8601()); writer.endElement("dateTime.iso8601"); } else throw new RuntimeException("unsupported Java type: " + what.getClass()); writer.endElement("value"); } }