blob: 20d5cce0b74f780a6d242f7ec0a268b89fd9bda8 [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 Ziesche09dcb6b2020-10-07 13:47:39 +0200203
204 public void UnregisterSubmodelElementHandler(string pathToElement)
205 {
206 if (submodelElementHandler.ContainsKey(pathToElement))
207 submodelElementHandler.Remove(pathToElement);
208 }
209
Constantin Ziesche08215502020-09-21 19:08:32 +0200210 public void RegisterMethodCalledHandler(string pathToOperation, MethodCalledHandler handler)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100211 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200212 if (!methodCalledHandler.ContainsKey(pathToOperation))
213 methodCalledHandler.Add(pathToOperation, handler);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100214 else
Constantin Ziesche08215502020-09-21 19:08:32 +0200215 methodCalledHandler[pathToOperation] = handler;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100216 }
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200217
Constantin Ziesche08215502020-09-21 19:08:32 +0200218 public void RegisterEventDelegate(string pathToEvent, EventDelegate eventDelegate)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100219 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200220 if (!eventDelegates.ContainsKey(pathToEvent))
221 eventDelegates.Add(pathToEvent, eventDelegate);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100222 else
Constantin Ziesche08215502020-09-21 19:08:32 +0200223 eventDelegates[pathToEvent] = eventDelegate;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100224 }
225
Constantin Ziesche08215502020-09-21 19:08:32 +0200226 public IResult<InvocationResponse> InvokeOperation(string pathToOperation, InvocationRequest invocationRequest)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100227 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200228 if (_submodel == null)
229 return new Result<InvocationResponse>(false, new NotFoundMessage("Submodel"));
230
231 var operation_Retrieved = _submodel.SubmodelElements.Retrieve<IOperation>(pathToOperation);
232 if (operation_Retrieved.Success && operation_Retrieved.Entity != null)
233 {
234 MethodCalledHandler methodHandler;
235 if (operation_Retrieved.Entity.OnMethodCalled != null)
236 methodHandler = operation_Retrieved.Entity.OnMethodCalled;
237 else if (methodCalledHandler.TryGetValue(pathToOperation, out MethodCalledHandler handler))
238 methodHandler = handler;
239 else
240 return new Result<InvocationResponse>(false, new NotFoundMessage($"MethodHandler for {pathToOperation}"));
241
242 InvocationResponse invocationResponse = new InvocationResponse(invocationRequest.RequestId);
243 invocationResponse.InOutputArguments = invocationRequest.InOutputArguments;
244
245 using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource())
246 {
247 Task<OperationResult> runner = Task.Run(async () =>
248 {
249 try
250 {
251 invocationResponse.ExecutionState = ExecutionState.Running;
252 var result = await methodHandler.Invoke(operation_Retrieved.Entity, invocationRequest.InputArguments, invocationResponse.InOutputArguments, invocationResponse.OutputArguments, cancellationTokenSource.Token);
253 invocationResponse.ExecutionState = ExecutionState.Completed;
254 return result;
255 }
256 catch (Exception e)
257 {
258 invocationResponse.ExecutionState = ExecutionState.Failed;
259 return new OperationResult(e);
260 }
261
262 }, cancellationTokenSource.Token);
263
264 if (Task.WhenAny(runner, Task.Delay(invocationRequest.Timeout.Value, cancellationTokenSource.Token)).Result == runner)
265 {
266 cancellationTokenSource.Cancel();
267 invocationResponse.OperationResult = runner.Result;
268 return new Result<InvocationResponse>(true, invocationResponse);
269 }
270 else
271 {
272 cancellationTokenSource.Cancel();
273 invocationResponse.OperationResult = new OperationResult(false, new TimeoutMessage());
274 invocationResponse.ExecutionState = ExecutionState.Timeout;
275 return new Result<InvocationResponse>(false, invocationResponse);
276 }
277 }
278 }
279 return new Result<InvocationResponse>(operation_Retrieved);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100280 }
281
Constantin Ziesche08215502020-09-21 19:08:32 +0200282 public IResult<CallbackResponse> InvokeOperationAsync(string pathToOperation, InvocationRequest invocationRequest)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100283 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200284 if (_submodel == null)
Constantin Zieschefa612082020-04-03 09:54:56 +0200285 return new Result<CallbackResponse>(false, new NotFoundMessage("Submodel"));
286 if (invocationRequest == null)
287 return new Result<CallbackResponse>(new ArgumentNullException(nameof(invocationRequest)));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100288
Constantin Ziesche08215502020-09-21 19:08:32 +0200289 var operation_Retrieved = _submodel.SubmodelElements.Retrieve<IOperation>(pathToOperation);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100290 if (operation_Retrieved.Success && operation_Retrieved.Entity != null)
291 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200292 MethodCalledHandler methodHandler;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100293 if (operation_Retrieved.Entity.OnMethodCalled != null)
Constantin Ziesche08215502020-09-21 19:08:32 +0200294 methodHandler = operation_Retrieved.Entity.OnMethodCalled;
295 else if (methodCalledHandler.TryGetValue(pathToOperation, out MethodCalledHandler handler))
296 methodHandler = handler;
Constantin Zieschefa612082020-04-03 09:54:56 +0200297 else
Constantin Ziesche08215502020-09-21 19:08:32 +0200298 return new Result<CallbackResponse>(false, new NotFoundMessage($"MethodHandler for {pathToOperation}"));
Constantin Zieschefa612082020-04-03 09:54:56 +0200299
Constantin Ziesche08215502020-09-21 19:08:32 +0200300 Task invocationTask = Task.Run(async() =>
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100301 {
Constantin Zieschefa612082020-04-03 09:54:56 +0200302 InvocationResponse invocationResponse = new InvocationResponse(invocationRequest.RequestId);
Constantin Ziesche08215502020-09-21 19:08:32 +0200303 invocationResponse.InOutputArguments = invocationRequest.InOutputArguments;
304 SetInvocationResult(pathToOperation, invocationRequest.RequestId, ref invocationResponse);
Constantin Zieschefa612082020-04-03 09:54:56 +0200305
Constantin Ziesche08215502020-09-21 19:08:32 +0200306 using (var cancellationTokenSource = new CancellationTokenSource())
Constantin Zieschefa612082020-04-03 09:54:56 +0200307 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200308 Task<OperationResult> runner = Task.Run(async () =>
309 {
310 try
311 {
312 invocationResponse.ExecutionState = ExecutionState.Running;
313 var result = await methodHandler.Invoke(operation_Retrieved.Entity, invocationRequest.InputArguments, invocationResponse.InOutputArguments, invocationResponse.OutputArguments, cancellationTokenSource.Token);
314 invocationResponse.ExecutionState = ExecutionState.Completed;
315 return result;
316 }
317 catch (Exception e)
318 {
319 invocationResponse.ExecutionState = ExecutionState.Failed;
320 return new OperationResult(e);
321 }
322 }, cancellationTokenSource.Token);
323
324 if (await Task.WhenAny(runner, Task.Delay(invocationRequest.Timeout.Value, cancellationTokenSource.Token)) == runner)
325 {
326 cancellationTokenSource.Cancel();
327 invocationResponse.OperationResult = runner.Result;
328 }
329 else
330 {
331 cancellationTokenSource.Cancel();
332 invocationResponse.OperationResult = new OperationResult(false, new TimeoutMessage());
333 invocationResponse.ExecutionState = ExecutionState.Timeout;
334 }
Constantin Zieschefa612082020-04-03 09:54:56 +0200335 }
336 });
Constantin Ziesche08215502020-09-21 19:08:32 +0200337
Constantin Zieschefa612082020-04-03 09:54:56 +0200338 string endpoint = ServiceDescriptor?.Endpoints?.FirstOrDefault()?.Address;
339 CallbackResponse callbackResponse = new CallbackResponse(invocationRequest.RequestId);
340 if (string.IsNullOrEmpty(endpoint))
Constantin Ziesche08215502020-09-21 19:08:32 +0200341 callbackResponse.CallbackUrl = new Uri($"/submodelElements/{pathToOperation}/invocationList/{invocationRequest.RequestId}", UriKind.Relative);
Constantin Zieschefa612082020-04-03 09:54:56 +0200342 else
Constantin Ziesche08215502020-09-21 19:08:32 +0200343 callbackResponse.CallbackUrl = new Uri($"{endpoint}/submodelElements/{pathToOperation}/invocationList/{invocationRequest.RequestId}", UriKind.Absolute);
Constantin Zieschefa612082020-04-03 09:54:56 +0200344 return new Result<CallbackResponse>(true, callbackResponse);
345 }
346 return new Result<CallbackResponse>(operation_Retrieved);
347 }
348
349 private void SetInvocationResult(string operationId, string requestId, ref InvocationResponse invocationResponse)
350 {
351 string key = string.Join("_", operationId, requestId);
352 if (invocationResults.ContainsKey(key))
353 {
354 invocationResults[key] = invocationResponse;
355 }
356 else
357 {
358 invocationResults.Add(key, invocationResponse);
359 }
360 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200361
362 public IResult<InvocationResponse> GetInvocationResult(string pathToOperation, string requestId)
Constantin Zieschefa612082020-04-03 09:54:56 +0200363 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200364 string key = string.Join("_", pathToOperation, requestId);
Constantin Zieschefa612082020-04-03 09:54:56 +0200365 if (invocationResults.ContainsKey(key))
366 {
367 return new Result<InvocationResponse>(true, invocationResults[key]);
368 }
369 else
370 {
371 return new Result<InvocationResponse>(false, new NotFoundMessage($"Request with id {requestId}"));
372 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200373 }
374
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100375 public IResult ThrowEvent(IPublishableEvent publishableEvent, string topic = "/", Action<IMessagePublishedEventArgs> MessagePublished = null, byte qosLevel = 2, bool retain = false)
376 {
377 if (messageClient == null || !messageClient.IsConnected)
378 return new Result(false, new Message(MessageType.Warning, "MessageClient is not initialized or not connected"));
379
380 if (publishableEvent == null)
Constantin Zieschee837f992020-08-19 12:04:32 +0200381 return new Result(new ArgumentNullException(nameof(publishableEvent)));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100382
383 if (eventDelegates.TryGetValue(publishableEvent.Name, out EventDelegate eventDelegate))
384 eventDelegate.Invoke(this, publishableEvent);
385
Constantin Zieschefa612082020-04-03 09:54:56 +0200386 string message = JsonConvert.SerializeObject(publishableEvent, Formatting.Indented);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100387 return messageClient.Publish(topic, message, MessagePublished, qosLevel, retain);
388 }
389
Constantin Ziesche08215502020-09-21 19:08:32 +0200390
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100391 public virtual void ConfigureEventHandler(IMessageClient messageClient)
392 {
393 this.messageClient = messageClient;
394 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200395
396 public virtual void SubscribeUpdates(string pathToSubmodelElement, Action<IValue> updateFunction)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100397 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200398 if (!updateFunctions.ContainsKey(pathToSubmodelElement))
399 updateFunctions.Add(pathToSubmodelElement, updateFunction);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100400 else
Constantin Ziesche08215502020-09-21 19:08:32 +0200401 updateFunctions[pathToSubmodelElement] = updateFunction;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100402 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200403
404 public virtual void PublishUpdate(string pathToSubmodelElement, IValue value)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100405 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200406 if (updateFunctions.TryGetValue(pathToSubmodelElement, out Action<IValue> updateFunction))
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100407 updateFunction.Invoke(value);
408
409 }
410
411 public IResult<ISubmodel> RetrieveSubmodel()
412 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200413 return new Result<ISubmodel>(_submodel != null, _submodel);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100414 }
415
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200416 public IResult<ISubmodelElement> CreateOrUpdateSubmodelElement(string pathToSubmodelElement, ISubmodelElement submodelElement)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100417 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200418 if (_submodel == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100419 return new Result<ISubmodelElement>(false, new NotFoundMessage("Submodel"));
420
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200421 var created = _submodel.SubmodelElements.CreateOrUpdate(pathToSubmodelElement, submodelElement);
422 if(created.Success && created.Entity != null)
423 RegisterSubmodelElementHandler(pathToSubmodelElement, new SubmodelElementHandler(submodelElement.Get, submodelElement.Set));
424 return created;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100425 }
426
427 public IResult<IElementContainer<ISubmodelElement>> RetrieveSubmodelElements()
428 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200429 if (_submodel == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100430 return new Result<ElementContainer<ISubmodelElement>>(false, new NotFoundMessage("Submodel"));
431
Constantin Ziesche08215502020-09-21 19:08:32 +0200432 if (_submodel.SubmodelElements == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100433 return new Result<ElementContainer<ISubmodelElement>>(false, new NotFoundMessage("SubmodelElements"));
Constantin Ziesche08215502020-09-21 19:08:32 +0200434 return _submodel.SubmodelElements.RetrieveAll();
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100435 }
436
437 public IResult<ISubmodelElement> RetrieveSubmodelElement(string submodelElementId)
438 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200439 if (_submodel == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100440 return new Result<ISubmodelElement>(false, new NotFoundMessage("Submodel"));
441
Constantin Ziesche08215502020-09-21 19:08:32 +0200442 if (_submodel.SubmodelElements == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100443 return new Result<ISubmodelElement>(false, new NotFoundMessage(submodelElementId));
Constantin Ziesche8b4a64d2020-06-25 11:52:09 +0200444
Constantin Ziesche08215502020-09-21 19:08:32 +0200445 return _submodel.SubmodelElements.Retrieve(submodelElementId);
Constantin Ziesche8b4a64d2020-06-25 11:52:09 +0200446 }
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100447 public IResult<IValue> RetrieveSubmodelElementValue(string submodelElementId)
448 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200449 if (_submodel == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100450 return new Result<IValue>(false, new NotFoundMessage("Submodel"));
451
Constantin Ziesche08215502020-09-21 19:08:32 +0200452 if (submodelElementHandler.TryGetValue(submodelElementId, out SubmodelElementHandler elementHandler) && elementHandler.GetValueHandler != null)
453 {
454 var submodelElement = _submodel.SubmodelElements.Retrieve<ISubmodelElement>(submodelElementId);
455 if (submodelElement.Success && submodelElement.Entity != null)
456 return new Result<IValue>(true, elementHandler.GetValueHandler.Invoke(submodelElement.Entity));
457 else
458 return new Result<IValue>(false, new Message(MessageType.Error, "SubmodelElement not found"));
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200459 }
Constantin Ziesche08215502020-09-21 19:08:32 +0200460 else
461 return new Result<IValue>(false, new Message(MessageType.Error, "SubmodelElementHandler not found"));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100462 }
463
Constantin Ziesche08215502020-09-21 19:08:32 +0200464 public IResult UpdateSubmodelElementValue(string submodelElementId, IValue value)
465 {
466 if (_submodel == null)
467 return new Result(false, new NotFoundMessage("Submodel"));
468
469 if (submodelElementHandler.TryGetValue(submodelElementId, out SubmodelElementHandler elementHandler) && elementHandler.SetValueHandler != null)
470 {
471 var submodelElement = _submodel.SubmodelElements.Retrieve<ISubmodelElement>(submodelElementId);
472 if (submodelElement.Success && submodelElement.Entity != null)
473 {
474 elementHandler.SetValueHandler.Invoke(submodelElement.Entity, value);
475 return new Result(true);
476 }
477 else
478 return new Result<IValue>(false, new Message(MessageType.Error, "property not found"));
479 }
480 else
481 return new Result<IValue>(false, new Message(MessageType.Error, "SubmodelElementHandler not found"));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100482 }
483
484 public IResult DeleteSubmodelElement(string submodelElementId)
485 {
Constantin Ziesche08215502020-09-21 19:08:32 +0200486 if (_submodel == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100487 return new Result(false, new NotFoundMessage("Submodel"));
488
Constantin Ziesche08215502020-09-21 19:08:32 +0200489 if (_submodel.SubmodelElements == null)
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100490 return new Result(false, new NotFoundMessage(submodelElementId));
491
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200492 var deleted = _submodel.SubmodelElements.Delete(submodelElementId);
493 if (deleted.Success)
494 UnregisterSubmodelElementHandler(submodelElementId);
495 return deleted;
Constantin Zieschee837f992020-08-19 12:04:32 +0200496 }
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100497 }
498}