enforce constraints in slicer as well as in slice + Handle -tx n/a better
This commit is contained in:
parent
d20582ca9d
commit
920c3193d0
|
@ -49,6 +49,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import org.fhir.ucum.UcumService;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.NoTerminologyServiceException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.r5.conformance.ProfileUtilities;
|
||||
import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy;
|
||||
|
@ -910,6 +911,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
txCache.cacheValidation(cacheToken, res, TerminologyCache.TRANSIENT);
|
||||
return res;
|
||||
} catch (Exception e) {
|
||||
if (e instanceof NoTerminologyServiceException) {
|
||||
return new ValidationResult(IssueSeverity.ERROR, "No Terminology Service", TerminologyServiceErrorClass.NOSERVICE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.NoTerminologyServiceException;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult;
|
||||
import org.hl7.fhir.r5.model.CanonicalType;
|
||||
|
@ -515,6 +516,9 @@ public class ValueSetCheckerSimple implements ValueSetChecker {
|
|||
if (res.getErrorClass() == TerminologyServiceErrorClass.UNKNOWN || res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED || res.getErrorClass() == TerminologyServiceErrorClass.VALUESET_UNSUPPORTED) {
|
||||
return null;
|
||||
}
|
||||
if (res.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) {
|
||||
throw new NoTerminologyServiceException();
|
||||
}
|
||||
return res.isOk();
|
||||
} else {
|
||||
if (vsi.hasFilter()) {
|
||||
|
|
|
@ -37,10 +37,8 @@ import java.io.ByteArrayInputStream;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
@ -51,15 +49,10 @@ import java.util.Set;
|
|||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64InputStream;
|
||||
import org.apache.commons.io.Charsets;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.r5.model.Reference;
|
||||
import org.hl7.fhir.convertors.*;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.exceptions.PathEngineException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.r5.conformance.ProfileUtilities;
|
||||
|
@ -86,6 +79,7 @@ import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
|||
import org.hl7.fhir.r5.model.CodeableConcept;
|
||||
import org.hl7.fhir.r5.model.Coding;
|
||||
import org.hl7.fhir.r5.model.ContactPoint;
|
||||
import org.hl7.fhir.r5.model.DataType;
|
||||
import org.hl7.fhir.r5.model.DateTimeType;
|
||||
import org.hl7.fhir.r5.model.DateType;
|
||||
import org.hl7.fhir.r5.model.DecimalType;
|
||||
|
@ -114,6 +108,7 @@ import org.hl7.fhir.r5.model.PrimitiveType;
|
|||
import org.hl7.fhir.r5.model.Quantity;
|
||||
import org.hl7.fhir.r5.model.Range;
|
||||
import org.hl7.fhir.r5.model.Ratio;
|
||||
import org.hl7.fhir.r5.model.Reference;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.r5.model.SampledData;
|
||||
import org.hl7.fhir.r5.model.SearchParameter;
|
||||
|
@ -127,18 +122,30 @@ import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionSnapshotComp
|
|||
import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
|
||||
import org.hl7.fhir.r5.model.TimeType;
|
||||
import org.hl7.fhir.r5.model.Timing;
|
||||
import org.hl7.fhir.r5.model.DataType;
|
||||
import org.hl7.fhir.r5.model.TypeDetails;
|
||||
import org.hl7.fhir.r5.model.UriType;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
|
||||
import org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.Utilities.DecimalStatus;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities.VersionURLInfo;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
|
||||
import org.hl7.fhir.utilities.validation.ValidationOptions;
|
||||
import org.hl7.fhir.utilities.xhtml.NodeType;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
import org.hl7.fhir.validation.BaseValidator;
|
||||
import org.hl7.fhir.validation.Validator.QuestionnaireMode;
|
||||
import org.hl7.fhir.validation.instance.type.BundleValidator;
|
||||
|
@ -148,19 +155,13 @@ import org.hl7.fhir.validation.instance.type.QuestionnaireValidator;
|
|||
import org.hl7.fhir.validation.instance.type.SearchParameterValidator;
|
||||
import org.hl7.fhir.validation.instance.type.StructureDefinitionValidator;
|
||||
import org.hl7.fhir.validation.instance.type.ValueSetValidator;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.Utilities.DecimalStatus;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities.VersionURLInfo;
|
||||
import org.hl7.fhir.utilities.validation.ValidationOptions;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
|
||||
import org.hl7.fhir.utilities.xhtml.NodeType;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
import org.hl7.fhir.validation.instance.utils.*;
|
||||
import org.hl7.fhir.validation.instance.utils.ChildIterator;
|
||||
import org.hl7.fhir.validation.instance.utils.ElementInfo;
|
||||
import org.hl7.fhir.validation.instance.utils.IndexedElement;
|
||||
import org.hl7.fhir.validation.instance.utils.NodeStack;
|
||||
import org.hl7.fhir.validation.instance.utils.ResolvedReference;
|
||||
import org.hl7.fhir.validation.instance.utils.ResourceValidationTracker;
|
||||
import org.hl7.fhir.validation.instance.utils.ValidatorHostContext;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
@ -343,6 +344,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
private String validationLanguage;
|
||||
private boolean baseOnly;
|
||||
private boolean noCheckAggregation;
|
||||
private boolean wantCheckSnapshotUnchanged;
|
||||
|
||||
private List<ImplementationGuide> igs = new ArrayList<>();
|
||||
private List<String> extensionDomains = new ArrayList<String>();
|
||||
|
@ -1004,7 +1006,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
ValidationResult vr = checkCodeOnServer(stack, valueset, cc, true); // we're going to validate the codings directly, so only check the valueset
|
||||
if (!vr.isOk()) {
|
||||
bindingsOk = false;
|
||||
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) {
|
||||
if (vr.getErrorClass() != null && vr.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) {
|
||||
if (binding.getStrength() == BindingStrength.REQUIRED || (binding.getStrength() == BindingStrength.EXTENSIBLE && binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))) {
|
||||
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOSVC_BOUND_REQ, describeReference(binding.getValueSet()));
|
||||
} else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
|
||||
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOSVC_BOUND_EXT, describeReference(binding.getValueSet()));
|
||||
}
|
||||
} else 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, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
|
||||
else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
|
||||
|
@ -3860,7 +3868,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
} else if (element.getType().equals("SearchParameter")) {
|
||||
new SearchParameterValidator(context, timeTracker, fpe).validateSearchParameter(errors, element, stack);
|
||||
} else if (element.getType().equals("StructureDefinition")) {
|
||||
new StructureDefinitionValidator(context, timeTracker, fpe).validateStructureDefinition(errors, element, stack);
|
||||
new StructureDefinitionValidator(context, timeTracker, fpe, wantCheckSnapshotUnchanged).validateStructureDefinition(errors, element, stack);
|
||||
} else if (element.getType().equals("ValueSet")) {
|
||||
new ValueSetValidator(context, timeTracker, this).validateValueSet(errors, element, stack);
|
||||
}
|
||||
|
@ -4128,236 +4136,252 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
Element resource, Element element, String actualType, NodeStack stack, boolean inCodeableConcept, boolean checkDisplayInContext, ElementInfo ei, String extensionUrl)
|
||||
throws FHIRException, DefinitionException {
|
||||
|
||||
List<String> profiles = new ArrayList<String>();
|
||||
if (ei.definition != null) {
|
||||
String type = null;
|
||||
ElementDefinition typeDefn = null;
|
||||
checkMustSupport(profile, ei);
|
||||
checkChildByDefinition(hostContext, errors, profile, definition, resource, element, actualType, stack, inCodeableConcept, checkDisplayInContext, ei,
|
||||
extensionUrl, ei.definition, false);
|
||||
}
|
||||
if (ei.slice != null) {
|
||||
checkChildByDefinition(hostContext, errors, profile, definition, resource, element, actualType, stack, inCodeableConcept, checkDisplayInContext, ei,
|
||||
extensionUrl, ei.slice, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (ei.definition.getType().size() == 1 && !"*".equals(ei.definition.getType().get(0).getWorkingCode()) && !"Element".equals(ei.definition.getType().get(0).getWorkingCode())
|
||||
&& !"BackboneElement".equals(ei.definition.getType().get(0).getWorkingCode())) {
|
||||
type = ei.definition.getType().get(0).getWorkingCode();
|
||||
String stype = ei.getElement().fhirType();
|
||||
if (ei.definition.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 (ei.definition.getType().get(0).hasProfile()) {
|
||||
for (CanonicalType p : ei.definition.getType().get(0).getProfile()) {
|
||||
profiles.add(p.getValue());
|
||||
}
|
||||
}
|
||||
} else if (ei.definition.getType().size() == 1 && "*".equals(ei.definition.getType().get(0).getWorkingCode())) {
|
||||
String prefix = tail(ei.definition.getPath());
|
||||
assert prefix.endsWith("[x]");
|
||||
type = ei.getName().substring(prefix.length() - 3);
|
||||
if (isPrimitiveType(type))
|
||||
type = Utilities.uncapitalize(type);
|
||||
if (ei.definition.getType().get(0).hasProfile()) {
|
||||
for (CanonicalType p : ei.definition.getType().get(0).getProfile()) {
|
||||
profiles.add(p.getValue());
|
||||
}
|
||||
}
|
||||
} else if (ei.definition.getType().size() > 1) {
|
||||
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);
|
||||
|
||||
String prefix = tail(ei.definition.getPath());
|
||||
assert typesAreAllReference(ei.definition.getType()) || ei.definition.hasRepresentation(PropertyRepresentation.TYPEATTR) || prefix.endsWith("[x]") : prefix;
|
||||
|
||||
if (ei.definition.hasRepresentation(PropertyRepresentation.TYPEATTR))
|
||||
type = ei.getElement().getType();
|
||||
else {
|
||||
prefix = prefix.substring(0, prefix.length() - 3);
|
||||
for (TypeRefComponent t : ei.definition.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 = ei.definition.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(ei.definition.getType()));
|
||||
}
|
||||
} else if (ei.definition.getContentReference() != null) {
|
||||
typeDefn = resolveNameReference(profile.getSnapshot(), ei.definition.getContentReference());
|
||||
|
||||
} else if (ei.definition.getType().size() == 1 && ("Element".equals(ei.definition.getType().get(0).getWorkingCode()) || "BackboneElement".equals(ei.definition.getType().get(0).getWorkingCode()))) {
|
||||
if (ei.definition.getType().get(0).hasProfile()) {
|
||||
CanonicalType pu = ei.definition.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 (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);
|
||||
}
|
||||
}
|
||||
|
||||
if (type != null) {
|
||||
if (type.startsWith("@")) {
|
||||
ei.definition = findElement(profile, type.substring(1));
|
||||
type = null;
|
||||
//
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
NodeStack localStack = stack.push(ei.getElement(), ei.count, ei.definition, type == null ? typeDefn : resolveType(type, ei.definition.getType()));
|
||||
} 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]") : prefix;
|
||||
|
||||
if (checkDefn.hasRepresentation(PropertyRepresentation.TYPEATTR))
|
||||
type = ei.getElement().getType();
|
||||
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(), 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 localStackLiterapPath = localStack.getLiteralPath();
|
||||
String eiPath = ei.getPath();
|
||||
assert (eiPath.equals(localStackLiterapPath)) : "ei.path: " + ei.getPath() + " - localStack.getLiteralPath: " + localStackLiterapPath;
|
||||
boolean thisIsCodeableConcept = false;
|
||||
String thisExtension = null;
|
||||
boolean checkDisplay = true;
|
||||
String localStackLiterapPath = localStack.getLiteralPath();
|
||||
String eiPath = ei.getPath();
|
||||
assert (eiPath.equals(localStackLiterapPath)) : "ei.path: " + ei.getPath() + " - localStack.getLiteralPath: " + localStackLiterapPath;
|
||||
boolean thisIsCodeableConcept = false;
|
||||
String thisExtension = null;
|
||||
boolean checkDisplay = true;
|
||||
|
||||
checkInvariants(hostContext, errors, profile, typeDefn != null ? typeDefn : ei.definition, resource, ei.getElement(), localStack, true);
|
||||
checkInvariants(hostContext, errors, profile, typeDefn != null ? typeDefn : checkDefn, resource, ei.getElement(), localStack, true);
|
||||
|
||||
ei.getElement().markValidation(profile, ei.definition);
|
||||
boolean elementValidated = false;
|
||||
if (type != null) {
|
||||
if (isPrimitiveType(type)) {
|
||||
checkPrimitive(hostContext, errors, ei.getPath(), type, ei.definition, ei.getElement(), profile, stack);
|
||||
} else {
|
||||
if (ei.definition.hasFixed()) {
|
||||
checkFixedValue(errors, ei.getPath(), ei.getElement(), ei.definition.getFixed(), profile.getUrl(), ei.definition.getSliceName(), null);
|
||||
}
|
||||
if (ei.definition.hasPattern()) {
|
||||
checkFixedValue(errors, ei.getPath(), ei.getElement(), ei.definition.getPattern(), profile.getUrl(), ei.definition.getSliceName(), null, true);
|
||||
}
|
||||
}
|
||||
if (type.equals("Identifier")) {
|
||||
checkIdentifier(errors, ei.getPath(), ei.getElement(), ei.definition);
|
||||
} else if (type.equals("Coding")) {
|
||||
checkCoding(errors, ei.getPath(), ei.getElement(), profile, ei.definition, inCodeableConcept, checkDisplayInContext, stack);
|
||||
} else if (type.equals("Quantity")) {
|
||||
checkQuantity(errors, ei.getPath(), ei.getElement(), profile, ei.definition, stack);
|
||||
} else if (type.equals("Attachment")) {
|
||||
checkAttachment(errors, ei.getPath(), ei.getElement(), profile, ei.definition, inCodeableConcept, checkDisplayInContext, stack);
|
||||
} else if (type.equals("CodeableConcept")) {
|
||||
checkDisplay = checkCodeableConcept(errors, ei.getPath(), ei.getElement(), profile, ei.definition, stack);
|
||||
thisIsCodeableConcept = true;
|
||||
} else if (type.equals("Reference")) {
|
||||
checkReference(hostContext, errors, ei.getPath(), ei.getElement(), profile, ei.definition, 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(), ei.definition, profile, localStack, stack, extensionUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (type.equals("Resource") || isResource(type)) {
|
||||
validateContains(hostContext, errors, ei.getPath(), ei.definition, definition, resource, ei.getElement(), localStack, idStatusForEntry(element, ei)); // if
|
||||
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, ei.definition, stack, defn);
|
||||
thisIsCodeableConcept = true;
|
||||
} else if (txtype.contains("Coding")) {
|
||||
checkTerminologyCoding(errors, ei.getPath(), ei.getElement(), profile, ei.definition, inCodeableConcept, checkDisplayInContext, stack, defn);
|
||||
}
|
||||
}
|
||||
}
|
||||
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 (rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), stack.getLiteralPath(), ei.definition != null, I18nConstants.VALIDATION_VAL_CONTENT_UNKNOWN, ei.getName()))
|
||||
validateElement(hostContext, errors, profile, ei.definition, 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, ei.definition.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);
|
||||
if (checkDefn.hasFixed()) {
|
||||
checkFixedValue(errors, ei.getPath(), ei.getElement(), checkDefn.getFixed(), profile.getUrl(), checkDefn.getSliceName(), null);
|
||||
}
|
||||
} else if (profiles.size() == 1) {
|
||||
String url = profiles.get(0);
|
||||
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
|
||||
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, 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, ei.definition, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension);
|
||||
if (hasErrors(profileErrors))
|
||||
badProfiles.put(typeProfile, profileErrors);
|
||||
else
|
||||
goodProfiles.put(typeProfile, profileErrors);
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
} 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 (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, ei.definition, ei.getElement(), ei.getElement(), type, localStack.resetIds(), thisIsCodeableConcept, checkDisplay, thisExtension);
|
||||
else
|
||||
validateElement(hostContext, errors, p, getElementByTail(p, tail), profile, ei.definition, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension);
|
||||
}
|
||||
int index = profile.getSnapshot().getElement().indexOf(ei.definition);
|
||||
if (index < profile.getSnapshot().getElement().size() - 1) {
|
||||
String nextPath = profile.getSnapshot().getElement().get(index + 1).getPath();
|
||||
if (!nextPath.equals(ei.definition.getPath()) && nextPath.startsWith(ei.definition.getPath()))
|
||||
validateElement(hostContext, errors, profile, ei.definition, null, null, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5091,4 +5115,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return questionnaireMode;
|
||||
}
|
||||
|
||||
public boolean isWantCheckSnapshotUnchanged() {
|
||||
return wantCheckSnapshotUnchanged;
|
||||
}
|
||||
|
||||
public void setWantCheckSnapshotUnchanged(boolean wantCheckSnapshotUnchanged) {
|
||||
this.wantCheckSnapshotUnchanged = wantCheckSnapshotUnchanged;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue