Example #1
0
        /// <summary>
        /// Uses forward algorithm to go from this constraint forward through the tree
        /// </summary>
        /// <param name="aTemplate"></param>
        /// <param name="aTemplateConstraint"></param>
        /// <returns></returns>
        public static string CreateFullBranchedParentContext(string aPrefix, Template aTemplate, TemplateConstraint aTemplateConstraint)
        {
            TemplateConstraint current = aTemplateConstraint;
            var igTypePlugin           = aTemplate.ImplementationGuideType.GetPlugin();

            string templateContext = TemplateContextBuilder.BuildContextString(
                aPrefix,
                igTypePlugin.TemplateIdentifierXpath,
                igTypePlugin.TemplateVersionIdentifierXpath,
                aTemplate) + "/";

            return(templateContext + CreateFullBranchedParentContext(aPrefix, aTemplateConstraint, isTarget: true));
        }
        /// <summary>
        /// Adds the constraints for the closed template to ensure that no template id's other than those explicitly named are used in the xml.
        /// </summary>
        /// <param name="aClosedTemplate">Closed template to generate the constraint for</param>
        /// <param name="aPhase">The error phase for the schematron</param>
        /// <returns>
        /// Pattern that was added to the schematron
        /// </returns>
        public Pattern AddClosedTemplateConstraints(Template aClosedTemplate, Phase aPhase)
        {
            if (aClosedTemplate.IsOpen)
            {
                return(null);
            }

            Pattern newPattern = null;
            string  test       = GenerateClosedTemplateConstraints(aClosedTemplate);

            if (!string.IsNullOrEmpty(test))
            {
                string templateContext = TemplateContextBuilder.BuildContextString(
                    this.ig.ImplementationGuideType.SchemaPrefix,
                    this.igTypePlugin.TemplateIdentifierXpath,
                    this.igTypePlugin.TemplateVersionIdentifierXpath,
                    aClosedTemplate);

                newPattern = new Pattern()
                {
                    ID   = string.Format("p-{0}-CLOSEDTEMPLATE", aClosedTemplate.Oid),
                    Name = string.Format("p-{0}-CLOSEDTEMPLATE", aClosedTemplate.Oid)
                };

                Rule newRule = new Rule()
                {
                    Id      = string.Format("r-{0}-errors-CL", aClosedTemplate.Oid),
                    Context = templateContext
                };

                Assertion newAssertion = new Assertion()
                {
                    Id               = string.Format("{0}-{1}", aClosedTemplate.OwningImplementationGuideId, aClosedTemplate.Id),
                    IdPostFix        = "-CL",
                    AssertionMessage = string.Format("'{0}' is a closed template, only defined templates are allowed.", aClosedTemplate.Oid),
                    Test             = test
                };

                newRule.Assertions.Add(newAssertion);

                newPattern.Rules.Add(newRule);

                if (newPattern.Rules.Count > 0)
                {
                    aPhase.ActivePatterns.Add(newPattern);
                }
            }
            return(newPattern);
        }
        internal void GenerateBranchedPattern(Conformance MinimumConformanceLevel, Pattern aPattern, IEnumerable <TemplateConstraint> aConstraints, IEnumerable <TemplateConstraint> aTemplateConstraints, Template aTemplate, Phase aPhase)
        {
            string     rulePostFix           = MinimumConformanceLevel == Conformance.SHALL ? "-errors" : "-warnings";
            string     errorId               = aTemplate.Oid.Trim() + "-{0}";
            string     patternErrorId        = "p-" + errorId;
            string     ruleErrorId           = "r-" + errorId + "-branch-{0}" + rulePostFix;
            List <int> AlreadyGeneratedRoots = new List <int>();

            foreach (var branch in aConstraints)
            {
                if (!branch.CategoryIsMatch(this.categories))
                {
                    continue;
                }

                TemplateConstraint root = GetBranch(branch);
                //get all constraints that have this root as their parent
                if (!AlreadyGeneratedRoots.Contains(root.Id))
                {
                    AlreadyGeneratedRoots.Add(root.Id);
                    string context = TemplateContextBuilder.CreateFullBranchedParentContext(this.ig.ImplementationGuideType.SchemaPrefix, aTemplate, root);
                    var    rule    = new Rule();
                    rule.Id      = string.Format(ruleErrorId, root.Number);
                    rule.Context = context;

                    // No branch identifiers unless there is custom schematron
                    var branchedConstraints = aTemplateConstraints.Where(c => (c.Id != root.Id) && (root == GetNearestBranch(c)))
                                              .Where(y => !y.IsBranchIdentifier || !string.IsNullOrEmpty(y.Schematron));

                    foreach (var constraint in branchedConstraints)
                    {
                        if (!constraint.CategoryIsMatch(this.categories))
                        {
                            continue;
                        }

                        try
                        {
                            Conformance leastConformanceForGraph = GetMinimumConformanceForConstraint(constraint);
                            //exclude MAYs (we never want a constraint whose conformance is MAY, we will take graph MAYs but not directly on the constraint)
                            if (constraint.BusinessConformanceType == Conformance.MAY || constraint.BusinessConformanceType == Conformance.MAY_NOT ||
                                ShouldSkipConstraint(constraint) || !MeetsConformance(MinimumConformanceLevel, leastConformanceForGraph))
                            {
                                continue;
                            }

                            //skip direct SHOULD on SHALL
                            if (constraint.BusinessConformanceType == Conformance.SHOULD && MinimumConformanceLevel == Conformance.SHALL)
                            {
                                continue;
                            }

                            //skip direct SHALL on SHOULD
                            if (constraint.BusinessConformanceType == Conformance.SHALL && MinimumConformanceLevel == Conformance.SHOULD)
                            {
                                continue;
                            }

                            // Skip for constraints that are rooted, but only when there is either custom schematron or it is a primitive
                            if (constraint.IsSchRooted && (!string.IsNullOrEmpty(constraint.Schematron) || constraint.IsPrimitive))
                            {
                                continue;
                            }

                            rule.Assertions.Add(GetAssertion(constraint, string.Format("-branch-{0}", root.Number)));
                        }
                        catch (Exception ex)
                        {
                            Log.For(this).Error("Error getting assertion for constraint {0} on template {1}.", ex, constraint.Id, constraint.TemplateId);
                            throw ex;
                        }
                    }

                    if (rule.Assertions.Count > 0)
                    {
                        aPattern.Rules.Add(rule);
                    }
                }
            }
        }
        internal void AddTemplate(Template template, Phase errorPhase, Phase warningPhase, bool isImplied = false)
        {
            string errorId                 = template.Oid.Trim() + "-errors";
            string warningId               = template.Oid.Trim() + "-warnings";
            string patternErrorId          = "p-" + errorId;
            string patternWarningId        = "p-" + warningId;
            string ruleErrorId             = "r-" + errorId;
            string ruleWarningId           = "r-" + warningId;
            string impliedPatternErrorId   = null;
            string impliedPatternWarningId = null;
            string impliedRuleErrorId      = null;
            string impliedRuleWarningId    = null;

            // Add the implied template first
            if (template.ImpliedTemplate != null && template.ImpliedTemplateId != template.Id && this.templates.Contains(template.ImpliedTemplate))
            {
                string impliedErrorId   = template.ImpliedTemplate.Oid.Trim() + "-errors";
                string impliedWarningId = template.ImpliedTemplate.Oid.Trim() + "-warnings";
                impliedPatternErrorId   = "p-" + impliedErrorId;
                impliedPatternWarningId = "p-" + impliedWarningId;
                impliedRuleErrorId      = "r-" + impliedErrorId;
                impliedRuleWarningId    = "r-" + impliedWarningId;

                // Make sure we haven't already added the implied template and that this is not an endless recursive loop
                if (!errorPhase.ActivePatterns.Exists(y => y.ID == impliedPatternErrorId) && !warningPhase.ActivePatterns.Exists(y => y.ID == impliedPatternWarningId))
                {
                    AddTemplate(template.ImpliedTemplate, errorPhase, warningPhase, true);
                }
            }

            bool alreadyGeneratedErrorPattern   = errorPhase.ActivePatterns.Exists(y => y.ID == patternErrorId);
            bool alreadyGeneratedWarningPattern = warningPhase.ActivePatterns.Exists(y => y.ID == patternWarningId);

            if (alreadyGeneratedErrorPattern && alreadyGeneratedWarningPattern)
            {
                return;
            }

            //realize the list so that all of them are pulled from database
            var constraints = template.ChildConstraints.ToList();

            //NOTE: there are also child templates on the template class. If GetRecursiveTemplates does not flatten the heirarchy, then we'll need to walk the tree. We could do this in the linq query, but I' not certain
            //whether the context is set explicitly in the child templates, or whether it's implied that the implementer (me) would have to discover it.

            //get only SHALLS that aren't part of a branch and don't have optional parents
            var requiredConformance = (from c in constraints
                                       where (!string.IsNullOrEmpty(c.Conformance) &&
                                              (c.BusinessConformanceType == Conformance.SHALL || c.BusinessConformanceType == Conformance.SHALL_NOT)) &&
                                       (!c.IsBranchIdentifier || (c.IsBranchIdentifier && !string.IsNullOrEmpty(c.Schematron)))
                                       select c).OrderBy(c => c.Id);

            //get all SHOULDs and only SHALLs having optional parents but that aren't part of a branch
            var optionalConformance = (from c in constraints
                                       where ((!string.IsNullOrEmpty(c.Conformance) &&
                                               (c.BusinessConformanceType == Conformance.SHOULD ||
                                                c.BusinessConformanceType == Conformance.SHOULD_NOT))) &&
                                       !(c.IsBranchIdentifier == true)
                                       select c).OrderBy(c => c.Id).ToList();

            //add in optional value conformance on required constraints
            AddOptionalValueConformanceOnRequiredElement(optionalConformance, constraints);

            //get only SHALLs that are leaf level of a branch and don't have optional parents
            var branchedRequiredConformance = (from c in constraints
                                               where (!string.IsNullOrEmpty(c.Conformance) &&
                                                      c.BusinessConformanceType == Conformance.SHALL || c.BusinessConformanceType == Conformance.SHALL_NOT) &&
                                               c.HasParentBranch()
                                               select c).OrderBy(c => c.Id);

            //get all SHOULDs and only SHALLs having optional parents but that are leaf level part of a branch
            var branchedOptionalConformance = (from c in constraints
                                               where ((!string.IsNullOrEmpty(c.Conformance) &&
                                                       (c.BusinessConformanceType == Conformance.SHOULD ||
                                                        c.BusinessConformanceType == Conformance.SHOULD_NOT)) ||
                                                      (IsOptionalParent(c) && HasRequiredElement(c)))
                                               select c).Where(c => IsBranchDescendent(c)).OrderBy(c => c.Id);
            string templateContext = string.Empty;

            templateContext = TemplateContextBuilder.BuildContextString(
                this.ig.ImplementationGuideType.SchemaPrefix,
                this.igTypePlugin.TemplateIdentifierXpath,
                this.igTypePlugin.TemplateVersionIdentifierXpath,
                template);

            Pattern ErrorPattern = null;

            ErrorPattern = GeneratePattern(Conformance.SHALL, requiredConformance, errorPhase, patternErrorId, ruleErrorId, templateContext, impliedPatternErrorId, impliedRuleErrorId, isImplied);

            Pattern WarningPattern = null;

            WarningPattern = GeneratePattern(Conformance.SHOULD, optionalConformance, warningPhase, patternWarningId, ruleWarningId, templateContext, impliedPatternWarningId, impliedRuleWarningId, isImplied);

            if (branchedRequiredConformance.Count() > 0)
            {
                GenerateBranchedPattern(Conformance.SHALL, ErrorPattern, branchedRequiredConformance, constraints, template, errorPhase);
            }

            if (branchedOptionalConformance.Count() > 0)
            {
                GenerateBranchedPattern(Conformance.SHOULD, WarningPattern, branchedOptionalConformance, constraints, template, warningPhase);
            }
        }