XmlRpcSystemObject.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*
  2. * Copyright (c) Contributors, http://www.openmetaverse.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. *
  27. */
  28. namespace Nwc.XmlRpc
  29. {
  30. using System;
  31. using System.Collections;
  32. using System.Reflection;
  33. /// <summary> XML-RPC System object implementation of extended specifications.</summary>
  34. [XmlRpcExposed]
  35. public class XmlRpcSystemObject
  36. {
  37. private XmlRpcServer _server;
  38. static private IDictionary _methodHelp = new Hashtable();
  39. /// <summary>Static <c>IDictionary</c> to hold mappings of method name to associated documentation String</summary>
  40. static public IDictionary MethodHelp
  41. {
  42. get { return _methodHelp; }
  43. }
  44. /// <summary>Constructor.</summary>
  45. /// <param name="server"><c>XmlRpcServer</c> server to be the system object for.</param>
  46. public XmlRpcSystemObject(XmlRpcServer server)
  47. {
  48. _server = server;
  49. server.Add("system", this);
  50. _methodHelp.Add(this.GetType().FullName + ".methodHelp", "Return a string description.");
  51. }
  52. /// <summary>Invoke a method on a given object.</summary>
  53. /// <remarks>Using reflection, and respecting the <c>XmlRpcExposed</c> attribute,
  54. /// invoke the <paramref>methodName</paramref> method on the <paramref>target</paramref>
  55. /// instance with the <paramref>parameters</paramref> provided. All this packages other <c>Invoke</c> methods
  56. /// end up calling this.</remarks>
  57. /// <returns><c>Object</c> the value the invoked method returns.</returns>
  58. /// <exception cref="XmlRpcException">If method does not exist, is not exposed, parameters invalid, or invocation
  59. /// results in an exception. Note, the <c>XmlRpcException.Code</c> will indicate cause.</exception>
  60. static public Object Invoke(Object target, String methodName, IList parameters)
  61. {
  62. if (target == null)
  63. throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
  64. XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Invalid target object.");
  65. Type type = target.GetType();
  66. MethodInfo method = type.GetMethod(methodName);
  67. try
  68. {
  69. if (!XmlRpcExposedAttribute.ExposedMethod(target, methodName))
  70. throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
  71. XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Method " + methodName + " is not exposed.");
  72. }
  73. catch (MissingMethodException me)
  74. {
  75. throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
  76. XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": " + me.Message);
  77. }
  78. Object[] args = new Object[parameters.Count];
  79. int index = 0;
  80. foreach (Object arg in parameters)
  81. {
  82. args[index] = arg;
  83. index++;
  84. }
  85. try
  86. {
  87. Object retValue = method.Invoke(target, args);
  88. if (retValue == null)
  89. throw new XmlRpcException(XmlRpcErrorCodes.APPLICATION_ERROR,
  90. XmlRpcErrorCodes.APPLICATION_ERROR_MSG + ": Method returned NULL.");
  91. return retValue;
  92. }
  93. catch (XmlRpcException e)
  94. {
  95. throw e;
  96. }
  97. catch (ArgumentException ae)
  98. {
  99. Logger.WriteEntry(XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": " + ae.Message,
  100. LogLevel.Information);
  101. String call = methodName + "( ";
  102. foreach (Object o in args)
  103. {
  104. call += o.GetType().Name;
  105. call += " ";
  106. }
  107. call += ")";
  108. throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_PARAMS,
  109. XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": Arguement type mismatch invoking " + call);
  110. }
  111. catch (TargetParameterCountException tpce)
  112. {
  113. Logger.WriteEntry(XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": " + tpce.Message,
  114. LogLevel.Information);
  115. throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_PARAMS,
  116. XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": Arguement count mismatch invoking " + methodName);
  117. }
  118. catch (TargetInvocationException tie)
  119. {
  120. throw new XmlRpcException(XmlRpcErrorCodes.APPLICATION_ERROR,
  121. XmlRpcErrorCodes.APPLICATION_ERROR_MSG + " Invoked method " + methodName + ": " + tie.Message);
  122. }
  123. }
  124. /// <summary>List methods available on all handlers of this server.</summary>
  125. /// <returns><c>IList</c> An array of <c>Strings</c>, each <c>String</c> will have form "object.method".</returns>
  126. [XmlRpcExposed]
  127. public IList listMethods()
  128. {
  129. IList methods = new ArrayList();
  130. Boolean considerExposure;
  131. foreach (DictionaryEntry handlerEntry in _server)
  132. {
  133. considerExposure = XmlRpcExposedAttribute.IsExposed(handlerEntry.Value.GetType());
  134. foreach (MemberInfo mi in handlerEntry.Value.GetType().GetMembers())
  135. {
  136. if (mi.MemberType != MemberTypes.Method)
  137. continue;
  138. if (!((MethodInfo)mi).IsPublic)
  139. continue;
  140. if (considerExposure && !XmlRpcExposedAttribute.IsExposed(mi))
  141. continue;
  142. methods.Add(handlerEntry.Key + "." + mi.Name);
  143. }
  144. }
  145. return methods;
  146. }
  147. /// <summary>Given a method name return the possible signatures for it.</summary>
  148. /// <param name="name"><c>String</c> The object.method name to look up.</param>
  149. /// <returns><c>IList</c> Of arrays of signatures.</returns>
  150. [XmlRpcExposed]
  151. public IList methodSignature(String name)
  152. {
  153. IList signatures = new ArrayList();
  154. int index = name.IndexOf('.');
  155. if (index < 0)
  156. return signatures;
  157. String oName = name.Substring(0, index);
  158. Object obj = _server[oName];
  159. if (obj == null)
  160. return signatures;
  161. MemberInfo[] mi = obj.GetType().GetMember(name.Substring(index + 1));
  162. if (mi == null || mi.Length != 1) // for now we want a single signature
  163. return signatures;
  164. MethodInfo method;
  165. try
  166. {
  167. method = (MethodInfo)mi[0];
  168. }
  169. catch (Exception e)
  170. {
  171. Logger.WriteEntry("Attempted methodSignature call on " + mi[0] + " caused: " + e,
  172. LogLevel.Information);
  173. return signatures;
  174. }
  175. if (!method.IsPublic)
  176. return signatures;
  177. IList signature = new ArrayList();
  178. signature.Add(method.ReturnType.Name);
  179. foreach (ParameterInfo param in method.GetParameters())
  180. {
  181. signature.Add(param.ParameterType.Name);
  182. }
  183. signatures.Add(signature);
  184. return signatures;
  185. }
  186. /// <summary>Help for given method signature. Not implemented yet.</summary>
  187. /// <param name="name"><c>String</c> The object.method name to look up.</param>
  188. /// <returns><c>String</c> help text. Rich HTML text.</returns>
  189. [XmlRpcExposed]
  190. public String methodHelp(String name)
  191. {
  192. String help = null;
  193. try
  194. {
  195. help = (String)_methodHelp[_server.MethodName(name)];
  196. }
  197. catch (XmlRpcException e)
  198. {
  199. throw e;
  200. }
  201. catch (Exception) { /* ignored */ };
  202. if (help == null)
  203. help = "No help available for: " + name;
  204. return help;
  205. }
  206. /// <summary>Boxcarring support method.</summary>
  207. /// <param name="calls"><c>IList</c> of calls</param>
  208. /// <returns><c>ArrayList</c> of results/faults.</returns>
  209. [XmlRpcExposed]
  210. public IList multiCall(IList calls)
  211. {
  212. IList responses = new ArrayList();
  213. XmlRpcResponse fault = new XmlRpcResponse();
  214. foreach (IDictionary call in calls)
  215. {
  216. try
  217. {
  218. XmlRpcRequest req = new XmlRpcRequest((String)call[XmlRpcXmlTokens.METHOD_NAME],
  219. (ArrayList)call[XmlRpcXmlTokens.PARAMS]);
  220. Object results = _server.Invoke(req);
  221. IList response = new ArrayList();
  222. response.Add(results);
  223. responses.Add(response);
  224. }
  225. catch (XmlRpcException e)
  226. {
  227. fault.SetFault(e.FaultCode, e.FaultString);
  228. responses.Add(fault.Value);
  229. }
  230. catch (Exception e2)
  231. {
  232. fault.SetFault(XmlRpcErrorCodes.APPLICATION_ERROR,
  233. XmlRpcErrorCodes.APPLICATION_ERROR_MSG + ": " + e2.Message);
  234. responses.Add(fault.Value);
  235. }
  236. }
  237. return responses;
  238. }
  239. }
  240. }