package de.timroes.axmlrpc;
import de.timroes.axmlrpc.serializer.SerializerHandler;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import org.apache.http.HttpEntity;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
/**
* The ResponseParser parses the response of an XMLRPC server to an object.
*
* @author Tim Roes
*/
class ResponseParser {
private static final String FAULT_CODE = "faultCode";
private static final String FAULT_STRING = "faultString";
/**
* Deallocate Http Entity and close streams
*/
private static void consumeHttpEntity(InputStream response, HttpEntity entity) {
// Ideally we should use EntityUtils.consume(), introduced in apache http utils 4.1 - not available in
// Android yet
if (entity != null) {
try {
entity.consumeContent();
} catch (IOException e) {
// ignore exception (could happen if Content-Length is wrong)
}
}
if (response != null) {
try {
response.close();
} catch (Exception e) {
// ignore exception
}
}
}
/**
* The given InputStream must contain the xml response from an xmlrpc server.
* This method extract the content of it as an object.
*
* @param response The InputStream of the server response.
* @return The returned object.
* @throws XMLRPCException Will be thrown whenever something fails.
* @throws XMLRPCServerException Will be thrown, if the server returns an error.
*/
public Object parse(InputStream response, HttpEntity entity) throws XMLRPCException {
try {
XmlPullParser pullParser = XmlPullParserFactory.newInstance().newPullParser();
pullParser.setInput(response, "UTF-8");
pullParser.nextTag();
pullParser.require(XmlPullParser.START_TAG, null, XMLRPCClient.METHOD_RESPONSE);
pullParser.nextTag(); // either TAG_PARAMS (<params>) or TAG_FAULT (<fault>)
String tag = pullParser.getName();
if (tag.equals(XMLRPCClient.PARAMS)) {
// normal response
pullParser.nextTag(); // TAG_PARAM (<param>)
pullParser.require(XmlPullParser.START_TAG, null, XMLRPCClient.PARAM);
pullParser.nextTag(); // TAG_VALUE (<value>)
// no parser.require() here since its called in XMLRPCSerializer.deserialize() below
// deserialize result
Object obj = SerializerHandler.getDefault().deserialize(pullParser);
consumeHttpEntity(response, entity);
return obj;
} else if (tag.equals(XMLRPCClient.FAULT)) {
// fault response
pullParser.nextTag(); // TAG_VALUE (<value>)
Map<String, Object> map = (Map<String, Object>) SerializerHandler.getDefault().deserialize(pullParser);
consumeHttpEntity(response, entity);
//Check that required tags are in the response
if (!map.containsKey(FAULT_STRING) || !map.containsKey(FAULT_CODE)) {
throw new XMLRPCException("Bad XMLRPC Fault response received - <faultCode> and/or <faultString> missing!");
}
throw new XMLRPCServerException((String) map.get(FAULT_STRING), (Integer) map.get(FAULT_CODE));
} else {
throw new XMLRPCException("Bad tag <" + tag + "> in XMLRPC response - neither <params> nor <fault>");
}
} catch (XmlPullParserException ex) {
consumeHttpEntity(response, entity);
throw new XMLRPCException("Error parsing response.", ex);
} catch (Exception ex) {
consumeHttpEntity(response, entity);
if(ex instanceof XMLRPCServerException)
throw (XMLRPCServerException)ex;
else
throw new XMLRPCException("Error getting result from server.", ex);
}
}
}