/// <summary> /// Gets a new instance of an elaborator based on a given context. /// </summary> /// <param name="subject">Given context</param> /// <param name="logger">Logger which can be used to log messages.</param> /// <returns>A new instance of a context aware elaborator.</returns> /// <exception cref="ArgumentNullException">If subject or logger null.</exception> /// <exception cref="NotSupportedException">If subject does not have an associated elaborator class.</exception> public static Elaborator GetElaborator(MgaModel subject, CyPhyGUIs.GMELogger logger, bool UnrollConnectors) { if (subject == null) { throw new ArgumentNullException("subject"); } if (logger == null) { throw new ArgumentNullException("logger"); } var factory = new CyPhyTypeFactory(subject.Project.RootMeta); Elaborator elaborator = null; if (subject.MetaBase.MetaRef == factory.TestBenchMeta || subject.MetaBase.MetaRef == factory.CADTestBenchMeta || subject.MetaBase.MetaRef == factory.BlastTestBenchMeta || subject.MetaBase.MetaRef == factory.BallisticTestBenchMeta || subject.MetaBase.MetaRef == factory.CFDTestBenchMeta || subject.MetaBase.MetaRef == factory.KinematicTestBenchMeta || subject.MetaBase.MetaRef == factory.CarTestBenchMeta) { elaborator = new TestBenchTypeElaborator(subject, UnrollConnectors); } else if (subject.MetaBase.MetaRef == factory.ComponentAssemblyMeta) { elaborator = new ComponentAssemblyElaborator(subject, UnrollConnectors); } else if (subject.MetaBase.MetaRef == factory.DesignContainerMeta) { elaborator = new DesignContainerElaborator(subject, UnrollConnectors); } else { throw new NotSupportedException(string.Format("Not supported context: {0} [{1}]", subject.Name, subject.MetaBase.Name)); } if (subject.IsLibObject) { throw new NotSupportedException(string.Format("{0} cannot be a library object.", subject.MetaBase.Name)); } elaborator.Logger = logger; elaborator.Factory = factory; // TODO: how can we determine this? elaborator.IsElaborated = false; return(elaborator); }
/// <summary> /// Runs the elaborator based on a given context. /// </summary> /// <param name="currentobj">Current context on which the elaborator should run.</param> /// <returns>True if the elaboration was successful</returns> /// <exception cref="ElaboratorException">If any problem occurred during elaboration.</exception> public bool ElaborateContext(MgaFCO currentobj) { // initialize traceability map with a new instance this.Traceability = new META.MgaTraceability(); // expose traceability for other interpreters this.set_ComponentParameter("traceability", this.Traceability); // count all descendant objects before elaboration var beforeElaboration = (currentobj as MgaModel).GetDescendantFCOs(currentobj.Project.CreateFilter()).Count; // get an elaborator for the current context var elaborator = Elaborator.GetElaborator(currentobj as MgaModel, this.Logger, UnrollConnectors); // elaborate the entire model starting from the current object elaborator.Elaborate(); // update traceability for this object. // TODO: would be nice to have a function on MgaTraceability class like update map and we can pass a dictionary. foreach (var item in elaborator.Traceability) { this.Traceability.AddItem(item.Key, item.Value); } // statistics about the traceability this.Logger.WriteDebug("Traceability map size: {0}", elaborator.Traceability.Count); // count all descendant objects after elaboration var afterElaboration = (currentobj as MgaModel).GetDescendantFCOs(currentobj.Project.CreateFilter()).Count; this.Logger.WriteDebug("Before: {0}, After: {1}", beforeElaboration, afterElaboration); // verify traceability if (afterElaboration == elaborator.Traceability.Count) { this.Logger.WriteDebug("Traceability map has traces for all objects within the current context."); } else { this.Logger.WriteWarning("Traceability map does not have traces for all objects. {0} are missing in the map.", elaborator.Traceability.Count - afterElaboration); } return(true); }
/// <summary> /// Elaborates the give test bench. /// </summary> public override void Elaborate() { // gets all objects within the test bench in any depth. MgaFilter filter = this.Subject.Project.CreateFilter(); var allObjects = this.Subject.GetDescendantFCOs(filter); // list of test injection points in the test bench List <MgaReference> tips = new List <MgaReference>(); foreach (MgaFCO obj in allObjects) { // add object to traceability this.Traceability.Add(obj.ID, obj.ID); if (this.Factory.TestInjectionPointsMeta.Contains(obj.MetaBase.MetaRef)) { // if object is a kind of test injection point if (obj is MgaReference) { // if it is a reference if ((obj as MgaReference).Referred == null) { this.Logger.WriteWarning(string.Format("{0} [{1}] was ignored and skipped, because it points to a null reference.", obj.Name, obj.MetaBase.Name)); } else { // has a valid reference which is not null tips.Add(obj as MgaReference); } } else { this.Logger.WriteError(string.Format("{0} [{1}] is not a reference, therefore it was ignored and skipped.", obj.Name, obj.MetaBase.Name)); } } } // get the top level system under test object for this test bench var tlsut = allObjects.OfType <MgaReference>().FirstOrDefault(x => x.MetaBase.Name == "TopLevelSystemUnderTest"); // ASSUME we have exactly one // make sure it is not null if (tlsut == null) { this.Logger.WriteWarning(string.Format("No top level system under test object in {0} [{1}]", this.Subject.Name, this.Subject.MetaBase.Name)); this.Logger.WriteWarning("Assumes [{0}] has been elaborated...", this.Subject.MetaBase.Name); this.IsElaborated = true; return; } // it has a null reference if (tlsut.Referred == null) { throw new ElaboratorException(string.Format("Top level system under test object in {0} [{1}] is a null reference.", this.Subject.Name, this.Subject.MetaBase.Name)); } // switch the top level system under test to a Component Assembly // FIXME: what if it is not a component assembly ??? string tlsu_referred_id = tlsut.Referred.ID; var ca_tlsut = this.SwitchReferenceToModel(this.Subject, tlsut, false); // delete the reference object. tlsut.DestroyObject(); // component assembly elaborator used to elaborate the Top Level System Under Test object. ComponentAssemblyElaborator componentAssemblyElaborator = null; // get a Componenet assembly elaborator for the top level system under test object. componentAssemblyElaborator = Elaborator.GetElaborator <ComponentAssemblyElaborator>(ca_tlsut, this.Logger, UnrollConnectors); // pass our current traceability information componentAssemblyElaborator.Traceability = this.Traceability; componentAssemblyElaborator.ComponentGUIDs = this.ComponentGUIDs; // elaborate the top level system under test object componentAssemblyElaborator.Elaborate(); // TODO: Elaborate test components // get a look up map for all test injection point references var map = componentAssemblyElaborator.GetReverseLookupMap(tips.Select(x => x.Referred.ID)); map[tlsu_referred_id] = new MgaFCO[] { (MgaFCO)ca_tlsut }.ToList(); // gather all information about test injection points, pretend everything is ok. bool success = true; foreach (MgaReference tip in tips) { // get the new targets for this test injection point var tipTargets = map[tip.Referred.ID]; // looking for exactly one target if (tipTargets.Count == 0) { // no target mark it as failure success = false; this.Logger.WriteFailed("{0} [{1}] --> {2} [{3}] was not found in traceability.", tip.Name, tip.MetaBase.Name, tip.Referred.Name, tip.Referred.MetaBase.Name); } else if (tipTargets.Count == 1) { // exactly one target try { // redirect test injection point to the new target var switcher = new ReferenceSwitcher.ReferenceSwitcherInterpreter(); switcher.SwitchReference(tipTargets[0] as IMgaFCO, tip as IMgaReference); } catch (Exception ex) { success = false; // handle failures for this (use case we can lose ports/connections/ // what if something is an instance/subtype/readonly etc... this.Logger.WriteFailed("{0} [{1}] --> {2} [{3}] redirecting to --> {4} [{5}]", tip.Name, tip.MetaBase.Name, tip.Referred.Name, tip.Referred.MetaBase.Name, tipTargets[0].Name, tipTargets[0].MetaBase.Name); this.Logger.WriteDebug(ex.ToString()); } } else { // tipTarget.Count > 1 // more than one possible targets, this case is ambiguous, therefore mark it as failure. success = false; this.Logger.WriteFailed("{0} [{1}] --> {2} [{3}] was found more than once in the system - the choice is ambiguous.", tip.Name, tip.MetaBase.Name, tip.Referred.Name, tip.Referred.MetaBase.Name); } } if (tips.Any()) { if (success) { // check if no problems this.Logger.WriteInfo("All test injection points were redirected successfully."); } else { // some problems occured, must raise an exception throw new ElaboratorException("At least one test injection point was not redirected successfully. See log messages above."); } } // if this point is reached, mark it successful. this.IsElaborated = true; }
/// <summary> /// Elaborates a DesignContainer object. /// </summary> public override void Elaborate() { MgaFilter filter = this.Subject.Project.CreateFilter(); var allObjects = this.Subject.GetDescendantFCOs(filter); foreach (MgaFCO obj in allObjects) { if (obj.IsPrimaryDerived) { obj.DetachFromArcheType(); } } foreach (MgaFCO obj in allObjects) { if (this.Traceability.ContainsKey(obj.ID) == false) { // add to traceability this.Traceability.Add(obj.ID, obj.ID); } if (obj is MgaReference) { var reference = obj as MgaReference; if (reference.Referred == null) { if (reference.MetaBase.MetaRef == this.Factory.ComponentRefMeta) { this.Logger.WriteWarning(string.Format("Null {0} [{1}] was ignored and skipped.", reference.Name, reference.MetaBase.Name)); } continue; } var referred = reference.Referred; MgaObject parent = null; GME.MGA.Meta.objtype_enum type; reference.GetParent(out parent, out type); if (IsConfigurationType(parent)) { continue; } if (parent.MetaBase.MetaRef == Factory.DecisionGroupMeta || parent.MetaBase.MetaRef == Factory.VisualConstraintMeta || parent.MetaBase.MetaRef == Factory.And_operatorMeta || parent.MetaBase.MetaRef == Factory.Or_operatorMeta || parent.MetaBase.MetaRef == Factory.Not_operatorMeta) { // DecisionGroup can hold only ComponentRefs, so we can't do anything with its children (META-3595) continue; } if (referred.MetaBase.MetaRef == this.Factory.ComponentMeta) { var copied = this.SwitchReferenceToModel(parent as MgaModel, reference, true); // delete reference reference.DestroyObject(); } else if (referred.MetaBase.MetaRef == this.Factory.ComponentAssemblyMeta) { MgaObject parent2 = parent; GME.MGA.Meta.objtype_enum type2; // worst case this will terminate at the root folder level while (parent2 != null && parent2 is MgaModel) { // FIXME: is this safe? should we compare IDs? if (parent2 == reference.Referred) { string message = string.Format("Circular dependency: {0} --> {1}", parent2.Name, reference.Referred.Name); throw new ElaboratorCircularReferenceException(message); } parent2.GetParent(out parent2, out type2); } if (this.ComponentAssemblyReferences.Any(x => x.ID == reference.Referred.ID)) { string message = string.Format("Circular dependency: {0} --> {1}", string.Join(" -> ", this.ComponentAssemblyReferences.Select(x => x.Name)), reference.Referred.Name); throw new ElaboratorCircularReferenceException(message); } var copied = this.SwitchReferenceToModel(parent as MgaModel, reference, false); // prevent circular dependency var innerElaborator = Elaborator.GetElaborator(copied, this.Logger, UnrollConnectors) as ComponentAssemblyElaborator; // use only one map innerElaborator.Traceability = this.Traceability; innerElaborator.ComponentGUIDs = this.ComponentGUIDs; innerElaborator.ComponentCopyMap = this.ComponentCopyMap; // hold only one queue foreach (var item in this.ComponentAssemblyReferences) { innerElaborator.ComponentAssemblyReferences.Enqueue(item); } innerElaborator.ComponentAssemblyReferences.Enqueue(reference.Referred); this.InnerElaborators.Add(innerElaborator); innerElaborator.Elaborate(); // delete reference reference.DestroyObject(); } else if (referred.MetaBase.MetaRef == this.Factory.DesignContainerMeta) { MgaObject parent2 = parent; GME.MGA.Meta.objtype_enum type2; // worst case this will terminate at the root folder level while (parent2 != null && parent2 is MgaModel) { // FIXME: is this safe? should we compare IDs? if (parent2 == reference.Referred) { string message = string.Format("Circular dependency: {0} --> {1}", parent2.Name, reference.Referred.Name); throw new ElaboratorCircularReferenceException(message); } parent2.GetParent(out parent2, out type2); } if (this.DesignSpaceReferences.Any(x => x.ID == reference.Referred.ID)) { string message = string.Format("Circular dependency: {0} --> {1}", string.Join(" -> ", this.DesignSpaceReferences.Select(x => x.Name)), reference.Referred.Name); throw new ElaboratorCircularReferenceException(message); } var copied = this.SwitchReferenceToModel(parent as MgaModel, reference, false); var innerElaborator = Elaborator.GetElaborator(copied, this.Logger, UnrollConnectors) as DesignContainerElaborator; // use only one map innerElaborator.Traceability = this.Traceability; innerElaborator.ComponentGUIDs = this.ComponentGUIDs; innerElaborator.ComponentCopyMap = this.ComponentCopyMap; // hold only one queue foreach (var item in this.DesignSpaceReferences) { innerElaborator.DesignSpaceReferences.Enqueue(item); } innerElaborator.DesignSpaceReferences.Enqueue(reference.Referred); this.InnerElaborators.Add(innerElaborator); innerElaborator.Elaborate(); // delete reference reference.DestroyObject(); } } } }
/// <summary> /// Elaborates the given context recursively. /// </summary> public override void Elaborate() { SortedDictionary <string, MgaModel> parentsWithDupComponentGuids = new SortedDictionary <string, MgaModel>(); MgaFilter filter = this.Subject.Project.CreateFilter(); var allObjects = this.Subject.GetDescendantFCOs(filter); foreach (MgaFCO obj in allObjects) { if (obj.IsPrimaryDerived) { obj.DetachFromArcheType(); } } foreach (MgaFCO obj in allObjects) { if (this.Traceability.ContainsKey(obj.ID) == false) { // add to traceability this.Traceability.Add(obj.ID, obj.ID); } if (obj is MgaModel) { var model = obj as MgaModel; if (model.MetaBase.MetaRef == this.Factory.ComponentAssemblyMeta) { var managedGuid = model.StrAttrByName["ManagedGUID"]; if (string.IsNullOrEmpty(managedGuid) == false) { // copiedObj.StrAttrByName["ManagedGUID"] = managedGuid; // model.RegistryValue[RegistryNameInstanceGuidChain] = model.RegistryValue[RegistryNameInstanceGuidChain] + managedGuid; } } } else if (obj is MgaReference) { var reference = obj as MgaReference; if (reference.Referred == null) { if (reference.MetaBase.MetaRef == this.Factory.ComponentRefMeta) { this.Logger.WriteWarning(string.Format("Null {0} [{1}] was ignored and skipped.", reference.Name, reference.MetaBase.Name)); } continue; } var referred = reference.Referred; if (referred.MetaBase.MetaRef == this.Factory.ComponentMeta) { MgaObject parent = null; GME.MGA.Meta.objtype_enum type; reference.GetParent(out parent, out type); var instanceGuid = reference.GetStrAttrByNameDisp("InstanceGUID"); if (string.IsNullOrWhiteSpace(instanceGuid)) { instanceGuid = new Guid(reference.GetGuidDisp()).ToString("D"); reference.SetStrAttrByNameDisp("InstanceGUID", instanceGuid); } if (parent is MgaModel) { instanceGuid = ((MgaModel)parent).RegistryValue[RegistryNameInstanceGuidChain] + instanceGuid; bool dupComponentGuid = !this.ComponentGUIDs.Add(instanceGuid); if (dupComponentGuid) { LogDebug("Duplicate ID " + instanceGuid, reference); parentsWithDupComponentGuids[parent.AbsPath] = parent as MgaModel; } } var copied = this.SwitchReferenceToModel(parent as MgaModel, reference, createInstance: true); // delete reference reference.DestroyObject(); } else if (referred.MetaBase.MetaRef == this.Factory.ComponentAssemblyMeta) { MgaObject parent = null; GME.MGA.Meta.objtype_enum type; reference.GetParent(out parent, out type); MgaObject parent2 = parent; GME.MGA.Meta.objtype_enum type2; // worst case this will terminate at the root folder level while (parent2 != null && parent2 is MgaModel) { // FIXME: is this safe? should we compare IDs? if (parent2 == reference.Referred) { string message = string.Format("Circular dependency: {0} --> {1}", parent2.Name, reference.Referred.Name); throw new ElaboratorCircularReferenceException(message); } parent2.GetParent(out parent2, out type2); } if (this.ComponentAssemblyReferences.Any(x => x.ID == reference.Referred.ID)) { string message = string.Format("Circular dependency: {0} --> {1}", string.Join(" -> ", this.ComponentAssemblyReferences.Select(x => x.Name)), reference.Referred.Name); throw new ElaboratorCircularReferenceException(message); } var copied = this.SwitchReferenceToModel(parent as MgaModel, reference, false); // prevent circular dependency var innerElaborator = Elaborator.GetElaborator(copied, this.Logger, UnrollConnectors) as ComponentAssemblyElaborator; // use only one map innerElaborator.Traceability = this.Traceability; innerElaborator.ComponentGUIDs = this.ComponentGUIDs; innerElaborator.ComponentCopyMap = this.ComponentCopyMap; // hold only one queue foreach (var item in this.ComponentAssemblyReferences) { innerElaborator.ComponentAssemblyReferences.Enqueue(item); } innerElaborator.ComponentAssemblyReferences.Enqueue(reference.Referred); this.InnerElaborators.Add(innerElaborator); innerElaborator.Elaborate(); // delete reference reference.DestroyObject(); } } } // FIXME: it is possible for a parentWithDupComponentGuid to contain child CAs that need to be deduped also string lastPath = null; foreach (var ent in parentsWithDupComponentGuids) { if (lastPath != null) { if (ent.Key.StartsWith(lastPath)) { continue; } } lastPath = ent.Key; var model = ent.Value; allObjects = model.GetDescendantFCOs(filter); var parentGuid = model.ParentModel != null ? model.ParentModel.RegistryValue[RegistryNameInstanceGuidChain] : null; // parent model should contain the concatenated InstanceGUID string guidConcat = (parentGuid ?? "") + new Guid(model.GetGuidDisp()).ToString("D"); foreach (MgaFCO obj in allObjects) { if (obj.MetaBase.MetaRef == this.Factory.ComponentMeta) { obj.SetStrAttrByNameDisp("InstanceGUID", guidConcat + obj.GetStrAttrByNameDisp("InstanceGUID")); } if (obj.MetaBase.MetaRef == this.Factory.ComponentAssemblyMeta) { obj.RegistryValue[RegistryNameInstanceGuidChain] = guidConcat; } } } this.IsElaborated = true; }