use of org.hl7.fhir.utilities.validation.ValidationMessage in project org.hl7.fhir.core by hapifhir.
the class StructureDefinitionValidator method validateElementDefinition.
private void validateElementDefinition(List<ValidationMessage> errors, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd) {
boolean typeMustSupport = false;
List<Element> types = element.getChildrenByName("type");
Set<String> typeCodes = new HashSet<>();
for (Element type : types) {
if (hasMustSupportExtension(type)) {
typeMustSupport = true;
}
String tc = type.getChildValue("code");
if (type.hasExtension(ToolingExtensions.EXT_FHIR_TYPE)) {
tc = type.getExtensionValue(ToolingExtensions.EXT_FHIR_TYPE).primitiveValue();
}
if (Utilities.noString(tc) && type.hasChild("code")) {
if (type.getNamedChild("code").hasExtension("http://hl7.org/fhir/StructureDefinition/structuredefinition-json-type")) {
tc = "*";
}
}
typeCodes.add(tc);
// check the stated profile - must be a constraint on the type
if (snapshot || sd != null) {
validateElementType(errors, type, stack.push(type, -1, null, null), sd, element.getChildValue("path"));
}
}
if (typeMustSupport) {
if (snapshot) {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_SNAPSHOT, element.getNamedChildValue("path"));
} else {
hint(errors, IssueType.EXCEPTION, stack.getLiteralPath(), hasSnapshot || "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_DIFF, element.getNamedChildValue("path"));
}
}
if (element.hasChild("binding")) {
Element binding = element.getNamedChild("binding");
validateBinding(errors, binding, stack.push(binding, -1, null, null), typeCodes, snapshot, element.getNamedChildValue("path"));
} else {
// this is a good idea but there's plenty of cases where the rule isn't met; maybe one day it's worth investing the time to exclude these cases and bring this rule back
// String bt = boundType(typeCodes);
// hint(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || bt == null, I18nConstants.SD_ED_SHOULD_BIND, element.getNamedChildValue("path"), bt);
}
// in a snapshot, we validate that fixedValue, pattern, and defaultValue, if present, are all of the right type
if (snapshot && (element.getIdBase() != null) && (element.getIdBase().contains("."))) {
if (rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), !typeCodes.isEmpty() || element.hasChild("contentReference"), I18nConstants.SD_NO_TYPES_OR_CONTENTREF, element.getIdBase())) {
// if we see fixed[x] or pattern[x] applied to a repeating element, we'll give the user a hint
boolean repeating = !Utilities.existsInList(element.getChildValue("max"), "0", "1");
Element v = element.getNamedChild("defaultValue");
if (v != null) {
rule(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "defaultValue", v.fhirType(), typeCodes);
}
v = element.getNamedChild("fixed");
if (v != null) {
rule(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "fixed", v.fhirType(), typeCodes);
hint(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_HINT, element.getIdBase(), "fixed");
if (isPrimitiveType(v.fhirType())) {
warning(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_WARNING_DOTNET, element.getIdBase(), "fixed");
}
}
v = element.getNamedChild("pattern");
if (v != null) {
rule(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "pattern", v.fhirType(), typeCodes);
hint(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_HINT, element.getIdBase(), "pattern");
if (isPrimitiveType(v.fhirType())) {
warning(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_WARNING_DOTNET, element.getIdBase(), "pattern");
}
}
}
// if we see fixed[x] or pattern[x] applied to a repeating element, we'll give the user a hint
}
}
use of org.hl7.fhir.utilities.validation.ValidationMessage in project org.hl7.fhir.core by hapifhir.
the class StructureDefinitionValidator method validateTargetProfile.
private void validateTargetProfile(List<ValidationMessage> errors, Element profile, String code, NodeStack stack, String path) {
String p = profile.primitiveValue();
StructureDefinition sd = context.fetchResource(StructureDefinition.class, p);
if (code.equals("Reference") || code.equals("CodeableReference")) {
if (warning(errors, IssueType.EXCEPTION, stack.getLiteralPath(), sd != null, I18nConstants.SD_ED_TYPE_PROFILE_UNKNOWN, p)) {
StructureDefinition t = determineBaseType(sd);
if (t == null) {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.SD_ED_TYPE_PROFILE_NOTYPE, p);
} else {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), sd.getKind() == StructureDefinitionKind.RESOURCE, I18nConstants.SD_ED_TYPE_PROFILE_WRONG_TARGET, p, t, code, path, "Resource");
}
}
} else if (code.equals("canonical")) {
if (warning(errors, IssueType.EXCEPTION, stack.getLiteralPath(), sd != null, I18nConstants.SD_ED_TYPE_PROFILE_UNKNOWN, p)) {
StructureDefinition t = determineBaseType(sd);
if (t == null) {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.SD_ED_TYPE_PROFILE_NOTYPE, p);
} else if (!VersionUtilities.isR5Ver(context.getVersion())) {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(t.getType()) || "Resource".equals(t.getType()), I18nConstants.SD_ED_TYPE_PROFILE_WRONG_TARGET, p, t, code, path, "Canonical Resource");
} else {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(t.getType()), I18nConstants.SD_ED_TYPE_PROFILE_WRONG_TARGET, p, t, code, path, "Canonical Resource");
}
}
} else {
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.SD_ED_TYPE_NO_TARGET_PROFILE, code);
}
}
use of org.hl7.fhir.utilities.validation.ValidationMessage in project org.hl7.fhir.core by hapifhir.
the class R3R4ConversionTests method test.
@SuppressWarnings("deprecation")
@ParameterizedTest(name = "{index}: id {0}")
@MethodSource("data")
public void test(String name, byte[] content) throws Exception {
checkLoad();
StructureMapUtilities smu4 = new StructureMapUtilities(contextR4, this);
StructureMapUtilities smu3 = new StructureMapUtilities(contextR3, this);
String tn = null;
workingid = null;
byte[] cnt = content;
Exception executionError = null;
List<ValidationMessage> r4validationErrors = new ArrayList<ValidationMessage>();
String roundTripError = null;
try {
extras = new ArrayList<Resource>();
// load the example (r3)
org.hl7.fhir.r4.elementmodel.Element r3 = new org.hl7.fhir.r4.elementmodel.XmlParser(contextR3).parse(new ByteArrayInputStream(content));
tn = r3.fhirType();
workingid = r3.getChildValue("id");
if (SAVING) {
ByteArrayOutputStream bso = new ByteArrayOutputStream();
new org.hl7.fhir.r4.elementmodel.JsonParser(contextR3).compose(r3, bso, OutputStyle.PRETTY, null);
cnt = bso.toByteArray();
Utilities.createDirectory(Utilities.path(TestingUtilities.home(), "implementations", "r3maps", "test-output"));
TextFile.bytesToFile(cnt, Utilities.path(TestingUtilities.home(), "implementations", "r3maps", "test-output", tn + "-" + workingid + ".input.json"));
}
String mapFile = Utilities.path(TestingUtilities.home(), "implementations", "r3maps", "R3toR4", r3.fhirType() + ".map");
if (new File(mapFile).exists()) {
StructureMap sm = smu4.parse(TextFile.fileToString(mapFile), mapFile);
tn = smu4.getTargetType(sm).getType();
// convert from r3 to r4
Resource r4 = ResourceFactory.createResource(tn);
smu4.transform(contextR4, r3, sm, r4);
ByteArrayOutputStream bs = new ByteArrayOutputStream();
new org.hl7.fhir.r4.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(bs, r4);
if (SAVING) {
TextFile.bytesToFile(bs.toByteArray(), Utilities.path(TestingUtilities.home(), "implementations", "r3maps", "test-output", tn + "-" + workingid + ".r4.json"));
for (Resource r : extras) {
bs = new ByteArrayOutputStream();
new org.hl7.fhir.r4.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(bs, r);
TextFile.bytesToFile(bs.toByteArray(), Utilities.path(TestingUtilities.home(), "implementations", "r3maps", "test-output", r.fhirType() + "-" + r.getId() + ".r4.json"));
}
}
// validate against R4
IResourceValidator validator = contextR4.newValidator();
validator.setNoTerminologyChecks(true);
validator.setFetcher(this);
validator.validate(null, r4validationErrors, r4);
// load the R4 to R3 map
mapFile = Utilities.path(TestingUtilities.home(), "implementations", "r3maps", "R4toR3", getMapFor(r4.fhirType(), r3.fhirType()) + ".map");
sm = smu3.parse(TextFile.fileToString(mapFile), mapFile);
// convert to R3
StructureDefinition sd = smu3.getTargetType(sm);
org.hl7.fhir.r4.elementmodel.Element ro3 = Manager.build(contextR3, sd);
smu3.transform(contextR3, r4, sm, ro3);
// compare the XML
bs = new ByteArrayOutputStream();
new org.hl7.fhir.r4.elementmodel.JsonParser(contextR3).compose(ro3, bs, OutputStyle.PRETTY, null);
if (SAVING)
TextFile.bytesToFile(bs.toByteArray(), Utilities.path(TestingUtilities.home(), "implementations", "r3maps", "test-output", tn + "-" + workingid + ".output.json"));
// check(errors, tn, workingid);
roundTripError = TestingUtilities.checkJsonSrcIsSame(new String(cnt), new String(bs.toByteArray()), filter != null);
if (roundTripError != null && roundTripError.equals(rules.getStringProperty(tn + "/" + workingid, "roundtrip")))
roundTripError = null;
} else {
if (loadErrors.containsKey(r3.fhirType() + ".map")) {
executionError = loadErrors.get(r3.fhirType() + ".map");
}
}
} catch (Exception e) {
executionError = e;
}
if (tn != null && workingid != null)
updateOutcomes(tn, workingid, executionError, r4validationErrors, roundTripError);
if (executionError != null)
throw executionError;
}
use of org.hl7.fhir.utilities.validation.ValidationMessage in project org.hl7.fhir.core by hapifhir.
the class R3R4ConversionTests method check.
private void check(List<ValidationMessage> errors, String tn, String id) throws FHIRException {
StringBuilder b = new StringBuilder();
for (ValidationMessage vm : errors) {
if (vm.getMessage() == null)
break;
if (vm.getMessage().contains("Error null validating Coding"))
break;
String s = rules.getStringProperty(tn + "/" + id, "validation");
if (!Utilities.noString(s)) {
boolean ok = false;
for (String m : s.split("\\;")) if (vm.getMessage().contains(m.trim()))
ok = true;
if (ok)
break;
}
s = rules.getStringProperty(tn, "validation");
if (!Utilities.noString(s)) {
boolean ok = false;
for (String m : s.split("\\;")) if (vm.getMessage().contains(m.trim()))
ok = true;
if (ok)
break;
}
if (vm.getLevel() == IssueSeverity.ERROR || vm.getLevel() == IssueSeverity.FATAL) {
b.append("[R4 validation error] " + vm.getLocation() + ": " + vm.getMessage() + "\r\n");
}
}
if (b.length() > 0)
throw new FHIRException(b.toString());
}
use of org.hl7.fhir.utilities.validation.ValidationMessage in project org.hl7.fhir.core by hapifhir.
the class InstanceValidator method validateContains.
private void validateContains(ValidatorHostContext hostContext, List<ValidationMessage> errors, String path, ElementDefinition child, ElementDefinition context, Element resource, Element element, NodeStack stack, IdStatus idstatus, StructureDefinition parentProfile) throws FHIRException {
SpecialElement special = element.getSpecial();
ContainedReferenceValidationPolicy containedValidationPolicy = getPolicyAdvisor() == null ? ContainedReferenceValidationPolicy.CHECK_VALID : getPolicyAdvisor().policyForContained(this, hostContext, context.fhirType(), context.getId(), special, path, parentProfile.getUrl());
if (containedValidationPolicy.ignore()) {
return;
}
String resourceName = element.getType();
TypeRefComponent typeForResource = null;
CommaSeparatedStringBuilder bt = new CommaSeparatedStringBuilder();
// Iterate through all possible types
for (TypeRefComponent type : child.getType()) {
bt.append(type.getCode());
if (type.getCode().equals("Resource") || type.getCode().equals(resourceName)) {
typeForResource = type;
break;
}
}
stack.qualifyPath(".ofType(" + resourceName + ")");
if (typeForResource == null) {
rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE, resourceName, bt.toString());
} else if (isValidResourceType(resourceName, typeForResource)) {
if (containedValidationPolicy.checkValid()) {
// special case: resource wrapper is reset if we're crossing a bundle boundary, but not otherwise
ValidatorHostContext hc = null;
if (special == SpecialElement.BUNDLE_ENTRY || special == SpecialElement.BUNDLE_OUTCOME || special == SpecialElement.PARAMETER) {
resource = element;
assert Utilities.existsInList(hostContext.getRootResource().fhirType(), "Bundle", "Parameters") : "Resource is " + hostContext.getRootResource().fhirType() + ", expected Bundle or Parameters";
// root becomes the grouping resource (should be either bundle or parameters)
hc = hostContext.forEntry(element, hostContext.getRootResource());
} else {
hc = hostContext.forContained(element);
}
stack.resetIds();
if (special != null) {
switch(special) {
case BUNDLE_ENTRY:
case BUNDLE_OUTCOME:
case PARAMETER:
idstatus = IdStatus.OPTIONAL;
break;
case CONTAINED:
stack.setContained(true);
idstatus = IdStatus.REQUIRED;
break;
default:
break;
}
}
if (typeForResource.getProfile().size() == 1) {
long t = System.nanoTime();
StructureDefinition profile = this.context.fetchResource(StructureDefinition.class, typeForResource.getProfile().get(0).asStringValue());
timeTracker.sd(t);
trackUsage(profile, hostContext, element);
if (rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_EXPL, special.toHuman(), resourceName, typeForResource.getProfile().get(0).asStringValue())) {
validateResource(hc, errors, resource, element, profile, idstatus, stack);
}
} else if (typeForResource.getProfile().isEmpty()) {
long t = System.nanoTime();
StructureDefinition profile = this.context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + resourceName);
timeTracker.sd(t);
trackUsage(profile, hostContext, element);
if (rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_TYPE, special == null ? "??" : special.toHuman(), resourceName)) {
validateResource(hc, errors, resource, element, profile, idstatus, stack);
}
} else {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
for (CanonicalType u : typeForResource.getProfile()) {
b.append(u.asStringValue());
}
rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES, special.toHuman(), typeForResource.getCode(), b.toString());
}
}
} else {
List<String> types = new ArrayList<>();
for (UriType u : typeForResource.getProfile()) {
StructureDefinition sd = this.context.fetchResource(StructureDefinition.class, u.getValue());
if (sd != null && !types.contains(sd.getType())) {
types.add(sd.getType());
}
}
if (types.size() == 1) {
rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE2, resourceName, types.get(0));
} else {
rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE3, resourceName, types);
}
}
}
Aggregations