Search in sources :

Example 1 with IndexedElement

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

the class BundleValidator method followResourceLinks.

private void followResourceLinks(Element entry, Map<String, Element> visitedResources, Map<Element, Element> candidateEntries, List<Element> candidateResources, List<ValidationMessage> errors, NodeStack stack, int depth) {
    Element resource = entry.getNamedChild(RESOURCE);
    if (visitedResources.containsValue(resource))
        return;
    visitedResources.put(entry.getNamedChildValue(FULL_URL), resource);
    String type = null;
    Set<String> references = findReferences(resource);
    for (String reference : references) {
        // We don't want errors when just retrieving the element as they will be caught (with better path info) in subsequent processing
        IndexedElement r = getFromBundle(stack.getElement(), reference, entry.getChildValue(FULL_URL), new ArrayList<ValidationMessage>(), stack.addToLiteralPath("entry[" + candidateResources.indexOf(resource) + "]"), type, "transaction".equals(stack.getElement().getChildValue(TYPE)));
        if (r != null && !visitedResources.containsValue(r.getMatch())) {
            followResourceLinks(candidateEntries.get(r.getMatch()), visitedResources, candidateEntries, candidateResources, errors, stack, depth + 1);
        }
    }
}
Also used : IndexedElement(org.hl7.fhir.validation.instance.utils.IndexedElement) ValidationMessage(org.hl7.fhir.utilities.validation.ValidationMessage) IndexedElement(org.hl7.fhir.validation.instance.utils.IndexedElement) Element(org.hl7.fhir.r5.elementmodel.Element)

Example 2 with IndexedElement

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

the class InstanceValidator method getContainedById.

private IndexedElement getContainedById(Element container, String id) {
    List<Element> contained = new ArrayList<Element>();
    container.getNamedChildren("contained", contained);
    for (int i = 0; i < contained.size(); i++) {
        Element we = contained.get(i);
        if (id.equals(we.getNamedChildValue(ID))) {
            return new IndexedElement(i, we, null);
        }
    }
    return null;
}
Also used : IndexedElement(org.hl7.fhir.validation.instance.utils.IndexedElement) 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) ContactPoint(org.hl7.fhir.r5.model.ContactPoint)

Example 3 with IndexedElement

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

the class InstanceValidator method localResolve.

private ResolvedReference localResolve(String ref, NodeStack stack, List<ValidationMessage> errors, String path, Element rootResource, Element groupingResource, Element source) {
    if (ref.startsWith("#")) {
        // work back through the parent list.
        // really, there should only be one level for this (contained resources cannot contain
        // contained resources), but we'll leave that to some other code to worry about
        boolean wasContained = false;
        NodeStack nstack = stack;
        while (nstack != null && nstack.getElement() != null) {
            if (nstack.getElement().getProperty().isResource()) {
                // ok, we'll try to find the contained reference
                if (ref.equals("#") && nstack.getElement().getSpecial() != SpecialElement.CONTAINED && wasContained) {
                    ResolvedReference rr = new ResolvedReference();
                    rr.setResource(nstack.getElement());
                    rr.setFocus(nstack.getElement());
                    rr.setExternal(false);
                    rr.setStack(nstack);
                    // System.out.println("-->"+nstack.getLiteralPath());
                    return rr;
                }
                if (nstack.getElement().getSpecial() == SpecialElement.CONTAINED) {
                    wasContained = true;
                }
                IndexedElement res = getContainedById(nstack.getElement(), ref.substring(1));
                if (res != null) {
                    ResolvedReference rr = new ResolvedReference();
                    rr.setResource(nstack.getElement());
                    rr.setFocus(res.getMatch());
                    rr.setExternal(false);
                    rr.setStack(nstack.push(res.getMatch(), res.getIndex(), res.getMatch().getProperty().getDefinition(), res.getMatch().getProperty().getDefinition()));
                    rr.getStack().qualifyPath(".ofType(" + nstack.getElement().fhirType() + ")");
                    return rr;
                }
            }
            if (nstack.getElement().getSpecial() == SpecialElement.BUNDLE_ENTRY || nstack.getElement().getSpecial() == SpecialElement.PARAMETER) {
                // we don't try to resolve contained references across this boundary
                return null;
            }
            nstack = nstack.getParent();
        }
        // try again, and work up the element parent list
        if (ref.equals("#")) {
            Element e = stack.getElement();
            while (e != null) {
                if (e.getProperty().isResource() && (e.getSpecial() != SpecialElement.CONTAINED)) {
                    ResolvedReference rr = new ResolvedReference();
                    rr.setResource(e);
                    rr.setFocus(e);
                    rr.setExternal(false);
                    rr.setStack(stack.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition()));
                    rr.getStack().qualifyPath(".ofType(" + e.fhirType() + ")");
                    return rr;
                }
                e = e.getParentForValidator();
            }
        }
        return null;
    } else {
        // work back through the parent list - if any of them are bundles, try to resolve
        // the resource in the bundle
        // we're going to try to work this out as we go up
        String fullUrl = null;
        while (stack != null && stack.getElement() != null) {
            if (stack.getElement().getSpecial() == SpecialElement.BUNDLE_ENTRY && fullUrl == null && stack.getParent() != null && stack.getParent().getElement().getName().equals(ENTRY)) {
                String type = stack.getParent().getParent().getElement().getChildValue(TYPE);
                // we don't try to resolve contained references across this boundary
                fullUrl = stack.getParent().getElement().getChildValue(FULL_URL);
                if (fullUrl == null)
                    rule(errors, IssueType.REQUIRED, stack.getParent().getElement().line(), stack.getParent().getElement().col(), stack.getParent().getLiteralPath(), Utilities.existsInList(type, "batch-response", "transaction-response") || fullUrl != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFULLURL);
            }
            if (BUNDLE.equals(stack.getElement().getType())) {
                String type = stack.getElement().getChildValue(TYPE);
                IndexedElement res = getFromBundle(stack.getElement(), ref, fullUrl, errors, path, type, "transaction".equals(type));
                if (res == null) {
                    return null;
                } else {
                    ResolvedReference rr = new ResolvedReference();
                    rr.setResource(res.getMatch());
                    rr.setFocus(res.getMatch());
                    rr.setExternal(false);
                    rr.setStack(stack.push(res.getEntry(), res.getIndex(), res.getEntry().getProperty().getDefinition(), res.getEntry().getProperty().getDefinition()).push(res.getMatch(), -1, res.getMatch().getProperty().getDefinition(), res.getMatch().getProperty().getDefinition()));
                    rr.getStack().qualifyPath(".ofType(" + rr.getResource().fhirType() + ")");
                    return rr;
                }
            }
            if (stack.getElement().getSpecial() == SpecialElement.PARAMETER && stack.getParent() != null) {
                NodeStack tgt = findInParams(stack.getParent().getParent(), ref);
                if (tgt != null) {
                    ResolvedReference rr = new ResolvedReference();
                    rr.setResource(tgt.getElement());
                    rr.setFocus(tgt.getElement());
                    rr.setExternal(false);
                    rr.setStack(tgt);
                    rr.getStack().qualifyPath(".ofType(" + tgt.getElement().fhirType() + ")");
                    return rr;
                }
            }
            stack = stack.getParent();
        }
        // we can get here if we got called via FHIRPath conformsTo which breaks the stack continuity.
        if (groupingResource != null && BUNDLE.equals(groupingResource.fhirType())) {
            // it could also be a Parameters resource - that case isn't handled yet
            String type = groupingResource.getChildValue(TYPE);
            Element entry = getEntryForSource(groupingResource, source);
            fullUrl = entry.getChildValue(FULL_URL);
            IndexedElement res = getFromBundle(groupingResource, ref, fullUrl, errors, path, type, "transaction".equals(type));
            if (res == null) {
                return null;
            } else {
                ResolvedReference rr = new ResolvedReference();
                rr.setResource(res.getMatch());
                rr.setFocus(res.getMatch());
                rr.setExternal(false);
                rr.setStack(new NodeStack(context, null, rootResource, validationLanguage).push(res.getEntry(), res.getIndex(), res.getEntry().getProperty().getDefinition(), res.getEntry().getProperty().getDefinition()).push(res.getMatch(), -1, res.getMatch().getProperty().getDefinition(), res.getMatch().getProperty().getDefinition()));
                rr.getStack().qualifyPath(".ofType(" + rr.getResource().fhirType() + ")");
                return rr;
            }
        }
    }
    return null;
}
Also used : ResolvedReference(org.hl7.fhir.validation.instance.utils.ResolvedReference) IndexedElement(org.hl7.fhir.validation.instance.utils.IndexedElement) 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) NodeStack(org.hl7.fhir.validation.instance.utils.NodeStack)

Example 4 with IndexedElement

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

the class BaseValidator method getFromBundle.

protected IndexedElement getFromBundle(Element bundle, String ref, String fullUrl, List<ValidationMessage> errors, String path, String type, boolean isTransaction) {
    String targetUrl = null;
    String version = "";
    String resourceType = null;
    if (ref.startsWith("http:") || ref.startsWith("urn:") || Utilities.isAbsoluteUrl(ref)) {
        // We've got an absolute reference, no need to calculate
        if (ref.contains("/_history/")) {
            targetUrl = ref.substring(0, ref.indexOf("/_history/") - 1);
            version = ref.substring(ref.indexOf("/_history/") + 10);
        } else
            targetUrl = ref;
    } else if (fullUrl == null) {
        // This isn't a problem for signatures - if it's a signature, we won't have a resolution for a relative reference.  For anything else, this is an error
        // but this rule doesn't apply for batches or transactions
        rule(errors, IssueType.REQUIRED, -1, -1, path, Utilities.existsInList(type, "batch-response", "transaction-response") || path.startsWith("Bundle.signature"), I18nConstants.BUNDLE_BUNDLE_FULLURL_MISSING);
        return null;
    } else if (ref.split("/").length != 2 && ref.split("/").length != 4) {
        if (isTransaction) {
            rule(errors, IssueType.INVALID, -1, -1, path, isSearchUrl(ref), I18nConstants.REFERENCE_REF_FORMAT1, ref);
        } else {
            rule(errors, IssueType.INVALID, -1, -1, path, false, I18nConstants.REFERENCE_REF_FORMAT2, ref);
        }
        return null;
    } else {
        String base = "";
        if (fullUrl.startsWith("urn")) {
            String[] parts = fullUrl.split("\\:");
            for (int i = 0; i < parts.length - 1; i++) {
                base = base + parts[i] + ":";
            }
        } else {
            String[] parts;
            parts = fullUrl.split("/");
            for (int i = 0; i < parts.length - 2; i++) {
                base = base + parts[i] + "/";
            }
        }
        String id = null;
        if (ref.contains("/_history/")) {
            version = ref.substring(ref.indexOf("/_history/") + 10);
            String[] refBaseParts = ref.substring(0, ref.indexOf("/_history/")).split("/");
            resourceType = refBaseParts[0];
            id = refBaseParts[1];
        } else if (base.startsWith("urn")) {
            resourceType = ref.split("/")[0];
            id = ref.split("/")[1];
        } else
            id = ref;
        targetUrl = base + id;
    }
    List<Element> entries = new ArrayList<Element>();
    bundle.getNamedChildren(ENTRY, entries);
    Element match = null;
    int matchIndex = -1;
    for (int i = 0; i < entries.size(); i++) {
        Element we = entries.get(i);
        if (targetUrl.equals(we.getChildValue(FULL_URL))) {
            Element r = we.getNamedChild(RESOURCE);
            if (version.isEmpty()) {
                rule(errors, IssueType.FORBIDDEN, -1, -1, path, match == null, I18nConstants.BUNDLE_BUNDLE_MULTIPLEMATCHES, ref);
                match = r;
                matchIndex = i;
            } else {
                try {
                    if (version.equals(r.getChildren(META).get(0).getChildValue("versionId"))) {
                        rule(errors, IssueType.FORBIDDEN, -1, -1, path, match == null, I18nConstants.BUNDLE_BUNDLE_MULTIPLEMATCHES, ref);
                        match = r;
                        matchIndex = i;
                    }
                } catch (Exception e) {
                    warning(errors, IssueType.REQUIRED, -1, -1, path, r.getChildren(META).size() == 1 && r.getChildren(META).get(0).getChildValue("versionId") != null, I18nConstants.BUNDLE_BUNDLE_FULLURL_NEEDVERSION, targetUrl);
                // If one of these things is null
                }
            }
        }
    }
    if (match != null && resourceType != null)
        rule(errors, IssueType.REQUIRED, -1, -1, path, match.getType().equals(resourceType), I18nConstants.REFERENCE_REF_RESOURCETYPE, ref, match.getType());
    if (match == null)
        warning(errors, IssueType.REQUIRED, -1, -1, path, !ref.startsWith("urn"), I18nConstants.BUNDLE_BUNDLE_NOT_LOCAL, ref);
    return match == null ? null : new IndexedElement(matchIndex, match, entries.get(matchIndex));
}
Also used : IndexedElement(org.hl7.fhir.validation.instance.utils.IndexedElement) IndexedElement(org.hl7.fhir.validation.instance.utils.IndexedElement) Element(org.hl7.fhir.r5.elementmodel.Element) ArrayList(java.util.ArrayList) IOException(java.io.IOException) FHIRException(org.hl7.fhir.exceptions.FHIRException)

Aggregations

Element (org.hl7.fhir.r5.elementmodel.Element)4 IndexedElement (org.hl7.fhir.validation.instance.utils.IndexedElement)4 ArrayList (java.util.ArrayList)2 SpecialElement (org.hl7.fhir.r5.elementmodel.Element.SpecialElement)2 NamedElement (org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement)2 IOException (java.io.IOException)1 FHIRException (org.hl7.fhir.exceptions.FHIRException)1 ContactPoint (org.hl7.fhir.r5.model.ContactPoint)1 ValidationMessage (org.hl7.fhir.utilities.validation.ValidationMessage)1 NodeStack (org.hl7.fhir.validation.instance.utils.NodeStack)1 ResolvedReference (org.hl7.fhir.validation.instance.utils.ResolvedReference)1