package com.sleazyweasel.pandora;/* Pandoroid Radio - open source pandora.com client for android
* Copyright (C) 2011 Andrew Regner <andrew@aregner.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.entity.StringEntity;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlrpc.android.Tag;
import org.xmlrpc.android.XMLRPCException;
import org.xmlrpc.android.XMLRPCFault;
import java.io.BufferedInputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
public class XmlRpc extends org.xmlrpc.android.XMLRPCClient {
private static final Logger logger = Logger.getLogger(XmlRpc.class.getName());
public XmlRpc(String url) {
super(url);
}
/* This method is extracted from the parent class with slight modifications
* for sending a request with a predetermined body content. */
public Object callWithBody(String url, String body) throws XMLRPCException {
// logger.info("url = " + url);
// logger.info("body = " + body);
postMethod.setURI(URI.create(url));
try {
// set POST body
HttpEntity entity = new StringEntity(body);
postMethod.setEntity(entity);
//Log.d(Tag.LOG, "ros HTTP POST");
// execute HTTP POST request
HttpResponse response = client.execute(postMethod);
//Log.d(Tag.LOG, "ros HTTP POSTed");
// check status code
int statusCode = response.getStatusLine().getStatusCode();
//Log.d(Tag.LOG, "ros status code:" + statusCode);
if (statusCode != HttpStatus.SC_OK) {
throw new XMLRPCException("HTTP status code: " + statusCode + " != " + HttpStatus.SC_OK);
}
// parse response stuff
//
// setup pull parser
XmlPullParser pullParser = XmlPullParserFactory.newInstance().newPullParser();
entity = response.getEntity();
Reader reader = new InputStreamReader(new BufferedInputStream(entity.getContent()), "UTF-8");
// for testing purposes only
// reader = new StringReader("<?xml version='1.0'?><methodResponse><params><param><value>\n\n\n</value></param></params></methodResponse>");
pullParser.setInput(reader);
// lets start pulling...
pullParser.nextTag();
pullParser.require(XmlPullParser.START_TAG, null, Tag.METHOD_RESPONSE);
pullParser.nextTag(); // either Tag.PARAMS (<params>) or Tag.FAULT (<fault>)
String tag = pullParser.getName();
if (tag.equals(Tag.PARAMS)) {
// normal response
pullParser.nextTag(); // Tag.PARAM (<param>)
pullParser.require(XmlPullParser.START_TAG, null, Tag.PARAM);
pullParser.nextTag(); // Tag.VALUE (<value>)
// no parser.require() here since its called in XMLRPCSerializer.deserialize() below
// deserialize result
Object obj = iXMLRPCSerializer.deserialize(pullParser);
entity.consumeContent();
return obj;
} else if (tag.equals(Tag.FAULT)) {
// fault response
pullParser.nextTag(); // Tag.VALUE (<value>)
// no parser.require() here since its called in XMLRPCSerializer.deserialize() below
// deserialize fault result
Map<String, Object> map = (Map<String, Object>) iXMLRPCSerializer.deserialize(pullParser);
String faultString = (String) map.get(Tag.FAULT_STRING);
int faultCode = (Integer) map.get(Tag.FAULT_CODE);
entity.consumeContent();
throw new XMLRPCFault(faultString, faultCode);
} else {
entity.consumeContent();
throw new XMLRPCException("Bad tag <" + tag + "> in XMLRPC response - neither <params> nor <fault>");
}
} catch (XMLRPCException e) {
logger.log(Level.WARNING, "Exception caught.", e);;
// catch & propagate XMLRPCException/XMLRPCFault
throw e;
} catch (Exception e) {
logger.log(Level.WARNING, "Exception caught.", e);;
// wrap any other Exception(s) around XMLRPCException
throw new XMLRPCException(e);
}
}
public void addHeader(String header, String value) {
postMethod.addHeader(header, value);
}
public static String value(String v) {
return "<value><string>" + v.replace("&", "&").replace("<", "<").replace(">", ">") + "</string></value>";
}
public static String value(boolean v) {
return v ? "<value><boolean>1</boolean></value>" : "<value><boolean>0</boolean></value>";
}
public static String value(int v) {
return "<value><int>" + String.valueOf(v) + "</int></value>";
}
public static String value(Number v) {
return value(v.intValue());
}
public static String value(String[] list) {
StringBuilder result = new StringBuilder("<value><array><data>");
for (int i = 0; i < list.length; i++) {
result.append(value(list[i]));
}
return result.append("</data></array></value>").toString();
}
public static String value(int[] list) {
StringBuilder result = new StringBuilder("<value><array><data>");
for (int i = 0; i < list.length; i++) {
result.append(value(list[i]));
}
return result.append("</data></array></value>").toString();
}
public static String value(AbstractCollection<?> list) {
StringBuilder result = new StringBuilder("<value><array><data>");
Iterator<?> listIter = list.iterator();
while (listIter.hasNext()) {
result.append(valueGuess(listIter.next()));
}
return result.append("</data></array></value>").toString();
}
public static String valueGuess(Object v) {
if (v instanceof Number)
return value((Number) v);
else if (v instanceof Boolean)
return value((Boolean) v);
else if (v instanceof String)
return value((String) v);
else if (v instanceof AbstractCollection<?>)
return value((AbstractCollection<?>) v);
else
return value(v.toString());
}
public static String makeCall(String method, ArrayList<Object> args) {
StringBuilder argsStr = new StringBuilder();
Iterator<Object> argsIter = args.iterator();
while (argsIter.hasNext()) {
Object item = argsIter.next();
argsStr.append("<param>").append(valueGuess(item)).append("</param>");
}
return "<?xml version=\"1.0\"?><methodCall><methodName>" + method + "</methodName><params>" + argsStr.toString() + "</params></methodCall>";
}
}