blob: 74cf51d24e552c8bf200a08addae6b2ffa0048fd [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.Components;
12using BaSyx.Models.Connectivity.Descriptors;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010013using BaSyx.Models.Core.Common;
Constantin Zieschefa612082020-04-03 09:54:56 +020014using BaSyx.Utils.DependencyInjection;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010015using BaSyx.Utils.ResultHandling;
16using Newtonsoft.Json;
17using NLog;
18using System;
19using System.Collections.Generic;
20using System.IO;
21using System.Linq;
22using System.Security.Cryptography;
23using System.Text;
24
25namespace BaSyx.Registry.ReferenceImpl.FileBased
26{
27 public class FileBasedRegistry : IAssetAdministrationShellRegistry
28 {
29 private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
30
31 public const string SubmodelFolder = "Submodels";
32
33 public FileBasedRegistrySettings Settings { get; }
34 public JsonSerializerSettings JsonSerializerSettings { get; }
35 public string FolderPath { get; }
36 public FileBasedRegistry(FileBasedRegistrySettings settings = null)
37 {
38 Settings = settings ?? FileBasedRegistrySettings.LoadSettings();
39 JsonSerializerSettings = new JsonStandardSettings();
40
41 FolderPath = Settings.Miscellaneous["FolderPath"];
42
43 if (string.IsNullOrEmpty(FolderPath))
44 {
45 logger.Error("FolderPath is null or empty");
46 throw new ArgumentNullException("FolderPath");
47 }
48 if (!Directory.Exists(FolderPath))
49 {
50 DirectoryInfo info;
51 try
52 {
53 info = Directory.CreateDirectory(FolderPath);
54 }
55 catch (Exception e)
56 {
57 logger.Error("FolderPath does not exist and cannot be created: " + e.Message);
58 throw;
59 }
60
61 if (!info.Exists)
62 {
63 logger.Error("FolderPath does not exist and cannot be created");
64 throw new InvalidOperationException("FolderPath does not exist and cannot be created");
65 }
66 }
67 }
68 public IResult<IAssetAdministrationShellDescriptor> CreateAssetAdministrationShell(IAssetAdministrationShellDescriptor aasDescriptor)
69 {
70 if (aasDescriptor == null)
71 return new Result<IAssetAdministrationShellDescriptor>(new ArgumentNullException(nameof(aasDescriptor)));
72 if (aasDescriptor.Identification?.Id == null)
Constantin Ziesche02817f12020-08-04 21:40:43 +020073 return new Result<IAssetAdministrationShellDescriptor>(new ArgumentNullException(nameof(aasDescriptor.Identification)));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010074 if (string.IsNullOrEmpty(aasDescriptor.IdShort))
Constantin Ziesche02817f12020-08-04 21:40:43 +020075 return new Result<IAssetAdministrationShellDescriptor>(new ArgumentNullException(nameof(aasDescriptor.IdShort)));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010076
77 try
78 {
79 string aasIdHash = GetHashString(aasDescriptor.Identification.Id);
80 string aasDirectoryPath = Path.Combine(FolderPath, aasIdHash);
81
82 if (!Directory.Exists(aasDirectoryPath))
83 Directory.CreateDirectory(aasDirectoryPath);
84
85 if(aasDescriptor.SubmodelDescriptors?.Count > 0)
86 {
87 foreach (var submodelDescriptor in aasDescriptor.SubmodelDescriptors)
88 {
89 var interimResult = CreateSubmodel(aasDescriptor.Identification.Id, submodelDescriptor);
90 if (!interimResult.Success)
91 return new Result<IAssetAdministrationShellDescriptor>(interimResult);
92 }
93 }
94 aasDescriptor.SubmodelDescriptors.Clear();
95
96 string aasDescriptorContent = JsonConvert.SerializeObject(aasDescriptor, JsonSerializerSettings);
97 string aasFilePath = Path.Combine(aasDirectoryPath, aasIdHash) + ".json";
98 File.WriteAllText(aasFilePath, aasDescriptorContent);
99
100 IResult<IAssetAdministrationShellDescriptor> readResult = RetrieveAssetAdministrationShell(aasDescriptor.Identification.Id);
101 return readResult;
102 }
103 catch (Exception e)
104 {
105 return new Result<IAssetAdministrationShellDescriptor>(e);
106 }
107 }
108
109 public IResult<ISubmodelDescriptor> CreateSubmodel(string aasId, ISubmodelDescriptor submodel)
110 {
111 if (string.IsNullOrEmpty(aasId))
112 return new Result<ISubmodelDescriptor>(new ArgumentNullException(nameof(aasId)));
113 if (submodel == null || string.IsNullOrEmpty(submodel.IdShort))
114 return new Result<ISubmodelDescriptor>(new ArgumentNullException("submodel.IdShort"));
115
116 string aasIdHash = GetHashString(aasId);
117 string aasDirectoryPath = Path.Combine(FolderPath, aasIdHash);
118 if (!Directory.Exists(aasDirectoryPath))
119 return new Result<ISubmodelDescriptor>(false, new Message(MessageType.Error, "AssetAdministrationShell does not exist - register AAS first"));
120
121 try
122 {
123 string submodelDirectory = Path.Combine(aasDirectoryPath, SubmodelFolder);
124 string submodelContent = JsonConvert.SerializeObject(submodel, JsonSerializerSettings);
125 if (!Directory.Exists(submodelDirectory))
126 Directory.CreateDirectory(submodelDirectory);
127
128 string submodelFilePath = Path.Combine(submodelDirectory, submodel.IdShort) + ".json";
129 File.WriteAllText(submodelFilePath, submodelContent);
130
131 IResult<ISubmodelDescriptor> readSubmodel = RetrieveSubmodel(aasId, submodel.IdShort);
132 return readSubmodel;
133 }
134 catch (Exception e)
135 {
136 return new Result<ISubmodelDescriptor>(e);
137 }
138 }
139
140 public IResult DeleteAssetAdministrationShell(string aasId)
141 {
142 if (string.IsNullOrEmpty(aasId))
143 return new Result(new ArgumentNullException(nameof(aasId)));
144
145 string aasIdHash = GetHashString(aasId);
146 string aasDirectoryPath = Path.Combine(FolderPath, aasIdHash);
147 if (!Directory.Exists(aasDirectoryPath))
148 return new Result(true, new Message(MessageType.Information, "No Asset Administration Shell found"));
149 else
150 {
151 try
152 {
153 Directory.Delete(aasDirectoryPath, true);
154 return new Result(true);
155 }
156 catch (Exception e)
157 {
158 return new Result(e);
159 }
160 }
161 }
162
163 public IResult DeleteSubmodel(string aasId, string submodelId)
164 {
165 if (string.IsNullOrEmpty(aasId))
166 return new Result(new ArgumentNullException(nameof(aasId)));
167 if (string.IsNullOrEmpty(submodelId))
168 return new Result(new ArgumentNullException(nameof(submodelId)));
169
170 string aasIdHash = GetHashString(aasId);
171 string submodelFilePath = Path.Combine(FolderPath, aasIdHash, SubmodelFolder, submodelId) + ".json";
172 if (!File.Exists(submodelFilePath))
173 return new Result(true, new Message(MessageType.Information, "No Submodel found"));
174 else
175 {
176 try
177 {
178 File.Delete(submodelFilePath);
179 return new Result(true);
180 }
181 catch (Exception e)
182 {
183 return new Result(e);
184 }
185 }
186 }
187
188 public IResult<IAssetAdministrationShellDescriptor> RetrieveAssetAdministrationShell(string aasId)
189 {
190 if (string.IsNullOrEmpty(aasId))
191 return new Result<IAssetAdministrationShellDescriptor>(new ArgumentNullException(nameof(aasId)));
192
193 string aasIdHash = GetHashString(aasId);
194 string aasFilePath = Path.Combine(FolderPath, aasIdHash, aasIdHash) + ".json";
195 if (File.Exists(aasFilePath))
196 {
197 try
198 {
199 string aasContent = File.ReadAllText(aasFilePath);
200 IAssetAdministrationShellDescriptor descriptor = JsonConvert.DeserializeObject<IAssetAdministrationShellDescriptor>(aasContent, JsonSerializerSettings);
201
202 var submodelDescriptors = RetrieveSubmodels(aasId);
203 if(submodelDescriptors.Success && submodelDescriptors.Entity?.Count > 0)
204 descriptor.SubmodelDescriptors = submodelDescriptors.Entity;
205
206 return new Result<IAssetAdministrationShellDescriptor>(true, descriptor);
207 }
208 catch (Exception e)
209 {
210 return new Result<IAssetAdministrationShellDescriptor>(e);
211 }
212 }
213 else
214 return new Result<IAssetAdministrationShellDescriptor>(false, new NotFoundMessage("Asset Administration Shell"));
215
216 }
217
218 public IResult<IElementContainer<IAssetAdministrationShellDescriptor>> RetrieveAssetAdministrationShells()
219 {
220 string[] aasDirectories = Directory.GetDirectories(FolderPath);
221 if(aasDirectories == null || aasDirectories.Length == 0)
222 return new Result<ElementContainer<IAssetAdministrationShellDescriptor>>(false, new NotFoundMessage("Asset Administration Shells"));
223 else
224 {
225 ElementContainer<IAssetAdministrationShellDescriptor> aasDescriptors = new ElementContainer<IAssetAdministrationShellDescriptor>();
226 foreach (var directory in aasDirectories)
227 {
228 string aasIdHash = directory.Split(Path.DirectorySeparatorChar).Last();
229 string aasFilePath = Path.Combine(directory, aasIdHash) + ".json";
230 IResult<IAssetAdministrationShellDescriptor> readAASDescriptor = ReadAssetAdministrationShell(aasFilePath);
231 if (readAASDescriptor.Success && readAASDescriptor.Entity != null)
232 aasDescriptors.Create(readAASDescriptor.Entity);
233 }
234 if (aasDescriptors.Count == 0)
235 return new Result<ElementContainer<IAssetAdministrationShellDescriptor>>(false, new NotFoundMessage("Asset Administration Shells"));
236 else
237 return new Result<ElementContainer<IAssetAdministrationShellDescriptor>>(true, aasDescriptors);
238 }
239
240 }
241
242 private IResult<IAssetAdministrationShellDescriptor> ReadAssetAdministrationShell(string aasFilePath)
243 {
244 if (string.IsNullOrEmpty(aasFilePath))
245 return new Result<IAssetAdministrationShellDescriptor>(new ArgumentNullException(nameof(aasFilePath)));
246
247 if (File.Exists(aasFilePath))
248 {
249 try
250 {
251 string aasContent = File.ReadAllText(aasFilePath);
252 IAssetAdministrationShellDescriptor descriptor = JsonConvert.DeserializeObject<IAssetAdministrationShellDescriptor>(aasContent, JsonSerializerSettings);
253
254 var submodelDescriptors = RetrieveSubmodels(descriptor.Identification.Id);
255 if (submodelDescriptors.Success && submodelDescriptors.Entity != null)
256 descriptor.SubmodelDescriptors = submodelDescriptors.Entity;
257
258 return new Result<IAssetAdministrationShellDescriptor>(true, descriptor);
259 }
260 catch (Exception e)
261 {
262 return new Result<IAssetAdministrationShellDescriptor>(e);
263 }
264 }
265 else
266 return new Result<IAssetAdministrationShellDescriptor>(false, new NotFoundMessage("Asset Administration Shell"));
267
268 }
269
270 public IResult<ISubmodelDescriptor> RetrieveSubmodel(string aasId, string submodelId)
271 {
272 if (string.IsNullOrEmpty(aasId))
273 return new Result<ISubmodelDescriptor>(new ArgumentNullException(nameof(aasId)));
274 if (string.IsNullOrEmpty(submodelId))
275 return new Result<ISubmodelDescriptor>(new ArgumentNullException(nameof(submodelId)));
276
277 string aasIdHash = GetHashString(aasId);
278 string aasDirectoryPath = Path.Combine(FolderPath, aasIdHash);
279 if (Directory.Exists(aasDirectoryPath))
280 {
281 string submodelPath = Path.Combine(aasDirectoryPath, SubmodelFolder, submodelId) + ".json";
282 if (File.Exists(submodelPath))
283 {
284 try
285 {
286 string submodelContent = File.ReadAllText(submodelPath);
287 ISubmodelDescriptor descriptor = JsonConvert.DeserializeObject<ISubmodelDescriptor>(submodelContent, JsonSerializerSettings);
288 return new Result<ISubmodelDescriptor>(true, descriptor);
289 }
290 catch (Exception e)
291 {
292 return new Result<ISubmodelDescriptor>(e);
293 }
294 }
295 else
296 return new Result<ISubmodelDescriptor>(false, new NotFoundMessage("Submodel"));
297 }
298 else
299 return new Result<ISubmodelDescriptor>(false, new NotFoundMessage("Asset Administration Shell"));
300 }
301
302 public IResult<IElementContainer<ISubmodelDescriptor>> RetrieveSubmodels(string aasId)
303 {
304 if (string.IsNullOrEmpty(aasId))
305 return new Result<ElementContainer<ISubmodelDescriptor>>(new ArgumentNullException(nameof(aasId)));
306
307 string aasIdHash = GetHashString(aasId);
308 string aasDirectoryPath = Path.Combine(FolderPath, aasIdHash);
309 if (Directory.Exists(aasDirectoryPath))
310 {
311 string submodelDirectoryPath = Path.Combine(aasDirectoryPath, SubmodelFolder);
312 if (Directory.Exists(submodelDirectoryPath))
313 {
314 ElementContainer<ISubmodelDescriptor> submodelDescriptors = new ElementContainer<ISubmodelDescriptor>();
315 string[] files = Directory.GetFiles(submodelDirectoryPath);
316 foreach (var file in files)
317 {
318 string submodelId = file.Split(Path.DirectorySeparatorChar)?.Last()?.Replace(".json", "");
319 var descriptor = RetrieveSubmodel(aasId, submodelId);
320 if (descriptor.Success && descriptor.Entity != null)
321 submodelDescriptors.Create(descriptor.Entity);
322 }
323 if (submodelDescriptors.Count == 0)
324 return new Result<ElementContainer<ISubmodelDescriptor>>(false, new NotFoundMessage("Submodels"));
325 else
326 return new Result<ElementContainer<ISubmodelDescriptor>>(true, submodelDescriptors);
327 }
328 else
329 return new Result<ElementContainer<ISubmodelDescriptor>>(false, new NotFoundMessage("Submodel"));
330 }
331 else
332 return new Result<ElementContainer<ISubmodelDescriptor>>(false, new NotFoundMessage("Asset Administration Shell"));
333 }
334
335 public IResult UpdateAssetAdministrationShell(string aasId, Dictionary<string, string> metaData)
336 {
337 IResult<IAssetAdministrationShellDescriptor> readAAS = ReadAssetAdministrationShell(aasId);
338 return new Result(readAAS);
339 }
340
341 private static string GetHashString(string input)
342 {
343 SHA256 shaAlgorithm = SHA256.Create();
344 byte[] data = Encoding.UTF8.GetBytes(input);
345
346 byte[] bHash = shaAlgorithm.ComputeHash(data);
347
348 string hashString = string.Empty;
349 for (int i = 0; i < bHash.Length; i++)
350 {
351 hashString += bHash[i].ToString("x2");
352
353 //break condition for filename length
354 if (i == 255)
355 break;
356 }
357 return hashString;
358 }
359 }
360}