296 lines
10 KiB
C#
296 lines
10 KiB
C#
// /**
|
|
// * File: JsonCallResource.cs
|
|
// * Author: haraldwolff
|
|
// *
|
|
// * This file and it's content is copyrighted by the Author and / or copyright holder.
|
|
// * Any use wihtout proper permission is illegal and may lead to legal actions.
|
|
// *
|
|
// *
|
|
// **/
|
|
using System;
|
|
using System.Reflection;
|
|
using System.Collections.Generic;
|
|
using ln.http.exceptions;
|
|
using ln.logging;
|
|
using System.Linq;
|
|
using System.Diagnostics;
|
|
using ln.json.mapping;
|
|
using ln.json;
|
|
namespace ln.http.resources
|
|
{
|
|
public class CallableAttribute : Attribute
|
|
{
|
|
public String Alias { get; set; }
|
|
|
|
}
|
|
|
|
public abstract class JsonCallResource : BaseResource
|
|
{
|
|
Dictionary<string, MethodInfo[]> callableMethods = new Dictionary<string, MethodInfo[]>();
|
|
Dictionary<string, MethodResource> methodResources = new Dictionary<string, MethodResource>();
|
|
|
|
|
|
public JsonCallResource(Resource container, string name)
|
|
: base(container, name)
|
|
{
|
|
initialize();
|
|
}
|
|
|
|
private void initialize()
|
|
{
|
|
Dictionary<string, List<MethodInfo>> callables = new Dictionary<string, List<MethodInfo>>();
|
|
|
|
foreach (MethodInfo methodInfo in this.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
|
|
{
|
|
CallableAttribute callableAttribute = methodInfo.GetCustomAttribute<CallableAttribute>();
|
|
if (callableAttribute != null)
|
|
{
|
|
string alias = callableAttribute.Alias == null ? methodInfo.Name : callableAttribute.Alias;
|
|
if (!callables.ContainsKey(alias))
|
|
{
|
|
callables.Add(alias, new List<MethodInfo>());
|
|
}
|
|
callables[alias].Add(methodInfo);
|
|
}
|
|
}
|
|
|
|
foreach (String alias in callables.Keys)
|
|
{
|
|
callableMethods.Add(alias, callables[alias].ToArray());
|
|
new MethodResource(this, alias);
|
|
}
|
|
|
|
foreach (PropertyInfo propertyInfo in this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
|
|
{
|
|
if (propertyInfo.GetCustomAttribute<CallableAttribute>() != null)
|
|
{
|
|
new CallableProperty(this, propertyInfo);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private object InvokeMethodCall(string methodName, object[] arguments)
|
|
{
|
|
Stopwatch stopwatch = new Stopwatch();
|
|
stopwatch.Start();
|
|
|
|
MethodInfo methodInfo = FindMethodSignature(methodName, arguments.Length);
|
|
object result = methodInfo.Invoke(this, arguments);
|
|
|
|
stopwatch.Stop();
|
|
Logging.Log(LogLevel.DEBUGDETAIL,"InvokeMethodCall({0},...): {1}ms",methodName,stopwatch.ElapsedMilliseconds);
|
|
|
|
return result;
|
|
}
|
|
|
|
private object InvokeMethodCall(string methodName, KeyValuePair<string,object>[] arguments)
|
|
{
|
|
MethodInfo methodInfo = FindMethodSignature(methodName, arguments.Select((kvp) => kvp.Key).ToArray());
|
|
Dictionary<string, object> args = new Dictionary<string, object>();
|
|
foreach (KeyValuePair<string,object> kvp in arguments)
|
|
args.Add(kvp.Key, kvp.Value);
|
|
|
|
ParameterInfo[] parameterInfos = methodInfo.GetParameters();
|
|
object[] pl = new object[parameterInfos.Length];
|
|
|
|
for (int n=0;n<parameterInfos.Length;n++)
|
|
pl[n] = args[parameterInfos[n].Name];
|
|
|
|
Stopwatch stopwatch = new Stopwatch();
|
|
stopwatch.Start();
|
|
|
|
object result = methodInfo.Invoke(this, pl);
|
|
|
|
stopwatch.Stop();
|
|
|
|
Logging.Log(LogLevel.DEBUGDETAIL, "InvokeMethodCall({0},...): {1}ms", methodName, stopwatch.ElapsedMilliseconds);
|
|
return result;
|
|
}
|
|
|
|
|
|
private MethodInfo FindMethodSignature(String methodName,int nParameters)
|
|
{
|
|
foreach (MethodInfo methodInfo in callableMethods[methodName])
|
|
{
|
|
if (nParameters == methodInfo.GetParameters().Length)
|
|
{
|
|
return methodInfo;
|
|
}
|
|
}
|
|
throw new ArgumentException("No method signature matching the parameters was found");
|
|
}
|
|
|
|
private MethodInfo FindMethodSignature(String methodName, String[] argumentNames)
|
|
{
|
|
foreach (MethodInfo methodInfo in callableMethods[methodName])
|
|
{
|
|
ParameterInfo[] parameterInfos = methodInfo.GetParameters();
|
|
if (parameterInfos.Length == argumentNames.Length)
|
|
{
|
|
int n;
|
|
for (n = 0; n < parameterInfos.Length; n++)
|
|
{
|
|
if (!argumentNames.Contains(parameterInfos[n].Name))
|
|
break;
|
|
}
|
|
|
|
if (n == argumentNames.Length)
|
|
return methodInfo;
|
|
}
|
|
}
|
|
throw new ArgumentException("No method signature matching the parameters was found");
|
|
}
|
|
|
|
|
|
public override HttpResponse GetResponse(HttpRequest httpRequest)
|
|
{
|
|
if (!httpRequest.GetRequestHeader("Content-Type").Equals("application/json"))
|
|
{
|
|
throw new HttpException("JSON Method call failed, call object not received");
|
|
}
|
|
|
|
MethodCall methodCall = JSONMapper.DefaultMapper.FromJson<MethodCall>(httpRequest.ContentReader.ReadToEnd());
|
|
MethodResult methodResult;
|
|
|
|
try
|
|
{
|
|
methodResult = new MethodResult();
|
|
methodResult.MethodName = methodCall.MethodName;
|
|
|
|
methodResult.Result = InvokeMethodCall(methodCall.MethodName, methodCall.Parameters);
|
|
} catch (Exception e)
|
|
{
|
|
methodResult = new MethodResult();
|
|
methodResult.MethodName = methodCall.MethodName;
|
|
methodResult.Exception = e;
|
|
Logging.Log(LogLevel.ERROR, "JsonCallResource: method call caught exception: {0}",e);
|
|
Logging.Log(e);
|
|
}
|
|
|
|
String result = JSONMapper.DefaultMapper.ToJson(methodResult).ToString();
|
|
|
|
HttpResponse httpResponse = new HttpResponse(httpRequest);
|
|
httpResponse.SetHeader("content-type", "application/json");
|
|
httpResponse.ContentWriter.Write(result);
|
|
|
|
return httpResponse;
|
|
}
|
|
|
|
private string SerializeResult(MethodInfo methodInfo,MethodResult methodResult)
|
|
{
|
|
if (methodResult.Exception != null)
|
|
{
|
|
return JSONMapper.DefaultMapper.ToJson(methodResult).ToString();
|
|
}
|
|
else
|
|
{
|
|
return FlatSerializeResult(methodResult);
|
|
}
|
|
}
|
|
|
|
private string FlatSerializeResult(MethodResult methodResult)
|
|
{
|
|
JSONObject jMethodResult = new JSONObject();
|
|
jMethodResult.Add("Exception", null);
|
|
jMethodResult.Add("MethodName", methodResult.MethodName);
|
|
|
|
JSONObject jResult = new JSONObject();
|
|
jMethodResult.Add("Result", jResult);
|
|
|
|
Type type = methodResult.GetType();
|
|
|
|
foreach (FieldInfo fieldInfo in type.GetFields(BindingFlags.Public | BindingFlags.Instance))
|
|
{
|
|
Type fType = fieldInfo.FieldType;
|
|
|
|
if ((fType.IsValueType) || (typeof(string).Equals(fType)) || (fType.IsArray))
|
|
{
|
|
jResult.Add(fieldInfo.Name, fieldInfo.GetValue(methodResult.Result));
|
|
}
|
|
else
|
|
{
|
|
jResult.Add(fieldInfo.Name, fieldInfo.GetValue(methodResult.Result).ToString());
|
|
}
|
|
}
|
|
|
|
return jMethodResult.ToString();
|
|
}
|
|
|
|
|
|
class MethodCall
|
|
{
|
|
public String MethodName;
|
|
public object[] Parameters;
|
|
}
|
|
|
|
class MethodResult
|
|
{
|
|
public String MethodName;
|
|
public object Result;
|
|
public Exception Exception;
|
|
}
|
|
|
|
|
|
class MethodResource : Resource
|
|
{
|
|
public MethodResource(JsonCallResource container,String methodName)
|
|
:base(container,methodName)
|
|
{
|
|
}
|
|
|
|
public override HttpResponse GetResponse(HttpRequest httpRequest)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
|
|
public override void AddResource(Resource resource) => throw new NotImplementedException();
|
|
public override bool Contains(string name) => throw new NotImplementedException();
|
|
public override IEnumerable<Resource> GetResources() => throw new NotImplementedException();
|
|
public override void RemoveResource(Resource resource) => throw new NotImplementedException();
|
|
}
|
|
|
|
class CallableProperty : Resource
|
|
{
|
|
public CallableProperty(JsonCallResource container, PropertyInfo propertyInfo)
|
|
: base(container, propertyInfo.Name)
|
|
{
|
|
this.propertyInfo = propertyInfo;
|
|
}
|
|
|
|
PropertyInfo propertyInfo;
|
|
|
|
public override void AddResource(Resource resource) => throw new NotImplementedException();
|
|
public override void RemoveResource(Resource resource) => throw new NotImplementedException();
|
|
|
|
public override bool Contains(string name) => false;
|
|
public override IEnumerable<Resource> GetResources() => new Resource[0];
|
|
|
|
public override HttpResponse GetResponse(HttpRequest httpRequest)
|
|
{
|
|
try
|
|
{
|
|
object v = propertyInfo.GetValue(Container);
|
|
String result = JSONMapper.DefaultMapper.ToJson(v).ToString();
|
|
|
|
HttpResponse httpResponse = new HttpResponse(httpRequest);
|
|
httpResponse.SetHeader("content-type", "application/json");
|
|
httpResponse.ContentWriter.Write(result);
|
|
|
|
return httpResponse;
|
|
} catch (Exception e)
|
|
{
|
|
Logging.Log(e);
|
|
|
|
HttpResponse httpResponse = new HttpResponse(httpRequest);
|
|
httpResponse.StatusCode = 500;
|
|
return httpResponse;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|