Old SDK removed
New dotnet SDK added - Release
diff --git a/sdks/dotnet/basyx-core/BaSyx.API/Components/SubmodelServiceProvider.cs b/sdks/dotnet/basyx-core/BaSyx.API/Components/SubmodelServiceProvider.cs
new file mode 100644
index 0000000..9b2543b
--- /dev/null
+++ b/sdks/dotnet/basyx-core/BaSyx.API/Components/SubmodelServiceProvider.cs
@@ -0,0 +1,452 @@
+/*******************************************************************************
+* Copyright (c) 2020 Robert Bosch GmbH
+* Author: Constantin Ziesche (constantin.ziesche@bosch.com)
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0
+*
+* SPDX-License-Identifier: EPL-2.0
+*******************************************************************************/
+using BaSyx.API.AssetAdministrationShell;
+using BaSyx.Models.Core.AssetAdministrationShell.Generics;
+using BaSyx.Models.Core.AssetAdministrationShell.Implementations;
+using BaSyx.Utils.ResultHandling;
+using BaSyx.Utils.Client;
+using System.Collections.Generic;
+using System;
+using Newtonsoft.Json;
+using System.Reflection;
+using System.Linq.Expressions;
+using System.Linq;
+using BaSyx.Models.Extensions;
+using BaSyx.Models.Connectivity.Descriptors;
+using BaSyx.Models.Core.Common;
+using BaSyx.Models.Core.AssetAdministrationShell.Generics.SubmodelElementTypes;
+
+namespace BaSyx.API.Components
+{
+ public class SubmodelServiceProvider : ISubmodelServiceProvider
+ {
+ public static JsonSerializerSettings JsonSerializerSettings { get; set; }
+ static SubmodelServiceProvider()
+ {
+ JsonSerializerSettings = new JsonStandardSettings();
+ }
+
+ public ISubmodel Submodel { get; protected set; }
+ public ISubmodelDescriptor ServiceDescriptor { get; internal set; }
+
+ private Dictionary<string, Delegate> methodCalledHandler;
+ private Dictionary<string, PropertyHandler> propertyHandler;
+ private Dictionary<string, Action<IValue>> updateFunctions;
+ private Dictionary<string, EventDelegate> eventDelegates;
+
+ private IMessageClient messageClient;
+
+ private readonly GetPropertyValueHandler GenericPropertyGetHandler = de => { return new ElementValue(de.Value, de.ValueType); };
+ private readonly SetPropertyValueHandler GenericPropertySetHandler = (de, val) => { de.Value = val.Value; };
+
+ public SubmodelServiceProvider()
+ {
+ methodCalledHandler = new Dictionary<string, Delegate>();
+ propertyHandler = new Dictionary<string, PropertyHandler>();
+ updateFunctions = new Dictionary<string, Action<IValue>>();
+ eventDelegates = new Dictionary<string, EventDelegate>();
+ }
+
+ public SubmodelServiceProvider(ISubmodel submodel) : this()
+ {
+ BindTo(submodel);
+ }
+ public SubmodelServiceProvider(ISubmodel submodel, ISubmodelDescriptor submodelDescriptor) : this()
+ {
+ Submodel = submodel;
+ ServiceDescriptor = submodelDescriptor;
+ }
+
+ public void BindTo(ISubmodel element)
+ {
+ Submodel = element;
+ ServiceDescriptor = new SubmodelDescriptor(element, null);
+ }
+ public ISubmodel GetBinding()
+ {
+ return Submodel;
+ }
+
+ public void UseInMemoryPropertyHandler()
+ {
+ if(Submodel.Properties?.Count() > 0)
+ foreach (var property in Submodel.Properties)
+ {
+ RegisterPropertyHandler(property.IdShort,
+ new PropertyHandler(property.Get ?? GenericPropertyGetHandler, property.Set ?? GenericPropertySetHandler));
+ }
+ }
+
+ public void UsePropertyHandler(PropertyHandler propertyHandler)
+ {
+ if (Submodel.Properties?.Count() > 0)
+ foreach (var property in Submodel.Properties)
+ RegisterPropertyHandler(property.IdShort, propertyHandler);
+ }
+
+ public void UseOperationHandler(MethodCalledHandler methodCalledHandler)
+ {
+ if (Submodel.Operations?.Count() > 0)
+ foreach (var operation in Submodel.Operations)
+ RegisterMethodCalledHandler(operation.IdShort, methodCalledHandler);
+ }
+
+ public IResult<IEvent> CreateEvent(IEvent eventable)
+ {
+ if (Submodel == null)
+ return new Result<IEvent>(false, new NotFoundMessage("Submodel"));
+
+ return Submodel.SubmodelElements.Create(eventable);
+ }
+
+ public IResult<IOperation> CreateOperation(IOperation operation)
+ {
+ if (Submodel == null)
+ return new Result<IOperation>(false, new NotFoundMessage("Submodel"));
+
+ return Submodel.SubmodelElements.Create(operation);
+ }
+
+ public IResult<IProperty> CreateProperty(IProperty property)
+ {
+ if (Submodel == null)
+ return new Result<IProperty>(false, new NotFoundMessage("Submodel"));
+
+ RegisterPropertyHandler(property.IdShort,
+ new PropertyHandler(property.Get ?? GenericPropertyGetHandler, property.Set ?? GenericPropertySetHandler));
+
+ return Submodel.SubmodelElements.Create(property);
+ }
+
+ public IResult DeleteEvent(string eventId)
+ {
+ if (Submodel == null)
+ return new Result(false, new NotFoundMessage("Submodel"));
+
+ if (Submodel.Events == null)
+ return new Result(false, new NotFoundMessage(eventId));
+ return Submodel.SubmodelElements.Delete(eventId);
+ }
+
+ public IResult DeleteOperation(string operationId)
+ {
+ if (Submodel == null)
+ return new Result(false, new NotFoundMessage("Submodel"));
+
+ if (Submodel.Operations == null)
+ return new Result(false, new NotFoundMessage(operationId));
+ return Submodel.SubmodelElements.Delete(operationId);
+ }
+
+ public IResult DeleteProperty(string propertyId)
+ {
+ if (Submodel == null)
+ return new Result(false, new NotFoundMessage("Submodel"));
+
+ if (Submodel.Properties == null)
+ return new Result(false, new NotFoundMessage(propertyId));
+
+ if (propertyHandler.ContainsKey(propertyId))
+ propertyHandler.Remove(propertyId);
+
+ return Submodel.SubmodelElements.Delete(propertyId);
+ }
+
+ public MethodCalledHandler RetrieveMethodCalledHandler(string operationId)
+ {
+ if (methodCalledHandler.TryGetValue(operationId, out Delegate handler))
+ return (MethodCalledHandler)handler;
+ else
+ return null;
+ }
+
+ public Delegate RetrieveMethodDelegate(string operationId)
+ {
+ if (methodCalledHandler.TryGetValue(operationId, out Delegate handler))
+ return handler;
+ else
+ return null;
+ }
+
+ public PropertyHandler RetrievePropertyHandler(string propertyId)
+ {
+ if (propertyHandler.TryGetValue(propertyId, out PropertyHandler handler))
+ return handler;
+ else
+ return null;
+ }
+
+ public void RegisterPropertyHandler(string propertyId, PropertyHandler handler)
+ {
+ if (!propertyHandler.ContainsKey(propertyId))
+ propertyHandler.Add(propertyId, handler);
+ else
+ propertyHandler[propertyId] = handler;
+ }
+
+ public void RegisterMethodCalledHandler(string operationId, MethodCalledHandler handler)
+ {
+ if (!methodCalledHandler.ContainsKey(operationId))
+ methodCalledHandler.Add(operationId, handler);
+ else
+ methodCalledHandler[operationId] = handler;
+ }
+
+ public void RegisterMethodCalledHandler(string operationId, Delegate handler)
+ {
+ if (!methodCalledHandler.ContainsKey(operationId))
+ methodCalledHandler.Add(operationId, handler);
+ else
+ methodCalledHandler[operationId] = handler;
+ }
+
+ public void RegisterEventDelegate(string eventId, EventDelegate eventDelegate)
+ {
+ if (!eventDelegates.ContainsKey(eventId))
+ eventDelegates.Add(eventId, eventDelegate);
+ else
+ eventDelegates[eventId] = eventDelegate;
+ }
+
+ public void RegisterMethodCalledHandler(string operationId, MethodInfo methodInfo, object target)
+ {
+ var parameters = from parameter in methodInfo.GetParameters() select parameter.ParameterType;
+ Delegate del = methodInfo.CreateDelegate(Expression.GetDelegateType(parameters.Concat(new[] { methodInfo.ReturnType }).ToArray()), target);
+ RegisterMethodCalledHandler(operationId, del);
+ }
+
+ public IResult InvokeOperation(string operationId, IOperationVariableSet inputArguments, IOperationVariableSet outputArguments, int timeout)
+ {
+ if (Submodel == null)
+ return new Result(false, new NotFoundMessage("Submodel"));
+
+ var operation_Retrieved = RetrieveOperation(operationId);
+ if (operation_Retrieved.Success && operation_Retrieved.Entity != null)
+ {
+ if (operation_Retrieved.Entity.OnMethodCalled != null)
+ {
+ var result = operation_Retrieved.Entity.OnMethodCalled.Invoke(operation_Retrieved.Entity, inputArguments, outputArguments);
+ return result;
+ }
+ else if (methodCalledHandler.TryGetValue(operationId, out Delegate handler))
+ {
+ var result = (IResult)handler.DynamicInvoke(operation_Retrieved.Entity, inputArguments, outputArguments);
+ return result;
+ }
+ }
+ outputArguments = null;
+ return operation_Retrieved;
+ }
+
+ public IResult ThrowEvent(IPublishableEvent publishableEvent, string topic = "/", Action<IMessagePublishedEventArgs> MessagePublished = null, byte qosLevel = 2, bool retain = false)
+ {
+ if (messageClient == null || !messageClient.IsConnected)
+ return new Result(false, new Message(MessageType.Warning, "MessageClient is not initialized or not connected"));
+
+ if (publishableEvent == null)
+ return new Result(new ArgumentNullException("publishableEvent"));
+
+ if (eventDelegates.TryGetValue(publishableEvent.Name, out EventDelegate eventDelegate))
+ eventDelegate.Invoke(this, publishableEvent);
+
+ string message = JsonConvert.SerializeObject(publishableEvent, JsonSerializerSettings);
+ return messageClient.Publish(topic, message, MessagePublished, qosLevel, retain);
+ }
+
+ public IResult<IEvent> RetrieveEvent(string eventId)
+ {
+ if (Submodel == null)
+ return new Result<IEvent>(false, new NotFoundMessage("Submodel"));
+
+ if (Submodel.Events == null)
+ return new Result<IEvent>(false, new NotFoundMessage(eventId));
+ return Submodel.SubmodelElements.Retrieve<IEvent>(eventId);
+ }
+
+ public IResult<IElementContainer<IEvent>> RetrieveEvents()
+ {
+ if (Submodel == null)
+ return new Result<ElementContainer<IEvent>>(false, new NotFoundMessage("Submodel"));
+
+ if(Submodel.Events == null)
+ return new Result<ElementContainer<IEvent>>(false, new NotFoundMessage("Events"));
+ return Submodel.SubmodelElements.RetrieveAll<IEvent>();
+ }
+
+ public IResult<IOperation> RetrieveOperation(string operationId)
+ {
+ if (Submodel == null)
+ return new Result<IOperation>(false, new NotFoundMessage("Submodel"));
+
+ if (Submodel.Operations == null)
+ return new Result<IOperation>(false, new NotFoundMessage(operationId));
+ return Submodel.SubmodelElements.Retrieve<IOperation>(operationId);
+ }
+
+ public IResult<IElementContainer<IOperation>> RetrieveOperations()
+ {
+ if (Submodel == null)
+ return new Result<ElementContainer<IOperation>>(false, new NotFoundMessage("Submodel"));
+
+ if (Submodel.Operations == null)
+ return new Result<ElementContainer<IOperation>>(false, new NotFoundMessage("Operations"));
+ return Submodel.SubmodelElements.RetrieveAll<IOperation>();
+ }
+
+ public IResult<IElementContainer<IProperty>> RetrieveProperties()
+ {
+ if (Submodel == null)
+ return new Result<ElementContainer<IProperty>>(false, new NotFoundMessage("Submodel"));
+
+ if (Submodel.Properties == null)
+ return new Result<ElementContainer<IProperty>>(false, new NotFoundMessage("Properties"));
+ return Submodel.SubmodelElements.RetrieveAll<IProperty>();
+ }
+
+ public IResult<IProperty> RetrieveProperty(string propertyId)
+ {
+ if (Submodel == null)
+ return new Result<IProperty>(false, new NotFoundMessage("Submodel"));
+
+ if (Submodel.Properties == null)
+ return new Result<IProperty>(false, new NotFoundMessage(propertyId));
+ return Submodel.SubmodelElements.Retrieve<IProperty>(propertyId);
+ }
+
+ public IResult<IValue> RetrievePropertyValue(string propertyId)
+ {
+ if (Submodel == null)
+ return new Result<IValue>(false, new NotFoundMessage("Submodel"));
+
+ if (propertyHandler.TryGetValue(propertyId, out PropertyHandler handler) && handler.GetHandler != null)
+ {
+ var property = RetrieveProperty(propertyId);
+ if(property.Success && property.Entity != null)
+ return new Result<IValue>(true, handler.GetHandler.Invoke(property.Entity));
+ else
+ return new Result<IValue>(false, new Message(MessageType.Error, "property not found"));
+ }
+ else
+ return new Result<IValue>(false, new Message(MessageType.Error, "propertyHandler or GetHandler not found"));
+ }
+
+
+ public IResult UpdatePropertyValue(string propertyId, IValue value)
+ {
+ if (Submodel == null)
+ return new Result(false, new NotFoundMessage("Submodel"));
+
+ if (propertyHandler.TryGetValue(propertyId, out PropertyHandler handler) && handler.SetHandler != null)
+ {
+ var property = RetrieveProperty(propertyId);
+ if (property.Success && property.Entity != null)
+ {
+ handler.SetHandler.Invoke(property.Entity, value);
+ return new Result(true);
+ }
+ else
+ return new Result<IValue>(false, new Message(MessageType.Error, "property not found"));
+ }
+ else
+ return new Result<IValue>(false, new Message(MessageType.Error, "propertyHandler or SetHandler not found"));
+ }
+
+ public virtual void ConfigureEventHandler(IMessageClient messageClient)
+ {
+ this.messageClient = messageClient;
+ }
+
+ public virtual void SubscribeUpdates(string propertyId, Action<IValue> updateFunction)
+ {
+ if (!updateFunctions.ContainsKey(propertyId))
+ updateFunctions.Add(propertyId, updateFunction);
+ else
+ updateFunctions[propertyId] = updateFunction;
+ }
+
+ public virtual void PublishUpdate(string propertyId, IValue value)
+ {
+ if (updateFunctions.TryGetValue(propertyId, out Action<IValue> updateFunction))
+ updateFunction.Invoke(value);
+
+ }
+
+ public IResult<ISubmodel> RetrieveSubmodel()
+ {
+ var submodel = GetBinding();
+ return new Result<ISubmodel>(submodel != null, submodel);
+ }
+
+ public IResult<ISubmodelElement> CreateSubmodelElement(ISubmodelElement submodelElement)
+ {
+ if (Submodel == null)
+ return new Result<ISubmodelElement>(false, new NotFoundMessage("Submodel"));
+
+ return Submodel.SubmodelElements.Create(submodelElement);
+ }
+
+ public IResult<IElementContainer<ISubmodelElement>> RetrieveSubmodelElements()
+ {
+ if (Submodel == null)
+ return new Result<ElementContainer<ISubmodelElement>>(false, new NotFoundMessage("Submodel"));
+
+ if (Submodel.SubmodelElements == null)
+ return new Result<ElementContainer<ISubmodelElement>>(false, new NotFoundMessage("SubmodelElements"));
+ return Submodel.SubmodelElements.RetrieveAll();
+ }
+
+ public IResult<ISubmodelElement> RetrieveSubmodelElement(string submodelElementId)
+ {
+ if (Submodel == null)
+ return new Result<ISubmodelElement>(false, new NotFoundMessage("Submodel"));
+
+ if (Submodel.SubmodelElements == null)
+ return new Result<ISubmodelElement>(false, new NotFoundMessage(submodelElementId));
+ return Submodel.SubmodelElements.Retrieve(submodelElementId);
+ }
+
+ public IResult<IValue> RetrieveSubmodelElementValue(string submodelElementId)
+ {
+ if (Submodel == null)
+ return new Result<IValue>(false, new NotFoundMessage("Submodel"));
+
+ if (Submodel.SubmodelElements == null)
+ return new Result<IValue>(false, new NotFoundMessage(submodelElementId));
+
+ return new Result<IValue>(true,
+ new ElementValue(
+ (Submodel.SubmodelElements[submodelElementId] as dynamic).Value,
+ (Submodel.SubmodelElements[submodelElementId] as dynamic).ValueType as DataType));
+ }
+
+ public IResult UpdateSubmodelElement(string submodelElementId, ISubmodelElement submodelElement)
+ {
+ if (Submodel == null)
+ return new Result(false, new NotFoundMessage("Submodel"));
+
+ if (Submodel.SubmodelElements == null)
+ return new Result(false, new NotFoundMessage(submodelElementId));
+
+ return Submodel.SubmodelElements.Update(submodelElementId, submodelElement);
+ }
+
+ public IResult DeleteSubmodelElement(string submodelElementId)
+ {
+ if (Submodel == null)
+ return new Result(false, new NotFoundMessage("Submodel"));
+
+ if (Submodel.SubmodelElements == null)
+ return new Result(false, new NotFoundMessage(submodelElementId));
+
+ return Submodel.SubmodelElements.Delete(submodelElementId);
+ }
+ }
+}