OpenSimMirror/XmlRpcCS/XmlRpcSystemObject.cs

253 lines
9.6 KiB
C#

namespace Nwc.XmlRpc
{
using System;
using System.Collections;
using System.Reflection;
/// <summary> XML-RPC System object implementation of extended specifications.</summary>
[XmlRpcExposed]
public class XmlRpcSystemObject
{
private XmlRpcServer _server;
static private IDictionary _methodHelp = new Hashtable();
/// <summary>Static <c>IDictionary</c> to hold mappings of method name to associated documentation String</summary>
static public IDictionary MethodHelp
{
get { return _methodHelp; }
}
/// <summary>Constructor.</summary>
/// <param name="server"><c>XmlRpcServer</c> server to be the system object for.</param>
public XmlRpcSystemObject(XmlRpcServer server)
{
_server = server;
server.Add("system", this);
_methodHelp.Add(this.GetType().FullName + ".methodHelp", "Return a string description.");
}
/// <summary>Invoke a method on a given object.</summary>
/// <remarks>Using reflection, and respecting the <c>XmlRpcExposed</c> attribute,
/// invoke the <paramref>methodName</paramref> method on the <paramref>target</paramref>
/// instance with the <paramref>parameters</paramref> provided. All this packages other <c>Invoke</c> methods
/// end up calling this.</remarks>
/// <returns><c>Object</c> the value the invoked method returns.</returns>
/// <exception cref="XmlRpcException">If method does not exist, is not exposed, parameters invalid, or invocation
/// results in an exception. Note, the <c>XmlRpcException.Code</c> will indicate cause.</exception>
static public Object Invoke(Object target, String methodName, IList parameters)
{
if (target == null)
throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Invalid target object.");
Type type = target.GetType();
MethodInfo method = type.GetMethod(methodName);
try
{
if (!XmlRpcExposedAttribute.ExposedMethod(target, methodName))
throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": Method " + methodName + " is not exposed.");
}
catch (MissingMethodException me)
{
throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_METHOD,
XmlRpcErrorCodes.SERVER_ERROR_METHOD_MSG + ": " + me.Message);
}
Object[] args = new Object[parameters.Count];
int index = 0;
foreach (Object arg in parameters)
{
args[index] = arg;
index++;
}
try
{
Object retValue = method.Invoke(target, args);
if (retValue == null)
throw new XmlRpcException(XmlRpcErrorCodes.APPLICATION_ERROR,
XmlRpcErrorCodes.APPLICATION_ERROR_MSG + ": Method returned NULL.");
return retValue;
}
catch (XmlRpcException e)
{
throw e;
}
catch (ArgumentException ae)
{
Logger.WriteEntry(XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": " + ae.Message,
LogLevel.Information);
String call = methodName + "( ";
foreach (Object o in args)
{
call += o.GetType().Name;
call += " ";
}
call += ")";
throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_PARAMS,
XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": Arguement type mismatch invoking " + call);
}
catch (TargetParameterCountException tpce)
{
Logger.WriteEntry(XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": " + tpce.Message,
LogLevel.Information);
throw new XmlRpcException(XmlRpcErrorCodes.SERVER_ERROR_PARAMS,
XmlRpcErrorCodes.SERVER_ERROR_PARAMS_MSG + ": Arguement count mismatch invoking " + methodName);
}
catch (TargetInvocationException tie)
{
throw new XmlRpcException(XmlRpcErrorCodes.APPLICATION_ERROR,
XmlRpcErrorCodes.APPLICATION_ERROR_MSG + " Invoked method " + methodName + ": " + tie.Message);
}
}
/// <summary>List methods available on all handlers of this server.</summary>
/// <returns><c>IList</c> An array of <c>Strings</c>, each <c>String</c> will have form "object.method".</returns>
[XmlRpcExposed]
public IList listMethods()
{
IList methods = new ArrayList();
Boolean considerExposure;
foreach (DictionaryEntry handlerEntry in _server)
{
considerExposure = XmlRpcExposedAttribute.IsExposed(handlerEntry.Value.GetType());
foreach (MemberInfo mi in handlerEntry.Value.GetType().GetMembers())
{
if (mi.MemberType != MemberTypes.Method)
continue;
if (!((MethodInfo)mi).IsPublic)
continue;
if (considerExposure && !XmlRpcExposedAttribute.IsExposed(mi))
continue;
methods.Add(handlerEntry.Key + "." + mi.Name);
}
}
return methods;
}
/// <summary>Given a method name return the possible signatures for it.</summary>
/// <param name="name"><c>String</c> The object.method name to look up.</param>
/// <returns><c>IList</c> Of arrays of signatures.</returns>
[XmlRpcExposed]
public IList methodSignature(String name)
{
IList signatures = new ArrayList();
int index = name.IndexOf('.');
if (index < 0)
return signatures;
String oName = name.Substring(0, index);
Object obj = _server[oName];
if (obj == null)
return signatures;
MemberInfo[] mi = obj.GetType().GetMember(name.Substring(index + 1));
if (mi == null || mi.Length != 1) // for now we want a single signature
return signatures;
MethodInfo method;
try
{
method = (MethodInfo)mi[0];
}
catch (Exception e)
{
Logger.WriteEntry("Attempted methodSignature call on " + mi[0] + " caused: " + e,
LogLevel.Information);
return signatures;
}
if (!method.IsPublic)
return signatures;
IList signature = new ArrayList();
signature.Add(method.ReturnType.Name);
foreach (ParameterInfo param in method.GetParameters())
{
signature.Add(param.ParameterType.Name);
}
signatures.Add(signature);
return signatures;
}
/// <summary>Help for given method signature. Not implemented yet.</summary>
/// <param name="name"><c>String</c> The object.method name to look up.</param>
/// <returns><c>String</c> help text. Rich HTML text.</returns>
[XmlRpcExposed]
public String methodHelp(String name)
{
String help = null;
try
{
help = (String)_methodHelp[_server.MethodName(name)];
}
catch (XmlRpcException e)
{
throw e;
}
catch (Exception) { /* ignored */ };
if (help == null)
help = "No help available for: " + name;
return help;
}
/// <summary>Boxcarring support method.</summary>
/// <param name="calls"><c>IList</c> of calls</param>
/// <returns><c>ArrayList</c> of results/faults.</returns>
[XmlRpcExposed]
public IList multiCall(IList calls)
{
IList responses = new ArrayList();
XmlRpcResponse fault = new XmlRpcResponse();
foreach (IDictionary call in calls)
{
try
{
XmlRpcRequest req = new XmlRpcRequest((String)call[XmlRpcXmlTokens.METHOD_NAME],
(ArrayList)call[XmlRpcXmlTokens.PARAMS]);
Object results = _server.Invoke(req);
IList response = new ArrayList();
response.Add(results);
responses.Add(response);
}
catch (XmlRpcException e)
{
fault.SetFault(e.FaultCode, e.FaultString);
responses.Add(fault.Value);
}
catch (Exception e2)
{
fault.SetFault(XmlRpcErrorCodes.APPLICATION_ERROR,
XmlRpcErrorCodes.APPLICATION_ERROR_MSG + ": " + e2.Message);
responses.Add(fault.Value);
}
}
return responses;
}
}
}