/// <summary> /// Create flat associations from the serialized models /// </summary> private IEnumerable<Association> CreateFlatAssociations(List<SerializedAssociationEnd> associations, GlobalStaticModel ownedModel) { List<Association> retVal = new List<Association>(associations.Count); foreach (var assoc in associations) { // Conver the serialized association to flat association Association flatAssoc = new Association() { Annotations = assoc.Annotations, SortKey = assoc.SortKey }; flatAssoc.Ends = new List<Relationship>() { assoc.SourceConnection.Content }; // Since a flat association simply points to a class name, we need to add the serialized class to the // owned model as a class and reference it by name var classItem = CreateFlatModelElement(assoc.TargetConnection.ParticipantClass.Content as ModelElement, ownedModel); string assocName = null; if (classItem is Class) assocName = (classItem as Class).Name; else if(classItem is CommonModelElementRef) assocName = (classItem as CommonModelElementRef).Name; flatAssoc.Ends.Add(new AssociationEnd() { Annotations = assoc.TargetConnection.Annotations, BusinessName = assoc.TargetConnection.BusinessName, ChoiceItem = assoc.TargetConnection.ChoiceItem, Conformance = assoc.TargetConnection.Conformance, DerivedFrom = assoc.TargetConnection.DerivedFrom, IsMandatory = assoc.TargetConnection.IsMandatory, MaximumMultiplicity = assoc.TargetConnection.MaximumMultiplicity, MinimumMultiplicity = assoc.TargetConnection.MinimumMultiplicity, Name = assoc.TargetConnection.Name, ParticipantClassName = assocName, ReferenceHistory = assoc.TargetConnection.ReferenceHistory, SortKey = assoc.TargetConnection.SortKey, UpdateModeDefault = assoc.TargetConnection.UpdateModeDefault, UpdateModesAllowed = assoc.TargetConnection.UpdateModesAllowed }); ownedModel.OwnedClass.Add(new ClassElement() { Choice = classItem }); retVal.Add(flatAssoc); } return retVal; }
public void ParseAssociation(Association asc, Dictionary<string, Package> derivationSuppliers) { // There are two scenarios // A: Two traversable connections // B: A traversable and non traversable end // Case A: Two traversable connections, this means that the connection appears in both classes if (asc.Ends[0] is AssociationEnd && asc.Ends[1] is AssociationEnd) { // Make processing a little easier AssociationEnd[] ends = new AssociationEnd[] { asc.Ends[0] as AssociationEnd, asc.Ends[1] as AssociationEnd }; // Loop so we write the code once for (int i = 0; i < 2; i++) { Property p = new Property(); p.Name = ends[i].Name; // Business Name foreach(BusinessName bn in ends[i].BusinessName ?? new List<BusinessName>()) if(bn.Language == MifCompiler.Language || bn.Language == null) p.BusinessName = bn.Name; // The multiplicity of the opposing end influences the property on this end of the // association p.MinOccurs = ends[1 - i].MinimumMultiplicity; p.MaxOccurs = ends[1 - i].MaximumMultiplicity; p.Conformance = ends[1 - i].IsMandatory ? ClassContent.ConformanceKind.Mandatory : ends[1 - i].Conformance == ConformanceKind.Required ? ClassContent.ConformanceKind.Required : ends[1 - i].MinimumMultiplicity == "1" ? ClassContent.ConformanceKind.Populated : ClassContent.ConformanceKind.Optional; // The type of this end is the type of the association p.Type = CreateTypeReference(ends[i], p); if (p.Type.Name == null) { if (p.Documentation == null) p.Documentation = new MohawkCollege.EHR.gpmr.COR.Documentation(); if (p.Documentation.Description == null) p.Documentation.Description = new List<string>(); p.Documentation.Description.Add(String.Format("GPMR: Association to type '{0}' was ignored and set as nothing as '{0}' could not be found. You should consider revising this", ends[i].ParticipantClassName)); } // Traversable association p.PropertyType = Property.PropertyTypes.TraversableAssociation; // Annotations if (asc.Annotations != null) p.Documentation = MohawkCollege.EHR.gpmr.Pipeline.Compiler.Mif20.Parsers.DocumentationParser.Parse(asc.Annotations.Documentation); // Find the class this end belongs in if (!ClassRepository.ContainsKey(string.Format("{0}.{1}", staticModel.PackageLocation.Artifact == ArtifactKind.RIM ? "RIM" : staticModel.PackageLocation.ToString(MifCompiler.NAME_FORMAT), ends[1 - i].ParticipantClassName))) throw new Exception(string.Format("Can't bind property '{0}' to class '{1}'... Class does not exist", p.Name, ends[1 - i].ParticipantClassName)); // Set derivation p.DerivedFrom = asc; p.SortKey = asc.SortKey; try { if (ends[i].DerivedFrom != null) { p.Realization = new List<ClassContent>(); foreach (var dei in ends[i].DerivedFrom) { MohawkCollege.EHR.gpmr.COR.Feature f = null; if (!ClassRepository.TryGetValue(string.Format("{0}.{1}", derivationSuppliers[dei.StaticModelDerivationId].PackageLocation.Artifact == ArtifactKind.RIM ? "RIM" : derivationSuppliers[dei.StaticModelDerivationId].PackageLocation.ToString(MifCompiler.NAME_FORMAT), dei.ClassName), out f)) System.Diagnostics.Trace.WriteLine(String.Format("Can't find derivation class '{0}' for association '{1}'", dei.ClassName, ends[i].Name), "debug"); else { ClassContent cc = (f as MohawkCollege.EHR.gpmr.COR.Class).GetFullContent().Find(o => o.Name == dei.AssociationEndName); p.Realization.Add(cc); } } } } catch (Exception ex) { Trace.WriteLine(String.Format("Cannot append derivation information to {0} (reason:{1})", ends[i].Name, ex.ToString()), "error"); } // Add to repository if(ends[1 - i].Conformance != ConformanceKind.NotPermitted) (ClassRepository[string.Format("{0}.{1}", staticModel.PackageLocation.Artifact == ArtifactKind.RIM ? "RIM" : staticModel.PackageLocation.ToString(MifCompiler.NAME_FORMAT), ends[1 - i].ParticipantClassName)] as MohawkCollege.EHR.gpmr.COR.Class).AddContent(p); } } else // Case 2: A traversable and non-traversable connection, { AssociationEnd ae = (asc.Ends[0] as AssociationEnd) ?? (asc.Ends[1] as AssociationEnd); NonTraversableAssociationEnd ntae = (asc.Ends[0] as NonTraversableAssociationEnd) ?? (asc.Ends[1] as NonTraversableAssociationEnd); // Start to process the property. ClassContent cc; if (ae.ChoiceItem != null && ae.ChoiceItem.Count > 0) cc = new Choice(); else cc = new Property(); cc.Name = ae.Name; // Business Name foreach(BusinessName bn in ae.BusinessName ?? new List<BusinessName>()) if(bn.Language == MifCompiler.Language || bn.Language == null) cc.BusinessName = bn.Name; // The multiplicity of the opposing end influences the property on this end of the // association cc.MinOccurs = ae.MinimumMultiplicity; cc.MaxOccurs = ae.MaximumMultiplicity; cc.Conformance = ae.IsMandatory ? ClassContent.ConformanceKind.Mandatory : ae.Conformance == ConformanceKind.Required && ae.MinimumMultiplicity == "1" ? ClassContent.ConformanceKind.Populated : ae.Conformance == ConformanceKind.Required ? ClassContent.ConformanceKind.Required : ClassContent.ConformanceKind.Optional; #region Bind To Class // Find the class on the traversable end, we'll need to append the property to it if (!ClassRepository.ContainsKey(string.Format("{0}.{1}", staticModel.PackageLocation.Artifact == ArtifactKind.RIM ? "RIM" : staticModel.PackageLocation.ToString(MifCompiler.NAME_FORMAT), ntae.ParticipantClassName))) System.Diagnostics.Trace.WriteLine(string.Format("Can't bind property '{0}' to class '{1}'... Class does not exist", cc.Name, ntae.ParticipantClassName), "error"); //throw new Exception(string.Format("Can't bind property '{0}' to class '{1}'... Class does not exist", p.Name, ae.ParticipantClassName)); else if (ae.Conformance != ConformanceKind.NotPermitted) // Append the property to the class { MohawkCollege.EHR.gpmr.COR.Class cls = ClassRepository[string.Format("{0}.{1}", staticModel.PackageLocation.Artifact == ArtifactKind.RIM ? "RIM" : staticModel.PackageLocation.ToString(MifCompiler.NAME_FORMAT), ntae.ParticipantClassName)] as MohawkCollege.EHR.gpmr.COR.Class; cls.AddContent(cc); // Add template parameter if (templateParameters.ContainsKey(ae.ParticipantClassName)) cls.AddTypeParameter(templateParameters[ae.ParticipantClassName]); } else return; #endregion // Choice or property? if (cc is Property) { Property p = cc as Property; p.Type = CreateTypeReference(ae, p); if (p.Type.Name == null) { if (p.Documentation == null) p.Documentation = new MohawkCollege.EHR.gpmr.COR.Documentation(); if (p.Documentation.Description == null) p.Documentation.Description = new List<string>(); p.Documentation.Description.Add(String.Format("GPMR: Association to type '{0}' was ignored and set as nothing as '{0}' could not be found. You should consider revising this", ae.ParticipantClassName)); } // Traversable association p.PropertyType = Property.PropertyTypes.TraversableAssociation; } else // Choice { Choice chc = cc as Choice; chc.MemberOf = ClassRepository; chc.Content = new List<ClassContent>(); // Get a type reference to the CMET or main type to be used TypeReference trf = CreateTypeReference(ae, cc); // Cannot find association if (trf.Name == null) { if (chc.Documentation == null) chc.Documentation = new MohawkCollege.EHR.gpmr.COR.Documentation(); if (chc.Documentation.Description == null) chc.Documentation.Description = new List<string>(); chc.Documentation.Description.Add(String.Format("GPMR: Association to type '{0}' was ignored and set as nothing as '{0}' could not be found. You should consider revising this", ae.ParticipantClassName)); } // Warn if (trf.Class == null) { throw new InvalidOperationException(String.Format("Cannot make association to class '{0}' as it was not defined!", ae.ParticipantClassName)); } if (ae.ChoiceItem.Count != trf.Class.SpecializedBy.Count) System.Diagnostics.Trace.WriteLine(string.Format("Number of choices on property does not match the number of child classes for its data type for association '{0}'", cc.Name), "warn"); chc.Content.AddRange(ProcessAssociations(ae, ae.ChoiceItem, trf, chc)); /* // Specializations List<TypeReference> specializations = new List<TypeReference>(trf.Class.SpecializedBy); // Flatten choice members for (int i = 0; i < ae.ChoiceItem.Count ; i++) if (ae.ChoiceItem[i].Specialization != null && ae.ChoiceItem[i].Specialization.Count > 0) { AssociationEndSpecialization aes = ae.ChoiceItem[i]; // Get local reference // Remove redundant data ae.ChoiceItem.RemoveAt(i); // Remove the redundant choice item i--; // redo this item // is this a cmet? if (ClassRepository.ContainsKey(aes.ClassName) && ClassRepository[aes.ClassName] is CommonTypeReference) { specializations.RemoveAll(o => o.Name == (ClassRepository[aes.ClassName] as CommonTypeReference).Class.Name); specializations.AddRange((ClassRepository[aes.ClassName] as CommonTypeReference).Class.Class.SpecializedBy); } ae.ChoiceItem.AddRange(aes.Specialization); // Now add the choices } int ip = 0; // Add choice members foreach (AssociationEndSpecialization aes in ae.ChoiceItem) { Property p = new Property(); // Now, construct the properties from the CMET entries // Try ... var rClassName = specializations.Find(o => o.Class != null && o.Class.Name.Equals(aes.ClassName)); // Determine if this is a CMET if (ClassRepository.ContainsKey(aes.ClassName) && ClassRepository[aes.ClassName] is CommonTypeReference) p.Type = (ClassRepository[aes.ClassName] as CommonTypeReference).Class; else if (rClassName != null) // Try using the inheritence method p.Type = rClassName; else if (ClassRepository.ContainsKey(String.Format("{0}.{1}", staticModel.PackageLocation.ToString(MifCompiler.NAME_FORMAT), aes.ClassName))) p.Type = ((ClassRepository[String.Format("{0}.{1}", staticModel.PackageLocation.ToString(MifCompiler.NAME_FORMAT), aes.ClassName)] as MohawkCollege.EHR.gpmr.COR.Class).CreateTypeReference()); else { System.Diagnostics.Trace.WriteLine(string.Format("Class '{2}' of CMET '{1}' could not be found or was not processed. The processing of the property '{0}' in '{3}.{4}' will NOT continue", cc.Name, aes.ClassName, ae.ParticipantClassName, staticModel.PackageLocation.ToString(MifCompiler.NAME_FORMAT), ntae.ParticipantClassName), "error"); break; } p.PropertyType = Property.PropertyTypes.TraversableAssociation; // Fix bug with optional choice p.MinOccurs = chc.MinOccurs; p.MaxOccurs = chc.MaxOccurs; p.Conformance = chc.Conformance; p.DerivedFrom = aes; p.Documentation = p.Type.ClassDocumentation; p.MemberOf = ClassRepository; p.Container = chc; // Traversal names p.Name = aes.TraversalName; chc.Content.Add(p); ip++; } */ } // Annotations if (asc.Annotations != null) cc.Documentation = MohawkCollege.EHR.gpmr.Pipeline.Compiler.Mif20.Parsers.DocumentationParser.Parse(asc.Annotations.Documentation); // Set derivation cc.DerivedFrom = asc; cc.SortKey = ae.SortKey; try { if (ae.DerivedFrom != null) { cc.Realization = new List<ClassContent>(); foreach (var dei in ae.DerivedFrom) { MohawkCollege.EHR.gpmr.COR.Feature ss = null; Package derivationPkg = null; if (!derivationSuppliers.TryGetValue(dei.StaticModelDerivationId, out derivationPkg) || derivationPkg == null) { continue; } // Has the package been compiled? if (!ClassRepository.TryGetValue(string.Format("{0}", derivationPkg.PackageLocation.Artifact == ArtifactKind.RIM ? "RIM" : derivationPkg.PackageLocation.ToString(MifCompiler.NAME_FORMAT)), out ss)) { // Attempt to parse PackageParser.Parse(derivationPkg.PackageLocation.ToString(MifCompiler.NAME_FORMAT), derivationPkg.MemberOfRepository, ClassRepository); // Ditch if still can't find if (!ClassRepository.TryGetValue(string.Format("{0}", derivationPkg.PackageLocation.Artifact == ArtifactKind.RIM ? "RIM" : derivationPkg.PackageLocation.ToString(MifCompiler.NAME_FORMAT)), out ss)) System.Diagnostics.Trace.WriteLine(String.Format("Can't find derivation class '{0}' for association '{1}' (derivation supplier {2})", dei.ClassName, dei.AssociationEndName, dei.StaticModelDerivationId), "warn"); } // Feature was found var f = (ss as MohawkCollege.EHR.gpmr.COR.SubSystem).FindClass(dei.ClassName); if (f != null) { // Realized Class content ClassContent rcc = f.GetFullContent().Find(o => o.Name == dei.AssociationEndName); cc.Realization.Add(rcc); } else System.Diagnostics.Trace.WriteLine(String.Format("Can't find derivation class '{0}' for association '{1}' (derivation supplier {2})", dei.ClassName, dei.AssociationEndName, dei.StaticModelDerivationId), "warn"); } } } catch (Exception ex) { Trace.WriteLine(String.Format("Cannot append derivation information to {0} (reason:{1})", ae.Name, ex.ToString()), "error"); } (cc.Container as MohawkCollege.EHR.gpmr.COR.Class).Content.Sort(new ClassContent.Comparator()); } }