private string CreateStructureAttribute(Class cls) { StringBuilder sb = new StringBuilder("[Structure("); sb.AppendFormat("Name = \"{0}\", StructureType = StructureAttribute.StructureAttributeType.MessageType, IsEntryPoint = {1}, Model=\"{2}\", Publisher={3} )]", cls.Name, cls.ContainerPackage.EntryPoint.Exists(o => o.Name == cls.Name) ? "true" : "false", cls.ContainerName, cls.Documentation != null ? "\"" + cls.Documentation.Copyright + "\"" : "null"); return sb.ToString(); }
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 }
internal static MohawkCollege.EHR.gpmr.COR.Class Parse(ClassBase cls, string vocabularyBindingRealm, ClassRepository cr, Dictionary <string, Package> derivationSuppliers) { // Return value MohawkCollege.EHR.gpmr.COR.Class retVal = new MohawkCollege.EHR.gpmr.COR.Class(); // Name of the class retVal.Name = cls.Name; // Identify where this class came from retVal.DerivedFrom = cls; // Set the business name foreach (BusinessName bn in cls.BusinessName) { if (bn.Language == MifCompiler.Language || bn.Language == null) { retVal.BusinessName = bn.Name; } } // Set the documentation & Copyright retVal.Documentation = new MohawkCollege.EHR.gpmr.COR.Documentation(); if (cls.Annotations != null) { retVal.Documentation = DocumentationParser.Parse(cls.Annotations.Documentation); } if (cls.Container.Header.Copyright != null) { retVal.Documentation.Copyright = string.Format("Copyright (C){0}, {1}", cls.Container.Header.Copyright.Year, cls.Container.Header.Copyright.Owner); } // Set abstractiveness of the class retVal.IsAbstract = cls.IsAbstract; // Sort the properties and add them to the class cls.Attribute.Sort(new ClassAttribute.Comparator()); retVal.Content = new List <ClassContent>(); foreach (ClassAttribute ca in cls.Attribute) { if (ca.Conformance == ConformanceKind.NotPermitted) { continue; } MohawkCollege.EHR.gpmr.COR.Property prp = PropertyParser.Parse(ca, vocabularyBindingRealm, cr, derivationSuppliers); prp.Container = retVal; retVal.AddContent(prp); } // Set sort key retVal.SortKey = cls.SortKey; // Return return(retVal); }
internal static MohawkCollege.EHR.gpmr.COR.Class Parse(ClassBase cls, string vocabularyBindingRealm, ClassRepository cr, Dictionary<string, Package> derivationSuppliers) { // Return value MohawkCollege.EHR.gpmr.COR.Class retVal = new MohawkCollege.EHR.gpmr.COR.Class(); // Name of the class retVal.Name = cls.Name; // Identify where this class came from retVal.DerivedFrom = cls; // Set the business name foreach (BusinessName bn in cls.BusinessName) if (bn.Language == MifCompiler.Language || bn.Language == null) retVal.BusinessName = bn.Name; // Set the documentation & Copyright retVal.Documentation = new MohawkCollege.EHR.gpmr.COR.Documentation(); if(cls.Annotations != null) retVal.Documentation = DocumentationParser.Parse(cls.Annotations.Documentation); if (cls.Container.Header.Copyright != null) retVal.Documentation.Copyright = string.Format("Copyright (C){0}, {1}", cls.Container.Header.Copyright.Year, cls.Container.Header.Copyright.Owner); // Set abstractiveness of the class retVal.IsAbstract = cls.IsAbstract; // Sort the properties and add them to the class cls.Attribute.Sort(new ClassAttribute.Comparator()); retVal.Content = new List<ClassContent>(); foreach (ClassAttribute ca in cls.Attribute) { if (ca.Conformance == ConformanceKind.NotPermitted) continue; MohawkCollege.EHR.gpmr.COR.Property prp = PropertyParser.Parse(ca, vocabularyBindingRealm, cr,derivationSuppliers); prp.Container = retVal; retVal.AddContent(prp); } // Set sort key retVal.SortKey = cls.SortKey; // Return return retVal; }
public static List<String> MapInterfaces(Class c, string ownerNs) { List<String> retVal = new List<string>(); // Find which interfaces this class implements foreach(var iface in s_heuristicData.Interfaces) { bool matches = true; Enumeration supplierDomain = null; foreach (var prop in iface.Properties) { Property p = c.Content.Find(o => (o is Property) && (o as Property).Type.Name != null && (o as Property).Type.Name.ToLower() + "." + o.Name.ToLower() == prop.DataType.ToLower() + "." + prop.Name.ToLower() && (o.MaxOccurs == "1" || o.MaxOccurs != "1" && prop.Name.StartsWith("LIST"))) as Property; matches &= p != null; if(matches) supplierDomain = p.SupplierDomain; } // Determine if match was found if (matches) { if (!String.IsNullOrEmpty(iface.GenericParameter)) { string rv = iface.Name; if (supplierDomain != null && !String.IsNullOrEmpty(EnumerationRenderer.WillRender(supplierDomain))) { if (retVal.Contains(rv)) retVal.Remove(rv); rv += String.Format("<{1}>", ownerNs, EnumerationRenderer.WillRender(supplierDomain)); retVal.Add(rv); } } else retVal.Add(iface.Name); } } return retVal; }
/// <summary> /// Generate the complex type /// </summary> /// <param name="cls">The class to generate the complex type for</param> /// <param name="prefix">The prefix namespace for the class</param> /// <param name="genericParameters">Generic parameters</param> private XmlSchemaComplexType GenerateComplexType(Class cls, string prefix, List<TypeReference> genericParameters, List<String> includedModels, List<TypeReference> additionalCompileTargets) { if (cls != null && genericParameters != null && cls.TypeParameters != null && cls.TypeParameters.Count != genericParameters.Count) return null; if (cls == null) { Trace.WriteLine("Cannot generate complex type for null class", "error"); return null; } // Create the complex type XmlSchemaComplexType complexType = new XmlSchemaComplexType() { Name = prefix != null ? String.Format("{0}.{1}.{2}", prefix, cls.ContainerName, cls.Name) : String.Format("{0}.{1}", cls.ContainerName, cls.Name), IsAbstract = cls.IsAbstract }; // Populate documentation for the type if (!Documentation.IsEmpty(cls.Documentation)) { XmlSchemaDocumentation documentation = new XmlSchemaDocumentation(); XmlDocument documentationMarkup = new XmlDocument(); documentationMarkup.LoadXml("<div xmlns=\"http://www.w3.org/1999/xhtml\">" + cls.Documentation.ToString() + "</div>"); documentation.Markup = new List<XmlNode>(documentationMarkup.ChildNodes.Cast<XmlNode>()).ToArray(); complexType.Annotation = new XmlSchemaAnnotation(); complexType.Annotation.Items.Add(documentation); } // Complex Content XmlSchemaComplexContentExtension content = new XmlSchemaComplexContentExtension(); // Null flavors and stuff if (cls.BaseClass != null) { // Add the import for model if (!includedModels.Contains(cls.BaseClass.Class.ContainerName)) includedModels.Add(cls.BaseClass.Class.ContainerName); // Set the extension content.BaseTypeName = new XmlQualifiedName(cls.BaseClass.Name, targetNs); } else if(cls.CreateTypeReference().Name != baseClass) content.BaseTypeName = new XmlQualifiedName(baseClass, targetNs); // Sequence XmlSchemaSequence sequence = new XmlSchemaSequence(); // Iterate through content foreach (ClassContent cc in cls.Content) { if (cc is Property) { Property property = cc as Property; TypeReference realReference = property.Type.Class == null && genericParameters != null ? genericParameters.Find(o => o is TypeParameter && (o as TypeParameter).ParameterName == property.Type.Name) : property.Type; // Is this a property that really represents a choice? // This sometimes happens when a property (namely ACT) points to an // abstract class that has many different sub-traversals... if (realReference != null && realReference.Class != null && realReference.Class.IsAbstract) // Choice { XmlSchemaChoice propertyChoice = new XmlSchemaChoice() { MinOccursString = property.MinOccurs, MaxOccursString = property.MaxOccurs == "*" ? "unbounded" : property.MaxOccurs }; List<XmlSchemaElement> elements = CreateChoice(property, realReference.Class, genericParameters, prefix, includedModels, additionalCompileTargets); foreach (XmlSchemaElement ele in elements) propertyChoice.Items.Add(ele); sequence.Items.Add(propertyChoice); } else // The property is really a property switch (property.PropertyType) { case Property.PropertyTypes.Structural: content.Attributes.Add(CreateAttribute(property)); break; default: sequence.Items.Add(CreateElement(property, genericParameters, prefix, includedModels, additionalCompileTargets)); break; } } else if (cc is Choice) { // Render the choice XmlSchemaChoice choice = new XmlSchemaChoice() { MinOccursString = cc.MinOccurs, MaxOccursString = cc.MaxOccurs == "*" ? "unbounded" : cc.MaxOccurs }; List<XmlSchemaElement> elements = CreateChoice(cc as Choice, genericParameters, prefix, includedModels, additionalCompileTargets); foreach (XmlSchemaElement element in elements) choice.Items.Add(element); sequence.Items.Add(choice); } } // Now for the inherited classes, these could also be sent if (cls.SpecializedBy.Count > 0) { XmlSchemaChoice childChoice = new XmlSchemaChoice(); //// Generate a choice for all child elements //List<XmlSchemaElement> elements = GenerateChildChoices(cls, genericParameters, prefix, includedModels, additionalCompileTargets); //foreach (XmlSchemaElement ele in elements) // childChoice.Items.Add(ele); } content.Particle = sequence; // Sequence // Add the sequence to the content if (sequence.Items.Count > 0) { if (content.BaseTypeName != null && !String.IsNullOrEmpty(content.BaseTypeName.Name)) complexType.ContentModel = new XmlSchemaComplexContent() { Content = content }; else complexType.Particle = sequence; } return complexType; }
public static List<String> MapInterfaces(Class c) { List<String> retVal = new List<string>(); // Find which interfaces this class implements foreach(KeyValuePair<Type, List<String>> kv in interfaces) { bool matches = true; Enumeration supplierDomain = null; foreach (String s in kv.Value) { Property p = c.Content.Find(o => (o is Property) && ((o as Property).Type.Name != null && (o as Property).Type.Name.ToLower() + "." + o.Name.ToLower() == s.ToLower()) && (o.MaxOccurs == "1" || o.MaxOccurs != "1" && s.StartsWith("LIST"))) as Property; matches &= p != null; if(matches && p.SupplierStrength == Property.CodingStrengthKind.CodedNoExtensions) supplierDomain = p.SupplierDomain; } // Determine if match was found if (matches) { if (kv.Key.FullName.Contains("`")) { string rv = kv.Key.FullName.Substring(0, kv.Key.FullName.IndexOf("`")); if (supplierDomain != null && !String.IsNullOrEmpty((EnumerationRenderer.WillRender(supplierDomain)))) { if (retVal.Contains(rv)) retVal.Remove(rv); rv += "<" + EnumerationRenderer.WillRender(supplierDomain) + ">"; retVal.Add(rv); } } else retVal.Add(kv.Key.FullName); } } return retVal; }
/// <summary> /// Copy members from <paramref name="typeReference"/> into the class <paramref name="p"/> in the context of the /// <paramref name="context"/> /// </summary> private void CopyMembers(TypeReference typeReference, Class p, ClassContent context) { if(typeReference.Class == null) throw new InvalidOperationException("Impossible condition to proceed"); foreach (ClassContent cc in typeReference.Class.Content) { // Can't use AddContent as that sorts the content and would mess up the outer loops ClassContent newCc = cc.Clone() as ClassContent; newCc.Container = p; newCc.MemberOf = p.MemberOf; newCc.Annotations.Add(new CodeCollapseAnnotation() { Name = context.Name, Order = 0, Property = context }); newCc.Annotations.Add(new CodeCollapseAnnotation() { Name = newCc.Name, Order = 1, Property = newCc}); // Assign code collapse attributes p.Content.Add(newCc); } }
private string CreateCollapsedConstructor(Class cls, String ownerNs) { // Is there only one useful thing in this class? Property pseudoProperty = new Property(); pseudoProperty.Name = "this"; pseudoProperty.Type = cls.CreateTypeReference(); // Determine the collapsed name Stack<KeyValuePair<String, TypeReference>> collapseData = DetermineCollapsedName(pseudoProperty); if (collapseData.Count > 0) { StringWriter sw = new StringWriter(); StringBuilder methodBody = new StringBuilder(); String methodParms = "", methodHelp = ""; // Create datatypes that will be used string path = "this"; while (collapseData.Count > 0) { KeyValuePair<String, TypeReference> current = collapseData.Pop(); string dt = CreateDatatypeRef(current.Value, current.Value.Container as Property); string pCasedName = Util.Util.PascalCase(current.Key) == dt ? current.Key : Util.Util.PascalCase(current.Key) == Util.Util.PascalCase(cls.Name) ? Util.Util.PascalCase(current.Key) + (current.Value.Container as Property).Type.Class.Name : Util.Util.PascalCase(current.Key); path += "." + pCasedName; if (current.Key != "this") methodBody.AppendFormat("\t\t\t{0} = new {1}();\r\n", path, CreateDatatypeRef(current.Value, new Property())); if (collapseData.Count == 0) // Last item, generate factory method data { Dictionary<String, String[]> childFactoryMethod = CreateFactoryMethod(current.Value, path); // Get mandatory stuff methodBody.Append(childFactoryMethod["mandatory"][1]); methodParms = childFactoryMethod["mandatory"][0]; methodHelp = childFactoryMethod["mandatory"][2]; } } if (String.IsNullOrEmpty(methodParms)) return ""; // Now generate the constructor sw.WriteLine("\t\t/// <summary> CTOR Populates {0} </summary>", path); sw.WriteLine(methodHelp); sw.WriteLine("\t\tpublic {0}({1}) {{ ", Util.Util.PascalCase(cls.Name), methodParms.Remove(methodParms.Length - 1)); sw.WriteLine(methodBody.ToString()); sw.WriteLine("\t\t}"); return sw.ToString(); } return ""; }
/// <summary> /// Create the equality method /// </summary> private string CreateEqualityMethod(Class cls) { string genericString = ""; foreach (TypeParameter tp in cls.TypeParameters ?? new List<TypeParameter>()) genericString += tp + ","; if(!String.IsNullOrEmpty(genericString)) genericString = genericString.Substring(0, genericString.Length - 1); string dataReference = String.Format("{0}{1}", Util.Util.PascalCase(cls.Name), String.IsNullOrEmpty(genericString) ? "" : String.Format("<{0}>", genericString) ); StringWriter swEquals = new StringWriter(), swHash = new StringWriter(); // Method signatures swEquals.WriteLine("\t\t/// <summary>Overload of the equality determiner</summary>\r\n\t\tpublic bool Equals({0} other)\r\n\t\t{{\r\n\t\t\tbool equal = true;", dataReference ); swHash.WriteLine("\t\t/// <summary>Overload of hash code</summary>\r\n\t\tpublic override int GetHashCode()\r\n\t\t{"); swHash.WriteLine("\t\tint result = 1;"); swEquals.WriteLine("\t\t\tif(other != null) {"); foreach (var prop in cls.Content) { if (prop is Property) { if (prop.MaxOccurs == "1" || (prop as Property).Type.CoreDatatypeName != null && Datatypes.IsCollectionType((prop as Property).Type)) swEquals.WriteLine("\t\t\t\tequal &= this.{0} != null ? this.{0}.Equals(other.{0}) : other.{0} == null;", CreatePascalCasedName(prop as Property)); else { swEquals.WriteLine("\t\t\t\tequal &= this.{0}.Count == other.{0}.Count;", CreatePascalCasedName(prop as Property)); swEquals.WriteLine("\t\t\t\tfor(int i = 0; i < (equal ? this.{0}.Count : 0); i++) equal &= this.{0}[i] != null ? this.{0}[i].Equals(other.{0}[i]) : other.{0}[i] == null;", CreatePascalCasedName(prop as Property)); } swHash.WriteLine("result = 17 * result + ((this.{0} == null) ? 0 : this.{0}.GetHashCode());", CreatePascalCasedName(prop as Property)); } else { if ((prop as Choice).Content.Count == 0) { Trace.WriteLine("Skipping equality check for choice with 0 choice elements", "warn"); continue; } swEquals.WriteLine("\t\t\t\tequal &= this.{0} != null ? this.{0}.Equals(other.{0}) : other.{0} == null;", CreatePascalCasedName(prop as Choice)); swHash.WriteLine("result = 17 * result + ((this.{0} == null) ? 0 : this.{0}.GetHashCode());", CreatePascalCasedName(prop as Choice)); } } swEquals.WriteLine("\t\t\t\treturn equal;"); swEquals.WriteLine("\t\t\t}"); swEquals.WriteLine("\t\t\treturn false;"); swEquals.WriteLine("\t\t}"); swEquals.WriteLine("\t\t/// <summary>Overload of the equality determiner</summary>\r\n\t\tpublic override bool Equals(Object obj)\r\n\t\t{"); swEquals.WriteLine("\t\t\tif(obj is {0}) return Equals(obj as {0});", dataReference); swEquals.WriteLine("\t\t\treturn base.Equals(obj);"); swEquals.WriteLine("\t\t}"); swHash.WriteLine("\t\t\treturn result;\r\n\t\t}"); return String.Format("{0}\r\n{1}", swEquals.ToString(), swHash.ToString()); }
public virtual void Compile() { string modelName = staticModel.PackageLocation.ToString(MifCompiler.NAME_FORMAT); System.Diagnostics.Trace.WriteLine(string.Format("Compiling static model package '{0}'...", modelName), "debug"); // Check if the package has already been "compiled" if (ClassRepository.ContainsKey(staticModel.PackageLocation.ToString(MifCompiler.NAME_FORMAT))) { return; // Already compiled } // Create a COR namespace or package area based on the static model MohawkCollege.EHR.gpmr.Pipeline.Compiler.Mif20.Parsers.SubsystemParser.Parse(staticModel); // Static Model Derivation Suppliers Dictionary <string, Package> derivationSuppliers = new Dictionary <string, Package>(); foreach (StaticModelDerivation smd in staticModel.DerivedFrom) { derivationSuppliers.Add(smd.StaticModelDerivationId, this.repository.Find(smd.TargetStaticModel) as Package); } // Compile owned entry points first foreach (var ep in staticModel.OwnedEntryPoint) { var cls = staticModel.OwnedClass.Find(o => o.Choice is MohawkCollege.EHR.HL7v3.MIF.MIF20.StaticModel.Flat.Class && (o.Choice as MohawkCollege.EHR.HL7v3.MIF.MIF20.StaticModel.Flat.Class).Name == ep.ClassName); if (cls != null) { ProcessClassElement(cls, derivationSuppliers); } } // Compile all contained classes in the package foreach (ClassElement c in staticModel.OwnedClass) { ProcessClassElement(c, derivationSuppliers); } // Get a ref to the current sub-system MohawkCollege.EHR.gpmr.COR.SubSystem ss = (ClassRepository[staticModel.PackageLocation.Artifact == ArtifactKind.RIM ? "RIM" : staticModel.PackageLocation.ToString(MifCompiler.NAME_FORMAT)] as MohawkCollege.EHR.gpmr.COR.SubSystem); // Compile all contained associations foreach (Association a in staticModel.OwnedAssociation) { ParseAssociation(a, derivationSuppliers); } // Process entry points foreach (EntryPoint ep in staticModel.OwnedEntryPoint) { // Find the class MohawkCollege.EHR.gpmr.COR.Class cls = ss.FindClass(ep.ClassName); // The ProcStack keeps track of the properties the CascadeGenerics is // processing so that we don't get a stack overflow Stack <string> procStack = new Stack <string>(); // Process any generic providers that need to be cascaded down to child properties // This is required for interactions to function properly. CascadeGenerics(cls, procStack); // Assign as the ep if (ss.EntryPoint == null) { ss.EntryPoint = new List <MohawkCollege.EHR.gpmr.COR.Class>(); // Have to do this here so we don't have E/P array with 0 elements } ss.EntryPoint.Add(cls); } }
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()); } }
internal static MohawkCollege.EHR.gpmr.COR.Class Parse(ClassParameterInfo classInfo) { // Has this been processed? if (classInfo.CompilerRepository.ContainsKey(string.Format("{0}.{1}", classInfo.ScopedPackageName, classInfo.Class.Name))) { return(null); } // Get the vocabulary realm that this package is bound to string vocabularyRealm = classInfo.MifContainer is StaticModel && (classInfo.MifContainer as StaticModel).ImportedVocabularyModelPackage != null ? (classInfo.MifContainer as StaticModel).ImportedVocabularyModelPackage.Realm : null; // Parse the common (class base) portion of the classes MohawkCollege.EHR.gpmr.COR.Class retVal = Parse(classInfo.Class as ClassBase, vocabularyRealm, classInfo.CompilerRepository, classInfo.DerivationSuppliers); // Base class retVal.BaseClass = classInfo.EnforcedBaseClass; // Containing subsystem retVal.ContainerPackage = classInfo.CompilerRepository[classInfo.ScopedPackageName] as MohawkCollege.EHR.gpmr.COR.SubSystem; // Fire parsed event retVal.FireParsed(); #region Specializations retVal.SpecializedBy = new List <TypeReference>(); // Iterate through each child class and process where neccessary foreach (ClassGeneralization cg in (classInfo.Class as MohawkCollege.EHR.HL7v3.MIF.MIF20.StaticModel.Flat.Class).SpecializationChild) { TypeReference tr = new TypeReference(); tr.Name = string.Format("{0}.{1}", classInfo.ScopedPackageName, cg.ChildClassName); // Make a ref to the child class tr.MemberOf = classInfo.CompilerRepository; bool isCMET = false; // Get the child class if (classInfo.MifContainer is GlobalStaticModel) { // Get the CMET reference from the MIF class hierarchy ClassElement ce = (classInfo.MifContainer as GlobalStaticModel).OwnedClass.Find(delegate(ClassElement c) { if (c != null && c.Choice != null && c.Choice is CommonModelElementRef) { return((c.Choice as CommonModelElementRef).Name == cg.ChildClassName); } else { return(false); } }); string cmetName = ce != null ? (ce.Choice as CommonModelElementRef).CmetName ?? (ce.Choice as CommonModelElementRef).Name : ""; // Determine if the reference is a cmet and gathe t isCMET = cmetName != null && ce != null && classInfo.CompilerRepository.ContainsKey(cmetName) && classInfo.CompilerRepository[cmetName] is CommonTypeReference; if (isCMET) // A CMET was successfully resolved { tr = (classInfo.CompilerRepository[cmetName] as CommonTypeReference).Class; } else if (ce != null && MifCompiler.cmetBindings.ContainsKey(cmetName)) // A CMET was not resolved, but a binding exists! { string boundModel = MifCompiler.cmetBindings[cmetName]; MohawkCollege.EHR.gpmr.COR.Feature boundSubSystem = null; if (classInfo.CompilerRepository.TryGetValue(boundModel, out boundSubSystem)) { tr = (boundSubSystem as MohawkCollege.EHR.gpmr.COR.SubSystem).EntryPoint[0].CreateTypeReference(); } else { PackageParser.Parse(boundModel, classInfo.MifContainer.MemberOfRepository, classInfo.CompilerRepository); } } else if (ce != null) // MIF References a CMET but one was never processed? This is odd! { System.Diagnostics.Trace.WriteLine(string.Format("CMET '{0}' was never processed, therefore CommonModelElementRef can't be processed in file '{1}'", cmetName, classInfo.ScopedPackageName), "warn"); continue; } } // The child class has not been processed yet if (!classInfo.CompilerRepository.ContainsKey(tr.Name)) { if (isCMET) // Explicit, have to process another model { PackageParser.ParseClassFromPackage(tr.Name, classInfo.MifContainer.MemberOfRepository, classInfo.CompilerRepository); // Assign the base class //if ((classInfo.CompilerRepository[tr.Name] as MohawkCollege.EHR.gpmr.COR.Class).BaseClass != null) // System.Diagnostics.Debugger.Break(); } else { ClassParameterInfo parm2 = new ClassParameterInfo(); parm2.Class = (classInfo.MifContainer as StaticModel).OwnedClass.Find(o => (o.Choice is MohawkCollege.EHR.HL7v3.MIF.MIF20.StaticModel.Flat.Class && string.Format("{0}.{1}", classInfo.ScopedPackageName, (o.Choice as MohawkCollege.EHR.HL7v3.MIF.MIF20.StaticModel.Flat.Class).Name) == tr.Name)).Choice as ClassBase; parm2.CompilerRepository = classInfo.CompilerRepository; parm2.DerivationSuppliers = classInfo.DerivationSuppliers; parm2.MifContainer = classInfo.MifContainer; parm2.ScopedPackageName = classInfo.ScopedPackageName; parm2.EnforcedBaseClass = retVal.CreateTypeReference(); ClassParser.Parse(parm2); } } // Add to specialization list MohawkCollege.EHR.gpmr.COR.Feature f = null; if (classInfo.CompilerRepository.TryGetValue(tr.Name, out f)) { retVal.SpecializedBy.Add((f as MohawkCollege.EHR.gpmr.COR.Class).CreateTypeReference()); (f as MohawkCollege.EHR.gpmr.COR.Class).BaseClass = retVal.CreateTypeReference(); } else { Trace.WriteLine(String.Format("Cannot find base class '{0}' for '{1}'. Base class must exist before it can be specialized", tr.Name, retVal.Name), "error"); } } #endregion // Assign Temporary Membership to the compiler class repository so the // locating of a structural member will succeed retVal.MemberOf = classInfo.CompilerRepository; // Is a classCode enforcement placed on this class? #region Supplier Structural Domain if (classInfo.Class.SupplierStructuralDomain != null && classInfo.Class.SupplierStructuralDomain.Code != null) { MohawkCollege.EHR.gpmr.COR.Property clsa = retVal.FindMember("classCode", false, MohawkCollege.EHR.gpmr.COR.Property.PropertyTypes.Structural); if (clsa == null)// Class code is derived... we need to override it { clsa = retVal.FindMember("classCode", true, MohawkCollege.EHR.gpmr.COR.Property.PropertyTypes.Structural); // Any class code defined? if (clsa != null) { clsa = PropertyParser.Parse(clsa.DerivedFrom as ClassAttribute, vocabularyRealm, classInfo.CompilerRepository, classInfo.DerivationSuppliers); retVal.AddContent(clsa); } else // Makes no sense, we have a class code enforcement but no class code? { if (MifCompiler.hostContext.Mode == Pipeline.OperationModeType.Quirks) { Trace.WriteLine(String.Format("Supplier domain is specified on class '{0}' which has class code. Since GPMR is in quirks mode, the classCode attribute will be created", retVal.Name), "quirks"); clsa = new Property(); clsa.Name = "classCode"; clsa.PropertyType = Property.PropertyTypes.Structural; clsa.Conformance = ClassContent.ConformanceKind.Mandatory; retVal.AddContent(clsa); } else { throw new InvalidOperationException("Shouldn't be here. Supplier domain specified on a class with no classCode"); } } } #region Now populate the code domain // Supplier domains if (classInfo.Class.SupplierStructuralDomain != null) { var supplierStruct = classInfo.Class.SupplierStructuralDomain; if (supplierStruct.Code != null && !String.IsNullOrEmpty(supplierStruct.Code.Code)) // Fixed code { clsa.FixedValue = string.Format("{0}", supplierStruct.Code.Code); } // JF: If the code system is identified, then bind if (supplierStruct.Code != null && !String.IsNullOrEmpty(supplierStruct.Code.CodeSystemName)) // Very odd thing that is present in UV mifs { Trace.WriteLine(String.Format("'{0}' is specified as fixed code's code system, however no fixed code is present. Assuming this is a bound code system instead", "assumption")); clsa.SupplierDomain = classInfo.CompilerRepository.Find(o => o is CodeSystem && (o as CodeSystem).Name.Equals(supplierStruct.Code.CodeSystemName)) as Enumeration; if (clsa.SupplierDomain == null) { Trace.WriteLine(String.Format("'{0}' could not be bound to '{1}' as the code system was not found", clsa.Name, supplierStruct.Code.CodeSystemName), "warn"); } } if (supplierStruct.ConceptDomain != null) { clsa.SupplierDomain = classInfo.CompilerRepository.Find(o => o is ConceptDomain && (o as ConceptDomain).Name.Equals(supplierStruct.ConceptDomain.Name)) as Enumeration; if (clsa.SupplierDomain == null) { Trace.WriteLine(String.Format("'{0}' could not be bound to '{1}' as the concept domain was not found", clsa.Name, supplierStruct.ConceptDomain.Name), "warn"); } } if (supplierStruct.ValueSet != null) { clsa.SupplierDomain = classInfo.CompilerRepository.Find(o => o is ValueSet && (o as ValueSet).Name.Equals(supplierStruct.ValueSet.Name)) as Enumeration; if (clsa.SupplierDomain == null) { Trace.WriteLine(String.Format("'{0}' could not be bound to '{1}' as the value set was not found", clsa.Name, supplierStruct.ValueSet.Name), "warn"); } bool shouldFix = false; if (clsa.SupplierDomain != null) { var enumLiteral = clsa.SupplierDomain.Literals.Find(o => o.Name == supplierStruct.ValueSet.RootCode); shouldFix = enumLiteral != null && enumLiteral.RelatedCodes != null && enumLiteral.RelatedCodes.Count == 0; } if (shouldFix) { clsa.FixedValue = String.Format("{0}", supplierStruct.ValueSet.RootCode); } } // Supplier strength(s) if (supplierStruct.ValueSet != null) { clsa.SupplierStrength = supplierStruct.ValueSet.CodingStrength == CodingStrengthKind.CNE ? (Property.CodingStrengthKind?)Property.CodingStrengthKind.CodedNoExtensions: supplierStruct.ValueSet.CodingStrength == CodingStrengthKind.CWE ? (Property.CodingStrengthKind?)Property.CodingStrengthKind.CodedNoExtensions : null; } else { clsa.SupplierStrength = Property.CodingStrengthKind.CodedNoExtensions; System.Diagnostics.Trace.WriteLine(string.Format("No vocabulary value set on property {0}! Defaulting to CNE for supplier strength", retVal.Name), "assumption"); } } //if (classInfo.Class.SupplierStructuralDomain.Code != null) // clsa.FixedValue = string.Format("{0}{1}", classInfo.Class.SupplierStructuralDomain.Code.CodeSystem == null ? "" : classInfo.Class.SupplierStructuralDomain.Code.CodeSystem + ":", classInfo.Class.SupplierStructuralDomain.Code.Code); //if (classInfo.Class.SupplierStructuralDomain.ConceptDomain != null) // clsa.SupplierDomain = classInfo.Class.SupplierStructuralDomain.ConceptDomain.Name; //if (classInfo.Class.SupplierStructuralDomain.ValueSet != null) //{ // clsa.SupplierStrength = classInfo.Class.SupplierStructuralDomain.ValueSet.CodingStrength == CodingStrengthKind.CNE ? (Property.CodingStrengthKind?)Property.CodingStrengthKind.CodedNoExtensions : // classInfo.Class.SupplierStructuralDomain.ValueSet.CodingStrength == CodingStrengthKind.CWE ? (Property.CodingStrengthKind?)Property.CodingStrengthKind.CodedNoExtensions : null; // clsa.SupplierDomainValueSet = classInfo.Class.SupplierStructuralDomain.ValueSet.Id; //} //else //{ // clsa.SupplierStrength = Property.CodingStrengthKind.CodedNoExtensions; // System.Diagnostics.Trace.WriteLine(string.Format("No vocabulary value set on property {0}! Defaulting to CNE for supplier strength", retVal.Name), "assumption"); //} #endregion } #endregion // All specifications #region Specializations //if ((classInfo.Class as MohawkCollege.EHR.HL7v3.MIF.MIF20.StaticModel.Flat.Class).SpecializationChild != null && (classInfo.Class as MohawkCollege.EHR.HL7v3.MIF.MIF20.StaticModel.Flat.Class).SpecializationChild.Count > 0) //{ // retVal.SpecializedBy = new List<MohawkCollege.EHR.gpmr.COR.TypeReference>(); // foreach (ClassGeneralization cg in (classInfo.Class as MohawkCollege.EHR.HL7v3.MIF.MIF20.StaticModel.Flat.Class).SpecializationChild) // { // MohawkCollege.EHR.gpmr.COR.TypeReference specRef = new MohawkCollege.EHR.gpmr.COR.TypeReference(); // specRef.Name = string.Format("{0}.{1}", classInfo.ScopedPackageName, cg.ChildClassName); // MohawkCollege.EHR.gpmr.COR.Property noProp = new MohawkCollege.EHR.gpmr.COR.Property(); // noProp.Container = retVal; // specRef.Container = noProp; // retVal.SpecializedBy.Add(specRef); // } //} #endregion #region Behaviors // State machine on the class if (classInfo.Class.Behavior != null) { // Find the property that this state machine acts on Property stateProperty = retVal.FindMember(classInfo.Class.Behavior.SupplierStateAttributeName, false, Property.PropertyTypes.NonStructural | Property.PropertyTypes.Structural); stateProperty.StateMachine = StateMachineParser.Parse(classInfo.Class.Behavior); } #endregion #region Derivation Supplier if (classInfo.Class.DerivedFrom != null) { // Init retVal projection retVal.Realizations = new List <MohawkCollege.EHR.gpmr.COR.TypeReference>(); // Iterate through each class this class is a projection of (is based on) foreach (ClassDerivation cd in classInfo.Class.DerivedFrom) { try { // See if this class has been parsed Package derivationPackage = null; if (!classInfo.DerivationSuppliers.TryGetValue(cd.StaticModelDerivationId, out derivationPackage) || derivationPackage == null) { continue; } MohawkCollege.EHR.gpmr.COR.Feature ss = null; // Has the package been compiled? if (!classInfo.CompilerRepository.TryGetValue(string.Format("{0}", derivationPackage.PackageLocation.Artifact == ArtifactKind.RIM ? "RIM" : derivationPackage.PackageLocation.ToString(MifCompiler.NAME_FORMAT)), out ss)) { // Attempt to parse PackageParser.Parse(derivationPackage.PackageLocation.ToString(MifCompiler.NAME_FORMAT), derivationPackage.MemberOfRepository, classInfo.CompilerRepository); // Ditch if still can't find if (!classInfo.CompilerRepository.TryGetValue(string.Format("{0}", derivationPackage.PackageLocation.Artifact == ArtifactKind.RIM ? "RIM" : derivationPackage.PackageLocation.ToString(MifCompiler.NAME_FORMAT)), out ss) || ss == null) { System.Diagnostics.Trace.WriteLine(String.Format("Can't find derivation class '{0}' (derivation supplier {1})", cd.ClassName, cd.StaticModelDerivationId), "warn"); } } // Attempt to parse MohawkCollege.EHR.gpmr.COR.SubSystem supplierSubSystem = ss as MohawkCollege.EHR.gpmr.COR.SubSystem; // Find the class MohawkCollege.EHR.gpmr.COR.Class supplierClass = classInfo.CompilerRepository[string.Format("{0}.{1}", supplierSubSystem.Name, cd.ClassName)] as MohawkCollege.EHR.gpmr.COR.Class; // Add a realization retVal.Realizations.Add(supplierClass.CreateTypeReference()); // Now do some processing foreach (ClassContent cc in supplierClass.Content) { ClassContent rcc = null; // Find the class content we are talking about if (cc is Property) { rcc = retVal.FindMember(cc.Name, true, (cc as MohawkCollege.EHR.gpmr.COR.Property).PropertyType); } else { ; //TODO: Clean up choices so they match the realization class. Not sure if this supposed to be done } // Correct Items if (rcc != null) { if (MohawkCollege.EHR.gpmr.COR.Documentation.IsEmpty(rcc.Documentation))// Correct documentation { rcc.Documentation = cc.Documentation; } // Removed: This was supposed to correct missing supplier domains from the RMIMs using the RIM data, however it does // cause some issues. // if (rcc is MohawkCollege.EHR.gpmr.COR.Property && (rcc as MohawkCollege.EHR.gpmr.COR.Property).SupplierDomain == null && // (cc as MohawkCollege.EHR.gpmr.COR.Property).SupplierDomain != null) // { // (rcc as MohawkCollege.EHR.gpmr.COR.Property).SupplierDomain = (cc as MohawkCollege.EHR.gpmr.COR.Property).SupplierDomain; // (rcc as MohawkCollege.EHR.gpmr.COR.Property).SupplierStrength = (cc as MohawkCollege.EHR.gpmr.COR.Property).SupplierStrength; // } } } } catch (Exception e) { System.Diagnostics.Trace.WriteLine(string.Format("Could not find derivation supplier information for {0}", retVal.Name), "warn"); } } } #endregion #region Correct Vocabulary // This is quite a problem, when a property is bound to a value set, and that value set // is merely a pointer to other value sets of data we need to correct the pointer foreach (var property in retVal.Content) { // If the content is a property and it has a supplier domain, try to find the supplier domain if (property is Property && (property as Property).SupplierDomain != null) { // Now to correct the reference if ((property as Property).SupplierDomain.EnumerationReference != null && (property as Property).SupplierDomain.EnumerationReference.Count == 1) { (property as Property).SupplierDomain = (property as Property).SupplierDomain.EnumerationReference[0]; } } } #endregion // Sort the class content retVal.Content.Sort(new ClassContent.Comparator()); // Return return(retVal); }
/// <summary> /// Replace references in the class content <paramref name="cc"/> from <paramref name="s"/> /// to <paramref name="f"/> /// </summary> private void ReplaceReferences(Class s, Class f, ClassContent cc) { string fqnF = String.Format("{0}.{1}", f.ContainerName, f.Name), fqnS = String.Format("{0}.{1}", s.ContainerName, s.Name); if (cc is Property && (cc as Property).Type.Name == fqnS) UpdateReference((cc as Property).Type, fqnS, fqnF); else if (cc is Choice) foreach (var c in (cc as Choice).Content) ReplaceReferences(s, f, c); // Alternate traversals if(cc is Property) foreach (var alt in (cc as Property).AlternateTraversalNames ?? new List<Property.AlternateTraversalData>()) if (alt.CaseWhen.Name.Equals(fqnS)) { alt.CaseWhen.Name = fqnF; alt.CaseWhen.MemberOf = s.MemberOf; } }
/// <summary> /// Replace references in the repository from <paramref name="s"/> to /// <paramref name="f"/> /// </summary> private void ReplaceReferences(Class s, Class f) { // Get all classes var classes = from cls in Repository where cls.Value is Class select cls.Value as Class; string fqnF = String.Format("{0}.{1}", f.ContainerName, f.Name), fqnS = String.Format("{0}.{1}", s.ContainerName, s.Name); // Iterate through classes and update the references foreach (var cls in classes) { // Replace the base class if (cls.BaseClass != null && cls.BaseClass.Name == fqnS) cls.BaseClass.Name = fqnF; // Replace all references foreach (ClassContent cc in cls.Content) ReplaceReferences(s, f, cc); // Replace sub classes if (cls.SpecializedBy != null) { foreach (TypeReference tr in cls.SpecializedBy) UpdateReference(tr, fqnS, fqnF); } } // Iterate through interactions and update any references var interactions = from cls in Repository where cls.Value is Interaction select cls.Value as Interaction; foreach (var interaction in interactions) UpdateReference(interaction.MessageType, fqnS, fqnF); // Iterate through type references (CMETS) and update any referneces var cmets = from cls in Repository where cls.Value is CommonTypeReference && (cls.Value as CommonTypeReference).Class.Name == fqnS select cls.Value as CommonTypeReference; foreach (var cmet in cmets) UpdateReference(cmet.Class, fqnS, fqnF); }
/// <summary> /// Generate a choice structure for all child classes of <paramref name="property"/> /// </summary> private List<XmlSchemaElement> CreateChoice(Property property, Class cls, List<TypeReference> genericParameters, string prefix, List<string> includedModels, List<TypeReference> additionalCompileTargets) { List<XmlSchemaElement> retVal = new List<XmlSchemaElement>(); // Iterate through the child classes foreach (TypeReference tr in cls.SpecializedBy) { if (tr.Class == null) continue; // Not interested in non-implementable classes! else if (tr.Class.IsAbstract && tr.Class.SpecializedBy.Count > 0) retVal.AddRange(CreateChoice(property, tr.Class, genericParameters, prefix, includedModels, additionalCompileTargets)); // Clone the property and set the type reference to what we really want to set it up as Property choiceProperty = property.Clone() as Property; choiceProperty.MemberOf = property.MemberOf; choiceProperty.Type = tr; // Generate a choice element for this option XmlSchemaElement element = CreateElement(choiceProperty, genericParameters, prefix, includedModels, additionalCompileTargets); // Find the correct name for this element if (element.Name == property.Name && property.AlternateTraversalNames != null && property.AlternateTraversalNames.Count > 0) { MohawkCollege.EHR.gpmr.COR.Property.AlternateTraversalData name = property.AlternateTraversalNames.Find(o => o.CaseWhen.Name == tr.Name && (o.InteractionOwner.Name == prefix || prefix == null)); if (name.TraversalName != null) element.Name = name.TraversalName; } else element.Name = tr.Class.Name; retVal.Add(element); } return retVal; }
private string CreateValidateFunction(Class cls) { StringWriter sw = new StringWriter(), swEx = new StringWriter(); sw.WriteLine("\t\t/// <summary> Validates that the current instance meets conformance rules specified in the model </summary>"); sw.WriteLine("\t\t/// <returns>True if this instance is valid, false otherwise</returns>"); sw.WriteLine("\t\t/// <remarks>Provides only basic validation functionality</remarks>"); sw.WriteLine("\t\tpublic {0} bool Validate() {{\r\n\t\t\tbool isValid = {1};\r\n\t\t\tif(!isValid) return false;", "RIM." + Util.Util.PascalCase(cls.Name) == RimbaCsRenderer.RootClass ? "virtual" : "override", "RIM." + Util.Util.PascalCase(cls.Name) == RimbaCsRenderer.RootClass ? "true" : "base.Validate()"); swEx.WriteLine("\t\t/// <summary> Validates that the current instance meets conformance rules specified in the model returning the detected errors</summary>"); swEx.WriteLine("\t\t/// <returns>A list of detected errors</returns>"); swEx.WriteLine("\t\t/// <remarks>Provides only basic validation functionality</remarks>"); swEx.WriteLine("\t\tpublic {0} IEnumerable<MARC.Everest.Connectors.IResultDetail> ValidateEx() {{\r\n\t\t\tList<MARC.Everest.Connectors.IResultDetail> retVal = {1};", "RIM." + Util.Util.PascalCase(cls.Name) == RimbaCsRenderer.RootClass ? "virtual" : "override", "RIM." + Util.Util.PascalCase(cls.Name) == RimbaCsRenderer.RootClass ? "new List<MARC.Everest.Connectors.IResultDetail>()" : "base.ValidateEx() as List<MARC.Everest.Connectors.IResultDetail>"); // Write the validation function foreach (ClassContent cc in cls.Content) { string pCasedName = String.Empty; if (cc is Property) { pCasedName = CreatePascalCasedName(cc as Property); TypeReference tr = Datatypes.MapDatatype((cc as Property).Type); string dt = CreateDatatypeRef(tr, cc as Property); } else { if ((cc as Choice).Content.Count == 0) { Trace.WriteLine("Skipping validation for choice element with no choices", "warn"); continue; } pCasedName = CreatePascalCasedName(cc as Choice); } // If this property is mandatory or populated then it must have a valid value if (cc.Conformance == ClassContent.ConformanceKind.Mandatory || cc.Conformance == ClassContent.ConformanceKind.Populated) { if (cc.MaxOccurs != "1") { sw.WriteLine("\t\t\tisValid &= this.{0} != null && this.{0}.Count <= {1} && this.{0}.Count >= {2};", pCasedName, cc.MaxOccurs == "*" ? "int.MaxValue" : cc.MaxOccurs, cc.MinOccurs); swEx.WriteLine("\t\t\tif(!(this.{0} != null && this.{0}.Count <= {1} && this.{0}.Count >= {2})) retVal.Add(new MARC.Everest.Connectors.InsufficientRepetitionsResultDetail(MARC.Everest.Connectors.ResultDetailType.Error, \"{0} must have between {2} and {1} elements\", \"{0}\")); ", pCasedName, cc.MaxOccurs == "*" ? "int.MaxValue" : cc.MaxOccurs, cc.MinOccurs); } else { sw.WriteLine("\t\t\t#region Validate {0}", pCasedName); sw.WriteLine("\t\t\tif(this.{0} == null) return false; // automatically not valid", pCasedName); sw.WriteLine("\t\t\telse {"); sw.WriteLine("\t\t\t\tSystem.Reflection.MethodInfo mi = this.{0}.GetType().GetMethod(\"Validate\");", pCasedName); sw.WriteLine("\t\t\t\tisValid &= (mi != null) ? ((bool)mi.Invoke(this.{0}, null)) : true;", pCasedName); sw.WriteLine("\t\t\t}"); sw.WriteLine("\t\t\t#endregion"); swEx.WriteLine("\t\t\t#region Validate {0}", pCasedName); swEx.WriteLine("\t\t\tif(this.{0} == null) retVal.Add(new MARC.Everest.Connectors.MandatoryElementMissingResultDetail(MARC.Everest.Connectors.ResultDetailType.Error, \"{0} does not meet criteria for {1} element\", \"{0}\"));", pCasedName, cc.Conformance); swEx.WriteLine("\t\t\telse {"); swEx.WriteLine("\t\t\t\tSystem.Reflection.MethodInfo mi = this.{0}.GetType().GetMethod(\"ValidateEx\");", pCasedName); swEx.WriteLine("\t\t\t\tif(mi != null) {{ foreach(var res in (IEnumerable<MARC.Everest.Connectors.IResultDetail>)mi.Invoke(this.{0}, null)) {{ \r\n\t\t\t\t if(res.Location != null) res.Location = \"{0}.\" + res.Location; \r\n\t\t\t\t else res.Location = \"{0}\"; \r\n\t\t\t\t retVal.Add(res); \r\n\t\t\t }} \r\n\t\t\t }} ", pCasedName); swEx.WriteLine("\t\t\t}"); swEx.WriteLine("\t\t\t#endregion"); } } } sw.WriteLine("\t\t\treturn isValid;\r\n\t\t}"); swEx.WriteLine("\t\t\treturn retVal;\r\n\t\t}"); sw.WriteLine("\r\n\r\n{0}", swEx); return sw.ToString(); }
/// <summary> /// Gets a common backing type for a particular property type reference through children /// Handles when data types change through child implementations ( handled by .NET via NEW ) /// </summary> private TypeReference GetBackingFieldTypeThroughChildren(Property property, Class searchClass) { TypeReference initialType = property.Type; foreach (var child in searchClass.SpecializedBy) // iterate through children { var childProp = child.Class.Content.Find(o => o.Name == property.Name); if (childProp is Property) { TypeReference candidate = GetBackingFieldTypeThroughChildren(childProp as Property, child.Class); if (!candidate.Name.Equals(initialType.Name)) initialType = new TypeReference() { Name = null }; } } return initialType; }
/// <summary> /// Create the structure annotation /// </summary> private string CreateStructureAnnotation(Class cls) { return String.Format("@Structure(name = \"{0}\", structureType = StructureType.MESSAGETYPE, isEntryPoint = {1}, model =\"{2}\", publisher = {3})", cls.Name, cls.ContainerPackage.EntryPoint.Exists(o => o.Name == cls.Name) ? "true" : "false", cls.ContainerName, cls.Documentation != null ? "\"" + cls.Documentation.Copyright + "\"" : "Structure.NULL"); }
/// <summary> /// Create the equality method /// </summary> private string CreateEqualityMethod(Class cls) { string genericString = ""; foreach (TypeParameter tp in cls.TypeParameters ?? new List<TypeParameter>()) genericString += tp + ","; if (!String.IsNullOrEmpty(genericString)) genericString = genericString.Substring(0, genericString.Length - 1); string dataReference = String.Format("{0}{1}", Util.Util.PascalCase(cls.Name), String.IsNullOrEmpty(genericString) ? "" : String.Format("<{0}>", genericString) ); StringWriter swEquals = new StringWriter(), swHash = new StringWriter(); // Method signatures swEquals.WriteLine("\t\t/** Overload of the equality determiner */\r\n\t\tpublic boolean equals({0} other)\r\n\t\t{{\r\n\t\t\tboolean equal = true;", dataReference ); swHash.WriteLine("\t\t/** Overload of hash code */\r\n\t\t@Override\r\n\t\tpublic int hashCode()\r\n\t\t{"); swHash.WriteLine("\t\tint result = 31;"); swEquals.WriteLine("\t\t\tif(other != null) {"); foreach (var prop in cls.Content) { if (prop is Property) { if (prop.MaxOccurs == "1" || (prop as Property).Type.CoreDatatypeName != null && Datatypes.IsCollectionType((prop as Property).Type)) swEquals.WriteLine("\t\t\t\tequal &= this.get{0}() != null ? this.get{0}().equals(other.get{0}()) : other.get{0}() == null;", Util.Util.PascalCase(prop.Name)); else { swEquals.WriteLine("\t\t\t\tequal &= this.get{0}().size() == other.get{0}().size();", Util.Util.PascalCase(prop.Name)); swEquals.WriteLine("\t\t\t\tfor(int i = 0; i < (equal ? this.get{0}().size() : 0); i++) equal &= this.get{0}().get(i) != null ? this.get{0}().get(i).equals(other.get{0}().get(i)) : other.get{0}().get(i) == null;", Util.Util.PascalCase(prop.Name)); } swHash.WriteLine("result = 17 * result + ((this.get{0}() == null) ? 0 : this.get{0}().hashCode());", Util.Util.PascalCase(prop.Name)); } else { if ((prop as Choice).Content.Count == 0) { Trace.WriteLine("Skipping equality check for choice with 0 choice elements", "warn"); continue; } swEquals.WriteLine("\t\t\t\tequal &= this.get{0}() != null ? this.get{0}().equals(other.get{0}()) : other.get{0}() == null;", Util.Util.PascalCase(prop.Name)); swHash.WriteLine("result = 17 * result + ((this.get{0}() == null) ? 0 : this.get{0}().hashCode());", Util.Util.PascalCase(prop.Name)); } } swEquals.WriteLine("\t\t\t\treturn equal;"); swEquals.WriteLine("\t\t\t}"); swEquals.WriteLine("\t\t\treturn false;"); swEquals.WriteLine("\t\t}"); swEquals.WriteLine("\t\t/** Overload of the equality determiner*/\r\n\t\t@Override\r\n\t\tpublic boolean equals(Object obj)\r\n\t\t{"); // Replace Subject<Act> with Subject<?> if (cls.TypeParameters != null && cls.TypeParameters.Count > 0) dataReference = Util.Util.PascalCase(cls.Name); swEquals.WriteLine("\t\t\tif(obj instanceof {0}) return this.equals(({0})obj);", dataReference); swEquals.WriteLine("\t\t\treturn super.equals(obj);"); swEquals.WriteLine("\t\t}"); swHash.WriteLine("\t\t\treturn result;\r\n\t\t}"); return String.Format("{0}\r\n{1}", swEquals.ToString(), swHash.ToString()); }
private TypeReference GenerateCombinedType(List<TypeReference> matching) { Class generatedClass = new Class(); generatedClass.Name = ""; generatedClass.MemberOf = matching[0].Class.MemberOf; generatedClass.ContainerPackage = (matching[0].Class as Class).ContainerPackage; generatedClass.Content = new List<ClassContent>(); // Combine everything foreach (var t in matching) { generatedClass.Name += t.Class.Name; List<Property> elements = FlattenPropertyHierarchy(t.Class.Content); int order = 0; foreach (var ele in elements) { Property clonedElement = ele.Clone() as Property, currentGeneratedElement = generatedClass.Content.Find(o => o.Name == ele.Name) as Property; // clone the property clonedElement.Container = generatedClass; if (ele.Container is Choice) clonedElement.Realization = (ele.Container as Choice).Realization; if (currentGeneratedElement == null) // Doesn't already exist! generatedClass.Content.Insert(order, clonedElement); else if (currentGeneratedElement != null && currentGeneratedElement.Type.Name != ele.Type.Name && ele.Type.Class != null) // a property with the same name but with different type exists // Combine those classes currentGeneratedElement.Type = GenerateCombinedType(new List<TypeReference>() { currentGeneratedElement.Type, ele.Type }); order++; } } return generatedClass.CreateTypeReference(); }
/// <summary> /// Collapse the data type of <paramref name="cc"/> so that it is the only meaningful data type provided by its /// natural type /// </summary> private void CollapseMemberType(ClassContent cc, Class context) { if(!(cc is Property)) throw new InvalidOperationException("Can't collapse this member type"); // Not a candidate // The condition for this type of collection is that the referenced type: // 1. Provides only ONE property (after --collapse-ignore are removed) // 2. The ONE property is mandatory (must be provided) List<ClassContent> content = (cc as Property).Type.Class.GetFullContent(); content.RemoveAll(a => CorCollapserPipelineTrigger.collapseIgnore.Contains(a.Name)); // Remove the ignore if (CorCollapserPipelineTrigger.collapseIgnoreFixed) content.RemoveAll(o => o is Property && !String.IsNullOrEmpty((o as Property).FixedValue) && (o as Property).PropertyType == Property.PropertyTypes.Structural); if(content.Count != 1) throw new InvalidOperationException("Can't collapse type with more than one meaningful content"); // can't collapse this relation as there is more than sub-property ClassContent candidate = content[0]; cc.Annotations.Add(new CodeCollapseAnnotation() { Name = cc.Name, Order = 0, Property = cc as Property }); // Has this collapsed member had any collapsing if (candidate.Annotations.Count > 0) { // Get all code collapse annotations from the candidate List<Annotation> collapseAnnotations = candidate.Annotations.FindAll(o => o is CodeCollapseAnnotation); // Find one that links it to the candidate //collapseAnnotations.RemoveAll(o => candidate.Annotations.Count(ca => (ca as CodeCollapseAnnotation).Property == (o as CodeCollapseAnnotation).Property) != 1); CodeCollapseAnnotation oldCca = null; foreach (CodeCollapseAnnotation cca in collapseAnnotations) { cca.Order = cc.Annotations.Count; if (cc.Annotations.Count(ca =>ca is CodeCollapseAnnotation && (ca as CodeCollapseAnnotation).Property == cca.Property) == 0) cc.Annotations.Add(cca); oldCca = cca; } } else cc.Annotations.Add(new CodeCollapseAnnotation() { Name = candidate.Name, Order = 1, Property = candidate as Property }); // Determine a better name if (CorCollapserPipelineTrigger.collapseSpecialNaming) { // We collapse the collapsee's name into the parent by default. string preferredName = candidate.Name; // If the container for the property already has an element by the name we prefer, we must // or the collapsee's name is in the useless words list we must keep the current name, or if the // parent's name is in the structurally important collection if((cc.Container as Class).GetFullContent().Find(o=>o.Name == preferredName) != null || CorCollapserPipelineTrigger.uselessWords.Contains(preferredName) || CorCollapserPipelineTrigger.importantWords.Contains(cc.Name)) preferredName = cc.Name; cc.Name = preferredName; } // Now determine if we can collapse (cc as Property).Type = (candidate as Property).Type.Clone() as TypeReference; (cc as Property).SupplierDomain = (candidate as Property).SupplierDomain; (cc as Property).SupplierStrength = (candidate as Property).SupplierStrength; (cc as Property).Type.Container = cc; (cc as Property).Type.MemberOf = cc.MemberOf; // Update documentation if((cc as Property).Documentation == null && candidate.Documentation != null) (cc as Property).Documentation = candidate.Documentation; }