blob: 3ea1ef99a2f03536da3b810e59596f4b9793d4b9 [file] [log] [blame]
Constantin Ziesche857c7ab2020-02-25 11:24:51 +01001/*******************************************************************************
2* Copyright (c) 2020 Robert Bosch GmbH
3* Author: Constantin Ziesche (constantin.ziesche@bosch.com)
4*
5* This program and the accompanying materials are made available under the
6* terms of the Eclipse Public License 2.0 which is available at
7* http://www.eclipse.org/legal/epl-2.0
8*
9* SPDX-License-Identifier: EPL-2.0
10*******************************************************************************/
11using BaSyx.API.AssetAdministrationShell;
12using BaSyx.Models.Core.AssetAdministrationShell.Generics;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010013using BaSyx.Utils.ResultHandling;
14using BaSyx.Utils.Client;
15using System.Collections.Generic;
16using System;
17using Newtonsoft.Json;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010018using System.Linq;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010019using BaSyx.Models.Connectivity.Descriptors;
20using BaSyx.Models.Core.Common;
Constantin Zieschefa612082020-04-03 09:54:56 +020021using BaSyx.Models.Communication;
22using System.Threading.Tasks;
Constantin Ziesche08215502020-09-21 19:08:32 +020023using NLog;
24using System.Threading;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010025
26namespace BaSyx.API.Components
27{
Constantin Ziesche08215502020-09-21 19:08:32 +020028 /// <summary>
29 /// Reference implementation of ISubmodelServiceProvider interface
30 /// </summary>
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010031 public class SubmodelServiceProvider : ISubmodelServiceProvider
32 {
Constantin Ziesche08215502020-09-21 19:08:32 +020033 private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
34
35 private ISubmodel _submodel;
36
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010037 public ISubmodelDescriptor ServiceDescriptor { get; internal set; }
38
Constantin Ziesche08215502020-09-21 19:08:32 +020039 private readonly Dictionary<string, MethodCalledHandler> methodCalledHandler;
40 private readonly Dictionary<string, SubmodelElementHandler> submodelElementHandler;
Constantin Zieschee837f992020-08-19 12:04:32 +020041 private readonly Dictionary<string, Action<IValue>> updateFunctions;
42 private readonly Dictionary<string, EventDelegate> eventDelegates;
43 private readonly Dictionary<string, InvocationResponse> invocationResults;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010044
45 private IMessageClient messageClient;
46
Constantin Ziesche08215502020-09-21 19:08:32 +020047 /// <summary>
48 /// Constructor for SubmodelServiceProvider
49 /// </summary>
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010050 public SubmodelServiceProvider()
51 {
Constantin Ziesche08215502020-09-21 19:08:32 +020052 methodCalledHandler = new Dictionary<string, MethodCalledHandler>();
53 submodelElementHandler = new Dictionary<string, SubmodelElementHandler>();
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010054 updateFunctions = new Dictionary<string, Action<IValue>>();
55 eventDelegates = new Dictionary<string, EventDelegate>();
Constantin Zieschefa612082020-04-03 09:54:56 +020056 invocationResults = new Dictionary<string, InvocationResponse>();
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010057 }
Constantin Ziesche08215502020-09-21 19:08:32 +020058 /// <summary>
59 /// Contructor for SubmodelServiceProvider with a Submodel object to bind to
60 /// </summary>
61 /// <param name="submodel">Submodel object</param>
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010062 public SubmodelServiceProvider(ISubmodel submodel) : this()
63 {
64 BindTo(submodel);
65 }
Constantin Ziesche08215502020-09-21 19:08:32 +020066 /// <summary>
67 /// Contructor for SubmodelServiceProvider with a Submodel object to bind to and a SubmodelDescriptor as ServiceDescriptor
68 /// </summary>
69 /// <param name="submodel">Submodel object</param>
70 /// <param name="submodelDescriptor">SubmodelDescriptor object</param>
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010071 public SubmodelServiceProvider(ISubmodel submodel, ISubmodelDescriptor submodelDescriptor) : this()
72 {
Constantin Ziesche08215502020-09-21 19:08:32 +020073 _submodel = submodel;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010074 ServiceDescriptor = submodelDescriptor;
75 }
76
Constantin Ziesche08215502020-09-21 19:08:32 +020077 /// <summary>
78 /// Bind this SubmodelServiceProvider to a specific Submodel
79 /// </summary>
80 /// <param name="submodel">Submodel object</param>
81 public void BindTo(ISubmodel submodel)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010082 {
Constantin Ziesche08215502020-09-21 19:08:32 +020083 _submodel = submodel;
84 ServiceDescriptor = new SubmodelDescriptor(submodel, null);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010085 }
Constantin Ziesche08215502020-09-21 19:08:32 +020086
87 /// <summary>
88 /// Returns the model binding of this SubmodelServiceProvider
89 /// </summary>
90 /// <returns>Submodel object</returns>
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010091 public ISubmodel GetBinding()
92 {
Constantin Ziesche08215502020-09-21 19:08:32 +020093 return _submodel;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010094 }
95
Constantin Ziesche08215502020-09-21 19:08:32 +020096 public void UseInMemorySubmodelElementHandler()
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010097 {
Constantin Ziesche08215502020-09-21 19:08:32 +020098 UseInMemorySubmodelElementHandlerInternal(_submodel.SubmodelElements);
99 }
100 private void UseInMemorySubmodelElementHandlerInternal(IElementContainer<ISubmodelElement> submodelElements)
101 {
102 if (submodelElements.HasChildren())
103 {
104 foreach (var child in submodelElements.Children)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100105 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200106 UseInMemorySubmodelElementHandlerInternal(child);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100107 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200108 }
109 if(submodelElements.Value != null)
110 {
111 if (submodelElements.Value.ModelType != ModelType.Operation)
112 RegisterSubmodelElementHandler(submodelElements.Path, new SubmodelElementHandler(submodelElements.Value.Get, submodelElements.Value.Set));
113 }
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100114 }
115
Constantin Ziesche08215502020-09-21 19:08:32 +0200116 /// <summary>
117 /// Use as specific SubmodelElementHandler for all SubmodelElements
118 /// </summary>
119 /// <param name="elementHandler">SubmodelElementHandler</param>
120 public void UseSubmodelElementHandler(SubmodelElementHandler elementHandler)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100121 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200122 UseSubmodelElementHandlerInternal(_submodel.SubmodelElements, elementHandler, null);
123 }
124 /// <summary>
125 /// Use a specific SubmodelElementHandler for all SubmodelElements of a specific ModelType (e.g. Property) except Operations
126 /// </summary>
127 /// <param name="elementHandler">SubmodelElementHandler</param>
128 /// <param name="modelType">ModelType</param>
129 public void UseSubmodelElementHandlerForModelType(SubmodelElementHandler elementHandler, ModelType modelType)
130 {
131 UseSubmodelElementHandlerInternal(_submodel.SubmodelElements, elementHandler, modelType);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100132 }
133
Constantin Ziesche08215502020-09-21 19:08:32 +0200134 private void UseSubmodelElementHandlerInternal(IElementContainer<ISubmodelElement> submodelElements, SubmodelElementHandler elementHandler, ModelType modelType = null)
135 {
136 if (submodelElements.HasChildren())
137 {
138 foreach (var child in submodelElements.Children)
139 {
140 UseSubmodelElementHandlerInternal(child, elementHandler, modelType);
141 }
142 }
143 if (submodelElements.Value != null)
144 {
145 if (modelType == null)
146 RegisterSubmodelElementHandler(submodelElements.Path, elementHandler);
147 else if (submodelElements.Value.ModelType == modelType)
148 RegisterSubmodelElementHandler(submodelElements.Path, elementHandler);
149 else
150 return;
151 }
152 }
153 /// <summary>
154 /// Use a specific MethodCalledHandler for all Operations
155 /// </summary>
156 /// <param name="methodCalledHandler"></param>
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100157 public void UseOperationHandler(MethodCalledHandler methodCalledHandler)
158 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200159 UseOperationHandlerInternal(_submodel.SubmodelElements, methodCalledHandler);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100160 }
161
Constantin Ziesche08215502020-09-21 19:08:32 +0200162 private void UseOperationHandlerInternal(IElementContainer<ISubmodelElement> submodelElements, MethodCalledHandler methodCalledHandler)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100163 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200164 if (submodelElements.HasChildren())
165 {
166 foreach (var child in submodelElements.Children)
167 {
168 UseOperationHandlerInternal(child, methodCalledHandler);
169 }
170 }
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100171 else
Constantin Ziesche08215502020-09-21 19:08:32 +0200172 {
173 if (submodelElements.Value is IOperation)
174 RegisterMethodCalledHandler(submodelElements.Path, methodCalledHandler);
175 else
176 return;
177 }
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100178 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200179
180 public MethodCalledHandler RetrieveMethodCalledHandler(string pathToOperation)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100181 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200182 if (methodCalledHandler.TryGetValue(pathToOperation, out MethodCalledHandler handler))
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100183 return handler;
184 else
185 return null;
186 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200187
188 public SubmodelElementHandler RetrieveSubmodelElementHandler(string pathToElement)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100189 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200190 if (submodelElementHandler.TryGetValue(pathToElement, out SubmodelElementHandler elementHandler))
191 return elementHandler;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100192 else
193 return null;
194 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200195
196 public void RegisterSubmodelElementHandler(string pathToElement, SubmodelElementHandler elementHandler)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100197 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200198 if (!submodelElementHandler.ContainsKey(pathToElement))
199 submodelElementHandler.Add(pathToElement, elementHandler);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100200 else
Constantin Ziesche08215502020-09-21 19:08:32 +0200201 submodelElementHandler[pathToElement] = elementHandler;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100202 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200203
204 public void RegisterMethodCalledHandler(string pathToOperation, MethodCalledHandler handler)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100205 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200206 if (!methodCalledHandler.ContainsKey(pathToOperation))
207 methodCalledHandler.Add(pathToOperation, handler);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100208 else
Constantin Ziesche08215502020-09-21 19:08:32 +0200209 methodCalledHandler[pathToOperation] = handler;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100210 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200211
212 public void RegisterEventDelegate(string pathToEvent, EventDelegate eventDelegate)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100213 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200214 if (!eventDelegates.ContainsKey(pathToEvent))
215 eventDelegates.Add(pathToEvent, eventDelegate);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100216 else
Constantin Ziesche08215502020-09-21 19:08:32 +0200217 eventDelegates[pathToEvent] = eventDelegate;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100218 }
219
Constantin Ziesche08215502020-09-21 19:08:32 +0200220 public IResult<InvocationResponse> InvokeOperation(string pathToOperation, InvocationRequest invocationRequest)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100221 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200222 if (_submodel == null)
223 return new Result<InvocationResponse>(false, new NotFoundMessage("Submodel"));
224
225 var operation_Retrieved = _submodel.SubmodelElements.Retrieve<IOperation>(pathToOperation);
226 if (operation_Retrieved.Success && operation_Retrieved.Entity != null)
227 {
228 MethodCalledHandler methodHandler;
229 if (operation_Retrieved.Entity.OnMethodCalled != null)
230 methodHandler = operation_Retrieved.Entity.OnMethodCalled;
231 else if (methodCalledHandler.TryGetValue(pathToOperation, out MethodCalledHandler handler))
232 methodHandler = handler;
233 else
234 return new Result<InvocationResponse>(false, new NotFoundMessage($"MethodHandler for {pathToOperation}"));
235
236 InvocationResponse invocationResponse = new InvocationResponse(invocationRequest.RequestId);
237 invocationResponse.InOutputArguments = invocationRequest.InOutputArguments;
238
239 using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource())
240 {
241 Task<OperationResult> runner = Task.Run(async () =>
242 {
243 try
244 {
245 invocationResponse.ExecutionState = ExecutionState.Running;
246 var result = await methodHandler.Invoke(operation_Retrieved.Entity, invocationRequest.InputArguments, invocationResponse.InOutputArguments, invocationResponse.OutputArguments, cancellationTokenSource.Token);
247 invocationResponse.ExecutionState = ExecutionState.Completed;
248 return result;
249 }
250 catch (Exception e)
251 {
252 invocationResponse.ExecutionState = ExecutionState.Failed;
253 return new OperationResult(e);
254 }
255
256 }, cancellationTokenSource.Token);
257
258 if (Task.WhenAny(runner, Task.Delay(invocationRequest.Timeout.Value, cancellationTokenSource.Token)).Result == runner)
259 {
260 cancellationTokenSource.Cancel();
261 invocationResponse.OperationResult = runner.Result;
262 return new Result<InvocationResponse>(true, invocationResponse);
263 }
264 else
265 {
266 cancellationTokenSource.Cancel();
267 invocationResponse.OperationResult = new OperationResult(false, new TimeoutMessage());
268 invocationResponse.ExecutionState = ExecutionState.Timeout;
269 return new Result<InvocationResponse>(false, invocationResponse);
270 }
271 }
272 }
273 return new Result<InvocationResponse>(operation_Retrieved);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100274 }
275
Constantin Ziesche08215502020-09-21 19:08:32 +0200276 public IResult<CallbackResponse> InvokeOperationAsync(string pathToOperation, InvocationRequest invocationRequest)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100277 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200278 if (_submodel == null)
Constantin Zieschefa612082020-04-03 09:54:56 +0200279 return new Result<CallbackResponse>(false, new NotFoundMessage("Submodel"));
280 if (invocationRequest == null)
281 return new Result<CallbackResponse>(new ArgumentNullException(nameof(invocationRequest)));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100282
Constantin Ziesche08215502020-09-21 19:08:32 +0200283 var operation_Retrieved = _submodel.SubmodelElements.Retrieve<IOperation>(pathToOperation);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100284 if (operation_Retrieved.Success && operation_Retrieved.Entity != null)
285 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200286 MethodCalledHandler methodHandler;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100287 if (operation_Retrieved.Entity.OnMethodCalled != null)
Constantin Ziesche08215502020-09-21 19:08:32 +0200288 methodHandler = operation_Retrieved.Entity.OnMethodCalled;
289 else if (methodCalledHandler.TryGetValue(pathToOperation, out MethodCalledHandler handler))
290 methodHandler = handler;
Constantin Zieschefa612082020-04-03 09:54:56 +0200291 else
Constantin Ziesche08215502020-09-21 19:08:32 +0200292 return new Result<CallbackResponse>(false, new NotFoundMessage($"MethodHandler for {pathToOperation}"));
Constantin Zieschefa612082020-04-03 09:54:56 +0200293
Constantin Ziesche08215502020-09-21 19:08:32 +0200294 Task invocationTask = Task.Run(async() =>
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100295 {
Constantin Zieschefa612082020-04-03 09:54:56 +0200296 InvocationResponse invocationResponse = new InvocationResponse(invocationRequest.RequestId);
Constantin Ziesche08215502020-09-21 19:08:32 +0200297 invocationResponse.InOutputArguments = invocationRequest.InOutputArguments;
298 SetInvocationResult(pathToOperation, invocationRequest.RequestId, ref invocationResponse);
Constantin Zieschefa612082020-04-03 09:54:56 +0200299
Constantin Ziesche08215502020-09-21 19:08:32 +0200300 using (var cancellationTokenSource = new CancellationTokenSource())
Constantin Zieschefa612082020-04-03 09:54:56 +0200301 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200302 Task<OperationResult> runner = Task.Run(async () =>
303 {
304 try
305 {
306 invocationResponse.ExecutionState = ExecutionState.Running;
307 var result = await methodHandler.Invoke(operation_Retrieved.Entity, invocationRequest.InputArguments, invocationResponse.InOutputArguments, invocationResponse.OutputArguments, cancellationTokenSource.Token);
308 invocationResponse.ExecutionState = ExecutionState.Completed;
309 return result;
310 }
311 catch (Exception e)
312 {
313 invocationResponse.ExecutionState = ExecutionState.Failed;
314 return new OperationResult(e);
315 }
316 }, cancellationTokenSource.Token);
317
318 if (await Task.WhenAny(runner, Task.Delay(invocationRequest.Timeout.Value, cancellationTokenSource.Token)) == runner)
319 {
320 cancellationTokenSource.Cancel();
321 invocationResponse.OperationResult = runner.Result;
322 }
323 else
324 {
325 cancellationTokenSource.Cancel();
326 invocationResponse.OperationResult = new OperationResult(false, new TimeoutMessage());
327 invocationResponse.ExecutionState = ExecutionState.Timeout;
328 }
Constantin Zieschefa612082020-04-03 09:54:56 +0200329 }
330 });
Constantin Ziesche08215502020-09-21 19:08:32 +0200331
Constantin Zieschefa612082020-04-03 09:54:56 +0200332 string endpoint = ServiceDescriptor?.Endpoints?.FirstOrDefault()?.Address;
333 CallbackResponse callbackResponse = new CallbackResponse(invocationRequest.RequestId);
334 if (string.IsNullOrEmpty(endpoint))
Constantin Ziesche08215502020-09-21 19:08:32 +0200335 callbackResponse.CallbackUrl = new Uri($"/submodelElements/{pathToOperation}/invocationList/{invocationRequest.RequestId}", UriKind.Relative);
Constantin Zieschefa612082020-04-03 09:54:56 +0200336 else
Constantin Ziesche08215502020-09-21 19:08:32 +0200337 callbackResponse.CallbackUrl = new Uri($"{endpoint}/submodelElements/{pathToOperation}/invocationList/{invocationRequest.RequestId}", UriKind.Absolute);
Constantin Zieschefa612082020-04-03 09:54:56 +0200338 return new Result<CallbackResponse>(true, callbackResponse);
339 }
340 return new Result<CallbackResponse>(operation_Retrieved);
341 }
342
343 private void SetInvocationResult(string operationId, string requestId, ref InvocationResponse invocationResponse)
344 {
345 string key = string.Join("_", operationId, requestId);
346 if (invocationResults.ContainsKey(key))
347 {
348 invocationResults[key] = invocationResponse;
349 }
350 else
351 {
352 invocationResults.Add(key, invocationResponse);
353 }
354 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200355
356 public IResult<InvocationResponse> GetInvocationResult(string pathToOperation, string requestId)
Constantin Zieschefa612082020-04-03 09:54:56 +0200357 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200358 string key = string.Join("_", pathToOperation, requestId);
Constantin Zieschefa612082020-04-03 09:54:56 +0200359 if (invocationResults.ContainsKey(key))
360 {
361 return new Result<InvocationResponse>(true, invocationResults[key]);
362 }
363 else
364 {
365 return new Result<InvocationResponse>(false, new NotFoundMessage($"Request with id {requestId}"));
366 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200367 }
368
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100369 public IResult ThrowEvent(IPublishableEvent publishableEvent, string topic = "/", Action<IMessagePublishedEventArgs> MessagePublished = null, byte qosLevel = 2, bool retain = false)
370 {
371 if (messageClient == null || !messageClient.IsConnected)
372 return new Result(false, new Message(MessageType.Warning, "MessageClient is not initialized or not connected"));
373
374 if (publishableEvent == null)
Constantin Zieschee837f992020-08-19 12:04:32 +0200375 return new Result(new ArgumentNullException(nameof(publishableEvent)));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100376
377 if (eventDelegates.TryGetValue(publishableEvent.Name, out EventDelegate eventDelegate))
378 eventDelegate.Invoke(this, publishableEvent);
379
Constantin Zieschefa612082020-04-03 09:54:56 +0200380 string message = JsonConvert.SerializeObject(publishableEvent, Formatting.Indented);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100381 return messageClient.Publish(topic, message, MessagePublished, qosLevel, retain);
382 }
383
Constantin Ziesche08215502020-09-21 19:08:32 +0200384
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100385 public virtual void ConfigureEventHandler(IMessageClient messageClient)
386 {
387 this.messageClient = messageClient;
388 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200389
390 public virtual void SubscribeUpdates(string pathToSubmodelElement, Action<IValue> updateFunction)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100391 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200392 if (!updateFunctions.ContainsKey(pathToSubmodelElement))
393 updateFunctions.Add(pathToSubmodelElement, updateFunction);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100394 else
Constantin Ziesche08215502020-09-21 19:08:32 +0200395 updateFunctions[pathToSubmodelElement] = updateFunction;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100396 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200397
398 public virtual void PublishUpdate(string pathToSubmodelElement, IValue value)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100399 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200400 if (updateFunctions.TryGetValue(pathToSubmodelElement, out Action<IValue> updateFunction))
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100401 updateFunction.Invoke(value);
402
403 }
404
405 public IResult<ISubmodel> RetrieveSubmodel()
406 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200407 return new Result<ISubmodel>(_submodel != null, _submodel);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100408 }
409
Constantin Ziesche08215502020-09-21 19:08:32 +0200410 public IResult<ISubmodelElement> CreateSubmodelElement(string pathToSubmodelElement, ISubmodelElement submodelElement)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100411 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200412 if (_submodel == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100413 return new Result<ISubmodelElement>(false, new NotFoundMessage("Submodel"));
414
Constantin Ziesche08215502020-09-21 19:08:32 +0200415 return _submodel.SubmodelElements.Create(submodelElement);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100416 }
417
418 public IResult<IElementContainer<ISubmodelElement>> RetrieveSubmodelElements()
419 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200420 if (_submodel == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100421 return new Result<ElementContainer<ISubmodelElement>>(false, new NotFoundMessage("Submodel"));
422
Constantin Ziesche08215502020-09-21 19:08:32 +0200423 if (_submodel.SubmodelElements == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100424 return new Result<ElementContainer<ISubmodelElement>>(false, new NotFoundMessage("SubmodelElements"));
Constantin Ziesche08215502020-09-21 19:08:32 +0200425 return _submodel.SubmodelElements.RetrieveAll();
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100426 }
427
428 public IResult<ISubmodelElement> RetrieveSubmodelElement(string submodelElementId)
429 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200430 if (_submodel == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100431 return new Result<ISubmodelElement>(false, new NotFoundMessage("Submodel"));
432
Constantin Ziesche08215502020-09-21 19:08:32 +0200433 if (_submodel.SubmodelElements == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100434 return new Result<ISubmodelElement>(false, new NotFoundMessage(submodelElementId));
Constantin Ziesche8b4a64d2020-06-25 11:52:09 +0200435
Constantin Ziesche08215502020-09-21 19:08:32 +0200436 return _submodel.SubmodelElements.Retrieve(submodelElementId);
Constantin Ziesche8b4a64d2020-06-25 11:52:09 +0200437 }
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100438 public IResult<IValue> RetrieveSubmodelElementValue(string submodelElementId)
439 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200440 if (_submodel == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100441 return new Result<IValue>(false, new NotFoundMessage("Submodel"));
442
Constantin Ziesche08215502020-09-21 19:08:32 +0200443 if (submodelElementHandler.TryGetValue(submodelElementId, out SubmodelElementHandler elementHandler) && elementHandler.GetValueHandler != null)
444 {
445 var submodelElement = _submodel.SubmodelElements.Retrieve<ISubmodelElement>(submodelElementId);
446 if (submodelElement.Success && submodelElement.Entity != null)
447 return new Result<IValue>(true, elementHandler.GetValueHandler.Invoke(submodelElement.Entity));
448 else
449 return new Result<IValue>(false, new Message(MessageType.Error, "SubmodelElement not found"));
450 }
451 else
452 return new Result<IValue>(false, new Message(MessageType.Error, "SubmodelElementHandler not found"));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100453 }
454
455 public IResult UpdateSubmodelElement(string submodelElementId, ISubmodelElement submodelElement)
456 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200457 if (_submodel == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100458 return new Result(false, new NotFoundMessage("Submodel"));
459
Constantin Ziesche08215502020-09-21 19:08:32 +0200460 if (_submodel.SubmodelElements == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100461 return new Result(false, new NotFoundMessage(submodelElementId));
462
Constantin Ziesche08215502020-09-21 19:08:32 +0200463 return _submodel.SubmodelElements.Update(submodelElementId, submodelElement);
464 }
465
466 public IResult UpdateSubmodelElementValue(string submodelElementId, IValue value)
467 {
468 if (_submodel == null)
469 return new Result(false, new NotFoundMessage("Submodel"));
470
471 if (submodelElementHandler.TryGetValue(submodelElementId, out SubmodelElementHandler elementHandler) && elementHandler.SetValueHandler != null)
472 {
473 var submodelElement = _submodel.SubmodelElements.Retrieve<ISubmodelElement>(submodelElementId);
474 if (submodelElement.Success && submodelElement.Entity != null)
475 {
476 elementHandler.SetValueHandler.Invoke(submodelElement.Entity, value);
477 return new Result(true);
478 }
479 else
480 return new Result<IValue>(false, new Message(MessageType.Error, "property not found"));
481 }
482 else
483 return new Result<IValue>(false, new Message(MessageType.Error, "SubmodelElementHandler not found"));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100484 }
485
486 public IResult DeleteSubmodelElement(string submodelElementId)
487 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200488 if (_submodel == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100489 return new Result(false, new NotFoundMessage("Submodel"));
490
Constantin Ziesche08215502020-09-21 19:08:32 +0200491 if (_submodel.SubmodelElements == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100492 return new Result(false, new NotFoundMessage(submodelElementId));
493
Constantin Ziesche08215502020-09-21 19:08:32 +0200494 return _submodel.SubmodelElements.Delete(submodelElementId);
Constantin Zieschee837f992020-08-19 12:04:32 +0200495 }
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100496 }
497}