use of org.hl7.fhir.validation.instance.utils.NodeStack in project org.hl7.fhir.core by hapifhir.
the class InstanceValidator method checkPrimitiveBinding.
private void checkPrimitiveBinding(ValidatorHostContext hostContext, List<ValidationMessage> errors, String path, String type, ElementDefinition elementContext, Element element, StructureDefinition profile, NodeStack stack) {
// We ignore bindings that aren't on string, uri or code
if (!element.hasPrimitiveValue() || !("code".equals(type) || "string".equals(type) || "uri".equals(type) || "url".equals(type) || "canonical".equals(type))) {
return;
}
if (noTerminologyChecks)
return;
String value = element.primitiveValue();
// System.out.println("check "+value+" in "+path);
// firstly, resolve the value set
ElementDefinitionBindingComponent binding = elementContext.getBinding();
if (binding.hasValueSet()) {
ValueSet vs = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl());
if (vs == 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, vs != null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND, describeReference(binding.getValueSet()));
}
} else {
CodedContentValidationPolicy validationPolicy = getPolicyAdvisor() == null ? CodedContentValidationPolicy.VALUESET : getPolicyAdvisor().policyForCodedContent(this, hostContext, stack.getLiteralPath(), elementContext, profile, BindingKind.PRIMARY, vs, new ArrayList<>());
if (validationPolicy != CodedContentValidationPolicy.IGNORE) {
long t = System.nanoTime();
ValidationResult vr = null;
if (binding.getStrength() != BindingStrength.EXAMPLE) {
ValidationOptions options = baseOptions.setLanguage(stack.getWorkingLang()).guessSystem();
if (validationPolicy == CodedContentValidationPolicy.CODE) {
options = options.noCheckValueSetMembership();
}
vr = checkCodeOnServer(stack, vs, value, options);
}
timeTracker.tx(t, "vc " + value + "");
if (binding.getStrength() == BindingStrength.REQUIRED) {
removeTrackedMessagesForLocation(errors, element, path);
}
if (vr != null && !vr.isOk()) {
if (vr.IsNoService())
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_15, value);
else if (binding.getStrength() == BindingStrength.REQUIRED)
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_16, value, describeValueSet(binding.getValueSet()), getErrorMessage(vr.getMessage()));
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"), value, stack);
else if (!noExtensibleWarnings && !isOkExtension(value, vs))
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_17, value, describeValueSet(binding.getValueSet()), getErrorMessage(vr.getMessage()));
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_18, value, describeValueSet(binding.getValueSet()), getErrorMessage(vr.getMessage()));
}
}
}
}
}
} else if (!noBindingMsgSuppressed)
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, !type.equals("code"), I18nConstants.TERMINOLOGY_TX_BINDING_NOSOURCE2);
}
use of org.hl7.fhir.validation.instance.utils.NodeStack 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;
}
use of org.hl7.fhir.validation.instance.utils.NodeStack in project org.hl7.fhir.core by hapifhir.
the class InstanceValidator method checkExtension.
private StructureDefinition checkExtension(ValidatorHostContext hostContext, List<ValidationMessage> errors, String path, Element resource, Element container, Element element, ElementDefinition def, StructureDefinition profile, NodeStack stack, NodeStack containerStack, String extensionUrl) throws FHIRException {
String url = element.getNamedChildValue("url");
boolean isModifier = element.getName().equals("modifierExtension");
assert def.getIsModifier() == isModifier;
long t = System.nanoTime();
StructureDefinition ex = Utilities.isAbsoluteUrl(url) ? context.fetchResource(StructureDefinition.class, url) : null;
timeTracker.sd(t);
if (ex == null) {
ex = getXverExt(errors, path, element, url);
}
if (ex == null) {
if (extensionUrl != null && !isAbsolute(url)) {
if (extensionUrl.equals(profile.getUrl())) {
rule(errors, IssueType.INVALID, element.line(), element.col(), path + "[url='" + url + "']", hasExtensionSlice(profile, url), I18nConstants.EXTENSION_EXT_SUBEXTENSION_INVALID, url, profile.getUrl());
}
} else if (SpecialExtensions.isKnownExtension(url)) {
ex = SpecialExtensions.getDefinition(url);
} else if (Utilities.existsInList(url, BuildExtensions.allConsts())) {
// nothing
} else if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, allowUnknownExtension(url), I18nConstants.EXTENSION_EXT_UNKNOWN_NOTHERE, url)) {
hint(errors, IssueType.STRUCTURE, element.line(), element.col(), path, isKnownExtension(url), I18nConstants.EXTENSION_EXT_UNKNOWN, url);
}
}
if (ex != null) {
trackUsage(ex, hostContext, element);
// check internal definitions are coherent
if (isModifier) {
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path + "[url='" + url + "']", def.getIsModifier() == isModifier, I18nConstants.EXTENSION_EXT_MODIFIER_MISMATCHY);
} else {
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path + "[url='" + url + "']", def.getIsModifier() == isModifier, I18nConstants.EXTENSION_EXT_MODIFIER_MISMATCHN);
}
// two questions
// 1. can this extension be used here?
checkExtensionContext(errors, resource, container, ex, containerStack, hostContext, isModifier);
if (isModifier)
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path + "[url='" + url + "']", ex.getSnapshot().getElement().get(0).getIsModifier(), I18nConstants.EXTENSION_EXT_MODIFIER_Y, url);
else
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path + "[url='" + url + "']", !ex.getSnapshot().getElement().get(0).getIsModifier(), I18nConstants.EXTENSION_EXT_MODIFIER_N, url);
// check the type of the extension:
Set<String> allowedTypes = listExtensionTypes(ex);
String actualType = getExtensionType(element);
if (actualType == null)
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, allowedTypes.isEmpty(), I18nConstants.EXTENSION_EXT_SIMPLE, url);
else
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, allowedTypes.contains(actualType), I18nConstants.EXTENSION_EXT_TYPE, url, allowedTypes.toString(), actualType);
// 3. is the content of the extension valid?
validateElement(hostContext, errors, ex, ex.getSnapshot().getElement().get(0), null, null, resource, element, "Extension", stack, false, true, url);
}
return ex;
}
use of org.hl7.fhir.validation.instance.utils.NodeStack in project org.hl7.fhir.core by hapifhir.
the class InstanceValidator method checkAttachment.
private void checkAttachment(List<ValidationMessage> errors, String path, Element element, StructureDefinition theProfile, ElementDefinition definition, boolean theInCodeableConcept, boolean theCheckDisplayInContext, NodeStack theStack) {
long size = -1;
// first check size
String fetchError = null;
if (element.hasChild("data")) {
String b64 = element.getChildValue("data");
// Note: If the value isn't valid, we're not adding an error here, as the test to the
// child Base64Binary will catch it and we don't want to log it twice
boolean ok = isValidBase64(b64);
if (ok && element.hasChild("size")) {
size = countBase64DecodedBytes(b64);
String sz = element.getChildValue("size");
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, Long.toString(size).equals(sz), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_SIZE_CORRECT, sz, size);
}
} else if (element.hasChild("size")) {
String sz = element.getChildValue("size");
if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, Utilities.isLong(sz), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_SIZE_INVALID, sz)) {
size = Long.parseLong(sz);
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, size >= 0, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_SIZE_INVALID, sz);
}
} else if (element.hasChild("url")) {
String url = element.getChildValue("url");
if (definition.hasExtension("http://hl7.org/fhir/StructureDefinition/maxSize")) {
try {
if (url.startsWith("http://") || url.startsWith("https://")) {
if (fetcher == null) {
fetchError = context.formatMessage(I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_NO_FETCHER, url);
} else {
byte[] cnt = fetcher.fetchRaw(this, url);
size = cnt.length;
}
} else if (url.startsWith("file:")) {
size = new File(url.substring(5)).length();
} else {
fetchError = context.formatMessage(I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_UNKNOWN_URL_SCHEME, url);
}
} catch (Exception e) {
if (STACK_TRACE)
e.printStackTrace();
fetchError = context.formatMessage(I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_URL_ERROR, url, e.getMessage());
}
}
}
if (definition.hasExtension("http://hl7.org/fhir/StructureDefinition/maxSize")) {
if (warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, size >= 0, fetchError)) {
long def = Long.parseLong(ToolingExtensions.readStringExtension(definition, "http://hl7.org/fhir/StructureDefinition/maxSize"));
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, size <= def, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_TOO_LONG, size, def);
}
}
warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, (element.hasChild("data") || element.hasChild("url")) || (element.hasChild("contentType") || element.hasChild("language")), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_NO_CONTENT);
}
use of org.hl7.fhir.validation.instance.utils.NodeStack in project org.hl7.fhir.core by hapifhir.
the class InstanceValidator method start.
// checkSpecials = we're only going to run these tests if we are actually validating this content (as opposed to we looked it up)
private void start(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element resource, Element element, StructureDefinition defn, NodeStack stack) throws FHIRException {
checkLang(resource, stack);
if (crumbTrails) {
element.addMessage(signpost(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), I18nConstants.VALIDATION_VAL_PROFILE_SIGNPOST, defn.getUrl()));
}
if (BUNDLE.equals(element.fhirType())) {
resolveBundleReferences(element, new ArrayList<Element>());
}
startInner(hostContext, errors, resource, element, defn, stack, hostContext.isCheckSpecials());
Element meta = element.getNamedChild(META);
if (meta != null) {
List<Element> profiles = new ArrayList<Element>();
meta.getNamedChildren("profile", profiles);
int i = 0;
for (Element profile : profiles) {
StructureDefinition sd = context.fetchResource(StructureDefinition.class, profile.primitiveValue());
if (!defn.getUrl().equals(profile.primitiveValue())) {
// is this a version specific reference?
VersionURLInfo vu = VersionUtilities.parseVersionUrl(profile.primitiveValue());
if (vu != null) {
if (!VersionUtilities.versionsCompatible(vu.getVersion(), context.getVersion())) {
hint(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath() + ".meta.profile[" + i + "]", false, I18nConstants.VALIDATION_VAL_PROFILE_OTHER_VERSION, vu.getVersion());
} else if (vu.getUrl().equals(defn.getUrl())) {
hint(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath() + ".meta.profile[" + i + "]", false, I18nConstants.VALIDATION_VAL_PROFILE_THIS_VERSION_OK);
} else {
StructureDefinition sdt = context.fetchResource(StructureDefinition.class, vu.getUrl());
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath() + ".meta.profile[" + i + "]", false, I18nConstants.VALIDATION_VAL_PROFILE_THIS_VERSION_OTHER, sdt == null ? "null" : sdt.getType());
}
} else {
if (sd == null) {
// we'll try fetching it directly from it's source, but this is likely to fail later even if the resolution succeeds
if (fetcher == null) {
warning(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath() + ".meta.profile[" + i + "]", false, I18nConstants.VALIDATION_VAL_PROFILE_UNKNOWN, profile.primitiveValue());
} else if (!fetcher.fetchesCanonicalResource(this, profile.primitiveValue())) {
warning(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath() + ".meta.profile[" + i + "]", false, I18nConstants.VALIDATION_VAL_PROFILE_UNKNOWN_NOT_POLICY, profile.primitiveValue());
} else {
try {
sd = (StructureDefinition) fetcher.fetchCanonicalResource(this, profile.primitiveValue());
} catch (Exception e) {
if (STACK_TRACE)
e.printStackTrace();
warning(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath() + ".meta.profile[" + i + "]", false, I18nConstants.VALIDATION_VAL_PROFILE_UNKNOWN_ERROR, profile.primitiveValue(), e.getMessage());
}
if (sd != null) {
context.cacheResource(sd);
}
}
}
if (sd != null) {
if (crumbTrails) {
element.addMessage(signpost(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), I18nConstants.VALIDATION_VAL_PROFILE_SIGNPOST_META, sd.getUrl()));
}
stack.resetIds();
startInner(hostContext, errors, resource, element, sd, stack, false);
}
}
}
i++;
}
}
String rt = element.fhirType();
for (ImplementationGuide ig : igs) {
for (ImplementationGuideGlobalComponent gl : ig.getGlobal()) {
if (rt.equals(gl.getType())) {
StructureDefinition sd = context.fetchResource(StructureDefinition.class, gl.getProfile());
if (warning(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), sd != null, I18nConstants.VALIDATION_VAL_GLOBAL_PROFILE_UNKNOWN, gl.getProfile())) {
if (crumbTrails) {
element.addMessage(signpost(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), I18nConstants.VALIDATION_VAL_PROFILE_SIGNPOST_GLOBAL, sd.getUrl(), ig.getUrl()));
}
stack.resetIds();
startInner(hostContext, errors, resource, element, sd, stack, false);
}
}
}
}
}
Aggregations