moved the serialization and deserialization of XML-RPC values into its own
class, 'cos we're going to write a client implementation eventually, and it can share this code
This commit is contained in:
parent
1762784ef0
commit
2eb1f58dba
|
@ -20,12 +20,9 @@ package com.silverwrist.dynamo.xmlrpc;
|
|||
import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import javax.mail.*;
|
||||
import javax.mail.internet.*;
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.*;
|
||||
import org.w3c.dom.*;
|
||||
import com.silverwrist.util.*;
|
||||
import com.silverwrist.util.xml.*;
|
||||
import com.silverwrist.dynamo.RequestType;
|
||||
import com.silverwrist.dynamo.Verb;
|
||||
|
@ -42,27 +39,6 @@ import com.silverwrist.dynamo.util.*;
|
|||
*/
|
||||
class XmlRpcRequest extends BaseDelegatingServiceProvider implements Request
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static final String EMPTY_STRING = "";
|
||||
|
||||
// Indicates the types of values associated with the request.
|
||||
private static final int ITYP_INTEGER = 0; // integer
|
||||
private static final int ITYP_BOOLEAN = 1; // Boolean
|
||||
private static final int ITYP_STRING = 2; // string
|
||||
private static final int ITYP_DOUBLE = 3; // double
|
||||
private static final int ITYP_DATETIME = 4; // date/time
|
||||
private static final int ITYP_BINARY = 5; // binary (byte array)
|
||||
private static final int ITYP_STRUCT = 6; // struct (Map)
|
||||
private static final int ITYP_ARRAY = 7; // array (List)
|
||||
|
||||
private static final Map MAP_TYPE; // maps element names to type values
|
||||
|
||||
private static final DateFormat s_iso8601; // used to format and parse date/time values
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
|
@ -120,6 +96,7 @@ class XmlRpcRequest extends BaseDelegatingServiceProvider implements Request
|
|||
|
||||
} // end catch
|
||||
|
||||
XmlRpcSerializer serializer = XmlRpcSerializer.get();
|
||||
try
|
||||
{ // load the XML body of the request, get the method name and parameters
|
||||
Element method_call = loader.getRootElement(request_doc,"methodCall");
|
||||
|
@ -135,7 +112,7 @@ class XmlRpcRequest extends BaseDelegatingServiceProvider implements Request
|
|||
{ // get the <value/> subelement from each <param/> and store it
|
||||
Element elt = (Element)(it.next());
|
||||
Element value_elt = loader.getSubElement(elt,"value");
|
||||
m_params.put(String.valueOf(ndx++),parseValue(value_elt));
|
||||
m_params.put(String.valueOf(ndx++),serializer.deserialize(value_elt));
|
||||
|
||||
} // end while
|
||||
|
||||
|
@ -155,274 +132,6 @@ class XmlRpcRequest extends BaseDelegatingServiceProvider implements Request
|
|||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Internal operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parses an XML-RPC <value/> element.
|
||||
*
|
||||
* @param elt The node coresponding to the <value/> element.
|
||||
* @return The parsed value.
|
||||
* @exception com.silverwrist.dynamo.xmlrpc.FaultCode If an error occurs in parsing the value.
|
||||
*/
|
||||
private static final Object parseValue(Element elt) throws FaultCode
|
||||
{
|
||||
NodeList nl = elt.getChildNodes();
|
||||
Element type_spec = null;
|
||||
for (int i=0; i<nl.getLength(); i++)
|
||||
{ // look through the subelements to find the type-specific element
|
||||
Node n = nl.item(i);
|
||||
if (n.getNodeType()!=Node.ELEMENT_NODE)
|
||||
continue;
|
||||
if (type_spec!=null)
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,
|
||||
"more than one type-specifying element within a <value/> element");
|
||||
type_spec = (Element)n;
|
||||
|
||||
} // end for
|
||||
|
||||
Object rc = null;
|
||||
if (type_spec!=null)
|
||||
{ // figure out what type this element is
|
||||
Integer tval = (Integer)(MAP_TYPE.get(type_spec.getTagName()));
|
||||
if (tval==null)
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid type \"" + type_spec.getTagName()
|
||||
+ "\"");
|
||||
DOMElementHelper h = new DOMElementHelper(type_spec);
|
||||
switch (tval.intValue())
|
||||
{ // based on the type, act on the contents
|
||||
case ITYP_INTEGER:
|
||||
try
|
||||
{ // parse the integer value
|
||||
rc = new Integer(Integer.parseInt(h.getElementText(),10));
|
||||
|
||||
} // end try
|
||||
catch (NumberFormatException e)
|
||||
{ // value wasn't an integer
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid integer format",e);
|
||||
|
||||
} // end catch
|
||||
catch (NullPointerException e)
|
||||
{ // value was null
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"integer value not specified");
|
||||
|
||||
} // end catch
|
||||
break;
|
||||
|
||||
case ITYP_BOOLEAN:
|
||||
{ // test the Boolean value
|
||||
String s = h.getElementText();
|
||||
if (s==null)
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"boolean value not specified");
|
||||
if (s.equals("1"))
|
||||
rc = Boolean.TRUE;
|
||||
else if (s.equals("0"))
|
||||
rc = Boolean.FALSE;
|
||||
else
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid boolean format");
|
||||
|
||||
} // end case
|
||||
break;
|
||||
|
||||
case ITYP_STRING:
|
||||
{ // get the string value and return it
|
||||
rc = h.getElementText();
|
||||
if (rc==null)
|
||||
rc = EMPTY_STRING;
|
||||
|
||||
} // end case
|
||||
break;
|
||||
|
||||
case ITYP_DOUBLE:
|
||||
try
|
||||
{ // convert to a Double value
|
||||
rc = new Double(h.getElementText());
|
||||
|
||||
} // end try
|
||||
catch (NumberFormatException e)
|
||||
{ // value wasn't an integer
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid double format",e);
|
||||
|
||||
} // end catch
|
||||
catch (NullPointerException e)
|
||||
{ // value was null
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"double value not specified");
|
||||
|
||||
} // end catch
|
||||
break;
|
||||
|
||||
case ITYP_DATETIME:
|
||||
try
|
||||
{ // convert to a Date value
|
||||
rc = s_iso8601.parse(h.getElementText());
|
||||
|
||||
} // end try
|
||||
catch (java.text.ParseException e)
|
||||
{ // date couldn't be parsed
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid ISO 8601 date format",e);
|
||||
|
||||
} // end catch
|
||||
catch (NullPointerException e)
|
||||
{ // no value in there...
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"date value not specified");
|
||||
|
||||
} // end catch
|
||||
break;
|
||||
|
||||
case ITYP_BINARY:
|
||||
try
|
||||
{ // get the string equivalent of the formatted data
|
||||
String s = h.getElementText();
|
||||
if (s==null)
|
||||
{ // null string - return null array
|
||||
rc = new byte[0];
|
||||
break;
|
||||
|
||||
} // end if
|
||||
|
||||
// get a stream of encoded bytes
|
||||
ByteArrayInputStream encoded_stm = new ByteArrayInputStream(s.getBytes("US-ASCII"));
|
||||
|
||||
// use the JavaMail MIME decoder to turn it into decoded bytes
|
||||
InputStream decoded_stm = MimeUtility.decode(encoded_stm,"base64");
|
||||
|
||||
// copy the decoded bytes to a new array
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
IOUtils.copy(decoded_stm,output);
|
||||
IOUtils.shutdown(decoded_stm);
|
||||
IOUtils.shutdown(encoded_stm);
|
||||
|
||||
// retrieve the output array
|
||||
rc = output.toByteArray();
|
||||
IOUtils.shutdown(output);
|
||||
|
||||
} // end try
|
||||
catch (UnsupportedEncodingException e)
|
||||
{ // WTF? shouldn't happen
|
||||
throw new SystemFaultCode(SystemFaultCode.INTERNAL_ERROR,"internal error: unsupported encoding",e);
|
||||
|
||||
} // end catch
|
||||
catch (IOException e)
|
||||
{ // some sort of error copying binary values around
|
||||
throw new SystemFaultCode(SystemFaultCode.INTERNAL_ERROR,"unable to get binary data",e);
|
||||
|
||||
} // end catch
|
||||
catch (MessagingException e)
|
||||
{ // error in the MIME parsing - dump it out
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid binary data format",e);
|
||||
|
||||
} // end catch
|
||||
break;
|
||||
|
||||
case ITYP_STRUCT:
|
||||
rc = parseStruct(type_spec);
|
||||
break;
|
||||
|
||||
case ITYP_ARRAY:
|
||||
rc = parseArray(type_spec);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid type \""
|
||||
+ type_spec.getTagName() + "\"");
|
||||
|
||||
} // end switch
|
||||
|
||||
} // end if
|
||||
else
|
||||
{ // if there's no type-specifying element, treat it as a String
|
||||
DOMElementHelper h = new DOMElementHelper(elt);
|
||||
rc = h.getElementText();
|
||||
if (rc==null)
|
||||
rc = EMPTY_STRING;
|
||||
|
||||
} // end else
|
||||
|
||||
return rc;
|
||||
|
||||
} // end parseValue
|
||||
|
||||
/**
|
||||
* Parses an XML-RPC <struct/> element.
|
||||
*
|
||||
* @param elt The node coresponding to the <struct/> element.
|
||||
* @return The parsed value.
|
||||
* @exception com.silverwrist.dynamo.xmlrpc.FaultCode If an error occurs in parsing the value.
|
||||
*/
|
||||
private static final Map parseStruct(Element elt) throws FaultCode
|
||||
{
|
||||
XMLLoader loader = XMLLoader.get();
|
||||
HashMap rc = new HashMap();
|
||||
try
|
||||
{ // get all <member/> sub-elements and process them
|
||||
List l = loader.getMatchingSubElements(elt,"member");
|
||||
Iterator it = l.iterator();
|
||||
while (it.hasNext())
|
||||
{ // get each <member/> and add its <name/> and <value/> to the map
|
||||
Element x = (Element)(it.next());
|
||||
DOMElementHelper h = new DOMElementHelper(x);
|
||||
String name = loader.getSubElementText(h,"name");
|
||||
Element val_elt = loader.getSubElement(h,"value");
|
||||
rc.put(name,parseValue(val_elt));
|
||||
|
||||
} // end while
|
||||
|
||||
} // end try
|
||||
catch (XMLLoadException e)
|
||||
{ // translate load exception
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,e);
|
||||
|
||||
} // end catch
|
||||
|
||||
if (rc.isEmpty())
|
||||
return Collections.EMPTY_MAP;
|
||||
else
|
||||
return Collections.unmodifiableMap(rc);
|
||||
|
||||
} // end parseStruct
|
||||
|
||||
/**
|
||||
* Parses an XML-RPC <array/> element.
|
||||
*
|
||||
* @param elt The node coresponding to the <array/> element.
|
||||
* @return The parsed value.
|
||||
* @exception com.silverwrist.dynamo.xmlrpc.FaultCode If an error occurs in parsing the value.
|
||||
*/
|
||||
private static final List parseArray(Element elt) throws FaultCode
|
||||
{
|
||||
XMLLoader loader = XMLLoader.get();
|
||||
ArrayList rc = null;
|
||||
try
|
||||
{ // get the <data/> sub-element
|
||||
Element data_elt = loader.getSubElement(elt,"data");
|
||||
|
||||
// get the values it contains
|
||||
List l = loader.getMatchingSubElements(data_elt,"value");
|
||||
rc = new ArrayList(l.size());
|
||||
Iterator it = l.iterator();
|
||||
while (it.hasNext())
|
||||
{ // parse the <value/> elements and add them to the list
|
||||
Element val_elt = (Element)(it.next());
|
||||
rc.add(parseValue(val_elt));
|
||||
|
||||
} // end while
|
||||
|
||||
} // end try
|
||||
catch (XMLLoadException e)
|
||||
{ // translate load exception
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,e);
|
||||
|
||||
} // end catch
|
||||
|
||||
if ((rc==null) || rc.isEmpty())
|
||||
return Collections.EMPTY_LIST;
|
||||
else
|
||||
return Collections.unmodifiableList(rc);
|
||||
|
||||
} // end parseArray
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Implementations from interface ObjectProvider
|
||||
*--------------------------------------------------------------------------------
|
||||
|
@ -670,31 +379,4 @@ class XmlRpcRequest extends BaseDelegatingServiceProvider implements Request
|
|||
|
||||
} // end getLocales
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static initializer
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static
|
||||
{ // Initialize the type map.
|
||||
HashMap tmp = new HashMap();
|
||||
Integer foo = new Integer(ITYP_INTEGER);
|
||||
tmp.put("i4",foo);
|
||||
tmp.put("int",foo);
|
||||
tmp.put("boolean",new Integer(ITYP_BOOLEAN));
|
||||
tmp.put("string",new Integer(ITYP_STRING));
|
||||
tmp.put("double",new Integer(ITYP_DOUBLE));
|
||||
tmp.put("dateTime.iso8601",new Integer(ITYP_DATETIME));
|
||||
tmp.put("base64",new Integer(ITYP_BINARY));
|
||||
tmp.put("struct",new Integer(ITYP_STRUCT));
|
||||
tmp.put("array",new Integer(ITYP_ARRAY));
|
||||
MAP_TYPE = Collections.unmodifiableMap(tmp);
|
||||
|
||||
// Initialize the ISO 8601 date formatter.
|
||||
SimpleDateFormat iso = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
|
||||
iso.setCalendar(new GregorianCalendar(new SimpleTimeZone(0,"UTC")));
|
||||
s_iso8601 = iso;
|
||||
|
||||
} // end static initializer
|
||||
|
||||
} // end class XmlRpcRequest
|
||||
|
|
|
@ -11,40 +11,19 @@
|
|||
*
|
||||
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
|
||||
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
|
||||
* Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
* Copyright (C) 2002-03 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.ref.Reference;
|
||||
import java.sql.Blob;
|
||||
import java.sql.SQLException;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import javax.mail.*;
|
||||
import javax.mail.internet.*;
|
||||
import com.silverwrist.util.*;
|
||||
import com.silverwrist.dynamo.HttpStatusCode;
|
||||
import com.silverwrist.dynamo.except.*;
|
||||
import com.silverwrist.dynamo.iface.*;
|
||||
|
||||
public class XmlRpcResult implements SelfRenderable, XmlRpcSelfSerializing
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static final String SERIALIZED_NULL = "<string>null</string>";
|
||||
private static final String START_ARRAY = "<array><data>\r\n";
|
||||
private static final String END_ARRAY = "</data></array>";
|
||||
private static final String START_VALUE = "<value>";
|
||||
private static final String END_VALUE = "</value>\r\n";
|
||||
|
||||
private static final DateFormat s_iso8601;
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
|
@ -73,7 +52,7 @@ public class XmlRpcResult implements SelfRenderable, XmlRpcSelfSerializing
|
|||
// Serialize the output value to a StringWriter.
|
||||
StringWriter wr = new StringWriter();
|
||||
wr.write("<methodResponse><params><param>\r\n<value>");
|
||||
serialize(wr,m_obj);
|
||||
XmlRpcSerializer.get().serialize(wr,m_obj);
|
||||
wr.write("</value>\r\n</param></params></methodResponse>\r\n");
|
||||
|
||||
// Now render the binary equivalent of this structure.
|
||||
|
@ -107,513 +86,8 @@ public class XmlRpcResult implements SelfRenderable, XmlRpcSelfSerializing
|
|||
|
||||
public void serializeXmlRpc(Writer wr) throws IOException
|
||||
{
|
||||
serialize(wr,m_obj);
|
||||
XmlRpcSerializer.get().serialize(wr,m_obj);
|
||||
|
||||
} // end serializeXmlRpc
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* External static operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public static void serializeBinary(Writer wr, InputStream stm) throws IOException
|
||||
{
|
||||
try
|
||||
{ // Encode the data as BASE-64.
|
||||
ByteArrayOutputStream internal_stm = new ByteArrayOutputStream();
|
||||
OutputStream encode_stm = MimeUtility.encode(internal_stm,"base64");
|
||||
IOUtils.copy(stm,encode_stm);
|
||||
encode_stm.flush();
|
||||
|
||||
// turn our encoded output into an InputStream
|
||||
ByteArrayInputStream internal2_stm = new ByteArrayInputStream(internal_stm.toByteArray());
|
||||
IOUtils.shutdown(encode_stm);
|
||||
IOUtils.shutdown(internal_stm);
|
||||
|
||||
// write out the data
|
||||
InputStreamReader rd = new InputStreamReader(internal2_stm,"US-ASCII");
|
||||
wr.write("<base64>");
|
||||
IOUtils.copy(rd,wr);
|
||||
wr.write("</base64>");
|
||||
IOUtils.shutdown(rd);
|
||||
IOUtils.shutdown(internal2_stm);
|
||||
|
||||
} // end try
|
||||
catch (MessagingException e)
|
||||
{ // encoder might have an error
|
||||
throw new IOException("error encoding binary data");
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end serializeBinary
|
||||
|
||||
public static void serialize(Writer wr, boolean b) throws IOException
|
||||
{
|
||||
wr.write("<boolean>");
|
||||
wr.write(b ? "1" : "0");
|
||||
wr.write("</boolean>");
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, boolean[] b) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<b.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,b[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, byte b) throws IOException
|
||||
{
|
||||
serialize(wr,(int)b);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, byte[] b) throws IOException
|
||||
{
|
||||
serializeBinary(wr,new ByteArrayInputStream(b));
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, char c) throws IOException
|
||||
{
|
||||
wr.write("<string>");
|
||||
wr.write(c);
|
||||
wr.write("</string>");
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, char[] c) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<c.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,c[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, short s) throws IOException
|
||||
{
|
||||
serialize(wr,(int)s);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, short[] s) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<s.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,s[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, int i) throws IOException
|
||||
{
|
||||
wr.write("<int>");
|
||||
wr.write(String.valueOf(i));
|
||||
wr.write("</int>");
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, int[] ia) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<ia.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,ia[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, long l) throws IOException
|
||||
{
|
||||
serialize(wr,(double)l);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, long[] l) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<l.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,l[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, float f) throws IOException
|
||||
{
|
||||
serialize(wr,(double)f);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, float[] f) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<f.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,f[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, double d) throws IOException
|
||||
{
|
||||
wr.write("<double>");
|
||||
wr.write(String.valueOf(d));
|
||||
wr.write("</double>");
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, double[] d) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<d.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,d[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serializeCalendar(Writer wr, Calendar cal) throws IOException
|
||||
{
|
||||
wr.write("<dateTime.iso8601>");
|
||||
|
||||
// Encode the year first.
|
||||
StringBuffer conv = new StringBuffer("0000");
|
||||
conv.append(cal.get(Calendar.YEAR));
|
||||
String c = conv.toString();
|
||||
wr.write(c.substring(c.length()-4));
|
||||
|
||||
// Now the month...
|
||||
conv.setLength(0);
|
||||
conv.append("00").append(cal.get(Calendar.MONTH) - Calendar.JANUARY + 1);
|
||||
c = conv.toString();
|
||||
wr.write(c.substring(c.length()-2));
|
||||
|
||||
// And the day...
|
||||
conv.setLength(0);
|
||||
conv.append("00").append(cal.get(Calendar.DAY_OF_MONTH));
|
||||
c = conv.toString();
|
||||
wr.write(c.substring(c.length()-2));
|
||||
wr.write("T");
|
||||
|
||||
// And the hour...
|
||||
conv.setLength(0);
|
||||
conv.append("00").append(cal.get(Calendar.HOUR_OF_DAY));
|
||||
c = conv.toString();
|
||||
wr.write(c.substring(c.length()-2));
|
||||
wr.write(":");
|
||||
|
||||
// And the minute...
|
||||
conv.setLength(0);
|
||||
conv.append("00").append(cal.get(Calendar.MINUTE));
|
||||
c = conv.toString();
|
||||
wr.write(c.substring(c.length()-2));
|
||||
wr.write(":");
|
||||
|
||||
// And the second...
|
||||
conv.setLength(0);
|
||||
conv.append("00").append(cal.get(Calendar.SECOND));
|
||||
c = conv.toString();
|
||||
wr.write(c.substring(c.length()-2));
|
||||
|
||||
// And we're done!
|
||||
wr.write("</dateTime.iso8601>");
|
||||
|
||||
} // end serializeCalendar
|
||||
|
||||
public static void serializeCollection(Writer wr, Collection coll) throws IOException
|
||||
{
|
||||
serializeIterator(wr,coll.iterator());
|
||||
|
||||
} // end serializeCollection
|
||||
|
||||
public static void serializeDate(Writer wr, Date d) throws IOException
|
||||
{
|
||||
wr.write("<dateTime.iso8601>");
|
||||
wr.write(s_iso8601.format(d));
|
||||
wr.write("</dateTime.iso8601>");
|
||||
|
||||
} // end serializeDate
|
||||
|
||||
public static void serializeEnumeration(Writer wr, Enumeration enum) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
while (enum.hasMoreElements())
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,enum.nextElement());
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serializeIterator
|
||||
|
||||
public static void serializeIterator(Writer wr, Iterator it) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
while (it.hasNext())
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,it.next());
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serializeIterator
|
||||
|
||||
public static void serializeMap(Writer wr, Map map) throws IOException
|
||||
{
|
||||
wr.write("<struct>\r\n");
|
||||
Iterator it = map.entrySet().iterator();
|
||||
while (it.hasNext())
|
||||
{ // write each entry in turn
|
||||
Map.Entry ntry = (Map.Entry)(it.next());
|
||||
wr.write("<member>\r\n<name>");
|
||||
wr.write(StringUtils.encodeHTML(ntry.getKey().toString()));
|
||||
wr.write("</name>\r\n<value>");
|
||||
serialize(wr,ntry.getValue());
|
||||
wr.write("</value>\r\n</member>");
|
||||
|
||||
} // end while
|
||||
|
||||
wr.write("\r\n</struct>");
|
||||
|
||||
} // end serializeMap
|
||||
|
||||
public static void serializeString(Writer wr, String s) throws IOException
|
||||
{
|
||||
wr.write("<string>");
|
||||
wr.write(StringUtils.encodeHTML(s));
|
||||
wr.write("</string>");
|
||||
|
||||
} // end serializeString
|
||||
|
||||
public static void serialize(Writer wr, Object obj) throws IOException
|
||||
{
|
||||
if (obj==null)
|
||||
{ // null object - bye!
|
||||
wr.write(SERIALIZED_NULL);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj.getClass().isArray())
|
||||
{ // for arrays, serialize them specially
|
||||
Class component = obj.getClass().getComponentType();
|
||||
if (component==Boolean.TYPE)
|
||||
serialize(wr,(boolean[])obj);
|
||||
else if (component==Byte.TYPE)
|
||||
serialize(wr,(byte[])obj);
|
||||
else if (component==Character.TYPE)
|
||||
serialize(wr,(char[])obj);
|
||||
else if (component==Short.TYPE)
|
||||
serialize(wr,(short[])obj);
|
||||
else if (component==Integer.TYPE)
|
||||
serialize(wr,(int[])obj);
|
||||
else if (component==Long.TYPE)
|
||||
serialize(wr,(long[])obj);
|
||||
else if (component==Float.TYPE)
|
||||
serialize(wr,(float[])obj);
|
||||
else if (component==Double.TYPE)
|
||||
serialize(wr,(double[])obj);
|
||||
else
|
||||
serialize(wr,(Object[])obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof XmlRpcSelfSerializing)
|
||||
{ // some objects may be self-serializing
|
||||
((XmlRpcSelfSerializing)obj).serializeXmlRpc(wr);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof DynamicWrapper)
|
||||
{ // for dynamic wrappers, unwrap them
|
||||
serialize(wr,((DynamicWrapper)obj).unwrap());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof InputStream)
|
||||
{ // for InputStream, turn it into binary
|
||||
serializeBinary(wr,(InputStream)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Blob)
|
||||
{ // serialize the blob as a binary stream
|
||||
try
|
||||
{ // just get its input stream
|
||||
serializeBinary(wr,((Blob)obj).getBinaryStream());
|
||||
return;
|
||||
|
||||
} // end try
|
||||
catch (SQLException e)
|
||||
{ // fault on error here
|
||||
throw new IOException("error writing binary data");
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Calendar)
|
||||
{ // serialize a Calendar
|
||||
serializeCalendar(wr,(Calendar)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Collection)
|
||||
{ // serialize a Collection
|
||||
serializeCollection(wr,(Collection)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Date)
|
||||
{ // serialize a Date
|
||||
serializeDate(wr,(Date)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Enumeration)
|
||||
{ // serialize a Enumeration
|
||||
serializeEnumeration(wr,(Enumeration)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Iterator)
|
||||
{ // serialize a Iterator
|
||||
serializeIterator(wr,(Iterator)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Map)
|
||||
{ // serialize a Map
|
||||
serializeMap(wr,(Map)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Reference)
|
||||
{ // for a Reference, serialize the referent
|
||||
serialize(wr,((Reference)obj).get());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Boolean)
|
||||
{ // serialize the boolean value
|
||||
serialize(wr,((Boolean)obj).booleanValue());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Character)
|
||||
{ // serialize the character value
|
||||
serialize(wr,((Character)obj).charValue());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if ((obj instanceof Byte) || (obj instanceof Short) || (obj instanceof Integer))
|
||||
{ // serialize the integer value
|
||||
serialize(wr,((Number)obj).intValue());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if ((obj instanceof Long) || (obj instanceof Float) || (obj instanceof Double))
|
||||
{ // serialize the double value
|
||||
serialize(wr,((Number)obj).doubleValue());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
// String and StringBuffer are handled properly by the fallback mechanism below
|
||||
|
||||
// last-ditch fallback method - use toString, get the string, and encode it
|
||||
serializeString(wr,obj.toString());
|
||||
|
||||
} // end serialize
|
||||
|
||||
public static void serialize(Writer wr, Object[] arr) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<arr.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,arr[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static initializer
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static
|
||||
{ // Initialize the ISO 8601 date formatter.
|
||||
SimpleDateFormat iso = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
|
||||
iso.setCalendar(new GregorianCalendar(new SimpleTimeZone(0,"UTC")));
|
||||
s_iso8601 = iso;
|
||||
|
||||
} // end static initializer
|
||||
|
||||
} // end class XmlRpcResult
|
||||
|
|
|
@ -0,0 +1,868 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1
|
||||
* (the "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Venice Web Communities System.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
|
||||
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
|
||||
* Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.dynamo.xmlrpc;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.ref.Reference;
|
||||
import java.sql.Blob;
|
||||
import java.sql.SQLException;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import javax.mail.*;
|
||||
import javax.mail.internet.*;
|
||||
import org.w3c.dom.*;
|
||||
import com.silverwrist.util.*;
|
||||
import com.silverwrist.util.xml.*;
|
||||
import com.silverwrist.dynamo.except.*;
|
||||
import com.silverwrist.dynamo.iface.*;
|
||||
|
||||
public class XmlRpcSerializer
|
||||
{
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Static data members
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private static XmlRpcSerializer _self = null;
|
||||
|
||||
private static final String SERIALIZED_NULL = "<string>null</string>";
|
||||
private static final String START_ARRAY = "<array><data>\r\n";
|
||||
private static final String END_ARRAY = "</data></array>";
|
||||
private static final String START_VALUE = "<value>";
|
||||
private static final String END_VALUE = "</value>\r\n";
|
||||
|
||||
// Indicates the types of values associated with the request.
|
||||
private static final int ITYP_INTEGER = 0; // integer
|
||||
private static final int ITYP_BOOLEAN = 1; // Boolean
|
||||
private static final int ITYP_STRING = 2; // string
|
||||
private static final int ITYP_DOUBLE = 3; // double
|
||||
private static final int ITYP_DATETIME = 4; // date/time
|
||||
private static final int ITYP_BINARY = 5; // binary (byte array)
|
||||
private static final int ITYP_STRUCT = 6; // struct (Map)
|
||||
private static final int ITYP_ARRAY = 7; // array (List)
|
||||
|
||||
private static final String EMPTY_STRING = "";
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Attributes
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private final DateFormat m_iso8601; // the ISO 8601 date format
|
||||
private final Map m_type_map; // mapping of type values to indices
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Constructor
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
private XmlRpcSerializer()
|
||||
{
|
||||
// Initialize the ISO 8601 date formatter.
|
||||
SimpleDateFormat iso = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
|
||||
iso.setCalendar(new GregorianCalendar(new SimpleTimeZone(0,"UTC")));
|
||||
m_iso8601 = iso;
|
||||
|
||||
// Initialize the type map.
|
||||
HashMap tmp = new HashMap();
|
||||
Integer foo = new Integer(ITYP_INTEGER);
|
||||
tmp.put("i4",foo);
|
||||
tmp.put("int",foo);
|
||||
tmp.put("boolean",new Integer(ITYP_BOOLEAN));
|
||||
tmp.put("string",new Integer(ITYP_STRING));
|
||||
tmp.put("double",new Integer(ITYP_DOUBLE));
|
||||
tmp.put("dateTime.iso8601",new Integer(ITYP_DATETIME));
|
||||
tmp.put("base64",new Integer(ITYP_BINARY));
|
||||
tmp.put("struct",new Integer(ITYP_STRUCT));
|
||||
tmp.put("array",new Integer(ITYP_ARRAY));
|
||||
m_type_map = Collections.unmodifiableMap(tmp);
|
||||
|
||||
} // end constructor
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* Internal operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Deserializes an XML-RPC <struct/> element.
|
||||
*
|
||||
* @param elt The node coresponding to the <struct/> element.
|
||||
* @return The parsed value.
|
||||
* @exception com.silverwrist.dynamo.xmlrpc.FaultCode If an error occurs in parsing the value.
|
||||
*/
|
||||
private final Map deserializeStruct(Element elt) throws FaultCode
|
||||
{
|
||||
XMLLoader loader = XMLLoader.get();
|
||||
HashMap rc = new HashMap();
|
||||
try
|
||||
{ // get all <member/> sub-elements and process them
|
||||
List l = loader.getMatchingSubElements(elt,"member");
|
||||
Iterator it = l.iterator();
|
||||
while (it.hasNext())
|
||||
{ // get each <member/> and add its <name/> and <value/> to the map
|
||||
Element x = (Element)(it.next());
|
||||
DOMElementHelper h = new DOMElementHelper(x);
|
||||
String name = loader.getSubElementText(h,"name");
|
||||
Element val_elt = loader.getSubElement(h,"value");
|
||||
rc.put(name,deserialize(val_elt));
|
||||
|
||||
} // end while
|
||||
|
||||
} // end try
|
||||
catch (XMLLoadException e)
|
||||
{ // translate load exception
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,e);
|
||||
|
||||
} // end catch
|
||||
|
||||
if (rc.isEmpty())
|
||||
return Collections.EMPTY_MAP;
|
||||
else
|
||||
return Collections.unmodifiableMap(rc);
|
||||
|
||||
} // end deserializeStruct
|
||||
|
||||
/**
|
||||
* Deserializes an XML-RPC <array/> element.
|
||||
*
|
||||
* @param elt The node coresponding to the <array/> element.
|
||||
* @return The parsed value.
|
||||
* @exception com.silverwrist.dynamo.xmlrpc.FaultCode If an error occurs in parsing the value.
|
||||
*/
|
||||
private final List deserializeArray(Element elt) throws FaultCode
|
||||
{
|
||||
XMLLoader loader = XMLLoader.get();
|
||||
ArrayList rc = null;
|
||||
try
|
||||
{ // get the <data/> sub-element
|
||||
Element data_elt = loader.getSubElement(elt,"data");
|
||||
|
||||
// get the values it contains
|
||||
List l = loader.getMatchingSubElements(data_elt,"value");
|
||||
rc = new ArrayList(l.size());
|
||||
Iterator it = l.iterator();
|
||||
while (it.hasNext())
|
||||
{ // parse the <value/> elements and add them to the list
|
||||
Element val_elt = (Element)(it.next());
|
||||
rc.add(deserialize(val_elt));
|
||||
|
||||
} // end while
|
||||
|
||||
} // end try
|
||||
catch (XMLLoadException e)
|
||||
{ // translate load exception
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,e);
|
||||
|
||||
} // end catch
|
||||
|
||||
if ((rc==null) || rc.isEmpty())
|
||||
return Collections.EMPTY_LIST;
|
||||
else
|
||||
return Collections.unmodifiableList(rc);
|
||||
|
||||
} // end deserializeArray
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* External operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public void serializeBinary(Writer wr, InputStream stm) throws IOException
|
||||
{
|
||||
try
|
||||
{ // Encode the data as BASE-64.
|
||||
ByteArrayOutputStream internal_stm = new ByteArrayOutputStream();
|
||||
OutputStream encode_stm = MimeUtility.encode(internal_stm,"base64");
|
||||
IOUtils.copy(stm,encode_stm);
|
||||
encode_stm.flush();
|
||||
|
||||
// turn our encoded output into an InputStream
|
||||
ByteArrayInputStream internal2_stm = new ByteArrayInputStream(internal_stm.toByteArray());
|
||||
IOUtils.shutdown(encode_stm);
|
||||
IOUtils.shutdown(internal_stm);
|
||||
|
||||
// write out the data
|
||||
InputStreamReader rd = new InputStreamReader(internal2_stm,"US-ASCII");
|
||||
wr.write("<base64>");
|
||||
IOUtils.copy(rd,wr);
|
||||
wr.write("</base64>");
|
||||
IOUtils.shutdown(rd);
|
||||
IOUtils.shutdown(internal2_stm);
|
||||
|
||||
} // end try
|
||||
catch (MessagingException e)
|
||||
{ // encoder might have an error
|
||||
throw new IOException("error encoding binary data");
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end serializeBinary
|
||||
|
||||
public void serialize(Writer wr, boolean b) throws IOException
|
||||
{
|
||||
wr.write("<boolean>");
|
||||
wr.write(b ? "1" : "0");
|
||||
wr.write("</boolean>");
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, boolean[] b) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<b.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,b[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, byte b) throws IOException
|
||||
{
|
||||
serialize(wr,(int)b);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, byte[] b) throws IOException
|
||||
{
|
||||
serializeBinary(wr,new ByteArrayInputStream(b));
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, char c) throws IOException
|
||||
{
|
||||
char[] xa = new char[] { c };
|
||||
serializeString(wr,new String(xa));
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, char[] c) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<c.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,c[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, short s) throws IOException
|
||||
{
|
||||
serialize(wr,(int)s);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, short[] s) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<s.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,s[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, int i) throws IOException
|
||||
{
|
||||
wr.write("<int>");
|
||||
wr.write(String.valueOf(i));
|
||||
wr.write("</int>");
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, int[] ia) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<ia.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,ia[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, long l) throws IOException
|
||||
{
|
||||
serialize(wr,(double)l);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, long[] l) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<l.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,l[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, float f) throws IOException
|
||||
{
|
||||
serialize(wr,(double)f);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, float[] f) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<f.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,f[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, double d) throws IOException
|
||||
{
|
||||
wr.write("<double>");
|
||||
wr.write(String.valueOf(d));
|
||||
wr.write("</double>");
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, double[] d) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<d.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,d[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serializeCalendar(Writer wr, Calendar cal) throws IOException
|
||||
{
|
||||
wr.write("<dateTime.iso8601>");
|
||||
|
||||
// Encode the year first.
|
||||
StringBuffer conv = new StringBuffer("0000");
|
||||
conv.append(cal.get(Calendar.YEAR));
|
||||
String c = conv.toString();
|
||||
wr.write(c.substring(c.length()-4));
|
||||
|
||||
// Now the month...
|
||||
conv.setLength(0);
|
||||
conv.append("00").append(cal.get(Calendar.MONTH) - Calendar.JANUARY + 1);
|
||||
c = conv.toString();
|
||||
wr.write(c.substring(c.length()-2));
|
||||
|
||||
// And the day...
|
||||
conv.setLength(0);
|
||||
conv.append("00").append(cal.get(Calendar.DAY_OF_MONTH));
|
||||
c = conv.toString();
|
||||
wr.write(c.substring(c.length()-2));
|
||||
wr.write("T");
|
||||
|
||||
// And the hour...
|
||||
conv.setLength(0);
|
||||
conv.append("00").append(cal.get(Calendar.HOUR_OF_DAY));
|
||||
c = conv.toString();
|
||||
wr.write(c.substring(c.length()-2));
|
||||
wr.write(":");
|
||||
|
||||
// And the minute...
|
||||
conv.setLength(0);
|
||||
conv.append("00").append(cal.get(Calendar.MINUTE));
|
||||
c = conv.toString();
|
||||
wr.write(c.substring(c.length()-2));
|
||||
wr.write(":");
|
||||
|
||||
// And the second...
|
||||
conv.setLength(0);
|
||||
conv.append("00").append(cal.get(Calendar.SECOND));
|
||||
c = conv.toString();
|
||||
wr.write(c.substring(c.length()-2));
|
||||
|
||||
// And we're done!
|
||||
wr.write("</dateTime.iso8601>");
|
||||
|
||||
} // end serializeCalendar
|
||||
|
||||
public void serializeCollection(Writer wr, Collection coll) throws IOException
|
||||
{
|
||||
serializeIterator(wr,coll.iterator());
|
||||
|
||||
} // end serializeCollection
|
||||
|
||||
public void serializeDate(Writer wr, Date d) throws IOException
|
||||
{
|
||||
wr.write("<dateTime.iso8601>");
|
||||
wr.write(m_iso8601.format(d));
|
||||
wr.write("</dateTime.iso8601>");
|
||||
|
||||
} // end serializeDate
|
||||
|
||||
public void serializeEnumeration(Writer wr, Enumeration enum) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
while (enum.hasMoreElements())
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,enum.nextElement());
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serializeIterator
|
||||
|
||||
public void serializeIterator(Writer wr, Iterator it) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
while (it.hasNext())
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,it.next());
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serializeIterator
|
||||
|
||||
public void serializeMap(Writer wr, Map map) throws IOException
|
||||
{
|
||||
wr.write("<struct>\r\n");
|
||||
Iterator it = map.entrySet().iterator();
|
||||
while (it.hasNext())
|
||||
{ // write each entry in turn
|
||||
Map.Entry ntry = (Map.Entry)(it.next());
|
||||
wr.write("<member>\r\n<name>");
|
||||
wr.write(StringUtils.encodeHTML(ntry.getKey().toString()));
|
||||
wr.write("</name>\r\n<value>");
|
||||
serialize(wr,ntry.getValue());
|
||||
wr.write("</value>\r\n</member>");
|
||||
|
||||
} // end while
|
||||
|
||||
wr.write("\r\n</struct>");
|
||||
|
||||
} // end serializeMap
|
||||
|
||||
public void serializeString(Writer wr, String s) throws IOException
|
||||
{
|
||||
wr.write("<string>");
|
||||
wr.write(StringUtils.encodeHTML(s));
|
||||
wr.write("</string>");
|
||||
|
||||
} // end serializeString
|
||||
|
||||
public void serialize(Writer wr, Object obj) throws IOException
|
||||
{
|
||||
if (obj==null)
|
||||
{ // null object - bye!
|
||||
wr.write(SERIALIZED_NULL);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj.getClass().isArray())
|
||||
{ // for arrays, serialize them specially
|
||||
Class component = obj.getClass().getComponentType();
|
||||
if (component==Boolean.TYPE)
|
||||
serialize(wr,(boolean[])obj);
|
||||
else if (component==Byte.TYPE)
|
||||
serialize(wr,(byte[])obj);
|
||||
else if (component==Character.TYPE)
|
||||
serialize(wr,(char[])obj);
|
||||
else if (component==Short.TYPE)
|
||||
serialize(wr,(short[])obj);
|
||||
else if (component==Integer.TYPE)
|
||||
serialize(wr,(int[])obj);
|
||||
else if (component==Long.TYPE)
|
||||
serialize(wr,(long[])obj);
|
||||
else if (component==Float.TYPE)
|
||||
serialize(wr,(float[])obj);
|
||||
else if (component==Double.TYPE)
|
||||
serialize(wr,(double[])obj);
|
||||
else
|
||||
serialize(wr,(Object[])obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof XmlRpcSelfSerializing)
|
||||
{ // some objects may be self-serializing
|
||||
((XmlRpcSelfSerializing)obj).serializeXmlRpc(wr);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof DynamicWrapper)
|
||||
{ // for dynamic wrappers, unwrap them
|
||||
serialize(wr,((DynamicWrapper)obj).unwrap());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof InputStream)
|
||||
{ // for InputStream, turn it into binary
|
||||
serializeBinary(wr,(InputStream)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Blob)
|
||||
{ // serialize the blob as a binary stream
|
||||
try
|
||||
{ // just get its input stream
|
||||
serializeBinary(wr,((Blob)obj).getBinaryStream());
|
||||
return;
|
||||
|
||||
} // end try
|
||||
catch (SQLException e)
|
||||
{ // fault on error here
|
||||
throw new IOException("error writing binary data");
|
||||
|
||||
} // end catch
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Calendar)
|
||||
{ // serialize a Calendar
|
||||
serializeCalendar(wr,(Calendar)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Collection)
|
||||
{ // serialize a Collection
|
||||
serializeCollection(wr,(Collection)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Date)
|
||||
{ // serialize a Date
|
||||
serializeDate(wr,(Date)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Enumeration)
|
||||
{ // serialize a Enumeration
|
||||
serializeEnumeration(wr,(Enumeration)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Iterator)
|
||||
{ // serialize a Iterator
|
||||
serializeIterator(wr,(Iterator)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Map)
|
||||
{ // serialize a Map
|
||||
serializeMap(wr,(Map)obj);
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Reference)
|
||||
{ // for a Reference, serialize the referent
|
||||
serialize(wr,((Reference)obj).get());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Boolean)
|
||||
{ // serialize the boolean value
|
||||
serialize(wr,((Boolean)obj).booleanValue());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if (obj instanceof Character)
|
||||
{ // serialize the character value
|
||||
serialize(wr,((Character)obj).charValue());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if ((obj instanceof Byte) || (obj instanceof Short) || (obj instanceof Integer))
|
||||
{ // serialize the integer value
|
||||
serialize(wr,((Number)obj).intValue());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
if ((obj instanceof Long) || (obj instanceof Float) || (obj instanceof Double))
|
||||
{ // serialize the double value
|
||||
serialize(wr,((Number)obj).doubleValue());
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
// String and StringBuffer are handled properly by the fallback mechanism below
|
||||
|
||||
// last-ditch fallback method - use toString, get the string, and encode it
|
||||
serializeString(wr,obj.toString());
|
||||
|
||||
} // end serialize
|
||||
|
||||
public void serialize(Writer wr, Object[] arr) throws IOException
|
||||
{
|
||||
wr.write(START_ARRAY);
|
||||
for (int i=0; i<arr.length; i++)
|
||||
{ // serialize the values we contain
|
||||
wr.write(START_VALUE);
|
||||
serialize(wr,arr[i]);
|
||||
wr.write(END_VALUE);
|
||||
|
||||
} // end for
|
||||
|
||||
wr.write(END_ARRAY);
|
||||
|
||||
} // end serialize
|
||||
|
||||
/**
|
||||
* Deserializes an XML-RPC <value/> element.
|
||||
*
|
||||
* @param elt The node coresponding to the <value/> element.
|
||||
* @return The parsed value.
|
||||
* @exception com.silverwrist.dynamo.xmlrpc.FaultCode If an error occurs in parsing the value.
|
||||
*/
|
||||
public Object deserialize(Element elt) throws FaultCode
|
||||
{
|
||||
NodeList nl = elt.getChildNodes();
|
||||
Element type_spec = null;
|
||||
for (int i=0; i<nl.getLength(); i++)
|
||||
{ // look through the subelements to find the type-specific element
|
||||
Node n = nl.item(i);
|
||||
if (n.getNodeType()!=Node.ELEMENT_NODE)
|
||||
continue;
|
||||
if (type_spec!=null)
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,
|
||||
"more than one type-specifying element within a <value/> element");
|
||||
type_spec = (Element)n;
|
||||
|
||||
} // end for
|
||||
|
||||
Object rc = null;
|
||||
if (type_spec!=null)
|
||||
{ // figure out what type this element is
|
||||
Integer tval = (Integer)(m_type_map.get(type_spec.getTagName()));
|
||||
if (tval==null)
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid type \"" + type_spec.getTagName() + "\"");
|
||||
DOMElementHelper h = new DOMElementHelper(type_spec);
|
||||
switch (tval.intValue())
|
||||
{ // based on the type, act on the contents
|
||||
case ITYP_INTEGER:
|
||||
try
|
||||
{ // parse the integer value
|
||||
rc = new Integer(Integer.parseInt(h.getElementText(),10));
|
||||
|
||||
} // end try
|
||||
catch (NumberFormatException e)
|
||||
{ // value wasn't an integer
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid integer format",e);
|
||||
|
||||
} // end catch
|
||||
catch (NullPointerException e)
|
||||
{ // value was null
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"integer value not specified");
|
||||
|
||||
} // end catch
|
||||
break;
|
||||
|
||||
case ITYP_BOOLEAN:
|
||||
{ // test the Boolean value
|
||||
String s = h.getElementText();
|
||||
if (s==null)
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"boolean value not specified");
|
||||
if (s.equals("1"))
|
||||
rc = Boolean.TRUE;
|
||||
else if (s.equals("0"))
|
||||
rc = Boolean.FALSE;
|
||||
else
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid boolean format");
|
||||
|
||||
} // end case
|
||||
break;
|
||||
|
||||
case ITYP_STRING:
|
||||
{ // get the string value and return it
|
||||
rc = h.getElementText();
|
||||
if (rc==null)
|
||||
rc = EMPTY_STRING;
|
||||
|
||||
} // end case
|
||||
break;
|
||||
|
||||
case ITYP_DOUBLE:
|
||||
try
|
||||
{ // convert to a Double value
|
||||
rc = new Double(h.getElementText());
|
||||
|
||||
} // end try
|
||||
catch (NumberFormatException e)
|
||||
{ // value wasn't an integer
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid double format",e);
|
||||
|
||||
} // end catch
|
||||
catch (NullPointerException e)
|
||||
{ // value was null
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"double value not specified");
|
||||
|
||||
} // end catch
|
||||
break;
|
||||
|
||||
case ITYP_DATETIME:
|
||||
try
|
||||
{ // convert to a Date value
|
||||
rc = m_iso8601.parse(h.getElementText());
|
||||
|
||||
} // end try
|
||||
catch (java.text.ParseException e)
|
||||
{ // date couldn't be parsed
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid ISO 8601 date format",e);
|
||||
|
||||
} // end catch
|
||||
catch (NullPointerException e)
|
||||
{ // no value in there...
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"date value not specified");
|
||||
|
||||
} // end catch
|
||||
break;
|
||||
|
||||
case ITYP_BINARY:
|
||||
try
|
||||
{ // get the string equivalent of the formatted data
|
||||
String s = h.getElementText();
|
||||
if (s==null)
|
||||
{ // null string - return null array
|
||||
rc = new byte[0];
|
||||
break;
|
||||
|
||||
} // end if
|
||||
|
||||
// get a stream of encoded bytes
|
||||
ByteArrayInputStream encoded_stm = new ByteArrayInputStream(s.getBytes("US-ASCII"));
|
||||
|
||||
// use the JavaMail MIME decoder to turn it into decoded bytes
|
||||
InputStream decoded_stm = MimeUtility.decode(encoded_stm,"base64");
|
||||
|
||||
// copy the decoded bytes to a new array
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
IOUtils.copy(decoded_stm,output);
|
||||
IOUtils.shutdown(decoded_stm);
|
||||
IOUtils.shutdown(encoded_stm);
|
||||
|
||||
// retrieve the output array
|
||||
rc = output.toByteArray();
|
||||
IOUtils.shutdown(output);
|
||||
|
||||
} // end try
|
||||
catch (UnsupportedEncodingException e)
|
||||
{ // WTF? shouldn't happen
|
||||
throw new SystemFaultCode(SystemFaultCode.INTERNAL_ERROR,"internal error: unsupported encoding",e);
|
||||
|
||||
} // end catch
|
||||
catch (IOException e)
|
||||
{ // some sort of error copying binary values around
|
||||
throw new SystemFaultCode(SystemFaultCode.INTERNAL_ERROR,"unable to get binary data",e);
|
||||
|
||||
} // end catch
|
||||
catch (MessagingException e)
|
||||
{ // error in the MIME parsing - dump it out
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid binary data format",e);
|
||||
|
||||
} // end catch
|
||||
break;
|
||||
|
||||
case ITYP_STRUCT:
|
||||
rc = deserializeStruct(type_spec);
|
||||
break;
|
||||
|
||||
case ITYP_ARRAY:
|
||||
rc = deserializeArray(type_spec);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new SystemFaultCode(SystemFaultCode.INVALID_REQUEST,"invalid type \""
|
||||
+ type_spec.getTagName() + "\"");
|
||||
|
||||
} // end switch
|
||||
|
||||
} // end if
|
||||
else
|
||||
{ // if there's no type-specifying element, treat it as a String
|
||||
DOMElementHelper h = new DOMElementHelper(elt);
|
||||
rc = h.getElementText();
|
||||
if (rc==null)
|
||||
rc = EMPTY_STRING;
|
||||
|
||||
} // end else
|
||||
|
||||
return rc;
|
||||
|
||||
} // end deserialize
|
||||
|
||||
/*--------------------------------------------------------------------------------
|
||||
* External static operations
|
||||
*--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public static XmlRpcSerializer get()
|
||||
{
|
||||
if (_self==null)
|
||||
_self = new XmlRpcSerializer();
|
||||
return _self;
|
||||
|
||||
} // end get
|
||||
|
||||
} // end class XmlRpcSerializer
|
Loading…
Reference in New Issue
Block a user