ln.http.resources/JsonCallResource.cs

265 lines
9.2 KiB
C#
Raw Normal View History

2019-03-14 08:35:59 +01:00
// /**
// * 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 Newtonsoft.Json;
using ln.http.exceptions;
2019-03-15 07:43:08 +01:00
using ln.logging;
using Newtonsoft.Json.Linq;
2019-03-18 08:12:36 +01:00
using System.Runtime.CompilerServices;
using System.Linq;
using System.Runtime.InteropServices;
2019-03-29 08:55:05 +01:00
using System.Diagnostics;
2019-03-14 08:35:59 +01:00
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[]>();
2019-03-18 08:12:36 +01:00
Dictionary<string, MethodResource> methodResources = new Dictionary<string, MethodResource>();
2019-03-14 08:35:59 +01:00
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());
2019-03-18 08:12:36 +01:00
new MethodResource(this, alias);
2019-03-14 08:35:59 +01:00
}
}
2019-03-18 08:12:36 +01:00
private object InvokeMethodCall(string methodName, object[] arguments)
{
2019-03-29 08:55:05 +01:00
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
2019-03-18 08:12:36 +01:00
MethodInfo methodInfo = FindMethodSignature(methodName, arguments.Length);
2019-03-29 08:55:05 +01:00
object result = methodInfo.Invoke(this, arguments);
stopwatch.Stop();
2019-04-01 07:48:24 +02:00
Logging.Log(LogLevel.DEBUGDETAIL,"InvokeMethodCall({0},...): {1}ms",methodName,stopwatch.ElapsedMilliseconds);
2019-03-29 08:55:05 +01:00
return result;
2019-03-18 08:12:36 +01:00
}
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];
2019-03-29 08:55:05 +01:00
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
object result = methodInfo.Invoke(this, pl);
stopwatch.Stop();
2019-04-01 07:48:24 +02:00
Logging.Log(LogLevel.DEBUGDETAIL, "InvokeMethodCall({0},...): {1}ms", methodName, stopwatch.ElapsedMilliseconds);
2019-03-29 08:55:05 +01:00
return result;
2019-03-18 08:12:36 +01:00
}
2019-03-14 08:35:59 +01:00
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");
}
2019-03-18 08:12:36 +01:00
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");
}
2019-03-14 08:35:59 +01:00
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 = JsonConvert.DeserializeObject<MethodCall>(httpRequest.ContentReader.ReadToEnd());
MethodResult methodResult;
try
{
methodResult = new MethodResult();
methodResult.MethodName = methodCall.MethodName;
2019-03-18 08:12:36 +01:00
2019-03-29 08:55:05 +01:00
//MethodInfo methodInfo = FindMethodSignature(methodCall.MethodName, methodCall.Parameters.Length);
//ParameterInfo[] mp = methodInfo.GetParameters();
2019-03-18 08:12:36 +01:00
2019-03-29 08:55:05 +01:00
//object[] arguments = new object[methodCall.Parameters.Length];
//for (int n=0;n<methodCall.Parameters.Length; n++)
//{
// arguments[n] = Convert.ChangeType(methodCall.Parameters[n], mp[n].ParameterType);
//}
//methodResult.Result = methodInfo.Invoke(this, arguments);
methodResult.Result = InvokeMethodCall(methodCall.MethodName, methodCall.Parameters);
2019-03-15 07:43:08 +01:00
2019-03-14 08:35:59 +01:00
} catch (Exception e)
{
methodResult = new MethodResult();
methodResult.MethodName = methodCall.MethodName;
methodResult.Exception = e;
2019-03-15 07:43:08 +01:00
Logging.Log(LogLevel.ERROR, "JsonCallResource: method call caught exception: {0}",e);
Logging.Log(e);
2019-03-14 08:35:59 +01:00
}
String result = JsonConvert.SerializeObject(methodResult);
HttpResponse httpResponse = new HttpResponse(httpRequest);
httpResponse.SetHeader("content-type", "application/json");
httpResponse.ContentWriter.Write(result);
return httpResponse;
}
2019-03-15 07:43:08 +01:00
private string SerializeResult(MethodInfo methodInfo,MethodResult methodResult)
{
if (methodResult.Exception != null)
{
return JsonConvert.SerializeObject(methodResult);
}
else
{
return FlatSerializeResult(methodResult);
}
}
private string FlatSerializeResult(MethodResult methodResult)
{
JObject jMethodResult = new JObject();
jMethodResult.Add("Exception", null);
jMethodResult.Add("MethodName", methodResult.MethodName);
JObject jResult = new JObject();
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, new JValue(fieldInfo.GetValue(methodResult.Result)));
}
else
{
jResult.Add(fieldInfo.Name, new JValue(fieldInfo.GetValue(methodResult.Result).ToString()));
}
}
return jMethodResult.ToString();
}
2019-03-14 08:35:59 +01:00
class MethodCall
{
public String MethodName;
public object[] Parameters;
}
class MethodResult
{
public String MethodName;
public object Result;
public Exception Exception;
}
2019-03-18 08:12:36 +01:00
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();
}
2019-03-14 08:35:59 +01:00
}
}