diff --git a/CDP4Common.NetCore.Tests/CDP4Common.NetCore.Tests.csproj b/CDP4Common.NetCore.Tests/CDP4Common.NetCore.Tests.csproj index a98ac451d..06f978032 100644 --- a/CDP4Common.NetCore.Tests/CDP4Common.NetCore.Tests.csproj +++ b/CDP4Common.NetCore.Tests/CDP4Common.NetCore.Tests.csproj @@ -12,7 +12,7 @@ - + @@ -30,5 +30,5 @@ - + diff --git a/CDP4Common.Tests/CDP4Common.Tests.csproj b/CDP4Common.Tests/CDP4Common.Tests.csproj index 8366d9282..6db697f0c 100644 --- a/CDP4Common.Tests/CDP4Common.Tests.csproj +++ b/CDP4Common.Tests/CDP4Common.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/CDP4Common/CDP4Common.csproj b/CDP4Common/CDP4Common.csproj index 339299fb4..31dec0d78 100644 --- a/CDP4Common/CDP4Common.csproj +++ b/CDP4Common/CDP4Common.csproj @@ -4,7 +4,7 @@ net45;net451;net452;net46;net461;net462;net47;netstandard1.6;netstandard2.0 RHEA System S.A. CDP4Common Community Edition - 1.1.0-rc1 + 1.1.1 CDP4 Common Class Library that contains DTOs, POCOs Copyright © RHEA System S.A. Sam, Merlin, Alex, Naron diff --git a/CDP4Common/Helpers/PocoThingFactory.cs b/CDP4Common/Helpers/PocoThingFactory.cs index 61ac55436..e12607b9d 100644 --- a/CDP4Common/Helpers/PocoThingFactory.cs +++ b/CDP4Common/Helpers/PocoThingFactory.cs @@ -227,7 +227,7 @@ internal static T Get(this ConcurrentDictionary, Lazy(firstKey); } - logger.Error("The {0} was not found in the cache: {1}", typeof(T).Name, key.Item1); + logger.Debug("The {0} was not found in the cache: {1}", typeof(T).Name, key.Item1); return null; } diff --git a/CDP4Dal.NetCore.Tests/CDP4Dal.NetCore.Tests.csproj b/CDP4Dal.NetCore.Tests/CDP4Dal.NetCore.Tests.csproj index 515424a45..7aa8dbc69 100644 --- a/CDP4Dal.NetCore.Tests/CDP4Dal.NetCore.Tests.csproj +++ b/CDP4Dal.NetCore.Tests/CDP4Dal.NetCore.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/CDP4Dal.Tests/CDP4Dal.Tests.csproj b/CDP4Dal.Tests/CDP4Dal.Tests.csproj index 9c6f87711..23ed45e2a 100644 --- a/CDP4Dal.Tests/CDP4Dal.Tests.csproj +++ b/CDP4Dal.Tests/CDP4Dal.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/CDP4Dal/Assembler.cs b/CDP4Dal/Assembler.cs index 77f0e7f5e..2d8b56b6a 100644 --- a/CDP4Dal/Assembler.cs +++ b/CDP4Dal/Assembler.cs @@ -1,688 +1,705 @@ -#region Copyright -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2015-2018 RHEA System S.A. -// -// Author: Sam Gerené, Merlin Bieze, Alex Vorobiev, Naron Phou -// -// This file is part of CDP4-SDK Community Edition -// -// The CDP4-SDK Community Edition is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// The CDP4-SDK Community Edition is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// -------------------------------------------------------------------------------------------------------------------- -#endregion - -namespace CDP4Dal -{ - using System; - using System.Collections; - using System.Collections.Concurrent; - using System.Collections.Generic; - using System.Diagnostics; - using System.Linq; - using System.Reflection; - using System.Threading; - using System.Threading.Tasks; - - using CDP4Common; - using CDP4Common.CommonData; - using CDP4Common.EngineeringModelData; - using CDP4Common.Helpers; - using CDP4Common.SiteDirectoryData; - using CDP4Common.Types; - using Events; - using NLog; - - using Dto = CDP4Common.DTO.Thing; - - /// - /// The Assembler orchestrates the interaction with the IDAL and the related Cache - /// - public class Assembler - { - #region Fields - /// - /// The associated with this assembler - /// - public readonly Uri IDalUri; - - /// - /// The current logger - /// - private static Logger logger = LogManager.GetCurrentClassLogger(); - - /// - /// The lock object - /// - private SemaphoreSlim threadLock = new SemaphoreSlim(1); - - /// - /// The unique - /// - private SiteDirectory siteDirectory; - - /// - /// The list of marked for deletion - /// - private List thingsMarkedForDeletion; - - /// - /// The not completely resolved that are in the cache - /// - private List unresolvedDtos; - #endregion - - /// - /// Initializes a new instance of the class. - /// - /// the associated with this - public Assembler(Uri uri) - { - Utils.AssertNotNull(uri, "The Uri may not be mull"); - - this.Cache = new ConcurrentDictionary, Lazy>(); - this.unresolvedDtos = new List(); - this.IDalUri = uri; - } - - #region Properties - - /// - /// Gets the Cache that contains all the s - /// - public ConcurrentDictionary, Lazy> Cache { get; private set; } - - /// - /// Gets or sets the list of to update - /// - private List DtoThingToUpdate { get; set; } - #endregion Properties - - #region Public Methods - - /// - /// Synchronize the Cache give an IEnumerable of DTO - /// - /// - /// the DTOs - /// - /// - /// An optional value indicating whether the should publish or not. - /// The default value is true - /// - /// - /// The that can be awaited. - /// - public async Task Synchronize(IEnumerable dtoThings, bool activeMessageBus = true) - { - if (dtoThings == null) - { - throw new ArgumentNullException("dtoThings"); - } - - await this.threadLock.WaitAsync().ConfigureAwait(false); - try - { - logger.Info("Start Synchronization of {0}", this.IDalUri); - this.thingsMarkedForDeletion = new List(); - - var synchronizeStopWatch = Stopwatch.StartNew(); - - logger.Trace("Starting Clean-up Unused references"); - var startwatch = Stopwatch.StartNew(); - - var existentGuid = - this.Cache.Select( - x => new Tuple, int>(x.Value.Value.CacheId, x.Value.Value.RevisionNumber)) - .ToList(); - - this.DtoThingToUpdate = dtoThings.ToList(); - - // Add the unresolved thing to the things to resolved in case it is possible to fully resolve them with the current update - // an example would be Citation contained by SiteDirectory where its Source is contained by a Rdl that is not loaded yet - var unresolvedThingToUpdate = - this.unresolvedDtos.Where(x => !this.DtoThingToUpdate.Select(y => y.Iid).Contains(x.Iid)); - this.DtoThingToUpdate.AddRange(unresolvedThingToUpdate); - this.unresolvedDtos.Clear(); - - if (!this.Cache.IsEmpty) - { - // marks things for deletion - this.ComputeThingsToRemoveInUpdatedThings(); - startwatch.Stop(); - logger.Trace("Clean up Unused references took {0} [ms]", startwatch.ElapsedMilliseconds); - } - - logger.Trace("Start Updating cache"); - startwatch = Stopwatch.StartNew(); - this.AddOrUpdateTheCache(this.DtoThingToUpdate); - startwatch.Stop(); - logger.Trace("Updating cache took {0} [ms]", startwatch.ElapsedMilliseconds); - - logger.Trace("Start Resolving properties"); - startwatch = Stopwatch.StartNew(); - PocoThingFactory.ResolveDependencies(this.DtoThingToUpdate, this.Cache); - startwatch.Stop(); - logger.Trace("Resolving properties took {0} [ms]", startwatch.ElapsedMilliseconds); - - if (activeMessageBus) - { - logger.Trace("Start Messaging"); - startwatch = Stopwatch.StartNew(); - - foreach (var dtoThing in this.DtoThingToUpdate) - { - Lazy updatedLazyThing; - var cacheKey = new Tuple(dtoThing.Iid, dtoThing.IterationContainerId); - var succeed = this.Cache.TryGetValue(cacheKey, out updatedLazyThing); - - if (succeed) - { - var thingObject = updatedLazyThing.Value; - var cacheId = new Tuple(dtoThing.Iid, dtoThing.IterationContainerId); - if (!existentGuid.Select(x => x.Item1).Contains(cacheId)) - { - CDPMessageBus.Current.SendObjectChangeEvent(thingObject, EventKind.Added); - } - else if (dtoThing.RevisionNumber > existentGuid.Single(x => x.Item1.Equals(cacheId)).Item2) - { - // send event only if revision number has increased from the old cached version - CDPMessageBus.Current.SendObjectChangeEvent(thingObject, EventKind.Updated); - } - - var sw = new Stopwatch(); - sw.Start(); - // add to the list of unresolved dtos if there is an error - thingObject.ValidatePoco(); - if (thingObject.ValidationErrors.Any()) - { - this.unresolvedDtos.Add(dtoThing); - } - sw.Stop(); - logger.Trace("Validate Poco took {0} [ms]", startwatch.Elapsed); - } - } - - startwatch.Stop(); - logger.Trace("Messaging things took {0} [ms]", startwatch.ElapsedMilliseconds); - } - - logger.Trace("Start Deleting things"); - startwatch = Stopwatch.StartNew(); - foreach (var markedThing in this.thingsMarkedForDeletion.Where(x => x.ChangeKind == ChangeKind.Delete)) - { - this.RemoveThingFromCache(markedThing); - } - - var deletedIterationSetups = this.DtoThingToUpdate.OfType().Where(x => x.IsDeleted).ToList(); - var deletedModelSetups = this.thingsMarkedForDeletion.OfType().ToList(); - this.thingsMarkedForDeletion.Clear(); - - if (deletedIterationSetups.Any()) - { - foreach (var deletedIterationSetup in deletedIterationSetups) - { - this.MarkAndDelete(deletedIterationSetup.IterationIid); - } - } - - if (deletedModelSetups.Any()) - { - foreach (var deletedModelSetup in deletedModelSetups) - { - this.MarkAndDelete(deletedModelSetup.EngineeringModelIid); - } - } - - startwatch.Stop(); - logger.Trace("Deleting things took {0} [ms]", startwatch.ElapsedMilliseconds); - - this.DtoThingToUpdate.Clear(); - - if (this.siteDirectory == null) - { - var keyvaluepair = this.Cache.Single(item => item.Value.Value.ClassKind == ClassKind.SiteDirectory); - this.siteDirectory = (SiteDirectory)keyvaluepair.Value.Value; - } - - logger.Info("Finish Synchronization of {0} in {1} [ms]", this.IDalUri, synchronizeStopWatch.ElapsedMilliseconds); - } - catch (Exception e) - { - logger.Error(e.Message); - } - finally - { - this.threadLock.Release(); - logger.Trace("Assembler thread released"); - } - } - - /// - /// Clears the cache and sends removed event for s - /// - /// The - public async Task Clear() - { - await this.threadLock.WaitAsync().ConfigureAwait(false); - try - { - var iterations = - this.Cache.Select(x => x.Value) - .Where(lazy => lazy.Value.ClassKind == ClassKind.Iteration) - .Select(lazy => lazy.Value) - .Cast(); - - foreach (var iteration in iterations) - { - CDPMessageBus.Current.SendObjectChangeEvent(iteration, EventKind.Removed); - logger.Trace("iteration with iid {0} removed", iteration.Iid); - } - - var models = - this.Cache.Select(x => x.Value) - .Where(lazy => lazy.Value.ClassKind == ClassKind.EngineeringModel) - .Select(lazy => lazy.Value) - .Cast(); - - foreach (var model in models) - { - CDPMessageBus.Current.SendObjectChangeEvent(model, EventKind.Removed); - logger.Trace("model with iid {0} removed", model.Iid); - } - - this.siteDirectory = null; - this.Cache.Clear(); - } - catch (Exception e) - { - logger.Error(e.Message); - } - finally - { - this.threadLock.Release(); - } - } - - /// - /// Close a by clearing all its contained elements - /// - /// The to close - /// The async - public async Task CloseRdl(ReferenceDataLibrary rdl) - { - await this.threadLock.WaitAsync().ConfigureAwait(false); - try - { - var startwatch = Stopwatch.StartNew(); - this.thingsMarkedForDeletion = new List(); - foreach (var category in rdl.DefinedCategory) - { - this.RecursivelyMarksForRemoval(category); - } - - foreach (var parameterType in rdl.ParameterType) - { - this.RecursivelyMarksForRemoval(parameterType); - } - - foreach (var measurementScale in rdl.Scale) - { - this.RecursivelyMarksForRemoval(measurementScale); - } - - foreach (var unitPrefix in rdl.UnitPrefix) - { - this.RecursivelyMarksForRemoval(unitPrefix); - } - - foreach (var measurementUnit in rdl.Unit) - { - this.RecursivelyMarksForRemoval(measurementUnit); - } - - foreach (var filetype in rdl.FileType) - { - this.RecursivelyMarksForRemoval(filetype); - } - - foreach (var glossary in rdl.Glossary) - { - this.RecursivelyMarksForRemoval(glossary); - } - - foreach (var referenceSource in rdl.ReferenceSource) - { - this.RecursivelyMarksForRemoval(referenceSource); - } - - foreach (var rule in rdl.Rule) - { - this.RecursivelyMarksForRemoval(rule); - } - - foreach (var constant in rdl.Constant) - { - this.RecursivelyMarksForRemoval(constant); - } - - rdl.DefinedCategory.Clear(); - rdl.ParameterType.Clear(); - rdl.Scale.Clear(); - rdl.UnitPrefix.Clear(); - rdl.Unit.Clear(); - rdl.FileType.Clear(); - rdl.Glossary.Clear(); - rdl.ReferenceSource.Clear(); - rdl.Rule.Clear(); - rdl.Constant.Clear(); - rdl.BaseQuantityKind.Clear(); - rdl.BaseUnit.Clear(); - - foreach (var thing in this.thingsMarkedForDeletion) - { - this.RemoveThingFromCache(thing); - } - - CDPMessageBus.Current.SendObjectChangeEvent(rdl, EventKind.Updated); - - this.thingsMarkedForDeletion.Clear(); - logger.Trace("Finish closing of {0} ({1}) in {2} [ms]", rdl.Name, this.IDalUri, startwatch.ElapsedMilliseconds); - } - catch (Exception e) - { - logger.Error(e.Message); - } - finally - { - this.threadLock.Release(); - } - } - - /// - /// Close a by clearing all its contained elements - /// - /// - /// The to close - /// - /// - /// The . - /// - public async Task CloseIterationSetup(IterationSetup iterationSetup) - { - await this.threadLock.WaitAsync().ConfigureAwait(false); - try - { - Lazy lazyIteration; - if ( - !this.Cache.TryGetValue(new Tuple(iterationSetup.IterationIid, null), out lazyIteration)) - { - this.threadLock.Release(); - return; - } - - var iteration = lazyIteration.Value as Iteration; - if (iteration == null) - { - this.threadLock.Release(); - return; - } - - // Delete from the cache all things contained by the iteration without blocking the UI - await this.ClearFromCacheThingsContainedByIteration(iteration); - } - catch (Exception e) - { - logger.Error(e.Message); - } - finally - { - this.threadLock.Release(); - } - } - - /// - /// Clear from cache things contained by iteration. - /// - /// - /// The iteration. - /// - /// - /// The . - /// - private async Task ClearFromCacheThingsContainedByIteration(Iteration iteration) - { - var startwatch = Stopwatch.StartNew(); - - this.thingsMarkedForDeletion = new List(); - this.RecursivelyMarksForRemoval(iteration); - foreach (var thing in this.thingsMarkedForDeletion) - { - this.RemoveThingFromCache(thing); - } - - this.thingsMarkedForDeletion.Clear(); - logger.Trace("Finish closing iteration {0} ({1}) in {2} [ms]", iteration.Iid, this.IDalUri, startwatch.ElapsedMilliseconds); - } - - /// - /// Retrieves the single of this - /// - /// The - public SiteDirectory RetrieveSiteDirectory() - { - return this.siteDirectory; - } - - #endregion Public Methods - - #region Private Methods - - /// - /// Checks the status of the updated s in the Cache - /// - private void ComputeThingsToRemoveInUpdatedThings() - { - foreach (var dtoThing in this.DtoThingToUpdate) - { - this.ComputeThingsToRemove(dtoThing); - } - } - - /// - /// Removes s part of a composition with the associated to the if the references are no longer in the updated - /// - /// the to check - private void ComputeThingsToRemove(Dto dtoThing) - { - Lazy cachedLazyThing; - if (!this.Cache.TryGetValue(new Tuple(dtoThing.Iid, dtoThing.IterationContainerId), out cachedLazyThing)) - { - return; - } - - var dtoContainedGuid = this.ComputeContainedGuid(dtoThing); - var pocoContainedThing = this.ComputeContainedThing(cachedLazyThing.Value); - - var thingsToRemove = pocoContainedThing.Where(poco => !dtoContainedGuid.Contains(poco.Iid)).ToList(); - foreach (var thing in thingsToRemove) - { - // isPersistent - this.RecursivelyMarksForRemoval(thing); - } - } - - /// - /// Get the non-persistent property type in a - /// - /// The - /// An containing the type of s that are not persistent in the - private List ComputeNonPersistentPropertyType(Thing thing) - { - var nonPersistentType = new List(); - - var propInfos = thing.GetType().GetProperties(); - foreach (var propertyInfo in propInfos) - { - if(!propertyInfo.IsDefined(typeof(UmlInformationAttribute))) - { - continue; - } - - var metadata = propertyInfo.GetCustomAttribute(); - if (metadata.Aggregation == AggregationKind.Composite && !metadata.IsPersistent) - { - nonPersistentType.Add(propertyInfo.PropertyType.GetGenericArguments().Single()); - } - } - - return nonPersistentType; - } - - /// - /// Compute the contained for a - /// - /// The to compute - /// An containing all the contained - private List ComputeContainedGuid(Dto dto) - { - var containedGuid = new List(); - foreach (var container in dto.ContainerLists) - { - foreach (var obj in container) - { - var orderedItem = obj as OrderedItem; - if (orderedItem != null) - { - containedGuid.Add(new Guid(orderedItem.V.ToString())); - } - else - { - containedGuid.Add((Guid)obj); - } - } - } - - return containedGuid; - } - - /// - /// Compute the contained for a - /// - /// The to compute - /// An containing all the contained - private List ComputeContainedThing(Thing thing) - { - var containedGuid = new List(); - var nonPersistentType = this.ComputeNonPersistentPropertyType(thing); - - foreach (var container in thing.ContainerLists) - { - var type = container.GetType(); - var genericType = type.GetGenericArguments().Single(); - if (nonPersistentType.Contains(genericType)) - { - // non-persistent things are not added - continue; - } - - containedGuid.AddRange(from Thing containedThing in container select containedThing); - } - - return containedGuid; - } - - /// - /// Recursively marks a for removal and all its contained - /// - /// the to remove - private void RecursivelyMarksForRemoval(Thing thingToRemove) - { - foreach (var containerList in thingToRemove.ContainerLists) - { - foreach (Thing thing in containerList) - { - this.RecursivelyMarksForRemoval(thing); - } - } - - // marks thing for deletion - thingToRemove.ChangeKind = ChangeKind.Delete; - this.thingsMarkedForDeletion.Add(thingToRemove); - } - - /// - /// Remove a from the cache - /// - /// The to remove - /// True if the operation succeeded - private bool RemoveThingFromCache(Thing thingToRemove) - { - Lazy outLazy; - var succeed = this.Cache.TryRemove(thingToRemove.CacheId, out outLazy); - if (succeed) - { - CDPMessageBus.Current.SendObjectChangeEvent(outLazy.Value, EventKind.Removed); - } - - logger.Trace("Remove of thing with Iid {0} succeeded : {1}", thingToRemove, succeed); - return succeed; - } - - /// - /// Add/Update a set of {key, value} in the cache with POCO which referenced properties have not been resolved yet - /// - /// the DTO with data - private void AddOrUpdateTheCache(IEnumerable dtoThings) - { - var dtolist = dtoThings.ToList(); - - foreach (var dto in dtolist) - { - if (dto.Iid == Guid.Empty) - { - throw new ArgumentException(string.Format("Cannot add Dto with a Guid.Empty reference: {0}", dto.ClassKind)); - } - - var cacheKey = new Tuple(dto.Iid, dto.IterationContainerId); - this.Cache.AddOrUpdate(cacheKey, new Lazy(() => dto.InstantiatePoco(this.Cache, this.IDalUri)), (key, oldValue) => oldValue); - } - } - - /// - /// Delete all s contained the with the given - /// - /// The - /// - /// This is used to delete and when thei respective setup was deleted - /// - private void MarkAndDelete(Guid guid) - { - Lazy lazy; - if (this.Cache.TryGetValue(new Tuple(guid, null), out lazy)) - { - this.thingsMarkedForDeletion.Clear(); - this.RecursivelyMarksForRemoval(lazy.Value); - foreach (var markedThing in this.thingsMarkedForDeletion) - { - this.RemoveThingFromCache(markedThing); - } - - this.thingsMarkedForDeletion.Clear(); - } - } - #endregion Private Methods - } +#region Copyright +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2015-2018 RHEA System S.A. +// +// Author: Sam Gerené, Merlin Bieze, Alex Vorobiev, Naron Phou +// +// This file is part of CDP4-SDK Community Edition +// +// The CDP4-SDK Community Edition is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// The CDP4-SDK Community Edition is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// -------------------------------------------------------------------------------------------------------------------- +#endregion + +namespace CDP4Dal +{ + using System; + using System.Collections; + using System.Collections.Concurrent; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using System.Reflection; + using System.Threading; + using System.Threading.Tasks; + + using CDP4Common; + using CDP4Common.CommonData; + using CDP4Common.EngineeringModelData; + using CDP4Common.Helpers; + using CDP4Common.SiteDirectoryData; + using CDP4Common.Types; + using Events; + using NLog; + + using Dto = CDP4Common.DTO.Thing; + + /// + /// The Assembler orchestrates the interaction with the IDAL and the related Cache + /// + public class Assembler + { + #region Fields + /// + /// The associated with this assembler + /// + public readonly Uri IDalUri; + + /// + /// The current logger + /// + private static Logger logger = LogManager.GetCurrentClassLogger(); + + /// + /// The lock object + /// + private SemaphoreSlim threadLock = new SemaphoreSlim(1); + + /// + /// The unique + /// + private SiteDirectory siteDirectory; + + /// + /// The list of marked for deletion + /// + private List thingsMarkedForDeletion; + + /// + /// The not completely resolved that are in the cache + /// + private List unresolvedDtos; + #endregion + + /// + /// Initializes a new instance of the class. + /// + /// the associated with this + public Assembler(Uri uri) + { + Utils.AssertNotNull(uri, "The Uri may not be mull"); + + this.Cache = new ConcurrentDictionary, Lazy>(); + this.unresolvedDtos = new List(); + this.IDalUri = uri; + } + + #region Properties + + /// + /// Gets the Cache that contains all the s + /// + public ConcurrentDictionary, Lazy> Cache { get; private set; } + + /// + /// Gets or sets the list of to update + /// + private List DtoThingToUpdate { get; set; } + #endregion Properties + + #region Public Methods + + /// + /// Synchronize the Cache give an IEnumerable of DTO + /// + /// + /// the DTOs + /// + /// + /// An optional value indicating whether the should publish or not. + /// The default value is true + /// + /// + /// The that can be awaited. + /// + public async Task Synchronize(IEnumerable dtoThings, bool activeMessageBus = true) + { + if (dtoThings == null) + { + throw new ArgumentNullException("dtoThings"); + } + + await this.threadLock.WaitAsync().ConfigureAwait(false); + try + { + logger.Info("Start Synchronization of {0}", this.IDalUri); + this.thingsMarkedForDeletion = new List(); + + var synchronizeStopWatch = Stopwatch.StartNew(); + + logger.Trace("Starting Clean-up Unused references"); + var startwatch = Stopwatch.StartNew(); + + var existentGuid = + this.Cache.Select( + x => new Tuple, int>(x.Value.Value.CacheId, x.Value.Value.RevisionNumber)) + .ToList(); + + this.DtoThingToUpdate = dtoThings.ToList(); + + // Add the unresolved thing to the things to resolved in case it is possible to fully resolve them with the current update + // an example would be Citation contained by SiteDirectory where its Source is contained by a Rdl that is not loaded yet + var unresolvedThingToUpdate = this.unresolvedDtos.Where(x => !this.DtoThingToUpdate.Select(y => y.Iid).Contains(x.Iid)); + this.DtoThingToUpdate.AddRange(unresolvedThingToUpdate); + this.unresolvedDtos.Clear(); + + if (!this.Cache.IsEmpty) + { + // marks things for deletion + this.ComputeThingsToRemoveInUpdatedThings(); + startwatch.Stop(); + logger.Trace("Clean up Unused references took {0} [ms]", startwatch.ElapsedMilliseconds); + } + + logger.Trace("Start Updating cache"); + startwatch = Stopwatch.StartNew(); + this.AddOrUpdateTheCache(this.DtoThingToUpdate); + startwatch.Stop(); + logger.Trace("Updating cache took {0} [ms]", startwatch.ElapsedMilliseconds); + + logger.Trace("Start Resolving properties"); + startwatch = Stopwatch.StartNew(); + PocoThingFactory.ResolveDependencies(this.DtoThingToUpdate, this.Cache); + startwatch.Stop(); + logger.Trace("Resolving properties took {0} [ms]", startwatch.ElapsedMilliseconds); + + // validate POCO's + logger.Trace("Start validating Things"); + startwatch = Stopwatch.StartNew(); + foreach (var dtoThing in this.DtoThingToUpdate) + { + Lazy updatedLazyThing; + var cacheKey = new Tuple(dtoThing.Iid, dtoThing.IterationContainerId); + var succeed = this.Cache.TryGetValue(cacheKey, out updatedLazyThing); + + if (succeed) + { + var thingObject = updatedLazyThing.Value; + thingObject.ValidatePoco(); + + // add to the list of unresolved dtos if there is an error + if (thingObject.ValidationErrors.Any()) + { + this.unresolvedDtos.Add(dtoThing); + } + } + } + startwatch.Stop(); + logger.Trace("Validating {0} Things took {1} [ms]", this.DtoThingToUpdate.Count, startwatch.ElapsedMilliseconds); + + // message added and updated POCO's + if (activeMessageBus) + { + logger.Trace("Start Messaging"); + startwatch = Stopwatch.StartNew(); + + var messageCounter = 0; + + foreach (var dtoThing in this.DtoThingToUpdate) + { + Lazy updatedLazyThing; + var cacheKey = new Tuple(dtoThing.Iid, dtoThing.IterationContainerId); + var succeed = this.Cache.TryGetValue(cacheKey, out updatedLazyThing); + + if (succeed) + { + var thingObject = updatedLazyThing.Value; + var cacheId = new Tuple(dtoThing.Iid, dtoThing.IterationContainerId); + if (!existentGuid.Select(x => x.Item1).Contains(cacheId)) + { + CDPMessageBus.Current.SendObjectChangeEvent(thingObject, EventKind.Added); + messageCounter++; + } + else if (dtoThing.RevisionNumber > existentGuid.Single(x => x.Item1.Equals(cacheId)).Item2) + { + // send event only if revision number has increased from the old cached version + CDPMessageBus.Current.SendObjectChangeEvent(thingObject, EventKind.Updated); + messageCounter++; + } + } + } + + startwatch.Stop(); + logger.Trace("Messaging {0} Things took {1} [ms]", messageCounter, startwatch.ElapsedMilliseconds); + } + + logger.Trace("Start Deleting things"); + startwatch = Stopwatch.StartNew(); + foreach (var markedThing in this.thingsMarkedForDeletion.Where(x => x.ChangeKind == ChangeKind.Delete)) + { + this.RemoveThingFromCache(markedThing); + } + + var deletedIterationSetups = this.DtoThingToUpdate.OfType().Where(x => x.IsDeleted).ToList(); + var deletedModelSetups = this.thingsMarkedForDeletion.OfType().ToList(); + this.thingsMarkedForDeletion.Clear(); + + if (deletedIterationSetups.Any()) + { + foreach (var deletedIterationSetup in deletedIterationSetups) + { + this.MarkAndDelete(deletedIterationSetup.IterationIid); + } + } + + if (deletedModelSetups.Any()) + { + foreach (var deletedModelSetup in deletedModelSetups) + { + this.MarkAndDelete(deletedModelSetup.EngineeringModelIid); + } + } + + startwatch.Stop(); + logger.Trace("Deleting things took {0} [ms]", startwatch.ElapsedMilliseconds); + + this.DtoThingToUpdate.Clear(); + + if (this.siteDirectory == null) + { + var keyvaluepair = this.Cache.Single(item => item.Value.Value.ClassKind == ClassKind.SiteDirectory); + this.siteDirectory = (SiteDirectory)keyvaluepair.Value.Value; + } + + logger.Info("Finish Synchronization of {0} in {1} [ms]", this.IDalUri, synchronizeStopWatch.ElapsedMilliseconds); + } + catch (Exception e) + { + logger.Error(e.Message); + } + finally + { + this.threadLock.Release(); + logger.Trace("Assembler thread released"); + } + } + + /// + /// Clears the cache and sends removed event for s + /// + /// The + public async Task Clear() + { + await this.threadLock.WaitAsync().ConfigureAwait(false); + try + { + var iterations = + this.Cache.Select(x => x.Value) + .Where(lazy => lazy.Value.ClassKind == ClassKind.Iteration) + .Select(lazy => lazy.Value) + .Cast(); + + foreach (var iteration in iterations) + { + CDPMessageBus.Current.SendObjectChangeEvent(iteration, EventKind.Removed); + logger.Trace("iteration with iid {0} removed", iteration.Iid); + } + + var models = + this.Cache.Select(x => x.Value) + .Where(lazy => lazy.Value.ClassKind == ClassKind.EngineeringModel) + .Select(lazy => lazy.Value) + .Cast(); + + foreach (var model in models) + { + CDPMessageBus.Current.SendObjectChangeEvent(model, EventKind.Removed); + logger.Trace("model with iid {0} removed", model.Iid); + } + + this.siteDirectory = null; + this.Cache.Clear(); + } + catch (Exception e) + { + logger.Error(e.Message); + } + finally + { + this.threadLock.Release(); + } + } + + /// + /// Close a by clearing all its contained elements + /// + /// The to close + /// The async + public async Task CloseRdl(ReferenceDataLibrary rdl) + { + await this.threadLock.WaitAsync().ConfigureAwait(false); + try + { + var startwatch = Stopwatch.StartNew(); + this.thingsMarkedForDeletion = new List(); + foreach (var category in rdl.DefinedCategory) + { + this.RecursivelyMarksForRemoval(category); + } + + foreach (var parameterType in rdl.ParameterType) + { + this.RecursivelyMarksForRemoval(parameterType); + } + + foreach (var measurementScale in rdl.Scale) + { + this.RecursivelyMarksForRemoval(measurementScale); + } + + foreach (var unitPrefix in rdl.UnitPrefix) + { + this.RecursivelyMarksForRemoval(unitPrefix); + } + + foreach (var measurementUnit in rdl.Unit) + { + this.RecursivelyMarksForRemoval(measurementUnit); + } + + foreach (var filetype in rdl.FileType) + { + this.RecursivelyMarksForRemoval(filetype); + } + + foreach (var glossary in rdl.Glossary) + { + this.RecursivelyMarksForRemoval(glossary); + } + + foreach (var referenceSource in rdl.ReferenceSource) + { + this.RecursivelyMarksForRemoval(referenceSource); + } + + foreach (var rule in rdl.Rule) + { + this.RecursivelyMarksForRemoval(rule); + } + + foreach (var constant in rdl.Constant) + { + this.RecursivelyMarksForRemoval(constant); + } + + rdl.DefinedCategory.Clear(); + rdl.ParameterType.Clear(); + rdl.Scale.Clear(); + rdl.UnitPrefix.Clear(); + rdl.Unit.Clear(); + rdl.FileType.Clear(); + rdl.Glossary.Clear(); + rdl.ReferenceSource.Clear(); + rdl.Rule.Clear(); + rdl.Constant.Clear(); + rdl.BaseQuantityKind.Clear(); + rdl.BaseUnit.Clear(); + + foreach (var thing in this.thingsMarkedForDeletion) + { + this.RemoveThingFromCache(thing); + } + + CDPMessageBus.Current.SendObjectChangeEvent(rdl, EventKind.Updated); + + this.thingsMarkedForDeletion.Clear(); + logger.Trace("Finish closing of {0} ({1}) in {2} [ms]", rdl.Name, this.IDalUri, startwatch.ElapsedMilliseconds); + } + catch (Exception e) + { + logger.Error(e.Message); + } + finally + { + this.threadLock.Release(); + } + } + + /// + /// Close a by clearing all its contained elements + /// + /// + /// The to close + /// + /// + /// The . + /// + public async Task CloseIterationSetup(IterationSetup iterationSetup) + { + await this.threadLock.WaitAsync().ConfigureAwait(false); + try + { + Lazy lazyIteration; + if ( + !this.Cache.TryGetValue(new Tuple(iterationSetup.IterationIid, null), out lazyIteration)) + { + this.threadLock.Release(); + return; + } + + var iteration = lazyIteration.Value as Iteration; + if (iteration == null) + { + this.threadLock.Release(); + return; + } + + // Delete from the cache all things contained by the iteration without blocking the UI + await this.ClearFromCacheThingsContainedByIteration(iteration); + } + catch (Exception e) + { + logger.Error(e.Message); + } + finally + { + this.threadLock.Release(); + } + } + + /// + /// Clear from cache things contained by iteration. + /// + /// + /// The iteration. + /// + /// + /// The . + /// + private async Task ClearFromCacheThingsContainedByIteration(Iteration iteration) + { + var startwatch = Stopwatch.StartNew(); + + this.thingsMarkedForDeletion = new List(); + this.RecursivelyMarksForRemoval(iteration); + foreach (var thing in this.thingsMarkedForDeletion) + { + this.RemoveThingFromCache(thing); + } + + this.thingsMarkedForDeletion.Clear(); + logger.Trace("Finish closing iteration {0} ({1}) in {2} [ms]", iteration.Iid, this.IDalUri, startwatch.ElapsedMilliseconds); + } + + /// + /// Retrieves the single of this + /// + /// The + public SiteDirectory RetrieveSiteDirectory() + { + return this.siteDirectory; + } + + #endregion Public Methods + + #region Private Methods + + /// + /// Checks the status of the updated s in the Cache + /// + private void ComputeThingsToRemoveInUpdatedThings() + { + foreach (var dtoThing in this.DtoThingToUpdate) + { + this.ComputeThingsToRemove(dtoThing); + } + } + + /// + /// Removes s part of a composition with the associated to the if the references are no longer in the updated + /// + /// the to check + private void ComputeThingsToRemove(Dto dtoThing) + { + Lazy cachedLazyThing; + if (!this.Cache.TryGetValue(new Tuple(dtoThing.Iid, dtoThing.IterationContainerId), out cachedLazyThing)) + { + return; + } + + var dtoContainedGuid = this.ComputeContainedGuid(dtoThing); + var pocoContainedThing = this.ComputeContainedThing(cachedLazyThing.Value); + + var thingsToRemove = pocoContainedThing.Where(poco => !dtoContainedGuid.Contains(poco.Iid)).ToList(); + foreach (var thing in thingsToRemove) + { + // isPersistent + this.RecursivelyMarksForRemoval(thing); + } + } + + /// + /// Get the non-persistent property type in a + /// + /// The + /// An containing the type of s that are not persistent in the + private List ComputeNonPersistentPropertyType(Thing thing) + { + var nonPersistentType = new List(); + + var propInfos = thing.GetType().GetProperties(); + foreach (var propertyInfo in propInfos) + { + if(!propertyInfo.IsDefined(typeof(UmlInformationAttribute))) + { + continue; + } + + var metadata = propertyInfo.GetCustomAttribute(); + if (metadata.Aggregation == AggregationKind.Composite && !metadata.IsPersistent) + { + nonPersistentType.Add(propertyInfo.PropertyType.GetGenericArguments().Single()); + } + } + + return nonPersistentType; + } + + /// + /// Compute the contained for a + /// + /// The to compute + /// An containing all the contained + private List ComputeContainedGuid(Dto dto) + { + var containedGuid = new List(); + foreach (var container in dto.ContainerLists) + { + foreach (var obj in container) + { + var orderedItem = obj as OrderedItem; + if (orderedItem != null) + { + containedGuid.Add(new Guid(orderedItem.V.ToString())); + } + else + { + containedGuid.Add((Guid)obj); + } + } + } + + return containedGuid; + } + + /// + /// Compute the contained for a + /// + /// The to compute + /// An containing all the contained + private List ComputeContainedThing(Thing thing) + { + var containedGuid = new List(); + var nonPersistentType = this.ComputeNonPersistentPropertyType(thing); + + foreach (var container in thing.ContainerLists) + { + var type = container.GetType(); + var genericType = type.GetGenericArguments().Single(); + if (nonPersistentType.Contains(genericType)) + { + // non-persistent things are not added + continue; + } + + containedGuid.AddRange(from Thing containedThing in container select containedThing); + } + + return containedGuid; + } + + /// + /// Recursively marks a for removal and all its contained + /// + /// the to remove + private void RecursivelyMarksForRemoval(Thing thingToRemove) + { + foreach (var containerList in thingToRemove.ContainerLists) + { + foreach (Thing thing in containerList) + { + this.RecursivelyMarksForRemoval(thing); + } + } + + // marks thing for deletion + thingToRemove.ChangeKind = ChangeKind.Delete; + this.thingsMarkedForDeletion.Add(thingToRemove); + } + + /// + /// Remove a from the cache + /// + /// The to remove + /// True if the operation succeeded + private bool RemoveThingFromCache(Thing thingToRemove) + { + Lazy outLazy; + var succeed = this.Cache.TryRemove(thingToRemove.CacheId, out outLazy); + if (succeed) + { + CDPMessageBus.Current.SendObjectChangeEvent(outLazy.Value, EventKind.Removed); + } + + logger.Trace("Remove of thing with Iid {0} succeeded : {1}", thingToRemove, succeed); + return succeed; + } + + /// + /// Add/Update a set of {key, value} in the cache with POCO which referenced properties have not been resolved yet + /// + /// the DTO with data + private void AddOrUpdateTheCache(IEnumerable dtoThings) + { + var dtolist = dtoThings.ToList(); + + foreach (var dto in dtolist) + { + if (dto.Iid == Guid.Empty) + { + throw new ArgumentException(string.Format("Cannot add Dto with a Guid.Empty reference: {0}", dto.ClassKind)); + } + + var cacheKey = new Tuple(dto.Iid, dto.IterationContainerId); + this.Cache.AddOrUpdate(cacheKey, new Lazy(() => dto.InstantiatePoco(this.Cache, this.IDalUri)), (key, oldValue) => oldValue); + } + } + + /// + /// Delete all s contained the with the given + /// + /// The + /// + /// This is used to delete and when thei respective setup was deleted + /// + private void MarkAndDelete(Guid guid) + { + Lazy lazy; + if (this.Cache.TryGetValue(new Tuple(guid, null), out lazy)) + { + this.thingsMarkedForDeletion.Clear(); + this.RecursivelyMarksForRemoval(lazy.Value); + foreach (var markedThing in this.thingsMarkedForDeletion) + { + this.RemoveThingFromCache(markedThing); + } + + this.thingsMarkedForDeletion.Clear(); + } + } + #endregion Private Methods + } } \ No newline at end of file diff --git a/CDP4Dal/CDP4Dal.csproj b/CDP4Dal/CDP4Dal.csproj index 4cd37d45a..0e3baf3c2 100644 --- a/CDP4Dal/CDP4Dal.csproj +++ b/CDP4Dal/CDP4Dal.csproj @@ -4,10 +4,10 @@ net45;net451;net452;net46;net461;net462;net47;netstandard2.0 RHEA System S.A. CDP4Dal Community Edition - 1.1.0-rc1 + 1.1.1 CDP4 Data Access Layer library, a consumer of an ECSS-E-TM-10-25 Annex C API Copyright © RHEA System S.A. - Sam, Merlin, Alex, Naron, Patxi + Sam, Merlin, Alex, Naron CDP4Dal-CE true http://sdk.cdp4.org @@ -25,7 +25,7 @@ - + diff --git a/CDP4Dal/Session.cs b/CDP4Dal/Session.cs index 9c21b38db..13c788bf9 100644 --- a/CDP4Dal/Session.cs +++ b/CDP4Dal/Session.cs @@ -28,6 +28,7 @@ namespace CDP4Dal { using System; using System.Collections.Generic; + using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -287,6 +288,8 @@ public IEnumerable GetEngineeringModelSetupRdlChain(Engine /// public async Task Open() { + var sw = new Stopwatch(); + sw.Start(); logger.Info("Open request {0}", this.DataSourceUri); // Create the token source @@ -312,12 +315,12 @@ public async Task Open() await this.Assembler.Synchronize(dtoThings); CDPMessageBus.Current.SendMessage(new SessionEvent(this, SessionStatus.EndUpdate)); - logger.Info("Synchronization with the {0} server done", this.DataSourceUri); + logger.Info("Synchronization with the {0} server done in {1} [ms]", this.DataSourceUri, sw.ElapsedMilliseconds); var sessionChange = new SessionEvent(this, SessionStatus.Open); CDPMessageBus.Current.SendMessage(sessionChange); - logger.Info("Session {0} opened successfully", this.DataSourceUri); + logger.Info("Session {0} opened successfully in {1} [ms]", this.DataSourceUri, sw.ElapsedMilliseconds); } /// diff --git a/CDP4JsonFileDal.Tests/CDP4JsonFileDal.Tests.csproj b/CDP4JsonFileDal.Tests/CDP4JsonFileDal.Tests.csproj index 5c068cf5a..bdf045b6a 100644 --- a/CDP4JsonFileDal.Tests/CDP4JsonFileDal.Tests.csproj +++ b/CDP4JsonFileDal.Tests/CDP4JsonFileDal.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/CDP4JsonFileDal/CDP4JsonFileDal.csproj b/CDP4JsonFileDal/CDP4JsonFileDal.csproj index 203acd245..0baa0e947 100644 --- a/CDP4JsonFileDal/CDP4JsonFileDal.csproj +++ b/CDP4JsonFileDal/CDP4JsonFileDal.csproj @@ -4,7 +4,7 @@ net45;net451;net452;net46;net461;net462;net47 RHEA System S.A. CDP4JsonFileDal Community Edition - 1.1.0-rc1 + 1.1.1 CDP4 Json File Dal Plugin Copyright © RHEA System S.A. Sam, Merlin, Alex, Naron @@ -22,8 +22,8 @@ - - + + diff --git a/CDP4JsonFileDal/JsonFileDal.cs b/CDP4JsonFileDal/JsonFileDal.cs index d8732f4c9..cfe200ec1 100644 --- a/CDP4JsonFileDal/JsonFileDal.cs +++ b/CDP4JsonFileDal/JsonFileDal.cs @@ -1271,7 +1271,7 @@ private List ReadInfoFromArchiveEntry(ZipEntry zipEntry, string archivePa } watch.Stop(); - Logger.Info("ZipEntry {0} retrieved {1} ", zipEntry.FileName, watch.Elapsed); + Logger.Info("ZipEntry {0} retrieved in {1} [ms]", zipEntry.FileName, watch.ElapsedMilliseconds); watch = Stopwatch.StartNew(); @@ -1280,7 +1280,7 @@ private List ReadInfoFromArchiveEntry(ZipEntry zipEntry, string archivePa stream.Dispose(); watch.Stop(); - Logger.Info("JSON Deserializer of {0} completed in {1} ", zipEntry.FileName, watch.Elapsed); + Logger.Info("JSON Deserializer of {0} completed in {1} [ms]", zipEntry.FileName, watch.ElapsedMilliseconds); return returned; } } diff --git a/CDP4JsonSerializer.NetCore.Tests/CDP4JsonSerializer.NetCore.Tests.csproj b/CDP4JsonSerializer.NetCore.Tests/CDP4JsonSerializer.NetCore.Tests.csproj index 600b25a83..1d6f78d43 100644 --- a/CDP4JsonSerializer.NetCore.Tests/CDP4JsonSerializer.NetCore.Tests.csproj +++ b/CDP4JsonSerializer.NetCore.Tests/CDP4JsonSerializer.NetCore.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/CDP4JsonSerializer.Tests/CDP4JsonSerializer.Tests.csproj b/CDP4JsonSerializer.Tests/CDP4JsonSerializer.Tests.csproj index 9e498d0c0..21ad778ee 100644 --- a/CDP4JsonSerializer.Tests/CDP4JsonSerializer.Tests.csproj +++ b/CDP4JsonSerializer.Tests/CDP4JsonSerializer.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/CDP4JsonSerializer/CDP4JsonSerializer.csproj b/CDP4JsonSerializer/CDP4JsonSerializer.csproj index 926eb608a..92588b36e 100644 --- a/CDP4JsonSerializer/CDP4JsonSerializer.csproj +++ b/CDP4JsonSerializer/CDP4JsonSerializer.csproj @@ -4,7 +4,7 @@ net45;net451;net452;net46;net461;net462;net47;netstandard1.6;netstandard2.0 RHEA System S.A. CDP4JsonSerializer Community Edition - 1.1.0-rc1 + 1.1.1 CDP4 JSON Serialization Library Copyright © RHEA System S.A. Sam, Merlin, Alex, Naron @@ -17,7 +17,7 @@ https://github.com/RHEAGROUP/CDP4-SDK-Community-Edition/blob/master/COPYING.LESSER [Update] Newtonsoft.Json version 11.0.2 - [Update] to CDP4Common-CE version 1.1.0-rc1 + [Update] to CDP4Common-CE version 1.1.0 Debug;Release;Dev @@ -25,7 +25,7 @@ - + diff --git a/CDP4JsonSerializer/Cdp4JsonSerializer.cs b/CDP4JsonSerializer/Cdp4JsonSerializer.cs index faca0b652..82dfefb63 100644 --- a/CDP4JsonSerializer/Cdp4JsonSerializer.cs +++ b/CDP4JsonSerializer/Cdp4JsonSerializer.cs @@ -119,11 +119,12 @@ public void SerializeToStream(object collectionSource, Stream outputStream) Logger.Trace("initializing JsonTextWriter"); var jsonWriter = new JsonTextWriter(new StreamWriter(outputStream)); + Logger.Trace("Serialize to JsonTextWriter"); serializer.Serialize(jsonWriter, collectionSource); jsonWriter.Flush(); sw.Stop(); - Logger.Debug("SerializeToStream in {0} [ms]", sw.Elapsed); + Logger.Debug("SerializeToStream in {0} [ms]", sw.ElapsedMilliseconds); } /// @@ -251,7 +252,10 @@ public T Deserialize(Stream contentStream) using (var streamReader = new StreamReader(contentStream)) using (var jsonTextReader = new JsonTextReader(streamReader)) { + var sw = new Stopwatch(); + sw.Start(); data = serializer.Deserialize(jsonTextReader); + Logger.Trace("Deserialize to stream {0} [ms]", sw.ElapsedMilliseconds); } return data; diff --git a/CDP4ServicesDal.NetCore.Tests/CDP4ServicesDal.NetCore.Tests.csproj b/CDP4ServicesDal.NetCore.Tests/CDP4ServicesDal.NetCore.Tests.csproj index 8f6d13066..727df0eca 100644 --- a/CDP4ServicesDal.NetCore.Tests/CDP4ServicesDal.NetCore.Tests.csproj +++ b/CDP4ServicesDal.NetCore.Tests/CDP4ServicesDal.NetCore.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/CDP4ServicesDal.Tests/CDP4ServicesDal.Tests.csproj b/CDP4ServicesDal.Tests/CDP4ServicesDal.Tests.csproj index d775be550..76e148208 100644 --- a/CDP4ServicesDal.Tests/CDP4ServicesDal.Tests.csproj +++ b/CDP4ServicesDal.Tests/CDP4ServicesDal.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/CDP4ServicesDal/CDP4ServicesDal.csproj b/CDP4ServicesDal/CDP4ServicesDal.csproj index 7f511e60f..23b3a3d2c 100644 --- a/CDP4ServicesDal/CDP4ServicesDal.csproj +++ b/CDP4ServicesDal/CDP4ServicesDal.csproj @@ -4,7 +4,7 @@ net45;net451;net452;net46;net461;net462;net47;netstandard2.0 RHEA System S.A. CDP4ServicesDal Community Edition - 1.1.0-rc1 + 1.1.1 CDP4ServicesDal Dal Plugin Copyright © RHEA System S.A. Sam, Merlin, Alex, Naron @@ -16,7 +16,7 @@ CDP CDP4 ECSS-E-TM-10-25 https://github.com/RHEAGROUP/CDP4-SDK-Community-Edition/blob/master/COPYING.LESSER - [Update] to CDP4JsonSerializer-CE and CDP4Dal-CE version 1.1.0-rc1. + [Update] to CDP4JsonSerializer-CE and CDP4Dal-CE version 1.1.0 [Add] cross model copy capability Debug;Release;Dev @@ -25,8 +25,8 @@ - - + + diff --git a/CDP4ServicesDal/CdpServicesDal.cs b/CDP4ServicesDal/CdpServicesDal.cs index e7bc78c60..c2178076e 100644 --- a/CDP4ServicesDal/CdpServicesDal.cs +++ b/CDP4ServicesDal/CdpServicesDal.cs @@ -153,8 +153,13 @@ public override async Task> Write(OperationContainer operatio var requestContent = this.CreateHttpContent(postToken, operationContainer, files); + var requestsw = Stopwatch.StartNew(); + using (var httpResponseMessage = await this.httpClient.PostAsync(resourcePath, requestContent)) { + Logger.Info("CDP4 Services responded in {0} [ms] to POST {1}", requestsw.ElapsedMilliseconds, postToken); + requestsw.Stop(); + if (httpResponseMessage.StatusCode != HttpStatusCode.OK) { var errorResponse = await httpResponseMessage.Content.ReadAsStringAsync(); @@ -174,9 +179,6 @@ public override async Task> Write(OperationContainer operatio { this.SetIterationContainer(result, iterationId); } - - watch.Stop(); - Logger.Info("JSON Deserializer completed in {0} ", watch.Elapsed); } } @@ -198,6 +200,9 @@ public override async Task> Write(OperationContainer operatio } } + watch.Stop(); + Logger.Info("Write Operation completed in {0} [ms]", watch.ElapsedMilliseconds); + return result; } @@ -262,14 +267,12 @@ public override async Task> Read(CDP4Common.DTO.Iteration ite var modelReferenceDataLibraryDto = modelReferenceDataLibrary.ToDto(); - var tasks = new List>>(); - tasks.Add(this.Read(modelReferenceDataLibraryDto, cancellationToken)); - tasks.Add(this.Read((Thing)iteration, cancellationToken)); - - var returned = await Task.WhenAll(tasks); - var returnedDto = returned.SelectMany(x => x.ToList()).ToList(); - - return returnedDto; + var result = new List(); + var referenceData = await this.Read(modelReferenceDataLibraryDto, cancellationToken); + result.AddRange(referenceData); + var engineeringModelData = await this.Read((Thing)iteration, cancellationToken); + result.AddRange(engineeringModelData); + return result; } /// @@ -319,8 +322,13 @@ public override async Task> Read(T thing, CancellationToke var uriBuilder = new UriBuilder(this.Credentials.Uri) { Path = resourcePath }; Logger.Debug("CDP4Services GET {0}: {1}", readToken, uriBuilder); + var requestsw = Stopwatch.StartNew(); + using (var httpResponseMessage = await this.httpClient.GetAsync(resourcePath, HttpCompletionOption.ResponseHeadersRead, cancellationToken)) { + Logger.Info("CDP4 Services responded in {0} [ms] to GET {1}", requestsw.ElapsedMilliseconds, readToken); + requestsw.Stop(); + if (httpResponseMessage.StatusCode != HttpStatusCode.OK) { var msg = $"The data-source replied with code {httpResponseMessage.StatusCode}: {httpResponseMessage.ReasonPhrase}"; @@ -341,7 +349,7 @@ public override async Task> Read(T thing, CancellationToke } watch.Stop(); - Logger.Info("JSON Deserializer completed in {0} ", watch.Elapsed); + Logger.Info("JSON Deserializer completed in {0} [ms]", watch.ElapsedMilliseconds); return returned; } @@ -459,8 +467,13 @@ public override async Task> Open(Credentials credentials, Can var uriBuilder = new UriBuilder(credentials.Uri) { Path = resourcePath }; Logger.Debug("CDP4Services Open {0}: {1}", openToken, uriBuilder); + var requestsw = Stopwatch.StartNew(); + using (var httpResponseMessage = await this.httpClient.GetAsync(resourcePath, HttpCompletionOption.ResponseHeadersRead, cancellationToken: cancellationToken)) { + Logger.Info("CDP4 Services responded in {0} [ms] to Open {1}", requestsw.ElapsedMilliseconds, openToken); + requestsw.Stop(); + if (httpResponseMessage.StatusCode != HttpStatusCode.OK) { var msg = $"The data-source replied with code {httpResponseMessage.StatusCode}: {httpResponseMessage.ReasonPhrase}"; @@ -469,7 +482,7 @@ public override async Task> Open(Credentials credentials, Can } watch.Stop(); - Logger.Info("CDP4Services Open {0} completed in {1} ", openToken, watch.Elapsed); + Logger.Info("CDP4Services Open {0}: {1} completed in {2} [ms]", openToken, uriBuilder, watch.ElapsedMilliseconds); this.ProcessHeaders(httpResponseMessage); @@ -480,7 +493,7 @@ public override async Task> Open(Credentials credentials, Can var returned = this.Serializer.Deserialize(resultStream); watch.Stop(); - Logger.Info("JSON Deserializer completed in {0} ", watch.Elapsed); + Logger.Info("JSON Deserializer completed in {0} [ms]", watch.ElapsedMilliseconds); var returnedPerson = returned.OfType().SingleOrDefault(x => x.ShortName == credentials.UserName); if (returnedPerson == null) diff --git a/CDP4WspDal.NetCore.Tests/CDP4WspDal.NetCore.Tests.csproj b/CDP4WspDal.NetCore.Tests/CDP4WspDal.NetCore.Tests.csproj index 62ac28be5..ef478fb83 100644 --- a/CDP4WspDal.NetCore.Tests/CDP4WspDal.NetCore.Tests.csproj +++ b/CDP4WspDal.NetCore.Tests/CDP4WspDal.NetCore.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/CDP4WspDal.Tests/CDP4WspDal.Tests.csproj b/CDP4WspDal.Tests/CDP4WspDal.Tests.csproj index 827d7b899..8009f0222 100644 --- a/CDP4WspDal.Tests/CDP4WspDal.Tests.csproj +++ b/CDP4WspDal.Tests/CDP4WspDal.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/CDP4WspDal/CDP4WspDal.csproj b/CDP4WspDal/CDP4WspDal.csproj index bc537b8dd..7e5b38b1a 100644 --- a/CDP4WspDal/CDP4WspDal.csproj +++ b/CDP4WspDal/CDP4WspDal.csproj @@ -4,7 +4,7 @@ net45;net451;net452;net46;net461;net462;net47;netstandard2.0 RHEA System S.A. CDP4WspDal Community Edition - 1.1.0-rc1 + 1.1.1 CDP4 WSP Dal Plugin Copyright © RHEA System S.A. Sam, Merlin, Alex, Naron @@ -16,7 +16,7 @@ CDP CDP4 ECSS-E-TM-10-25 https://github.com/RHEAGROUP/CDP4-SDK-Community-Edition/blob/master/COPYING.LESSER - [Update] to CDP4JsonSerializer-CE and CDP4Dal-CE version 1.1.0-rc1. + [Update] to CDP4JsonSerializer-CE and CDP4Dal-CE version 1.1.0 [Cleanup] WspDal Debug;Release;Dev @@ -25,8 +25,8 @@ - - + + diff --git a/CDP4WspDal/WSPDal.cs b/CDP4WspDal/WSPDal.cs index f720dd865..bcf60ffcd 100644 --- a/CDP4WspDal/WSPDal.cs +++ b/CDP4WspDal/WSPDal.cs @@ -151,8 +151,13 @@ public override async Task> Write(OperationContainer operatio var requestContent = this.CreateHttpContent(postToken, operationContainer, files); + var requestsw = Stopwatch.StartNew(); + using (var httpResponseMessage = await this.httpClient.PostAsync(resourcePath, requestContent)) { + Logger.Info("The ECSS-E-TM-10-25A Annex C Services responded in {0} [ms] to POST {1}", requestsw.ElapsedMilliseconds, postToken); + requestsw.Stop(); + if (httpResponseMessage.StatusCode != HttpStatusCode.OK) { var errorResponse = await httpResponseMessage.Content.ReadAsStringAsync(); @@ -170,9 +175,6 @@ public override async Task> Write(OperationContainer operatio { this.SetIterationContainer(result, iterationId); } - - watch.Stop(); - Logger.Info("JSON Deserializer completed in {0} ", watch.Elapsed); } } @@ -194,6 +196,9 @@ public override async Task> Write(OperationContainer operatio } } + watch.Stop(); + Logger.Info("Write Operation completed in {0} [ms]", watch.ElapsedMilliseconds); + return result; } @@ -258,14 +263,12 @@ public override async Task> Read(CDP4Common.DTO.Iteration ite var modelReferenceDataLibraryDto = modelReferenceDataLibrary.ToDto(); - var tasks = new List>>(); - tasks.Add(this.Read(modelReferenceDataLibraryDto, cancellationToken)); - tasks.Add(this.Read((Thing)iteration, cancellationToken)); - - var returned = await Task.WhenAll(tasks); - var returnedDto = returned.SelectMany(x => x.ToList()).ToList(); - - return returnedDto; + var result = new List(); + var referenceData = await this.Read(modelReferenceDataLibraryDto, cancellationToken); + result.AddRange(referenceData); + var engineeringModelData = await this.Read((Thing)iteration, cancellationToken); + result.AddRange(engineeringModelData); + return result; } /// @@ -315,8 +318,13 @@ public override async Task> Read(T thing, CancellationToke var uriBuilder = new UriBuilder(this.Credentials.Uri) { Path = resourcePath }; Logger.Debug("WSP GET {0}: {1}", readToken, uriBuilder); + var requestsw = Stopwatch.StartNew(); + using (var httpResponseMessage = await this.httpClient.GetAsync(resourcePath, HttpCompletionOption.ResponseHeadersRead, cancellationToken)) { + Logger.Info("The ECSS-E-TM-10-25A Annex C Services responded in {0} [ms] to GET {1}", requestsw.ElapsedMilliseconds, readToken); + requestsw.Stop(); + if (httpResponseMessage.StatusCode != HttpStatusCode.OK) { var msg = $"The data-source replied with code {httpResponseMessage.StatusCode}: {httpResponseMessage.ReasonPhrase}"; @@ -335,7 +343,7 @@ public override async Task> Read(T thing, CancellationToke } watch.Stop(); - Logger.Info("JSON Deserializer completed in {0} ", watch.Elapsed); + Logger.Info("JSON Deserializer completed in {0} [ms]", watch.ElapsedMilliseconds); return returned; } @@ -452,8 +460,13 @@ public override async Task> Open(Credentials credentials, Can var uriBuilder = new UriBuilder(credentials.Uri) { Path = resourcePath }; Logger.Debug("WSP Open {0}: {1}", openToken, uriBuilder); + var requestsw = Stopwatch.StartNew(); + using (var httpResponseMessage = await this.httpClient.GetAsync(resourcePath, HttpCompletionOption.ResponseHeadersRead, cancellationToken: cancellationToken)) { + Logger.Info("The ECSS-E-TM-10-25A Annex C Services responded in {0} [ms] to Open {1}", requestsw.ElapsedMilliseconds, openToken); + requestsw.Stop(); + if (httpResponseMessage.StatusCode != HttpStatusCode.OK) { var msg = $"The data-source replied with code {httpResponseMessage.StatusCode}: {httpResponseMessage.ReasonPhrase}"; @@ -462,7 +475,7 @@ public override async Task> Open(Credentials credentials, Can } watch.Stop(); - Logger.Info("WSP DAL Open {0} completed in {1} ", openToken, watch.Elapsed); + Logger.Info("WSP DAL Open {0} completed in {1} [ms]", openToken, watch.ElapsedMilliseconds); watch = Stopwatch.StartNew(); @@ -471,7 +484,7 @@ public override async Task> Open(Credentials credentials, Can var returned = this.Serializer.Deserialize(resultStream); watch.Stop(); - Logger.Info("JSON Deserializer completed in {0} ", watch.Elapsed); + Logger.Info("JSON Deserializer completed in {0} [ms]", watch.ElapsedMilliseconds); var returnedPerson = returned.OfType().SingleOrDefault(x => x.ShortName == credentials.UserName); if (returnedPerson == null)