/// <summary> /// Recursively Create <see cref="NestedElement"/>s /// </summary> /// <param name="elementDefinition"> /// The <see cref="ElementDefinition"/> that contains <see cref="ElementUsage"/>s that /// </param> /// <param name="rootElement"> /// The <see cref="ElementDefinition"/> that is the root of the <see cref="NestedElement"/> tree. /// </param> /// <param name="domainOfExpertise"> /// The <see cref="DomainOfExpertise"/> for which the <see cref="NestedElement"/> tree needs to be generated. Only the <see cref="Parameter"/>s, <see cref="ParameterOverride"/>s and /// <see cref="ParameterSubscription"/>s that are owned by the <see cref="DomainOfExpertise"/> will be taken into account when generating <see cref="NestedParameter"/>s /// </param> /// <param name="elementUsages"> /// A <see cref="List{ElementUsage}"/> that contains the <see cref="ElementUsage"/> that define the containment tree /// for the <see cref="NestedElement"/>s at the level of the <paramref name="elementDefinition"/>. /// </param> /// <param name="option"> /// The <see cref="Option"/> for which the <see cref="NestedElement"/> tree is created. When the <see cref="Option"/> /// is null then none of the <see cref="ElementUsage"/>s are filtered. /// </param> /// <param name="updateOption"> /// Value indicating whether the <see cref="Option"/> shall be updated with the created <see cref="NestedElement"/>s or not. /// </param> /// <returns> /// The <see cref="IEnumerable{NestedElement}"/> that have been created. /// </returns> private IEnumerable <NestedElement> RecursivelyCreateNestedElements(ElementDefinition elementDefinition, ElementDefinition rootElement, DomainOfExpertise domainOfExpertise, List <ElementUsage> elementUsages, Option option, bool updateOption) { var cache = elementDefinition.Cache; var uri = elementDefinition.IDalUri; foreach (var elementUsage in elementDefinition.ContainedElement) { // comparison is done based on unique identifiers, not on object level. The provided option may be a clone if (elementUsage.ExcludeOption.Any(x => x.Iid == option.Iid)) { Logger.Debug($"ElementUsage {elementUsage.Iid}:{elementUsage.ShortName} is excluded from the Nested Elements."); continue; } var nestedElement = new NestedElement(Guid.NewGuid(), cache, uri) { RootElement = rootElement, IsVolatile = true }; if (updateOption) { option.NestedElement.Add(nestedElement); } else { nestedElement.Container = option; } var nestedParameters = this.CreateNestedParameters(elementUsage, domainOfExpertise, option); foreach (var nestedParameter in nestedParameters) { nestedElement.NestedParameter.Add(nestedParameter); } var containmentUsages = new List <ElementUsage>(); foreach (var usage in elementUsages) { nestedElement.ElementUsage.Add(usage); containmentUsages.Add(usage); } nestedElement.ElementUsage.Add(elementUsage); containmentUsages.Add(elementUsage); var referencedElementDefinition = elementUsage.ElementDefinition; var nestedElements = this.RecursivelyCreateNestedElements(referencedElementDefinition, rootElement, domainOfExpertise, containmentUsages, option, updateOption); foreach (var element in nestedElements) { yield return(element); } yield return(nestedElement); } }
/// <summary> /// Initializes a new instance of the <see cref="DataCollectorNode{T}"/> class. /// </summary> /// <param name="categoryDecompositionHierarchy"> /// The <see cref="CategoryDecompositionHierarchy"/> associated with this node's subtree. /// </param> /// <param name="topElement"> /// The <see cref="CDP4Common.EngineeringModelData.NestedElement"/> associated with this node. /// </param> /// <param name="parent"> /// The parent node in the hierarhical tree upon which the data collector is based. /// </param> public DataCollectorNode( CategoryDecompositionHierarchy categoryDecompositionHierarchy, NestedElement topElement, DataCollectorNode <T> parent = null) { this.Initialize(); this.NestedElement = topElement; this.parent = parent; this.InitializeCategoryDecompositionHierarchy(categoryDecompositionHierarchy); }
/// <summary> /// Serialize the <see cref="NestedElement"/> /// </summary> /// <param name="nestedElement">The <see cref="NestedElement"/> to serialize</param> /// <returns>The <see cref="JObject"/></returns> private JObject Serialize(NestedElement nestedElement) { var jsonObject = new JObject(); jsonObject.Add("classKind", this.PropertySerializerMap["classKind"](Enum.GetName(typeof(CDP4Common.CommonData.ClassKind), nestedElement.ClassKind))); jsonObject.Add("elementUsage", this.PropertySerializerMap["elementUsage"](nestedElement.ElementUsage.OrderBy(x => x, this.orderedItemComparer))); jsonObject.Add("excludedDomain", this.PropertySerializerMap["excludedDomain"](nestedElement.ExcludedDomain.OrderBy(x => x, this.guidComparer))); jsonObject.Add("excludedPerson", this.PropertySerializerMap["excludedPerson"](nestedElement.ExcludedPerson.OrderBy(x => x, this.guidComparer))); jsonObject.Add("iid", this.PropertySerializerMap["iid"](nestedElement.Iid)); jsonObject.Add("isVolatile", this.PropertySerializerMap["isVolatile"](nestedElement.IsVolatile)); jsonObject.Add("modifiedOn", this.PropertySerializerMap["modifiedOn"](nestedElement.ModifiedOn)); jsonObject.Add("nestedParameter", this.PropertySerializerMap["nestedParameter"](nestedElement.NestedParameter.OrderBy(x => x, this.guidComparer))); jsonObject.Add("revisionNumber", this.PropertySerializerMap["revisionNumber"](nestedElement.RevisionNumber)); jsonObject.Add("rootElement", this.PropertySerializerMap["rootElement"](nestedElement.RootElement)); jsonObject.Add("thingPreference", this.PropertySerializerMap["thingPreference"](nestedElement.ThingPreference)); return(jsonObject); }
/// <summary> /// Gets the tree of <see cref="DataCollectorNode{T}"/>s. This method can call itself recursively. /// </summary> /// <param name="nestedElement"> /// The <see cref="NestedElement"/> /// </param> /// <param name="categoryDecompositionHierarchy"> /// The <see cref="CategoryDecompositionHierarchy"/> used for filtering the considered <see cref="NestedElement"/> items. /// </param> /// <param name="nestedElements"> /// The <see cref="List{NestedElement}"/>s /// </param> /// <param name="parentNode"> /// The <see cref=" DataCollectorNode{T}"/> that is the parent of new nodes. /// </param> /// <returns> /// An <see cref="IEnumerable{T}"/> of <see cref="DataCollectorNode{T}"/> /// </returns> private IEnumerable <DataCollectorNode <T> > GetDataCollectorNodes(NestedElement nestedElement, CategoryDecompositionHierarchy categoryDecompositionHierarchy, List <NestedElement> nestedElements, DataCollectorNode <T> parentNode) { var resultNodes = new List <DataCollectorNode <T> >(); DataCollectorNode <T> newNode = null; var searchCategory = categoryDecompositionHierarchy; if (categoryDecompositionHierarchy.Child != null && parentNode?.CountCategoryRecursionLevel(categoryDecompositionHierarchy.Category) > 0 && nestedElement.IsMemberOfCategory(categoryDecompositionHierarchy.Child.Category)) { searchCategory = categoryDecompositionHierarchy.Child; newNode = new DataCollectorNode <T>(searchCategory, nestedElement, parentNode); parentNode.Children.Add(newNode); resultNodes.Add(newNode); } else if (nestedElement.IsMemberOfCategory(categoryDecompositionHierarchy.Category)) { newNode = new DataCollectorNode <T>(categoryDecompositionHierarchy, nestedElement, parentNode); parentNode?.Children.Add(newNode); resultNodes.Add(newNode); } else if (!(categoryDecompositionHierarchy.Child?.AllowSkipUnknownCategories ?? true)) { return(resultNodes); } var children = nestedElement.GetChildren(nestedElements).ToList(); foreach (var child in children) { var nodes = this.GetDataCollectorNodes(child, searchCategory, nestedElements, newNode ?? parentNode).ToArray(); if (newNode == null && nodes.Any()) { resultNodes = resultNodes.Concat(nodes).ToList(); } } return(resultNodes); }
/// <summary> /// Persist the <see cref="NestedElement"/> containment tree to the ORM layer. Update if it already exists. /// This is typically used during the import of existing data to the Database. /// </summary> /// <param name="transaction"> /// The current <see cref="NpgsqlTransaction"/> to the database. /// </param> /// <param name="partition"> /// The database partition (schema) where the requested resource will be stored. /// </param> /// <param name="nestedElement"> /// The <see cref="NestedElement"/> instance to persist. /// </param> /// <returns> /// True if the persistence was successful. /// </returns> private bool UpsertContainment(NpgsqlTransaction transaction, string partition, NestedElement nestedElement) { var results = new List <bool>(); foreach (var nestedParameter in this.ResolveFromRequestCache(nestedElement.NestedParameter)) { results.Add(this.NestedParameterService.UpsertConcept(transaction, partition, nestedParameter, nestedElement)); } return(results.All(x => x)); }
/// <summary> /// Add an Nested Element row view model to the list of <see cref="NestedElement"/> /// </summary> /// <param name="nestedElement"> /// The <see cref="NestedElement"/> that is to be added /// </param> private NestedElementRowViewModel AddNestedElementRowViewModel(NestedElement nestedElement) { return(new NestedElementRowViewModel(nestedElement, this.Session, this)); }
/// <summary> /// Creates The <see cref="NestedElement"/> and contained <see cref="NestedParameter"/> that represents the <paramref name="rootElement"/> /// </summary> /// <param name="rootElement"> /// The <see cref="ElementDefinition"/> that is the root of the <see cref="NestedElement"/> tree. /// </param> /// <param name="domainOfExpertise"> /// The <see cref="DomainOfExpertise"/> for which the <see cref="NestedElement"/> tree needs to be generated. Only the <see cref="Parameter"/>s, <see cref="ParameterOverride"/>s and /// <see cref="ParameterSubscription"/>s that are owned by the <see cref="DomainOfExpertise"/> will be taken into account when generating <see cref="NestedParameter"/>s /// </param> /// <param name="option"> /// The <see cref="Option"/> for which the <see cref="NestedElement"/> tree is created. When the <see cref="Option"/> /// is null then none of the <see cref="ElementUsage"/>s are filtered. /// </param> /// <param name="updateOption"> /// Value indicating whether the <see cref="Option"/> shall be updated with the created <see cref="NestedElement"/>s or not. /// </param> /// <returns> /// The <see cref="IEnumerable{NestedElement}"/> that have been created. /// </returns> private NestedElement CreateNestedElementAndNestedParametersForRootElement(ElementDefinition rootElement, DomainOfExpertise domainOfExpertise, Option option, bool updateOption) { var nestedElement = new NestedElement(Guid.NewGuid(), rootElement.Cache, rootElement.IDalUri) { RootElement = rootElement, IsVolatile = true, IsRootElement = true }; if (updateOption) { option.NestedElement.Add(nestedElement); } else { nestedElement.Container = option; } foreach (var parameter in rootElement.Parameter) { var compoundParameterType = parameter.ParameterType as CompoundParameterType; if (domainOfExpertise == null || parameter.Owner == domainOfExpertise) { var valueSets = parameter.IsOptionDependent ? parameter.ValueSet.Where(vs => vs.ActualOption == option).ToList() : parameter.ValueSet; foreach (var parameterValueSet in valueSets) { if (compoundParameterType == null) { var nestedParameter = this.CreatedNestedParameter(parameter, null, parameterValueSet, option); nestedElement.NestedParameter.Add(nestedParameter); } else { foreach (var component in compoundParameterType.Component) { var comp = (ParameterTypeComponent)component; var nestedParameter = this.CreatedNestedParameter(parameter, comp, parameterValueSet, option); nestedElement.NestedParameter.Add(nestedParameter); } } } } else { var subscription = parameter.ParameterSubscription.SingleOrDefault(ps => ps.Owner == domainOfExpertise); if (subscription != null) { var nestedParameters = this.CreatedNestedParameters(subscription, option, compoundParameterType); foreach (var nestedParameter in nestedParameters) { nestedElement.NestedParameter.Add(nestedParameter); } } } } return(nestedElement); }
public virtual void Setup() { this.Assembler = new Assembler(this.Uri); this.Domain = new DomainOfExpertise(Guid.NewGuid(), this.Assembler.Cache, this.Uri) { ShortName = "test" }; this.Person = new Person(Guid.NewGuid(), this.Assembler.Cache, this.Uri) { DefaultDomain = this.Domain }; this.Participant = new Participant(Guid.NewGuid(), this.Assembler.Cache, this.Uri); this.Option = new Option(Guid.NewGuid(), this.Assembler.Cache, this.Uri) { Name = "TestOption", }; this.SetupElements(); this.ElementUsage = new ElementUsage(Guid.NewGuid(), this.Assembler.Cache, this.Uri) { Name = "testName", ShortName = "testShortName", Owner = this.Domain, ElementDefinition = this.ElementDefinition1, Category = new List <Category>() { new Category(Guid.NewGuid(), this.Assembler.Cache, this.Uri) { ShortName = "Test" } } }; this.NestedElement = new NestedElement(Guid.NewGuid(), this.Assembler.Cache, this.Uri) { RootElement = this.TopElement, Container = this.Option, ElementUsage = new OrderedItemList <ElementUsage>(null) { this.ElementUsage1 } }; this.EngineeringModelSetup = new EngineeringModelSetup(Guid.NewGuid(), this.Assembler.Cache, this.Uri) { Name = "test", Participant = { new Participant(Guid.NewGuid(), this.Assembler.Cache, this.Uri) { Person = this.Person } } }; this.EngineeringModel = new EngineeringModel(Guid.NewGuid(), this.Assembler.Cache, this.Uri) { EngineeringModelSetup = this.EngineeringModelSetup }; this.IterationSetup = new IterationSetup(Guid.NewGuid(), this.Assembler.Cache, this.Uri) { IterationNumber = int.MaxValue }; this.Iteration = new Iteration(Guid.NewGuid(), this.Assembler.Cache, this.Uri) { IterationSetup = this.IterationSetup, TopElement = this.TopElement, DefaultOption = this.Option }; this.Iteration.Option.Add(this.Option); this.AddThingsToTheCache(); this.EngineeringModel.Iteration.Add(this.Iteration); this.Session = new Mock <ISession>(); this.Session.Setup(x => x.Assembler).Returns(this.Assembler); this.Session.Setup(x => x.ActivePerson).Returns(this.Person); this.Session.Setup(x => x.QuerySelectedDomainOfExpertise(this.Iteration)).Returns(this.Domain); }
public void Setup() { this.cache = new ConcurrentDictionary <CacheKey, Lazy <Thing> >(); this.iteration = new Iteration(Guid.NewGuid(), this.cache, this.uri); this.option = new Option(Guid.NewGuid(), this.cache, this.uri) { Container = this.iteration }; this.iteration.Option.Add(this.option); this.nestedElement = new NestedElement(Guid.NewGuid(), this.cache, this.uri); this.rootElementDef = new ElementDefinition(Guid.NewGuid(), this.cache, this.uri) { Name = "ElementDef", ShortName = "Def", Container = this.iteration }; this.elementDef1 = new ElementDefinition(Guid.NewGuid(), this.cache, this.uri) { Name = "ElementDef1", ShortName = "Def1", Container = this.iteration }; this.elementDef2 = new ElementDefinition(Guid.NewGuid(), this.cache, this.uri) { Name = "ElementDef2", ShortName = "Def2", Container = this.iteration }; this.elementDef3 = new ElementDefinition(Guid.NewGuid(), this.cache, this.uri) { Name = "ElementDef3", ShortName = "Def3", Container = this.iteration }; this.elementDef4 = new ElementDefinition(Guid.NewGuid(), this.cache, this.uri) { Name = "ElementDef4", ShortName = "Def4", Container = this.iteration }; this.elementUsage1 = new ElementUsage(Guid.NewGuid(), this.cache, this.uri) { Name = "ElementUsage", ShortName = "Use1", ElementDefinition = this.elementDef1 }; this.elementUsage2 = new ElementUsage(Guid.NewGuid(), this.cache, this.uri) { Name = "ElementUsage2", ShortName = "Use2", ElementDefinition = this.elementDef2 }; this.elementUsage3_1 = new ElementUsage(Guid.NewGuid(), this.cache, this.uri) { Name = "ElementUsage3_1", ShortName = "Use3_1", ElementDefinition = this.elementDef3 }; this.elementUsage3_2 = new ElementUsage(Guid.NewGuid(), this.cache, this.uri) { Name = "ElementUsage3_2", ShortName = "Use3_2", ElementDefinition = this.elementDef3 }; this.elementUsage4 = new ElementUsage(Guid.NewGuid(), this.cache, this.uri) { Name = "ElementUsage4", ShortName = "Use4", ElementDefinition = this.elementDef4 }; this.iteration.TopElement = this.rootElementDef; this.rootElementDef.ContainedElement.Add(this.elementUsage1); this.elementDef1.ContainedElement.Add(this.elementUsage2); this.elementDef1.ContainedElement.Add(this.elementUsage3_1); this.elementDef1.ContainedElement.Add(this.elementUsage3_2); this.elementDef3.ContainedElement.Add(this.elementUsage4); this.domain = new DomainOfExpertise(Guid.NewGuid(), this.cache, this.uri); this.domain2 = new DomainOfExpertise(Guid.NewGuid(), this.cache, this.uri); this.elementUsage1.Owner = this.domain2; this.elementUsage2.Owner = this.domain2; this.elementUsage2.ElementDefinition = this.elementDef2; this.elementUsage3_1.Owner = this.domain2; this.elementUsage3_2.Owner = this.domain2; this.elementUsage4.Owner = this.domain2; this.rootElementDef.Owner = this.domain; this.nestedElement.RootElement = this.rootElementDef; this.nestedElement.ElementUsage.Add(this.elementUsage1); this.nestedElement.ElementUsage.Add(this.elementUsage2); this.category = new Category(Guid.NewGuid(), this.cache, this.uri) { Name = "Category", ShortName = "Cat" }; var lazyCategory = new Lazy <Thing>(() => this.category); this.cache.TryAdd(new CacheKey(this.category.Iid, null), lazyCategory); var iterationSetup = new IterationSetup(Guid.NewGuid(), this.cache, this.uri); this.iteration.IterationSetup = iterationSetup; var engineeringModelSetup = new EngineeringModelSetup(Guid.NewGuid(), this.cache, this.uri); engineeringModelSetup.IterationSetup.Add(iterationSetup); var modelReferenceLibrary = new ModelReferenceDataLibrary(Guid.NewGuid(), this.cache, this.uri); modelReferenceLibrary.DefinedCategory.Add(this.category); engineeringModelSetup.RequiredRdl.Add(modelReferenceLibrary); }