| using oneM2MClient.Client; |
| using oneM2MClient.Resources; |
| using oneM2MClient.Protocols; |
| using BaSys40.Utils.ResultHandling; |
| using BaSys40.Utils.ModelHandling; |
| using System; |
| using System.Collections; |
| using System.Collections.Generic; |
| using System.Linq; |
| using System.Reflection; |
| using System.Text; |
| |
| namespace oneM2MClient.Utils |
| { |
| public static class Helper |
| { |
| public static Uri ConcatUrl(string Scheme, string Host, int? Port, params string[] path) |
| { |
| if (!string.IsNullOrEmpty(Host)) |
| { |
| StringBuilder uriBuilder = new StringBuilder(); |
| |
| if (!string.IsNullOrEmpty(Scheme)) |
| uriBuilder.Append(Scheme).Append("://"); |
| |
| uriBuilder.Append(Host); |
| |
| if (Port.HasValue) |
| uriBuilder.Append(":").Append(Port.Value); |
| |
| if (path != null) |
| { |
| string joinedPath = string.Join("/", path); |
| uriBuilder.Append("/").Append(joinedPath); |
| } |
| return new Uri(uriBuilder.ToString()); |
| } |
| return null; |
| } |
| |
| |
| /// <summary> |
| /// Returns the urils of the resource and its substructure to be discovered |
| /// </summary> |
| /// <param name="client"></param> |
| /// <param name="request"></param> |
| /// <param name="labels"></param> |
| /// <param name="additionalPath"></param> |
| /// <returns>List with urils of the resource and its substructure</returns> |
| public static Result<Response> DiscoverResource(IClient client, Request request, out List<string> resourceLinks, params string[] additionalPath) |
| { |
| if (additionalPath != null && additionalPath.Length > 0) |
| request.AddPath(additionalPath); |
| var contResp = CSEBase.Discover(client, request, oneM2M.FilterUsage.DISCOVERY_CRITERIA, null); |
| if (contResp.Success && contResp.Entity != null) |
| { |
| if (contResp.Entity.Uril.Count > 0) |
| resourceLinks = contResp.Entity.Uril; |
| else if (contResp.Entity.PrimitiveContent?.Items?.Count > 0) |
| { |
| resourceLinks = new List<string>(); |
| foreach (var item in contResp.Entity.PrimitiveContent.Items) |
| { |
| resourceLinks.Add((item as resource).Ri); |
| } |
| if (resourceLinks.Count == 0) |
| resourceLinks = null; |
| } |
| else |
| resourceLinks = null; |
| return contResp; |
| } |
| resourceLinks = null; |
| return contResp; |
| } |
| |
| |
| #region Read-Functions (Always return real resources) |
| /// <summary> |
| /// Reads resource by path |
| /// </summary> |
| /// <param name="client"></param> |
| /// <param name="request"></param> |
| /// <param name="path"></param> |
| /// <returns></returns> |
| public static resource ReadResourceByPath(IClient client, Request request, params string[] path) |
| { |
| if (path != null && path.Length > 0) |
| request.SetPath(path); |
| |
| return ReadResource(client, request); |
| } |
| |
| /// <summary> |
| /// Reads resource by resource id |
| /// </summary> |
| /// <param name="client"></param> |
| /// <param name="request"></param> |
| /// <param name="resourceId"></param> |
| /// <returns></returns> |
| public static resource ReadResourceById(IClient client, Request request, string resourceId) |
| { |
| if (string.IsNullOrEmpty(resourceId)) |
| return null; |
| |
| if(resourceId.Contains("/")) |
| { |
| resourceId = resourceId.Split('/')[2]; |
| } |
| request.SetResourcePath(resourceId); |
| return ReadResource(client, request); |
| } |
| |
| public static resource ReadResource(IClient client, Request request) |
| { |
| Result<Response> contResp = CSEBase.Retrieve(client, request); |
| if (contResp.Success && contResp.Entity != null) |
| { |
| if (contResp.Entity.TryGetResource(out resource res)) |
| return res; |
| } |
| return null; |
| } |
| |
| /// <summary> |
| /// Reads resources in oneM2M tree based on labels |
| /// </summary> |
| /// <param name="client"></param> |
| /// <param name="request"></param> |
| /// <param name="labels"></param> |
| /// <returns>List of resources</returns> |
| public static Result<Response> ReadResourcesByLabels(IClient client, Request request, List<string> labels, out List<resource> resources) |
| { |
| var contResp = CSEBase.Discover(client, request, oneM2M.FilterUsage.DISCOVERY_CRITERIA, null, labels); |
| if (contResp.Success && contResp.Entity != null) |
| { |
| resources = new List<resource>(); |
| if (contResp.Entity.Uril.Count > 0) |
| foreach (var uril in contResp.Entity.Uril) |
| { |
| var resource = ReadResourceByPath(client, request, uril); |
| if (resource != null) |
| resources.Add(resource); |
| } |
| if (contResp.Entity.PrimitiveContent?.Items.Count > 0) |
| foreach (var item in contResp.Entity.PrimitiveContent.Items) |
| { |
| if (item != null) |
| resources.Add((resource)item); |
| } |
| return contResp; |
| } |
| resources = null; |
| return contResp; |
| } |
| |
| public static Result<Response> ReadLatestAddedResource(IClient client, Request request, out resource resource, params string[] additionalPath) |
| { |
| if (additionalPath != null && additionalPath.Length > 0) |
| request.AddPath(additionalPath); |
| |
| if(!request.RequestPath.Segments.Contains("la")) |
| request.AddPath("la"); |
| |
| var contResp = CSEBase.Retrieve(client, request); |
| if (contResp.Success && contResp.Entity != null && contResp.Entity.PrimitiveContent != null) |
| { |
| var items = contResp.Entity.PrimitiveContent.Items; |
| var result = items?.FirstOrDefault(); |
| if (result != null) |
| resource = result as resource; |
| else |
| resource = null; |
| } |
| else |
| resource = null; |
| |
| return contResp; |
| } |
| #endregion |
| |
| #region Tree-Functions (Always return an ObjectTree) |
| /// <summary> |
| /// Returns an object tree with fully requested resources by resource id |
| /// </summary> |
| /// <param name="client"></param> |
| /// <param name="request"></param> |
| /// <param name="resourceId"></param> |
| /// <returns></returns> |
| public static Result<Response> ReadResourceTreeById(IClient client, Request request, string resourceId, out ObjectTreeBuilder tree) |
| { |
| request.SetResourcePath(resourceId); |
| return ReadResourceTree(client, request, out tree, null); |
| } |
| |
| /// <summary> |
| /// Return an object tree with the full requested resources |
| /// </summary> |
| /// <param name="client"></param> |
| /// <param name="request"></param> |
| /// <param name="additionalPath"></param> |
| /// <returns>Object tree with full resources</returns> |
| public static Result<Response> ReadResourceTree(IClient client, Request request, out ObjectTreeBuilder tree, params string[] additionalPath) |
| { |
| if (additionalPath != null && additionalPath.Length > 0) |
| request.AddPath(additionalPath); |
| var result = DiscoverResource(client, request, out List<string> resourceReferences, additionalPath); |
| if (result.Success && resourceReferences != null) |
| { |
| List<resource> resources = new List<resource>(); |
| foreach (var resourceReference in resourceReferences) |
| { |
| resource res = null; |
| if (IsPath(resourceReference)) |
| res = ReadResourceByPath(client, request, resourceReference); |
| else if (IsId(resourceReference)) |
| res = ReadResourceById(client, request, resourceReference); |
| |
| if (res != null) |
| resources.Add(res); |
| } |
| if (resources.Count > 0) |
| tree = GetResourceObjectTree(resources); |
| else |
| tree = null; |
| |
| return result; |
| } |
| tree = null; |
| return result; |
| } |
| |
| |
| |
| public static void ListObjectInTree(IClient client, Request request, string objName, object obj, params string[] path) |
| { |
| if (path != null && path.Length > 0) |
| request.SetPath(path); |
| |
| Container.Create(client, request, objName); |
| |
| var newPath = path.ToList(); |
| newPath.Add(objName); |
| request.ClearRequest().SetPath(newPath.ToArray()); |
| |
| foreach (PropertyInfo property in obj.GetType().GetProperties()) |
| { |
| string name = property.Name; |
| object value = property.GetValue(obj, null); |
| string content = value == null ? "NULL" : value.ToString(); |
| ContentInstance.Create(client, request, name, content); |
| request.ClearRequest(); |
| } |
| } |
| /// <summary> |
| /// Returns a resource object tree structure based on a flat list of resources as input. This is done by comparing ParentId with ResourceId. |
| /// </summary> |
| /// <param name="items">A flat list of resources</param> |
| /// <returns>Object tree with resources</returns> |
| public static ObjectTreeBuilder GetResourceObjectTree(List<resource> items) |
| { |
| if (items != null && items.Count > 0) |
| { |
| resource firstItem = items[0]; |
| ObjectTreeBuilder root = new ObjectTreeBuilder(firstItem.Rn, firstItem); |
| //ToDo: Remove cse names |
| var childrenOfRoot = items.FindAll(c => c.Pi.Replace("/","").Replace("InCSE1", "").Replace("in-cse", "") == firstItem.Ri.Replace("/","").Replace("InCSE1", "").Replace("in-cse","")); |
| foreach (var child in childrenOfRoot) |
| { |
| int index = items.IndexOf(child); |
| ObjectTreeBuilder treeChild = GetResourceObjectTree(items.GetRange(index, items.Count - index)); |
| root.AddChild(treeChild); |
| } |
| return root; |
| } |
| else |
| return null; |
| } |
| |
| /// <summary> |
| /// Writes the entire tree as container structure in the oneM2M hierarchy tree based on the name of the input tree elements |
| /// </summary> |
| /// <param name="client">oneM2M-Client</param> |
| /// <param name="request">Request-Object</param> |
| /// <param name="tree">Arbitrary tree with named elements</param> |
| /// <param name="path">Start path in the oneM2M hierarchy where the container structure is added to</param> |
| public static void WriteTree(IClient client, Request request, ObjectTreeBuilder tree, params string[] path) |
| { |
| if (tree != null) |
| { |
| if (path != null && path.Length > 0) |
| request.SetPath(path); |
| |
| Container.Create(client, request, tree.Name); |
| request.ClearRequest(); |
| if (tree.HasChildren()) |
| { |
| foreach (var child in tree.Children) |
| { |
| var newPath = path.ToList(); |
| newPath.Add(tree.Name); |
| |
| WriteTree(client, request, child, newPath.ToArray()); |
| } |
| } |
| } |
| } |
| |
| public static void WriteResourceTree(IClient client, Request request, ObjectTreeBuilder tree, params string[] path) |
| { |
| if (tree != null) |
| { |
| if (path != null && path.Length > 0) |
| request.SetPath(path); |
| |
| var res = tree.Value.FirstOrDefault(); |
| if (res != null) |
| { |
| CSEBase.CRUD(client, request, oneM2M.Operation.CREATE, GetResourceType(res), res); |
| request.ClearRequest(); |
| } |
| if (res != null && tree.HasChildren()) |
| { |
| foreach (var child in tree.Children) |
| { |
| var newPath = path.ToList(); |
| newPath.Add(((resource)res).Rn); |
| |
| WriteResourceTree(client, request, child, newPath.ToArray()); |
| } |
| } |
| } |
| } |
| #endregion |
| |
| #region Resource Handling (Converter, Instantiator) |
| public static object ConvertToBaseResource(object convenientResource) |
| { |
| if (convenientResource == null) |
| return null; |
| |
| string conResTypeName = convenientResource.GetType().Name.LowercaseFirst(); |
| string shortname = oneM2M.Name.LongToShort(conResTypeName).ToLower(); |
| Type baseResourceType = Type.GetType(oneM2M.PRIMITIVE_PACKAGE + shortname, true, true); |
| object baseResource = Activator.CreateInstance(baseResourceType); |
| |
| PropertyInfo[] convResField = convenientResource.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); |
| |
| for (int i = 0; i < convResField.Length; i++) |
| { |
| string longName = LowercaseFirst(convResField[i].Name); |
| string shortName = UppercaseFirst(oneM2M.Name.LongToShort(longName)); |
| |
| object value = convResField[i].GetValue(convenientResource); |
| |
| if (value != null && !string.IsNullOrEmpty(shortName) && shortName != "Ty") |
| { |
| PropertyInfo propInfo = baseResource.GetType().GetProperty(shortName, BindingFlags.Instance | BindingFlags.Public); |
| if (propInfo != null) |
| { |
| if(value.GetType() != propInfo.PropertyType) |
| { |
| Type t = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType; |
| try { value = Convert.ChangeType(value, t); } catch { value = null; } |
| } |
| var setMethod = propInfo.GetSetMethod(); |
| if(setMethod != null) |
| propInfo.SetValue(baseResource, value, null); |
| } |
| } |
| } |
| return baseResource; |
| } |
| |
| public static void ConvertToConvenientResource(this IResource convenientResource, object resource) |
| { |
| PropertyInfo[] resField = resource.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); |
| |
| for (int i = 0; i < resField.Length; i++) |
| { |
| string shortName = resField[i].Name.ToLower(); |
| string longName = oneM2M.Name.ShortTolong(shortName).UppercaseFirst(); |
| |
| object value = resField[i].GetValue(resource); |
| |
| if (value != null && !string.IsNullOrEmpty(longName)) |
| { |
| PropertyInfo propInfo = convenientResource.GetType().GetProperty(longName, BindingFlags.Instance | BindingFlags.Public); |
| if (propInfo != null) |
| { |
| if (value is ICollection && (value as ICollection).Count == 0) |
| continue; |
| |
| if (value.GetType() != propInfo.PropertyType) |
| { |
| Type t = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType; |
| if (t.IsEnum) |
| value = Enum.Parse(t, value.ToString()); |
| else |
| value = Convert.ChangeType(value, t); |
| } |
| var setMethod = propInfo.GetSetMethod(); |
| if (setMethod != null) |
| propInfo.SetValue(convenientResource, value, null); |
| } |
| } |
| } |
| } |
| |
| public static string UppercaseFirst(this string s) |
| { |
| if (string.IsNullOrEmpty(s)) |
| { |
| return string.Empty; |
| } |
| return char.ToUpper(s[0]) + s.Substring(1); |
| } |
| |
| public static string LowercaseFirst(this string s) |
| { |
| if (string.IsNullOrEmpty(s)) |
| { |
| return string.Empty; |
| } |
| return char.ToLower(s[0]) + s.Substring(1); |
| } |
| |
| public static object InstantiateResource(MethodBase m, int parameterIndex, Type t, params object[] args) |
| { |
| if (IsNullObjects(m, t)) |
| return null; |
| |
| ParameterInfo[] parameters = m.GetParameters(); |
| object resource = Activator.CreateInstance(t); |
| |
| for (int i = 0; i < parameters.Length - parameterIndex; i++) |
| { |
| string longName = parameters[i + parameterIndex].Name; |
| string shortName = UppercaseFirst(oneM2M.Name.LongToShort(longName)); |
| |
| object value = args[i]; |
| |
| if (!string.IsNullOrEmpty(shortName)) |
| { |
| PropertyInfo propInfo = resource.GetType().GetProperty(shortName, BindingFlags.Instance | BindingFlags.Public); |
| if (propInfo != null) |
| { |
| propInfo.SetValue(resource, value, null); |
| } |
| } |
| else |
| throw new KeyNotFoundException(shortName + " is missing in the longToShort-Dictionary - longName: " + longName); |
| } |
| return resource; |
| } |
| |
| public static cin GetLatestResource(ObjectTreeBuilder objectTreeBuilder) |
| { |
| if(objectTreeBuilder != null && objectTreeBuilder.HasChildren()) |
| { |
| List<cin> cins = objectTreeBuilder.Children.Select(c => c.GetValue<cin>()).ToList(); |
| |
| var latestCreationTime = cins.Where(a => a != null)?.Max(c => oneM2M.Time.Parse(c.Ct)); |
| var latestResource = cins.Where(a => a != null)?.FirstOrDefault(c => oneM2M.Time.Parse(c.Ct) == latestCreationTime); |
| return latestResource; |
| } |
| return null; |
| } |
| |
| public static oneM2M.ResourceType GetResourceType(object resource) |
| { |
| switch (resource.GetType().Name.ToString()) |
| { |
| case "cnt": return oneM2M.ResourceType.Container; |
| case "cin": return oneM2M.ResourceType.ContentInstance; |
| case "ae": return oneM2M.ResourceType.ApplicationEntity; |
| case "sub": return oneM2M.ResourceType.Subscription; |
| default: |
| return default(oneM2M.ResourceType); |
| } |
| } |
| #endregion |
| |
| #region Miscellaneous |
| [Obsolete("Works only in openDaylight IoTDM")] |
| public static string GetResourceIdFromParentId(string resourceId) |
| { |
| if (!string.IsNullOrEmpty(resourceId)) |
| { |
| string[] split = resourceId.Split('/'); |
| if (split != null && split.Length >= 3) |
| return (split[2]); |
| else |
| return null; |
| } |
| else |
| return null; |
| } |
| |
| public static bool IsPath(string path) |
| { |
| if (!string.IsNullOrEmpty(path)) |
| if (path.Contains("/")) |
| return true; |
| return false; |
| } |
| public static bool IsId(string id) |
| { |
| if (!string.IsNullOrEmpty(id)) |
| if (!id.Contains("/")) //ToDo: check regex |
| return true; |
| return false; |
| } |
| |
| public static Result<T> HandleResultWithException<T>(Result<T> result, Exception e) |
| { |
| if (result == null) |
| return new Result<T>(false, default(T), new Message(MessageType.Error, e.Message)); |
| else |
| { |
| var newResult = new Result<T>(e); |
| newResult.Messages.AddRange(result.Messages); |
| return result; |
| } |
| } |
| |
| public static bool IsNullObjects(params object[] args) |
| { |
| for (int i = 0; i < args.Length; i++) |
| { |
| if (args[i] == null) |
| return true; |
| } |
| return false; |
| } |
| #endregion |
| |
| } |
| } |