Search in sources :

Example 46 with NodeStack

use of org.hl7.fhir.validation.instance.utils.NodeStack in project org.hl7.fhir.core by hapifhir.

the class MeasureValidator method validateMeasureReportGroups.

private void validateMeasureReportGroups(ValidatorHostContext hostContext, MeasureContext m, List<ValidationMessage> errors, Element mr, NodeStack stack, boolean inProgress) {
    if (m.groups().size() == 0) {
        // only validate the report groups if the measure has groups.
        return;
    }
    List<MeasureGroupComponent> groups = new ArrayList<MeasureGroupComponent>();
    List<Element> glist = mr.getChildrenByName("group");
    if (glist.size() == 1 && m.groups().size() == 1) {
        // if there's only one group, it can be ((and usually is) anonymous)
        // but we still check that the code, if both have one, is consistent.
        Element mrg = glist.get(0);
        NodeStack ns = stack.push(mrg, 0, mrg.getProperty().getDefinition(), mrg.getProperty().getDefinition());
        if (m.groups().get(0).hasCode() && mrg.hasChild("code")) {
            CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrg.getNamedChild("code"));
            if (rule(errors, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), hasUseableCode(cc), I18nConstants.MEASURE_MR_GRP_NO_USABLE_CODE)) {
                rule(errors, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), cc.matches(m.groups().get(0).getCode()), I18nConstants.MEASURE_MR_GRP_NO_WRONG_CODE, DataRenderer.display(context, cc), DataRenderer.display(context, m.groups().get(0).getCode()));
            }
        }
        validateMeasureReportGroup(hostContext, m, m.groups().get(0), errors, mrg, ns, inProgress);
    } else {
        int i = 0;
        for (Element mrg : glist) {
            NodeStack ns = stack.push(mrg, i, mrg.getProperty().getDefinition(), mrg.getProperty().getDefinition());
            CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrg.getNamedChild("code"));
            if (rule(errors, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), cc != null, I18nConstants.MEASURE_MR_GRP_NO_CODE)) {
                MeasureGroupComponent mg = getGroupForCode(cc, m.measure());
                if (rule(errors, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), mg != null, I18nConstants.MEASURE_MR_GRP_UNK_CODE)) {
                    if (rule(errors, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), !groups.contains(mg), I18nConstants.MEASURE_MR_GRP_DUPL_CODE)) {
                        groups.add(mg);
                        validateMeasureReportGroup(hostContext, m, mg, errors, mrg, ns, inProgress);
                    }
                }
            }
            i++;
        }
        boolean dataCollection = isDataCollection(mr);
        for (MeasureGroupComponent mg : m.groups()) {
            if (!groups.contains(mg)) {
                rule(errors, IssueType.BUSINESSRULE, mr.line(), mr.col(), stack.getLiteralPath(), groups.contains(mg) || dataCollection, I18nConstants.MEASURE_MR_GRP_MISSING_BY_CODE, DataRenderer.display(context, mg.getCode()));
            }
        }
    }
}
Also used : Element(org.hl7.fhir.r5.elementmodel.Element) ArrayList(java.util.ArrayList) MeasureGroupComponent(org.hl7.fhir.r5.model.Measure.MeasureGroupComponent) NodeStack(org.hl7.fhir.validation.instance.utils.NodeStack) CodeableConcept(org.hl7.fhir.r5.model.CodeableConcept)

Example 47 with NodeStack

use of org.hl7.fhir.validation.instance.utils.NodeStack in project org.hl7.fhir.core by hapifhir.

the class InstanceValidator method listChildren.

public List<ElementInfo> listChildren(Element element, NodeStack stack) {
    // 1. List the children, and remember their exact path (convenience)
    List<ElementInfo> children = new ArrayList<ElementInfo>();
    ChildIterator iter = new ChildIterator(this, stack.getLiteralPath(), element);
    while (iter.next()) children.add(new ElementInfo(iter.name(), iter.element(), iter.path(), iter.count()));
    return children;
}
Also used : ElementInfo(org.hl7.fhir.validation.instance.utils.ElementInfo) ArrayList(java.util.ArrayList) ChildIterator(org.hl7.fhir.validation.instance.utils.ChildIterator)

Example 48 with NodeStack

use of org.hl7.fhir.validation.instance.utils.NodeStack in project org.hl7.fhir.core by hapifhir.

the class InstanceValidator method checkCode.

// public API
private boolean checkCode(List<ValidationMessage> errors, Element element, String path, String code, String system, String version, String display, boolean checkDisplay, NodeStack stack) throws TerminologyServiceException {
    long t = System.nanoTime();
    boolean ss = context.supportsSystem(system);
    timeTracker.tx(t, "ss " + system);
    if (ss) {
        t = System.nanoTime();
        ValidationResult s = checkCodeOnServer(stack, code, system, version, display, checkDisplay);
        timeTracker.tx(t, "vc " + system + "#" + code + " '" + display + "'");
        if (s == null)
            return true;
        if (s.isOk()) {
            if (s.getMessage() != null)
                txWarning(errors, s.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, s == null, I18nConstants.TERMINOLOGY_PASSTHROUGH_TX_MESSAGE, s.getMessage(), system, code);
            return true;
        }
        if (s.getErrorClass() != null && s.getErrorClass().isInfrastructure())
            txWarning(errors, s.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, s == null, s.getMessage());
        else if (s.getSeverity() == IssueSeverity.INFORMATION)
            txHint(errors, s.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, s == null, s.getMessage());
        else if (s.getSeverity() == IssueSeverity.WARNING)
            txWarning(errors, s.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, s == null, s.getMessage());
        else
            return txRule(errors, s.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, s == null, I18nConstants.TERMINOLOGY_PASSTHROUGH_TX_MESSAGE, s.getMessage(), system, code);
        return true;
    } else if (system.startsWith("http://build.fhir.org") || system.startsWith("https://build.fhir.org")) {
        rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_WRONG_BUILD, system, suggestSystemForBuild(system));
        return false;
    } else if (system.startsWith("http://hl7.org/fhir") || system.startsWith("https://hl7.org/fhir") || system.startsWith("http://www.hl7.org/fhir") || system.startsWith("https://www.hl7.org/fhir")) {
        if (SIDUtilities.isknownCodeSystem(system)) {
            // else don't check these (for now)
            return true;
        } else if (system.startsWith("http://hl7.org/fhir/test")) {
            // we don't validate these
            return true;
        } else if (system.endsWith(".html")) {
            rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_WRONG_HTML, system, suggestSystemForPage(system));
            return false;
        } else {
            CodeSystem cs = getCodeSystem(system);
            if (rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, cs != null, I18nConstants.TERMINOLOGY_TX_SYSTEM_UNKNOWN, system)) {
                ConceptDefinitionComponent def = getCodeDefinition(cs, code);
                if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, def != null, I18nConstants.TERMINOLOGY_TX_CODE_UNKNOWN, system, code))
                    return warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, display == null || display.equals(def.getDisplay()), I18nConstants.TERMINOLOGY_TX_DISPLAY_WRONG, def.getDisplay());
            }
            return false;
        }
    } else if (context.isNoTerminologyServer() && Utilities.existsInList(system, "http://loinc.org", "http://unitsofmeasure.org", "http://hl7.org/fhir/sid/icd-9-cm", "http://snomed.info/sct", "http://www.nlm.nih.gov/research/umls/rxnorm")) {
        // no checks in this case
        return true;
    } else if (startsWithButIsNot(system, "http://snomed.info/sct", "http://loinc.org", "http://unitsofmeasure.org", "http://www.nlm.nih.gov/research/umls/rxnorm")) {
        rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_INVALID, system);
        return false;
    } else {
        try {
            if (context.fetchResourceWithException(ValueSet.class, system) != null) {
                rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_VALUESET, system);
            // Lloyd: This error used to prohibit checking for downstream issues, but there are some cases where that checking needs to occur.  Please talk to me before changing the code back.
            }
            boolean done = false;
            if (system.startsWith("https:") && system.length() > 7) {
                String ns = "http:" + system.substring(6);
                CodeSystem cs = getCodeSystem(ns);
                if (cs != null || Utilities.existsInList(system, "https://loinc.org", "https://unitsofmeasure.org", "https://snomed.info/sct", "https://www.nlm.nih.gov/research/umls/rxnorm")) {
                    rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_HTTPS, system);
                    done = true;
                }
            }
            hint(errors, IssueType.UNKNOWN, element.line(), element.col(), path, done, I18nConstants.TERMINOLOGY_TX_SYSTEM_NOTKNOWN, system);
            return true;
        } catch (Exception e) {
            return true;
        }
    }
}
Also used : ConceptDefinitionComponent(org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent) ValidationResult(org.hl7.fhir.r5.context.IWorkerContext.ValidationResult) CodeSystem(org.hl7.fhir.r5.model.CodeSystem) ValueSet(org.hl7.fhir.r5.model.ValueSet) TerminologyServiceException(org.hl7.fhir.exceptions.TerminologyServiceException) DefinitionException(org.hl7.fhir.exceptions.DefinitionException) IOException(java.io.IOException) FHIRException(org.hl7.fhir.exceptions.FHIRException) NotImplementedException(org.apache.commons.lang3.NotImplementedException) PathEngineException(org.hl7.fhir.exceptions.PathEngineException) FHIRLexerException(org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException)

Example 49 with NodeStack

use of org.hl7.fhir.validation.instance.utils.NodeStack in project org.hl7.fhir.core by hapifhir.

the class InstanceValidator method checkReference.

private void checkReference(ValidatorHostContext hostContext, List<ValidationMessage> errors, String path, Element element, StructureDefinition profile, ElementDefinition container, String parentType, NodeStack stack) throws FHIRException {
    Reference reference = ObjectConverter.readAsReference(element);
    String ref = reference.getReference();
    if (Utilities.noString(ref)) {
        if (!path.contains("element.pattern")) {
            // this business rule doesn't apply to patterns
            if (Utilities.noString(reference.getIdentifier().getSystem()) && Utilities.noString(reference.getIdentifier().getValue())) {
                warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, !Utilities.noString(element.getNamedChildValue("display")), I18nConstants.REFERENCE_REF_NODISPLAY);
            }
        }
        return;
    } else if (Utilities.existsInList(ref, "http://tools.ietf.org/html/bcp47")) {
        // special known URLs that can't be validated but are known to be valid
        return;
    }
    warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, !isSuspiciousReference(ref), I18nConstants.REFERENCE_REF_SUSPICIOUS, ref);
    ResolvedReference we = localResolve(ref, stack, errors, path, hostContext.getRootResource(), hostContext.getGroupingResource(), element);
    String refType;
    if (ref.startsWith("#")) {
        refType = "contained";
    } else {
        if (we == null) {
            refType = "remote";
        } else {
            refType = "bundled";
        }
    }
    ReferenceValidationPolicy pol;
    if (refType.equals("contained") || refType.equals("bundled")) {
        pol = ReferenceValidationPolicy.CHECK_VALID;
    } else {
        if (policyAdvisor == null)
            pol = ReferenceValidationPolicy.IGNORE;
        else
            pol = policyAdvisor.policyForReference(this, hostContext.getAppContext(), path, ref);
    }
    if (pol.checkExists()) {
        if (we == null) {
            if (!refType.equals("contained")) {
                if (fetcher == null) {
                    throw new FHIRException(context.formatMessage(I18nConstants.RESOURCE_RESOLUTION_SERVICES_NOT_PROVIDED));
                } else {
                    Element ext = null;
                    if (fetchCache.containsKey(ref)) {
                        ext = fetchCache.get(ref);
                    } else {
                        try {
                            ext = fetcher.fetch(this, hostContext.getAppContext(), ref);
                        } catch (IOException e) {
                            if (STACK_TRACE)
                                e.printStackTrace();
                            throw new FHIRException(e);
                        }
                        if (ext != null) {
                            setParents(ext);
                            fetchCache.put(ref, ext);
                        }
                    }
                    we = ext == null ? null : makeExternalRef(ext, path);
                }
            }
        }
        boolean ok = (allowExamples && (ref.contains("example.org") || ref.contains("acme.com"))) || (we != null || pol == ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS);
        rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, ok, I18nConstants.REFERENCE_REF_CANTRESOLVE, ref);
    }
    String ft;
    if (we != null) {
        ft = we.getType();
    } else {
        ft = tryParse(ref);
    }
    if (reference.hasType()) {
        // R4 onwards...
        // the type has to match the specified
        String tu = isAbsolute(reference.getType()) ? reference.getType() : "http://hl7.org/fhir/StructureDefinition/" + reference.getType();
        TypeRefComponent containerType = container.getType("Reference");
        if (!containerType.hasTargetProfile(tu) && !containerType.hasTargetProfile("http://hl7.org/fhir/StructureDefinition/Resource") && !containerType.getTargetProfile().isEmpty()) {
            boolean matchingResource = false;
            for (CanonicalType target : containerType.getTargetProfile()) {
                StructureDefinition sd = resolveProfile(profile, target.asStringValue());
                if (rule(errors, IssueType.NOTFOUND, element.line(), element.col(), path, sd != null, I18nConstants.REFERENCE_REF_CANTRESOLVEPROFILE, target.asStringValue())) {
                    if (("http://hl7.org/fhir/StructureDefinition/" + sd.getType()).equals(tu)) {
                        matchingResource = true;
                        break;
                    }
                }
            }
            rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, matchingResource, I18nConstants.REFERENCE_REF_WRONGTARGET, reference.getType(), container.getType("Reference").getTargetProfile());
        }
        // the type has to match the actual
        rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, ft == null || ft.equals(reference.getType()), I18nConstants.REFERENCE_REF_BADTARGETTYPE, reference.getType(), ft);
    }
    if (we != null && pol.checkType()) {
        if (warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, ft != null, I18nConstants.REFERENCE_REF_NOTYPE)) {
            // we validate as much as we can. First, can we infer a type from the profile?
            boolean ok = false;
            TypeRefComponent type = getReferenceTypeRef(container.getType());
            if (type.hasTargetProfile() && !type.hasTargetProfile("http://hl7.org/fhir/StructureDefinition/Resource")) {
                Set<String> types = new HashSet<>();
                List<StructureDefinition> profiles = new ArrayList<>();
                for (UriType u : type.getTargetProfile()) {
                    StructureDefinition sd = resolveProfile(profile, u.getValue());
                    if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, sd != null, I18nConstants.REFERENCE_REF_CANTRESOLVEPROFILE, u.getValue())) {
                        types.add(sd.getType());
                        if (ft.equals(sd.getType())) {
                            ok = true;
                            profiles.add(sd);
                        }
                    }
                }
                if (!pol.checkValid()) {
                    rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, profiles.size() > 0, I18nConstants.REFERENCE_REF_CANTMATCHTYPE, ref, StringUtils.join("; ", type.getTargetProfile()));
                } else {
                    Map<StructureDefinition, List<ValidationMessage>> badProfiles = new HashMap<>();
                    Map<StructureDefinition, List<ValidationMessage>> goodProfiles = new HashMap<>();
                    int goodCount = 0;
                    for (StructureDefinition pr : profiles) {
                        List<ValidationMessage> profileErrors = new ArrayList<ValidationMessage>();
                        validateResource(we.hostContext(hostContext, pr), profileErrors, we.getResource(), we.getFocus(), pr, IdStatus.OPTIONAL, we.getStack().resetIds());
                        if (!hasErrors(profileErrors)) {
                            goodCount++;
                            goodProfiles.put(pr, profileErrors);
                            trackUsage(pr, hostContext, element);
                        } else {
                            badProfiles.put(pr, profileErrors);
                        }
                    }
                    if (goodCount == 1) {
                        if (showMessagesFromReferences) {
                            for (ValidationMessage vm : goodProfiles.values().iterator().next()) {
                                if (!errors.contains(vm)) {
                                    errors.add(vm);
                                }
                            }
                        }
                    } else if (goodProfiles.size() == 0) {
                        if (!isShowMessagesFromReferences()) {
                            rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, areAllBaseProfiles(profiles), I18nConstants.REFERENCE_REF_CANTMATCHCHOICE, ref, asList(type.getTargetProfile()));
                            for (StructureDefinition sd : badProfiles.keySet()) {
                                slicingHint(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, false, context.formatMessage(I18nConstants.DETAILS_FOR__MATCHING_AGAINST_PROFILE_, ref, sd.getUrl()), errorSummaryForSlicingAsHtml(badProfiles.get(sd)), errorSummaryForSlicingAsText(badProfiles.get(sd)));
                            }
                        } else {
                            rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, profiles.size() == 1, I18nConstants.REFERENCE_REF_CANTMATCHCHOICE, ref, asList(type.getTargetProfile()));
                            for (List<ValidationMessage> messages : badProfiles.values()) {
                                for (ValidationMessage vm : messages) {
                                    if (!errors.contains(vm)) {
                                        errors.add(vm);
                                    }
                                }
                            }
                        }
                    } else {
                        if (!isShowMessagesFromReferences()) {
                            warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, I18nConstants.REFERENCE_REF_MULTIPLEMATCHES, ref, asListByUrl(goodProfiles.keySet()));
                            for (StructureDefinition sd : badProfiles.keySet()) {
                                slicingHint(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, false, context.formatMessage(I18nConstants.DETAILS_FOR__MATCHING_AGAINST_PROFILE_, ref, sd.getUrl()), errorSummaryForSlicingAsHtml(badProfiles.get(sd)), errorSummaryForSlicingAsText(badProfiles.get(sd)));
                            }
                        } else {
                            warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, I18nConstants.REFERENCE_REF_MULTIPLEMATCHES, ref, asListByUrl(goodProfiles.keySet()));
                            for (List<ValidationMessage> messages : goodProfiles.values()) {
                                for (ValidationMessage vm : messages) {
                                    if (!errors.contains(vm)) {
                                        errors.add(vm);
                                    }
                                }
                            }
                        }
                    }
                }
                rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, ok, I18nConstants.REFERENCE_REF_BADTARGETTYPE, ft, types.toString());
            }
            if (type.hasAggregation() && !noCheckAggregation) {
                boolean modeOk = false;
                CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
                for (Enumeration<AggregationMode> mode : type.getAggregation()) {
                    b.append(mode.getCode());
                    if (mode.getValue().equals(AggregationMode.CONTAINED) && refType.equals("contained"))
                        modeOk = true;
                    else if (mode.getValue().equals(AggregationMode.BUNDLED) && refType.equals("bundled"))
                        modeOk = true;
                    else if (mode.getValue().equals(AggregationMode.REFERENCED) && (refType.equals("bundled") || refType.equals("remote")))
                        modeOk = true;
                }
                rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, modeOk, I18nConstants.REFERENCE_REF_AGGREGATION, refType, b.toString());
            }
        }
    }
    if (we == null) {
        TypeRefComponent type = getReferenceTypeRef(container.getType());
        boolean okToRef = !type.hasAggregation() || type.hasAggregation(AggregationMode.REFERENCED);
        rule(errors, IssueType.REQUIRED, -1, -1, path, okToRef, I18nConstants.REFERENCE_REF_NOTFOUND_BUNDLE, ref);
    }
    if (we == null && ft != null && assumeValidRestReferences) {
        // if we == null, we inferred ft from the reference. if we are told to treat this as gospel
        TypeRefComponent type = getReferenceTypeRef(container.getType());
        Set<String> types = new HashSet<>();
        StructureDefinition sdFT = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + ft);
        boolean ok = false;
        for (CanonicalType tp : type.getTargetProfile()) {
            StructureDefinition sd = context.fetchResource(StructureDefinition.class, tp.getValue());
            if (sd != null) {
                types.add(sd.getType());
            }
            StructureDefinition sdF = sdFT;
            while (sdF != null) {
                if (sdF.getType().equals(sd.getType())) {
                    ok = true;
                    break;
                }
                sdF = sdF.hasBaseDefinition() ? context.fetchResource(StructureDefinition.class, sdF.getBaseDefinition()) : null;
            }
        }
        rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, types.isEmpty() || ok, I18nConstants.REFERENCE_REF_BADTARGETTYPE2, ft, ref, types);
    }
    if (pol == ReferenceValidationPolicy.CHECK_VALID) {
    // todo....
    }
}
Also used : ResolvedReference(org.hl7.fhir.validation.instance.utils.ResolvedReference) ValidationMessage(org.hl7.fhir.utilities.validation.ValidationMessage) HashMap(java.util.HashMap) NamedElement(org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement) IndexedElement(org.hl7.fhir.validation.instance.utils.IndexedElement) SpecialElement(org.hl7.fhir.r5.elementmodel.Element.SpecialElement) Element(org.hl7.fhir.r5.elementmodel.Element) ArrayList(java.util.ArrayList) AggregationMode(org.hl7.fhir.r5.model.ElementDefinition.AggregationMode) CanonicalType(org.hl7.fhir.r5.model.CanonicalType) UriType(org.hl7.fhir.r5.model.UriType) StructureDefinition(org.hl7.fhir.r5.model.StructureDefinition) TypeRefComponent(org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent) ArrayList(java.util.ArrayList) List(java.util.List) HashSet(java.util.HashSet) Reference(org.hl7.fhir.r5.model.Reference) ResolvedReference(org.hl7.fhir.validation.instance.utils.ResolvedReference) CommaSeparatedStringBuilder(org.hl7.fhir.utilities.CommaSeparatedStringBuilder) IOException(java.io.IOException) FHIRException(org.hl7.fhir.exceptions.FHIRException) ContactPoint(org.hl7.fhir.r5.model.ContactPoint)

Example 50 with NodeStack

use of org.hl7.fhir.validation.instance.utils.NodeStack in project org.hl7.fhir.core by hapifhir.

the class InstanceValidator method assignChildren.

public List<String> assignChildren(ValidatorHostContext hostContext, List<ValidationMessage> errors, StructureDefinition profile, Element resource, NodeStack stack, List<ElementDefinition> childDefinitions, List<ElementInfo> children) throws DefinitionException {
    // 2. assign children to a definition
    // for each definition, for each child, check whether it belongs in the slice
    ElementDefinition slicer = null;
    boolean unsupportedSlicing = false;
    List<String> problematicPaths = new ArrayList<String>();
    String slicingPath = null;
    int sliceOffset = 0;
    for (int i = 0; i < childDefinitions.size(); i++) {
        ElementDefinition ed = childDefinitions.get(i);
        boolean childUnsupportedSlicing = false;
        boolean process = true;
        if (ed.hasSlicing() && !ed.getSlicing().getOrdered()) {
            slicingPath = ed.getPath();
        } else if (slicingPath != null && ed.getPath().equals(slicingPath)) {
            // nothing
            ;
        } else if (slicingPath != null && !ed.getPath().startsWith(slicingPath)) {
            slicingPath = null;
        }
        // where are we with slicing
        if (ed.hasSlicing()) {
            if (slicer != null && slicer.getPath().equals(ed.getPath())) {
                String errorContext = "profile " + profile.getUrl();
                if (!resource.getChildValue(ID).isEmpty()) {
                    errorContext += "; instance " + resource.getChildValue("id");
                }
                throw new DefinitionException(context.formatMessage(I18nConstants.SLICE_ENCOUNTERED_MIDWAY_THROUGH_SET_PATH___ID___, slicer.getPath(), slicer.getId(), errorContext));
            }
            slicer = ed;
            process = false;
            sliceOffset = i;
        } else if (slicer != null && !slicer.getPath().equals(ed.getPath()))
            slicer = null;
        for (ElementInfo ei : children) {
            if (ei.sliceInfo == null) {
                ei.sliceInfo = new ArrayList<>();
            }
            unsupportedSlicing = matchSlice(hostContext, errors, ei.sliceInfo, profile, stack, slicer, unsupportedSlicing, problematicPaths, sliceOffset, i, ed, childUnsupportedSlicing, ei);
        }
    }
    int last = -1;
    ElementInfo lastei = null;
    int lastSlice = -1;
    for (ElementInfo ei : children) {
        String sliceInfo = "";
        if (slicer != null) {
            sliceInfo = " (slice: " + slicer.getPath() + ")";
        }
        if (!unsupportedSlicing) {
            if (ei.additionalSlice && ei.definition != null) {
                if (ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN) || ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPENATEND) && true) /* TODO: replace "true" with condition to check that this element is at "end" */
                {
                    slicingHint(errors, IssueType.INFORMATIONAL, ei.line(), ei.col(), ei.getPath(), false, isProfile(slicer) || isCritical(ei.sliceInfo), context.formatMessage(I18nConstants.THIS_ELEMENT_DOES_NOT_MATCH_ANY_KNOWN_SLICE_, profile == null ? "" : " defined in the profile " + profile.getUrl()), context.formatMessage(I18nConstants.THIS_ELEMENT_DOES_NOT_MATCH_ANY_KNOWN_SLICE_, profile == null ? "" : I18nConstants.DEFINED_IN_THE_PROFILE + profile.getUrl()) + errorSummaryForSlicingAsHtml(ei.sliceInfo), errorSummaryForSlicingAsText(ei.sliceInfo));
                } else if (ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.CLOSED)) {
                    rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_NOTSLICE, (profile == null ? "" : " defined in the profile " + profile.getUrl()), errorSummaryForSlicing(ei.sliceInfo));
                }
            } else {
                // Don't raise this if we're in an abstract profile, like Resource
                if (!profile.getAbstract()) {
                    rule(errors, IssueType.NOTSUPPORTED, ei.line(), ei.col(), ei.getPath(), (ei.definition != null), I18nConstants.VALIDATION_VAL_PROFILE_NOTALLOWED, profile.getUrl());
                }
            }
        }
        // TODO: Should get the order of elements correct when parsing elements that are XML attributes vs. elements
        boolean isXmlAttr = false;
        if (ei.definition != null) {
            for (Enumeration<PropertyRepresentation> r : ei.definition.getRepresentation()) {
                if (r.getValue() == PropertyRepresentation.XMLATTR) {
                    isXmlAttr = true;
                    break;
                }
            }
        }
        if (!ToolingExtensions.readBoolExtension(profile, "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-no-order")) {
            boolean ok = (ei.definition == null) || (ei.index >= last) || isXmlAttr;
            rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), ok, I18nConstants.VALIDATION_VAL_PROFILE_OUTOFORDER, profile.getUrl(), ei.getName(), lastei == null ? "(null)" : lastei.getName());
        }
        if (ei.slice != null && ei.index == last && ei.slice.getSlicing().getOrdered()) {
            rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), (ei.definition == null) || (ei.sliceindex >= lastSlice) || isXmlAttr, I18nConstants.VALIDATION_VAL_PROFILE_SLICEORDER, profile.getUrl(), ei.getName());
        }
        if (ei.definition == null || !isXmlAttr) {
            last = ei.index;
            lastei = ei;
        }
        if (ei.slice != null) {
            lastSlice = ei.sliceindex;
        } else {
            lastSlice = -1;
        }
    }
    return problematicPaths;
}
Also used : PropertyRepresentation(org.hl7.fhir.r5.model.ElementDefinition.PropertyRepresentation) ElementInfo(org.hl7.fhir.validation.instance.utils.ElementInfo) ArrayList(java.util.ArrayList) TypedElementDefinition(org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition) ElementDefinition(org.hl7.fhir.r5.model.ElementDefinition) DefinitionException(org.hl7.fhir.exceptions.DefinitionException) ContactPoint(org.hl7.fhir.r5.model.ContactPoint)

Aggregations

Element (org.hl7.fhir.r5.elementmodel.Element)50 ArrayList (java.util.ArrayList)35 NodeStack (org.hl7.fhir.validation.instance.utils.NodeStack)32 FHIRException (org.hl7.fhir.exceptions.FHIRException)22 IndexedElement (org.hl7.fhir.validation.instance.utils.IndexedElement)22 IOException (java.io.IOException)14 SpecialElement (org.hl7.fhir.r5.elementmodel.Element.SpecialElement)14 NamedElement (org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement)13 DefinitionException (org.hl7.fhir.exceptions.DefinitionException)12 ContactPoint (org.hl7.fhir.r5.model.ContactPoint)12 StructureDefinition (org.hl7.fhir.r5.model.StructureDefinition)12 ValueSet (org.hl7.fhir.r5.model.ValueSet)12 FHIRLexerException (org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException)11 NotImplementedException (org.apache.commons.lang3.NotImplementedException)10 PathEngineException (org.hl7.fhir.exceptions.PathEngineException)10 TerminologyServiceException (org.hl7.fhir.exceptions.TerminologyServiceException)10 ValidationResult (org.hl7.fhir.r5.context.IWorkerContext.ValidationResult)10 List (java.util.List)8 CodeSystem (org.hl7.fhir.r5.model.CodeSystem)8 Coding (org.hl7.fhir.r5.model.Coding)8