Extension domains configuration for the fhr instance validator (#917)
* Fix the url of the StructureDefinition extensions http://hl7.org/fhir/tools/StructureDefinition/ -> http://hl7.org/fhir/StructureDefinition/ That makes the entry for the structuredefinition-expression superfluous. The url behind IG_DEPENDSON_PACKAGE_EXTENSION does not point is not (yet?) valid too. * Add ability to configure custom extension domains. * Testing the extension domains configuration * Fix obvious bug when determining resource name The for loop was completely superfluous beforehand. Either fix it as e.g. in this patch or remove it. * small improvements and TODO's for possible NPE's - javadoc see - use diamond operator for generics - remove throws clause when exception is not thrown - add TODO's for some cases a NPE might occur. My knowledge of the context is not sufficient to suggest the proper way to solve this.
This commit is contained in:
parent
1afe36e60a
commit
89ede0e524
|
@ -60,6 +60,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
private IValidationSupport myValidationSupport;
|
private IValidationSupport myValidationSupport;
|
||||||
private boolean noTerminologyChecks = false;
|
private boolean noTerminologyChecks = false;
|
||||||
private volatile WorkerContextWrapper myWrappedWorkerContext;
|
private volatile WorkerContextWrapper myWrappedWorkerContext;
|
||||||
|
private List<String> extensionDomains = Collections.emptyList();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -81,18 +82,52 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
myValidationSupport = theValidationSupport;
|
myValidationSupport = theValidationSupport;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String determineResourceName(Document theDocument) {
|
/**
|
||||||
Element root = null;
|
* Every element in a resource or data type includes an optional <it>extension</it> child element
|
||||||
|
* which is identified by it's {@code url attribute}. There exists a number of predefined
|
||||||
|
* extension urls or extension domains:<ul>
|
||||||
|
* <li>any url which contains {@code example.org}, {@code nema.org}, or {@code acme.com}.</li>
|
||||||
|
* <li>any url which starts with {@code http://hl7.org/fhir/StructureDefinition/}.</li>
|
||||||
|
* </ul>
|
||||||
|
* It is possible to extend this list of known extension by defining custom extensions:
|
||||||
|
* Any url which starts which one of the elements in the list of custom extension domains is
|
||||||
|
* considered as known.
|
||||||
|
* <p>
|
||||||
|
* Any unknown extension domain will result in an information message when validating a resource.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public FhirInstanceValidator setCustomExtensionDomains(List<String> extensionDomains) {
|
||||||
|
this.extensionDomains = extensionDomains;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every element in a resource or data type includes an optional <it>extension</it> child element
|
||||||
|
* which is identified by it's {@code url attribute}. There exists a number of predefined
|
||||||
|
* extension urls or extension domains:<ul>
|
||||||
|
* <li>any url which contains {@code example.org}, {@code nema.org}, or {@code acme.com}.</li>
|
||||||
|
* <li>any url which starts with {@code http://hl7.org/fhir/StructureDefinition/}.</li>
|
||||||
|
* </ul>
|
||||||
|
* It is possible to extend this list of known extension by defining custom extensions:
|
||||||
|
* Any url which starts which one of the elements in the list of custom extension domains is
|
||||||
|
* considered as known.
|
||||||
|
* <p>
|
||||||
|
* Any unknown extension domain will result in an information message when validating a resource.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public FhirInstanceValidator setCustomExtensionDomains(String... extensionDomains) {
|
||||||
|
this.extensionDomains = Arrays.asList(extensionDomains);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String determineResourceName(Document theDocument) {
|
||||||
NodeList list = theDocument.getChildNodes();
|
NodeList list = theDocument.getChildNodes();
|
||||||
for (int i = 0; i < list.getLength(); i++) {
|
for (int i = 0; i < list.getLength(); i++) {
|
||||||
if (list.item(i) instanceof Element) {
|
if (list.item(i) instanceof Element) {
|
||||||
root = (Element) list.item(i);
|
return list.item(i).getLocalName();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
root = theDocument.getDocumentElement();
|
return theDocument.getDocumentElement().getLocalName();
|
||||||
return root.getLocalName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayList<String> determineIfProfilesSpecified(Document theDocument) {
|
private ArrayList<String> determineIfProfilesSpecified(Document theDocument) {
|
||||||
|
@ -138,7 +173,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
* guielines will be ignored.
|
* guielines will be ignored.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @see {@link #setBestPracticeWarningLevel(BestPracticeWarningLevel)}
|
* @see #setBestPracticeWarningLevel(BestPracticeWarningLevel)
|
||||||
*/
|
*/
|
||||||
public BestPracticeWarningLevel getBestPracticeWarningLevel() {
|
public BestPracticeWarningLevel getBestPracticeWarningLevel() {
|
||||||
return myBestPracticeWarningLevel;
|
return myBestPracticeWarningLevel;
|
||||||
|
@ -235,6 +270,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
v.setAnyExtensionsAllowed(isAnyExtensionsAllowed());
|
v.setAnyExtensionsAllowed(isAnyExtensionsAllowed());
|
||||||
v.setResourceIdRule(IdStatus.OPTIONAL);
|
v.setResourceIdRule(IdStatus.OPTIONAL);
|
||||||
v.setNoTerminologyChecks(isNoTerminologyChecks());
|
v.setNoTerminologyChecks(isNoTerminologyChecks());
|
||||||
|
v.addExtensionDomains(extensionDomains);
|
||||||
|
|
||||||
List<ValidationMessage> messages = new ArrayList<>();
|
List<ValidationMessage> messages = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -343,7 +379,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
private LoadingCache<ResourceKey, org.hl7.fhir.r4.model.Resource> myFetchResourceCache;
|
private LoadingCache<ResourceKey, org.hl7.fhir.r4.model.Resource> myFetchResourceCache;
|
||||||
private org.hl7.fhir.r4.model.Parameters myExpansionProfile;
|
private org.hl7.fhir.r4.model.Parameters myExpansionProfile;
|
||||||
|
|
||||||
public WorkerContextWrapper(HapiWorkerContext theWorkerContext) {
|
WorkerContextWrapper(HapiWorkerContext theWorkerContext) {
|
||||||
myWrap = theWorkerContext;
|
myWrap = theWorkerContext;
|
||||||
myConverter = new VersionConvertor_30_40();
|
myConverter = new VersionConvertor_30_40();
|
||||||
|
|
||||||
|
@ -424,7 +460,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cacheResource(org.hl7.fhir.r4.model.Resource res) throws FHIRException {
|
public void cacheResource(org.hl7.fhir.r4.model.Resource res) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,7 +482,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSetExpander.ValueSetExpansionOutcome expandVS(org.hl7.fhir.r4.model.ValueSet source, boolean cacheOk, boolean heiarchical) {
|
public ValueSetExpander.ValueSetExpansionOutcome expandVS(org.hl7.fhir.r4.model.ValueSet source, boolean cacheOk, boolean heiarchical) {
|
||||||
ValueSet convertedSource = null;
|
ValueSet convertedSource;
|
||||||
try {
|
try {
|
||||||
convertedSource = VersionConvertor_30_40.convertValueSet(source);
|
convertedSource = VersionConvertor_30_40.convertValueSet(source);
|
||||||
} catch (FHIRException e) {
|
} catch (FHIRException e) {
|
||||||
|
@ -470,7 +506,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSetExpander.ValueSetExpansionOutcome expandVS(org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent binding, boolean cacheOk, boolean heiarchical) throws FHIRException {
|
public ValueSetExpander.ValueSetExpansionOutcome expandVS(org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent binding, boolean cacheOk, boolean heiarchical) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,7 +673,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IResourceValidator newValidator() throws FHIRException {
|
public IResourceValidator newValidator() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -662,7 +698,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsSystem(String system) throws TerminologyServiceException {
|
public boolean supportsSystem(String system) {
|
||||||
return myWrap.supportsSystem(system);
|
return myWrap.supportsSystem(system);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -679,6 +715,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
@Override
|
@Override
|
||||||
public ValidationResult validateCode(String system, String code, String display) {
|
public ValidationResult validateCode(String system, String code, String display) {
|
||||||
org.hl7.fhir.dstu3.context.IWorkerContext.ValidationResult result = myWrap.validateCode(system, code, display);
|
org.hl7.fhir.dstu3.context.IWorkerContext.ValidationResult result = myWrap.validateCode(system, code, display);
|
||||||
|
// TODO: converted code might be null -> NPE
|
||||||
return convertValidationResult(result);
|
return convertValidationResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -729,6 +766,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
throw new InternalErrorException(e);
|
throw new InternalErrorException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: converted code might be null -> NPE
|
||||||
org.hl7.fhir.dstu3.context.IWorkerContext.ValidationResult result = myWrap.validateCode(convertedCode, convertedVs);
|
org.hl7.fhir.dstu3.context.IWorkerContext.ValidationResult result = myWrap.validateCode(convertedCode, convertedVs);
|
||||||
return convertValidationResult(result);
|
return convertValidationResult(result);
|
||||||
}
|
}
|
||||||
|
@ -749,6 +787,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
throw new InternalErrorException(e);
|
throw new InternalErrorException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: converted code might be null -> NPE
|
||||||
org.hl7.fhir.dstu3.context.IWorkerContext.ValidationResult result = myWrap.validateCode(convertedCode, convertedVs);
|
org.hl7.fhir.dstu3.context.IWorkerContext.ValidationResult result = myWrap.validateCode(convertedCode, convertedVs);
|
||||||
return convertValidationResult(result);
|
return convertValidationResult(result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -45,6 +46,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
private DocumentBuilderFactory myDocBuilderFactory;
|
private DocumentBuilderFactory myDocBuilderFactory;
|
||||||
private boolean myNoTerminologyChecks;
|
private boolean myNoTerminologyChecks;
|
||||||
private StructureDefinition myStructureDefintion;
|
private StructureDefinition myStructureDefintion;
|
||||||
|
private List<String> extensionDomains = Collections.emptyList();
|
||||||
|
|
||||||
private IValidationSupport myValidationSupport;
|
private IValidationSupport myValidationSupport;
|
||||||
|
|
||||||
|
@ -68,18 +70,52 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
myValidationSupport = theValidationSupport;
|
myValidationSupport = theValidationSupport;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String determineResourceName(Document theDocument) {
|
/**
|
||||||
Element root = null;
|
* Every element in a resource or data type includes an optional <it>extension</it> child element
|
||||||
|
* which is identified by it's {@code url attribute}. There exists a number of predefined
|
||||||
|
* extension urls or extension domains:<ul>
|
||||||
|
* <li>any url which contains {@code example.org}, {@code nema.org}, or {@code acme.com}.</li>
|
||||||
|
* <li>any url which starts with {@code http://hl7.org/fhir/StructureDefinition/}.</li>
|
||||||
|
* </ul>
|
||||||
|
* It is possible to extend this list of known extension by defining custom extensions:
|
||||||
|
* Any url which starts which one of the elements in the list of custom extension domains is
|
||||||
|
* considered as known.
|
||||||
|
* <p>
|
||||||
|
* Any unknown extension domain will result in an information message when validating a resource.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public FhirInstanceValidator setCustomExtensionDomains(List<String> extensionDomains) {
|
||||||
|
this.extensionDomains = extensionDomains;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every element in a resource or data type includes an optional <it>extension</it> child element
|
||||||
|
* which is identified by it's {@code url attribute}. There exists a number of predefined
|
||||||
|
* extension urls or extension domains:<ul>
|
||||||
|
* <li>any url which contains {@code example.org}, {@code nema.org}, or {@code acme.com}.</li>
|
||||||
|
* <li>any url which starts with {@code http://hl7.org/fhir/StructureDefinition/}.</li>
|
||||||
|
* </ul>
|
||||||
|
* It is possible to extend this list of known extension by defining custom extensions:
|
||||||
|
* Any url which starts which one of the elements in the list of custom extension domains is
|
||||||
|
* considered as known.
|
||||||
|
* <p>
|
||||||
|
* Any unknown extension domain will result in an information message when validating a resource.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public FhirInstanceValidator setCustomExtensionDomains(String... extensionDomains) {
|
||||||
|
this.extensionDomains = Arrays.asList(extensionDomains);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String determineResourceName(Document theDocument) {
|
||||||
NodeList list = theDocument.getChildNodes();
|
NodeList list = theDocument.getChildNodes();
|
||||||
for (int i = 0; i < list.getLength(); i++) {
|
for (int i = 0; i < list.getLength(); i++) {
|
||||||
if (list.item(i) instanceof Element) {
|
if (list.item(i) instanceof Element) {
|
||||||
root = (Element) list.item(i);
|
return list.item(i).getLocalName();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
root = theDocument.getDocumentElement();
|
return theDocument.getDocumentElement().getLocalName();
|
||||||
return root.getLocalName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayList<String> determineIfProfilesSpecified(Document theDocument) {
|
private ArrayList<String> determineIfProfilesSpecified(Document theDocument) {
|
||||||
|
@ -120,8 +156,8 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
* reported at the ERROR level. If this setting is set to {@link BestPracticeWarningLevel#Ignore}, best practice
|
* reported at the ERROR level. If this setting is set to {@link BestPracticeWarningLevel#Ignore}, best practice
|
||||||
* guielines will be ignored.
|
* guielines will be ignored.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @see {@link #setBestPracticeWarningLevel(BestPracticeWarningLevel)}
|
* @see #setBestPracticeWarningLevel(BestPracticeWarningLevel)
|
||||||
*/
|
*/
|
||||||
public BestPracticeWarningLevel getBestPracticeWarningLevel() {
|
public BestPracticeWarningLevel getBestPracticeWarningLevel() {
|
||||||
return myBestPracticeWarningLevel;
|
return myBestPracticeWarningLevel;
|
||||||
|
@ -211,8 +247,9 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
v.setAnyExtensionsAllowed(isAnyExtensionsAllowed());
|
v.setAnyExtensionsAllowed(isAnyExtensionsAllowed());
|
||||||
v.setResourceIdRule(IdStatus.OPTIONAL);
|
v.setResourceIdRule(IdStatus.OPTIONAL);
|
||||||
v.setNoTerminologyChecks(isNoTerminologyChecks());
|
v.setNoTerminologyChecks(isNoTerminologyChecks());
|
||||||
|
v.addExtensionDomains(extensionDomains);
|
||||||
|
|
||||||
List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
List<ValidationMessage> messages = new ArrayList<>();
|
||||||
|
|
||||||
if (theEncoding == EncodingEnum.XML) {
|
if (theEncoding == EncodingEnum.XML) {
|
||||||
Document document;
|
Document document;
|
||||||
|
@ -312,7 +349,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
public static class NullEvaluationContext implements IEvaluationContext {
|
public static class NullEvaluationContext implements IEvaluationContext {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TypeDetails checkFunction(Object theAppContext, String theFunctionName, List<TypeDetails> theParameters) throws PathEngineException {
|
public TypeDetails checkFunction(Object theAppContext, String theFunctionName, List<TypeDetails> theParameters) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,12 +364,12 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Base resolveConstant(Object theAppContext, String theName) throws PathEngineException {
|
public Base resolveConstant(Object theAppContext, String theName) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TypeDetails resolveConstantType(Object theAppContext, String theName) throws PathEngineException {
|
public TypeDetails resolveConstantType(Object theAppContext, String theName) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -416,8 +416,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean allowUnknownExtension(String url) {
|
private boolean allowUnknownExtension(String url) {
|
||||||
if (url.contains("example.org") || url.contains("acme.com") || url.contains("nema.org") || url.startsWith("http://hl7.org/fhir/tools/StructureDefinition/") || url.equals("http://hl7.org/fhir/StructureDefinition/structuredefinition-expression"))
|
if (isPredefinedExtension(url))
|
||||||
// Added structuredefinition-expression explicitly because it wasn't defined in the version of the spec it needs to be used with
|
|
||||||
return true;
|
return true;
|
||||||
for (String s : extensionDomains)
|
for (String s : extensionDomains)
|
||||||
if (url.startsWith(s))
|
if (url.startsWith(s))
|
||||||
|
@ -426,8 +425,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isKnownExtension(String url) {
|
private boolean isKnownExtension(String url) {
|
||||||
// Added structuredefinition-expression and following extensions explicitly because they weren't defined in the version of the spec they need to be used with
|
if (isPredefinedExtension(url))
|
||||||
if (url.contains("example.org") || url.contains("acme.com") || url.contains("nema.org") || url.startsWith("http://hl7.org/fhir/tools/StructureDefinition/") || url.equals("http://hl7.org/fhir/StructureDefinition/structuredefinition-expression") || url.equals(VersionConvertorConstants.IG_DEPENDSON_PACKAGE_EXTENSION))
|
|
||||||
return true;
|
return true;
|
||||||
for (String s : extensionDomains)
|
for (String s : extensionDomains)
|
||||||
if (url.startsWith(s))
|
if (url.startsWith(s))
|
||||||
|
@ -435,6 +433,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isPredefinedExtension(String url) {
|
||||||
|
return url.contains("example.org")
|
||||||
|
|| url.contains("acme.com")
|
||||||
|
|| url.contains("nema.org")
|
||||||
|
|| url.startsWith("http://hl7.org/fhir/StructureDefinition/")
|
||||||
|
|| url.equals(VersionConvertorConstants.IG_DEPENDSON_PACKAGE_EXTENSION);
|
||||||
|
}
|
||||||
|
|
||||||
private void bpCheck(List<ValidationMessage> errors, IssueType invalid, int line, int col, String literalPath, boolean test, String message) {
|
private void bpCheck(List<ValidationMessage> errors, IssueType invalid, int line, int col, String literalPath, boolean test, String message) {
|
||||||
if (bpWarnings != null) {
|
if (bpWarnings != null) {
|
||||||
switch (bpWarnings) {
|
switch (bpWarnings) {
|
||||||
|
@ -1950,6 +1956,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
return extensionDomains;
|
return extensionDomains;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public InstanceValidator addExtensionDomains(List<String> extensionDomains) {
|
||||||
|
this.extensionDomains.addAll(extensionDomains);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
private Element getFromBundle(Element bundle, String ref, String fullUrl, List<ValidationMessage> errors, String path) {
|
private Element getFromBundle(Element bundle, String ref, String fullUrl, List<ValidationMessage> errors, String path) {
|
||||||
String targetUrl = null;
|
String targetUrl = null;
|
||||||
String version = "";
|
String version = "";
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
package org.hl7.fhir.dstu3.hapi.validation;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import ca.uhn.fhir.validation.FhirValidator;
|
||||||
|
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||||
|
import ca.uhn.fhir.validation.ValidationResult;
|
||||||
|
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
||||||
|
import org.hl7.fhir.dstu3.model.CodeableConcept;
|
||||||
|
import org.hl7.fhir.dstu3.model.Coding;
|
||||||
|
import org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus;
|
||||||
|
import org.hl7.fhir.dstu3.model.Questionnaire;
|
||||||
|
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
public class QuestionnaireValidatorDstu3Test {
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(QuestionnaireValidatorDstu3Test.class);
|
||||||
|
private static DefaultProfileValidationSupport myDefaultValidationSupport = new DefaultProfileValidationSupport();
|
||||||
|
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||||
|
private FhirInstanceValidator myInstanceVal;
|
||||||
|
private FhirValidator myVal;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
IValidationSupport myValSupport = mock(IValidationSupport.class);
|
||||||
|
|
||||||
|
myVal = ourCtx.newValidator();
|
||||||
|
myVal.setValidateAgainstStandardSchema(false);
|
||||||
|
myVal.setValidateAgainstStandardSchematron(false);
|
||||||
|
|
||||||
|
ValidationSupportChain validationSupport = new ValidationSupportChain(myValSupport, myDefaultValidationSupport);
|
||||||
|
myInstanceVal = new FhirInstanceValidator(validationSupport);
|
||||||
|
|
||||||
|
myVal.registerValidatorModule(myInstanceVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQuestionnaireWithPredefinedExtensionDomainsForCoding() {
|
||||||
|
String[] extensionDomainsToTest = new String[] {
|
||||||
|
"http://example.org/questionnaire-color-control-1",
|
||||||
|
"https://example.org/questionnaire-color-control-2",
|
||||||
|
"http://acme.com/questionnaire-color-control-3",
|
||||||
|
"https://acme.com/questionnaire-color-control-4",
|
||||||
|
"http://nema.org/questionnaire-color-control-5",
|
||||||
|
"https://nema.org/questionnaire-color-control-6",
|
||||||
|
"http://hl7.org/fhir/StructureDefinition/questionnaire-scoreItem",
|
||||||
|
"http://hl7.org/fhir/StructureDefinition/structuredefinition-expression",
|
||||||
|
};
|
||||||
|
for (String extensionDomainToTest : extensionDomainsToTest) {
|
||||||
|
Questionnaire q = new Questionnaire();
|
||||||
|
q.setStatus(PublicationStatus.ACTIVE)
|
||||||
|
.addItem()
|
||||||
|
.setLinkId("link0")
|
||||||
|
.setType(QuestionnaireItemType.STRING)
|
||||||
|
.addExtension()
|
||||||
|
.setUrl(extensionDomainToTest)
|
||||||
|
.setValue(new Coding(null, "text-box", null));
|
||||||
|
|
||||||
|
ValidationResult errors = myVal.validateWithResult(q);
|
||||||
|
ourLog.info(errors.toString());
|
||||||
|
assertThat(errors.isSuccessful(), Matchers.is(true));
|
||||||
|
assertThat(errors.getMessages(), Matchers.empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQuestionnaireWithPredefinedExtensionDomainsForCodeableConcept() {
|
||||||
|
String[] extensionDomainsToTest = new String[] {
|
||||||
|
"http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl",
|
||||||
|
};
|
||||||
|
for (String extensionDomainToTest : extensionDomainsToTest) {
|
||||||
|
Questionnaire q = new Questionnaire();
|
||||||
|
q.setStatus(PublicationStatus.ACTIVE)
|
||||||
|
.addItem()
|
||||||
|
.setLinkId("link0")
|
||||||
|
.setType(QuestionnaireItemType.STRING)
|
||||||
|
.addExtension()
|
||||||
|
.setUrl(extensionDomainToTest)
|
||||||
|
.setValue(new CodeableConcept().addCoding(new Coding(null, "text-box", null)));
|
||||||
|
|
||||||
|
ValidationResult errors = myVal.validateWithResult(q);
|
||||||
|
ourLog.info(errors.toString());
|
||||||
|
assertThat(errors.isSuccessful(), Matchers.is(true));
|
||||||
|
assertThat(errors.getMessages(), Matchers.empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQuestionnaireWithCustomExtensionDomain() {
|
||||||
|
Questionnaire q = new Questionnaire();
|
||||||
|
String extensionUrl = "http://my.own.domain/StructureDefinition/";
|
||||||
|
q.setStatus(PublicationStatus.ACTIVE)
|
||||||
|
.addItem()
|
||||||
|
.setLinkId("link0")
|
||||||
|
.setType(QuestionnaireItemType.STRING)
|
||||||
|
.addExtension()
|
||||||
|
.setUrl(extensionUrl + "questionnaire-itemControl")
|
||||||
|
.setValue(new Coding(null, "text-box", null));
|
||||||
|
|
||||||
|
ValidationResult errors = myVal.validateWithResult(q);
|
||||||
|
|
||||||
|
ourLog.info(errors.toString());
|
||||||
|
assertThat(errors.isSuccessful(), Matchers.is(true));
|
||||||
|
assertThat(errors.getMessages(), Matchers.hasSize(1));
|
||||||
|
assertEquals(errors.getMessages().get(0).getSeverity(), ResultSeverityEnum.INFORMATION);
|
||||||
|
assertThat(errors.getMessages().get(0).getMessage(), Matchers.startsWith("Unknown extension " + extensionUrl));
|
||||||
|
|
||||||
|
myInstanceVal.setCustomExtensionDomains(Collections.singletonList(extensionUrl));
|
||||||
|
errors = myVal.validateWithResult(q);
|
||||||
|
|
||||||
|
ourLog.info(errors.toString());
|
||||||
|
assertThat(errors.isSuccessful(), Matchers.is(true));
|
||||||
|
assertThat(errors.getMessages(), Matchers.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() {
|
||||||
|
myDefaultValidationSupport.flush();
|
||||||
|
myDefaultValidationSupport = null;
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,145 @@
|
||||||
|
package org.hl7.fhir.r4.validation;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import ca.uhn.fhir.validation.FhirValidator;
|
||||||
|
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||||
|
import ca.uhn.fhir.validation.ValidationResult;
|
||||||
|
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
|
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
|
||||||
|
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||||
|
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
||||||
|
import org.hl7.fhir.r4.hapi.validation.ValidationSupportChain;
|
||||||
|
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||||
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
|
import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
|
||||||
|
import org.hl7.fhir.r4.model.Narrative;
|
||||||
|
import org.hl7.fhir.r4.model.Narrative.NarrativeStatus;
|
||||||
|
import org.hl7.fhir.r4.model.Questionnaire;
|
||||||
|
import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemType;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
public class QuestionnaireValidatorR4Test {
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(QuestionnaireValidatorR4Test.class);
|
||||||
|
private static DefaultProfileValidationSupport myDefaultValidationSupport = new DefaultProfileValidationSupport();
|
||||||
|
private static FhirContext ourCtx = FhirContext.forR4();
|
||||||
|
private FhirInstanceValidator myInstanceVal;
|
||||||
|
private FhirValidator myVal;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
IValidationSupport myValSupport = mock(IValidationSupport.class);
|
||||||
|
|
||||||
|
myVal = ourCtx.newValidator();
|
||||||
|
myVal.setValidateAgainstStandardSchema(false);
|
||||||
|
myVal.setValidateAgainstStandardSchematron(false);
|
||||||
|
|
||||||
|
ValidationSupportChain validationSupport = new ValidationSupportChain(myValSupport, myDefaultValidationSupport);
|
||||||
|
myInstanceVal = new FhirInstanceValidator(validationSupport);
|
||||||
|
|
||||||
|
myVal.registerValidatorModule(myInstanceVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQuestionnaireWithPredefinedExtensionDomains() {
|
||||||
|
String[] extensionDomainsToTest = new String[] {
|
||||||
|
"http://example.org/questionnaire-color-control-1",
|
||||||
|
"https://example.org/questionnaire-color-control-2",
|
||||||
|
"http://acme.com/questionnaire-color-control-3",
|
||||||
|
"https://acme.com/questionnaire-color-control-4",
|
||||||
|
"http://nema.org/questionnaire-color-control-5",
|
||||||
|
"https://nema.org/questionnaire-color-control-6",
|
||||||
|
"http://hl7.org/fhir/StructureDefinition/questionnaire-scoreItem",
|
||||||
|
"http://hl7.org/fhir/StructureDefinition/structuredefinition-expression",
|
||||||
|
|
||||||
|
};
|
||||||
|
for (String extensionDomainToTest : extensionDomainsToTest) {
|
||||||
|
Questionnaire q = minimalValidQuestionnaire();
|
||||||
|
q.addItem()
|
||||||
|
.setLinkId("link0")
|
||||||
|
.setType(QuestionnaireItemType.STRING)
|
||||||
|
.addExtension()
|
||||||
|
.setUrl(extensionDomainToTest)
|
||||||
|
.setValue(new Coding(null, "text-box", null));
|
||||||
|
|
||||||
|
ValidationResult errors = myVal.validateWithResult(q);
|
||||||
|
ourLog.info(errors.toString());
|
||||||
|
assertThat(errors.isSuccessful(), Matchers.is(true));
|
||||||
|
assertThat(errors.getMessages(), Matchers.empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQuestionnaireWithPredefinedExtensionDomainsForCodeableConcept() {
|
||||||
|
String[] extensionDomainsToTest = new String[] {
|
||||||
|
"http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl",
|
||||||
|
};
|
||||||
|
for (String extensionDomainToTest : extensionDomainsToTest) {
|
||||||
|
Questionnaire q = minimalValidQuestionnaire();
|
||||||
|
q.addItem()
|
||||||
|
.setLinkId("link0")
|
||||||
|
.setType(QuestionnaireItemType.STRING)
|
||||||
|
.addExtension()
|
||||||
|
.setUrl(extensionDomainToTest)
|
||||||
|
.setValue(new CodeableConcept().addCoding(new Coding(null, "text-box", null)));
|
||||||
|
|
||||||
|
ValidationResult errors = myVal.validateWithResult(q);
|
||||||
|
ourLog.info(errors.toString());
|
||||||
|
assertThat(errors.isSuccessful(), Matchers.is(true));
|
||||||
|
assertThat(errors.getMessages(), Matchers.empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQuestionnaireWithCustomExtensionDomain() {
|
||||||
|
String extensionUrl = "http://my.own.domain/StructureDefinition/";
|
||||||
|
Questionnaire q = minimalValidQuestionnaire();
|
||||||
|
q.addItem()
|
||||||
|
.setLinkId("link0")
|
||||||
|
.setType(QuestionnaireItemType.STRING)
|
||||||
|
.addExtension()
|
||||||
|
.setUrl(extensionUrl + "questionnaire-itemControl")
|
||||||
|
.setValue(new Coding(null, "text-box", null));
|
||||||
|
|
||||||
|
ValidationResult errors = myVal.validateWithResult(q);
|
||||||
|
|
||||||
|
ourLog.info(errors.toString());
|
||||||
|
assertThat(errors.isSuccessful(), Matchers.is(true));
|
||||||
|
assertThat(errors.getMessages(), Matchers.hasSize(1));
|
||||||
|
assertEquals(errors.getMessages().get(0).getSeverity(), ResultSeverityEnum.INFORMATION);
|
||||||
|
assertThat(errors.getMessages().get(0).getMessage(), Matchers.startsWith("Unknown extension " + extensionUrl));
|
||||||
|
|
||||||
|
myInstanceVal.setCustomExtensionDomains(extensionUrl);
|
||||||
|
errors = myVal.validateWithResult(q);
|
||||||
|
|
||||||
|
ourLog.info(errors.toString());
|
||||||
|
assertThat(errors.isSuccessful(), Matchers.is(true));
|
||||||
|
assertThat(errors.getMessages(), Matchers.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Questionnaire minimalValidQuestionnaire() {
|
||||||
|
Narrative n = new Narrative().setStatus(NarrativeStatus.GENERATED);
|
||||||
|
n.setDivAsString("simple example");
|
||||||
|
Questionnaire q = new Questionnaire();
|
||||||
|
q.setText(n);
|
||||||
|
q.setName("SomeName");
|
||||||
|
q.setStatus(PublicationStatus.ACTIVE);
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() {
|
||||||
|
myDefaultValidationSupport.flush();
|
||||||
|
myDefaultValidationSupport = null;
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue