Search in sources :

Example 1 with ValidatorHostContext

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

the class InstanceValidator method sliceMatches.

/**
 * @param element - the candidate that might be in the slice
 * @param path    - for reporting any errors. the XPath for the element
 * @param slicer  - the definition of how slicing is determined
 * @param ed      - the slice for which to test membership
 * @param errors
 * @param stack
 * @param srcProfile
 * @return
 * @throws DefinitionException
 * @throws DefinitionException
 * @throws IOException
 * @throws FHIRException
 */
private boolean sliceMatches(ValidatorHostContext hostContext, Element element, String path, ElementDefinition slicer, ElementDefinition ed, StructureDefinition profile, List<ValidationMessage> errors, List<ValidationMessage> sliceInfo, NodeStack stack, StructureDefinition srcProfile) throws DefinitionException, FHIRException {
    if (!slicer.getSlicing().hasDiscriminator())
        // cannot validate in this case
        return false;
    ExpressionNode n = (ExpressionNode) ed.getUserData("slice.expression.cache");
    if (n == null) {
        long t = System.nanoTime();
        // GG: this approach is flawed because it treats discriminators individually rather than collectively
        StringBuilder expression = new StringBuilder("true");
        boolean anyFound = false;
        Set<String> discriminators = new HashSet<>();
        for (ElementDefinitionSlicingDiscriminatorComponent s : slicer.getSlicing().getDiscriminator()) {
            String discriminator = s.getPath();
            discriminators.add(discriminator);
            List<ElementDefinition> criteriaElements = getCriteriaForDiscriminator(path, ed, discriminator, profile, s.getType() == DiscriminatorType.PROFILE, srcProfile);
            boolean found = false;
            for (ElementDefinition criteriaElement : criteriaElements) {
                found = true;
                if (s.getType() == DiscriminatorType.TYPE) {
                    String type = null;
                    if (!criteriaElement.getPath().contains("[") && discriminator.contains("[")) {
                        discriminator = discriminator.substring(0, discriminator.indexOf('['));
                        String lastNode = tail(discriminator);
                        type = tail(criteriaElement.getPath()).substring(lastNode.length());
                        type = type.substring(0, 1).toLowerCase() + type.substring(1);
                    } else if (!criteriaElement.hasType() || criteriaElement.getType().size() == 1) {
                        if (discriminator.contains("["))
                            discriminator = discriminator.substring(0, discriminator.indexOf('['));
                        if (criteriaElement.hasType()) {
                            type = criteriaElement.getType().get(0).getWorkingCode();
                        } else if (!criteriaElement.getPath().contains(".")) {
                            type = criteriaElement.getPath();
                        } else {
                            throw new DefinitionException(context.formatMessage(I18nConstants.DISCRIMINATOR__IS_BASED_ON_TYPE_BUT_SLICE__IN__HAS_NO_TYPES, discriminator, ed.getId(), profile.getUrl()));
                        }
                    } else if (criteriaElement.getType().size() > 1) {
                        throw new DefinitionException(context.formatMessage(I18nConstants.DISCRIMINATOR__IS_BASED_ON_TYPE_BUT_SLICE__IN__HAS_MULTIPLE_TYPES_, discriminator, ed.getId(), profile.getUrl(), criteriaElement.typeSummary()));
                    } else
                        throw new DefinitionException(context.formatMessage(I18nConstants.DISCRIMINATOR__IS_BASED_ON_TYPE_BUT_SLICE__IN__HAS_NO_TYPES, discriminator, ed.getId(), profile.getUrl()));
                    if (discriminator.isEmpty())
                        expression.append(" and $this is " + type);
                    else
                        expression.append(" and " + discriminator + " is " + type);
                } else if (s.getType() == DiscriminatorType.PROFILE) {
                    if (criteriaElement.getType().size() == 0) {
                        throw new DefinitionException(context.formatMessage(I18nConstants.PROFILE_BASED_DISCRIMINATORS_MUST_HAVE_A_TYPE__IN_PROFILE_, criteriaElement.getId(), profile.getUrl()));
                    }
                    if (criteriaElement.getType().size() != 1) {
                        throw new DefinitionException(context.formatMessage(I18nConstants.PROFILE_BASED_DISCRIMINATORS_MUST_HAVE_ONLY_ONE_TYPE__IN_PROFILE_, criteriaElement.getId(), profile.getUrl()));
                    }
                    List<CanonicalType> list = discriminator.endsWith(".resolve()") || discriminator.equals("resolve()") ? criteriaElement.getType().get(0).getTargetProfile() : criteriaElement.getType().get(0).getProfile();
                    if (list.size() == 0) {
                        throw new DefinitionException(context.formatMessage(I18nConstants.PROFILE_BASED_DISCRIMINATORS_MUST_HAVE_A_TYPE_WITH_A_PROFILE__IN_PROFILE_, criteriaElement.getId(), profile.getUrl()));
                    } else if (list.size() > 1) {
                        CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(" or ");
                        for (CanonicalType c : list) {
                            b.append(discriminator + ".conformsTo('" + c.getValue() + "')");
                        }
                        expression.append(" and (" + b + ")");
                    } else {
                        expression.append(" and " + discriminator + ".conformsTo('" + list.get(0).getValue() + "')");
                    }
                } else if (s.getType() == DiscriminatorType.EXISTS) {
                    if (criteriaElement.hasMin() && criteriaElement.getMin() >= 1)
                        expression.append(" and (" + discriminator + ".exists())");
                    else if (criteriaElement.hasMax() && criteriaElement.getMax().equals("0"))
                        expression.append(" and (" + discriminator + ".exists().not())");
                    else
                        throw new FHIRException(context.formatMessage(I18nConstants.DISCRIMINATOR__IS_BASED_ON_ELEMENT_EXISTENCE_BUT_SLICE__NEITHER_SETS_MIN1_OR_MAX0, discriminator, ed.getId()));
                } else if (criteriaElement.hasFixed()) {
                    buildFixedExpression(ed, expression, discriminator, criteriaElement);
                } else if (criteriaElement.hasPattern()) {
                    buildPattternExpression(ed, expression, discriminator, criteriaElement);
                } else if (criteriaElement.hasBinding() && criteriaElement.getBinding().hasStrength() && criteriaElement.getBinding().getStrength().equals(BindingStrength.REQUIRED) && criteriaElement.getBinding().hasValueSet()) {
                    expression.append(" and (" + discriminator + " memberOf '" + criteriaElement.getBinding().getValueSet() + "')");
                } else {
                    found = false;
                }
                if (found)
                    break;
            }
            if (found)
                anyFound = true;
        }
        if (!anyFound) {
            if (slicer.getSlicing().getDiscriminator().size() > 1)
                throw new DefinitionException(context.formatMessage(I18nConstants.COULD_NOT_MATCH_ANY_DISCRIMINATORS__FOR_SLICE__IN_PROFILE___NONE_OF_THE_DISCRIMINATOR__HAVE_FIXED_VALUE_BINDING_OR_EXISTENCE_ASSERTIONS, discriminators, ed.getId(), profile.getUrl(), discriminators));
            else
                throw new DefinitionException(context.formatMessage(I18nConstants.COULD_NOT_MATCH_DISCRIMINATOR__FOR_SLICE__IN_PROFILE___THE_DISCRIMINATOR__DOES_NOT_HAVE_FIXED_VALUE_BINDING_OR_EXISTENCE_ASSERTIONS, discriminators, ed.getId(), profile.getUrl(), discriminators));
        }
        try {
            n = fpe.parse(fixExpr(expression.toString(), null));
        } catch (FHIRLexerException e) {
            if (STACK_TRACE)
                e.printStackTrace();
            throw new FHIRException(context.formatMessage(I18nConstants.PROBLEM_PROCESSING_EXPRESSION__IN_PROFILE__PATH__, expression, profile.getUrl(), path, e.getMessage()));
        }
        timeTracker.fpe(t);
        ed.setUserData("slice.expression.cache", n);
    }
    ValidatorHostContext shc = hostContext.forSlicing();
    boolean pass = evaluateSlicingExpression(shc, element, path, profile, n);
    if (!pass) {
        slicingHint(sliceInfo, IssueType.STRUCTURE, element.line(), element.col(), path, false, isProfile(slicer), (context.formatMessage(I18nConstants.DOES_NOT_MATCH_SLICE_, ed.getSliceName())), "discriminator = " + Utilities.escapeXml(n.toString()), null);
        for (String url : shc.getSliceRecords().keySet()) {
            slicingHint(sliceInfo, IssueType.STRUCTURE, element.line(), element.col(), path, false, isProfile(slicer), context.formatMessage(I18nConstants.DETAILS_FOR__MATCHING_AGAINST_PROFILE_, stack.getLiteralPath(), url), context.formatMessage(I18nConstants.PROFILE__DOES_NOT_MATCH_FOR__BECAUSE_OF_THE_FOLLOWING_PROFILE_ISSUES__, url, stack.getLiteralPath(), errorSummaryForSlicingAsHtml(shc.getSliceRecords().get(url))), errorSummaryForSlicingAsText(shc.getSliceRecords().get(url)));
        }
    }
    return pass;
}
Also used : CommaSeparatedStringBuilder(org.hl7.fhir.utilities.CommaSeparatedStringBuilder) FHIRLexerException(org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException) CommaSeparatedStringBuilder(org.hl7.fhir.utilities.CommaSeparatedStringBuilder) CanonicalType(org.hl7.fhir.r5.model.CanonicalType) FHIRException(org.hl7.fhir.exceptions.FHIRException) ElementDefinitionSlicingDiscriminatorComponent(org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionSlicingDiscriminatorComponent) ExpressionNode(org.hl7.fhir.r5.model.ExpressionNode) ValidatorHostContext(org.hl7.fhir.validation.instance.utils.ValidatorHostContext) ArrayList(java.util.ArrayList) List(java.util.List) TypedElementDefinition(org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition) ElementDefinition(org.hl7.fhir.r5.model.ElementDefinition) DefinitionException(org.hl7.fhir.exceptions.DefinitionException) HashSet(java.util.HashSet)

Example 2 with ValidatorHostContext

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

the class ValidationEngine method evaluateFhirPath.

public String evaluateFhirPath(String source, String expression) throws FHIRException, IOException {
    Content cnt = igLoader.loadContent(source, "validate", false);
    FHIRPathEngine fpe = this.getValidator(null).getFHIRPathEngine();
    Element e = Manager.parseSingle(context, new ByteArrayInputStream(cnt.focus), cnt.cntType);
    ExpressionNode exp = fpe.parse(expression);
    return fpe.evaluateToString(new ValidatorHostContext(context, e), e, e, e, exp);
}
Also used : FHIRPathEngine(org.hl7.fhir.r5.utils.FHIRPathEngine) Element(org.hl7.fhir.r5.elementmodel.Element) ValidatorHostContext(org.hl7.fhir.validation.instance.utils.ValidatorHostContext)

Example 3 with ValidatorHostContext

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

the class InstanceValidator method checkInvariants.

private void checkInvariants(ValidatorHostContext hostContext, List<ValidationMessage> errors, String path, StructureDefinition profile, ElementDefinition ed, String typename, String typeProfile, Element resource, Element element, boolean onlyNonInherited) throws FHIRException, FHIRException {
    if (noInvariantChecks)
        return;
    for (ElementDefinitionConstraintComponent inv : ed.getConstraint()) {
        if (inv.hasExpression() && (!onlyNonInherited || !inv.hasSource() || (!isInheritedProfile(profile, inv.getSource()) && !isInheritedProfile(ed.getType(), inv.getSource())))) {
            @SuppressWarnings("unchecked") Map<String, List<ValidationMessage>> invMap = executionId.equals(element.getUserString(EXECUTION_ID)) ? (Map<String, List<ValidationMessage>>) element.getUserData(EXECUTED_CONSTRAINT_LIST) : null;
            if (invMap == null) {
                invMap = new HashMap<>();
                element.setUserData(EXECUTED_CONSTRAINT_LIST, invMap);
                element.setUserData(EXECUTION_ID, executionId);
            }
            List<ValidationMessage> invErrors = null;
            // We key based on inv.expression rather than inv.key because expressions can change in derived profiles and aren't guaranteed to be consistent across profiles.
            String key = fixExpr(inv.getExpression(), inv.getKey());
            if (!invMap.keySet().contains(key)) {
                invErrors = new ArrayList<ValidationMessage>();
                invMap.put(key, invErrors);
                checkInvariant(hostContext, invErrors, path, profile, resource, element, inv);
            } else {
                invErrors = (ArrayList<ValidationMessage>) invMap.get(key);
            }
            errors.addAll(invErrors);
        }
    }
}
Also used : ValidationMessage(org.hl7.fhir.utilities.validation.ValidationMessage) ArrayList(java.util.ArrayList) List(java.util.List) ElementDefinitionConstraintComponent(org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionConstraintComponent)

Example 4 with ValidatorHostContext

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

the class InstanceValidator method startInner.

public void startInner(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element resource, Element element, StructureDefinition defn, NodeStack stack, boolean checkSpecials) {
    // the first piece of business is to see if we've validated this resource against this profile before.
    // if we have (*or if we still are*), then we'll just return our existing errors
    ResourceValidationTracker resTracker = getResourceTracker(element);
    List<ValidationMessage> cachedErrors = resTracker.getOutcomes(defn);
    if (cachedErrors != null) {
        for (ValidationMessage vm : cachedErrors) {
            if (!errors.contains(vm)) {
                errors.add(vm);
            }
        }
        return;
    }
    if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), defn.hasSnapshot(), I18nConstants.VALIDATION_VAL_PROFILE_NOSNAPSHOT, defn.getUrl())) {
        List<ValidationMessage> localErrors = new ArrayList<ValidationMessage>();
        resTracker.startValidating(defn);
        trackUsage(defn, hostContext, element);
        validateElement(hostContext, localErrors, defn, defn.getSnapshot().getElement().get(0), null, null, resource, element, element.getName(), stack, false, true, null);
        resTracker.storeOutcomes(defn, localErrors);
        for (ValidationMessage vm : localErrors) {
            if (!errors.contains(vm)) {
                errors.add(vm);
            }
        }
    }
    if (checkSpecials) {
        checkSpecials(hostContext, errors, element, stack, checkSpecials);
        validateResourceRules(errors, element, stack);
    }
}
Also used : ValidationMessage(org.hl7.fhir.utilities.validation.ValidationMessage) ResourceValidationTracker(org.hl7.fhir.validation.instance.utils.ResourceValidationTracker) ArrayList(java.util.ArrayList)

Example 5 with ValidatorHostContext

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

the class InstanceValidator method checkChildByDefinition.

public void checkChildByDefinition(ValidatorHostContext hostContext, List<ValidationMessage> errors, StructureDefinition profile, ElementDefinition definition, Element resource, Element element, String actualType, NodeStack stack, boolean inCodeableConcept, boolean checkDisplayInContext, ElementInfo ei, String extensionUrl, ElementDefinition checkDefn, boolean isSlice) {
    List<String> profiles = new ArrayList<String>();
    String type = null;
    ElementDefinition typeDefn = null;
    checkMustSupport(profile, ei);
    if (checkDefn.getType().size() == 1 && !"*".equals(checkDefn.getType().get(0).getWorkingCode()) && !"Element".equals(checkDefn.getType().get(0).getWorkingCode()) && !"BackboneElement".equals(checkDefn.getType().get(0).getWorkingCode())) {
        type = checkDefn.getType().get(0).getWorkingCode();
        String stype = ei.getElement().fhirType();
        if (checkDefn.isChoice() && !stype.equals(type)) {
            if ("Extension".equals(profile.getType())) {
            // error will be raised elsewhere
            } else {
                rule(errors, IssueType.STRUCTURE, element.line(), element.col(), ei.getPath(), false, I18nConstants.EXTENSION_PROF_TYPE, profile.getUrl(), type, stype);
            }
        }
        // Excluding reference is a kludge to get around versioning issues
        if (checkDefn.getType().get(0).hasProfile()) {
            for (CanonicalType p : checkDefn.getType().get(0).getProfile()) {
                profiles.add(p.getValue());
            }
        }
    } else if (checkDefn.getType().size() == 1 && "*".equals(checkDefn.getType().get(0).getWorkingCode())) {
        String prefix = tail(checkDefn.getPath());
        assert prefix.endsWith("[x]");
        type = ei.getName().substring(prefix.length() - 3);
        if (isPrimitiveType(type))
            type = Utilities.uncapitalize(type);
        if (checkDefn.getType().get(0).hasProfile()) {
            for (CanonicalType p : checkDefn.getType().get(0).getProfile()) {
                profiles.add(p.getValue());
            }
        }
    } else if (checkDefn.getType().size() > 1) {
        String prefix = tail(checkDefn.getPath());
        assert typesAreAllReference(checkDefn.getType()) || checkDefn.hasRepresentation(PropertyRepresentation.TYPEATTR) || prefix.endsWith("[x]") || isResourceAndTypes(checkDefn) : "Multiple Types allowed, but name is wrong @ " + checkDefn.getPath() + ": " + checkDefn.typeSummaryVB();
        if (checkDefn.hasRepresentation(PropertyRepresentation.TYPEATTR)) {
            type = ei.getElement().getType();
        } else if (ei.getElement().isResource()) {
            type = ei.getElement().fhirType();
        } else {
            prefix = prefix.substring(0, prefix.length() - 3);
            for (TypeRefComponent t : checkDefn.getType()) if ((prefix + Utilities.capitalize(t.getWorkingCode())).equals(ei.getName())) {
                type = t.getWorkingCode();
                // Excluding reference is a kludge to get around versioning issues
                if (t.hasProfile() && !type.equals("Reference"))
                    profiles.add(t.getProfile().get(0).getValue());
            }
        }
        if (type == null) {
            TypeRefComponent trc = checkDefn.getType().get(0);
            if (trc.getWorkingCode().equals("Reference"))
                type = "Reference";
            else
                rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), stack.getLiteralPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_NOTYPE, ei.getName(), describeTypes(checkDefn.getType()));
        }
    } else if (checkDefn.getContentReference() != null) {
        typeDefn = resolveNameReference(profile.getSnapshot(), checkDefn.getContentReference());
    } else if (checkDefn.getType().size() == 1 && ("Element".equals(checkDefn.getType().get(0).getWorkingCode()) || "BackboneElement".equals(checkDefn.getType().get(0).getWorkingCode()))) {
        if (checkDefn.getType().get(0).hasProfile()) {
            CanonicalType pu = checkDefn.getType().get(0).getProfile().get(0);
            if (pu.hasExtension(ToolingExtensions.EXT_PROFILE_ELEMENT))
                profiles.add(pu.getValue() + "#" + pu.getExtensionString(ToolingExtensions.EXT_PROFILE_ELEMENT));
            else
                profiles.add(pu.getValue());
        }
    }
    if (type != null) {
        if (type.startsWith("@")) {
            checkDefn = findElement(profile, type.substring(1));
            if (isSlice) {
                ei.slice = ei.definition;
            } else {
                ei.definition = ei.definition;
            }
            type = null;
        }
    }
    NodeStack localStack = stack.push(ei.getElement(), "*".equals(ei.getDefinition().getBase().getMax()) && ei.count == -1 ? 0 : ei.count, checkDefn, type == null ? typeDefn : resolveType(type, checkDefn.getType()));
    // if (debug) {
    // System.out.println("  check " + localStack.getLiteralPath()+" against "+ei.getDefinition().getId()+" in profile "+profile.getUrl());
    // }
    String localStackLiteralPath = localStack.getLiteralPath();
    String eiPath = ei.getPath();
    if (!eiPath.equals(localStackLiteralPath)) {
        assert (eiPath.equals(localStackLiteralPath)) : "ei.path: " + ei.getPath() + "  -  localStack.getLiteralPath: " + localStackLiteralPath;
    }
    boolean thisIsCodeableConcept = false;
    String thisExtension = null;
    boolean checkDisplay = true;
    SpecialElement special = ei.getElement().getSpecial();
    if (special == SpecialElement.BUNDLE_ENTRY || special == SpecialElement.BUNDLE_OUTCOME || special == SpecialElement.PARAMETER) {
        checkInvariants(hostContext, errors, profile, typeDefn != null ? typeDefn : checkDefn, ei.getElement(), ei.getElement(), localStack, false);
    } else {
        checkInvariants(hostContext, errors, profile, typeDefn != null ? typeDefn : checkDefn, resource, ei.getElement(), localStack, false);
    }
    ei.getElement().markValidation(profile, checkDefn);
    boolean elementValidated = false;
    if (type != null) {
        if (isPrimitiveType(type)) {
            checkPrimitive(hostContext, errors, ei.getPath(), type, checkDefn, ei.getElement(), profile, stack);
        } else {
            if (checkDefn.hasFixed()) {
                checkFixedValue(errors, ei.getPath(), ei.getElement(), checkDefn.getFixed(), profile.getUrl(), checkDefn.getSliceName(), null, false);
            }
            if (checkDefn.hasPattern()) {
                checkFixedValue(errors, ei.getPath(), ei.getElement(), checkDefn.getPattern(), profile.getUrl(), checkDefn.getSliceName(), null, true);
            }
        }
        if (type.equals("Identifier")) {
            checkIdentifier(errors, ei.getPath(), ei.getElement(), checkDefn);
        } else if (type.equals("Coding")) {
            checkCoding(errors, ei.getPath(), ei.getElement(), profile, checkDefn, inCodeableConcept, checkDisplayInContext, stack);
        } else if (type.equals("Quantity")) {
            checkQuantity(errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack);
        } else if (type.equals("Attachment")) {
            checkAttachment(errors, ei.getPath(), ei.getElement(), profile, checkDefn, inCodeableConcept, checkDisplayInContext, stack);
        } else if (type.equals("CodeableConcept")) {
            checkDisplay = checkCodeableConcept(errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack);
            thisIsCodeableConcept = true;
        } else if (type.equals("Reference")) {
            checkReference(hostContext, errors, ei.getPath(), ei.getElement(), profile, checkDefn, actualType, localStack);
        // We only check extensions if we're not in a complex extension or if the element we're dealing with is not defined as part of that complex extension
        } else if (type.equals("Extension")) {
            Element eurl = ei.getElement().getNamedChild("url");
            if (rule(errors, IssueType.INVALID, ei.getPath(), eurl != null, I18nConstants.EXTENSION_EXT_URL_NOTFOUND)) {
                String url = eurl.primitiveValue();
                thisExtension = url;
                if (rule(errors, IssueType.INVALID, ei.getPath(), !Utilities.noString(url), I18nConstants.EXTENSION_EXT_URL_NOTFOUND)) {
                    if (rule(errors, IssueType.INVALID, ei.getPath(), (extensionUrl != null) || Utilities.isAbsoluteUrl(url), I18nConstants.EXTENSION_EXT_URL_ABSOLUTE)) {
                        checkExtension(hostContext, errors, ei.getPath(), resource, element, ei.getElement(), checkDefn, profile, localStack, stack, extensionUrl);
                    }
                }
            }
        } else if (type.equals("Resource") || isResource(type)) {
            validateContains(hostContext, errors, ei.getPath(), checkDefn, definition, resource, ei.getElement(), localStack, idStatusForEntry(element, ei), // if
            profile);
            elementValidated = true;
        // (str.matches(".*([.,/])work\\1$"))
        } else if (Utilities.isAbsoluteUrl(type)) {
            StructureDefinition defn = context.fetchTypeDefinition(type);
            if (defn != null && hasMapping("http://hl7.org/fhir/terminology-pattern", defn, defn.getSnapshot().getElementFirstRep())) {
                List<String> txtype = getMapping("http://hl7.org/fhir/terminology-pattern", defn, defn.getSnapshot().getElementFirstRep());
                if (txtype.contains("CodeableConcept")) {
                    checkTerminologyCodeableConcept(errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack, defn);
                    thisIsCodeableConcept = true;
                } else if (txtype.contains("Coding")) {
                    checkTerminologyCoding(errors, ei.getPath(), ei.getElement(), profile, checkDefn, inCodeableConcept, checkDisplayInContext, stack, defn);
                }
            }
        }
    } else {
        if (rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), stack.getLiteralPath(), checkDefn != null, I18nConstants.VALIDATION_VAL_CONTENT_UNKNOWN, ei.getName()))
            validateElement(hostContext, errors, profile, checkDefn, null, null, resource, ei.getElement(), type, localStack, false, true, null);
    }
    StructureDefinition p = null;
    String tail = null;
    if (profiles.isEmpty()) {
        if (type != null) {
            p = getProfileForType(type, checkDefn.getType());
            // If dealing with a primitive type, then we need to check the current child against
            // the invariants (constraints) on the current element, because otherwise it only gets
            // checked against the primary type's invariants: LLoyd
            // if (p.getKind() == StructureDefinitionKind.PRIMITIVETYPE) {
            // checkInvariants(hostContext, errors, ei.path, profile, ei.definition, null, null, resource, ei.element);
            // }
            rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), p != null, I18nConstants.VALIDATION_VAL_NOTYPE, type);
        }
    } else if (profiles.size() == 1) {
        String url = profiles.get(0);
        if (url.contains("#")) {
            tail = url.substring(url.indexOf("#") + 1);
            url = url.substring(0, url.indexOf("#"));
        }
        p = this.context.fetchResource(StructureDefinition.class, url);
        rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), p != null, I18nConstants.VALIDATION_VAL_UNKNOWN_PROFILE, profiles.get(0));
    } else {
        elementValidated = true;
        HashMap<String, List<ValidationMessage>> goodProfiles = new HashMap<String, List<ValidationMessage>>();
        HashMap<String, List<ValidationMessage>> badProfiles = new HashMap<String, List<ValidationMessage>>();
        for (String typeProfile : profiles) {
            String url = typeProfile;
            tail = null;
            if (url.contains("#")) {
                tail = url.substring(url.indexOf("#") + 1);
                url = url.substring(0, url.indexOf("#"));
            }
            p = this.context.fetchResource(StructureDefinition.class, typeProfile);
            if (rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), p != null, I18nConstants.VALIDATION_VAL_UNKNOWN_PROFILE, typeProfile)) {
                List<ValidationMessage> profileErrors = new ArrayList<ValidationMessage>();
                validateElement(hostContext, profileErrors, p, getElementByTail(p, tail), profile, checkDefn, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension);
                if (hasErrors(profileErrors))
                    badProfiles.put(typeProfile, profileErrors);
                else
                    goodProfiles.put(typeProfile, profileErrors);
            }
        }
        if (goodProfiles.size() == 1) {
            errors.addAll(goodProfiles.values().iterator().next());
        } else if (goodProfiles.size() == 0) {
            rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_NOMATCH, StringUtils.join("; ", profiles));
            for (String m : badProfiles.keySet()) {
                p = this.context.fetchResource(StructureDefinition.class, m);
                for (ValidationMessage message : badProfiles.get(m)) {
                    message.setMessage(message.getMessage() + " (validating against " + p.getUrl() + (p.hasVersion() ? "|" + p.getVersion() : "") + " [" + p.getName() + "])");
                    errors.add(message);
                }
            }
        } else {
            warning(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_MULTIPLEMATCHES, StringUtils.join("; ", goodProfiles.keySet()));
            for (String m : goodProfiles.keySet()) {
                p = this.context.fetchResource(StructureDefinition.class, m);
                for (ValidationMessage message : goodProfiles.get(m)) {
                    message.setMessage(message.getMessage() + " (validating against " + p.getUrl() + (p.hasVersion() ? "|" + p.getVersion() : "") + " [" + p.getName() + "])");
                    errors.add(message);
                }
            }
        }
    }
    if (p != null) {
        trackUsage(p, hostContext, element);
        if (!elementValidated) {
            if (ei.getElement().getSpecial() == SpecialElement.BUNDLE_ENTRY || ei.getElement().getSpecial() == SpecialElement.BUNDLE_OUTCOME || ei.getElement().getSpecial() == SpecialElement.PARAMETER)
                validateElement(hostContext, errors, p, getElementByTail(p, tail), profile, checkDefn, ei.getElement(), ei.getElement(), type, localStack.resetIds(), thisIsCodeableConcept, checkDisplay, thisExtension);
            else
                validateElement(hostContext, errors, p, getElementByTail(p, tail), profile, checkDefn, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension);
        }
        int index = profile.getSnapshot().getElement().indexOf(checkDefn);
        if (index < profile.getSnapshot().getElement().size() - 1) {
            String nextPath = profile.getSnapshot().getElement().get(index + 1).getPath();
            if (!nextPath.equals(checkDefn.getPath()) && nextPath.startsWith(checkDefn.getPath()))
                validateElement(hostContext, errors, profile, checkDefn, null, null, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension);
        }
    }
}
Also used : 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) SpecialElement(org.hl7.fhir.r5.elementmodel.Element.SpecialElement) NodeStack(org.hl7.fhir.validation.instance.utils.NodeStack) CanonicalType(org.hl7.fhir.r5.model.CanonicalType) ContactPoint(org.hl7.fhir.r5.model.ContactPoint) StructureDefinition(org.hl7.fhir.r5.model.StructureDefinition) TypeRefComponent(org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent) ArrayList(java.util.ArrayList) List(java.util.List) TypedElementDefinition(org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition) ElementDefinition(org.hl7.fhir.r5.model.ElementDefinition)

Aggregations

ArrayList (java.util.ArrayList)18 Element (org.hl7.fhir.r5.elementmodel.Element)16 NodeStack (org.hl7.fhir.validation.instance.utils.NodeStack)14 StructureDefinition (org.hl7.fhir.r5.model.StructureDefinition)9 List (java.util.List)8 DefinitionException (org.hl7.fhir.exceptions.DefinitionException)7 FHIRException (org.hl7.fhir.exceptions.FHIRException)7 IOException (java.io.IOException)6 SpecialElement (org.hl7.fhir.r5.elementmodel.Element.SpecialElement)5 ContactPoint (org.hl7.fhir.r5.model.ContactPoint)5 ElementDefinition (org.hl7.fhir.r5.model.ElementDefinition)5 FHIRLexerException (org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException)5 TypedElementDefinition (org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition)5 IndexedElement (org.hl7.fhir.validation.instance.utils.IndexedElement)5 HashMap (java.util.HashMap)4 NotImplementedException (org.apache.commons.lang3.NotImplementedException)4 PathEngineException (org.hl7.fhir.exceptions.PathEngineException)4 TerminologyServiceException (org.hl7.fhir.exceptions.TerminologyServiceException)4 NamedElement (org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement)4 CanonicalType (org.hl7.fhir.r5.model.CanonicalType)4