From 9ec9d46412bba57325e111e01b94187ae98ae0a2 Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Wed, 21 Feb 2024 17:42:49 +0100 Subject: [PATCH 01/17] Create docker-compose for MongoDB --- content-for-demo/docker-compose.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 content-for-demo/docker-compose.yaml diff --git a/content-for-demo/docker-compose.yaml b/content-for-demo/docker-compose.yaml new file mode 100644 index 000000000..c248196c5 --- /dev/null +++ b/content-for-demo/docker-compose.yaml @@ -0,0 +1,13 @@ +version: '3.8' +services: + mongodb: + image: mongo + hostname: "mongo" + restart: always + volumes: + - ./mongo/data:/data/db + ports: + - '27017:27017' + environment: + - MONGO_INITDB_ROOT_USERNAME=mongo + - MONGO_INITDB_ROOT_PASSWORD=mongo \ No newline at end of file From 7753a39e2c0542af0145596e3d85fb9194305dc2 Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Wed, 21 Feb 2024 17:43:50 +0100 Subject: [PATCH 02/17] Add MongoDB Driver --- src/AasxServerBlazor/Properties/launchSettings.json | 2 +- src/AasxServerStandardBib/AasxServerStandardBib.csproj | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AasxServerBlazor/Properties/launchSettings.json b/src/AasxServerBlazor/Properties/launchSettings.json index ecd4b048a..e345b36a6 100644 --- a/src/AasxServerBlazor/Properties/launchSettings.json +++ b/src/AasxServerBlazor/Properties/launchSettings.json @@ -10,7 +10,7 @@ }, "AasxServerBlazor": { "commandName": "Project", - "commandLineArgs": "--no-security --aasx-in-memory 1000 --data-path \"C:\\Development\\PCF View\" --edit --external-blazor http://localhost:5001", + "commandLineArgs": "--no-security --aasx-in-memory 1000 --data-path \"C:\\GitClones\\aasx-server\\content-for-demo\\aasxs\" --edit --external-blazor http://localhost:5001", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", diff --git a/src/AasxServerStandardBib/AasxServerStandardBib.csproj b/src/AasxServerStandardBib/AasxServerStandardBib.csproj index 1409baa9c..c4738e816 100644 --- a/src/AasxServerStandardBib/AasxServerStandardBib.csproj +++ b/src/AasxServerStandardBib/AasxServerStandardBib.csproj @@ -32,6 +32,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + From f333ec03198e175a0b699e664a7380de11262623 Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Wed, 21 Feb 2024 17:44:15 +0100 Subject: [PATCH 03/17] Insert AssetEnv into MongoDB on startup --- src/AasxServerStandardBib/Database.cs | 81 +++++++++++++++++++++++++++ src/AasxServerStandardBib/Program.cs | 12 ++++ 2 files changed, 93 insertions(+) create mode 100644 src/AasxServerStandardBib/Database.cs diff --git a/src/AasxServerStandardBib/Database.cs b/src/AasxServerStandardBib/Database.cs new file mode 100644 index 000000000..ed673a082 --- /dev/null +++ b/src/AasxServerStandardBib/Database.cs @@ -0,0 +1,81 @@ +using MongoDB.Bson.Serialization.Serializers; +using MongoDB.Bson.Serialization; +using MongoDB.Driver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using AasxServerStandardBib.Exceptions; +using MongoDB.Bson; + + +//Author: Jonas Graubner +//contact: jogithub@graubner-bayern.de +namespace AasxServerStandardBib +{ + public interface IDatabase + { + void Initialize(String connectionString); + public void writeDB(String collectionName, object data, bool throwError = false); + public void importAASCoreEnvironment(AasCore.Aas3_0.Environment environment); + } + public class MongoDatabase : IDatabase + { + private MongoClient _client; + private IMongoDatabase _database; + + public void Initialize(String connectionString) + { + //_client = new MongoClient("mongodb://AAS:SefuSWE63811!@192.168.0.22:27017/?authSource=AAS"); + _client = new MongoClient(connectionString); + try + { + _client.StartSession(); + } + catch (System.TimeoutException ex) + { + System.Console.WriteLine(ex.Message); + System.Environment.Exit(1); + } + + _database = _client.GetDatabase("AAS"); + var objectSerializer = new ObjectSerializer(type => ObjectSerializer.DefaultAllowedTypes(type) || type.FullName.StartsWith("AasCore") || type.FullName.StartsWith("MongoDB")); + BsonSerializer.RegisterSerializer(objectSerializer); + } + + public void writeDB(String collectionName, object data, bool throwError = false) + { + var collection = _database.GetCollection(collectionName); + try + { + collection.InsertOne(data); + } + catch (MongoWriteException ex) + { + if (throwError) + { + throw new DuplicateException($"{collectionName} with id {data} already exists."); + } + } + } + + public void importAASCoreEnvironment(AasCore.Aas3_0.Environment environment) + { + environment.AssetAdministrationShells.ForEach(shell => { + writeDB("AssetAdministrationShells", shell); + }); + + environment.Submodels.ForEach(submodel => + { + writeDB("Submodels", submodel); + }); + + environment.ConceptDescriptions.ForEach(conceptDescription => + { + writeDB("ConceptDescriptions", conceptDescription); + }); + + } + } +} diff --git a/src/AasxServerStandardBib/Program.cs b/src/AasxServerStandardBib/Program.cs index f8b2e1a26..9ccdfc134 100644 --- a/src/AasxServerStandardBib/Program.cs +++ b/src/AasxServerStandardBib/Program.cs @@ -1,6 +1,8 @@ using AasOpcUaServer; using AasxMqttServer; using AasxRestServerLibrary; +using AasxServerStandardBib; + //using AasxServerStandardBib.Migrations; using AdminShellNS; using Extensions; @@ -34,6 +36,7 @@ using System.Timers; using System.Xml; using System.Xml.Serialization; +using static AasxServerStandardBib.IDatabase; using Formatting = Newtonsoft.Json.Formatting; /* Copyright (c) 2019-2020 PHOENIX CONTACT GmbH & Co. KG , author: Andreas Orzelski @@ -530,6 +533,7 @@ public static bool loadPackageForSubmodel(string submodelIdentifier, out ISubmod public static string[] envFileName = null; public static string[] envSymbols = null; public static string[] envSubjectIssuer = null; + public static IDatabase database = null; /* public static AdminShellPackageEnv[] env = new AdminShellPackageEnv[envimax]; { @@ -1012,6 +1016,10 @@ private static async Task Run(CommandLineArguments a) int envi = 0; int count = 0; + //Mongo Database + database = new MongoDatabase(); + database.Initialize("mongodb://mongo:mongo@localhost:27017/"); + // Migrate always if (withDb) { @@ -1110,6 +1118,10 @@ private static async Task Run(CommandLineArguments a) // try { fn = fileNames[fi]; + + //Insert into DB + database.importAASCoreEnvironment(new AdminShellPackageEnv(fn, true, false).AasEnv); + if (fn.ToLower().Contains("globalsecurity")) { envFileName[envi] = fn; From 393ac57205a0cdd5ce4e8d3306766340bc6b3f6c Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Thu, 22 Feb 2024 16:34:59 +0100 Subject: [PATCH 04/17] Add DB Implementation of AasxServerStandardBib.Services Reimplemented Interfaces for DB Use: - IAasxFileServerInterfaceService - IAdminShellPackageEnvironmentService - IConceptDescriptionService - ISubmodelService AASX Server Blazor / Startup.cs Change to DB Class (@JoTec2002 change later to dynamic switch based on startup Parameter) --- src/AasxServerAspNetCore/Startup.cs | 2 +- src/AasxServerBlazor/Startup.cs | 2 +- src/AasxServerStandardBib/Database.cs | 80 ++- .../AasxFileServerInterfaceServiceDB.cs | 296 ++++++++ .../AdminShellPackageEnvironmentServiceDB.cs | 519 ++++++++++++++ .../ConceptDescriptionServiceDB.cs | 143 ++++ .../Services-DB/SubmodelServiceDB.cs | 633 ++++++++++++++++++ 7 files changed, 1657 insertions(+), 18 deletions(-) create mode 100644 src/AasxServerStandardBib/Services-DB/AasxFileServerInterfaceServiceDB.cs create mode 100644 src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs create mode 100644 src/AasxServerStandardBib/Services-DB/ConceptDescriptionServiceDB.cs create mode 100644 src/AasxServerStandardBib/Services-DB/SubmodelServiceDB.cs diff --git a/src/AasxServerAspNetCore/Startup.cs b/src/AasxServerAspNetCore/Startup.cs index 7ddc74963..2bc3c813e 100644 --- a/src/AasxServerAspNetCore/Startup.cs +++ b/src/AasxServerAspNetCore/Startup.cs @@ -72,7 +72,7 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); services.AddTransient(); - services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/src/AasxServerBlazor/Startup.cs b/src/AasxServerBlazor/Startup.cs index 2a77e0cd2..8ce21f5ea 100644 --- a/src/AasxServerBlazor/Startup.cs +++ b/src/AasxServerBlazor/Startup.cs @@ -96,7 +96,7 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); services.AddTransient(); - services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/src/AasxServerStandardBib/Database.cs b/src/AasxServerStandardBib/Database.cs index ed673a082..060e6acc0 100644 --- a/src/AasxServerStandardBib/Database.cs +++ b/src/AasxServerStandardBib/Database.cs @@ -8,6 +8,9 @@ using System.Threading.Tasks; using AasxServerStandardBib.Exceptions; using MongoDB.Bson; +using MongoDB.Driver.Linq; +using System.Collections; +using AasCore.Aas3_0; //Author: Jonas Graubner @@ -17,9 +20,14 @@ namespace AasxServerStandardBib public interface IDatabase { void Initialize(String connectionString); - public void writeDB(String collectionName, object data, bool throwError = false); - public void importAASCoreEnvironment(AasCore.Aas3_0.Environment environment); + public void writeDBAssetAdministrationShell(IAssetAdministrationShell shell); + public bool deleteDBAssetAdministrationShell(IAssetAdministrationShell shell); + public IQueryable getLINQAssetAdministrationShell(); + public void updateDBAssetAdministrationShellById(IAssetAdministrationShell body, string aasIdentifier); + public void importAASCoreEnvironment(IEnvironment environment); } + + public class MongoDatabase : IDatabase { private MongoClient _client; @@ -43,39 +51,79 @@ public void Initialize(String connectionString) var objectSerializer = new ObjectSerializer(type => ObjectSerializer.DefaultAllowedTypes(type) || type.FullName.StartsWith("AasCore") || type.FullName.StartsWith("MongoDB")); BsonSerializer.RegisterSerializer(objectSerializer); } + private IMongoCollection getAasCollection() + { + return _database.GetCollection("AssetAdministrationShells"); + } + private IMongoCollection getSubmodelCollection() + { + return _database.GetCollection("Submodels"); + } + private IMongoCollection getConceptDescriptionCollection() + { + return _database.GetCollection("ConceptDescriptions"); + } - public void writeDB(String collectionName, object data, bool throwError = false) + + public void writeDBAssetAdministrationShell(IAssetAdministrationShell shell) + { + try + { + getAasCollection().InsertOne((AssetAdministrationShell)shell); + } catch (MongoWriteException) + { + } + } + public void writeDBSubmodel(ISubmodel submodel) + { + try + { + getSubmodelCollection().InsertOne(submodel); + } + catch (MongoWriteException) + { + } + } + public void writeDBConceptDescription(IConceptDescription conceptDescription) { - var collection = _database.GetCollection(collectionName); try { - collection.InsertOne(data); + getConceptDescriptionCollection().InsertOne(conceptDescription); } - catch (MongoWriteException ex) + catch (MongoWriteException) { - if (throwError) - { - throw new DuplicateException($"{collectionName} with id {data} already exists."); - } } } + + public bool deleteDBAssetAdministrationShell(IAssetAdministrationShell shell) + { + throw new NotImplementedException(); + } + public IQueryable getLINQAssetAdministrationShell() + { + return getAasCollection().AsQueryable(); + } + public async void updateDBAssetAdministrationShellById(IAssetAdministrationShell body, string aasIdentifier) + { + await getAasCollection().ReplaceOneAsync(r => r.Id.Equals(aasIdentifier), (AssetAdministrationShell)body); + } - public void importAASCoreEnvironment(AasCore.Aas3_0.Environment environment) + + public void importAASCoreEnvironment(IEnvironment environment) { environment.AssetAdministrationShells.ForEach(shell => { - writeDB("AssetAdministrationShells", shell); + writeDBAssetAdministrationShell(shell); }); environment.Submodels.ForEach(submodel => { - writeDB("Submodels", submodel); + writeDBSubmodel(submodel); }); environment.ConceptDescriptions.ForEach(conceptDescription => { - writeDB("ConceptDescriptions", conceptDescription); + writeDBConceptDescription(conceptDescription); }); - - } + } } } diff --git a/src/AasxServerStandardBib/Services-DB/AasxFileServerInterfaceServiceDB.cs b/src/AasxServerStandardBib/Services-DB/AasxFileServerInterfaceServiceDB.cs new file mode 100644 index 000000000..77aae641c --- /dev/null +++ b/src/AasxServerStandardBib/Services-DB/AasxFileServerInterfaceServiceDB.cs @@ -0,0 +1,296 @@ +using AasxRestServerLibrary; +using AasxServer; +using AasxServerStandardBib.Exceptions; +using AasxServerStandardBib.Interfaces; +using AasxServerStandardBib.Logging; +using AdminShellNS; +using AdminShellNS.Models; +using Extensions; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace AasxServerStandardBib.Services +{ + public class AasxFileServerInterfaceServiceDB : IAasxFileServerInterfaceService + { + private readonly IAppLogger _logger; + private AdminShellPackageEnv[] _packages; + private string[] _envFileNames; + + public AasxFileServerInterfaceServiceDB(IAppLogger logger) + { + _logger = logger; + _packages = Program.env; + _envFileNames = Program.envFileName; + } + + public void DeleteAASXByPackageId(string packageId) + { + int packageIndex = int.Parse(packageId); + var requestedPackage = _packages[packageIndex]; + if (requestedPackage != null) + { + //Move the file to archive + var archivePath = Path.Combine(AasxHttpContextHelper.DataPath, "AasxFileArchive"); + if (!Directory.Exists(archivePath)) + { + Directory.CreateDirectory(archivePath); + } + var fileName = Path.Combine(archivePath, Path.GetFileName(_envFileNames[packageIndex])); + if (System.IO.File.Exists(fileName)) + { + System.IO.File.Delete(fileName); + } + System.IO.File.Move(_envFileNames[packageIndex], fileName); + + _packages[packageIndex] = null; + _envFileNames[packageIndex] = null; + Program.signalNewData(2); + } + else + { + throw new NotFoundException($"Package with packageId {packageId} not found."); + } + } + + public string GetAASXByPackageId(string packageId, out byte[] content, out long fileSize, out IAssetAdministrationShell aas) + { + aas = null; + content = null; + fileSize = 0; + int packageIndex = int.Parse(packageId); + var requestedPackage = _packages[packageIndex]; + var requestedFileName = _envFileNames[packageIndex]; + if (!string.IsNullOrEmpty(requestedFileName) && requestedPackage != null) + { + //Create Temp file + string copyFileName = Path.GetTempFileName().Replace(".tmp", ".aasx"); + System.IO.File.Copy(requestedFileName, copyFileName, true); + Program.env[packageIndex].SaveAs(copyFileName); + + content = System.IO.File.ReadAllBytes(copyFileName); + string fileName = Path.GetFileName(requestedFileName); + fileSize = content.Length; + _packages[packageIndex].SetFilename(requestedFileName); + + //Set aas + aas = requestedPackage.AasEnv.AssetAdministrationShells[0]; + + //Delete Temp file + System.IO.File.Delete(copyFileName); + return fileName; + } + else if (requestedPackage != null && string.IsNullOrEmpty(requestedFileName)) + { + //File does not exist, may be AAS is added by REST-API + //Check if AAS exists + if (requestedPackage.AasEnv.AssetAdministrationShells.Count != 0) + { + string newFileName = Path.Combine(AasxHttpContextHelper.DataPath, requestedPackage.AasEnv.AssetAdministrationShells[0].IdShort + ".aasx"); + using (new FileStream(newFileName, FileMode.CreateNew)) { } + Program.env[packageIndex].SetTempFn(newFileName); + + //Create Temp file + string copyFileName = Path.GetTempFileName().Replace(".tmp", ".aasx"); + System.IO.File.Copy(newFileName, copyFileName, true); + Program.env[packageIndex].SaveAs(copyFileName); + + content = System.IO.File.ReadAllBytes(copyFileName); + string fileName = Path.GetFileName(newFileName); + fileSize = content.Length; + + System.IO.File.Copy(copyFileName, newFileName, true); + Program.envFileName[packageIndex] = newFileName; + _packages[packageIndex].SetFilename(newFileName); + + //Set aas + aas = requestedPackage.AasEnv.AssetAdministrationShells[0]; + + //Delete Temp file + System.IO.File.Delete(copyFileName); + return fileName; + } + } + + return null; + } + + public List GetAllAASXPackageIds(string aasId = null) + { + var output = new List(); + + for (int i = 0; i < _packages.Length; i++) + { + var package = _packages[i]; + if (package != null) + { + var packageDescription = new PackageDescription(); + packageDescription.PackageId = i.ToString(); + var aasIdList = new List(); + foreach (var aas in _packages[i].AasEnv.AssetAdministrationShells) + { + aasIdList.Add(aas.Id); + } + packageDescription.AasIds = aasIdList; + output.Add(packageDescription); + } + + } + + //Filter w..r.t aasId + if (output.Any()) + { + if (!string.IsNullOrEmpty(aasId)) + { + output = output.Where(x => x.AasIds.Contains(aasId)).ToList(); + } + } + + return output; + } + + public IAssetAdministrationShell GetAssetAdministrationShellByPackageId(string packageId) + { + int packageIndex = int.Parse(packageId); + var requestedPackage = _packages[packageIndex]; + if (requestedPackage != null && requestedPackage.AasEnv != null) + { + if (requestedPackage.AasEnv.AssetAdministrationShells != null) + { + return requestedPackage.AasEnv.AssetAdministrationShells.First(); + } + } + + return null; + } + + public string PostAASXPackage(byte[] fileContent, string fileName) + { + var newFileName = Path.Combine(AasxHttpContextHelper.DataPath, fileName); + //Check if file already exists + if (System.IO.File.Exists(newFileName)) + { + throw new Exception($"File already exists"); + } + + //TODO:Check file extentsion ".aasx" + //Write the received file content to this temp file + //var content = Convert.FromBase64String(body); + System.IO.File.WriteAllBytes(newFileName, fileContent); + // open again + var newAasx = new AdminShellPackageEnv(newFileName, true); + if (newAasx != null) + { + if (EmptyPackageAvailable(out int emptyPackageIndex)) + { + _packages[emptyPackageIndex] = newAasx; + _envFileNames[emptyPackageIndex] = newFileName; + var timeStamp = DateTime.UtcNow; + newAasx.AasEnv.AssetAdministrationShells[0].TimeStampCreate = timeStamp; + newAasx.AasEnv.AssetAdministrationShells[0].SetTimeStamp(timeStamp); + foreach (var submodel in newAasx.AasEnv.Submodels) + { + //submodel.SetAllParents(); + submodel.TimeStampCreate = timeStamp; + submodel.SetParentAndTimestamp(timeStamp); + } + Program.signalNewData(2); + return emptyPackageIndex.ToString(); + } + else + { + throw new Exception($"Could not create the file as the datastructure is completely filled."); + } + } + else + { + throw new Exception($"Cannot load new package {fileName}."); + } + } + + public void UpdateAASXPackageById(string packageId, byte[] fileContent, string fileName) + { + int packageIndex = int.Parse(packageId); + var package = _packages[packageIndex]; + if (package != null) + { + var originalFile = _packages[packageIndex].Filename; + + //Create temporary file + var tempNewFile = Path.GetTempFileName().Replace(".tmp", ".aasx"); + //Write the received file content to this temp file + //var content = Convert.FromBase64String(fileContent); + System.IO.File.WriteAllBytes(tempNewFile, fileContent); + + lock (Program.changeAasxFile) + { + try + { + _packages[packageIndex].Close(); + //Create back up of existing file + System.IO.File.Copy(originalFile, originalFile + ".bak", overwrite: true); + } + catch (Exception e) + { + throw new Exception($"Cannot close/ backup old AASX {originalFile}. Aborting. Exception: {e.Message}"); + } + try + { + //Replace existing file with temp file + //originalFile = fileName; + var rootPath = Path.GetDirectoryName(originalFile); + originalFile = Path.Combine(rootPath, fileName); + + //Copy tempFile into originalFile location + System.IO.File.Copy(tempNewFile, originalFile, overwrite: true); + // open again + var newAasx = new AdminShellPackageEnv(originalFile, true); + if (newAasx != null) + { + foreach (var submodel in newAasx.AasEnv.Submodels) + { + submodel.SetAllParents(); + } + _packages[packageIndex] = newAasx; + } + else + { + throw new Exception($"Cannot load new package {originalFile} for replacing via PUT. Aborting."); + } + //now delete tempFile + System.IO.File.Delete(tempNewFile); + } + catch (Exception e) + { + throw new Exception($"Cannot replace AASX {originalFile} with new {tempNewFile}. Aborting. Exception: {e.Message}"); + } + } + + Program.signalNewData(2); + } + else + { + throw new NotFoundException($"Requested package with packageId {packageId} not found."); + } + } + + private bool EmptyPackageAvailable(out int emptyPackageIndex) + { + emptyPackageIndex = -1; + + for (int envi = 0; envi < _packages.Length; envi++) + { + if (_packages[envi] == null) + { + emptyPackageIndex = envi; + _packages[emptyPackageIndex] = new AdminShellPackageEnv(); + return true; + } + } + + return false; + } + } +} diff --git a/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs b/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs new file mode 100644 index 000000000..f18dba80c --- /dev/null +++ b/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs @@ -0,0 +1,519 @@ +/* Copyright (c) 2019-2023 Fraunhofer IOSB-INA Lemgo, +    eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft +    zur Foerderung der angewandten Forschung e.V. + */ +using AasxServer; +using AasxServerStandardBib.Exceptions; +using AasxServerStandardBib.Interfaces; +using AasxServerStandardBib.Logging; +using AdminShellNS; +using Extensions; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace AasxServerStandardBib.Services +{ + public class AdminShellPackageEnvironmentServiceDB : IAdminShellPackageEnvironmentService + { + private readonly IAppLogger _logger; + private readonly Lazy _aasService; + private IDatabase _database; + private AdminShellPackageEnv[] _packages; + + public AdminShellPackageEnvironmentServiceDB(IAppLogger logger, Lazy aasService) + { + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _aasService = aasService; + //_packages = Program.env; + _database = Program.database; + } + + #region Others + + private bool EmptyPackageAvailable(out int emptyPackageIndex) + { + emptyPackageIndex = -1; + + for (int envi = 0; envi < _packages.Length; envi++) + { + if (_packages[envi] == null) + { + emptyPackageIndex = envi; + _packages[emptyPackageIndex] = new AdminShellPackageEnv(); + return true; + } + } + + return false; + } + #endregion + + #region AssetAdministrationShell + public IAssetAdministrationShell CreateAssetAdministrationShell(IAssetAdministrationShell body) + { + var timeStamp = DateTime.UtcNow; + body.TimeStampCreate = timeStamp; + body.SetTimeStamp(timeStamp); + _database.writeDBAssetAdministrationShell(body); + Program.signalNewData(2); + return body; + } + + public void DeleteAssetAdministrationShell(int packageIndex, IAssetAdministrationShell aas) + { + bool deleted = _database.deleteDBAssetAdministrationShell(aas); + if (deleted) + { + _logger.LogDebug($"Deleted Asset Administration Shell with id {aas.Id}"); + Program.signalNewData(2); + } + else + { + _logger.LogError($"Could not delete Asset Administration Shell with id {aas.Id}"); + } + } + + public List GetAllAssetAdministrationShells() + { + return _database.getLINQAssetAdministrationShell().Cast().ToList(); + } + + public IAssetAdministrationShell GetAssetAdministrationShellById(string aasIdentifier, out int packageIndex) + { + packageIndex = -1; //TODO unused -> remove in the future + var output = _database.getLINQAssetAdministrationShell() + .Where(r => r.Id.Equals(aasIdentifier)) + .ToList(); + + if (output.Any()) + { + _logger.LogDebug($"Asset Administration Shell with id {aasIdentifier} found."); + return output.First(); + } + else + { + throw new NotFoundException($"Asset Administration Shell with id {aasIdentifier} not found."); + } + } + + public bool IsAssetAdministrationShellPresent(string aasIdentifier) + { + //TODO unused -> remove in the future + throw new NotImplementedException(); + return false; + } + + private bool IsAssetAdministrationShellPresent(string aasIdentifier, out IAssetAdministrationShell output, out int packageIndex) + { + output = null; packageIndex = -1; + //TODO unused -> remove in the future + throw new NotImplementedException(); + + Program.loadPackageForAas(aasIdentifier, out output, out packageIndex); + + foreach (var package in _packages) + { + if (package != null) + { + var env = package.AasEnv; + if (env != null) + { + var aas = env.AssetAdministrationShells.Where(a => a.Id.Equals(aasIdentifier)); + if (aas.Any()) + { + output = aas.First(); + packageIndex = Array.IndexOf(_packages, package); + return true; + } + } + } + } + + return false; + } + + public void UpdateAssetAdministrationShellById(IAssetAdministrationShell body, string aasIdentifier) + { + //TODO Test -> should work -> function unused + var timeStamp = DateTime.UtcNow; + body.TimeStampCreate = timeStamp; + body.SetTimeStamp(timeStamp); + + _database.updateDBAssetAdministrationShellById(body, aasIdentifier); + + Program.signalNewData(1); //0 not working, hence 1 = same tree, structure may change + _logger.LogDebug($"Successfully updated the AAS with requested AAS"); + } + + public void DeleteAssetInformationThumbnail(int packageIndex, IResource defaultThumbnail) + { + //TODO + throw new NotImplementedException(); + //_packages[packageIndex].DeleteAssetInformationThumbnail(defaultThumbnail); + Program.signalNewData(0); + } + + public Stream GetAssetInformationThumbnail(int packageIndex) + { + return _packages[packageIndex].GetLocalThumbnailStream(); + } + + public void UpdateAssetInformationThumbnail(IResource defaultThumbnail, Stream fileContent, int packageIndex) + { + _packages[packageIndex].EmbeddAssetInformationThumbnail(defaultThumbnail, fileContent); + Program.signalNewData(0); + } + #endregion + + #region Submodel + + public void DeleteSubmodelById(string submodelIdentifier) + { + var submodel = GetSubmodelById(submodelIdentifier, out int packageIndex); + if (submodel != null && packageIndex != -1) + { + foreach (var aas in _packages[packageIndex].AasEnv.AssetAdministrationShells) + { + _aasService.Value.DeleteSubmodelReferenceById(aas.Id, submodelIdentifier); + } + _packages[packageIndex].AasEnv.Submodels.Remove(submodel); + _logger.LogDebug($"Deleted submodel with id {submodelIdentifier}."); + AasxServer.Program.signalNewData(1); + } + } + + public ISubmodel GetSubmodelById(string submodelIdentifier, out int packageIndex) + { + var found = IsSubmodelPresent(submodelIdentifier, out ISubmodel submodel, out packageIndex); + if (found) + { + _logger.LogDebug($"Found the submodel with Id {submodelIdentifier}"); + return submodel; + } + else + { + throw new NotFoundException($"Submodel with id {submodelIdentifier} NOT found."); + } + } + + public void DeleteSupplementaryFileInPackage(string submodelIdentifier, string filePath) + { + _ = GetSubmodelById(submodelIdentifier, out int packageIndex); + if (packageIndex != -1) + { + _packages[packageIndex].DeleteSupplementaryFile(filePath); + } + } + + public bool IsSubmodelPresent(string submodelIdentifier) + { + return IsSubmodelPresent(submodelIdentifier, out _, out _); + } + + private bool IsSubmodelPresent(string submodelIdentifier, out ISubmodel output, out int packageIndex) + { + output = null; + packageIndex = -1; + + Program.loadPackageForSubmodel(submodelIdentifier, out output, out packageIndex); + + foreach (var package in _packages) + { + if (package != null) + { + var env = package.AasEnv; + if (env != null) + { + var submodels = env.Submodels.Where(a => a.Id.Equals(submodelIdentifier)); + if (submodels.Any()) + { + if (!Program.withDb) + { + output = submodels.First(); + } + else + { + output = DBRead.getSubmodel(submodelIdentifier); + } + packageIndex = Array.IndexOf(_packages, package); + return true; + } + } + } + } + + return false; + } + + #endregion + + #region ConceptDescription + + public void DeleteConceptDescriptionById(string cdIdentifier) + { + var conceptDescription = GetConceptDescriptionById(cdIdentifier, out int packageIndex); + + if ((conceptDescription != null) && (packageIndex != -1)) + { + _packages[packageIndex].AasEnv.ConceptDescriptions.Remove(conceptDescription); + _logger.LogDebug($"Delete ConceptDescription with id {cdIdentifier}"); + AasxServer.Program.signalNewData(1); + } + } + + public IConceptDescription GetConceptDescriptionById(string cdIdentifier, out int packageIndex) + { + var found = IsConceptDescriptionPresent(cdIdentifier, out IConceptDescription output, out packageIndex); + if (found) + { + _logger.LogDebug($"Found the conceptDescription with id {cdIdentifier}"); + return output; + } + else + { + throw new NotFoundException($"ConceptDescription with id {cdIdentifier} NOT found."); + } + } + + private bool IsConceptDescriptionPresent(string cdIdentifier, out IConceptDescription output, out int packageIndex) + { + output = null; + packageIndex = -1; + foreach (var package in _packages) + { + if (package != null) + { + var env = package.AasEnv; + if (env != null) + { + var conceptDescriptions = env.ConceptDescriptions.Where(c => c.Id.Equals(cdIdentifier)); + if (conceptDescriptions.Any()) + { + output = conceptDescriptions.First(); + packageIndex = Array.IndexOf(_packages, package); + return true; + } + } + } + } + + return false; + } + + public List GetAllConceptDescriptions() + { + var output = new List(); + + //Get All Concept descriptions + foreach (var package in _packages) + { + if (package != null) + { + var env = package.AasEnv; + if (env != null) + { + output.AddRange(env.ConceptDescriptions); + } + } + } + + return output; + } + + public bool IsConceptDescriptionPresent(string cdIdentifier) + { + return IsConceptDescriptionPresent(cdIdentifier, out _, out _); + } + + public IConceptDescription CreateConceptDescription(IConceptDescription body) + { + if (EmptyPackageAvailable(out int emptyPackageIndex)) + { + + _packages[emptyPackageIndex].AasEnv.ConceptDescriptions.Add(body); + var timeStamp = DateTime.UtcNow; + body.TimeStampCreate = timeStamp; + body.SetTimeStamp(timeStamp); + Program.signalNewData(2); + return _packages[emptyPackageIndex].AasEnv.ConceptDescriptions[0]; //Considering it is the first AAS being added to empty package. + } + else + { + throw new Exception("No empty environment package available in the server."); + } + } + + public void UpdateConceptDescriptionById(IConceptDescription body, string cdIdentifier) + { + var conceptDescription = GetConceptDescriptionById(cdIdentifier, out int packageIndex); + if (conceptDescription != null && packageIndex != -1) + { + var cdIndex = _packages[packageIndex].AasEnv.ConceptDescriptions.IndexOf(conceptDescription); + _packages[packageIndex].AasEnv.ConceptDescriptions.Remove(conceptDescription); + _packages[packageIndex].AasEnv.ConceptDescriptions.Insert(cdIndex, body); + var timeStamp = DateTime.UtcNow; + body.TimeStampCreate = timeStamp; + body.SetTimeStamp(timeStamp); + Program.signalNewData(1); //0 not working, hence 1 = same tree, structure may change + + _logger.LogDebug($"Successfully updated the ConceptDescription."); + } + } + + public Stream GetFileFromPackage(string submodelIdentifier, string fileName) + { + if (!string.IsNullOrEmpty(fileName)) + { + var _ = GetSubmodelById(submodelIdentifier, out int packageIndex); + return _packages[packageIndex].GetLocalStreamFromPackage(fileName); + } + else + { + _logger.LogError($"File name is empty."); + throw new UnprocessableEntityException($"File name is empty."); + } + } + + public void ReplaceAssetAdministrationShellById(string aasIdentifier, IAssetAdministrationShell newAas) + { + var aas = GetAssetAdministrationShellById(aasIdentifier, out int packageIndex); + if (aas != null && packageIndex != -1) + { + var existingIndex = _packages[packageIndex].AasEnv.AssetAdministrationShells.IndexOf(aas); + _packages[packageIndex].AasEnv.AssetAdministrationShells.Remove(aas); + _packages[packageIndex].AasEnv.AssetAdministrationShells.Insert(existingIndex, newAas); + var timeStamp = DateTime.UtcNow; + newAas.TimeStampCreate = timeStamp; + newAas.SetTimeStamp(timeStamp); + Program.signalNewData(1); + } + } + + public void ReplaceSubmodelById(string submodelIdentifier, ISubmodel newSubmodel) + { + var submodel = GetSubmodelById(submodelIdentifier, out int packageIndex); + if (submodel != null && packageIndex != -1) + { + var existingIndex = _packages[packageIndex].AasEnv.Submodels.IndexOf(submodel); + _packages[packageIndex].AasEnv.Submodels.Remove(submodel); + _packages[packageIndex].AasEnv.Submodels.Insert(existingIndex, newSubmodel); + var timeStamp = DateTime.UtcNow; + newSubmodel.TimeStampCreate = timeStamp; + newSubmodel.SetParentAndTimestamp(timeStamp); + Program.signalNewData(1); + } + } + + public List GetAllSubmodels(IReference reqSemanticId = null, string idShort = null) + { + List output = new List(); + + //Get All Submodels + foreach (var package in _packages) + { + if (package != null) + { + var env = package.AasEnv; + if (env != null) + { + foreach (var s in env.Submodels) + { + // TODO (jtikekar, 2023-09-04): uncomment and support + //if (SecurityCheckTestOnly(s.IdShort, "", s)) + output.Add(s); + } + } + } + } + + //Apply filters + if (output.Any()) + { + //Filter w.r.t idShort + if (!string.IsNullOrEmpty(idShort)) + { + var submodels = output.Where(s => s.IdShort.Equals(idShort)).ToList(); + if (submodels.IsNullOrEmpty()) + { + _logger.LogInformation($"Submodels with IdShort {idShort} Not Found."); + } + + output = submodels; + } + + //Filter w.r.t. SemanticId + if (reqSemanticId != null) + { + if (output.Any()) + { + var submodels = output.Where(s => s.SemanticId.Matches(reqSemanticId)).ToList(); + if (submodels.IsNullOrEmpty()) + { + _logger.LogInformation($"Submodels with requested SemnaticId Not Found."); + } + + output = submodels; + } + + } + } + + return output; + } + + public ISubmodel CreateSubmodel(ISubmodel newSubmodel, string aasIdentifier = null) + { + //Check if Submodel exists + var found = IsSubmodelPresent(newSubmodel.Id, out _, out _); + if (found) + { + throw new DuplicateException($"Submodel with id {newSubmodel.Id} already exists."); + } + + //Check if corresponding AAS exist. If yes, then add to the same environment + if (!string.IsNullOrEmpty(aasIdentifier)) + { + var aasFound = IsAssetAdministrationShellPresent(aasIdentifier, out IAssetAdministrationShell aas, out int packageIndex); + if (aasFound) + { + newSubmodel.SetAllParents(DateTime.UtcNow); + aas.Submodels ??= new List(); + aas.Submodels.Add(newSubmodel.GetReference()); + _packages[packageIndex].AasEnv.Submodels.Add(newSubmodel); + var timeStamp = DateTime.UtcNow; + aas.SetTimeStamp(timeStamp); + newSubmodel.TimeStampCreate = timeStamp; + newSubmodel.SetTimeStamp(timeStamp); + AasxServer.Program.signalNewData(2); + return newSubmodel; // TODO: jtikekar find proper solution + } + } + + if (EmptyPackageAvailable(out int emptyPackageIndex)) + { + _packages[emptyPackageIndex].AasEnv.Submodels.Add(newSubmodel); + var timeStamp = DateTime.UtcNow; + newSubmodel.TimeStampCreate = timeStamp; + newSubmodel.SetTimeStamp(timeStamp); + Program.signalNewData(2); + return _packages[emptyPackageIndex].AasEnv.Submodels[0]; //Considering it is the first AAS being added to empty package. + } + else + { + throw new Exception("No empty environment package available in the server."); + } + } + + public Task ReplaceSupplementaryFileInPackage(string submodelIdentifier, string sourceFile, string targetFile, string contentType, MemoryStream fileContent) + { + var submodel = GetSubmodelById(submodelIdentifier, out int packageIndex); + return _packages[packageIndex].ReplaceSupplementaryFileInPackageAsync(sourceFile, targetFile, contentType, fileContent); + } + + #endregion + } +} diff --git a/src/AasxServerStandardBib/Services-DB/ConceptDescriptionServiceDB.cs b/src/AasxServerStandardBib/Services-DB/ConceptDescriptionServiceDB.cs new file mode 100644 index 000000000..fb3eb7210 --- /dev/null +++ b/src/AasxServerStandardBib/Services-DB/ConceptDescriptionServiceDB.cs @@ -0,0 +1,143 @@ + +using AasxServerStandardBib.Exceptions; +using AasxServerStandardBib.Interfaces; +using AasxServerStandardBib.Logging; +using Extensions; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace AasxServerStandardBib.Services +{ + public class ConceptDescriptionServiceDB : IConceptDescriptionService + { + private readonly IAppLogger _logger; + private readonly IAdminShellPackageEnvironmentService _packageEnvService; + private readonly IMetamodelVerificationService _verificationService; + + public ConceptDescriptionServiceDB(IAppLogger logger, IAdminShellPackageEnvironmentService packageEnvService, IMetamodelVerificationService verificationService) + { + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); ; + _packageEnvService = packageEnvService; + _verificationService = verificationService; + } + + public IConceptDescription CreateConceptDescription(IConceptDescription body) + { + //Verify the body first + //_verificationService.VerifyRequestBody(body); + + var found = _packageEnvService.IsConceptDescriptionPresent(body.Id); + if (found) + { + _logger.LogDebug($"Cannot create requested ConceptDescription !!"); + throw new DuplicateException($"ConceptDescription with id {body.Id} already exists."); + } + + var output = _packageEnvService.CreateConceptDescription(body); + + return output; + } + + public void DeleteConceptDescriptionById(string cdIdentifier) + { + _packageEnvService.DeleteConceptDescriptionById(cdIdentifier); + } + + public List GetAllConceptDescriptions(string idShort, Reference isCaseOf, Reference dataSpecificationRef) + { + //Get All Concept descriptions + var output = _packageEnvService.GetAllConceptDescriptions(); + + if (output.Any()) + { + //Filter AASs based on IdShort + if (!string.IsNullOrEmpty(idShort)) + { + var cdList = output.Where(cd => cd.IdShort.Equals(idShort)).ToList(); + if (cdList.IsNullOrEmpty()) + { + _logger.LogDebug($"No Concept Description with IdShort {idShort} Found."); + } + else + { + output = cdList; + } + } + + //Filter based on IsCaseOf + if (isCaseOf != null) + { + var cdList = new List(); + foreach (var conceptDescription in output) + { + if (!conceptDescription.IsCaseOf.IsNullOrEmpty()) + { + foreach (var reference in conceptDescription.IsCaseOf) + { + if (reference != null && reference.Matches(isCaseOf)) + { + cdList.Add(conceptDescription); + break; + } + } + } + } + if (cdList.IsNullOrEmpty()) + { + _logger.LogDebug($"No Concept Description with requested IsCaseOf found."); + } + else + { + output = cdList; + } + + } + + //Filter based on DataSpecificationRef + if (dataSpecificationRef != null) + { + var cdList = new List(); + foreach (var conceptDescription in output) + { + if (!conceptDescription.EmbeddedDataSpecifications.IsNullOrEmpty()) + { + foreach (var reference in conceptDescription.EmbeddedDataSpecifications) + { + if (reference != null && reference.DataSpecification.Matches(dataSpecificationRef)) + { + cdList.Add(conceptDescription); + break; + } + } + } + } + if (cdList.IsNullOrEmpty()) + { + _logger.LogDebug($"No Concept Description with requested DataSpecificationReference found."); + } + else + { + output = cdList; + } + } + } + + return output; + } + + public IConceptDescription GetConceptDescriptionById(string cdIdentifier) + { + return _packageEnvService.GetConceptDescriptionById(cdIdentifier, out _); + } + + public void UpdateConceptDescriptionById(ConceptDescription body, string cdIdentifier) + { + //Verify the body first + _verificationService.VerifyRequestBody(body); + + _packageEnvService.UpdateConceptDescriptionById(body, cdIdentifier); + } + } +} diff --git a/src/AasxServerStandardBib/Services-DB/SubmodelServiceDB.cs b/src/AasxServerStandardBib/Services-DB/SubmodelServiceDB.cs new file mode 100644 index 000000000..82b347cb3 --- /dev/null +++ b/src/AasxServerStandardBib/Services-DB/SubmodelServiceDB.cs @@ -0,0 +1,633 @@ + +using AasxServer; +using AasxServerStandardBib.Exceptions; +using AasxServerStandardBib.Interfaces; +using AasxServerStandardBib.Logging; +using AasxServerStandardBib.Transformers; +using Extensions; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace AasxServerStandardBib.Services +{ + public class SubmodelServiceDB : ISubmodelService + { + private readonly IAppLogger _logger; + private readonly IAdminShellPackageEnvironmentService _packageEnvService; + private readonly IMetamodelVerificationService _verificationService; + + public SubmodelServiceDB(IAppLogger logger, IAdminShellPackageEnvironmentService packageEnvService, IMetamodelVerificationService verificationService) + { + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); ; + _packageEnvService = packageEnvService; + _verificationService = verificationService; + } + + #region PrivateMethods + + private bool IsSubmodelElementPresent(string submodelIdentifier, string idShortPath, out ISubmodelElement output, out IReferable smeParent) + { + output = null; + smeParent = null; + var submodel = _packageEnvService.GetSubmodelById(submodelIdentifier, out _); + + if (submodel != null) + { + output = GetSubmodelElementByPath(submodel, idShortPath, out IReferable parent); + smeParent = parent; + if (output != null) + { + _logger.LogInformation($"Found SubmodelElement at {idShortPath} in submodel with Id {submodelIdentifier}"); + return true; + } + + } + + return false; + } + + private ISubmodelElement GetSubmodelElementByPath(IReferable parent, string idShortPath, out IReferable outParent) + { + outParent = parent; + if (idShortPath.Contains('.')) + { + string[] idShorts = idShortPath.Split('.', 2); + if (parent is Submodel submodel) + { + var submodelElement = submodel.FindSubmodelElementByIdShort(idShorts[0]); + if (submodelElement != null) + { + return GetSubmodelElementByPath(submodelElement, idShorts[1], out outParent); + } + } + else if (parent is SubmodelElementCollection collection) + { + var submodelElement = collection.FindFirstIdShortAs(idShorts[0]); + if (submodelElement != null) + { + return GetSubmodelElementByPath(submodelElement, idShorts[1], out outParent); + } + } + else if (parent is SubmodelElementList list) + { + var submodelElement = list.FindFirstIdShortAs(idShorts[0]); + if (submodelElement != null) + { + return GetSubmodelElementByPath(submodelElement, idShorts[1], out outParent); + } + } + else if (parent is Entity entity) + { + var submodelElement = entity.FindFirstIdShortAs(idShortPath); + if (submodelElement != null) + { + return GetSubmodelElementByPath(submodelElement, idShorts[1], out outParent); + } + } + else if (parent is AnnotatedRelationshipElement annotatedRelationshipElement) + { + var submodelElement = annotatedRelationshipElement.FindFirstIdShortAs(idShortPath); + if (submodelElement != null) + { + return GetSubmodelElementByPath(submodelElement, idShorts[1], out outParent); + } + } + else + { + throw new Exception($"Parent of type {parent.GetType()} not supported."); + } + } + else + { + if (parent is Submodel submodel) + { + var submodelElement = submodel.FindSubmodelElementByIdShort(idShortPath); + if (submodelElement != null) + { + return submodelElement; + } + } + else if (parent is SubmodelElementCollection collection) + { + var submodelElement = collection.FindFirstIdShortAs(idShortPath); + if (submodelElement != null) + { + return submodelElement; + } + } + else if (parent is SubmodelElementList list) + { + var submodelElement = list.FindFirstIdShortAs(idShortPath); + if (submodelElement != null) + { + return submodelElement; + } + } + else if (parent is Entity entity) + { + var submodelElement = entity.FindFirstIdShortAs(idShortPath); + if (submodelElement != null) + { + return submodelElement; + } + } + else if (parent is AnnotatedRelationshipElement annotatedRelationshipElement) + { + var submodelElement = annotatedRelationshipElement.FindFirstIdShortAs(idShortPath); + if (submodelElement != null) + { + return submodelElement; + } + } + else + { + throw new Exception($"Parent of type {parent.GetType()} not supported."); + } + } + return null; + } + + + + #endregion + + public bool IsSubmodelElementPresent(string submodelIdentifier, string idShortPath) + { + return IsSubmodelElementPresent(submodelIdentifier, idShortPath, out _, out _); + } + + public void DeleteSubmodelById(string submodelIdentifier) + { + _packageEnvService.DeleteSubmodelById(submodelIdentifier); + } + + public void DeleteSubmodelElementByPath(string submodelIdentifier, string idShortPath) + { + var found = IsSubmodelElementPresent(submodelIdentifier, idShortPath, out ISubmodelElement submodelElement, out IReferable smeParent); + if (found) + { + if (smeParent is SubmodelElementCollection parentCollection) + { + parentCollection.Value.Remove(submodelElement); + } + else if (smeParent is SubmodelElementList parentList) + { + parentList.Value.Remove(submodelElement); + } + else if (smeParent is AnnotatedRelationshipElement annotatedRelationshipElement) + { + annotatedRelationshipElement.Annotations.Remove((IDataElement)submodelElement); + } + else if (smeParent is Entity entity) + { + entity.Statements.Remove(submodelElement); + } + else if (smeParent is Submodel parentSubmodel) + { + parentSubmodel.SubmodelElements.Remove(submodelElement); + } + else + { + _logger.LogDebug($"Could not delete SubmodelElement {submodelElement.IdShort}"); + throw new Exception($"Unsupported data type of parent {smeParent.IdShort} for delete operation."); + } + } + else + { + throw new NotFoundException($"Requested SubmodelElement NOT found in submodel with Id {submodelIdentifier}"); + } + + Program.signalNewData(1); + _logger.LogDebug($"Deleted SubmodelElement at {idShortPath} from submodel with Id {submodelIdentifier}"); + } + + public List GetAllSubmodelElements(string submodelIdentifier) + { + var submodel = _packageEnvService.GetSubmodelById(submodelIdentifier, out _); + return submodel.SubmodelElements; + } + + public void DeleteFileByPath(string submodelIdentifier, string idShortPath) + { + var found = IsSubmodelElementPresent(submodelIdentifier, idShortPath, out ISubmodelElement submodelElement, out _); + if (found) + { + if (submodelElement is AasCore.Aas3_0.File file) + { + if (!string.IsNullOrEmpty(file.Value)) + { + //check if it is external location + if (file.Value.StartsWith("http") || file.Value.StartsWith("https")) + { + _logger.LogWarning($"Value of the Submodel-Element File with IdShort {file.IdShort} is an external link."); + throw new NotImplementedException($"File location for {file.IdShort} is external {file.Value}. Currently this fuctionality is not supported."); + } + //Check if a directory + else if (file.Value.StartsWith('/') || file.Value.StartsWith('\\')) + { + _logger.LogInformation($"Value of the Submodel-Element File with IdShort {file.IdShort} is a File-Path."); + + _packageEnvService.DeleteSupplementaryFileInPackage(submodelIdentifier, file.Value); + + file.Value = string.Empty; + } + // incorrect value + else + { + _logger.LogError($"Incorrect value {file.Value} of the Submodel-Element File with IdShort {file.IdShort}"); + throw new OperationNotSupported($"Incorrect value {file.Value} of the File with IdShort {file.IdShort}."); + } + } + else + { + throw new OperationNotSupported($"Cannot delete the file. SubmodelElement {idShortPath} does not have a file attached."); + } + } + else + { + throw new OperationNotSupported($"SubmodelElement found at {idShortPath} is not of type File"); + } + } + else + { + throw new NotFoundException($"Requested SubmodelElement NOT found in submodel with Id {submodelIdentifier}"); + } + + Program.signalNewData(1); + _logger.LogDebug($"Deleted the file at {idShortPath} from submodel with Id {submodelIdentifier}"); + } + + public string GetFileByPath(string submodelIdentifier, string idShortPath, out byte[] byteArray, out long fileSize) + { + byteArray = null; + string fileName = null; + fileSize = 0; + + var fileElement = GetSubmodelElementByPath(submodelIdentifier, idShortPath); + + if (fileElement != null) + { + + if (fileElement is AasCore.Aas3_0.File file) + { + fileName = file.Value; + + if (string.IsNullOrEmpty(fileName)) + { + _logger.LogError($"File name is empty. Cannot fetch the file."); + throw new UnprocessableEntityException($"File value Null!!"); + } + + //check if it is external location + if (file.Value.StartsWith("http") || file.Value.StartsWith("https")) + { + _logger.LogWarning($"Value of the Submodel-Element File with IdShort {file.IdShort} is an external link."); + throw new NotImplementedException($"File location for {file.IdShort} is external {file.Value}. Currently this fuctionality is not supported."); + } + //Check if a directory + else if (file.Value.StartsWith('/') || file.Value.StartsWith('\\')) + { + _logger.LogInformation($"Value of the Submodel-Element File with IdShort {file.IdShort} is a File-Path."); + Stream stream = _packageEnvService.GetFileFromPackage(submodelIdentifier, fileName); + byteArray = stream.ToByteArray(); + fileSize = byteArray.Length; + } + // incorrect value + else + { + _logger.LogError($"Incorrect value {file.Value} of the Submodel-Element File with IdShort {file.IdShort}"); + throw new UnprocessableEntityException($"Incorrect value {file.Value} of the File with IdShort {file.IdShort}."); + } + + } + else + { + throw new NotFoundException($"Submodel element {fileElement.IdShort} is not of type File."); + } + } + + return fileName; + } + + public ISubmodel GetSubmodelById(string submodelIdentifier) + { + return _packageEnvService.GetSubmodelById(submodelIdentifier, out _); + } + + public ISubmodelElement GetSubmodelElementByPath(string submodelIdentifier, string idShortPath) + { + var found = IsSubmodelElementPresent(submodelIdentifier, idShortPath, out ISubmodelElement output, out _); + if (found) + { + return output; + } + else + { + throw new NotFoundException($"Submodel Element at {idShortPath} not found in the submodel with id {submodelIdentifier}"); + } + } + + public ISubmodelElement CreateSubmodelElement(string submodelIdentifier, ISubmodelElement newSubmodelElement, bool first) + { + //Verify the body first + _verificationService.VerifyRequestBody(newSubmodelElement); + + var smeFound = IsSubmodelElementPresent(submodelIdentifier, newSubmodelElement.IdShort, out _, out IReferable smeParent); + if (smeFound) + { + _logger.LogDebug($"Cannot create requested submodel element !!"); + throw new DuplicateException($"SubmodelElement with idShort {newSubmodelElement.IdShort} already exists in the submodel."); + } + + //Create new SME + var submodel = GetSubmodelById(submodelIdentifier); + + submodel.SubmodelElements ??= new List(); + if (first) + { + submodel.SubmodelElements.Insert(0, newSubmodelElement); + } + else + { + submodel.SubmodelElements.Add(newSubmodelElement); + } + + var timeStamp = DateTime.UtcNow; + newSubmodelElement.SetAllParentsAndTimestamps(submodel, timeStamp, timeStamp); + newSubmodelElement.SetTimeStamp(timeStamp); + + Program.signalNewData(1); + return newSubmodelElement; + } + + public ISubmodelElement CreateSubmodelElementByPath(string submodelIdentifier, string idShortPath, bool first, ISubmodelElement newSubmodelElement) + { + //Verify the body first + _verificationService.VerifyRequestBody(newSubmodelElement); + + var newIdShortPath = idShortPath + "." + newSubmodelElement.IdShort; + var smeFound = IsSubmodelElementPresent(submodelIdentifier, newIdShortPath, out _, out IReferable smeParent); + if (smeFound) + { + _logger.LogDebug($"Cannot create requested submodel element !!"); + throw new DuplicateException($"SubmodelElement with idShort {newSubmodelElement.IdShort} already exists at {idShortPath} in the submodel."); + } + + //Create new SME + _logger.LogDebug("Create the new submodel element."); + if (smeParent != null && smeParent is Submodel submodel) + { + submodel.SubmodelElements ??= new List(); + if (first) + { + submodel.SubmodelElements.Insert(0, newSubmodelElement); + } + else + { + submodel.SubmodelElements.Add(newSubmodelElement); + } + } + else if (smeParent != null && smeParent is SubmodelElementCollection collection) + { + collection.Value ??= new List(); + if (first) + { + collection.Value.Insert(0, newSubmodelElement); + } + else + { + collection.Value.Add(newSubmodelElement); + } + } + else if (smeParent != null && smeParent is SubmodelElementList list) + { + list.Value ??= new List(); + if (first) + { + list.Value.Insert(0, newSubmodelElement); + } + else + { + list.Value.Add(newSubmodelElement); + } + } + else if (smeParent != null && smeParent is Entity entity) + { + entity.Statements ??= new List(); + if (first) + { + entity.Statements.Insert(0, newSubmodelElement); + } + else + { + entity.Statements.Add(newSubmodelElement); + } + } + else if (smeParent != null && smeParent is AnnotatedRelationshipElement annotatedRelationshipElement) + { + annotatedRelationshipElement.Annotations ??= new List(); + if (first) + { + annotatedRelationshipElement.Annotations.Insert(0, (IDataElement)newSubmodelElement); + } + else + { + annotatedRelationshipElement.Annotations.Add((IDataElement)newSubmodelElement); + } + } + else + { + throw new Exception($"The submodel element {idShortPath} does not support child elements."); + } + + var timeStamp = DateTime.UtcNow; + newSubmodelElement.SetAllParentsAndTimestamps(smeParent, timeStamp, timeStamp); + newSubmodelElement.SetTimeStamp(timeStamp); + Program.signalNewData(1); + return newSubmodelElement; + } + + public void ReplaceSubmodelById(string submodelIdentifier, ISubmodel newSubmodel) + { + _verificationService.VerifyRequestBody(newSubmodel); + _packageEnvService.ReplaceSubmodelById(submodelIdentifier, newSubmodel); + } + + public void ReplaceSubmodelElementByPath(string submodelIdentifier, string idShortPath, ISubmodelElement newSme) + { + _verificationService.VerifyRequestBody(newSme); + var submodel = GetSubmodelById(submodelIdentifier); + var existingSme = GetSubmodelElementByPath(submodel, idShortPath, out IReferable smeParent); + + if (existingSme != null && smeParent != null) + { + if (smeParent is Submodel) + { + var existingIndex = submodel.SubmodelElements.IndexOf(existingSme); + submodel.SubmodelElements.Remove(existingSme); + submodel.SubmodelElements.Insert(existingIndex, newSme); + } + else if (smeParent is SubmodelElementCollection collection) + { + var existingIndex = collection.Value.IndexOf(existingSme); + collection.Value.Remove(existingSme); + collection.Value.Insert(existingIndex, newSme); + } + else if (smeParent is SubmodelElementList smeList) + { + var existingIndex = smeList.Value.IndexOf(existingSme); + smeList.Value.Remove(existingSme); + smeList.Value.Insert(existingIndex, newSme); + } + else if (smeParent is Entity entity) + { + var existingIndex = entity.Statements.IndexOf(existingSme); + entity.Statements.Remove(existingSme); + entity.Statements.Insert(existingIndex, newSme); + } + else if (smeParent is AnnotatedRelationshipElement annotatedRelElement) + { + var existingIndex = annotatedRelElement.Annotations.IndexOf((IDataElement)existingSme); + annotatedRelElement.Annotations.Remove((IDataElement)existingSme); + annotatedRelElement.Annotations.Insert(existingIndex, (IDataElement)newSme); + } + else + { + throw new Exception($"The submodel element {idShortPath} does not support child elements."); + } + + var timeStamp = DateTime.UtcNow; + newSme.SetAllParentsAndTimestamps(smeParent, timeStamp, timeStamp); + newSme.SetTimeStamp(timeStamp); + Program.signalNewData(1); + } + } + + public List GetAllSubmodels(IReference reqSemanticId = null, string idShort = null) + { + return _packageEnvService.GetAllSubmodels(reqSemanticId, idShort); + } + + public ISubmodel CreateSubmodel(ISubmodel newSubmodel, string aasIdentifier) + { + //Verify the body first + _verificationService.VerifyRequestBody(newSubmodel); + + var found = _packageEnvService.IsSubmodelPresent(newSubmodel.Id); + if (found) + { + _logger.LogDebug($"Cannot create requested Submodel !!"); + throw new DuplicateException($"Submodel with id {newSubmodel.Id} already exists."); + } + + var output = _packageEnvService.CreateSubmodel(newSubmodel, aasIdentifier); + + return output; + } + + public void UpdateSubmodelById(string submodelIdentifier, ISubmodel newSubmodel) + { + var submodel = _packageEnvService.GetSubmodelById(submodelIdentifier, out _); + + //Verify the body first + _verificationService.VerifyRequestBody(newSubmodel); + + Update.ToUpdateObject(submodel, newSubmodel); + + submodel.SetTimeStamp(DateTime.UtcNow); + + Program.signalNewData(0); + } + + public void UpdateSubmodelElementByPath(string submodelIdentifier, string idShortPath, ISubmodelElement newSme) + { + var submodelElement = GetSubmodelElementByPath(submodelIdentifier, idShortPath); + + //Verify the body first + _verificationService.VerifyRequestBody(newSme); + + Update.ToUpdateObject(submodelElement, newSme); + + newSme.SetTimeStamp(DateTime.UtcNow); + + Program.signalNewData(0); + } + + public void ReplaceFileByPath(string submodelIdentifier, string idShortPath, string fileName, string contentType, MemoryStream fileContent) + { + var fileElement = GetSubmodelElementByPath(submodelIdentifier, idShortPath); + + if (fileElement != null) + { + if (fileElement is AasCore.Aas3_0.File file) + { + //Check if file has location + if (!string.IsNullOrEmpty(file.Value)) + { + //check if it is external location + if (file.Value.StartsWith("http") || file.Value.StartsWith("https")) + { + _logger.LogWarning($"Value of the Submodel-Element File with IdShort {file.IdShort} is an external link."); + throw new NotImplementedException($"File location for {file.IdShort} is external {file.Value}. Currently this fuctionality is not supported."); + } + //Check if a directory + else if (file.Value.StartsWith('/') || file.Value.StartsWith('\\')) + { + _logger.LogInformation($"Value of the Submodel-Element File with IdShort {file.IdShort} is a File-Path."); + //check if the value consists file extension + string sourcePath; + if (Path.HasExtension(file.Value)) + { + sourcePath = Path.GetDirectoryName(file.Value); //This should get platform specific path, without file name + } + else + { + sourcePath = Path.Combine(file.Value); + } + + var targetFile = Path.Combine(sourcePath, fileName); + targetFile = targetFile.Replace('/', Path.DirectorySeparatorChar); //TODO:jtikekar: better way to handle + Task task = _packageEnvService.ReplaceSupplementaryFileInPackage(submodelIdentifier, file.Value, targetFile, contentType, fileContent); + file.Value = FormatFileName(targetFile); + AasxServer.Program.signalNewData(2); + } + // incorrect value + else + { + _logger.LogError($"Incorrect value {file.Value} of the Submodel-Element File with IdShort {file.IdShort}"); + throw new UnprocessableEntityException($"Incorrect value {file.Value} of the File with IdShort {file.IdShort}."); + } + } + else + { + //The value is null, so store the file to default location "/aasx/files" + _logger.LogError($"Null Value of the Submodel-Element File with IdShort {file.IdShort}"); + var targetFile = Path.Combine("/aasx/files", fileName); + targetFile = targetFile.Replace('/', Path.DirectorySeparatorChar); + Task task = _packageEnvService.ReplaceSupplementaryFileInPackage(submodelIdentifier, file.Value, targetFile, contentType, fileContent); + file.Value = FormatFileName(targetFile); + AasxServer.Program.signalNewData(2); + } + + } + else + { + throw new NotFoundException($"Submodel element {fileElement.IdShort} is not of type File."); + } + } + + } + + private string FormatFileName(string fileName) + { + string fileNameTemp = fileName; + + string output = Regex.Replace(fileNameTemp, @"\\", "/"); + + return output; + } + } +} From ca400b439feb474b62422460b2d4473ee1516426 Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Fri, 23 Feb 2024 08:49:02 +0100 Subject: [PATCH 05/17] AdminShellPackageEnvironmentServiceDB Finish AAS Region --- .../Services-DB/AdminShellPackageEnvironmentServiceDB.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs b/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs index f18dba80c..7034cff7f 100644 --- a/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs +++ b/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs @@ -159,11 +159,15 @@ public void DeleteAssetInformationThumbnail(int packageIndex, IResource defaultT public Stream GetAssetInformationThumbnail(int packageIndex) { + //TODO + throw new NotImplementedException(); return _packages[packageIndex].GetLocalThumbnailStream(); } public void UpdateAssetInformationThumbnail(IResource defaultThumbnail, Stream fileContent, int packageIndex) { + //TODO + throw new NotImplementedException(); _packages[packageIndex].EmbeddAssetInformationThumbnail(defaultThumbnail, fileContent); Program.signalNewData(0); } From 1f252ed9e932ee18cacad3603a98bf580064687f Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:34:55 +0100 Subject: [PATCH 06/17] AdminShellPackageEnvironmentServiceDB Finish Submodel Region --- src/AasxServerStandardBib/Database.cs | 68 +++-- .../AdminShellPackageEnvironmentServiceDB.cs | 287 +++++++----------- 2 files changed, 163 insertions(+), 192 deletions(-) diff --git a/src/AasxServerStandardBib/Database.cs b/src/AasxServerStandardBib/Database.cs index 060e6acc0..6c974b244 100644 --- a/src/AasxServerStandardBib/Database.cs +++ b/src/AasxServerStandardBib/Database.cs @@ -20,10 +20,21 @@ namespace AasxServerStandardBib public interface IDatabase { void Initialize(String connectionString); - public void writeDBAssetAdministrationShell(IAssetAdministrationShell shell); - public bool deleteDBAssetAdministrationShell(IAssetAdministrationShell shell); + + #region AssetAdministrationShell + public void WriteDBAssetAdministrationShell(IAssetAdministrationShell shell); public IQueryable getLINQAssetAdministrationShell(); - public void updateDBAssetAdministrationShellById(IAssetAdministrationShell body, string aasIdentifier); + public void UpdateDBAssetAdministrationShellById(IAssetAdministrationShell body, string aasIdentifier); + public bool DeleteDBAssetAdministrationShell(IAssetAdministrationShell shell); + #endregion + + #region Submodel + public void WriteDBSubmodel(ISubmodel submodel); + public IQueryable getLINQSubmodel(); + public void UpdateDBSubmodelById(string submodelIdentifier, ISubmodel newSubmodel); + public void DeleteDBSubmodelById(string submodelIdentifier); + #endregion + public void importAASCoreEnvironment(IEnvironment environment); } @@ -55,9 +66,9 @@ private IMongoCollection getAasCollection() { return _database.GetCollection("AssetAdministrationShells"); } - private IMongoCollection getSubmodelCollection() + private IMongoCollection getSubmodelCollection() { - return _database.GetCollection("Submodels"); + return _database.GetCollection("Submodels"); } private IMongoCollection getConceptDescriptionCollection() { @@ -65,7 +76,7 @@ private IMongoCollection getConceptDescriptionCollection() } - public void writeDBAssetAdministrationShell(IAssetAdministrationShell shell) + public void WriteDBAssetAdministrationShell(IAssetAdministrationShell shell) { try { @@ -74,50 +85,69 @@ public void writeDBAssetAdministrationShell(IAssetAdministrationShell shell) { } } - public void writeDBSubmodel(ISubmodel submodel) + public void writeDBConceptDescription(IConceptDescription conceptDescription) { try { - getSubmodelCollection().InsertOne(submodel); + getConceptDescriptionCollection().InsertOne(conceptDescription); } catch (MongoWriteException) { } } - public void writeDBConceptDescription(IConceptDescription conceptDescription) + + #region AssetAdministrationShell + public bool DeleteDBAssetAdministrationShell(IAssetAdministrationShell shell) + { + throw new NotImplementedException(); + } + public IQueryable getLINQAssetAdministrationShell() + { + return getAasCollection().AsQueryable(); + } + public async void UpdateDBAssetAdministrationShellById(IAssetAdministrationShell body, string aasIdentifier) + { + await getAasCollection().ReplaceOneAsync(r => r.Id.Equals(aasIdentifier), (AssetAdministrationShell)body); + } + #endregion + + #region Submodel + public void WriteDBSubmodel(ISubmodel submodel) { try { - getConceptDescriptionCollection().InsertOne(conceptDescription); + getSubmodelCollection().InsertOne((Submodel)submodel); } catch (MongoWriteException) { } } - - public bool deleteDBAssetAdministrationShell(IAssetAdministrationShell shell) + public async void DeleteDBSubmodelById(string submodelIdentifier) { - throw new NotImplementedException(); + await getSubmodelCollection().DeleteOneAsync(a => a.Id == submodelIdentifier); } - public IQueryable getLINQAssetAdministrationShell() + public IQueryable getLINQSubmodel() { - return getAasCollection().AsQueryable(); + return getSubmodelCollection().AsQueryable(); } - public async void updateDBAssetAdministrationShellById(IAssetAdministrationShell body, string aasIdentifier) + public async void UpdateDBSubmodelById(string submodelIdentifier, ISubmodel newSubmodel) { - await getAasCollection().ReplaceOneAsync(r => r.Id.Equals(aasIdentifier), (AssetAdministrationShell)body); + await getSubmodelCollection().ReplaceOneAsync(r => r.Id.Equals(submodelIdentifier), (Submodel)newSubmodel); } + #endregion + + public void importAASCoreEnvironment(IEnvironment environment) { environment.AssetAdministrationShells.ForEach(shell => { - writeDBAssetAdministrationShell(shell); + WriteDBAssetAdministrationShell(shell); }); environment.Submodels.ForEach(submodel => { - writeDBSubmodel(submodel); + WriteDBSubmodel(submodel); }); environment.ConceptDescriptions.ForEach(conceptDescription => diff --git a/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs b/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs index 7034cff7f..578c68000 100644 --- a/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs +++ b/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs @@ -58,14 +58,14 @@ public IAssetAdministrationShell CreateAssetAdministrationShell(IAssetAdministra var timeStamp = DateTime.UtcNow; body.TimeStampCreate = timeStamp; body.SetTimeStamp(timeStamp); - _database.writeDBAssetAdministrationShell(body); + _database.WriteDBAssetAdministrationShell(body); Program.signalNewData(2); return body; } public void DeleteAssetAdministrationShell(int packageIndex, IAssetAdministrationShell aas) { - bool deleted = _database.deleteDBAssetAdministrationShell(aas); + bool deleted = _database.DeleteDBAssetAdministrationShell(aas); if (deleted) { _logger.LogDebug($"Deleted Asset Administration Shell with id {aas.Id}"); @@ -102,9 +102,9 @@ public IAssetAdministrationShell GetAssetAdministrationShellById(string aasIdent public bool IsAssetAdministrationShellPresent(string aasIdentifier) { - //TODO unused -> remove in the future - throw new NotImplementedException(); - return false; + return _database.getLINQAssetAdministrationShell() + .Where(r => r.Id.Equals(aasIdentifier)) + .ToList().Any(); } private bool IsAssetAdministrationShellPresent(string aasIdentifier, out IAssetAdministrationShell output, out int packageIndex) @@ -143,7 +143,7 @@ public void UpdateAssetAdministrationShellById(IAssetAdministrationShell body, s body.TimeStampCreate = timeStamp; body.SetTimeStamp(timeStamp); - _database.updateDBAssetAdministrationShellById(body, aasIdentifier); + _database.UpdateDBAssetAdministrationShellById(body, aasIdentifier); Program.signalNewData(1); //0 not working, hence 1 = same tree, structure may change _logger.LogDebug($"Successfully updated the AAS with requested AAS"); @@ -174,87 +174,142 @@ public void UpdateAssetInformationThumbnail(IResource defaultThumbnail, Stream f #endregion #region Submodel + public ISubmodel CreateSubmodel(ISubmodel newSubmodel, string aasIdentifier = null) + { + //Check if Submodel exists + var found = IsSubmodelPresent(newSubmodel.Id); + if (found) + { + throw new DuplicateException($"Submodel with id {newSubmodel.Id} already exists."); + } + DateTime timeStamp = DateTime.UtcNow; + //Check if corresponding AAS exist. If yes, then add to the same environment + if (!string.IsNullOrEmpty(aasIdentifier)) + { + IAssetAdministrationShell aas = GetAssetAdministrationShellById(aasIdentifier, out int packageIndex); //Throws Exception if not found + newSubmodel.SetAllParents(timeStamp); - public void DeleteSubmodelById(string submodelIdentifier) + aas.Submodels ??= new List(); + aas.Submodels.Add(newSubmodel.GetReference()); + aas.SetTimeStamp(timeStamp); + _database.UpdateDBAssetAdministrationShellById(aas, aasIdentifier); //Save aas Changes in db + + newSubmodel.TimeStampCreate = timeStamp; + newSubmodel.SetTimeStamp(timeStamp); + _database.WriteDBSubmodel(newSubmodel); + + AasxServer.Program.signalNewData(2); + return newSubmodel; // TODO: jtikekar find proper solution + } + + newSubmodel.TimeStampCreate = timeStamp; + newSubmodel.SetTimeStamp(timeStamp); + _database.WriteDBSubmodel(newSubmodel); + Program.signalNewData(2); + return newSubmodel; + } + public List GetAllSubmodels(IReference reqSemanticId = null, string idShort = null) { - var submodel = GetSubmodelById(submodelIdentifier, out int packageIndex); - if (submodel != null && packageIndex != -1) + //Get All Submodels + List output = _database.getLINQSubmodel().ToList().Cast().ToList(); + // TODO (jtikekar, 2023-09-04): uncomment and support + //if (SecurityCheckTestOnly(s.IdShort, "", s)) + + //Apply filters + if (output.Any()) { - foreach (var aas in _packages[packageIndex].AasEnv.AssetAdministrationShells) + //Filter w.r.t idShort + if (!string.IsNullOrEmpty(idShort)) { - _aasService.Value.DeleteSubmodelReferenceById(aas.Id, submodelIdentifier); + var submodels = output.Where(s => s.IdShort.Equals(idShort)).ToList(); + if (submodels.IsNullOrEmpty()) + { + _logger.LogInformation($"Submodels with IdShort {idShort} Not Found."); + } + + output = submodels; + } + + //Filter w.r.t. SemanticId + if (reqSemanticId != null) + { + if (output.Any()) + { + var submodels = output.Where(s => s.SemanticId.Matches(reqSemanticId)).ToList(); + if (submodels.IsNullOrEmpty()) + { + _logger.LogInformation($"Submodels with requested SemnaticId Not Found."); + } + + output = submodels; + } } - _packages[packageIndex].AasEnv.Submodels.Remove(submodel); - _logger.LogDebug($"Deleted submodel with id {submodelIdentifier}."); - AasxServer.Program.signalNewData(1); } - } + return output; + } public ISubmodel GetSubmodelById(string submodelIdentifier, out int packageIndex) { - var found = IsSubmodelPresent(submodelIdentifier, out ISubmodel submodel, out packageIndex); - if (found) + packageIndex = -1; //TODO unused -> remove in the future + List output = _database.getLINQSubmodel() + .Where(r => r.Id.Equals(submodelIdentifier)) + .ToList(); + + if (output.Any()) { _logger.LogDebug($"Found the submodel with Id {submodelIdentifier}"); - return submodel; + return output.First(); } else { throw new NotFoundException($"Submodel with id {submodelIdentifier} NOT found."); } } - - public void DeleteSupplementaryFileInPackage(string submodelIdentifier, string filePath) + public bool IsSubmodelPresent(string submodelIdentifier) { - _ = GetSubmodelById(submodelIdentifier, out int packageIndex); - if (packageIndex != -1) - { - _packages[packageIndex].DeleteSupplementaryFile(filePath); - } + return _database.getLINQSubmodel() + .Where(r => r.Id.Equals(submodelIdentifier)) + .ToList().Any(); } - - public bool IsSubmodelPresent(string submodelIdentifier) + public void ReplaceSubmodelById(string submodelIdentifier, ISubmodel newSubmodel) { - return IsSubmodelPresent(submodelIdentifier, out _, out _); + var timeStamp = DateTime.UtcNow; + newSubmodel.TimeStampCreate = timeStamp; + newSubmodel.SetParentAndTimestamp(timeStamp); + _database.UpdateDBSubmodelById(submodelIdentifier, newSubmodel); + Program.signalNewData(1); } - - private bool IsSubmodelPresent(string submodelIdentifier, out ISubmodel output, out int packageIndex) + public void DeleteSubmodelById(string submodelIdentifier) { - output = null; - packageIndex = -1; - - Program.loadPackageForSubmodel(submodelIdentifier, out output, out packageIndex); + // Get all Submodels that Reference the given submodelIdentifier + List aasToModify = _database.getLINQAssetAdministrationShell() + .Where(aas => aas.Submodels + .Any(s => s.Keys + .Any(k => k.Value.Equals(submodelIdentifier)))) + .ToList(); - foreach (var package in _packages) + foreach (var aas in aasToModify) { - if (package != null) - { - var env = package.AasEnv; - if (env != null) - { - var submodels = env.Submodels.Where(a => a.Id.Equals(submodelIdentifier)); - if (submodels.Any()) - { - if (!Program.withDb) - { - output = submodels.First(); - } - else - { - output = DBRead.getSubmodel(submodelIdentifier); - } - packageIndex = Array.IndexOf(_packages, package); - return true; - } - } - } + _aasService.Value.DeleteSubmodelReferenceById(aas.Id, submodelIdentifier); + //TODO Jonas Graubner make sure, that reference is deleted in DB + } + _database.DeleteDBSubmodelById(submodelIdentifier); + _logger.LogDebug($"Deleted submodel with id {submodelIdentifier}."); + AasxServer.Program.signalNewData(1); + } + public void DeleteSupplementaryFileInPackage(string submodelIdentifier, string filePath) + { + //TODO + throw new NotImplementedException(); + _ = GetSubmodelById(submodelIdentifier, out int packageIndex); + if (packageIndex != -1) + { + _packages[packageIndex].DeleteSupplementaryFile(filePath); } - - return false; } - #endregion + #region ConceptDescription public void DeleteConceptDescriptionById(string cdIdentifier) @@ -397,120 +452,6 @@ public void ReplaceAssetAdministrationShellById(string aasIdentifier, IAssetAdmi } } - public void ReplaceSubmodelById(string submodelIdentifier, ISubmodel newSubmodel) - { - var submodel = GetSubmodelById(submodelIdentifier, out int packageIndex); - if (submodel != null && packageIndex != -1) - { - var existingIndex = _packages[packageIndex].AasEnv.Submodels.IndexOf(submodel); - _packages[packageIndex].AasEnv.Submodels.Remove(submodel); - _packages[packageIndex].AasEnv.Submodels.Insert(existingIndex, newSubmodel); - var timeStamp = DateTime.UtcNow; - newSubmodel.TimeStampCreate = timeStamp; - newSubmodel.SetParentAndTimestamp(timeStamp); - Program.signalNewData(1); - } - } - - public List GetAllSubmodels(IReference reqSemanticId = null, string idShort = null) - { - List output = new List(); - - //Get All Submodels - foreach (var package in _packages) - { - if (package != null) - { - var env = package.AasEnv; - if (env != null) - { - foreach (var s in env.Submodels) - { - // TODO (jtikekar, 2023-09-04): uncomment and support - //if (SecurityCheckTestOnly(s.IdShort, "", s)) - output.Add(s); - } - } - } - } - - //Apply filters - if (output.Any()) - { - //Filter w.r.t idShort - if (!string.IsNullOrEmpty(idShort)) - { - var submodels = output.Where(s => s.IdShort.Equals(idShort)).ToList(); - if (submodels.IsNullOrEmpty()) - { - _logger.LogInformation($"Submodels with IdShort {idShort} Not Found."); - } - - output = submodels; - } - - //Filter w.r.t. SemanticId - if (reqSemanticId != null) - { - if (output.Any()) - { - var submodels = output.Where(s => s.SemanticId.Matches(reqSemanticId)).ToList(); - if (submodels.IsNullOrEmpty()) - { - _logger.LogInformation($"Submodels with requested SemnaticId Not Found."); - } - - output = submodels; - } - - } - } - - return output; - } - - public ISubmodel CreateSubmodel(ISubmodel newSubmodel, string aasIdentifier = null) - { - //Check if Submodel exists - var found = IsSubmodelPresent(newSubmodel.Id, out _, out _); - if (found) - { - throw new DuplicateException($"Submodel with id {newSubmodel.Id} already exists."); - } - - //Check if corresponding AAS exist. If yes, then add to the same environment - if (!string.IsNullOrEmpty(aasIdentifier)) - { - var aasFound = IsAssetAdministrationShellPresent(aasIdentifier, out IAssetAdministrationShell aas, out int packageIndex); - if (aasFound) - { - newSubmodel.SetAllParents(DateTime.UtcNow); - aas.Submodels ??= new List(); - aas.Submodels.Add(newSubmodel.GetReference()); - _packages[packageIndex].AasEnv.Submodels.Add(newSubmodel); - var timeStamp = DateTime.UtcNow; - aas.SetTimeStamp(timeStamp); - newSubmodel.TimeStampCreate = timeStamp; - newSubmodel.SetTimeStamp(timeStamp); - AasxServer.Program.signalNewData(2); - return newSubmodel; // TODO: jtikekar find proper solution - } - } - - if (EmptyPackageAvailable(out int emptyPackageIndex)) - { - _packages[emptyPackageIndex].AasEnv.Submodels.Add(newSubmodel); - var timeStamp = DateTime.UtcNow; - newSubmodel.TimeStampCreate = timeStamp; - newSubmodel.SetTimeStamp(timeStamp); - Program.signalNewData(2); - return _packages[emptyPackageIndex].AasEnv.Submodels[0]; //Considering it is the first AAS being added to empty package. - } - else - { - throw new Exception("No empty environment package available in the server."); - } - } public Task ReplaceSupplementaryFileInPackage(string submodelIdentifier, string sourceFile, string targetFile, string contentType, MemoryStream fileContent) { From 783839b98c25f73f94c5b976c1584882f1846fa5 Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:25:43 +0100 Subject: [PATCH 07/17] First Implementation of AdminShellPackageEnvironmentServiceDB Implementation of Many File operations still Missing --- src/AasxServerStandardBib/Database.cs | 72 +++-- .../AdminShellPackageEnvironmentServiceDB.cs | 256 +++++------------- 2 files changed, 113 insertions(+), 215 deletions(-) diff --git a/src/AasxServerStandardBib/Database.cs b/src/AasxServerStandardBib/Database.cs index 6c974b244..7733487b9 100644 --- a/src/AasxServerStandardBib/Database.cs +++ b/src/AasxServerStandardBib/Database.cs @@ -23,18 +23,25 @@ public interface IDatabase #region AssetAdministrationShell public void WriteDBAssetAdministrationShell(IAssetAdministrationShell shell); - public IQueryable getLINQAssetAdministrationShell(); + public IQueryable GetLINQAssetAdministrationShell(); public void UpdateDBAssetAdministrationShellById(IAssetAdministrationShell body, string aasIdentifier); - public bool DeleteDBAssetAdministrationShell(IAssetAdministrationShell shell); + public bool DeleteDBAssetAdministrationShellById(IAssetAdministrationShell shell); #endregion #region Submodel public void WriteDBSubmodel(ISubmodel submodel); - public IQueryable getLINQSubmodel(); + public IQueryable GetLINQSubmodel(); public void UpdateDBSubmodelById(string submodelIdentifier, ISubmodel newSubmodel); public void DeleteDBSubmodelById(string submodelIdentifier); #endregion + #region ConceptDescription + public void WriteDBConceptDescription(IConceptDescription conceptDescription); + public IQueryable GetLINQConceptDescription(); + public void UpdateDBConceptDescriptionById(IConceptDescription newConceptDescription, string cdIdentifier); + public void DeleteDBConceptDescriptionById(string conceptDescription); + #endregion + public void importAASCoreEnvironment(IEnvironment environment); } @@ -70,38 +77,28 @@ private IMongoCollection getSubmodelCollection() { return _database.GetCollection("Submodels"); } - private IMongoCollection getConceptDescriptionCollection() + private IMongoCollection getConceptDescriptionCollection() { - return _database.GetCollection("ConceptDescriptions"); + return _database.GetCollection("ConceptDescriptions"); } - + + #region AssetAdministrationShell public void WriteDBAssetAdministrationShell(IAssetAdministrationShell shell) { try { getAasCollection().InsertOne((AssetAdministrationShell)shell); - } catch (MongoWriteException) - { - } - } - public void writeDBConceptDescription(IConceptDescription conceptDescription) - { - try - { - getConceptDescriptionCollection().InsertOne(conceptDescription); } catch (MongoWriteException) { } } - - #region AssetAdministrationShell - public bool DeleteDBAssetAdministrationShell(IAssetAdministrationShell shell) + public bool DeleteDBAssetAdministrationShellById(IAssetAdministrationShell shell) { throw new NotImplementedException(); } - public IQueryable getLINQAssetAdministrationShell() + public IQueryable GetLINQAssetAdministrationShell() { return getAasCollection().AsQueryable(); } @@ -122,11 +119,7 @@ public void WriteDBSubmodel(ISubmodel submodel) { } } - public async void DeleteDBSubmodelById(string submodelIdentifier) - { - await getSubmodelCollection().DeleteOneAsync(a => a.Id == submodelIdentifier); - } - public IQueryable getLINQSubmodel() + public IQueryable GetLINQSubmodel() { return getSubmodelCollection().AsQueryable(); } @@ -134,9 +127,36 @@ public async void UpdateDBSubmodelById(string submodelIdentifier, ISubmodel newS { await getSubmodelCollection().ReplaceOneAsync(r => r.Id.Equals(submodelIdentifier), (Submodel)newSubmodel); } + public async void DeleteDBSubmodelById(string submodelIdentifier) + { + await getSubmodelCollection().DeleteOneAsync(a => a.Id.Equals(submodelIdentifier)); + } #endregion - + #region ConceptDescription + public void WriteDBConceptDescription(IConceptDescription conceptDescription) + { + try + { + getConceptDescriptionCollection().InsertOne((ConceptDescription)conceptDescription); + } + catch (MongoWriteException) + { + } + } + public IQueryable GetLINQConceptDescription() + { + return getConceptDescriptionCollection().AsQueryable(); + } + public async void UpdateDBConceptDescriptionById(IConceptDescription newConceptDescription, string cdIdentifier) + { + await getConceptDescriptionCollection().ReplaceOneAsync(r => r.Id.Equals(cdIdentifier), (ConceptDescription)newConceptDescription); + } + public async void DeleteDBConceptDescriptionById(string conceptDescription) + { + await getConceptDescriptionCollection().DeleteOneAsync(a => a.Id.Equals(conceptDescription)); + } + #endregion public void importAASCoreEnvironment(IEnvironment environment) @@ -152,7 +172,7 @@ public void importAASCoreEnvironment(IEnvironment environment) environment.ConceptDescriptions.ForEach(conceptDescription => { - writeDBConceptDescription(conceptDescription); + WriteDBConceptDescription(conceptDescription); }); } } diff --git a/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs b/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs index 578c68000..56e35e9ed 100644 --- a/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs +++ b/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs @@ -28,30 +28,9 @@ public AdminShellPackageEnvironmentServiceDB(IAppLogger GetAllAssetAdministrationShells() { - return _database.getLINQAssetAdministrationShell().Cast().ToList(); + return _database.GetLINQAssetAdministrationShell().Cast().ToList(); } - public IAssetAdministrationShell GetAssetAdministrationShellById(string aasIdentifier, out int packageIndex) { packageIndex = -1; //TODO unused -> remove in the future - var output = _database.getLINQAssetAdministrationShell() + var output = _database.GetLINQAssetAdministrationShell() .Where(r => r.Id.Equals(aasIdentifier)) .ToList(); @@ -99,43 +75,12 @@ public IAssetAdministrationShell GetAssetAdministrationShellById(string aasIdent throw new NotFoundException($"Asset Administration Shell with id {aasIdentifier} not found."); } } - public bool IsAssetAdministrationShellPresent(string aasIdentifier) { - return _database.getLINQAssetAdministrationShell() + return _database.GetLINQAssetAdministrationShell() .Where(r => r.Id.Equals(aasIdentifier)) .ToList().Any(); } - - private bool IsAssetAdministrationShellPresent(string aasIdentifier, out IAssetAdministrationShell output, out int packageIndex) - { - output = null; packageIndex = -1; - //TODO unused -> remove in the future - throw new NotImplementedException(); - - Program.loadPackageForAas(aasIdentifier, out output, out packageIndex); - - foreach (var package in _packages) - { - if (package != null) - { - var env = package.AasEnv; - if (env != null) - { - var aas = env.AssetAdministrationShells.Where(a => a.Id.Equals(aasIdentifier)); - if (aas.Any()) - { - output = aas.First(); - packageIndex = Array.IndexOf(_packages, package); - return true; - } - } - } - } - - return false; - } - public void UpdateAssetAdministrationShellById(IAssetAdministrationShell body, string aasIdentifier) { //TODO Test -> should work -> function unused @@ -148,6 +93,14 @@ public void UpdateAssetAdministrationShellById(IAssetAdministrationShell body, s Program.signalNewData(1); //0 not working, hence 1 = same tree, structure may change _logger.LogDebug($"Successfully updated the AAS with requested AAS"); } + public void ReplaceAssetAdministrationShellById(string aasIdentifier, IAssetAdministrationShell newAas) + { + var timeStamp = DateTime.UtcNow; + newAas.TimeStampCreate = timeStamp; + newAas.SetTimeStamp(timeStamp); + _database.UpdateDBAssetAdministrationShellById(newAas, aasIdentifier); + Program.signalNewData(1); + } public void DeleteAssetInformationThumbnail(int packageIndex, IResource defaultThumbnail) { @@ -156,14 +109,12 @@ public void DeleteAssetInformationThumbnail(int packageIndex, IResource defaultT //_packages[packageIndex].DeleteAssetInformationThumbnail(defaultThumbnail); Program.signalNewData(0); } - public Stream GetAssetInformationThumbnail(int packageIndex) { //TODO throw new NotImplementedException(); return _packages[packageIndex].GetLocalThumbnailStream(); } - public void UpdateAssetInformationThumbnail(IResource defaultThumbnail, Stream fileContent, int packageIndex) { //TODO @@ -211,7 +162,7 @@ public ISubmodel CreateSubmodel(ISubmodel newSubmodel, string aasIdentifier = nu public List GetAllSubmodels(IReference reqSemanticId = null, string idShort = null) { //Get All Submodels - List output = _database.getLINQSubmodel().ToList().Cast().ToList(); + List output = _database.GetLINQSubmodel().ToList().Cast().ToList(); // TODO (jtikekar, 2023-09-04): uncomment and support //if (SecurityCheckTestOnly(s.IdShort, "", s)) @@ -251,7 +202,7 @@ public List GetAllSubmodels(IReference reqSemanticId = null, string i public ISubmodel GetSubmodelById(string submodelIdentifier, out int packageIndex) { packageIndex = -1; //TODO unused -> remove in the future - List output = _database.getLINQSubmodel() + List output = _database.GetLINQSubmodel() .Where(r => r.Id.Equals(submodelIdentifier)) .ToList(); @@ -267,7 +218,7 @@ public ISubmodel GetSubmodelById(string submodelIdentifier, out int packageIndex } public bool IsSubmodelPresent(string submodelIdentifier) { - return _database.getLINQSubmodel() + return _database.GetLINQSubmodel() .Where(r => r.Id.Equals(submodelIdentifier)) .ToList().Any(); } @@ -282,7 +233,7 @@ public void ReplaceSubmodelById(string submodelIdentifier, ISubmodel newSubmodel public void DeleteSubmodelById(string submodelIdentifier) { // Get all Submodels that Reference the given submodelIdentifier - List aasToModify = _database.getLINQAssetAdministrationShell() + List aasToModify = _database.GetLINQAssetAdministrationShell() .Where(aas => aas.Submodels .Any(s => s.Keys .Any(k => k.Value.Equals(submodelIdentifier)))) @@ -297,6 +248,7 @@ public void DeleteSubmodelById(string submodelIdentifier) _logger.LogDebug($"Deleted submodel with id {submodelIdentifier}."); AasxServer.Program.signalNewData(1); } + public void DeleteSupplementaryFileInPackage(string submodelIdentifier, string filePath) { //TODO @@ -307,158 +259,84 @@ public void DeleteSupplementaryFileInPackage(string submodelIdentifier, string f _packages[packageIndex].DeleteSupplementaryFile(filePath); } } - #endregion - - - #region ConceptDescription - - public void DeleteConceptDescriptionById(string cdIdentifier) - { - var conceptDescription = GetConceptDescriptionById(cdIdentifier, out int packageIndex); - - if ((conceptDescription != null) && (packageIndex != -1)) - { - _packages[packageIndex].AasEnv.ConceptDescriptions.Remove(conceptDescription); - _logger.LogDebug($"Delete ConceptDescription with id {cdIdentifier}"); - AasxServer.Program.signalNewData(1); - } - } - - public IConceptDescription GetConceptDescriptionById(string cdIdentifier, out int packageIndex) + public Stream GetFileFromPackage(string submodelIdentifier, string fileName) { - var found = IsConceptDescriptionPresent(cdIdentifier, out IConceptDescription output, out packageIndex); - if (found) + //TODO + throw new NotImplementedException(); + if (!string.IsNullOrEmpty(fileName)) { - _logger.LogDebug($"Found the conceptDescription with id {cdIdentifier}"); - return output; + var _ = GetSubmodelById(submodelIdentifier, out int packageIndex); + return _packages[packageIndex].GetLocalStreamFromPackage(fileName); } else { - throw new NotFoundException($"ConceptDescription with id {cdIdentifier} NOT found."); + _logger.LogError($"File name is empty."); + throw new UnprocessableEntityException($"File name is empty."); } } - - private bool IsConceptDescriptionPresent(string cdIdentifier, out IConceptDescription output, out int packageIndex) + public Task ReplaceSupplementaryFileInPackage(string submodelIdentifier, string sourceFile, string targetFile, string contentType, MemoryStream fileContent) { - output = null; - packageIndex = -1; - foreach (var package in _packages) - { - if (package != null) - { - var env = package.AasEnv; - if (env != null) - { - var conceptDescriptions = env.ConceptDescriptions.Where(c => c.Id.Equals(cdIdentifier)); - if (conceptDescriptions.Any()) - { - output = conceptDescriptions.First(); - packageIndex = Array.IndexOf(_packages, package); - return true; - } - } - } - } - - return false; + //TODO + throw new NotImplementedException(); + var submodel = GetSubmodelById(submodelIdentifier, out int packageIndex); + return _packages[packageIndex].ReplaceSupplementaryFileInPackageAsync(sourceFile, targetFile, contentType, fileContent); } + #endregion - public List GetAllConceptDescriptions() - { - var output = new List(); - - //Get All Concept descriptions - foreach (var package in _packages) - { - if (package != null) - { - var env = package.AasEnv; - if (env != null) - { - output.AddRange(env.ConceptDescriptions); - } - } - } - - return output; - } - public bool IsConceptDescriptionPresent(string cdIdentifier) + #region ConceptDescription + public IConceptDescription CreateConceptDescription(IConceptDescription body) { - return IsConceptDescriptionPresent(cdIdentifier, out _, out _); + var timeStamp = DateTime.UtcNow; + body.TimeStampCreate = timeStamp; + body.SetTimeStamp(timeStamp); + _database.WriteDBConceptDescription(body); + Program.signalNewData(2); + return body; } - - public IConceptDescription CreateConceptDescription(IConceptDescription body) + public IConceptDescription GetConceptDescriptionById(string cdIdentifier, out int packageIndex) { - if (EmptyPackageAvailable(out int emptyPackageIndex)) - { + packageIndex = -1; //TODO unused -> remove in the future + List output = _database.GetLINQConceptDescription() + .Where(c => c.Id.Equals(cdIdentifier)) + .ToList(); - _packages[emptyPackageIndex].AasEnv.ConceptDescriptions.Add(body); - var timeStamp = DateTime.UtcNow; - body.TimeStampCreate = timeStamp; - body.SetTimeStamp(timeStamp); - Program.signalNewData(2); - return _packages[emptyPackageIndex].AasEnv.ConceptDescriptions[0]; //Considering it is the first AAS being added to empty package. + if (output.Any()) + { + _logger.LogDebug($"Found the conceptDescription with id {cdIdentifier}"); + return output.First(); //List will always contain just 1 entry -> Primary Key in DB } else { - throw new Exception("No empty environment package available in the server."); + throw new NotFoundException($"ConceptDescription with id {cdIdentifier} NOT found."); } } - - public void UpdateConceptDescriptionById(IConceptDescription body, string cdIdentifier) + public List GetAllConceptDescriptions() { - var conceptDescription = GetConceptDescriptionById(cdIdentifier, out int packageIndex); - if (conceptDescription != null && packageIndex != -1) - { - var cdIndex = _packages[packageIndex].AasEnv.ConceptDescriptions.IndexOf(conceptDescription); - _packages[packageIndex].AasEnv.ConceptDescriptions.Remove(conceptDescription); - _packages[packageIndex].AasEnv.ConceptDescriptions.Insert(cdIndex, body); - var timeStamp = DateTime.UtcNow; - body.TimeStampCreate = timeStamp; - body.SetTimeStamp(timeStamp); - Program.signalNewData(1); //0 not working, hence 1 = same tree, structure may change - - _logger.LogDebug($"Successfully updated the ConceptDescription."); - } + return _database.GetLINQConceptDescription().ToList().Cast().ToList(); ; } - - public Stream GetFileFromPackage(string submodelIdentifier, string fileName) + public bool IsConceptDescriptionPresent(string cdIdentifier) { - if (!string.IsNullOrEmpty(fileName)) - { - var _ = GetSubmodelById(submodelIdentifier, out int packageIndex); - return _packages[packageIndex].GetLocalStreamFromPackage(fileName); - } - else - { - _logger.LogError($"File name is empty."); - throw new UnprocessableEntityException($"File name is empty."); - } + return _database.GetLINQConceptDescription() + .Where(c => c.Id.Equals(cdIdentifier)) + .ToList().Any(); } - - public void ReplaceAssetAdministrationShellById(string aasIdentifier, IAssetAdministrationShell newAas) + public void UpdateConceptDescriptionById(IConceptDescription body, string cdIdentifier) { - var aas = GetAssetAdministrationShellById(aasIdentifier, out int packageIndex); - if (aas != null && packageIndex != -1) - { - var existingIndex = _packages[packageIndex].AasEnv.AssetAdministrationShells.IndexOf(aas); - _packages[packageIndex].AasEnv.AssetAdministrationShells.Remove(aas); - _packages[packageIndex].AasEnv.AssetAdministrationShells.Insert(existingIndex, newAas); - var timeStamp = DateTime.UtcNow; - newAas.TimeStampCreate = timeStamp; - newAas.SetTimeStamp(timeStamp); - Program.signalNewData(1); - } - } - + var timeStamp = DateTime.UtcNow; + body.TimeStampCreate = timeStamp; + body.SetTimeStamp(timeStamp); - public Task ReplaceSupplementaryFileInPackage(string submodelIdentifier, string sourceFile, string targetFile, string contentType, MemoryStream fileContent) + _database.UpdateDBConceptDescriptionById(body, cdIdentifier); + Program.signalNewData(1); //0 not working, hence 1 = same tree, structure may change + _logger.LogDebug($"Successfully updated the ConceptDescription."); + } + public void DeleteConceptDescriptionById(string cdIdentifier) { - var submodel = GetSubmodelById(submodelIdentifier, out int packageIndex); - return _packages[packageIndex].ReplaceSupplementaryFileInPackageAsync(sourceFile, targetFile, contentType, fileContent); + _database.DeleteDBConceptDescriptionById(cdIdentifier); + _logger.LogDebug($"Delete ConceptDescription with id {cdIdentifier}"); + AasxServer.Program.signalNewData(1); } - #endregion } } From 2aaacb5bdfd75d8e96e5b45c5a55cc7b6a19a878 Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Fri, 1 Mar 2024 10:20:30 +0100 Subject: [PATCH 08/17] Add Startup Argument for Mongo --- src/AasxServerBlazor/Program.cs | 4 +++- .../Properties/launchSettings.json | 2 +- src/AasxServerBlazor/Startup.cs | 9 ++++++++- src/AasxServerStandardBib/Program.cs | 17 ++++++++++++++--- .../AdminShellPackageEnvironmentServiceDB.cs | 2 +- 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/AasxServerBlazor/Program.cs b/src/AasxServerBlazor/Program.cs index 3d9e09aa2..2bd194769 100644 --- a/src/AasxServerBlazor/Program.cs +++ b/src/AasxServerBlazor/Program.cs @@ -5,13 +5,14 @@ using Microsoft.Extensions.Hosting; using System; using System.IO; +using System.Linq; using System.Threading; namespace AasxServerBlazor { public class Program1 { - + public static bool withMongodb = false; public static void Main(string[] args) { Console.WriteLine(Directory.GetCurrentDirectory()); @@ -25,6 +26,7 @@ public static void Main(string[] args) if (url[2] != null) AasxServer.Program.blazorPort = url[2]; + withMongodb = args.Contains("--with-mongodb"); var host = CreateHostBuilder(args).Build(); host.RunAsync(); diff --git a/src/AasxServerBlazor/Properties/launchSettings.json b/src/AasxServerBlazor/Properties/launchSettings.json index e345b36a6..09e32bcc4 100644 --- a/src/AasxServerBlazor/Properties/launchSettings.json +++ b/src/AasxServerBlazor/Properties/launchSettings.json @@ -10,7 +10,7 @@ }, "AasxServerBlazor": { "commandName": "Project", - "commandLineArgs": "--no-security --aasx-in-memory 1000 --data-path \"C:\\GitClones\\aasx-server\\content-for-demo\\aasxs\" --edit --external-blazor http://localhost:5001", + "commandLineArgs": "--no-security --aasx-in-memory 1000 --data-path \"C:\\GitClones\\aasx-server\\content-for-demo\\aasxs\" --edit --external-blazor http://localhost:5001 --with-mongodb \"mongodb://mongo:mongo@localhost:27017/\"", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", diff --git a/src/AasxServerBlazor/Startup.cs b/src/AasxServerBlazor/Startup.cs index 8ce21f5ea..c7731fb32 100644 --- a/src/AasxServerBlazor/Startup.cs +++ b/src/AasxServerBlazor/Startup.cs @@ -96,7 +96,14 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); services.AddTransient(); - services.AddTransient(); + if (Program1.withMongodb) + { + services.AddTransient(); + } + else + { + services.AddTransient(); + } services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/src/AasxServerStandardBib/Program.cs b/src/AasxServerStandardBib/Program.cs index 9ccdfc134..38e66eeb1 100644 --- a/src/AasxServerStandardBib/Program.cs +++ b/src/AasxServerStandardBib/Program.cs @@ -690,6 +690,7 @@ public static bool loadPackageForSubmodel(string submodelIdentifier, out ISubmod public static int startIndex = 0; public static bool withPolicy = false; + public static string withMongoDB { get; set; } private class CommandLineArguments { // ReSharper disable UnusedAutoPropertyAccessor.Local @@ -719,6 +720,7 @@ private class CommandLineArguments public bool WithDb { get; set; } public bool NoDbFiles { get; set; } public int StartIndex { get; set; } + public string WithMongoDB { get; set; } #pragma warning restore 8618 // ReSharper enable UnusedAutoPropertyAccessor.Local } @@ -862,6 +864,7 @@ private static async Task Run(CommandLineArguments a) { Console.WriteLine("Recommend an OPC client update rate > 200 ms."); } + Program.withMongoDB = a.WithMongoDB; // allocate memory env = new AdminShellPackageEnv[envimax]; @@ -1017,8 +1020,12 @@ private static async Task Run(CommandLineArguments a) int count = 0; //Mongo Database - database = new MongoDatabase(); - database.Initialize("mongodb://mongo:mongo@localhost:27017/"); + if (!withMongoDB.IsNullOrEmpty()) + { + database = new MongoDatabase(); + //database.Initialize("mongodb://mongo:mongo@localhost:27017/"); + database.Initialize(withMongoDB); + } // Migrate always if (withDb) @@ -1700,7 +1707,11 @@ public static void Main(string[] args) new Option( new[] {"--start-index"}, - "If set, start index in list of AASX files") + "If set, start index in list of AASX files"), + + new Option( + new[] {"--with-mongodb"}, + "If set, will use MongoDB Data save") }; if (args.Length == 0) diff --git a/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs b/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs index 56e35e9ed..3c0b40964 100644 --- a/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs +++ b/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs @@ -56,7 +56,7 @@ public void DeleteAssetAdministrationShell(int packageIndex, IAssetAdministratio } public List GetAllAssetAdministrationShells() { - return _database.GetLINQAssetAdministrationShell().Cast().ToList(); + return _database.GetLINQAssetAdministrationShell().ToList().Cast().ToList(); } public IAssetAdministrationShell GetAssetAdministrationShellById(string aasIdentifier, out int packageIndex) { From e98035d251bd5fbf3025938827edc0d7d7ad61b9 Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Thu, 14 Mar 2024 13:23:34 +0100 Subject: [PATCH 09/17] Rename Mongo Docker Compose --- content-for-demo/.gitignore | 1 + .../{docker-compose.yaml => docker-compose-mongodb.yaml} | 0 2 files changed, 1 insertion(+) create mode 100644 content-for-demo/.gitignore rename content-for-demo/{docker-compose.yaml => docker-compose-mongodb.yaml} (100%) diff --git a/content-for-demo/.gitignore b/content-for-demo/.gitignore new file mode 100644 index 000000000..616a8a1e7 --- /dev/null +++ b/content-for-demo/.gitignore @@ -0,0 +1 @@ +/mongo \ No newline at end of file diff --git a/content-for-demo/docker-compose.yaml b/content-for-demo/docker-compose-mongodb.yaml similarity index 100% rename from content-for-demo/docker-compose.yaml rename to content-for-demo/docker-compose-mongodb.yaml From f379dd181417caeb43c5e1b785449c7676324fd4 Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:06:58 +0100 Subject: [PATCH 10/17] Add MongoDB LFS -> Files can be loaded into MongoDB -> Server can be stateless --- .../AasxServerStandardBib.csproj | 3 +- src/AasxServerStandardBib/Database.cs | 69 ++++++++++++++++++- src/AasxServerStandardBib/Program.cs | 3 +- 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/src/AasxServerStandardBib/AasxServerStandardBib.csproj b/src/AasxServerStandardBib/AasxServerStandardBib.csproj index c4738e816..7830a9197 100644 --- a/src/AasxServerStandardBib/AasxServerStandardBib.csproj +++ b/src/AasxServerStandardBib/AasxServerStandardBib.csproj @@ -32,7 +32,8 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + + diff --git a/src/AasxServerStandardBib/Database.cs b/src/AasxServerStandardBib/Database.cs index 7733487b9..2e2355310 100644 --- a/src/AasxServerStandardBib/Database.cs +++ b/src/AasxServerStandardBib/Database.cs @@ -11,6 +11,10 @@ using MongoDB.Driver.Linq; using System.Collections; using AasCore.Aas3_0; +using AdminShellNS; +using MongoDB.Driver.GridFS; +using static AasxServerStandardBib.TimeSeriesPlotting.PlotArguments; +using System.IO; //Author: Jonas Graubner @@ -42,7 +46,13 @@ public interface IDatabase public void DeleteDBConceptDescriptionById(string conceptDescription); #endregion + #region Filestream + public void WriteFile(Stream stream, string filename); + public Stream ReadFile(string filename); + #endregion + public void importAASCoreEnvironment(IEnvironment environment); + public void importAdminShellPackageEnv(AdminShellPackageEnv adminShellPackageEnv); } @@ -50,6 +60,7 @@ public class MongoDatabase : IDatabase { private MongoClient _client; private IMongoDatabase _database; + private GridFSBucket _bucket; public void Initialize(String connectionString) { @@ -68,6 +79,10 @@ public void Initialize(String connectionString) _database = _client.GetDatabase("AAS"); var objectSerializer = new ObjectSerializer(type => ObjectSerializer.DefaultAllowedTypes(type) || type.FullName.StartsWith("AasCore") || type.FullName.StartsWith("MongoDB")); BsonSerializer.RegisterSerializer(objectSerializer); + _bucket = new GridFSBucket(_database, new GridFSBucketOptions + { + BucketName = "aasxFiles", + }); } private IMongoCollection getAasCollection() { @@ -158,6 +173,40 @@ public async void DeleteDBConceptDescriptionById(string conceptDescription) } #endregion + #region Filestream + public async void WriteFile(Stream stream, string filename) + { + if (stream != null) + { + Console.WriteLine("New File"); + var id = await _bucket.UploadFromStreamAsync(filename, stream); + stream.Close(); + }else + { + //throw new ArgumentNullException(nameof(stream)); + } + } + public Stream ReadFile(string filename) + { + var filter = Builders.Filter.Eq(x => x.Filename, filename); + var sort = Builders.Sort.Descending(x => x.UploadDateTime); + var options = new GridFSFindOptions + { + Limit = 1, + Sort = sort + }; + + using (var cursor = _bucket.Find(filter, options)) + { + var fileInfo = cursor.ToList().FirstOrDefault(); + // fileInfo either has the matching file information or is null + return _bucket.OpenDownloadStream(fileInfo.Id); + } + } + + + #endregion + public void importAASCoreEnvironment(IEnvironment environment) { @@ -174,6 +223,24 @@ public void importAASCoreEnvironment(IEnvironment environment) { WriteDBConceptDescription(conceptDescription); }); - } + } + + public void importAdminShellPackageEnv(AdminShellPackageEnv adminShellPackageEnv) + { + importAASCoreEnvironment(adminShellPackageEnv.AasEnv); + + //now import Files + var files = adminShellPackageEnv.GetListOfSupplementaryFiles(); + var assetid = adminShellPackageEnv.AasEnv.AssetAdministrationShells[0].AssetInformation.GlobalAssetId; //unique identifier + foreach ( var file in files ) + { + if (file.Location == AdminShellNS.AdminShellPackageSupplementaryFile.LocationType.InPackage) + { + WriteFile(adminShellPackageEnv.GetLocalStreamFromPackage(file.Uri.ToString()), assetid+file.Uri.ToString()); + //ReadFile(assetid + file.Uri.ToString()); + } + } + + } } } diff --git a/src/AasxServerStandardBib/Program.cs b/src/AasxServerStandardBib/Program.cs index 38e66eeb1..df8e850d4 100644 --- a/src/AasxServerStandardBib/Program.cs +++ b/src/AasxServerStandardBib/Program.cs @@ -1127,7 +1127,8 @@ private static async Task Run(CommandLineArguments a) fn = fileNames[fi]; //Insert into DB - database.importAASCoreEnvironment(new AdminShellPackageEnv(fn, true, false).AasEnv); + //database.importAASCoreEnvironment(new AdminShellPackageEnv(fn, true, false).AasEnv); + database.importAdminShellPackageEnv(new AdminShellPackageEnv(fn, true, false)); if (fn.ToLower().Contains("globalsecurity")) { From 433abaa9d5faa798eaf9b6a4cb8ad01c0bd2badb Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Fri, 15 Mar 2024 14:34:37 +0100 Subject: [PATCH 11/17] Add Database LFS to AdminShellPackageEnvironmentServiceDB --- src/AasxServerStandardBib/Database.cs | 14 ++++- .../AdminShellPackageEnvironmentServiceDB.cs | 55 ++++++++++++------- 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/src/AasxServerStandardBib/Database.cs b/src/AasxServerStandardBib/Database.cs index 2e2355310..f69826b9e 100644 --- a/src/AasxServerStandardBib/Database.cs +++ b/src/AasxServerStandardBib/Database.cs @@ -49,6 +49,7 @@ public interface IDatabase #region Filestream public void WriteFile(Stream stream, string filename); public Stream ReadFile(string filename); + public void DeleteFile(string filename); #endregion public void importAASCoreEnvironment(IEnvironment environment); @@ -187,6 +188,17 @@ public async void WriteFile(Stream stream, string filename) } } public Stream ReadFile(string filename) + { + return _bucket.OpenDownloadStream(getFileIdFromFilename(filename)); + } + + public async void DeleteFile(string filename) + { + ObjectId fileId = getFileIdFromFilename(filename); + await _bucket.DeleteAsync(fileId); + } + + private ObjectId getFileIdFromFilename(string filename) { var filter = Builders.Filter.Eq(x => x.Filename, filename); var sort = Builders.Sort.Descending(x => x.UploadDateTime); @@ -200,7 +212,7 @@ public Stream ReadFile(string filename) { var fileInfo = cursor.ToList().FirstOrDefault(); // fileInfo either has the matching file information or is null - return _bucket.OpenDownloadStream(fileInfo.Id); + return fileInfo.Id; } } diff --git a/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs b/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs index 3c0b40964..c22ae00b1 100644 --- a/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs +++ b/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs @@ -9,6 +9,7 @@ using AdminShellNS; using Extensions; using Microsoft.IdentityModel.Tokens; +using SharpCompress.Common; using System; using System.Collections.Generic; using System.IO; @@ -22,7 +23,6 @@ public class AdminShellPackageEnvironmentServiceDB : IAdminShellPackageEnvironme private readonly IAppLogger _logger; private readonly Lazy _aasService; private IDatabase _database; - private AdminShellPackageEnv[] _packages; public AdminShellPackageEnvironmentServiceDB(IAppLogger logger, Lazy aasService) { @@ -31,6 +31,17 @@ public AdminShellPackageEnvironmentServiceDB(IAppLogger GetAssetAdministrationShellsBySubmodelIdentifier(string submodelIdentifier) { + // Get all AssetAdministrationShells that Reference the given submodelIdentifier + return _database.GetLINQAssetAdministrationShell() + .Where(aas => aas.Submodels + .Any(s => s.Keys + .Any(k => k.Value.Equals(submodelIdentifier)))) + .ToList(); + } + #endregion + #region AssetAdministrationShell public IAssetAdministrationShell CreateAssetAdministrationShell(IAssetAdministrationShell body) { @@ -111,16 +122,18 @@ public void DeleteAssetInformationThumbnail(int packageIndex, IResource defaultT } public Stream GetAssetInformationThumbnail(int packageIndex) { - //TODO + //TODO find a solution to get the right Thumbnail throw new NotImplementedException(); - return _packages[packageIndex].GetLocalThumbnailStream(); + //return _packages[packageIndex].GetLocalThumbnailStream(); } public void UpdateAssetInformationThumbnail(IResource defaultThumbnail, Stream fileContent, int packageIndex) { - //TODO + //TODO find a solution to get the right Thumbnail throw new NotImplementedException(); + /* _packages[packageIndex].EmbeddAssetInformationThumbnail(defaultThumbnail, fileContent); Program.signalNewData(0); + */ } #endregion @@ -232,16 +245,12 @@ public void ReplaceSubmodelById(string submodelIdentifier, ISubmodel newSubmodel } public void DeleteSubmodelById(string submodelIdentifier) { - // Get all Submodels that Reference the given submodelIdentifier - List aasToModify = _database.GetLINQAssetAdministrationShell() - .Where(aas => aas.Submodels - .Any(s => s.Keys - .Any(k => k.Value.Equals(submodelIdentifier)))) - .ToList(); + List aasToModify = GetAssetAdministrationShellsBySubmodelIdentifier(submodelIdentifier); foreach (var aas in aasToModify) { - _aasService.Value.DeleteSubmodelReferenceById(aas.Id, submodelIdentifier); + _aasService.Value.DeleteSubmodelReferenceById(aas.Id, submodelIdentifier); //Just in Memory Modification + UpdateAssetAdministrationShellById(aas, aas.Id); //Update the Asset in the DB //TODO Jonas Graubner make sure, that reference is deleted in DB } _database.DeleteDBSubmodelById(submodelIdentifier); @@ -251,22 +260,28 @@ public void DeleteSubmodelById(string submodelIdentifier) public void DeleteSupplementaryFileInPackage(string submodelIdentifier, string filePath) { - //TODO - throw new NotImplementedException(); - _ = GetSubmodelById(submodelIdentifier, out int packageIndex); - if (packageIndex != -1) + //TODO tests & maybe optimization + // Get all AssetAdministrationShells that Reference the given submodelIdentifier + List aasWithSubmodel = GetAssetAdministrationShellsBySubmodelIdentifier(submodelIdentifier); + + foreach (var aas in aasWithSubmodel) { - _packages[packageIndex].DeleteSupplementaryFile(filePath); + string GlobalAssetId = aas.AssetInformation.GlobalAssetId; + string filename = GlobalAssetId + filePath; + _database.DeleteFile(filename); } } public Stream GetFileFromPackage(string submodelIdentifier, string fileName) { //TODO - throw new NotImplementedException(); if (!string.IsNullOrEmpty(fileName)) { - var _ = GetSubmodelById(submodelIdentifier, out int packageIndex); - return _packages[packageIndex].GetLocalStreamFromPackage(fileName); + List aasWithSubmodel = GetAssetAdministrationShellsBySubmodelIdentifier(submodelIdentifier); + + + string GlobalAssetId = aasWithSubmodel.First().AssetInformation.GlobalAssetId; + string filename = GlobalAssetId + fileName; + return _database.ReadFile(filename); } else { @@ -278,8 +293,10 @@ public Task ReplaceSupplementaryFileInPackage(string submodelIdentifier, string { //TODO throw new NotImplementedException(); + /* var submodel = GetSubmodelById(submodelIdentifier, out int packageIndex); return _packages[packageIndex].ReplaceSupplementaryFileInPackageAsync(sourceFile, targetFile, contentType, fileContent); + */ } #endregion From 4517e317baf33c88002540c59c232b970312c499 Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Fri, 15 Mar 2024 15:30:43 +0100 Subject: [PATCH 12/17] remove FileServerInterfaceDB --- .../AasxFileServerInterfaceServiceDB.cs | 296 ------------------ 1 file changed, 296 deletions(-) delete mode 100644 src/AasxServerStandardBib/Services-DB/AasxFileServerInterfaceServiceDB.cs diff --git a/src/AasxServerStandardBib/Services-DB/AasxFileServerInterfaceServiceDB.cs b/src/AasxServerStandardBib/Services-DB/AasxFileServerInterfaceServiceDB.cs deleted file mode 100644 index 77aae641c..000000000 --- a/src/AasxServerStandardBib/Services-DB/AasxFileServerInterfaceServiceDB.cs +++ /dev/null @@ -1,296 +0,0 @@ -using AasxRestServerLibrary; -using AasxServer; -using AasxServerStandardBib.Exceptions; -using AasxServerStandardBib.Interfaces; -using AasxServerStandardBib.Logging; -using AdminShellNS; -using AdminShellNS.Models; -using Extensions; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace AasxServerStandardBib.Services -{ - public class AasxFileServerInterfaceServiceDB : IAasxFileServerInterfaceService - { - private readonly IAppLogger _logger; - private AdminShellPackageEnv[] _packages; - private string[] _envFileNames; - - public AasxFileServerInterfaceServiceDB(IAppLogger logger) - { - _logger = logger; - _packages = Program.env; - _envFileNames = Program.envFileName; - } - - public void DeleteAASXByPackageId(string packageId) - { - int packageIndex = int.Parse(packageId); - var requestedPackage = _packages[packageIndex]; - if (requestedPackage != null) - { - //Move the file to archive - var archivePath = Path.Combine(AasxHttpContextHelper.DataPath, "AasxFileArchive"); - if (!Directory.Exists(archivePath)) - { - Directory.CreateDirectory(archivePath); - } - var fileName = Path.Combine(archivePath, Path.GetFileName(_envFileNames[packageIndex])); - if (System.IO.File.Exists(fileName)) - { - System.IO.File.Delete(fileName); - } - System.IO.File.Move(_envFileNames[packageIndex], fileName); - - _packages[packageIndex] = null; - _envFileNames[packageIndex] = null; - Program.signalNewData(2); - } - else - { - throw new NotFoundException($"Package with packageId {packageId} not found."); - } - } - - public string GetAASXByPackageId(string packageId, out byte[] content, out long fileSize, out IAssetAdministrationShell aas) - { - aas = null; - content = null; - fileSize = 0; - int packageIndex = int.Parse(packageId); - var requestedPackage = _packages[packageIndex]; - var requestedFileName = _envFileNames[packageIndex]; - if (!string.IsNullOrEmpty(requestedFileName) && requestedPackage != null) - { - //Create Temp file - string copyFileName = Path.GetTempFileName().Replace(".tmp", ".aasx"); - System.IO.File.Copy(requestedFileName, copyFileName, true); - Program.env[packageIndex].SaveAs(copyFileName); - - content = System.IO.File.ReadAllBytes(copyFileName); - string fileName = Path.GetFileName(requestedFileName); - fileSize = content.Length; - _packages[packageIndex].SetFilename(requestedFileName); - - //Set aas - aas = requestedPackage.AasEnv.AssetAdministrationShells[0]; - - //Delete Temp file - System.IO.File.Delete(copyFileName); - return fileName; - } - else if (requestedPackage != null && string.IsNullOrEmpty(requestedFileName)) - { - //File does not exist, may be AAS is added by REST-API - //Check if AAS exists - if (requestedPackage.AasEnv.AssetAdministrationShells.Count != 0) - { - string newFileName = Path.Combine(AasxHttpContextHelper.DataPath, requestedPackage.AasEnv.AssetAdministrationShells[0].IdShort + ".aasx"); - using (new FileStream(newFileName, FileMode.CreateNew)) { } - Program.env[packageIndex].SetTempFn(newFileName); - - //Create Temp file - string copyFileName = Path.GetTempFileName().Replace(".tmp", ".aasx"); - System.IO.File.Copy(newFileName, copyFileName, true); - Program.env[packageIndex].SaveAs(copyFileName); - - content = System.IO.File.ReadAllBytes(copyFileName); - string fileName = Path.GetFileName(newFileName); - fileSize = content.Length; - - System.IO.File.Copy(copyFileName, newFileName, true); - Program.envFileName[packageIndex] = newFileName; - _packages[packageIndex].SetFilename(newFileName); - - //Set aas - aas = requestedPackage.AasEnv.AssetAdministrationShells[0]; - - //Delete Temp file - System.IO.File.Delete(copyFileName); - return fileName; - } - } - - return null; - } - - public List GetAllAASXPackageIds(string aasId = null) - { - var output = new List(); - - for (int i = 0; i < _packages.Length; i++) - { - var package = _packages[i]; - if (package != null) - { - var packageDescription = new PackageDescription(); - packageDescription.PackageId = i.ToString(); - var aasIdList = new List(); - foreach (var aas in _packages[i].AasEnv.AssetAdministrationShells) - { - aasIdList.Add(aas.Id); - } - packageDescription.AasIds = aasIdList; - output.Add(packageDescription); - } - - } - - //Filter w..r.t aasId - if (output.Any()) - { - if (!string.IsNullOrEmpty(aasId)) - { - output = output.Where(x => x.AasIds.Contains(aasId)).ToList(); - } - } - - return output; - } - - public IAssetAdministrationShell GetAssetAdministrationShellByPackageId(string packageId) - { - int packageIndex = int.Parse(packageId); - var requestedPackage = _packages[packageIndex]; - if (requestedPackage != null && requestedPackage.AasEnv != null) - { - if (requestedPackage.AasEnv.AssetAdministrationShells != null) - { - return requestedPackage.AasEnv.AssetAdministrationShells.First(); - } - } - - return null; - } - - public string PostAASXPackage(byte[] fileContent, string fileName) - { - var newFileName = Path.Combine(AasxHttpContextHelper.DataPath, fileName); - //Check if file already exists - if (System.IO.File.Exists(newFileName)) - { - throw new Exception($"File already exists"); - } - - //TODO:Check file extentsion ".aasx" - //Write the received file content to this temp file - //var content = Convert.FromBase64String(body); - System.IO.File.WriteAllBytes(newFileName, fileContent); - // open again - var newAasx = new AdminShellPackageEnv(newFileName, true); - if (newAasx != null) - { - if (EmptyPackageAvailable(out int emptyPackageIndex)) - { - _packages[emptyPackageIndex] = newAasx; - _envFileNames[emptyPackageIndex] = newFileName; - var timeStamp = DateTime.UtcNow; - newAasx.AasEnv.AssetAdministrationShells[0].TimeStampCreate = timeStamp; - newAasx.AasEnv.AssetAdministrationShells[0].SetTimeStamp(timeStamp); - foreach (var submodel in newAasx.AasEnv.Submodels) - { - //submodel.SetAllParents(); - submodel.TimeStampCreate = timeStamp; - submodel.SetParentAndTimestamp(timeStamp); - } - Program.signalNewData(2); - return emptyPackageIndex.ToString(); - } - else - { - throw new Exception($"Could not create the file as the datastructure is completely filled."); - } - } - else - { - throw new Exception($"Cannot load new package {fileName}."); - } - } - - public void UpdateAASXPackageById(string packageId, byte[] fileContent, string fileName) - { - int packageIndex = int.Parse(packageId); - var package = _packages[packageIndex]; - if (package != null) - { - var originalFile = _packages[packageIndex].Filename; - - //Create temporary file - var tempNewFile = Path.GetTempFileName().Replace(".tmp", ".aasx"); - //Write the received file content to this temp file - //var content = Convert.FromBase64String(fileContent); - System.IO.File.WriteAllBytes(tempNewFile, fileContent); - - lock (Program.changeAasxFile) - { - try - { - _packages[packageIndex].Close(); - //Create back up of existing file - System.IO.File.Copy(originalFile, originalFile + ".bak", overwrite: true); - } - catch (Exception e) - { - throw new Exception($"Cannot close/ backup old AASX {originalFile}. Aborting. Exception: {e.Message}"); - } - try - { - //Replace existing file with temp file - //originalFile = fileName; - var rootPath = Path.GetDirectoryName(originalFile); - originalFile = Path.Combine(rootPath, fileName); - - //Copy tempFile into originalFile location - System.IO.File.Copy(tempNewFile, originalFile, overwrite: true); - // open again - var newAasx = new AdminShellPackageEnv(originalFile, true); - if (newAasx != null) - { - foreach (var submodel in newAasx.AasEnv.Submodels) - { - submodel.SetAllParents(); - } - _packages[packageIndex] = newAasx; - } - else - { - throw new Exception($"Cannot load new package {originalFile} for replacing via PUT. Aborting."); - } - //now delete tempFile - System.IO.File.Delete(tempNewFile); - } - catch (Exception e) - { - throw new Exception($"Cannot replace AASX {originalFile} with new {tempNewFile}. Aborting. Exception: {e.Message}"); - } - } - - Program.signalNewData(2); - } - else - { - throw new NotFoundException($"Requested package with packageId {packageId} not found."); - } - } - - private bool EmptyPackageAvailable(out int emptyPackageIndex) - { - emptyPackageIndex = -1; - - for (int envi = 0; envi < _packages.Length; envi++) - { - if (_packages[envi] == null) - { - emptyPackageIndex = envi; - _packages[emptyPackageIndex] = new AdminShellPackageEnv(); - return true; - } - } - - return false; - } - } -} From e172a3392c91a3559a4235a5dc947ee2a35b7bed Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Fri, 15 Mar 2024 15:33:37 +0100 Subject: [PATCH 13/17] No need for change in these Services for DB use --- .../ConceptDescriptionServiceDB.cs | 143 ---- .../Services-DB/SubmodelServiceDB.cs | 633 ------------------ 2 files changed, 776 deletions(-) delete mode 100644 src/AasxServerStandardBib/Services-DB/ConceptDescriptionServiceDB.cs delete mode 100644 src/AasxServerStandardBib/Services-DB/SubmodelServiceDB.cs diff --git a/src/AasxServerStandardBib/Services-DB/ConceptDescriptionServiceDB.cs b/src/AasxServerStandardBib/Services-DB/ConceptDescriptionServiceDB.cs deleted file mode 100644 index fb3eb7210..000000000 --- a/src/AasxServerStandardBib/Services-DB/ConceptDescriptionServiceDB.cs +++ /dev/null @@ -1,143 +0,0 @@ - -using AasxServerStandardBib.Exceptions; -using AasxServerStandardBib.Interfaces; -using AasxServerStandardBib.Logging; -using Extensions; -using Microsoft.IdentityModel.Tokens; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace AasxServerStandardBib.Services -{ - public class ConceptDescriptionServiceDB : IConceptDescriptionService - { - private readonly IAppLogger _logger; - private readonly IAdminShellPackageEnvironmentService _packageEnvService; - private readonly IMetamodelVerificationService _verificationService; - - public ConceptDescriptionServiceDB(IAppLogger logger, IAdminShellPackageEnvironmentService packageEnvService, IMetamodelVerificationService verificationService) - { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); ; - _packageEnvService = packageEnvService; - _verificationService = verificationService; - } - - public IConceptDescription CreateConceptDescription(IConceptDescription body) - { - //Verify the body first - //_verificationService.VerifyRequestBody(body); - - var found = _packageEnvService.IsConceptDescriptionPresent(body.Id); - if (found) - { - _logger.LogDebug($"Cannot create requested ConceptDescription !!"); - throw new DuplicateException($"ConceptDescription with id {body.Id} already exists."); - } - - var output = _packageEnvService.CreateConceptDescription(body); - - return output; - } - - public void DeleteConceptDescriptionById(string cdIdentifier) - { - _packageEnvService.DeleteConceptDescriptionById(cdIdentifier); - } - - public List GetAllConceptDescriptions(string idShort, Reference isCaseOf, Reference dataSpecificationRef) - { - //Get All Concept descriptions - var output = _packageEnvService.GetAllConceptDescriptions(); - - if (output.Any()) - { - //Filter AASs based on IdShort - if (!string.IsNullOrEmpty(idShort)) - { - var cdList = output.Where(cd => cd.IdShort.Equals(idShort)).ToList(); - if (cdList.IsNullOrEmpty()) - { - _logger.LogDebug($"No Concept Description with IdShort {idShort} Found."); - } - else - { - output = cdList; - } - } - - //Filter based on IsCaseOf - if (isCaseOf != null) - { - var cdList = new List(); - foreach (var conceptDescription in output) - { - if (!conceptDescription.IsCaseOf.IsNullOrEmpty()) - { - foreach (var reference in conceptDescription.IsCaseOf) - { - if (reference != null && reference.Matches(isCaseOf)) - { - cdList.Add(conceptDescription); - break; - } - } - } - } - if (cdList.IsNullOrEmpty()) - { - _logger.LogDebug($"No Concept Description with requested IsCaseOf found."); - } - else - { - output = cdList; - } - - } - - //Filter based on DataSpecificationRef - if (dataSpecificationRef != null) - { - var cdList = new List(); - foreach (var conceptDescription in output) - { - if (!conceptDescription.EmbeddedDataSpecifications.IsNullOrEmpty()) - { - foreach (var reference in conceptDescription.EmbeddedDataSpecifications) - { - if (reference != null && reference.DataSpecification.Matches(dataSpecificationRef)) - { - cdList.Add(conceptDescription); - break; - } - } - } - } - if (cdList.IsNullOrEmpty()) - { - _logger.LogDebug($"No Concept Description with requested DataSpecificationReference found."); - } - else - { - output = cdList; - } - } - } - - return output; - } - - public IConceptDescription GetConceptDescriptionById(string cdIdentifier) - { - return _packageEnvService.GetConceptDescriptionById(cdIdentifier, out _); - } - - public void UpdateConceptDescriptionById(ConceptDescription body, string cdIdentifier) - { - //Verify the body first - _verificationService.VerifyRequestBody(body); - - _packageEnvService.UpdateConceptDescriptionById(body, cdIdentifier); - } - } -} diff --git a/src/AasxServerStandardBib/Services-DB/SubmodelServiceDB.cs b/src/AasxServerStandardBib/Services-DB/SubmodelServiceDB.cs deleted file mode 100644 index 82b347cb3..000000000 --- a/src/AasxServerStandardBib/Services-DB/SubmodelServiceDB.cs +++ /dev/null @@ -1,633 +0,0 @@ - -using AasxServer; -using AasxServerStandardBib.Exceptions; -using AasxServerStandardBib.Interfaces; -using AasxServerStandardBib.Logging; -using AasxServerStandardBib.Transformers; -using Extensions; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace AasxServerStandardBib.Services -{ - public class SubmodelServiceDB : ISubmodelService - { - private readonly IAppLogger _logger; - private readonly IAdminShellPackageEnvironmentService _packageEnvService; - private readonly IMetamodelVerificationService _verificationService; - - public SubmodelServiceDB(IAppLogger logger, IAdminShellPackageEnvironmentService packageEnvService, IMetamodelVerificationService verificationService) - { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); ; - _packageEnvService = packageEnvService; - _verificationService = verificationService; - } - - #region PrivateMethods - - private bool IsSubmodelElementPresent(string submodelIdentifier, string idShortPath, out ISubmodelElement output, out IReferable smeParent) - { - output = null; - smeParent = null; - var submodel = _packageEnvService.GetSubmodelById(submodelIdentifier, out _); - - if (submodel != null) - { - output = GetSubmodelElementByPath(submodel, idShortPath, out IReferable parent); - smeParent = parent; - if (output != null) - { - _logger.LogInformation($"Found SubmodelElement at {idShortPath} in submodel with Id {submodelIdentifier}"); - return true; - } - - } - - return false; - } - - private ISubmodelElement GetSubmodelElementByPath(IReferable parent, string idShortPath, out IReferable outParent) - { - outParent = parent; - if (idShortPath.Contains('.')) - { - string[] idShorts = idShortPath.Split('.', 2); - if (parent is Submodel submodel) - { - var submodelElement = submodel.FindSubmodelElementByIdShort(idShorts[0]); - if (submodelElement != null) - { - return GetSubmodelElementByPath(submodelElement, idShorts[1], out outParent); - } - } - else if (parent is SubmodelElementCollection collection) - { - var submodelElement = collection.FindFirstIdShortAs(idShorts[0]); - if (submodelElement != null) - { - return GetSubmodelElementByPath(submodelElement, idShorts[1], out outParent); - } - } - else if (parent is SubmodelElementList list) - { - var submodelElement = list.FindFirstIdShortAs(idShorts[0]); - if (submodelElement != null) - { - return GetSubmodelElementByPath(submodelElement, idShorts[1], out outParent); - } - } - else if (parent is Entity entity) - { - var submodelElement = entity.FindFirstIdShortAs(idShortPath); - if (submodelElement != null) - { - return GetSubmodelElementByPath(submodelElement, idShorts[1], out outParent); - } - } - else if (parent is AnnotatedRelationshipElement annotatedRelationshipElement) - { - var submodelElement = annotatedRelationshipElement.FindFirstIdShortAs(idShortPath); - if (submodelElement != null) - { - return GetSubmodelElementByPath(submodelElement, idShorts[1], out outParent); - } - } - else - { - throw new Exception($"Parent of type {parent.GetType()} not supported."); - } - } - else - { - if (parent is Submodel submodel) - { - var submodelElement = submodel.FindSubmodelElementByIdShort(idShortPath); - if (submodelElement != null) - { - return submodelElement; - } - } - else if (parent is SubmodelElementCollection collection) - { - var submodelElement = collection.FindFirstIdShortAs(idShortPath); - if (submodelElement != null) - { - return submodelElement; - } - } - else if (parent is SubmodelElementList list) - { - var submodelElement = list.FindFirstIdShortAs(idShortPath); - if (submodelElement != null) - { - return submodelElement; - } - } - else if (parent is Entity entity) - { - var submodelElement = entity.FindFirstIdShortAs(idShortPath); - if (submodelElement != null) - { - return submodelElement; - } - } - else if (parent is AnnotatedRelationshipElement annotatedRelationshipElement) - { - var submodelElement = annotatedRelationshipElement.FindFirstIdShortAs(idShortPath); - if (submodelElement != null) - { - return submodelElement; - } - } - else - { - throw new Exception($"Parent of type {parent.GetType()} not supported."); - } - } - return null; - } - - - - #endregion - - public bool IsSubmodelElementPresent(string submodelIdentifier, string idShortPath) - { - return IsSubmodelElementPresent(submodelIdentifier, idShortPath, out _, out _); - } - - public void DeleteSubmodelById(string submodelIdentifier) - { - _packageEnvService.DeleteSubmodelById(submodelIdentifier); - } - - public void DeleteSubmodelElementByPath(string submodelIdentifier, string idShortPath) - { - var found = IsSubmodelElementPresent(submodelIdentifier, idShortPath, out ISubmodelElement submodelElement, out IReferable smeParent); - if (found) - { - if (smeParent is SubmodelElementCollection parentCollection) - { - parentCollection.Value.Remove(submodelElement); - } - else if (smeParent is SubmodelElementList parentList) - { - parentList.Value.Remove(submodelElement); - } - else if (smeParent is AnnotatedRelationshipElement annotatedRelationshipElement) - { - annotatedRelationshipElement.Annotations.Remove((IDataElement)submodelElement); - } - else if (smeParent is Entity entity) - { - entity.Statements.Remove(submodelElement); - } - else if (smeParent is Submodel parentSubmodel) - { - parentSubmodel.SubmodelElements.Remove(submodelElement); - } - else - { - _logger.LogDebug($"Could not delete SubmodelElement {submodelElement.IdShort}"); - throw new Exception($"Unsupported data type of parent {smeParent.IdShort} for delete operation."); - } - } - else - { - throw new NotFoundException($"Requested SubmodelElement NOT found in submodel with Id {submodelIdentifier}"); - } - - Program.signalNewData(1); - _logger.LogDebug($"Deleted SubmodelElement at {idShortPath} from submodel with Id {submodelIdentifier}"); - } - - public List GetAllSubmodelElements(string submodelIdentifier) - { - var submodel = _packageEnvService.GetSubmodelById(submodelIdentifier, out _); - return submodel.SubmodelElements; - } - - public void DeleteFileByPath(string submodelIdentifier, string idShortPath) - { - var found = IsSubmodelElementPresent(submodelIdentifier, idShortPath, out ISubmodelElement submodelElement, out _); - if (found) - { - if (submodelElement is AasCore.Aas3_0.File file) - { - if (!string.IsNullOrEmpty(file.Value)) - { - //check if it is external location - if (file.Value.StartsWith("http") || file.Value.StartsWith("https")) - { - _logger.LogWarning($"Value of the Submodel-Element File with IdShort {file.IdShort} is an external link."); - throw new NotImplementedException($"File location for {file.IdShort} is external {file.Value}. Currently this fuctionality is not supported."); - } - //Check if a directory - else if (file.Value.StartsWith('/') || file.Value.StartsWith('\\')) - { - _logger.LogInformation($"Value of the Submodel-Element File with IdShort {file.IdShort} is a File-Path."); - - _packageEnvService.DeleteSupplementaryFileInPackage(submodelIdentifier, file.Value); - - file.Value = string.Empty; - } - // incorrect value - else - { - _logger.LogError($"Incorrect value {file.Value} of the Submodel-Element File with IdShort {file.IdShort}"); - throw new OperationNotSupported($"Incorrect value {file.Value} of the File with IdShort {file.IdShort}."); - } - } - else - { - throw new OperationNotSupported($"Cannot delete the file. SubmodelElement {idShortPath} does not have a file attached."); - } - } - else - { - throw new OperationNotSupported($"SubmodelElement found at {idShortPath} is not of type File"); - } - } - else - { - throw new NotFoundException($"Requested SubmodelElement NOT found in submodel with Id {submodelIdentifier}"); - } - - Program.signalNewData(1); - _logger.LogDebug($"Deleted the file at {idShortPath} from submodel with Id {submodelIdentifier}"); - } - - public string GetFileByPath(string submodelIdentifier, string idShortPath, out byte[] byteArray, out long fileSize) - { - byteArray = null; - string fileName = null; - fileSize = 0; - - var fileElement = GetSubmodelElementByPath(submodelIdentifier, idShortPath); - - if (fileElement != null) - { - - if (fileElement is AasCore.Aas3_0.File file) - { - fileName = file.Value; - - if (string.IsNullOrEmpty(fileName)) - { - _logger.LogError($"File name is empty. Cannot fetch the file."); - throw new UnprocessableEntityException($"File value Null!!"); - } - - //check if it is external location - if (file.Value.StartsWith("http") || file.Value.StartsWith("https")) - { - _logger.LogWarning($"Value of the Submodel-Element File with IdShort {file.IdShort} is an external link."); - throw new NotImplementedException($"File location for {file.IdShort} is external {file.Value}. Currently this fuctionality is not supported."); - } - //Check if a directory - else if (file.Value.StartsWith('/') || file.Value.StartsWith('\\')) - { - _logger.LogInformation($"Value of the Submodel-Element File with IdShort {file.IdShort} is a File-Path."); - Stream stream = _packageEnvService.GetFileFromPackage(submodelIdentifier, fileName); - byteArray = stream.ToByteArray(); - fileSize = byteArray.Length; - } - // incorrect value - else - { - _logger.LogError($"Incorrect value {file.Value} of the Submodel-Element File with IdShort {file.IdShort}"); - throw new UnprocessableEntityException($"Incorrect value {file.Value} of the File with IdShort {file.IdShort}."); - } - - } - else - { - throw new NotFoundException($"Submodel element {fileElement.IdShort} is not of type File."); - } - } - - return fileName; - } - - public ISubmodel GetSubmodelById(string submodelIdentifier) - { - return _packageEnvService.GetSubmodelById(submodelIdentifier, out _); - } - - public ISubmodelElement GetSubmodelElementByPath(string submodelIdentifier, string idShortPath) - { - var found = IsSubmodelElementPresent(submodelIdentifier, idShortPath, out ISubmodelElement output, out _); - if (found) - { - return output; - } - else - { - throw new NotFoundException($"Submodel Element at {idShortPath} not found in the submodel with id {submodelIdentifier}"); - } - } - - public ISubmodelElement CreateSubmodelElement(string submodelIdentifier, ISubmodelElement newSubmodelElement, bool first) - { - //Verify the body first - _verificationService.VerifyRequestBody(newSubmodelElement); - - var smeFound = IsSubmodelElementPresent(submodelIdentifier, newSubmodelElement.IdShort, out _, out IReferable smeParent); - if (smeFound) - { - _logger.LogDebug($"Cannot create requested submodel element !!"); - throw new DuplicateException($"SubmodelElement with idShort {newSubmodelElement.IdShort} already exists in the submodel."); - } - - //Create new SME - var submodel = GetSubmodelById(submodelIdentifier); - - submodel.SubmodelElements ??= new List(); - if (first) - { - submodel.SubmodelElements.Insert(0, newSubmodelElement); - } - else - { - submodel.SubmodelElements.Add(newSubmodelElement); - } - - var timeStamp = DateTime.UtcNow; - newSubmodelElement.SetAllParentsAndTimestamps(submodel, timeStamp, timeStamp); - newSubmodelElement.SetTimeStamp(timeStamp); - - Program.signalNewData(1); - return newSubmodelElement; - } - - public ISubmodelElement CreateSubmodelElementByPath(string submodelIdentifier, string idShortPath, bool first, ISubmodelElement newSubmodelElement) - { - //Verify the body first - _verificationService.VerifyRequestBody(newSubmodelElement); - - var newIdShortPath = idShortPath + "." + newSubmodelElement.IdShort; - var smeFound = IsSubmodelElementPresent(submodelIdentifier, newIdShortPath, out _, out IReferable smeParent); - if (smeFound) - { - _logger.LogDebug($"Cannot create requested submodel element !!"); - throw new DuplicateException($"SubmodelElement with idShort {newSubmodelElement.IdShort} already exists at {idShortPath} in the submodel."); - } - - //Create new SME - _logger.LogDebug("Create the new submodel element."); - if (smeParent != null && smeParent is Submodel submodel) - { - submodel.SubmodelElements ??= new List(); - if (first) - { - submodel.SubmodelElements.Insert(0, newSubmodelElement); - } - else - { - submodel.SubmodelElements.Add(newSubmodelElement); - } - } - else if (smeParent != null && smeParent is SubmodelElementCollection collection) - { - collection.Value ??= new List(); - if (first) - { - collection.Value.Insert(0, newSubmodelElement); - } - else - { - collection.Value.Add(newSubmodelElement); - } - } - else if (smeParent != null && smeParent is SubmodelElementList list) - { - list.Value ??= new List(); - if (first) - { - list.Value.Insert(0, newSubmodelElement); - } - else - { - list.Value.Add(newSubmodelElement); - } - } - else if (smeParent != null && smeParent is Entity entity) - { - entity.Statements ??= new List(); - if (first) - { - entity.Statements.Insert(0, newSubmodelElement); - } - else - { - entity.Statements.Add(newSubmodelElement); - } - } - else if (smeParent != null && smeParent is AnnotatedRelationshipElement annotatedRelationshipElement) - { - annotatedRelationshipElement.Annotations ??= new List(); - if (first) - { - annotatedRelationshipElement.Annotations.Insert(0, (IDataElement)newSubmodelElement); - } - else - { - annotatedRelationshipElement.Annotations.Add((IDataElement)newSubmodelElement); - } - } - else - { - throw new Exception($"The submodel element {idShortPath} does not support child elements."); - } - - var timeStamp = DateTime.UtcNow; - newSubmodelElement.SetAllParentsAndTimestamps(smeParent, timeStamp, timeStamp); - newSubmodelElement.SetTimeStamp(timeStamp); - Program.signalNewData(1); - return newSubmodelElement; - } - - public void ReplaceSubmodelById(string submodelIdentifier, ISubmodel newSubmodel) - { - _verificationService.VerifyRequestBody(newSubmodel); - _packageEnvService.ReplaceSubmodelById(submodelIdentifier, newSubmodel); - } - - public void ReplaceSubmodelElementByPath(string submodelIdentifier, string idShortPath, ISubmodelElement newSme) - { - _verificationService.VerifyRequestBody(newSme); - var submodel = GetSubmodelById(submodelIdentifier); - var existingSme = GetSubmodelElementByPath(submodel, idShortPath, out IReferable smeParent); - - if (existingSme != null && smeParent != null) - { - if (smeParent is Submodel) - { - var existingIndex = submodel.SubmodelElements.IndexOf(existingSme); - submodel.SubmodelElements.Remove(existingSme); - submodel.SubmodelElements.Insert(existingIndex, newSme); - } - else if (smeParent is SubmodelElementCollection collection) - { - var existingIndex = collection.Value.IndexOf(existingSme); - collection.Value.Remove(existingSme); - collection.Value.Insert(existingIndex, newSme); - } - else if (smeParent is SubmodelElementList smeList) - { - var existingIndex = smeList.Value.IndexOf(existingSme); - smeList.Value.Remove(existingSme); - smeList.Value.Insert(existingIndex, newSme); - } - else if (smeParent is Entity entity) - { - var existingIndex = entity.Statements.IndexOf(existingSme); - entity.Statements.Remove(existingSme); - entity.Statements.Insert(existingIndex, newSme); - } - else if (smeParent is AnnotatedRelationshipElement annotatedRelElement) - { - var existingIndex = annotatedRelElement.Annotations.IndexOf((IDataElement)existingSme); - annotatedRelElement.Annotations.Remove((IDataElement)existingSme); - annotatedRelElement.Annotations.Insert(existingIndex, (IDataElement)newSme); - } - else - { - throw new Exception($"The submodel element {idShortPath} does not support child elements."); - } - - var timeStamp = DateTime.UtcNow; - newSme.SetAllParentsAndTimestamps(smeParent, timeStamp, timeStamp); - newSme.SetTimeStamp(timeStamp); - Program.signalNewData(1); - } - } - - public List GetAllSubmodels(IReference reqSemanticId = null, string idShort = null) - { - return _packageEnvService.GetAllSubmodels(reqSemanticId, idShort); - } - - public ISubmodel CreateSubmodel(ISubmodel newSubmodel, string aasIdentifier) - { - //Verify the body first - _verificationService.VerifyRequestBody(newSubmodel); - - var found = _packageEnvService.IsSubmodelPresent(newSubmodel.Id); - if (found) - { - _logger.LogDebug($"Cannot create requested Submodel !!"); - throw new DuplicateException($"Submodel with id {newSubmodel.Id} already exists."); - } - - var output = _packageEnvService.CreateSubmodel(newSubmodel, aasIdentifier); - - return output; - } - - public void UpdateSubmodelById(string submodelIdentifier, ISubmodel newSubmodel) - { - var submodel = _packageEnvService.GetSubmodelById(submodelIdentifier, out _); - - //Verify the body first - _verificationService.VerifyRequestBody(newSubmodel); - - Update.ToUpdateObject(submodel, newSubmodel); - - submodel.SetTimeStamp(DateTime.UtcNow); - - Program.signalNewData(0); - } - - public void UpdateSubmodelElementByPath(string submodelIdentifier, string idShortPath, ISubmodelElement newSme) - { - var submodelElement = GetSubmodelElementByPath(submodelIdentifier, idShortPath); - - //Verify the body first - _verificationService.VerifyRequestBody(newSme); - - Update.ToUpdateObject(submodelElement, newSme); - - newSme.SetTimeStamp(DateTime.UtcNow); - - Program.signalNewData(0); - } - - public void ReplaceFileByPath(string submodelIdentifier, string idShortPath, string fileName, string contentType, MemoryStream fileContent) - { - var fileElement = GetSubmodelElementByPath(submodelIdentifier, idShortPath); - - if (fileElement != null) - { - if (fileElement is AasCore.Aas3_0.File file) - { - //Check if file has location - if (!string.IsNullOrEmpty(file.Value)) - { - //check if it is external location - if (file.Value.StartsWith("http") || file.Value.StartsWith("https")) - { - _logger.LogWarning($"Value of the Submodel-Element File with IdShort {file.IdShort} is an external link."); - throw new NotImplementedException($"File location for {file.IdShort} is external {file.Value}. Currently this fuctionality is not supported."); - } - //Check if a directory - else if (file.Value.StartsWith('/') || file.Value.StartsWith('\\')) - { - _logger.LogInformation($"Value of the Submodel-Element File with IdShort {file.IdShort} is a File-Path."); - //check if the value consists file extension - string sourcePath; - if (Path.HasExtension(file.Value)) - { - sourcePath = Path.GetDirectoryName(file.Value); //This should get platform specific path, without file name - } - else - { - sourcePath = Path.Combine(file.Value); - } - - var targetFile = Path.Combine(sourcePath, fileName); - targetFile = targetFile.Replace('/', Path.DirectorySeparatorChar); //TODO:jtikekar: better way to handle - Task task = _packageEnvService.ReplaceSupplementaryFileInPackage(submodelIdentifier, file.Value, targetFile, contentType, fileContent); - file.Value = FormatFileName(targetFile); - AasxServer.Program.signalNewData(2); - } - // incorrect value - else - { - _logger.LogError($"Incorrect value {file.Value} of the Submodel-Element File with IdShort {file.IdShort}"); - throw new UnprocessableEntityException($"Incorrect value {file.Value} of the File with IdShort {file.IdShort}."); - } - } - else - { - //The value is null, so store the file to default location "/aasx/files" - _logger.LogError($"Null Value of the Submodel-Element File with IdShort {file.IdShort}"); - var targetFile = Path.Combine("/aasx/files", fileName); - targetFile = targetFile.Replace('/', Path.DirectorySeparatorChar); - Task task = _packageEnvService.ReplaceSupplementaryFileInPackage(submodelIdentifier, file.Value, targetFile, contentType, fileContent); - file.Value = FormatFileName(targetFile); - AasxServer.Program.signalNewData(2); - } - - } - else - { - throw new NotFoundException($"Submodel element {fileElement.IdShort} is not of type File."); - } - } - - } - - private string FormatFileName(string fileName) - { - string fileNameTemp = fileName; - - string output = Regex.Replace(fileNameTemp, @"\\", "/"); - - return output; - } - } -} From 4d0220156d4d92412b615871cc04805570807f11 Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Mon, 10 Jun 2024 08:14:08 +0200 Subject: [PATCH 14/17] Fix Merging Bugs --- .../Services-DB/AdminShellPackageEnvironmentServiceDB.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs b/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs index c22ae00b1..7b1b645bf 100644 --- a/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs +++ b/src/AasxServerStandardBib/Services-DB/AdminShellPackageEnvironmentServiceDB.cs @@ -355,5 +355,14 @@ public void DeleteConceptDescriptionById(string cdIdentifier) AasxServer.Program.signalNewData(1); } #endregion + public void setWrite(int packageIndex, bool status) + { + throw new NotImplementedException(); + } + + public bool IsSubmodelPresent(string submodelIdentifier, out ISubmodel output, out int packageIndex) + { + throw new NotImplementedException(); + } } } From 0349a118fdc3855497c89c52f6865b2a87bde59a Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Thu, 13 Jun 2024 08:57:49 +0200 Subject: [PATCH 15/17] Update Dependencies --- src/AasxServerStandardBib/AasxServerStandardBib.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AasxServerStandardBib/AasxServerStandardBib.csproj b/src/AasxServerStandardBib/AasxServerStandardBib.csproj index 384fa26d2..f06de2f10 100644 --- a/src/AasxServerStandardBib/AasxServerStandardBib.csproj +++ b/src/AasxServerStandardBib/AasxServerStandardBib.csproj @@ -32,8 +32,8 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - + + From 3496d029f5fe0a8ef569453fbf32661680dd56a3 Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Thu, 13 Jun 2024 08:58:51 +0200 Subject: [PATCH 16/17] Add Thumbnail Endpoint for MongoDB Version --- src/AasxServerBlazor/Startup.cs | 6 +- .../AssetAdministrationShellServiceDB.cs | 561 ++++++++++++++++++ 2 files changed, 565 insertions(+), 2 deletions(-) create mode 100644 src/AasxServerStandardBib/Services-DB/AssetAdministrationShellServiceDB.cs diff --git a/src/AasxServerBlazor/Startup.cs b/src/AasxServerBlazor/Startup.cs index ea3185240..3d5749b4f 100644 --- a/src/AasxServerBlazor/Startup.cs +++ b/src/AasxServerBlazor/Startup.cs @@ -95,13 +95,15 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); - services.AddTransient(); + if (Program1.withMongodb) { - services.AddTransient(); + services.AddTransient(); + services.AddTransient(); } else { + services.AddTransient(); services.AddTransient(); } services.AddTransient(); diff --git a/src/AasxServerStandardBib/Services-DB/AssetAdministrationShellServiceDB.cs b/src/AasxServerStandardBib/Services-DB/AssetAdministrationShellServiceDB.cs new file mode 100644 index 000000000..92459d6ce --- /dev/null +++ b/src/AasxServerStandardBib/Services-DB/AssetAdministrationShellServiceDB.cs @@ -0,0 +1,561 @@ + +using AasxServer; +using AasxServerStandardBib.Exceptions; +using AasxServerStandardBib.Interfaces; +using AasxServerStandardBib.Logging; +using AdminShellNS.Extensions; +using Extensions; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace AasxServerStandardBib.Services +{ + public class AssetAdministrationShellServiceDB : IAssetAdministrationShellService + { + private readonly IAppLogger _logger; + private readonly IAdminShellPackageEnvironmentService _packageEnvService; + private readonly IMetamodelVerificationService _verificationService; + private readonly ISubmodelService _submodelService; + private IDatabase _database; + + + public AssetAdministrationShellServiceDB(IAppLogger logger, IAdminShellPackageEnvironmentService packageEnvService, IMetamodelVerificationService verificationService, ISubmodelService submodelService) + { + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); ; + _packageEnvService = packageEnvService; + _verificationService = verificationService; + _submodelService = submodelService; + _database = Program.database; + } + + public IAssetAdministrationShell CreateAssetAdministrationShell(IAssetAdministrationShell body) + { + //Verify the body first + _verificationService.VerifyRequestBody(body); + + var found = _packageEnvService.IsAssetAdministrationShellPresent(body.Id); + if (found) + { + _logger.LogDebug($"Cannot create requested AAS !!"); + throw new DuplicateException($"AssetAdministrationShell with id {body.Id} already exists."); + } + + var output = _packageEnvService.CreateAssetAdministrationShell(body); + + return output; + } + + public IReference CreateSubmodelReferenceInAAS(IReference body, string aasIdentifier) + { + IReference output = null; + //Verify request body + _verificationService.VerifyRequestBody(body); + + // TODO (jtikekar, 2023-09-04): to check if submodel with requested submodelReference exists in the server + var aas = _packageEnvService.GetAssetAdministrationShellById(aasIdentifier, out _); + + if (aas != null) + { + if (aas.Submodels.IsNullOrEmpty()) + { + aas.Submodels = new List + { + body + }; + output = aas.Submodels.Last(); + } + else + { + bool found = false; + //Check if duplicate + foreach (var submodelReference in aas.Submodels) + { + if (submodelReference.Matches(body)) + { + found = true; + break; + } + } + + if (found) + { + _logger.LogDebug($"Cannot create requested Submodel-Reference in the AAS !!"); + throw new DuplicateException($"Requested SubmodelReference already exists in the AAS with Id {aasIdentifier}."); + } + else + { + aas.Submodels.Add(body); + output = aas.Submodels.Last(); + } + } + } + + return output; + } + + + + public void DeleteAssetAdministrationShellById(string aasIdentifier) + { + var aas = _packageEnvService.GetAssetAdministrationShellById(aasIdentifier, out int packageIndex); + + if (aas != null && packageIndex != -1) + { + _packageEnvService.DeleteAssetAdministrationShell(packageIndex, aas); + } + } + + public void DeleteFileByPath(string aasIdentifier, string submodelIdentifier, string idShortPath) + { + var found = IsSubmodelPresentWithinAAS(aasIdentifier, submodelIdentifier); + if (found) + { + _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); + _submodelService.DeleteFileByPath(submodelIdentifier, idShortPath); + } + else + { + throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + } + } + + public void DeleteSubmodelById(string aasIdentifier, string submodelIdentifier) + { + var found = IsSubmodelPresentWithinAAS(aasIdentifier, submodelIdentifier); + if (found) + { + _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); + //delete the submodel first, this should eventually delete the submodel reference from all the AASs + _submodelService.DeleteSubmodelById(submodelIdentifier); + } + else + { + throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + } + } + + public void DeleteSubmodelElementByPath(string aasIdentifier, string submodelIdentifier, string idShortPath) + { + var found = IsSubmodelPresentWithinAAS(aasIdentifier, submodelIdentifier); + if (found) + { + _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); + _submodelService.DeleteSubmodelElementByPath(submodelIdentifier, idShortPath); + } + else + { + throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + } + + } + + + + public void DeleteSubmodelReferenceById(string aasIdentifier, string submodelIdentifier) + { + var aas = _packageEnvService.GetAssetAdministrationShellById(aasIdentifier, out _); + + if (aas != null) + { + var submodelReference = aas.Submodels.Where(s => s.Matches(submodelIdentifier)); + if (submodelReference.Any()) + { + _logger.LogDebug($"Found requested submodel reference in the aas."); + bool deleted = aas.Submodels.Remove(submodelReference.First()); + if (deleted) + { + _logger.LogDebug($"Deleted submodel reference with id {submodelIdentifier} from the AAS with id {aasIdentifier}."); + Program.signalNewData(1); + } + else + { + _logger.LogError($"Could not delete submodel reference with id {submodelIdentifier} from the AAS with id {aasIdentifier}."); + } + } + else + { + throw new NotFoundException($"SubmodelReference with id {submodelIdentifier} not found in AAS with id {aasIdentifier}"); + } + } + } + + + + public List GetAllAssetAdministrationShells(List assetIds = null, string idShort = null) + { + var output = _packageEnvService.GetAllAssetAdministrationShells(); + + //Apply filters + + if (output.Any()) + { + if (!string.IsNullOrEmpty(idShort)) + { + _logger.LogDebug($"Filtering AASs with idShort {idShort}."); + output = output.Where(a => a.IdShort.Equals(idShort)).ToList(); + if (output.IsNullOrEmpty()) + { + _logger.LogInformation($"No AAS with idShhort {idShort} found."); + } + } + + if (!assetIds.IsNullOrEmpty()) + { + _logger.LogDebug($"Filtering AASs with requested specific assetIds."); + var aasList = new List(); + foreach (var assetId in assetIds) + { + aasList = output.Where(a => a.AssetInformation.SpecificAssetIds.ContainsSpecificAssetId(assetId)).ToList(); + } + + if (aasList.Any()) + { + output = aasList; + } + else + { + _logger.LogInformation($"No AAS with requested specific assetId found."); + } + } + } + + return output; + } + + public List GetAllSubmodelElements(string aasIdentifier, string submodelIdentifier) + { + var found = IsSubmodelPresentWithinAAS(aasIdentifier, submodelIdentifier); + if (found) + { + _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); + return _submodelService.GetAllSubmodelElements(submodelIdentifier); + } + else + { + throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + } + } + + public List GetAllSubmodelReferencesFromAas(string aasIdentifier) + { + List output = new List(); + var aas = _packageEnvService.GetAssetAdministrationShellById(aasIdentifier, out _); + + if (aas != null) + { + if (aas.Submodels.IsNullOrEmpty()) + { + _logger.LogDebug($"No submodels present in the AAS with Id {aasIdentifier}"); + } + + output = aas.Submodels; + } + + return output; + } + + public IAssetAdministrationShell GetAssetAdministrationShellById(string aasIdentifier) + { + return _packageEnvService.GetAssetAdministrationShellById(aasIdentifier, out _); + } + + public IAssetInformation GetAssetInformation(string aasIdentifier) + { + var aas = _packageEnvService.GetAssetAdministrationShellById(aasIdentifier, out _); + return aas.AssetInformation; + } + + public void DeleteThumbnail(string aasIdentifier) + { + var aas = _packageEnvService.GetAssetAdministrationShellById(aasIdentifier, out int packageIndex); + if (aas != null) + { + if (aas.AssetInformation != null) + { + if (aas.AssetInformation.DefaultThumbnail != null && !string.IsNullOrEmpty(aas.AssetInformation.DefaultThumbnail.Path)) + { + _packageEnvService.DeleteAssetInformationThumbnail(packageIndex, aas.AssetInformation.DefaultThumbnail); + } + else + { + throw new NotFoundException($"No default thumbnail embedded in the AssetInformation of the requested AAS."); + } + } + } + } + + public string GetThumbnail(string aasIdentifier, out byte[] byteArray, out long fileSize) + { + string fileName = null; + byteArray = null; + fileSize = 0; + var aas = _packageEnvService.GetAssetAdministrationShellById(aasIdentifier, out int packageIndex); + if (aas != null) + { + if (aas.AssetInformation != null) + { + if (aas.AssetInformation.DefaultThumbnail != null && !string.IsNullOrEmpty(aas.AssetInformation.DefaultThumbnail.Path)) + { + fileName = aas.AssetInformation.GlobalAssetId + aas.AssetInformation.DefaultThumbnail.Path; + + Stream stream = _database.ReadFile(fileName); + byteArray = stream.ToByteArray(); + fileSize = byteArray.Length; + + _logger.LogDebug($"Retrived the thumbnail in AAS with Id {aasIdentifier}"); + } + else + { + throw new NotFoundException($"No default thumbnail embedded in the AssetInformation of the requested AAS."); + } + } + else + { + throw new NotFoundException($"AssetInformation is NULL in requested AAS with id {aasIdentifier}"); + } + } + + return fileName; + } + + public void UpdateAssetAdministrationShellById(IAssetAdministrationShell body, string aasIdentifier) + { + //Verify the body first + _verificationService.VerifyRequestBody(body); + + _packageEnvService.UpdateAssetAdministrationShellById(body, aasIdentifier); + + } + + public void UpdateAssetInformation(AssetInformation body, string aasIdentifier) + { + _verificationService.VerifyRequestBody(body); + var aas = _packageEnvService.GetAssetAdministrationShellById(aasIdentifier, out _); + if (aas != null) + { + aas.AssetInformation = body; + Program.signalNewData(0); + + _logger.LogDebug($"AssetInformation from AAS with id {aasIdentifier} updated successfully."); + } + } + + public void UpdateThumbnail(string aasIdentifier, string fileName, string contentType, Stream fileContent) + { + var aas = _packageEnvService.GetAssetAdministrationShellById(aasIdentifier, out int packageIndex); + if (aas != null) + { + if (aas.AssetInformation != null) + { + var asset = aas.AssetInformation; + + if (string.IsNullOrEmpty(contentType)) + { + contentType = "application/octet-stream"; + } + + if (asset.DefaultThumbnail == null) + { + //If thumbnail is not set, set to default path + asset.DefaultThumbnail ??= new Resource(Path.Combine("/aasx/files", fileName).Replace('/', Path.DirectorySeparatorChar), contentType); + } + else + { + asset.DefaultThumbnail.Path = asset.DefaultThumbnail.Path.Replace('/', Path.DirectorySeparatorChar); + } + + _packageEnvService.UpdateAssetInformationThumbnail(asset.DefaultThumbnail, fileContent, packageIndex); + + + } + else + { + throw new NotFoundException($"AssetInformation is NULL in requested AAS with id {aasIdentifier}"); + } + } + } + + #region PrivateMethods + + private bool IsSubmodelPresentWithinAAS(string aasIdentifier, string submodelIdentifier) + { + var aas = _packageEnvService.GetAssetAdministrationShellById(aasIdentifier, out _); + if (aas != null) + { + foreach (var submodelReference in aas.Submodels) + { + if (submodelReference.GetAsExactlyOneKey().Value.Equals(submodelIdentifier)) + { return true; } + } + } + + return false; + } + + public string GetFileByPath(string aasIdentifier, string submodelIdentifier, string idShortPath, out byte[] content, out long fileSize) + { + content = null; + fileSize = 0; + var found = IsSubmodelPresentWithinAAS(aasIdentifier, submodelIdentifier); + if (found) + { + _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); + return _submodelService.GetFileByPath(submodelIdentifier, idShortPath, out content, out fileSize); + } + else + { + throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + } + + } + + public ISubmodel GetSubmodelById(string aasIdentifier, string submodelIdentifier) + { + var found = IsSubmodelPresentWithinAAS(aasIdentifier, submodelIdentifier); + if (found) + { + _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); + return _submodelService.GetSubmodelById(submodelIdentifier); + } + else + { + throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + } + } + + public ISubmodelElement GetSubmodelElementByPath(string aasIdentifier, string submodelIdentifier, string idShortPath) + { + var found = IsSubmodelPresentWithinAAS(aasIdentifier, submodelIdentifier); + if (found) + { + _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); + return _submodelService.GetSubmodelElementByPath(submodelIdentifier, idShortPath); + } + else + { + throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + } + } + + public ISubmodelElement CreateSubmodelElement(string aasIdentifier, string submodelIdentifier, bool first, ISubmodelElement newSubmodelElement) + { + var smFound = IsSubmodelPresentWithinAAS(aasIdentifier, submodelIdentifier); + if (smFound) + { + _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); + return _submodelService.CreateSubmodelElement(submodelIdentifier, newSubmodelElement, first); + } + else + { + throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + } + } + + public ISubmodelElement CreateSubmodelElementByPath(string aasIdentifier, string submodelIdentifier, string idShortPath, bool first, ISubmodelElement newSubmodelElement) + { + var smFound = IsSubmodelPresentWithinAAS(aasIdentifier, submodelIdentifier); + if (smFound) + { + _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); + return _submodelService.CreateSubmodelElementByPath(submodelIdentifier, idShortPath, first, newSubmodelElement); + } + else + { + throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + } + } + + public void ReplaceAssetAdministrationShellById(string aasIdentifier, IAssetAdministrationShell newAas) + { + _verificationService.VerifyRequestBody(newAas); + _packageEnvService.ReplaceAssetAdministrationShellById(aasIdentifier, newAas); + } + + public void ReplaceAssetInformation(string aasIdentifier, IAssetInformation newAssetInformation) + { + var aas = _packageEnvService.GetAssetAdministrationShellById(aasIdentifier, out _); + if (aas != null) + { + _verificationService.VerifyRequestBody(newAssetInformation); + aas.AssetInformation = newAssetInformation; + Program.signalNewData(0); + } + } + + public void ReplaceSubmodelById(string aasIdentifier, string submodelIdentifier, Submodel newSubmodel) + { + var found = IsSubmodelPresentWithinAAS(aasIdentifier, submodelIdentifier); + if (found) + { + _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); + _submodelService.ReplaceSubmodelById(submodelIdentifier, newSubmodel); + } + else + { + throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + } + + } + + public void ReplaceSubmodelElementByPath(string aasIdentifier, string submodelIdentifier, string idShortPath, ISubmodelElement newSme) + { + var found = IsSubmodelPresentWithinAAS(aasIdentifier, submodelIdentifier); + if (found) + { + _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); + _submodelService.ReplaceSubmodelElementByPath(submodelIdentifier, idShortPath, newSme); + } + else + { + throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + } + } + + public void UpdateSubmodelById(string aasIdentifier, string submodelIdentifier, ISubmodel newSubmodel) + { + var found = IsSubmodelPresentWithinAAS(aasIdentifier, submodelIdentifier); + if (found) + { + _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); + _submodelService.UpdateSubmodelById(submodelIdentifier, newSubmodel); + } + else + { + throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + } + } + + public void UpdateSubmodelElementByPath(string aasIdentifier, string submodelIdentifier, string idShortPath, ISubmodelElement newSme) + { + var found = IsSubmodelPresentWithinAAS(aasIdentifier, submodelIdentifier); + if (found) + { + _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); + _submodelService.UpdateSubmodelElementByPath(submodelIdentifier, idShortPath, newSme); + } + else + { + throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + } + } + + public void ReplaceFileByPath(string aasIdentifier, string submodelIdentifier, string idShortPath, string fileName, string contentType, MemoryStream fileContent) + { + var found = IsSubmodelPresentWithinAAS(aasIdentifier, submodelIdentifier); + if (found) + { + _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); + _submodelService.ReplaceFileByPath(submodelIdentifier, idShortPath, fileName, contentType, fileContent); + } + else + { + throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + } + } + + #endregion + } +} From 1f7c1785175dfc0e3d6c73bd148b16f6c2f1ace1 Mon Sep 17 00:00:00 2001 From: Jonas Graubner <82174634+JoTec2002@users.noreply.github.com> Date: Thu, 13 Jun 2024 08:59:10 +0200 Subject: [PATCH 17/17] Update Docker Deployment --- src/AasxServerBlazor/startForDemo.sh | 2 +- src/docker/docker-compose-demo.yaml | 10 ++++++--- src/docker/docker-compose-mongodb.yaml | 30 ++++++++++++++++++++++++++ src/docker/docker-compose.yaml | 4 ++-- 4 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 src/docker/docker-compose-mongodb.yaml diff --git a/src/AasxServerBlazor/startForDemo.sh b/src/AasxServerBlazor/startForDemo.sh index bdf52e0f6..3fac751d2 100755 --- a/src/AasxServerBlazor/startForDemo.sh +++ b/src/AasxServerBlazor/startForDemo.sh @@ -1 +1 @@ -dotnet AasxServerBlazor.dll --no-security --data-path ./aasxs --host 0.0.0.0 $OPTIONSAASXSERVER \ No newline at end of file +dotnet AasxServerBlazor.dll --no-security --aasx-in-memory 1000 --data-path ./aasxs --edit --external-blazor http://localhost:5001 --with-mongodb "mongodb://mongo:mongo@mongodb-server:27017/" $OPTIONSAASXSERVER \ No newline at end of file diff --git a/src/docker/docker-compose-demo.yaml b/src/docker/docker-compose-demo.yaml index 87d5c12c7..152ec13df 100644 --- a/src/docker/docker-compose-demo.yaml +++ b/src/docker/docker-compose-demo.yaml @@ -2,10 +2,14 @@ services: aasx-server: container_name: aasx-server hostname: aasx-server - image: adminshellio/aasx-server-blazor-for-demo:v3latest + image: adminshellio/aasx-server-blazor-for-demo:main restart: unless-stopped ports: - "5001:5001" volumes: - - ./aasxs:/usr/share/aasxs - command: --start-index 0 --no-security --edit --data-path /usr/share/aasxs --external-blazor http://localhost:5001 + - C:\GitClones\aasx-server\content-for-demo\aasxs:/AasxServerBlazor/aasxs + deploy: + resources: + limits: + memory: 3G + command: --start-index 0 --no-security --edit --data-path /AasxServerBlazor/aasxs --external-blazor http://localhost:5001 diff --git a/src/docker/docker-compose-mongodb.yaml b/src/docker/docker-compose-mongodb.yaml new file mode 100644 index 000000000..24b33ac11 --- /dev/null +++ b/src/docker/docker-compose-mongodb.yaml @@ -0,0 +1,30 @@ +version: '3.8' +services: + mongodb: + image: mongo + hostname: "mongodb-server" + container_name: "mongodb-server" + restart: unless-stopped + volumes: + - ./mongo/data:/data/db + ports: + - '27017:27017' + environment: + - MONGO_INITDB_ROOT_USERNAME=mongo + - MONGO_INITDB_ROOT_PASSWORD=mongo + aasx-server: + container_name: aasx-server + hostname: aasx-server + image: aasx-server-blazor-for-demo:latest + restart: unless-stopped + ports: + - "5001:5001" + depends_on: + - mongodb + volumes: + - C:\GitClones\aasx-server\content-for-demo\aasxs:/AasxServerBlazor/aasxs + deploy: + resources: + limits: + memory: 3G + command: --start-index 0 --no-security --aasx-in-memory 1000 --data-path "./aasxs" --edit --external-blazor http://localhost:5001 --with-mongodb "mongodb://mongo:mongo@localhost:27017/" \ No newline at end of file diff --git a/src/docker/docker-compose.yaml b/src/docker/docker-compose.yaml index 9189fb998..8e80e352b 100644 --- a/src/docker/docker-compose.yaml +++ b/src/docker/docker-compose.yaml @@ -9,5 +9,5 @@ services: ports: - "5001:5001" volumes: - - ./aasxs:/usr/share/aasxs - command: --start-index 0 --no-security --edit --data-path /usr/share/aasxs --external-blazor http://localhost:5001 \ No newline at end of file + - C:\GitClones\aasx-server\content-for-demo\aasxs:/usr/share/aasxs + command: --start-index 0 --no-security --aasx-in-memory 1000 --data-path "./aasxs" --edit --external-blazor http://localhost:5001 --with-mongodb "mongodb://mongo:mongo@localhost:27017/"