diff --git a/app/build.gradle b/app/build.gradle index 6791fdb0..f83738c3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -93,6 +93,7 @@ dependencies { implementation 'com.github.aegnor:rencode-java:cb628e824e' implementation 'org.apache.openjpa:openjpa-lib:3.1.1' implementation 'net.iharder:base64:2.3.9' + //implementation 'de.timroes:aXMLRPC:1.12.0' implementation('com.github.afollestad.material-dialogs:core:0.9.6.0@aar') { transitive = true } diff --git a/app/src/main/java/de/timroes/axmlrpc/Call.java b/app/src/main/java/de/timroes/axmlrpc/Call.java index de393ec5..26bfabe4 100644 --- a/app/src/main/java/de/timroes/axmlrpc/Call.java +++ b/app/src/main/java/de/timroes/axmlrpc/Call.java @@ -16,13 +16,14 @@ public class Call { private String method; private Object[] params; + private final SerializerHandler serializerHandler; /** * Create a new method call with the given name and no parameters. * @param method The method to be called. */ - public Call(String method) { - this(method, null); + public Call(SerializerHandler serializerHandler, String method) { + this(serializerHandler, method, null); } /** @@ -30,9 +31,10 @@ public class Call { * @param method The method to be called. * @param params An array of parameters for the method. */ - public Call(String method, Object[] params) { + public Call(SerializerHandler serializerHandler, String method, Object[] params) { this.method = method; this.params = params; + this.serializerHandler = serializerHandler; } /** @@ -57,11 +59,11 @@ public class Call { methodCall.addChildren(methodName); if(params != null && params.length > 0) { - XmlElement params = new XmlElement(XMLRPCClient.PARAMS); - methodCall.addChildren(params); + XmlElement callParams = new XmlElement(XMLRPCClient.PARAMS); + methodCall.addChildren(callParams); for(Object o : this.params) { - params.addChildren(getXMLParam(o)); + callParams.addChildren(getXMLParam(o)); } } @@ -79,7 +81,7 @@ public class Call { XmlElement param = new XmlElement(XMLRPCClient.PARAM); XmlElement value = new XmlElement(XMLRPCClient.VALUE); param.addChildren(value); - value.addChildren(SerializerHandler.getDefault().serialize(o)); + value.addChildren(serializerHandler.serialize(o)); return param; } diff --git a/app/src/main/java/de/timroes/axmlrpc/ResponseParser.java b/app/src/main/java/de/timroes/axmlrpc/ResponseParser.java index c58b13d3..c47d2240 100644 --- a/app/src/main/java/de/timroes/axmlrpc/ResponseParser.java +++ b/app/src/main/java/de/timroes/axmlrpc/ResponseParser.java @@ -16,7 +16,7 @@ import org.xmlpull.v1.XmlPullParserFactory; * * @author Tim Roes */ -class ResponseParser { +public class ResponseParser { private static final String FAULT_CODE = "faultCode"; private static final String FAULT_STRING = "faultString"; @@ -71,13 +71,13 @@ class ResponseParser { pullParser.nextTag(); // TAG_VALUE () // no parser.require() here since its called in XMLRPCSerializer.deserialize() below // deserialize result - Object obj = SerializerHandler.getDefault().deserialize(pullParser); + Object obj = SerializerHandler.deserialize(pullParser); consumeHttpEntity(response, entity); return obj; } else if (tag.equals(XMLRPCClient.FAULT)) { // fault response pullParser.nextTag(); // TAG_VALUE () - Map map = (Map) SerializerHandler.getDefault().deserialize(pullParser); + Map map = (Map) SerializerHandler.deserialize(pullParser); consumeHttpEntity(response, entity); //Check that required tags are in the response @@ -92,12 +92,11 @@ class ResponseParser { } catch (XmlPullParserException ex) { consumeHttpEntity(response, entity); throw new XMLRPCException("Error parsing response.", ex); + } catch(XMLRPCServerException e) { + throw e; } catch (Exception ex) { consumeHttpEntity(response, entity); - if(ex instanceof XMLRPCServerException) - throw (XMLRPCServerException)ex; - else - throw new XMLRPCException("Error getting result from server.", ex); + throw new XMLRPCException("Error getting result from server.", ex); } } -} \ No newline at end of file +} diff --git a/app/src/main/java/de/timroes/axmlrpc/XMLRPCClient.java b/app/src/main/java/de/timroes/axmlrpc/XMLRPCClient.java index f6003f87..317e3e07 100644 --- a/app/src/main/java/de/timroes/axmlrpc/XMLRPCClient.java +++ b/app/src/main/java/de/timroes/axmlrpc/XMLRPCClient.java @@ -127,6 +127,11 @@ public class XMLRPCClient { */ public static final int FLAGS_NO_STRING_ENCODE = 0x1000; + /** + * Accepts response containing eg: + */ + public static final int FLAGS_ACCEPT_NULL_DATES = 0x4000; + /** * This flag should be used if the server is an apache ws xmlrpc server. * This will set some flags, so that the not standard conform behavior @@ -140,28 +145,30 @@ public class XMLRPCClient { private final int flags; private DefaultHttpClient httpclient; - + private String url; private Map backgroundCalls = new ConcurrentHashMap(); private ResponseParser responseParser; + private final SerializerHandler serializerHandler; + /** * Create a new XMLRPC client for the given URL. - * + * * @param httpclient The already-initialized Apache HttpClient to use for connection. * @param url The URL to send the requests to. * @param flags A combination of flags to be set. */ public XMLRPCClient(DefaultHttpClient httpclient, String url, int flags) { - SerializerHandler.initialize(flags); + this.serializerHandler = new SerializerHandler(flags); this.httpclient = httpclient; this.url = url; this.flags = flags; - + // Create a parser for the http responses. responseParser = new ResponseParser(); @@ -260,7 +267,7 @@ public class XMLRPCClient { throw new XMLRPCRuntimeException("Method name must only contain A-Z a-z . : _ / "); } - return new Call(method, params); + return new Call(serializerHandler, method, params); } @@ -368,7 +375,7 @@ public class XMLRPCClient { try { 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); @@ -377,10 +384,10 @@ public class XMLRPCClient { StringEntity entity = new StringEntity(c.getXML(), HTTP.UTF_8); entity.setContentType(TYPE_XML); post.setEntity(entity); - + HttpResponse response = httpclient.execute(post); int statusCode = response.getStatusLine().getStatusCode(); - + InputStream istream; // If status code was 401 or 403 throw exception or if appropriate @@ -406,7 +413,7 @@ public class XMLRPCClient { || statusCode == HttpURLConnection.HTTP_MOVED_TEMP) { // ... do either a foward if(isFlagSet(FLAGS_FORWARD)) { - boolean temporaryForward = (statusCode == HttpURLConnection.HTTP_MOVED_TEMP); + boolean temporaryForward = statusCode == HttpURLConnection.HTTP_MOVED_TEMP; // Get new location from header field. String newLocation = response.getFirstHeader("Location").getValue(); @@ -440,10 +447,8 @@ public class XMLRPCClient { } // Check for strict parameters - if(isFlagSet(FLAGS_STRICT)) { - if(!response.getFirstHeader("Content-Type").getValue().startsWith(TYPE_XML)) { + if(isFlagSet(FLAGS_STRICT) && !response.getFirstHeader("Content-Type").getValue().startsWith(TYPE_XML)) { throw new XMLRPCException("The Content-Type of the response must be text/xml."); - } } return responseParser.parse(istream, entity); @@ -462,9 +467,9 @@ public class XMLRPCClient { } } - + } - + public static class CancelException extends Exception { private static final long serialVersionUID = 9125122307255855136L; } @@ -475,5 +480,5 @@ public class XMLRPCClient { public UnauthorizdException(int statusCode) { this.statusCode = statusCode; } public int getStatusCode() { return statusCode; } } - + } diff --git a/app/src/main/java/de/timroes/axmlrpc/XMLRPCServerException.java b/app/src/main/java/de/timroes/axmlrpc/XMLRPCServerException.java index 0b403e93..20bccca2 100644 --- a/app/src/main/java/de/timroes/axmlrpc/XMLRPCServerException.java +++ b/app/src/main/java/de/timroes/axmlrpc/XMLRPCServerException.java @@ -8,7 +8,7 @@ package de.timroes.axmlrpc; */ public class XMLRPCServerException extends XMLRPCException { - private int errornr; + private final int errornr; public XMLRPCServerException(String ex, int errnr) { super(ex); diff --git a/app/src/main/java/de/timroes/axmlrpc/XMLUtil.java b/app/src/main/java/de/timroes/axmlrpc/XMLUtil.java index 7e444591..6cc97643 100644 --- a/app/src/main/java/de/timroes/axmlrpc/XMLUtil.java +++ b/app/src/main/java/de/timroes/axmlrpc/XMLUtil.java @@ -9,6 +9,8 @@ import de.timroes.axmlrpc.xmlcreator.XmlElement; */ public class XMLUtil { + private XMLUtil() {} + /** * Creates an xml tag with a given type and content. * @@ -22,4 +24,4 @@ public class XMLUtil { return xml; } -} \ No newline at end of file +} diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/ArraySerializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/ArraySerializer.java index d1b054fe..8789fa3d 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/ArraySerializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/ArraySerializer.java @@ -3,6 +3,7 @@ package de.timroes.axmlrpc.serializer; import de.timroes.axmlrpc.XMLRPCException; import de.timroes.axmlrpc.XMLRPCRuntimeException; import de.timroes.axmlrpc.xmlcreator.XmlElement; +import java.util.Arrays; /** * @@ -12,10 +13,20 @@ public class ArraySerializer implements Serializer { private static final String ARRAY_DATA = "data"; private static final String ARRAY_VALUE = "value"; + private final SerializerHandler serializerHandler; + + public ArraySerializer(SerializerHandler serializerHandler){ + this.serializerHandler = serializerHandler; + } public XmlElement serialize(Object object) { - Iterable iter = (Iterable)object; + Iterable iter; + if ( object instanceof Iterable){ + iter = (Iterable)object; + } else { + iter = Arrays.asList((Object[]) object); + } XmlElement array = new XmlElement(SerializerHandler.TYPE_ARRAY); XmlElement data = new XmlElement(ARRAY_DATA); array.addChildren(data); @@ -25,7 +36,7 @@ public class ArraySerializer implements Serializer { XmlElement e; for(Object obj : iter) { e = new XmlElement(ARRAY_VALUE); - e.addChildren(SerializerHandler.getDefault().serialize(obj)); + e.addChildren(serializerHandler.serialize(obj)); data.addChildren(e); } @@ -37,4 +48,4 @@ public class ArraySerializer implements Serializer { } -} \ No newline at end of file +} diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/BooleanSerializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/BooleanSerializer.java index f64a7f4e..c85162cd 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/BooleanSerializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/BooleanSerializer.java @@ -11,7 +11,7 @@ public class BooleanSerializer implements Serializer { public XmlElement serialize(Object object) { return XMLUtil.makeXmlTag(SerializerHandler.TYPE_BOOLEAN, - ((Boolean)object == true) ? "1" : "0"); + (Boolean) object ? "1" : "0"); } -} \ No newline at end of file +} diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/DateTimeSerializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/DateTimeSerializer.java index 8c19f0f3..7cb67c6e 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/DateTimeSerializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/DateTimeSerializer.java @@ -10,9 +10,15 @@ import java.text.SimpleDateFormat; */ public class DateTimeSerializer implements Serializer { - public static final String DATETIME_FORMAT = "yyyyMMdd'T'HH:mm:ss"; + public static final String DATETIME_FORMAT = "yyyyMMdd'T'HHmmss"; public static final SimpleDateFormat DATE_FORMATER = new SimpleDateFormat(DATETIME_FORMAT); + public final boolean accepts_null_input; + + public DateTimeSerializer(boolean accepts_null_input) { + this.accepts_null_input = accepts_null_input; + } + public XmlElement serialize(Object object) { return XMLUtil.makeXmlTag(SerializerHandler.TYPE_DATETIME, DATE_FORMATER.format(object)); diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/SerializerHandler.java b/app/src/main/java/de/timroes/axmlrpc/serializer/SerializerHandler.java index 8666183e..9f15e556 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/SerializerHandler.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/SerializerHandler.java @@ -2,7 +2,6 @@ package de.timroes.axmlrpc.serializer; import de.timroes.axmlrpc.XMLRPCClient; import de.timroes.axmlrpc.XMLRPCException; -import de.timroes.axmlrpc.XMLRPCRuntimeException; import de.timroes.axmlrpc.xmlcreator.XmlElement; import java.io.BufferedReader; @@ -60,54 +59,29 @@ public class SerializerHandler { public static final String TYPE_BASE64 = "base64"; public static final String TYPE_NULL = "nil"; - private static SerializerHandler instance; - - /** - * Initialize the serialization handler. This method must be called before - * the get method returns any object. - * - * @param flags The flags that has been set in the XMLRPCClient. - * @see XMLRPCClient - */ - public static void initialize(int flags) { - instance = new SerializerHandler(flags); - } - - /** - * Return the instance of the SerializerHandler. - * It must have been initialized with initialize() before. - * - * @return The instance of the SerializerHandler. - */ - public static SerializerHandler getDefault() { - if(instance == null) { - throw new XMLRPCRuntimeException("The SerializerHandler has not been initialized."); - } - return instance; - } - private StringSerializer string; private BooleanSerializer bool = new BooleanSerializer(); private IntSerializer integer = new IntSerializer(); private LongSerializer long8 = new LongSerializer(); - private StructSerializer struct = new StructSerializer(); + private StructSerializer struct; private DoubleSerializer floating = new DoubleSerializer(); - private DateTimeSerializer datetime = new DateTimeSerializer(); - private ArraySerializer array = new ArraySerializer(); + private DateTimeSerializer datetime; + public static boolean accepts_null_input; + public SerializerHandler(boolean accepts_null_input) { + SerializerHandler.accepts_null_input = accepts_null_input; + } + private ArraySerializer array; private Base64Serializer base64 = new Base64Serializer(); private NullSerializer nil = new NullSerializer(); - + private int flags; - /** - * Generates the SerializerHandler. - * This method can only called from within the class (the initialize method). - * - * @param flags The flags to use. - */ - private SerializerHandler(int flags) { + public SerializerHandler(int flags) { this.flags = flags; string = new StringSerializer((flags & XMLRPCClient.FLAGS_NO_STRING_ENCODE) == 0); + struct = new StructSerializer(this); + array = new ArraySerializer(this); + datetime = new DateTimeSerializer((flags & XMLRPCClient.FLAGS_ACCEPT_NULL_DATES) != 0); } /** @@ -152,8 +126,12 @@ public class SerializerHandler { obj = parser.nextText(); } else if (typeNodeName.equals(TYPE_DATE_TIME_ISO8601)) { + dateFormat.setCalendar(cal); String value = parser.nextText(); + if (accepts_null_input && (value==null || value.trim().length()==0)) { + return null; + } try { obj = dateFormat.parseObject(value); } catch (ParseException e) { @@ -232,7 +210,7 @@ public class SerializerHandler { */ public XmlElement serialize(Object object) throws XMLRPCException { - Serializer s = null; + Serializer s; if((flags & XMLRPCClient.FLAGS_NIL) != 0 && object == null) { s = nil; @@ -277,7 +255,7 @@ public class SerializerHandler { s = base64; } else if(object instanceof Byte[]) { s = base64; - } else if(object instanceof Iterable) { + } else if(object instanceof Iterable || object instanceof Object[]) { s = array; } else { throw new XMLRPCException("No serializer found for type '" @@ -288,4 +266,4 @@ public class SerializerHandler { } -} \ No newline at end of file +} diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/StringSerializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/StringSerializer.java index 823edad6..c16daff2 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/StringSerializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/StringSerializer.java @@ -19,9 +19,12 @@ public class StringSerializer implements Serializer { public XmlElement serialize(Object object) { String content = object.toString(); if(encodeStrings) { - content = content.replaceAll("&", "&").replaceAll("<", "<"); + content = content + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll("]]>", "]]>"); } return XMLUtil.makeXmlTag(SerializerHandler.TYPE_STRING, content); } -} \ No newline at end of file +} diff --git a/app/src/main/java/de/timroes/axmlrpc/serializer/StructSerializer.java b/app/src/main/java/de/timroes/axmlrpc/serializer/StructSerializer.java index 722f54a3..34ee8c0d 100644 --- a/app/src/main/java/de/timroes/axmlrpc/serializer/StructSerializer.java +++ b/app/src/main/java/de/timroes/axmlrpc/serializer/StructSerializer.java @@ -15,6 +15,12 @@ public class StructSerializer implements Serializer { private static final String STRUCT_NAME = "name"; private static final String STRUCT_VALUE = "value"; + private final SerializerHandler serializerHandler; + + public StructSerializer(SerializerHandler serializerHandler) { + this.serializerHandler = serializerHandler; + } + public XmlElement serialize(Object object) { XmlElement struct = new XmlElement(SerializerHandler.TYPE_STRUCT); @@ -33,7 +39,7 @@ public class StructSerializer implements Serializer { name = new XmlElement(STRUCT_NAME); value = new XmlElement(STRUCT_VALUE); name.setContent(member.getKey()); - value.addChildren(SerializerHandler.getDefault().serialize(member.getValue())); + value.addChildren(serializerHandler.serialize(member.getValue())); entry.addChildren(name); entry.addChildren(value); struct.addChildren(entry); @@ -46,4 +52,4 @@ public class StructSerializer implements Serializer { return struct; } -} \ No newline at end of file +} diff --git a/app/src/main/java/de/timroes/base64/Base64.java b/app/src/main/java/de/timroes/base64/Base64.java index 24612791..68bc1f35 100644 --- a/app/src/main/java/de/timroes/base64/Base64.java +++ b/app/src/main/java/de/timroes/base64/Base64.java @@ -14,6 +14,8 @@ public class Base64 { private static final HashMap map = new HashMap(); + private Base64() {} + static { for(int i = 0; i < code.length; i++) { map.put(code[i], (byte)i); @@ -44,10 +46,10 @@ public class Base64 { int outi = 0; int b1, b2, b3, b4; for(int i = 0; i < input.length; i+=4) { - b1 = (map.get(input[i]) - 1); - b2 = (map.get(input[i+1]) - 1); - b3 = (map.get(input[i+2]) - 1); - b4 = (map.get(input[i+3]) - 1); + b1 = map.get(input[i]) - 1; + b2 = map.get(input[i+1]) - 1; + b3 = map.get(input[i+2]) - 1; + b4 = map.get(input[i+3]) - 1; out[outi++] = (byte)(b1 << 2 | b2 >>> 4); out[outi++] = (byte)((b2 & 0x0F) << 4 | b3 >>> 2); out[outi++] = (byte)((b3 & 0x03) << 6 | (b4 & 0x3F)); @@ -158,4 +160,4 @@ public class Base64 { return out; } -} \ No newline at end of file +}