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.io.*;
|
||||||
import java.text.*;
|
import java.text.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import javax.mail.*;
|
|
||||||
import javax.mail.internet.*;
|
|
||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
import javax.servlet.http.*;
|
import javax.servlet.http.*;
|
||||||
import org.w3c.dom.*;
|
import org.w3c.dom.*;
|
||||||
import com.silverwrist.util.*;
|
|
||||||
import com.silverwrist.util.xml.*;
|
import com.silverwrist.util.xml.*;
|
||||||
import com.silverwrist.dynamo.RequestType;
|
import com.silverwrist.dynamo.RequestType;
|
||||||
import com.silverwrist.dynamo.Verb;
|
import com.silverwrist.dynamo.Verb;
|
||||||
|
@ -42,27 +39,6 @@ import com.silverwrist.dynamo.util.*;
|
||||||
*/
|
*/
|
||||||
class XmlRpcRequest extends BaseDelegatingServiceProvider implements Request
|
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
|
* Attributes
|
||||||
*--------------------------------------------------------------------------------
|
*--------------------------------------------------------------------------------
|
||||||
|
@ -120,6 +96,7 @@ class XmlRpcRequest extends BaseDelegatingServiceProvider implements Request
|
||||||
|
|
||||||
} // end catch
|
} // end catch
|
||||||
|
|
||||||
|
XmlRpcSerializer serializer = XmlRpcSerializer.get();
|
||||||
try
|
try
|
||||||
{ // load the XML body of the request, get the method name and parameters
|
{ // load the XML body of the request, get the method name and parameters
|
||||||
Element method_call = loader.getRootElement(request_doc,"methodCall");
|
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
|
{ // get the <value/> subelement from each <param/> and store it
|
||||||
Element elt = (Element)(it.next());
|
Element elt = (Element)(it.next());
|
||||||
Element value_elt = loader.getSubElement(elt,"value");
|
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
|
} // end while
|
||||||
|
|
||||||
|
@ -155,274 +132,6 @@ class XmlRpcRequest extends BaseDelegatingServiceProvider implements Request
|
||||||
|
|
||||||
} // end constructor
|
} // 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
|
* Implementations from interface ObjectProvider
|
||||||
*--------------------------------------------------------------------------------
|
*--------------------------------------------------------------------------------
|
||||||
|
@ -670,31 +379,4 @@ class XmlRpcRequest extends BaseDelegatingServiceProvider implements Request
|
||||||
|
|
||||||
} // end getLocales
|
} // 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
|
} // end class XmlRpcRequest
|
||||||
|
|
|
@ -11,40 +11,19 @@
|
||||||
*
|
*
|
||||||
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
|
* 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
|
* 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):
|
* Contributor(s):
|
||||||
*/
|
*/
|
||||||
package com.silverwrist.dynamo.xmlrpc;
|
package com.silverwrist.dynamo.xmlrpc;
|
||||||
|
|
||||||
import java.io.*;
|
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.HttpStatusCode;
|
||||||
import com.silverwrist.dynamo.except.*;
|
import com.silverwrist.dynamo.except.*;
|
||||||
import com.silverwrist.dynamo.iface.*;
|
import com.silverwrist.dynamo.iface.*;
|
||||||
|
|
||||||
public class XmlRpcResult implements SelfRenderable, XmlRpcSelfSerializing
|
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
|
* Attributes
|
||||||
*--------------------------------------------------------------------------------
|
*--------------------------------------------------------------------------------
|
||||||
|
@ -73,7 +52,7 @@ public class XmlRpcResult implements SelfRenderable, XmlRpcSelfSerializing
|
||||||
// Serialize the output value to a StringWriter.
|
// Serialize the output value to a StringWriter.
|
||||||
StringWriter wr = new StringWriter();
|
StringWriter wr = new StringWriter();
|
||||||
wr.write("<methodResponse><params><param>\r\n<value>");
|
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");
|
wr.write("</value>\r\n</param></params></methodResponse>\r\n");
|
||||||
|
|
||||||
// Now render the binary equivalent of this structure.
|
// 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
|
public void serializeXmlRpc(Writer wr) throws IOException
|
||||||
{
|
{
|
||||||
serialize(wr,m_obj);
|
XmlRpcSerializer.get().serialize(wr,m_obj);
|
||||||
|
|
||||||
} // end serializeXmlRpc
|
} // 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
|
} // 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