XmlRpcSystemObject.cs 9.6 KB

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