diff options
Diffstat (limited to 'Common/XmlRpcCS/XmlRpcSystemObject.cs')
-rw-r--r-- | Common/XmlRpcCS/XmlRpcSystemObject.cs | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/Common/XmlRpcCS/XmlRpcSystemObject.cs b/Common/XmlRpcCS/XmlRpcSystemObject.cs new file mode 100644 index 0000000..5f79951 --- /dev/null +++ b/Common/XmlRpcCS/XmlRpcSystemObject.cs | |||
@@ -0,0 +1,252 @@ | |||
1 | namespace Nwc.XmlRpc | ||
2 | { | ||
3 | using System; | ||
4 | using System.Collections; | ||
5 | using System.Reflection; | ||
6 | |||
7 | /// <summary> XML-RPC System object implementation of extended specifications.</summary> | ||
8 | [XmlRpcExposed] | ||
9 | public class XmlRpcSystemObject | ||
10 | { | ||
11 | private XmlRpcServer _server; | ||
12 | static private IDictionary _methodHelp = new Hashtable(); | ||
13 | |||
14 | /// <summary>Static <c>IDictionary</c> to hold mappings of method name to associated documentation String</summary> | ||
15 | static public IDictionary MethodHelp | ||
16 | { | ||
17 | get { return _methodHelp; } | ||
18 | } | ||
19 | |||
20 | /// <summary>Constructor.</summary> | ||
21 | /// <param name="server"><c>XmlRpcServer</c> server to be the system object for.</param> | ||
22 | public XmlRpcSystemObject(XmlRpcServer server) | ||
23 | { | ||
24 | _server = server; | ||
25 | server.Add("system", this); | ||
26 | _methodHelp.Add(this.GetType().FullName + ".methodHelp", "Return a string description."); | ||
27 | } | ||
28 | |||
29 | /// <summary>Invoke a method on a given object.</summary> | ||
30 | /// <remarks>Using reflection, and respecting the <c>XmlRpcExposed</c> attribute, | ||
31 | /// invoke the <paramref>methodName</paramref> method on the <paramref>target</paramref> | ||
32 | /// instance with the <paramref>parameters</paramref> provided. All this packages other <c>Invoke</c> methods | ||
33 | /// end up calling this.</remarks> | ||
34 | /// <returns><c>Object</c> the value the invoked method returns.</returns> | ||
35 | /// <exception cref="XmlRpcException">If method does not exist, is not exposed, parameters invalid, or invocation | ||
36 | /// results in an exception. Note, the <c>XmlRpcException.Code</c> will indicate cause.</exception> | ||
37 | static public Object Invoke(Object target, String methodName, IList parameters) | ||
38 | { | ||
39 | if (target == null) | ||
40 | throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD, | ||
41 | XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Invalid target object."); | ||
42 | |||
43 | Type type = target.GetType(); | ||
44 | MethodInfo method = type.GetMethod(methodName); | ||
45 | |||
46 | try | ||
47 | { | ||
48 | if (!XmlRpcExposedAttribute.ExposedMethod(target, methodName)) | ||
49 | throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD, | ||
50 | XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Method " + methodName + " is not exposed."); | ||
51 | } | ||
52 | catch (MissingMethodException me) | ||
53 | { | ||
54 | throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD, | ||
55 | XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": " + me.Message); | ||
56 | } | ||
57 | |||
58 | Object[] args = new Object[parameters.Count]; | ||
59 | |||
60 | int index = 0; | ||
61 | foreach (Object arg in parameters) | ||
62 | { | ||
63 | args[index] = arg; | ||
64 | index++; | ||
65 | } | ||
66 | |||
67 | try | ||
68 | { | ||
69 | Object retValue = method.Invoke(target, args); | ||
70 | if (retValue == null) | ||
71 | throw new XmlRpcException(XmlRpcErrorCodes.APPLICATION_ERROR, | ||
72 | XmlRpcErrorCodes.APPLICATION_ERROR_MSG + ": Method returned NULL."); | ||
73 | return retValue; | ||
74 | } | ||
75 | catch (XmlRpcException e) | ||
76 | { | ||
77 | throw e; | ||
78 | } | ||
79 | catch (ArgumentException ae) | ||
80 | { | ||
81 | Logger.WriteEntry(XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": " + ae.Message, | ||
82 | LogLevel.Information); | ||
83 | String call = methodName + "( "; | ||
84 | foreach (Object o in args) | ||
85 | { | ||
86 | call += o.GetType().Name; | ||
87 | call += " "; | ||
88 | } | ||
89 | call += ")"; | ||
90 | throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_PARAMS, | ||
91 | XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": Arguement type mismatch invoking " + call); | ||
92 | } | ||
93 | catch (TargetParameterCountException tpce) | ||
94 | { | ||
95 | Logger.WriteEntry(XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": " + tpce.Message, | ||
96 | LogLevel.Information); | ||
97 | throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_PARAMS, | ||
98 | XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": Arguement count mismatch invoking " + methodName); | ||
99 | } | ||
100 | catch (TargetInvocationException tie) | ||
101 | { | ||
102 | throw new XmlRpcException(XmlRpcErrorCodes.APPLICATION_ERROR, | ||
103 | XmlRpcErrorCodes.APPLICATION_ERROR_MSG + " Invoked method " + methodName + ": " + tie.Message); | ||
104 | } | ||
105 | } | ||
106 | |||
107 | /// <summary>List methods available on all handlers of this server.</summary> | ||
108 | /// <returns><c>IList</c> An array of <c>Strings</c>, each <c>String</c> will have form "object.method".</returns> | ||
109 | [XmlRpcExposed] | ||
110 | public IList listMethods() | ||
111 | { | ||
112 | IList methods = new ArrayList(); | ||
113 | Boolean considerExposure; | ||
114 | |||
115 | foreach (DictionaryEntry handlerEntry in _server) | ||
116 | { | ||
117 | considerExposure = XmlRpcExposedAttribute.IsExposed(handlerEntry.Value.GetType()); | ||
118 | |||
119 | foreach (MemberInfo mi in handlerEntry.Value.GetType().GetMembers()) | ||
120 | { | ||
121 | if (mi.MemberType != MemberTypes.Method) | ||
122 | continue; | ||
123 | |||
124 | if (!((MethodInfo)mi).IsPublic) | ||
125 | continue; | ||
126 | |||
127 | if (considerExposure && !XmlRpcExposedAttribute.IsExposed(mi)) | ||
128 | continue; | ||
129 | |||
130 | methods.Add(handlerEntry.Key + "." + mi.Name); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | return methods; | ||
135 | } | ||
136 | |||
137 | /// <summary>Given a method name return the possible signatures for it.</summary> | ||
138 | /// <param name="name"><c>String</c> The object.method name to look up.</param> | ||
139 | /// <returns><c>IList</c> Of arrays of signatures.</returns> | ||
140 | [XmlRpcExposed] | ||
141 | public IList methodSignature(String name) | ||
142 | { | ||
143 | IList signatures = new ArrayList(); | ||
144 | int index = name.IndexOf('.'); | ||
145 | |||
146 | if (index < 0) | ||
147 | return signatures; | ||
148 | |||
149 | String oName = name.Substring(0, index); | ||
150 | Object obj = _server[oName]; | ||
151 | |||
152 | if (obj == null) | ||
153 | return signatures; | ||
154 | |||
155 | MemberInfo[] mi = obj.GetType().GetMember(name.Substring(index + 1)); | ||
156 | |||
157 | if (mi == null || mi.Length != 1) // for now we want a single signature | ||
158 | return signatures; | ||
159 | |||
160 | MethodInfo method; | ||
161 | |||
162 | try | ||
163 | { | ||
164 | method = (MethodInfo)mi[0]; | ||
165 | } | ||
166 | catch (Exception e) | ||
167 | { | ||
168 | Logger.WriteEntry("Attempted methodSignature call on " + mi[0] + " caused: " + e, | ||
169 | LogLevel.Information); | ||
170 | return signatures; | ||
171 | } | ||
172 | |||
173 | if (!method.IsPublic) | ||
174 | return signatures; | ||
175 | |||
176 | IList signature = new ArrayList(); | ||
177 | signature.Add(method.ReturnType.Name); | ||
178 | |||
179 | foreach (ParameterInfo param in method.GetParameters()) | ||
180 | { | ||
181 | signature.Add(param.ParameterType.Name); | ||
182 | } | ||
183 | |||
184 | |||
185 | signatures.Add(signature); | ||
186 | |||
187 | return signatures; | ||
188 | } | ||
189 | |||
190 | /// <summary>Help for given method signature. Not implemented yet.</summary> | ||
191 | /// <param name="name"><c>String</c> The object.method name to look up.</param> | ||
192 | /// <returns><c>String</c> help text. Rich HTML text.</returns> | ||
193 | [XmlRpcExposed] | ||
194 | public String methodHelp(String name) | ||
195 | { | ||
196 | String help = null; | ||
197 | |||
198 | try | ||
199 | { | ||
200 | help = (String)_methodHelp[_server.MethodName(name)]; | ||
201 | } | ||
202 | catch (XmlRpcException e) | ||
203 | { | ||
204 | throw e; | ||
205 | } | ||
206 | catch (Exception) { /* ignored */ }; | ||
207 | |||
208 | if (help == null) | ||
209 | help = "No help available for: " + name; | ||
210 | |||
211 | return help; | ||
212 | } | ||
213 | |||
214 | /// <summary>Boxcarring support method.</summary> | ||
215 | /// <param name="calls"><c>IList</c> of calls</param> | ||
216 | /// <returns><c>ArrayList</c> of results/faults.</returns> | ||
217 | [XmlRpcExposed] | ||
218 | public IList multiCall(IList calls) | ||
219 | { | ||
220 | IList responses = new ArrayList(); | ||
221 | XmlRpcResponse fault = new XmlRpcResponse(); | ||
222 | |||
223 | foreach (IDictionary call in calls) | ||
224 | { | ||
225 | try | ||
226 | { | ||
227 | XmlRpcRequest req = new XmlRpcRequest((String)call[XmlRpcXmlTokens.METHOD_NAME], | ||
228 | (ArrayList)call[XmlRpcXmlTokens.PARAMS]); | ||
229 | Object results = _server.Invoke(req); | ||
230 | IList response = new ArrayList(); | ||
231 | response.Add(results); | ||
232 | responses.Add(response); | ||
233 | } | ||
234 | catch (XmlRpcException e) | ||
235 | { | ||
236 | fault.SetFault(e.FaultCode, e.FaultString); | ||
237 | responses.Add(fault.Value); | ||
238 | } | ||
239 | catch (Exception e2) | ||
240 | { | ||
241 | fault.SetFault(XmlRpcErrorCodes.APPLICATION_ERROR, | ||
242 | XmlRpcErrorCodes.APPLICATION_ERROR_MSG + ": " + e2.Message); | ||
243 | responses.Add(fault.Value); | ||
244 | } | ||
245 | } | ||
246 | |||
247 | return responses; | ||
248 | } | ||
249 | |||
250 | } | ||
251 | } | ||
252 | |||