Search in sources :

Example 51 with NodeStack

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

the class InstanceValidator method validateElement.

private void validateElement(ValidatorHostContext hostContext, List<ValidationMessage> errors, StructureDefinition profile, ElementDefinition definition, StructureDefinition cprofile, ElementDefinition context, Element resource, Element element, String actualType, NodeStack stack, boolean inCodeableConcept, boolean checkDisplayInContext, String extensionUrl) throws FHIRException {
    String id = element.getChildValue("id");
    if (!Utilities.noString(id)) {
        if (stack.getIds().containsKey(id) && stack.getIds().get(id) != element) {
            rule(errors, IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.DUPLICATE_ID, id);
        }
        if (!stack.isResetPoint()) {
            stack.getIds().put(id, element);
        }
    }
    if (definition.getPath().equals("StructureDefinition.snapshot")) {
        // work around a known issue in the spec, that ids are duplicated in snapshot and differential
        stack.resetIds();
    }
    // check type invariants
    checkInvariants(hostContext, errors, profile, definition, resource, element, stack, false);
    if (definition.getFixed() != null) {
        checkFixedValue(errors, stack.getLiteralPath(), element, definition.getFixed(), profile.getUrl(), definition.getSliceName(), null, false);
    }
    if (definition.getPattern() != null) {
        checkFixedValue(errors, stack.getLiteralPath(), element, definition.getPattern(), profile.getUrl(), definition.getSliceName(), null, true);
    }
    // get the list of direct defined children, including slices
    List<ElementDefinition> childDefinitions = profileUtilities.getChildMap(profile, definition);
    if (childDefinitions.isEmpty()) {
        if (actualType == null)
            // there'll be an error elsewhere in this case, and we're going to stop.
            return;
        childDefinitions = getActualTypeChildren(hostContext, element, actualType);
    } else if (definition.getType().size() > 1) {
        // this only happens when the profile constrains the abstract children but leaves th choice open.
        if (actualType == null)
            // there'll be an error elsewhere in this case, and we're going to stop.
            return;
        List<ElementDefinition> typeChildDefinitions = getActualTypeChildren(hostContext, element, actualType);
        // what were going to do is merge them - the type is not allowed to constrain things that the child definitions already do (well, if it does, it'll be ignored)
        mergeChildLists(childDefinitions, typeChildDefinitions, definition.getPath(), actualType);
    }
    List<ElementInfo> children = listChildren(element, stack);
    List<String> problematicPaths = assignChildren(hostContext, errors, profile, resource, stack, childDefinitions, children);
    checkCardinalities(errors, profile, element, stack, childDefinitions, children, problematicPaths);
    // 5. inspect each child for validity
    for (ElementInfo ei : children) {
        checkChild(hostContext, errors, profile, definition, resource, element, actualType, stack, inCodeableConcept, checkDisplayInContext, ei, extensionUrl);
    }
}
Also used : ElementInfo(org.hl7.fhir.validation.instance.utils.ElementInfo) ArrayList(java.util.ArrayList) List(java.util.List) TypedElementDefinition(org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition) ElementDefinition(org.hl7.fhir.r5.model.ElementDefinition)

Example 52 with NodeStack

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

the class InstanceValidator method makeExternalRef.

private ResolvedReference makeExternalRef(Element external, String path) {
    ResolvedReference res = new ResolvedReference();
    res.setResource(external);
    res.setFocus(external);
    res.setExternal(true);
    res.setStack(new NodeStack(context, external, path, validationLanguage));
    return res;
}
Also used : ResolvedReference(org.hl7.fhir.validation.instance.utils.ResolvedReference) NodeStack(org.hl7.fhir.validation.instance.utils.NodeStack)

Example 53 with NodeStack

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

the class InstanceValidator method checkCardinalities.

public void checkCardinalities(List<ValidationMessage> errors, StructureDefinition profile, Element element, NodeStack stack, List<ElementDefinition> childDefinitions, List<ElementInfo> children, List<String> problematicPaths) throws DefinitionException {
    // 3. report any definitions that have a cardinality problem
    for (ElementDefinition ed : childDefinitions) {
        if (ed.getRepresentation().isEmpty()) {
            // ignore xml attributes
            int count = 0;
            List<ElementDefinition> slices = null;
            if (ed.hasSlicing())
                slices = profileUtilities.getSliceList(profile, ed);
            for (ElementInfo ei : children) if (ei.definition == ed)
                count++;
            else if (slices != null) {
                for (ElementDefinition sed : slices) {
                    if (ei.definition == sed) {
                        count++;
                        break;
                    }
                }
            }
            if (ed.getMin() > 0) {
                if (problematicPaths.contains(ed.getPath()))
                    hint(errors, IssueType.NOTSUPPORTED, element.line(), element.col(), stack.getLiteralPath(), count >= ed.getMin(), I18nConstants.VALIDATION_VAL_PROFILE_NOCHECKMIN, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(), ed.getLabel(), stack.getLiteralPath(), Integer.toString(ed.getMin()));
                else {
                    if (count < ed.getMin()) {
                        rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_MINIMUM, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(), ed.getLabel(), stack.getLiteralPath(), Integer.toString(ed.getMin()), Integer.toString(count));
                    }
                }
            }
            if (ed.hasMax() && !ed.getMax().equals("*")) {
                if (problematicPaths.contains(ed.getPath()))
                    hint(errors, IssueType.NOTSUPPORTED, element.line(), element.col(), stack.getLiteralPath(), count <= Integer.parseInt(ed.getMax()), I18nConstants.VALIDATION_VAL_PROFILE_NOCHECKMAX, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(), ed.getLabel(), stack.getLiteralPath(), ed.getMax());
                else if (count > Integer.parseInt(ed.getMax())) {
                    rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_MAXIMUM, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(), ed.getLabel(), stack.getLiteralPath(), ed.getMax(), Integer.toString(count));
                }
            }
        }
    }
}
Also used : ElementInfo(org.hl7.fhir.validation.instance.utils.ElementInfo) TypedElementDefinition(org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition) ElementDefinition(org.hl7.fhir.r5.model.ElementDefinition) ContactPoint(org.hl7.fhir.r5.model.ContactPoint)

Example 54 with NodeStack

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

the class InstanceValidator method checkExtensionContext.

private boolean checkExtensionContext(List<ValidationMessage> errors, Element resource, Element container, StructureDefinition definition, NodeStack stack, ValidatorHostContext hostContext, boolean modifier) {
    String extUrl = definition.getUrl();
    boolean ok = false;
    CommaSeparatedStringBuilder contexts = new CommaSeparatedStringBuilder();
    List<String> plist = new ArrayList<>();
    plist.add(stripIndexes(stack.getLiteralPath()));
    for (String s : stack.getLogicalPaths()) {
        String p = stripIndexes(s);
        // all extensions are always allowed in ElementDefinition.example.value, and in fixed and pattern values. TODO: determine the logical paths from the path stated in the element definition....
        if (Utilities.existsInList(p, "ElementDefinition.example.value", "ElementDefinition.pattern", "ElementDefinition.fixed")) {
            return true;
        }
        plist.add(p);
    }
    for (StructureDefinitionContextComponent ctxt : fixContexts(extUrl, definition.getContext())) {
        if (ok) {
            break;
        }
        if (ctxt.getType() == ExtensionContextType.ELEMENT) {
            String en = ctxt.getExpression();
            contexts.append("e:" + en);
            if (Utilities.existsInList(en, "Element", "Any")) {
                ok = true;
            } else if (en.equals("Resource") && container.isResource()) {
                ok = true;
            }
            for (String p : plist) {
                if (ok) {
                    break;
                }
                if (p.equals(en)) {
                    ok = true;
                } else {
                    String pn = p;
                    String pt = "";
                    if (p.contains(".")) {
                        pn = p.substring(0, p.indexOf("."));
                        pt = p.substring(p.indexOf("."));
                    }
                    StructureDefinition sd = context.fetchTypeDefinition(pn);
                    while (sd != null) {
                        if ((sd.getType() + pt).equals(en)) {
                            ok = true;
                            break;
                        }
                        if (sd.getBaseDefinition() != null) {
                            sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition());
                        } else {
                            sd = null;
                        }
                    }
                }
            }
        } else if (ctxt.getType() == ExtensionContextType.EXTENSION) {
            contexts.append("x:" + ctxt.getExpression());
            NodeStack estack = stack.getParent();
            if (estack != null && estack.getElement().fhirType().equals("Extension")) {
                String ext = estack.getElement().getNamedChildValue("url");
                if (ctxt.getExpression().equals(ext)) {
                    ok = true;
                }
            }
        } else if (ctxt.getType() == ExtensionContextType.FHIRPATH) {
            contexts.append("p:" + ctxt.getExpression());
            // The context is all elements that match the FHIRPath query found in the expression.
            List<Base> res = fpe.evaluate(hostContext, resource, hostContext.getRootResource(), resource, fpe.parse(ctxt.getExpression()));
            if (res.contains(container)) {
                ok = true;
            }
        } else {
            throw new Error(context.formatMessage(I18nConstants.UNRECOGNISED_EXTENSION_CONTEXT_, ctxt.getTypeElement().asStringValue()));
        }
    }
    if (!ok) {
        if (definition.hasUserData(XVerExtensionManager.XVER_EXT_MARKER)) {
            warning(errors, IssueType.STRUCTURE, container.line(), container.col(), stack.getLiteralPath(), false, modifier ? I18nConstants.EXTENSION_EXTM_CONTEXT_WRONG_XVER : I18nConstants.EXTENSION_EXTP_CONTEXT_WRONG_XVER, extUrl, contexts.toString(), plist.toString());
        } else {
            rule(errors, IssueType.STRUCTURE, container.line(), container.col(), stack.getLiteralPath(), false, modifier ? I18nConstants.EXTENSION_EXTP_CONTEXT_WRONG : I18nConstants.EXTENSION_EXTM_CONTEXT_WRONG, extUrl, contexts.toString(), plist.toString());
        }
        return false;
    } else {
        if (definition.hasContextInvariant()) {
            for (StringType s : definition.getContextInvariant()) {
                if (!fpe.evaluateToBoolean(hostContext, resource, hostContext.getRootResource(), container, fpe.parse(s.getValue()))) {
                    if (definition.hasUserData(XVerExtensionManager.XVER_EXT_MARKER)) {
                        warning(errors, IssueType.STRUCTURE, container.line(), container.col(), stack.getLiteralPath(), false, I18nConstants.PROFILE_EXT_NOT_HERE, extUrl, s.getValue());
                        return true;
                    } else {
                        rule(errors, IssueType.STRUCTURE, container.line(), container.col(), stack.getLiteralPath(), false, I18nConstants.PROFILE_EXT_NOT_HERE, extUrl, s.getValue());
                        return false;
                    }
                }
            }
        }
        return true;
    }
}
Also used : StructureDefinition(org.hl7.fhir.r5.model.StructureDefinition) StructureDefinitionContextComponent(org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionContextComponent) StringType(org.hl7.fhir.r5.model.StringType) ArrayList(java.util.ArrayList) CommaSeparatedStringBuilder(org.hl7.fhir.utilities.CommaSeparatedStringBuilder) NodeStack(org.hl7.fhir.validation.instance.utils.NodeStack) ParserBase(org.hl7.fhir.r5.elementmodel.ParserBase) Base(org.hl7.fhir.r5.model.Base)

Example 55 with NodeStack

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

the class InstanceValidator method checkTerminologyCodeableConcept.

private boolean checkTerminologyCodeableConcept(List<ValidationMessage> errors, String path, Element element, StructureDefinition profile, ElementDefinition theElementCntext, NodeStack stack, StructureDefinition logical) {
    boolean res = true;
    if (!noTerminologyChecks && theElementCntext != null && theElementCntext.hasBinding()) {
        ElementDefinitionBindingComponent binding = theElementCntext.getBinding();
        if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, I18nConstants.TERMINOLOGY_TX_BINDING_MISSING, path)) {
            if (binding.hasValueSet()) {
                ValueSet valueset = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl());
                if (valueset == null) {
                    CodeSystem cs = context.fetchCodeSystem(binding.getValueSet());
                    if (rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(binding.getValueSet()))) {
                        warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND, describeReference(binding.getValueSet()));
                    }
                } else {
                    try {
                        CodeableConcept cc = convertToCodeableConcept(element, logical);
                        if (!cc.hasCoding()) {
                            if (binding.getStrength() == BindingStrength.REQUIRED)
                                rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "No code provided, and a code is required from the value set " + describeReference(binding.getValueSet()) + " (" + valueset.getUrl());
                            else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
                                if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
                                    rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESETMAX, describeReference(ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")), valueset.getUrl());
                                else
                                    warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET_EXT, describeValueSet(binding.getValueSet()));
                            }
                        } else {
                            long t = System.nanoTime();
                            // Check whether the codes are appropriate for the type of binding we have
                            boolean bindingsOk = true;
                            if (binding.getStrength() != BindingStrength.EXAMPLE) {
                                if (binding.getStrength() == BindingStrength.REQUIRED) {
                                    removeTrackedMessagesForLocation(errors, element, path);
                                }
                                boolean atLeastOneSystemIsSupported = false;
                                for (Coding nextCoding : cc.getCoding()) {
                                    String nextSystem = nextCoding.getSystem();
                                    if (isNotBlank(nextSystem) && context.supportsSystem(nextSystem)) {
                                        atLeastOneSystemIsSupported = true;
                                        break;
                                    }
                                }
                                if (!atLeastOneSystemIsSupported && binding.getStrength() == BindingStrength.EXAMPLE) {
                                // ignore this since we can't validate but it doesn't matter..
                                } else {
                                    // we're going to validate the codings directly
                                    ValidationResult vr = checkCodeOnServer(stack, valueset, cc, false);
                                    if (!vr.isOk()) {
                                        bindingsOk = false;
                                        if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) {
                                            if (binding.getStrength() == BindingStrength.REQUIRED)
                                                txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_1_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
                                            else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
                                                if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
                                                    checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack);
                                                else if (!noExtensibleWarnings)
                                                    txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
                                            } else if (binding.getStrength() == BindingStrength.PREFERRED) {
                                                if (baseOnly) {
                                                    txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_3_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
                                                }
                                            }
                                        } else {
                                            if (binding.getStrength() == BindingStrength.REQUIRED)
                                                txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1_CC, describeValueSet(binding.getValueSet()), ccSummary(cc));
                                            else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
                                                if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
                                                    checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack);
                                                if (!noExtensibleWarnings)
                                                    txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2_CC, describeValueSet(binding.getValueSet()), ccSummary(cc));
                                            } else if (binding.getStrength() == BindingStrength.PREFERRED) {
                                                if (baseOnly) {
                                                    txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3_CC, describeValueSet(binding.getValueSet()), ccSummary(cc));
                                                }
                                            }
                                        }
                                    } else if (vr.getMessage() != null) {
                                        res = false;
                                        txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage());
                                    } else {
                                        res = false;
                                    }
                                }
                                // to validate, we'll validate that the codes actually exist
                                if (bindingsOk) {
                                    for (Coding nextCoding : cc.getCoding()) {
                                        String nextCode = nextCoding.getCode();
                                        String nextSystem = nextCoding.getSystem();
                                        String nextVersion = nextCoding.getVersion();
                                        if (isNotBlank(nextCode) && isNotBlank(nextSystem) && context.supportsSystem(nextSystem)) {
                                            ValidationResult vr = checkCodeOnServer(stack, nextCode, nextSystem, nextVersion, null, false);
                                            if (!vr.isOk()) {
                                                txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_NOTVALID, nextCode, nextSystem);
                                            }
                                        }
                                    }
                                }
                                timeTracker.tx(t, DataRenderer.display(context, cc));
                            }
                        }
                    } catch (Exception e) {
                        if (STACK_TRACE)
                            e.printStackTrace();
                        warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_ERROR_CODEABLECONCEPT, e.getMessage());
                    }
                    // special case: if the logical model has both CodeableConcept and Coding mappings, we'll also check the first coding.
                    if (getMapping("http://hl7.org/fhir/terminology-pattern", logical, logical.getSnapshot().getElementFirstRep()).contains("Coding")) {
                        checkTerminologyCoding(errors, path, element, profile, theElementCntext, true, true, stack, logical);
                    }
                }
            } else if (binding.hasValueSet()) {
                hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_CANTCHECK);
            } else if (!noBindingMsgSuppressed) {
                hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSOURCE, path);
            }
        }
    }
    return res;
}
Also used : Coding(org.hl7.fhir.r5.model.Coding) ValidationResult(org.hl7.fhir.r5.context.IWorkerContext.ValidationResult) ElementDefinitionBindingComponent(org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent) ValueSet(org.hl7.fhir.r5.model.ValueSet) CodeSystem(org.hl7.fhir.r5.model.CodeSystem) 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) CodeableConcept(org.hl7.fhir.r5.model.CodeableConcept)

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