private void CascadeGenerics(MohawkCollege.EHR.gpmr.COR.Class cls, Stack <string> CurrentlyProcessing) { if (cls == null || CurrentlyProcessing.Contains(cls.Name)) // Something to process and we aren't already processing it { return; } // Push on the current class CurrentlyProcessing.Push(cls.Name); foreach (ClassContent cc in cls.Content) { if (cc is Property) { // Now set the generics of the class to this if ((cc as Property).Type.Class == null) { continue; // Base datatype so don't worry } CascadeGenerics((cc as Property).Type.Class, CurrentlyProcessing); foreach (TypeParameter p in (cc as Property).Type.Class.TypeParameters ?? new List <TypeParameter>()) { cls.AddTypeParameter(p); (cc as Property).Type.AddGenericSupplier(p.ParameterName, p); } } } CurrentlyProcessing.Pop(); // Pop off the current class }
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()); } }