21 |
* |
* |
22 |
* -------------------------------------------------------------------------- |
* -------------------------------------------------------------------------- |
23 |
*/ |
*/ |
24 |
namespace DotGNU.XmlRpc |
using System; |
25 |
{ |
using System.Collections; |
26 |
using System; |
using System.IO; |
27 |
using System.IO; |
using System.CodeDom.Compiler; |
|
using System.Globalization; |
|
|
using System.Collections; |
|
|
using System.Reflection; |
|
|
using System.Text; |
|
|
using System.Xml; |
|
28 |
|
|
|
public enum XmlRpcParamType |
|
|
{ |
|
|
tInvalid, |
|
|
tInt32, |
|
|
tBoolean, |
|
|
tString, |
|
|
tDouble, |
|
|
tDateTime, |
|
|
tBase64, |
|
|
tStruct, |
|
|
tHashtable, |
|
|
tArray, |
|
|
tMultiDimArray, |
|
|
tVoid |
|
|
} |
|
29 |
|
|
30 |
public class XmlRpcSerializer |
namespace DotGNU.XmlRpc |
31 |
|
{ |
32 |
|
|
33 |
|
// For now, indentation is the default since it makes it easier for |
34 |
|
// a human to read the output. later the output should not be |
35 |
|
// formatted at all. ideally it should be an unindented block |
36 |
|
public class XmlRpcWriter |
37 |
{ |
{ |
38 |
|
private IndentedTextWriter writer; |
39 |
/* |
private StringWriter sw; |
40 |
public XmlRpcRequest DeserializeRequest( Stream stream ) |
private XmlRpcMethod m; |
41 |
{ |
|
42 |
XmlRpcRequest xmlReq = new XmlRpcRequest(); |
public XmlRpcWriter() |
43 |
|
{ |
44 |
return xmlReq; |
sw = new StringWriter(); |
45 |
} |
writer = new IndentedTextWriter( sw, " " ); |
46 |
*/ |
} |
47 |
|
|
48 |
// The original prototype, changed to StringBuilder for the first release |
private void WriteHead() |
49 |
// of DGEE |
{ |
50 |
// TODO: Put this back to using Streams |
writer.WriteLine( "<?xml version=\"1.0\"?>" ); |
51 |
public void SerializeResponse( Stream stream, XmlRpcResponse reply ) {} |
writer.WriteLine( "<methodResponse>" ); |
52 |
|
writer.Indent++; |
53 |
public StringBuilder SerializeResponse( XmlRpcResponse reply ) |
writer.WriteLine( "<params>" ); |
54 |
{ |
writer.Indent++; |
55 |
StringBuilder xmldoc = new StringBuilder(); |
writer.WriteLine( "<param>" ); |
56 |
|
writer.Indent++; |
57 |
xmldoc.Append( "<?xml version=\"1.0\"?>\n" ); |
writer.WriteLine( "<value>" ); |
58 |
xmldoc.Append( "<methodResponse>\n <params>\n <param>\n" ); |
writer.Indent++; |
59 |
|
} |
60 |
xmldoc.Append( SerializeObject( reply.retVal ) ); |
|
61 |
|
private void WriteTail() |
62 |
xmldoc.Append( " </param>\n </params>\n</methodResponse>\n" ); |
{ |
63 |
|
writer.Indent--; |
64 |
// StreamWriter sw = new StreamWriter( stream, Encoding.ASCII ); |
writer.WriteLine( "</value>" ); |
65 |
// sw.Write( xmldoc ); |
writer.Indent--; |
66 |
// sw.Flush(); |
writer.WriteLine( "</param>" ); |
67 |
|
writer.Indent--; |
68 |
return xmldoc; |
writer.WriteLine( "</params>" ); |
69 |
} |
writer.Indent--; |
70 |
|
writer.WriteLine( "</methodResponse>" ); |
71 |
struct XmlFaultStruct |
} |
72 |
{ |
|
73 |
public int faultCode; |
private void Write( object o ) |
74 |
public string faultString; |
{ |
75 |
} |
string tag; |
76 |
|
if( o is int ) { |
77 |
// The original prototype, changed to StringBuilder for the first release |
tag = "i4"; |
78 |
// of DGEE |
WriteObject( tag, o ); |
79 |
// TODO: Put this back to using Streams |
} |
80 |
public void SerializeFault( Stream stream, XmlRpcFaultException rfault ) {} |
else if( o is double ) { |
81 |
|
tag = "double"; |
82 |
public StringBuilder SerializeFault( XmlRpcFaultException rfault ) |
WriteObject( tag, o ); |
83 |
{ |
} |
84 |
XmlFaultStruct f; |
else if( o is string ) { |
85 |
|
tag = "string"; |
86 |
Console.WriteLine( "SerializeFault: A" ); |
WriteObject( tag, o ); |
87 |
StringBuilder xmldoc = new StringBuilder(); |
} |
88 |
|
else if( o is bool ) { |
89 |
Console.WriteLine( "SerializeFault: B" ); |
tag = "boolean"; |
90 |
f.faultCode = rfault.FaultCode + 100; |
WriteObject( tag, o ); |
91 |
f.faultString = rfault.FaultString; |
} |
92 |
|
else if( o is DateTime ) { |
93 |
Console.WriteLine( "SerializeFault: C" ); |
tag = "dateTime.iso8601"; |
94 |
xmldoc.Append( "<?xml version=\"1.0\"?>\n" ); |
WriteObject( tag, o ); |
95 |
xmldoc.Append( "<methodResponse>\n <fault>\n" ); |
} |
96 |
|
else if( o is byte[] ) { |
97 |
Console.WriteLine( "SerializeFault: D" ); |
tag = "base64"; |
98 |
xmldoc.Append( SerializeObject( f ) ); |
WriteObject( tag, o ); |
99 |
|
} |
100 |
// Fake struct output until SerilizeObject( -struct- ) works |
else if( o is XmlRpcStruct ) { |
101 |
// --------------------------------------------------------- |
tag = "struct"; |
102 |
/* |
writer.WriteLine( "<struct>" ); |
103 |
xmldoc.Append( " <value>\n <struct>\n <member>\n" ); |
writer.Indent++; |
104 |
xmldoc.Append( " <name>" ); |
|
105 |
xmldoc.Append( "faultCode" ); |
foreach( DictionaryEntry entry in (XmlRpcStruct)o ) { |
106 |
xmldoc.Append( "</name>\n" ); |
writer.WriteLine( "<member>" ); |
107 |
xmldoc.Append( SerializeObject( f.code ) ); |
writer.Indent++; |
108 |
xmldoc.Append( " </member>\n" ); |
writer.WriteLine( "<name>" ); |
109 |
xmldoc.Append( " <member>\n" ); |
writer.Indent++; |
110 |
xmldoc.Append( " <name>" ); |
writer.WriteLine( entry.Key ); |
111 |
xmldoc.Append( "faultString" ); |
writer.Indent--; |
112 |
xmldoc.Append( "</name>\n" ); |
writer.WriteLine( "</name>" ); |
113 |
xmldoc.Append( SerializeObject( f.text ) ); |
writer.WriteLine( "<value>" ); |
114 |
xmldoc.Append( " </member>\n" ); |
writer.Indent++; |
115 |
|
this.Write( entry.Value ); |
116 |
xmldoc.Append( " </struct>\n</value>\n" ); |
writer.Indent--; |
117 |
*/ |
writer.WriteLine( "</value>" ); |
118 |
// --------------------------------------------------------- |
writer.Indent--; |
119 |
|
writer.WriteLine( "</member>" ); |
120 |
Console.WriteLine( "SerializeFault: E" ); |
} |
121 |
xmldoc.Append( " </fault>\n</methodResponse>\n" ); |
writer.Indent--; |
122 |
|
writer.WriteLine( "</struct>" ); |
|
// StreamWriter sw = new StreamWriter( stream, Encoding.ASCII ); |
|
|
// sw.Write( xmldoc ); |
|
|
// sw.Flush(); |
|
|
|
|
|
Console.WriteLine( "SerializeFault: F" ); |
|
|
return xmldoc; |
|
|
} |
|
|
|
|
|
public Object [] MarshallRequestParameters( Object []plist ) |
|
|
{ |
|
|
Object[] margs = new Object[plist.Length]; |
|
|
|
|
|
int i = 0; |
|
|
foreach(XmlRpcParameter xparam in plist) |
|
|
{ |
|
|
margs[i++] = MarshallRequestParameter( xparam ); |
|
|
} |
|
|
|
|
|
return margs; |
|
|
} |
|
|
|
|
|
public Object MarshallRequestParameter( XmlRpcParameter xparam ) |
|
|
{ |
|
|
Object robj = null; |
|
|
|
|
|
// TODO Validate that the current parameter is of a type expected |
|
|
// by the method being called - This is not strictly necessary |
|
|
// when being used in the DGEE as the ServiceManager will |
|
|
// verify that the parameter signature of the request |
|
|
// matches that of the method. |
|
|
// |
|
|
// There is nothing wrong in verifying that |
|
|
// the parameters in the request match the types in the dgmx file and |
|
|
// the type of the actual method, when we can. We can in C#, we may |
|
|
// not be able to in other languages. |
|
|
|
|
|
switch( xparam.type ) |
|
|
{ |
|
|
case "i4": |
|
|
case "int" : robj = ParseInt ( xparam ); break; |
|
|
case "string" : robj = ParseString ( xparam ); break; |
|
|
case "boolean": robj = ParseBoolean( xparam ); break; |
|
|
case "double" : robj = ParseDouble ( xparam ); break; |
|
|
case "base64" : robj = ParseBase64 ( xparam ); break; |
|
|
|
|
|
case "dateTime.iso8691": robj = ParseDateTime( xparam ); break; |
|
|
|
|
|
case "array" : // TODO not implemented |
|
|
case "struct": // TODO not implemented |
|
|
default: |
|
|
throw new XmlRpcBadParamException( |
|
|
"XML-RPC parameter type " + xparam.type + " is not implemented"); |
|
|
break; |
|
|
} |
|
|
|
|
|
return robj; |
|
|
} |
|
|
|
|
|
Object ParseInt(XmlRpcParameter node ) |
|
|
{ |
|
|
if(node.value == null) |
|
|
{ |
|
|
throw new XmlRpcBadParamException("Integer element is empty"); |
|
|
} |
|
|
try |
|
|
{ |
|
|
return Int32.Parse(node.value.ToString()); |
|
|
} |
|
|
catch(Exception) |
|
|
{ |
|
|
throw new XmlRpcBadParamException( "Integer element is non-numeric." ); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
Object ParseString(XmlRpcParameter node ) |
|
|
{ |
|
|
return node.value; |
|
|
} |
|
|
|
|
|
Object ParseBoolean(XmlRpcParameter node ) |
|
|
{ |
|
|
string s = node.value.ToString(); |
|
|
if (s == "1") |
|
|
{ |
|
|
return true; |
|
|
} |
|
|
else if (s == "0") |
|
|
{ |
|
|
return false; |
|
|
} |
|
|
throw new XmlRpcBadParamException( "Boolean element is invalid."); |
|
|
} |
|
|
|
|
|
Object ParseDouble(XmlRpcParameter node ) |
|
|
{ |
|
|
try |
|
|
{ |
|
|
return Double.Parse( node.value.ToString(), |
|
|
CultureInfo.InvariantCulture.NumberFormat); |
|
|
} |
|
|
catch(Exception) |
|
|
{ |
|
|
throw new XmlRpcBadParamException( "Double element is invalid."); |
|
|
} |
|
|
} |
|
|
|
|
|
Object ParseDateTime(XmlRpcParameter node ) |
|
|
{ |
|
|
string s = node.value.ToString(); |
|
|
try |
|
|
{ |
|
|
DateTime dt = new DateTime( |
|
|
Int32.Parse(s.Substring(0,4)), |
|
|
Int32.Parse(s.Substring(4,2)), |
|
|
Int32.Parse(s.Substring(6,2)), |
|
|
Int32.Parse(s.Substring(9,2)), |
|
|
Int32.Parse(s.Substring(12,2)), |
|
|
Int32.Parse(s.Substring(15,2))); |
|
|
return dt; |
|
123 |
} |
} |
124 |
catch(Exception) |
else if( o is XmlRpcArray ) { |
125 |
{ |
tag = "array"; |
126 |
} |
} |
|
throw new XmlRpcBadParamException( "dateTime element is invalid."); |
|
|
} |
|
|
|
|
|
Object ParseBase64(XmlRpcParameter node ) |
|
|
{ |
|
|
string s = node.value.ToString(); |
|
|
byte[] retBuffer = Convert.FromBase64String(s); |
|
|
return retBuffer; |
|
127 |
} |
} |
128 |
|
|
129 |
public StringBuilder SerializeObjectTree( Object []tree ) |
private void WriteObject( string tag, object o ) |
130 |
{ |
{ |
131 |
StringBuilder sb = new StringBuilder(); |
writer.WriteLine( "<{0}>", tag ); |
132 |
|
writer.Indent++; |
133 |
foreach( Object obj in tree ) |
writer.WriteLine( o ); |
134 |
{ |
writer.Indent--; |
135 |
sb.Append( SerializeObject( obj ) ); |
writer.WriteLine( "</{0}>", tag ); |
|
} |
|
|
return sb; |
|
136 |
} |
} |
137 |
|
|
138 |
public StringBuilder SerializeObject( Object obj ) |
public string Parse( XmlRpcStruct s ) |
139 |
{ |
{ |
140 |
StringBuilder xml = new StringBuilder(); |
WriteHead(); |
141 |
|
Write( s ); |
142 |
try |
WriteTail(); |
|
{ |
|
|
XmlRpcParamType dtype = GetParamType( obj.GetType() ); |
|
|
|
|
|
xml.Append( "<value>" ); |
|
|
|
|
|
switch( dtype ) |
|
|
{ |
|
|
case XmlRpcParamType.tString: |
|
|
xml.Append( "<string>" ); |
|
|
xml.Append( obj.ToString() ); |
|
|
xml.Append( "</string>" ); |
|
|
break; |
|
|
|
|
|
case XmlRpcParamType.tInt32: |
|
|
xml.Append( "<i4>" ); |
|
|
xml.Append( ((Int32)obj).ToString() ); |
|
|
xml.Append( "</i4>" ); |
|
|
break; |
|
|
|
|
|
case XmlRpcParamType.tDouble: |
|
|
xml.Append( "<double>" ); |
|
|
xml.Append( ((double)obj).ToString() ); |
|
|
xml.Append( "</double>" ); |
|
|
break; |
|
|
|
|
|
case XmlRpcParamType.tBoolean: |
|
|
xml.Append( "<boolean>" ); |
|
|
xml.Append( ((bool)obj) ? "1" : "0" ); |
|
|
xml.Append( "</boolean>" ); |
|
|
break; |
|
|
|
|
|
case XmlRpcParamType.tBase64: // TODO Not implemented |
|
|
xml.Append( "<!-- <base64>" ); |
|
|
xml.Append( "Base 64 Serialisation not implemented" ); |
|
|
xml.Append( "</base64> -->" ); |
|
|
break; |
|
|
|
|
|
case XmlRpcParamType.tDateTime: |
|
|
String dt = ((DateTime)obj).ToString("yyyyMMddTHH:mm:ss"); |
|
|
xml.Append( "<dateTime.iso8601>" ); |
|
|
xml.Append( dt ); |
|
|
xml.Append( "</dateTime.iso8601>" ); |
|
|
break; |
|
|
|
|
|
case XmlRpcParamType.tArray: |
|
|
xml.Append( "<array>\n <data>\n " ); |
|
|
foreach ( Object ar_obj in (Array)obj ) |
|
|
{ |
|
|
xml.Append( SerializeObject( ar_obj ) ); |
|
|
} |
|
|
xml.Append( " </data>\n</array>" ); |
|
|
break; |
|
|
|
|
|
case XmlRpcParamType.tStruct: |
|
|
xml.Append( "<struct>\n" ); |
|
|
|
|
|
MemberInfo []miarr = obj.GetType().GetMembers(); |
|
|
foreach( MemberInfo mi in miarr ) |
|
|
{ |
|
|
if( mi.MemberType == MemberTypes.Field ) |
|
|
{ |
|
|
FieldInfo f = (FieldInfo)mi; |
|
|
|
|
|
xml.Append( " <member>\n" ); |
|
|
|
|
|
xml.Append( " <name>" ); |
|
|
xml.Append( f.Name ); |
|
|
xml.Append( "</name>\n" ); |
|
|
|
|
|
xml.Append( SerializeObject( f.GetValue(obj) ) ); |
|
|
|
|
|
xml.Append( " </member>\n" ); |
|
|
} |
|
|
} |
|
|
|
|
|
xml.Append( "</struct>\n" ); |
|
|
break; |
|
|
} |
|
|
|
|
|
xml.Append( "</value>\n" ); |
|
|
|
|
|
} |
|
|
catch(System.NullReferenceException) |
|
|
{ |
|
|
// throw new XmlRpcNullReferenceException( |
|
|
// "Cannot serialize null reference"); |
|
|
} |
|
|
return xml; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
internal static XmlRpcParamType GetParamType( Type t ) |
|
|
{ |
|
|
XmlRpcParamType ret; |
|
|
if ( t == typeof(Int32) ) ret = XmlRpcParamType.tInt32; |
|
|
else if( t == typeof(Boolean) ) ret = XmlRpcParamType.tBoolean; |
|
|
else if( t == typeof(String) ) ret = XmlRpcParamType.tString; |
|
|
else if( t == typeof(Double) ) ret = XmlRpcParamType.tDouble; |
|
|
else if( t == typeof(DateTime) ) ret = XmlRpcParamType.tDateTime; |
|
|
else if( t == typeof(byte[]) ) ret = XmlRpcParamType.tBase64; |
|
|
else if( t == typeof(Array) ) ret = XmlRpcParamType.tArray; |
|
|
// else if (t == typeof(XmlRpcStruct)) |
|
|
// { |
|
|
// ret = XmlRpcParamType.tHashtable; |
|
|
// } |
|
|
else if (t.IsArray) |
|
|
{ |
|
|
// TODO check types of array elements if not Object[] |
|
|
} |
|
|
else if (t == typeof(void)) |
|
|
{ |
|
|
ret = XmlRpcParamType.tVoid; |
|
|
} |
|
|
else if (t.IsValueType && !t.IsPrimitive) |
|
|
{ |
|
|
MemberInfo[] mis = t.GetMembers(); |
|
|
|
|
|
foreach (MemberInfo mi in mis) |
|
|
{ |
|
|
if (mi.MemberType == MemberTypes.Field) |
|
|
{ |
|
|
FieldInfo fi = (FieldInfo)mi; |
|
|
if (GetParamType(fi.FieldType) == XmlRpcParamType.tInvalid) |
|
|
{ |
|
|
return XmlRpcParamType.tInvalid; |
|
|
} |
|
|
} |
|
|
} |
|
|
ret = XmlRpcParamType.tStruct; |
|
|
} |
|
|
else |
|
|
ret = XmlRpcParamType.tInvalid; |
|
143 |
|
|
144 |
return ret; |
return sw.ToString(); |
145 |
} |
} |
146 |
|
|
147 |
|
//public override string ToString() |
148 |
|
//{ |
149 |
|
//} |
150 |
} |
} |
151 |
} |
} |