• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package de.timroes.axmlrpc.serializer;
2 
3 import de.timroes.axmlrpc.XMLRPCClient;
4 import de.timroes.axmlrpc.XMLRPCException;
5 import de.timroes.axmlrpc.XMLUtil;
6 import de.timroes.axmlrpc.xmlcreator.XmlElement;
7 import java.math.BigDecimal;
8 import java.util.Calendar;
9 import java.util.Date;
10 import java.util.Map;
11 import org.w3c.dom.Element;
12 
13 /**
14  * The serializer handler serializes and deserializes objects.
15  * It takes an object, determine its type and let the responsible handler serialize it.
16  * For deserialization it looks at the xml tag around the element.
17  *
18  * @author Tim Roes
19  */
20 public class SerializerHandler {
21 
22 	public static final String TYPE_STRING = "string";
23 	public static final String TYPE_BOOLEAN = "boolean";
24 	public static final String TYPE_INT = "int";
25 	public static final String TYPE_INT2 = "i4";
26 	public static final String TYPE_LONG = "i8";
27 	public static final String TYPE_DOUBLE = "double";
28 	public static final String TYPE_DATETIME = "dateTime.iso8601";
29 	public static final String TYPE_STRUCT = "struct";
30 	public static final String TYPE_ARRAY = "array";
31 	public static final String TYPE_BASE64 = "base64";
32 	public static final String TYPE_NULL = "nil";
33 
34 	private StringSerializer string;
35 	private BooleanSerializer bool = new BooleanSerializer();
36 	private IntSerializer integer = new IntSerializer();
37 	private LongSerializer long8 = new LongSerializer();
38 	private StructSerializer struct;
39 	private DoubleSerializer floating = new DoubleSerializer();
40 	private DateTimeSerializer datetime;
41 	private ArraySerializer array;
42 	private Base64Serializer base64 = new Base64Serializer();
43 	private NullSerializer nil = new NullSerializer();
44 
45 	private int flags;
46 
SerializerHandler()47 	public SerializerHandler(){
48 		this(XMLRPCClient.FLAGS_DEBUG);
49 	}
50 
SerializerHandler(int flags)51 	public SerializerHandler(int flags) { this(flags, DateTimeSerializer.DEFAULT_DATETIME_FORMAT); }
52 
SerializerHandler(int flags, String datetimeFormat)53 	public SerializerHandler(int flags, String datetimeFormat) {
54 		this.flags = flags;
55 		string = new StringSerializer(
56 			(flags & XMLRPCClient.FLAGS_NO_STRING_ENCODE) == 0,
57 			(flags & XMLRPCClient.FLAGS_NO_STRING_DECODE) == 0
58 		);
59 		struct = new StructSerializer(this);
60 		array = new ArraySerializer(this);
61 		boolean accepts_null_input = (flags & XMLRPCClient.FLAGS_ACCEPT_NULL_DATES) != 0;
62 		datetime = new DateTimeSerializer(accepts_null_input, datetimeFormat);
63 	}
64 
65 	/**
66 	 * Deserializes an incoming xml element to an java object.
67 	 * The xml element must be the value element around the type element.
68 	 * The type of the returning object depends on the type tag.
69 	 *
70 	 * @param element An type element from within a value tag.
71 	 * @return The deserialized object.
72 	 * @throws XMLRPCException Will be thrown whenever an error occurs.
73 	 */
deserialize(Element element)74 	public Object deserialize(Element element) throws XMLRPCException {
75 
76 		if(!XMLRPCClient.VALUE.equals(element.getNodeName())) {
77 			throw new XMLRPCException("Value tag is missing around value.");
78 		}
79 
80 		if(!XMLUtil.hasChildElement(element.getChildNodes())) {
81 			// Value element doesn't contain a child element
82 			if((flags & XMLRPCClient.FLAGS_DEFAULT_TYPE_STRING) != 0) {
83 				return string.deserialize(element);
84 			} else {
85 				throw new XMLRPCException("Missing type element inside of value element.");
86 			}
87 		}
88 
89 		// Grep type element from inside value element
90 		Element childElement = XMLUtil.getOnlyChildElement(element.getChildNodes());
91 
92 		Serializer s;
93 
94 		String type;
95 
96 		// If FLAGS_IGNORE_NAMESPACE has been set, only use local name.
97 		if((flags & XMLRPCClient.FLAGS_IGNORE_NAMESPACES) != 0) {
98 			type = childElement.getLocalName() == null ? childElement.getNodeName() : childElement.getLocalName();
99 		} else {
100 			type = childElement.getNodeName();
101 		}
102 
103 		if((flags & XMLRPCClient.FLAGS_NIL) != 0 && TYPE_NULL.equals(type)) {
104 			s = nil;
105 		} else if(TYPE_STRING.equals(type)) {
106 			s = string;
107 		} else if(TYPE_BOOLEAN.equals(type)) {
108 			s = bool;
109 		} else if(TYPE_DOUBLE.equals(type)) {
110 			s = floating;
111 		} else if (TYPE_INT.equals(type) || TYPE_INT2.equals(type)) {
112 			s = integer;
113 		} else if(TYPE_DATETIME.equals(type)) {
114 			s = datetime;
115 		} else if (TYPE_LONG.equals(type)) {
116 			if((flags & XMLRPCClient.FLAGS_8BYTE_INT) != 0) {
117 				s = long8;
118 			} else {
119 				throw new XMLRPCException("8 byte integer is not in the specification. "
120 						+ "You must use FLAGS_8BYTE_INT to enable the i8 tag.");
121 			}
122 		} else if(TYPE_STRUCT.equals(type)) {
123 			s = struct;
124 		} else if(TYPE_ARRAY.equals(type)) {
125 			s = array;
126 		} else if(TYPE_BASE64.equals(type)) {
127 			s = base64;
128 		} else {
129 			throw new XMLRPCException("No deserializer found for type '" + type + "'.");
130 		}
131 
132 		return s.deserialize(childElement);
133 
134 	}
135 
136 	/**
137 	 * Serialize an object to its representation as an xml element.
138 	 * The xml element will be the type element for the use within a value tag.
139 	 *
140 	 * @param object The object that should be serialized.
141 	 * @return The xml representation of this object.
142 	 * @throws XMLRPCException Will be thrown, if an error occurs (e.g. the object
143 	 * 		cannot be serialized to an xml element.
144 	 */
serialize(Object object)145 	public XmlElement serialize(Object object) throws XMLRPCException {
146 
147 		Serializer s;
148 
149 		if((flags & XMLRPCClient.FLAGS_NIL) != 0 && object == null) {
150 			s = nil;
151 		} else if(object instanceof String) {
152 			s = string;
153 		} else if(object instanceof Boolean) {
154 			s = bool;
155 		} else if(object instanceof Double || object instanceof Float
156 				|| object instanceof BigDecimal) {
157 			s = floating;
158 		} else if (object instanceof Integer || object instanceof Short
159 				|| object instanceof Byte) {
160 			s = integer;
161 		} else if(object instanceof Long) {
162 			// Check whether the 8 byte integer flag was set.
163 			if((flags & XMLRPCClient.FLAGS_8BYTE_INT) != 0) {
164 				s = long8;
165 			} else {
166 				// Allow long values as long as their fit within the 4 byte integer range.
167 				long l = (Long)object;
168 				if(l > Integer.MAX_VALUE || l < Integer.MIN_VALUE) {
169 					throw new XMLRPCException("FLAGS_8BYTE_INT must be set, if values "
170 							+ "outside the 4 byte integer range should be transfered.");
171 				} else {
172 					s = integer;
173 				}
174 			}
175 		} else if(object instanceof Date) {
176 			s = datetime;
177 		} else if(object instanceof Calendar) {
178 			object = ((Calendar)object).getTime();
179 			s = datetime;
180 		} else if (object instanceof Map) {
181 			s = struct;
182 		} else if(object instanceof byte[]) {
183 			byte[] old = (byte[])object;
184 			Byte[] boxed = new Byte[old.length];
185 			for(int i = 0; i < boxed.length; i++) {
186 				boxed[i] = Byte.valueOf(old[i]);
187 			}
188 			object = boxed;
189 			s = base64;
190 		} else if(object instanceof Byte[]) {
191 			s = base64;
192 		} else if(object instanceof Iterable<?> || object instanceof Object[]) {
193 			s = array;
194 		} else {
195 			throw new XMLRPCException("No serializer found for type '"
196 					+ object.getClass().getName() + "'.");
197 		}
198 
199 		return s.serialize(object);
200 
201 	}
202 
203 }
204