Browse Source

Merge pull request #350 from fbarriga/fbarriga/axmlrpc_update

rtorrent: axmlrpc updated
pull/311/merge
Eric Kok 7 years ago committed by GitHub
parent
commit
ad7ac3efc6
  1. 125
      app/src/main/java/de/timroes/axmlrpc/ResponseParser.java
  2. 8
      app/src/main/java/de/timroes/axmlrpc/XMLRPCClient.java
  3. 99
      app/src/main/java/de/timroes/axmlrpc/XMLUtil.java
  4. 38
      app/src/main/java/de/timroes/axmlrpc/serializer/ArraySerializer.java
  5. 6
      app/src/main/java/de/timroes/axmlrpc/serializer/Base64Serializer.java
  6. 7
      app/src/main/java/de/timroes/axmlrpc/serializer/BooleanSerializer.java
  7. 15
      app/src/main/java/de/timroes/axmlrpc/serializer/DateTimeSerializer.java
  8. 6
      app/src/main/java/de/timroes/axmlrpc/serializer/DoubleSerializer.java
  9. 6
      app/src/main/java/de/timroes/axmlrpc/serializer/IntSerializer.java
  10. 6
      app/src/main/java/de/timroes/axmlrpc/serializer/LongSerializer.java
  11. 6
      app/src/main/java/de/timroes/axmlrpc/serializer/NullSerializer.java
  12. 11
      app/src/main/java/de/timroes/axmlrpc/serializer/Serializer.java
  13. 191
      app/src/main/java/de/timroes/axmlrpc/serializer/SerializerHandler.java
  14. 13
      app/src/main/java/de/timroes/axmlrpc/serializer/StringSerializer.java
  15. 63
      app/src/main/java/de/timroes/axmlrpc/serializer/StructSerializer.java

125
app/src/main/java/de/timroes/axmlrpc/ResponseParser.java

@ -1,12 +1,15 @@ @@ -1,12 +1,15 @@
package de.timroes.axmlrpc;
import de.timroes.axmlrpc.serializer.SerializerHandler;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
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.
@ -18,6 +21,30 @@ class ResponseParser { @@ -18,6 +21,30 @@ 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.
@ -27,70 +54,50 @@ class ResponseParser { @@ -27,70 +54,50 @@ class ResponseParser {
* @throws XMLRPCException Will be thrown whenever something fails.
* @throws XMLRPCServerException Will be thrown, if the server returns an error.
*/
public Object parse(InputStream response) throws XMLRPCException {
public Object parse(InputStream response, HttpEntity entity) throws XMLRPCException {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document dom = builder.parse(response);
Element e = dom.getDocumentElement();
// Check for root tag
if(!e.getNodeName().equals(XMLRPCClient.METHOD_RESPONSE)) {
throw new XMLRPCException("MethodResponse root tag is missing.");
}
e = XMLUtil.getOnlyChildElement(e.getChildNodes());
if(e.getNodeName().equals(XMLRPCClient.PARAMS)) {
e = XMLUtil.getOnlyChildElement(e.getChildNodes());
if(!e.getNodeName().equals(XMLRPCClient.PARAM)) {
throw new XMLRPCException("The params tag must contain a param tag.");
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!");
}
return getReturnValueFromElement(e);
} else if(e.getNodeName().equals(XMLRPCClient.FAULT)) {
@SuppressWarnings("unchecked")
Map<String,Object> o = (Map<String,Object>)getReturnValueFromElement(e);
throw new XMLRPCServerException((String)o.get(FAULT_STRING), (Integer)o.get(FAULT_CODE));
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>");
}
throw new XMLRPCException("The methodResponse tag must contain a fault or params tag.");
} 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);
}
}
/**
* This method takes an element (must be a param or fault element) and
* returns the deserialized object of this param tag.
*
* @param element An param element.
* @return The deserialized object within the given param element.
* @throws XMLRPCException Will be thrown when the structure of the document
* doesn't match the XML-RPC specification.
*/
private Object getReturnValueFromElement(Element element) throws XMLRPCException {
element = XMLUtil.getOnlyChildElement(element.getChildNodes());
return SerializerHandler.getDefault().deserialize(element);
}
}

8
app/src/main/java/de/timroes/axmlrpc/XMLRPCClient.java

@ -9,6 +9,7 @@ import java.util.concurrent.ConcurrentHashMap; @@ -9,6 +9,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HTTP;
@ -356,7 +357,7 @@ public class XMLRPCClient { @@ -356,7 +357,7 @@ public class XMLRPCClient {
* Read the README file delivered with the source code of this library for more
* information.
*
* @param method A method name to call.
* @param methodName A method name to call.
* @param params An array of parameters for the method.
* @return The result of the server.
* @throws XMLRPCException Will be thrown if an error occurred during the call.
@ -369,8 +370,9 @@ public class XMLRPCClient { @@ -369,8 +370,9 @@ public class XMLRPCClient {
Call c = createCall(methodName, params);
// Prepare POST request
// FIXME: where creating a new HttpPost so calling #cancel isn't going to do anything
HttpPost post = new HttpPost(url);
post.getParams().setParameter("http.protocol.handle-redirects", false);
post.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, false);
post.setHeader(CONTENT_TYPE, TYPE_XML);
StringEntity entity = new StringEntity(c.getXML(), HTTP.UTF_8);
entity.setContentType(TYPE_XML);
@ -444,7 +446,7 @@ public class XMLRPCClient { @@ -444,7 +446,7 @@ public class XMLRPCClient {
}
}
return responseParser.parse(istream);
return responseParser.parse(istream, entity);
} catch(SocketTimeoutException ex) {
throw new XMLRPCTimeoutException("The XMLRPC call timed out.");

99
app/src/main/java/de/timroes/axmlrpc/XMLUtil.java

@ -1,9 +1,6 @@ @@ -1,9 +1,6 @@
package de.timroes.axmlrpc;
import de.timroes.axmlrpc.xmlcreator.XmlElement;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* This class provides some utility methods for the use with the Java DOM parser.
@ -12,102 +9,6 @@ import org.w3c.dom.NodeList; @@ -12,102 +9,6 @@ import org.w3c.dom.NodeList;
*/
public class XMLUtil {
/**
* Returns the only child element in a given NodeList.
* Will throw an error if there is more then one child element or any other
* child that is not an element or an empty text string (whitespace are normal).
*
* @param list A NodeList of children nodes.
* @return The only child element in the given node list.
* @throws XMLRPCException Will be thrown if there is more then one child element
* except empty text nodes.
*/
public static Element getOnlyChildElement(NodeList list) throws XMLRPCException {
Element e = null;
Node n;
for(int i = 0; i < list.getLength(); i++) {
n = list.item(i);
// Strip only whitespace text elements and comments
if((n.getNodeType() == Node.TEXT_NODE
&& n.getNodeValue().trim().length() <= 0)
|| n.getNodeType() == Node.COMMENT_NODE)
continue;
// Check if there is anything else than an element node.
if(n.getNodeType() != Node.ELEMENT_NODE) {
throw new XMLRPCException("Only element nodes allowed.");
}
// If there was already an element, throw exception.
if(e != null) {
throw new XMLRPCException("Element has more than one children.");
}
e = (Element)n;
}
return e;
}
/**
* Returns the text node from a given NodeList. If the list contains
* more then just text nodes, an exception will be thrown.
*
* @param list The given list of nodes.
* @return The text of the given node list.
* @throws XMLRPCException Will be thrown if there is more than just one
* text node within the list.
*/
public static String getOnlyTextContent(NodeList list) throws XMLRPCException {
StringBuilder builder = new StringBuilder();
Node n;
for(int i = 0; i < list.getLength(); i++) {
n = list.item(i);
// Skip comments inside text tag.
if(n.getNodeType() == Node.COMMENT_NODE) {
continue;
}
if(n.getNodeType() != Node.TEXT_NODE) {
throw new XMLRPCException("Element must contain only text elements.");
}
builder.append(n.getNodeValue());
}
return builder.toString();
}
/**
* Checks if the given {@link NodeList} contains a child element.
*
* @param list The {@link NodeList} to check.
* @return Whether the {@link NodeList} contains children.
*/
public static boolean hasChildElement(NodeList list) {
Node n;
for(int i = 0; i < list.getLength(); i++) {
n = list.item(i);
if(n.getNodeType() == Node.ELEMENT_NODE) {
return true;
}
}
return false;
}
/**
* Creates an xml tag with a given type and content.
*

38
app/src/main/java/de/timroes/axmlrpc/serializer/ArraySerializer.java

@ -2,12 +2,7 @@ package de.timroes.axmlrpc.serializer; @@ -2,12 +2,7 @@ package de.timroes.axmlrpc.serializer;
import de.timroes.axmlrpc.XMLRPCException;
import de.timroes.axmlrpc.XMLRPCRuntimeException;
import de.timroes.axmlrpc.XMLUtil;
import de.timroes.axmlrpc.xmlcreator.XmlElement;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
*
@ -18,39 +13,6 @@ public class ArraySerializer implements Serializer { @@ -18,39 +13,6 @@ public class ArraySerializer implements Serializer {
private static final String ARRAY_DATA = "data";
private static final String ARRAY_VALUE = "value";
public Object deserialize(Element content) throws XMLRPCException {
List<Object> list = new ArrayList<Object>();
Element data = XMLUtil.getOnlyChildElement(content.getChildNodes());
if(!ARRAY_DATA.equals(data.getNodeName())) {
throw new XMLRPCException("The array must contain one data tag.");
}
// Deserialize every array element
Node value;
for(int i = 0; i < data.getChildNodes().getLength(); i++) {
value = data.getChildNodes().item(i);
// Strip only whitespace text elements and comments
if(value == null || (value.getNodeType() == Node.TEXT_NODE
&& value.getNodeValue().trim().length() <= 0)
|| value.getNodeType() == Node.COMMENT_NODE)
continue;
if(value.getNodeType() != Node.ELEMENT_NODE) {
throw new XMLRPCException("Wrong element inside of array.");
}
list.add(SerializerHandler.getDefault().deserialize((Element)value));
}
return list.toArray();
}
public XmlElement serialize(Object object) {
Iterable<?> iter = (Iterable<?>)object;

6
app/src/main/java/de/timroes/axmlrpc/serializer/Base64Serializer.java

@ -1,10 +1,8 @@ @@ -1,10 +1,8 @@
package de.timroes.axmlrpc.serializer;
import de.timroes.axmlrpc.XMLRPCException;
import de.timroes.axmlrpc.XMLUtil;
import de.timroes.axmlrpc.xmlcreator.XmlElement;
import de.timroes.base64.Base64;
import org.w3c.dom.Element;
/**
*
@ -12,10 +10,6 @@ import org.w3c.dom.Element; @@ -12,10 +10,6 @@ import org.w3c.dom.Element;
*/
public class Base64Serializer implements Serializer {
public Object deserialize(Element content) throws XMLRPCException {
return Base64.decode(XMLUtil.getOnlyTextContent(content.getChildNodes()));
}
public XmlElement serialize(Object object) {
return XMLUtil.makeXmlTag(SerializerHandler.TYPE_BASE64,
Base64.encode((Byte[])object));

7
app/src/main/java/de/timroes/axmlrpc/serializer/BooleanSerializer.java

@ -1,9 +1,7 @@ @@ -1,9 +1,7 @@
package de.timroes.axmlrpc.serializer;
import de.timroes.axmlrpc.XMLRPCException;
import de.timroes.axmlrpc.XMLUtil;
import de.timroes.axmlrpc.xmlcreator.XmlElement;
import org.w3c.dom.Element;
/**
*
@ -11,11 +9,6 @@ import org.w3c.dom.Element; @@ -11,11 +9,6 @@ import org.w3c.dom.Element;
*/
public class BooleanSerializer implements Serializer {
public Object deserialize(Element content) throws XMLRPCException {
return (XMLUtil.getOnlyTextContent(content.getChildNodes()).equals("1"))
? Boolean.TRUE : Boolean.FALSE;
}
public XmlElement serialize(Object object) {
return XMLUtil.makeXmlTag(SerializerHandler.TYPE_BOOLEAN,
((Boolean)object == true) ? "1" : "0");

15
app/src/main/java/de/timroes/axmlrpc/serializer/DateTimeSerializer.java

@ -1,11 +1,8 @@ @@ -1,11 +1,8 @@
package de.timroes.axmlrpc.serializer;
import de.timroes.axmlrpc.XMLRPCException;
import de.timroes.axmlrpc.XMLUtil;
import de.timroes.axmlrpc.xmlcreator.XmlElement;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import org.w3c.dom.Element;
/**
*
@ -13,16 +10,8 @@ import org.w3c.dom.Element; @@ -13,16 +10,8 @@ import org.w3c.dom.Element;
*/
public class DateTimeSerializer implements Serializer {
private static final String DATETIME_FORMAT = "yyyyMMdd'T'HH:mm:ss";
private static final SimpleDateFormat DATE_FORMATER = new SimpleDateFormat(DATETIME_FORMAT);
public Object deserialize(Element content) throws XMLRPCException {
try {
return DATE_FORMATER.parse(XMLUtil.getOnlyTextContent(content.getChildNodes()));
} catch (ParseException ex) {
throw new XMLRPCException("Unable to parse given date.", ex);
}
}
public static final String DATETIME_FORMAT = "yyyyMMdd'T'HH:mm:ss";
public static final SimpleDateFormat DATE_FORMATER = new SimpleDateFormat(DATETIME_FORMAT);
public XmlElement serialize(Object object) {
return XMLUtil.makeXmlTag(SerializerHandler.TYPE_DATETIME,

6
app/src/main/java/de/timroes/axmlrpc/serializer/DoubleSerializer.java

@ -1,10 +1,8 @@ @@ -1,10 +1,8 @@
package de.timroes.axmlrpc.serializer;
import de.timroes.axmlrpc.XMLRPCException;
import de.timroes.axmlrpc.XMLUtil;
import de.timroes.axmlrpc.xmlcreator.XmlElement;
import java.math.BigDecimal;
import org.w3c.dom.Element;
/**
* This serializer is responsible for floating point numbers.
@ -13,10 +11,6 @@ import org.w3c.dom.Element; @@ -13,10 +11,6 @@ import org.w3c.dom.Element;
*/
public class DoubleSerializer implements Serializer {
public Object deserialize(Element content) throws XMLRPCException {
return Double.valueOf(XMLUtil.getOnlyTextContent(content.getChildNodes()));
}
public XmlElement serialize(Object object) {
// Turn double value of object into a BigDecimal to get the
// right decimal point format.

6
app/src/main/java/de/timroes/axmlrpc/serializer/IntSerializer.java

@ -1,9 +1,7 @@ @@ -1,9 +1,7 @@
package de.timroes.axmlrpc.serializer;
import de.timroes.axmlrpc.XMLRPCException;
import de.timroes.axmlrpc.XMLUtil;
import de.timroes.axmlrpc.xmlcreator.XmlElement;
import org.w3c.dom.Element;
/**
*
@ -11,10 +9,6 @@ import org.w3c.dom.Element; @@ -11,10 +9,6 @@ import org.w3c.dom.Element;
*/
public class IntSerializer implements Serializer {
public Object deserialize(Element content) throws XMLRPCException {
return Integer.parseInt(XMLUtil.getOnlyTextContent(content.getChildNodes()));
}
public XmlElement serialize(Object object) {
return XMLUtil.makeXmlTag(SerializerHandler.TYPE_INT,
object.toString());

6
app/src/main/java/de/timroes/axmlrpc/serializer/LongSerializer.java

@ -1,9 +1,7 @@ @@ -1,9 +1,7 @@
package de.timroes.axmlrpc.serializer;
import de.timroes.axmlrpc.XMLRPCException;
import de.timroes.axmlrpc.XMLUtil;
import de.timroes.axmlrpc.xmlcreator.XmlElement;
import org.w3c.dom.Element;
/**
*
@ -11,10 +9,6 @@ import org.w3c.dom.Element; @@ -11,10 +9,6 @@ import org.w3c.dom.Element;
*/
class LongSerializer implements Serializer {
public Object deserialize(Element content) throws XMLRPCException {
return Long.parseLong(XMLUtil.getOnlyTextContent(content.getChildNodes()));
}
public XmlElement serialize(Object object) {
return XMLUtil.makeXmlTag(SerializerHandler.TYPE_LONG,
((Long)object).toString());

6
app/src/main/java/de/timroes/axmlrpc/serializer/NullSerializer.java

@ -1,8 +1,6 @@ @@ -1,8 +1,6 @@
package de.timroes.axmlrpc.serializer;
import de.timroes.axmlrpc.XMLRPCException;
import de.timroes.axmlrpc.xmlcreator.XmlElement;
import org.w3c.dom.Element;
/**
*
@ -10,10 +8,6 @@ import org.w3c.dom.Element; @@ -10,10 +8,6 @@ import org.w3c.dom.Element;
*/
public class NullSerializer implements Serializer {
public Object deserialize(Element content) throws XMLRPCException {
return null;
}
public XmlElement serialize(Object object) {
return new XmlElement(SerializerHandler.TYPE_NULL);
}

11
app/src/main/java/de/timroes/axmlrpc/serializer/Serializer.java

@ -1,8 +1,6 @@ @@ -1,8 +1,6 @@
package de.timroes.axmlrpc.serializer;
import de.timroes.axmlrpc.XMLRPCException;
import de.timroes.axmlrpc.xmlcreator.XmlElement;
import org.w3c.dom.Element;
/**
* A Serializer is responsible to serialize a specific type of data to
@ -12,15 +10,6 @@ import org.w3c.dom.Element; @@ -12,15 +10,6 @@ import org.w3c.dom.Element;
*/
public interface Serializer {
/**
* This method takes an xml type element and deserialize it to an object.
*
* @param content Must be an xml element of a specific type.
* @return The deserialized content.
* @throws XMLRPCException Will be thrown whenervt the deserialization fails.
*/
public Object deserialize(Element content) throws XMLRPCException;
/**
* This method takes an object and returns a representation as a string
* containing the right xml type tag. The returning string must be useable

191
app/src/main/java/de/timroes/axmlrpc/serializer/SerializerHandler.java

@ -3,13 +3,27 @@ package de.timroes.axmlrpc.serializer; @@ -3,13 +3,27 @@ package de.timroes.axmlrpc.serializer;
import de.timroes.axmlrpc.XMLRPCClient;
import de.timroes.axmlrpc.XMLRPCException;
import de.timroes.axmlrpc.XMLRPCRuntimeException;
import de.timroes.axmlrpc.XMLUtil;
import de.timroes.axmlrpc.xmlcreator.XmlElement;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.w3c.dom.Element;
import java.util.SimpleTimeZone;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.util.Base64;
import android.util.Log;
/**
* The serializer handler serializes and deserialized objects.
@ -21,6 +35,18 @@ import org.w3c.dom.Element; @@ -21,6 +35,18 @@ import org.w3c.dom.Element;
* @author Tim Roes
*/
public class SerializerHandler {
private static final String LOG_NAME = "SerializerHandler";
public static final String TAG_NAME = "name";
public static final String TAG_MEMBER = "member";
public static final String TAG_VALUE = "value";
public static final String TAG_DATA = "data";
public static final String TYPE_DATE_TIME_ISO8601 = "dateTime.iso8601";
static SimpleDateFormat dateFormat = DateTimeSerializer.DATE_FORMATER;
static Calendar cal = Calendar.getInstance(new SimpleTimeZone(0, "GMT"));
public static final String TYPE_STRING = "string";
public static final String TYPE_BOOLEAN = "boolean";
@ -81,83 +107,120 @@ public class SerializerHandler { @@ -81,83 +107,120 @@ public class SerializerHandler {
*/
private SerializerHandler(int flags) {
this.flags = flags;
string = new StringSerializer(
(flags & XMLRPCClient.FLAGS_NO_STRING_ENCODE) == 0,
(flags & XMLRPCClient.FLAGS_NO_STRING_DECODE) == 0
);
string = new StringSerializer((flags & XMLRPCClient.FLAGS_NO_STRING_ENCODE) == 0);
}
/**
* Deserializes an incoming xml element to an java object.
* The xml element must be the value element around the type element.
* Deserialize an incoming xml to a java object.
* The type of the returning object depends on the type tag.
*
* @param element An type element from within a value tag.
* @param parser Initialized parser.
* @return The deserialized object.
* @throws XMLRPCException Will be thrown whenever an error occurs.
* @throws XmlPullParserException
* @throws IOException
* @throws NumberFormatException
*/
public Object deserialize(Element element) throws XMLRPCException {
public static Object deserialize(XmlPullParser parser) throws XmlPullParserException, IOException, NumberFormatException {
parser.require(XmlPullParser.START_TAG, null, TAG_VALUE);
if(!XMLRPCClient.VALUE.equals(element.getNodeName())) {
throw new XMLRPCException("Value tag is missing around value.");
}
if(!XMLUtil.hasChildElement(element.getChildNodes())) {
// Value element doesn't contain a child element
if((flags & XMLRPCClient.FLAGS_DEFAULT_TYPE_STRING) != 0) {
return string.deserialize(element);
} else {
throw new XMLRPCException("Missing type element inside of value element.");
}
}
// Grep type element from inside value element
element = XMLUtil.getOnlyChildElement(element.getChildNodes());
Serializer s = null;
parser.nextTag();
String typeNodeName = parser.getName();
String type;
// If FLAGS_IGNORE_NAMESPACE has been set, only use local name.
if((flags & XMLRPCClient.FLAGS_IGNORE_NAMESPACES) != 0) {
type = element.getLocalName() == null ? element.getNodeName() : element.getLocalName();
} else {
type = element.getNodeName();
}
Object obj;
if (typeNodeName.equals(TYPE_INT) || typeNodeName.equals(TYPE_INT2)) {
String value = parser.nextText();
try {
obj = Integer.parseInt(value);
} catch (NumberFormatException nfe) {
Log.w(LOG_NAME, "Server replied with an invalid 4 bytes int value, trying to parse it as 8 bytes long.");
obj = Long.parseLong(value);
}
} else
if (typeNodeName.equals(TYPE_LONG)) {
String value = parser.nextText();
obj = Long.parseLong(value);
} else
if (typeNodeName.equals(TYPE_DOUBLE)) {
String value = parser.nextText();
obj = Double.parseDouble(value);
} else
if (typeNodeName.equals(TYPE_BOOLEAN)) {
String value = parser.nextText();
obj = value.equals("1") ? Boolean.TRUE : Boolean.FALSE;
} else
if (typeNodeName.equals(TYPE_STRING)) {
obj = parser.nextText();
} else
if (typeNodeName.equals(TYPE_DATE_TIME_ISO8601)) {
dateFormat.setCalendar(cal);
String value = parser.nextText();
try {
obj = dateFormat.parseObject(value);
} catch (ParseException e) {
Log.e(LOG_NAME, "Error parsing date, using non-parsed string.");
obj = value;
}
} else
if (typeNodeName.equals(TYPE_BASE64)) {
String value = parser.nextText();
BufferedReader reader = new BufferedReader(new StringReader(value));
String line;
StringBuffer sb = new StringBuffer();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
obj = Base64.decode(sb.toString(), Base64.DEFAULT);
} else
if (typeNodeName.equals(TYPE_ARRAY)) {
parser.nextTag(); // TAG_DATA (<data>)
parser.require(XmlPullParser.START_TAG, null, TAG_DATA);
if((flags & XMLRPCClient.FLAGS_NIL) != 0 && TYPE_NULL.equals(type)) {
s = nil;
} else if(TYPE_STRING.equals(type)) {
s = string;
} else if(TYPE_BOOLEAN.equals(type)) {
s = bool;
} else if(TYPE_DOUBLE.equals(type)) {
s = floating;
} else if (TYPE_INT.equals(type) || TYPE_INT2.equals(type)) {
s = integer;
} else if(TYPE_DATETIME.equals(type)) {
s = datetime;
} else if (TYPE_LONG.equals(type)) {
if((flags & XMLRPCClient.FLAGS_8BYTE_INT) != 0) {
s = long8;
} else {
throw new XMLRPCException("8 byte integer is not in the specification. "
+ "You must use FLAGS_8BYTE_INT to enable the i8 tag.");
parser.nextTag();
List<Object> list = new ArrayList<Object>();
while (parser.getName().equals(TAG_VALUE)) {
list.add(deserialize(parser));
parser.nextTag();
}
} else if(TYPE_STRUCT.equals(type)) {
s = struct;
} else if(TYPE_ARRAY.equals(type)) {
s = array;
} else if(TYPE_BASE64.equals(type)) {
s = base64;
parser.require(XmlPullParser.END_TAG, null, TAG_DATA);
parser.nextTag(); // TAG_ARRAY (</array>)
parser.require(XmlPullParser.END_TAG, null, TYPE_ARRAY);
obj = list.toArray();
} else
if (typeNodeName.equals(TYPE_STRUCT)) {
parser.nextTag();
Map<String, Object> map = new HashMap<String, Object>();
while (parser.getName().equals(TAG_MEMBER)) {
String memberName = null;
Object memberValue = null;
while (true) {
parser.nextTag();
String name = parser.getName();
if (name.equals(TAG_NAME)) {
memberName = parser.nextText();
} else
if (name.equals(TAG_VALUE)) {
memberValue = deserialize(parser);
} else {
break;
}
}
if (memberName != null && memberValue != null) {
map.put(memberName, memberValue);
}
parser.require(XmlPullParser.END_TAG, null, TAG_MEMBER);
parser.nextTag();
}
parser.require(XmlPullParser.END_TAG, null, TYPE_STRUCT);
obj = map;
} else {
throw new XMLRPCException("No deserializer found for type '" + type + "'.");
throw new IOException("Cannot deserialize " + parser.getName());
}
return s.deserialize(element);
parser.nextTag(); // TAG_VALUE (</value>)
parser.require(XmlPullParser.END_TAG, null, TAG_VALUE);
return obj;
}
/**
* Serialize an object to its representation as an xml element.
* The xml element will be the type element for the use within a value tag.

13
app/src/main/java/de/timroes/axmlrpc/serializer/StringSerializer.java

@ -1,9 +1,7 @@ @@ -1,9 +1,7 @@
package de.timroes.axmlrpc.serializer;
import de.timroes.axmlrpc.XMLRPCException;
import de.timroes.axmlrpc.XMLUtil;
import de.timroes.axmlrpc.xmlcreator.XmlElement;
import org.w3c.dom.Element;
/**
*
@ -11,21 +9,12 @@ import org.w3c.dom.Element; @@ -11,21 +9,12 @@ import org.w3c.dom.Element;
*/
public class StringSerializer implements Serializer {
private boolean decodeStrings;
private boolean encodeStrings;
public StringSerializer(boolean encodeStrings, boolean decodeStrings) {
this.decodeStrings = decodeStrings;
public StringSerializer(boolean encodeStrings) {
this.encodeStrings = encodeStrings;
}
public Object deserialize(Element content) throws XMLRPCException {
String text = XMLUtil.getOnlyTextContent(content.getChildNodes());
if(decodeStrings) {
text = text.replaceAll("&lt;", "<").replaceAll("&amp;", "&");
}
return text;
}
public XmlElement serialize(Object object) {
String content = object.toString();

63
app/src/main/java/de/timroes/axmlrpc/serializer/StructSerializer.java

@ -2,12 +2,8 @@ package de.timroes.axmlrpc.serializer; @@ -2,12 +2,8 @@ package de.timroes.axmlrpc.serializer;
import de.timroes.axmlrpc.XMLRPCException;
import de.timroes.axmlrpc.XMLRPCRuntimeException;
import de.timroes.axmlrpc.XMLUtil;
import de.timroes.axmlrpc.xmlcreator.XmlElement;
import java.util.HashMap;
import java.util.Map;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
*
@ -19,65 +15,6 @@ public class StructSerializer implements Serializer { @@ -19,65 +15,6 @@ public class StructSerializer implements Serializer {
private static final String STRUCT_NAME = "name";
private static final String STRUCT_VALUE = "value";
public Object deserialize(Element content) throws XMLRPCException {
Map<String, Object> map = new HashMap<String, Object>();
Node n, m;
String s;
Object o;
for(int i = 0; i < content.getChildNodes().getLength(); i++) {
n = content.getChildNodes().item(i);
// Strip only whitespace text elements and comments
if((n.getNodeType() == Node.TEXT_NODE
&& n.getNodeValue().trim().length() <= 0)
|| n.getNodeType() == Node.COMMENT_NODE)
continue;
if(n.getNodeType() != Node.ELEMENT_NODE
|| !STRUCT_MEMBER.equals(n.getNodeName())) {
throw new XMLRPCException("Only struct members allowed within a struct.");
}
// Grep name and value from member
s = null; o = null;
for(int j = 0; j < n.getChildNodes().getLength(); j++) {
m = n.getChildNodes().item(j);
// Strip only whitespace text elements and comments
if((m.getNodeType() == Node.TEXT_NODE
&& m.getNodeValue().trim().length() <= 0)
|| m.getNodeType() == Node.COMMENT_NODE)
continue;
if(STRUCT_NAME.equals(m.getNodeName())) {
if(s != null) {
throw new XMLRPCException("Name of a struct member cannot be set twice.");
} else {
s = XMLUtil.getOnlyTextContent(m.getChildNodes());
}
} else if(m.getNodeType() == Node.ELEMENT_NODE && STRUCT_VALUE.equals(m.getNodeName())) {
if(o != null) {
throw new XMLRPCException("Value of a struct member cannot be set twice.");
} else {
o = SerializerHandler.getDefault().deserialize((Element)m);
}
} else {
throw new XMLRPCException("A struct member must only contain one name and one value.");
}
}
map.put(s, o);
}
return map;
}
public XmlElement serialize(Object object) {
XmlElement struct = new XmlElement(SerializerHandler.TYPE_STRUCT);

Loading…
Cancel
Save