Use R4 validator for DSTU3 validation
This commit is contained in:
parent
e52f582769
commit
8d468de551
|
@ -18,7 +18,7 @@ import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
|
|||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.dstu3.utils.IResourceValidator.BestPracticeWarningLevel;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -66,7 +66,7 @@ public class BaseDstu3Config extends BaseConfig {
|
|||
@Lazy
|
||||
public IValidatorModule instanceValidatorDstu3() {
|
||||
FhirInstanceValidator val = new FhirInstanceValidator();
|
||||
val.setBestPracticeWarningLevel(BestPracticeWarningLevel.Warning);
|
||||
val.setBestPracticeWarningLevel(IResourceValidator.BestPracticeWarningLevel.Warning);
|
||||
val.setValidationSupport(validationSupportChainDstu3());
|
||||
return val;
|
||||
}
|
||||
|
|
|
@ -1,354 +1,335 @@
|
|||
package org.hl7.fhir.dstu3.context;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.dstu3.formats.IParser;
|
||||
import org.hl7.fhir.dstu3.formats.ParserType;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.dstu3.model.CodeableConcept;
|
||||
import org.hl7.fhir.dstu3.model.Coding;
|
||||
import org.hl7.fhir.dstu3.model.ConceptMap;
|
||||
import org.hl7.fhir.dstu3.model.ExpansionProfile;
|
||||
import org.hl7.fhir.dstu3.model.MetadataResource;
|
||||
import org.hl7.fhir.dstu3.model.Resource;
|
||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
|
||||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.dstu3.utils.INarrativeGenerator;
|
||||
import org.hl7.fhir.dstu3.utils.IResourceValidator;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
||||
|
||||
/**
|
||||
* This is the standard interface used for access to underlying FHIR
|
||||
* services through the tools and utilities provided by the reference
|
||||
* implementation.
|
||||
*
|
||||
* The functionality it provides is
|
||||
* - get access to parsers, validators, narrative builders etc
|
||||
* (you can't create these directly because they need access
|
||||
* to the right context for their information)
|
||||
*
|
||||
* - find resources that the tools need to carry out their tasks
|
||||
*
|
||||
* - provide access to terminology services they need.
|
||||
* (typically, these terminology service requests are just
|
||||
* passed through to the local implementation's terminology
|
||||
* service)
|
||||
*
|
||||
* @author Grahame
|
||||
*/
|
||||
public interface IWorkerContext {
|
||||
|
||||
/**
|
||||
* Get the versions of the definitions loaded in context
|
||||
* @return
|
||||
*/
|
||||
public String getVersion();
|
||||
|
||||
// -- Parsers (read and write instances) ----------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Get a parser to read/write instances. Use the defined type (will be extended
|
||||
* as further types are added, though the only currently anticipate type is RDF)
|
||||
*
|
||||
* XML/JSON - the standard renderers
|
||||
* XHTML - render the narrative only (generate it if necessary)
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public IParser getParser(ParserType type);
|
||||
|
||||
/**
|
||||
* Get a parser to read/write instances. Determine the type
|
||||
* from the stated type. Supported value for type:
|
||||
* - the recommended MIME types
|
||||
* - variants of application/xml and application/json
|
||||
* - _format values xml, json
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public IParser getParser(String type);
|
||||
|
||||
/**
|
||||
* Get a JSON parser
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public IParser newJsonParser();
|
||||
|
||||
/**
|
||||
* Get an XML parser
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public IParser newXmlParser();
|
||||
|
||||
/**
|
||||
* Get a generator that can generate narrative for the instance
|
||||
*
|
||||
* @return a prepared generator
|
||||
*/
|
||||
public INarrativeGenerator getNarrativeGenerator(String prefix, String basePath);
|
||||
|
||||
/**
|
||||
* Get a validator that can check whether a resource is valid
|
||||
*
|
||||
* @return a prepared generator
|
||||
* @throws FHIRException
|
||||
* @
|
||||
*/
|
||||
public IResourceValidator newValidator() throws FHIRException;
|
||||
|
||||
// -- resource fetchers ---------------------------------------------------
|
||||
|
||||
/**
|
||||
* Find an identified resource. The most common use of this is to access the the
|
||||
* standard conformance resources that are part of the standard - structure
|
||||
* definitions, value sets, concept maps, etc.
|
||||
*
|
||||
* Also, the narrative generator uses this, and may access any kind of resource
|
||||
*
|
||||
* The URI is called speculatively for things that might exist, so not finding
|
||||
* a matching resouce, return null, not an error
|
||||
*
|
||||
* The URI can have one of 3 formats:
|
||||
* - a full URL e.g. http://acme.org/fhir/ValueSet/[id]
|
||||
* - a relative URL e.g. ValueSet/[id]
|
||||
* - a logical id e.g. [id]
|
||||
*
|
||||
* It's an error if the second form doesn't agree with class_. It's an
|
||||
* error if class_ is null for the last form
|
||||
*
|
||||
* @param resource
|
||||
* @param Reference
|
||||
* @return
|
||||
* @throws FHIRException
|
||||
* @throws Exception
|
||||
*/
|
||||
public <T extends Resource> T fetchResource(Class<T> class_, String uri);
|
||||
public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri) throws FHIRException;
|
||||
|
||||
/**
|
||||
* find whether a resource is available.
|
||||
*
|
||||
* Implementations of the interface can assume that if hasResource ruturns
|
||||
* true, the resource will usually be fetched subsequently
|
||||
*
|
||||
* @param class_
|
||||
* @param uri
|
||||
* @return
|
||||
*/
|
||||
public <T extends Resource> boolean hasResource(Class<T> class_, String uri);
|
||||
|
||||
// -- profile services ---------------------------------------------------------
|
||||
|
||||
public List<String> getResourceNames();
|
||||
public List<String> getTypeNames();
|
||||
public List<StructureDefinition> allStructures();
|
||||
public List<MetadataResource> allConformanceResources();
|
||||
|
||||
// -- Terminology services ------------------------------------------------------
|
||||
|
||||
public ExpansionProfile getExpansionProfile();
|
||||
public void setExpansionProfile(ExpansionProfile expProfile);
|
||||
|
||||
// these are the terminology services used internally by the tools
|
||||
/**
|
||||
* Find the code system definition for the nominated system uri.
|
||||
* return null if there isn't one (then the tool might try
|
||||
* supportsSystem)
|
||||
*
|
||||
* @param system
|
||||
* @return
|
||||
*/
|
||||
public CodeSystem fetchCodeSystem(String system);
|
||||
|
||||
/**
|
||||
* True if the underlying terminology service provider will do
|
||||
* expansion and code validation for the terminology. Corresponds
|
||||
* to the extension
|
||||
*
|
||||
* http://hl7.org/fhir/StructureDefinition/capabilitystatement-supported-system
|
||||
*
|
||||
* in the Conformance resource
|
||||
*
|
||||
* @param system
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public boolean supportsSystem(String system) throws TerminologyServiceException;
|
||||
|
||||
/**
|
||||
* find concept maps for a source
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public List<ConceptMap> findMapsForSource(String url);
|
||||
|
||||
/**
|
||||
* ValueSet Expansion - see $expand
|
||||
*
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
public ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean heiarchical);
|
||||
|
||||
/**
|
||||
* Value set expanion inside the internal expansion engine - used
|
||||
* for references to supported system (see "supportsSystem") for
|
||||
* which there is no value set.
|
||||
*
|
||||
* @param inc
|
||||
* @return
|
||||
* @throws FHIRException
|
||||
*/
|
||||
public ValueSetExpansionComponent expandVS(ConceptSetComponent inc, boolean heiarchical) throws TerminologyServiceException;
|
||||
|
||||
public class ValidationResult {
|
||||
private ConceptDefinitionComponent definition;
|
||||
private IssueSeverity severity;
|
||||
private String message;
|
||||
private TerminologyServiceErrorClass errorClass;
|
||||
|
||||
public ValidationResult(IssueSeverity severity, String message) {
|
||||
this.severity = severity;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public ValidationResult(ConceptDefinitionComponent definition) {
|
||||
this.definition = definition;
|
||||
}
|
||||
|
||||
public ValidationResult(IssueSeverity severity, String message, ConceptDefinitionComponent definition) {
|
||||
this.severity = severity;
|
||||
this.message = message;
|
||||
this.definition = definition;
|
||||
}
|
||||
|
||||
public ValidationResult(IssueSeverity severity, String message, TerminologyServiceErrorClass errorClass) {
|
||||
this.severity = severity;
|
||||
this.message = message;
|
||||
this.errorClass = errorClass;
|
||||
}
|
||||
|
||||
public boolean isOk() {
|
||||
return definition != null;
|
||||
}
|
||||
|
||||
public String getDisplay() {
|
||||
// We don't want to return question-marks because that prevents something more useful from being displayed (e.g. the code) if there's no display value
|
||||
// return definition == null ? "??" : definition.getDisplay();
|
||||
return definition == null ? null : definition.getDisplay();
|
||||
}
|
||||
|
||||
public ConceptDefinitionComponent asConceptDefinition() {
|
||||
return definition;
|
||||
}
|
||||
|
||||
public IssueSeverity getSeverity() {
|
||||
return severity;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public boolean IsNoService() {
|
||||
return errorClass == TerminologyServiceErrorClass.NOSERVICE;
|
||||
}
|
||||
|
||||
public TerminologyServiceErrorClass getErrorClass() {
|
||||
return errorClass;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation of a code - consult the terminology service
|
||||
* to see whether it is known. If known, return a description of it
|
||||
*
|
||||
* note: always return a result, with either an error or a code description
|
||||
*
|
||||
* corresponds to 2 terminology service calls: $validate-code and $lookup
|
||||
*
|
||||
* @param system
|
||||
* @param code
|
||||
* @param display
|
||||
* @return
|
||||
*/
|
||||
public ValidationResult validateCode(String system, String code, String display);
|
||||
|
||||
/**
|
||||
* Validation of a code - consult the terminology service
|
||||
* to see whether it is known. If known, return a description of it
|
||||
* Also, check whether it's in the provided value set
|
||||
*
|
||||
* note: always return a result, with either an error or a code description, or both (e.g. known code, but not in the value set)
|
||||
*
|
||||
* corresponds to 2 terminology service calls: $validate-code and $lookup
|
||||
*
|
||||
* @param system
|
||||
* @param code
|
||||
* @param display
|
||||
* @return
|
||||
*/
|
||||
public ValidationResult validateCode(String system, String code, String display, ValueSet vs);
|
||||
public ValidationResult validateCode(Coding code, ValueSet vs);
|
||||
public ValidationResult validateCode(CodeableConcept code, ValueSet vs);
|
||||
|
||||
/**
|
||||
* Validation of a code - consult the terminology service
|
||||
* to see whether it is known. If known, return a description of it
|
||||
* Also, check whether it's in the provided value set fragment (for supported systems with no value set definition)
|
||||
*
|
||||
* note: always return a result, with either an error or a code description, or both (e.g. known code, but not in the value set)
|
||||
*
|
||||
* corresponds to 2 terminology service calls: $validate-code and $lookup
|
||||
*
|
||||
* @param system
|
||||
* @param code
|
||||
* @param display
|
||||
* @return
|
||||
*/
|
||||
public ValidationResult validateCode(String system, String code, String display, ConceptSetComponent vsi);
|
||||
|
||||
/**
|
||||
* returns the recommended tla for the type
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public String getAbbreviation(String name);
|
||||
|
||||
// return a set of types that have tails
|
||||
public Set<String> typeTails();
|
||||
|
||||
public String oid2Uri(String code);
|
||||
|
||||
public boolean hasCache();
|
||||
|
||||
public interface ILoggingService {
|
||||
public enum LogCategory {
|
||||
PROGRESS, TX, INIT, CONTEXT, HTML
|
||||
}
|
||||
public void logMessage(String message); // status messages, always display
|
||||
public void logDebugMessage(LogCategory category, String message); // verbose; only when debugging
|
||||
}
|
||||
|
||||
public void setLogger(ILoggingService logger);
|
||||
|
||||
public boolean isNoTerminologyServer();
|
||||
|
||||
}
|
||||
package org.hl7.fhir.dstu3.context;
|
||||
|
||||
import org.hl7.fhir.dstu3.formats.IParser;
|
||||
import org.hl7.fhir.dstu3.formats.ParserType;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
|
||||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.dstu3.utils.INarrativeGenerator;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* This is the standard interface used for access to underlying FHIR
|
||||
* services through the tools and utilities provided by the reference
|
||||
* implementation.
|
||||
*
|
||||
* The functionality it provides is
|
||||
* - get access to parsers, validators, narrative builders etc
|
||||
* (you can't create these directly because they need access
|
||||
* to the right context for their information)
|
||||
*
|
||||
* - find resources that the tools need to carry out their tasks
|
||||
*
|
||||
* - provide access to terminology services they need.
|
||||
* (typically, these terminology service requests are just
|
||||
* passed through to the local implementation's terminology
|
||||
* service)
|
||||
*
|
||||
* @author Grahame
|
||||
*/
|
||||
public interface IWorkerContext {
|
||||
|
||||
/**
|
||||
* Get the versions of the definitions loaded in context
|
||||
* @return
|
||||
*/
|
||||
public String getVersion();
|
||||
|
||||
// -- Parsers (read and write instances) ----------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Get a parser to read/write instances. Use the defined type (will be extended
|
||||
* as further types are added, though the only currently anticipate type is RDF)
|
||||
*
|
||||
* XML/JSON - the standard renderers
|
||||
* XHTML - render the narrative only (generate it if necessary)
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public IParser getParser(ParserType type);
|
||||
|
||||
/**
|
||||
* Get a parser to read/write instances. Determine the type
|
||||
* from the stated type. Supported value for type:
|
||||
* - the recommended MIME types
|
||||
* - variants of application/xml and application/json
|
||||
* - _format values xml, json
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public IParser getParser(String type);
|
||||
|
||||
/**
|
||||
* Get a JSON parser
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public IParser newJsonParser();
|
||||
|
||||
/**
|
||||
* Get an XML parser
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public IParser newXmlParser();
|
||||
|
||||
/**
|
||||
* Get a generator that can generate narrative for the instance
|
||||
*
|
||||
* @return a prepared generator
|
||||
*/
|
||||
public INarrativeGenerator getNarrativeGenerator(String prefix, String basePath);
|
||||
|
||||
|
||||
// -- resource fetchers ---------------------------------------------------
|
||||
|
||||
/**
|
||||
* Find an identified resource. The most common use of this is to access the the
|
||||
* standard conformance resources that are part of the standard - structure
|
||||
* definitions, value sets, concept maps, etc.
|
||||
*
|
||||
* Also, the narrative generator uses this, and may access any kind of resource
|
||||
*
|
||||
* The URI is called speculatively for things that might exist, so not finding
|
||||
* a matching resouce, return null, not an error
|
||||
*
|
||||
* The URI can have one of 3 formats:
|
||||
* - a full URL e.g. http://acme.org/fhir/ValueSet/[id]
|
||||
* - a relative URL e.g. ValueSet/[id]
|
||||
* - a logical id e.g. [id]
|
||||
*
|
||||
* It's an error if the second form doesn't agree with class_. It's an
|
||||
* error if class_ is null for the last form
|
||||
*
|
||||
* @return
|
||||
* @throws FHIRException
|
||||
* @throws Exception
|
||||
*/
|
||||
public <T extends Resource> T fetchResource(Class<T> class_, String uri);
|
||||
public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri) throws FHIRException;
|
||||
|
||||
/**
|
||||
* find whether a resource is available.
|
||||
*
|
||||
* Implementations of the interface can assume that if hasResource ruturns
|
||||
* true, the resource will usually be fetched subsequently
|
||||
*
|
||||
* @param class_
|
||||
* @param uri
|
||||
* @return
|
||||
*/
|
||||
public <T extends Resource> boolean hasResource(Class<T> class_, String uri);
|
||||
|
||||
// -- profile services ---------------------------------------------------------
|
||||
|
||||
public List<String> getResourceNames();
|
||||
public List<String> getTypeNames();
|
||||
public List<StructureDefinition> allStructures();
|
||||
public List<MetadataResource> allConformanceResources();
|
||||
|
||||
// -- Terminology services ------------------------------------------------------
|
||||
|
||||
public ExpansionProfile getExpansionProfile();
|
||||
public void setExpansionProfile(ExpansionProfile expProfile);
|
||||
|
||||
// these are the terminology services used internally by the tools
|
||||
/**
|
||||
* Find the code system definition for the nominated system uri.
|
||||
* return null if there isn't one (then the tool might try
|
||||
* supportsSystem)
|
||||
*
|
||||
* @param system
|
||||
* @return
|
||||
*/
|
||||
public CodeSystem fetchCodeSystem(String system);
|
||||
|
||||
/**
|
||||
* True if the underlying terminology service provider will do
|
||||
* expansion and code validation for the terminology. Corresponds
|
||||
* to the extension
|
||||
*
|
||||
* http://hl7.org/fhir/StructureDefinition/capabilitystatement-supported-system
|
||||
*
|
||||
* in the Conformance resource
|
||||
*
|
||||
* @param system
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public boolean supportsSystem(String system) throws TerminologyServiceException;
|
||||
|
||||
/**
|
||||
* find concept maps for a source
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public List<ConceptMap> findMapsForSource(String url);
|
||||
|
||||
/**
|
||||
* ValueSet Expansion - see $expand
|
||||
*
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
public ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean heiarchical);
|
||||
|
||||
/**
|
||||
* Value set expanion inside the internal expansion engine - used
|
||||
* for references to supported system (see "supportsSystem") for
|
||||
* which there is no value set.
|
||||
*
|
||||
* @param inc
|
||||
* @return
|
||||
* @throws FHIRException
|
||||
*/
|
||||
public ValueSetExpansionComponent expandVS(ConceptSetComponent inc, boolean heiarchical) throws TerminologyServiceException;
|
||||
|
||||
public class ValidationResult {
|
||||
private ConceptDefinitionComponent definition;
|
||||
private IssueSeverity severity;
|
||||
private String message;
|
||||
private TerminologyServiceErrorClass errorClass;
|
||||
|
||||
public ValidationResult(IssueSeverity severity, String message) {
|
||||
this.severity = severity;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public ValidationResult(ConceptDefinitionComponent definition) {
|
||||
this.definition = definition;
|
||||
}
|
||||
|
||||
public ValidationResult(IssueSeverity severity, String message, ConceptDefinitionComponent definition) {
|
||||
this.severity = severity;
|
||||
this.message = message;
|
||||
this.definition = definition;
|
||||
}
|
||||
|
||||
public ValidationResult(IssueSeverity severity, String message, TerminologyServiceErrorClass errorClass) {
|
||||
this.severity = severity;
|
||||
this.message = message;
|
||||
this.errorClass = errorClass;
|
||||
}
|
||||
|
||||
public boolean isOk() {
|
||||
return definition != null;
|
||||
}
|
||||
|
||||
public String getDisplay() {
|
||||
// We don't want to return question-marks because that prevents something more useful from being displayed (e.g. the code) if there's no display value
|
||||
// return definition == null ? "??" : definition.getDisplay();
|
||||
return definition == null ? null : definition.getDisplay();
|
||||
}
|
||||
|
||||
public ConceptDefinitionComponent asConceptDefinition() {
|
||||
return definition;
|
||||
}
|
||||
|
||||
public IssueSeverity getSeverity() {
|
||||
return severity;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public boolean IsNoService() {
|
||||
return errorClass == TerminologyServiceErrorClass.NOSERVICE;
|
||||
}
|
||||
|
||||
public TerminologyServiceErrorClass getErrorClass() {
|
||||
return errorClass;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation of a code - consult the terminology service
|
||||
* to see whether it is known. If known, return a description of it
|
||||
*
|
||||
* note: always return a result, with either an error or a code description
|
||||
*
|
||||
* corresponds to 2 terminology service calls: $validate-code and $lookup
|
||||
*
|
||||
* @param system
|
||||
* @param code
|
||||
* @param display
|
||||
* @return
|
||||
*/
|
||||
public ValidationResult validateCode(String system, String code, String display);
|
||||
|
||||
/**
|
||||
* Validation of a code - consult the terminology service
|
||||
* to see whether it is known. If known, return a description of it
|
||||
* Also, check whether it's in the provided value set
|
||||
*
|
||||
* note: always return a result, with either an error or a code description, or both (e.g. known code, but not in the value set)
|
||||
*
|
||||
* corresponds to 2 terminology service calls: $validate-code and $lookup
|
||||
*
|
||||
* @param system
|
||||
* @param code
|
||||
* @param display
|
||||
* @return
|
||||
*/
|
||||
public ValidationResult validateCode(String system, String code, String display, ValueSet vs);
|
||||
public ValidationResult validateCode(Coding code, ValueSet vs);
|
||||
public ValidationResult validateCode(CodeableConcept code, ValueSet vs);
|
||||
|
||||
/**
|
||||
* Validation of a code - consult the terminology service
|
||||
* to see whether it is known. If known, return a description of it
|
||||
* Also, check whether it's in the provided value set fragment (for supported systems with no value set definition)
|
||||
*
|
||||
* note: always return a result, with either an error or a code description, or both (e.g. known code, but not in the value set)
|
||||
*
|
||||
* corresponds to 2 terminology service calls: $validate-code and $lookup
|
||||
*
|
||||
* @param system
|
||||
* @param code
|
||||
* @param display
|
||||
* @return
|
||||
*/
|
||||
public ValidationResult validateCode(String system, String code, String display, ConceptSetComponent vsi);
|
||||
|
||||
/**
|
||||
* returns the recommended tla for the type
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public String getAbbreviation(String name);
|
||||
|
||||
// return a set of types that have tails
|
||||
public Set<String> typeTails();
|
||||
|
||||
public String oid2Uri(String code);
|
||||
|
||||
public boolean hasCache();
|
||||
|
||||
public interface ILoggingService {
|
||||
public enum LogCategory {
|
||||
PROGRESS, TX, INIT, CONTEXT, HTML
|
||||
}
|
||||
public void logMessage(String message); // status messages, always display
|
||||
public void logDebugMessage(LogCategory category, String message); // verbose; only when debugging
|
||||
}
|
||||
|
||||
public void setLogger(ILoggingService logger);
|
||||
|
||||
public boolean isNoTerminologyServer();
|
||||
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ import org.hl7.fhir.dstu3.terminologies.ValueSetExpander;
|
|||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpanderFactory;
|
||||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpanderSimple;
|
||||
import org.hl7.fhir.dstu3.utils.INarrativeGenerator;
|
||||
import org.hl7.fhir.dstu3.utils.IResourceValidator;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
@ -124,10 +123,6 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IResourceValidator newValidator() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IParser newXmlParser() {
|
||||
|
@ -204,8 +199,8 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
boolean caseSensitive = true;
|
||||
if (isNotBlank(theSystem)) {
|
||||
CodeSystem system = fetchCodeSystem(theSystem);
|
||||
|
|
|
@ -1,174 +0,0 @@
|
|||
package org.hl7.fhir.dstu3.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.dstu3.elementmodel.Element;
|
||||
import org.hl7.fhir.dstu3.elementmodel.Manager.FhirFormat;
|
||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu3.utils.IResourceValidator.ReferenceValidationPolicy;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* Interface to the instance validator. This takes a resource, in one of many forms, and
|
||||
* checks whether it is valid
|
||||
*
|
||||
* @author Grahame Grieve
|
||||
*
|
||||
*/
|
||||
public interface IResourceValidator {
|
||||
|
||||
public enum ReferenceValidationPolicy {
|
||||
IGNORE, CHECK_TYPE_IF_EXISTS, CHECK_EXISTS, CHECK_EXISTS_AND_TYPE, CHECK_VALID;
|
||||
|
||||
public boolean checkExists() {
|
||||
return this == CHECK_EXISTS_AND_TYPE || this == CHECK_EXISTS || this == CHECK_VALID;
|
||||
}
|
||||
|
||||
public boolean checkType() {
|
||||
return this == CHECK_TYPE_IF_EXISTS || this == CHECK_EXISTS_AND_TYPE || this == CHECK_VALID;
|
||||
}
|
||||
|
||||
public boolean checkValid() {
|
||||
return this == CHECK_VALID;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IValidatorResourceFetcher {
|
||||
Element fetch(Object appContext, String url) throws FHIRFormatError, DefinitionException, IOException, FHIRException;
|
||||
ReferenceValidationPolicy validationPolicy(Object appContext, String path, String url);
|
||||
boolean resolveURL(Object appContext, String path, String url) throws IOException, FHIRException;
|
||||
}
|
||||
|
||||
public enum BestPracticeWarningLevel {
|
||||
Ignore,
|
||||
Hint,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
|
||||
public enum CheckDisplayOption {
|
||||
Ignore,
|
||||
Check,
|
||||
CheckCaseAndSpace,
|
||||
CheckCase,
|
||||
CheckSpace
|
||||
}
|
||||
|
||||
enum IdStatus {
|
||||
OPTIONAL, REQUIRED, PROHIBITED
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* how much to check displays for coded elements
|
||||
* @return
|
||||
*/
|
||||
CheckDisplayOption getCheckDisplay();
|
||||
void setCheckDisplay(CheckDisplayOption checkDisplay);
|
||||
|
||||
/**
|
||||
* whether the resource must have an id or not (depends on context)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
||||
IdStatus getResourceIdRule();
|
||||
void setResourceIdRule(IdStatus resourceIdRule);
|
||||
|
||||
/**
|
||||
* whether the validator should enforce best practice guidelines
|
||||
* as defined by various HL7 committees
|
||||
*
|
||||
*/
|
||||
BestPracticeWarningLevel getBasePracticeWarningLevel();
|
||||
IResourceValidator setBestPracticeWarningLevel(BestPracticeWarningLevel value);
|
||||
|
||||
IValidatorResourceFetcher getFetcher();
|
||||
IResourceValidator setFetcher(IValidatorResourceFetcher value);
|
||||
|
||||
boolean isNoBindingMsgSuppressed();
|
||||
IResourceValidator setNoBindingMsgSuppressed(boolean noBindingMsgSuppressed);
|
||||
|
||||
public boolean isNoInvariantChecks();
|
||||
public IResourceValidator setNoInvariantChecks(boolean value) ;
|
||||
|
||||
public boolean isNoTerminologyChecks();
|
||||
public IResourceValidator setNoTerminologyChecks(boolean noTerminologyChecks);
|
||||
|
||||
/**
|
||||
* Whether being unable to resolve a profile in found in Resource.meta.profile or ElementDefinition.type.profile or targetProfile is an error or just a warning
|
||||
* @return
|
||||
*/
|
||||
public boolean isErrorForUnknownProfiles();
|
||||
public void setErrorForUnknownProfiles(boolean errorForUnknownProfiles);
|
||||
|
||||
/**
|
||||
* Validate suite
|
||||
*
|
||||
* you can validate one of the following representations of resources:
|
||||
*
|
||||
* stream - provide a format - this is the preferred choice
|
||||
*
|
||||
* Use one of these two if the content is known to be valid XML/JSON, and already parsed
|
||||
* - a DOM element or Document
|
||||
* - a Json Object
|
||||
*
|
||||
* In order to use these, the content must already be parsed - e.g. it must syntactically valid
|
||||
* - a native resource
|
||||
* - a elementmodel resource
|
||||
*
|
||||
* in addition, you can pass one or more profiles ti validate beyond the base standard - as structure definitions or canonical URLs
|
||||
* @throws IOException
|
||||
*/
|
||||
void validate(Object Context, List<ValidationMessage> errors, org.hl7.fhir.dstu3.elementmodel.Element element) throws FHIRException, IOException;
|
||||
void validate(Object Context, List<ValidationMessage> errors, org.hl7.fhir.dstu3.elementmodel.Element element, ValidationProfileSet profiles) throws FHIRException, IOException;
|
||||
@Deprecated
|
||||
void validate(Object Context, List<ValidationMessage> errors, org.hl7.fhir.dstu3.elementmodel.Element element, String profile) throws FHIRException, IOException;
|
||||
@Deprecated
|
||||
void validate(Object Context, List<ValidationMessage> errors, org.hl7.fhir.dstu3.elementmodel.Element element, StructureDefinition profile) throws FHIRException, IOException;
|
||||
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, InputStream stream, FhirFormat format) throws FHIRException, IOException;
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, InputStream stream, FhirFormat format, ValidationProfileSet profiles) throws FHIRException, IOException;
|
||||
@Deprecated
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, InputStream stream, FhirFormat format, String profile) throws FHIRException, IOException;
|
||||
@Deprecated
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, InputStream stream, FhirFormat format, StructureDefinition profile) throws FHIRException, IOException;
|
||||
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, org.hl7.fhir.dstu3.model.Resource resource) throws FHIRException, IOException;
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, org.hl7.fhir.dstu3.model.Resource resource, ValidationProfileSet profiles) throws FHIRException, IOException;
|
||||
@Deprecated
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, org.hl7.fhir.dstu3.model.Resource resource, String profile) throws FHIRException, IOException;
|
||||
@Deprecated
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, org.hl7.fhir.dstu3.model.Resource resource, StructureDefinition profile) throws FHIRException, IOException;
|
||||
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, org.w3c.dom.Element element) throws FHIRException, IOException;
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, org.w3c.dom.Element element, ValidationProfileSet profiles) throws FHIRException, IOException;
|
||||
@Deprecated
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, org.w3c.dom.Element element, String profile) throws FHIRException, IOException;
|
||||
@Deprecated
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, org.w3c.dom.Element element, StructureDefinition profile) throws FHIRException, IOException;
|
||||
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, org.w3c.dom.Document document) throws FHIRException, IOException;
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, org.w3c.dom.Document document, ValidationProfileSet profiles) throws FHIRException, IOException;
|
||||
@Deprecated
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, org.w3c.dom.Document document, String profile) throws FHIRException, IOException;
|
||||
@Deprecated
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, org.w3c.dom.Document document, StructureDefinition profile) throws FHIRException, IOException;
|
||||
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, JsonObject object) throws FHIRException, IOException;
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, JsonObject object, ValidationProfileSet profiles) throws FHIRException, IOException;
|
||||
@Deprecated
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, JsonObject object, String profile) throws FHIRException, IOException;
|
||||
@Deprecated
|
||||
org.hl7.fhir.dstu3.elementmodel.Element validate(Object Context, List<ValidationMessage> errors, JsonObject object, StructureDefinition profile) throws FHIRException, IOException;
|
||||
|
||||
|
||||
}
|
|
@ -25,6 +25,11 @@
|
|||
<artifactId>hapi-fhir-utilities</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-converter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
Optional dependencies from RI codebase
|
||||
|
@ -105,12 +110,6 @@
|
|||
<artifactId>woodstox-core-asl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-converter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-server</artifactId>
|
||||
|
|
|
@ -1,284 +1,609 @@
|
|||
package org.hl7.fhir.dstu3.hapi.validation;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.*;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.utils.FHIRPathEngine.IEvaluationContext;
|
||||
import org.hl7.fhir.dstu3.utils.IResourceValidator.BestPracticeWarningLevel;
|
||||
import org.hl7.fhir.dstu3.utils.IResourceValidator.IdStatus;
|
||||
import org.hl7.fhir.dstu3.validation.InstanceValidator;
|
||||
import org.hl7.fhir.exceptions.PathEngineException;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import com.google.gson.*;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.validation.IValidationContext;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.convertors.VersionConvertor_30_40;
|
||||
import org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||
import org.hl7.fhir.r4.formats.IParser;
|
||||
import org.hl7.fhir.r4.formats.ParserType;
|
||||
import org.hl7.fhir.r4.terminologies.ValueSetExpander;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r4.utils.INarrativeGenerator;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator.BestPracticeWarningLevel;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator.IdStatus;
|
||||
import org.hl7.fhir.r4.validation.InstanceValidator;
|
||||
import org.hl7.fhir.utilities.TranslationServices;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import java.io.StringReader;
|
||||
import java.util.*;
|
||||
|
||||
public class FhirInstanceValidator extends BaseValidatorBridge implements IValidatorModule {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirInstanceValidator.class);
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirInstanceValidator.class);
|
||||
|
||||
private boolean myAnyExtensionsAllowed = true;
|
||||
private BestPracticeWarningLevel myBestPracticeWarningLevel;
|
||||
private DocumentBuilderFactory myDocBuilderFactory;
|
||||
private StructureDefinition myStructureDefintion;
|
||||
private IValidationSupport myValidationSupport;
|
||||
private boolean noTerminologyChecks = false;
|
||||
private boolean myAnyExtensionsAllowed = true;
|
||||
private BestPracticeWarningLevel myBestPracticeWarningLevel;
|
||||
private DocumentBuilderFactory myDocBuilderFactory;
|
||||
private StructureDefinition myStructureDefintion;
|
||||
private IValidationSupport myValidationSupport;
|
||||
private boolean noTerminologyChecks = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Uses {@link DefaultProfileValidationSupport} for {@link IValidationSupport validation support}
|
||||
*/
|
||||
public FhirInstanceValidator() {
|
||||
this(new DefaultProfileValidationSupport());
|
||||
}
|
||||
/**
|
||||
* Constructor
|
||||
* <p>
|
||||
* Uses {@link DefaultProfileValidationSupport} for {@link IValidationSupport validation support}
|
||||
*/
|
||||
public FhirInstanceValidator() {
|
||||
this(new DefaultProfileValidationSupport());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor which uses the given validation support
|
||||
*
|
||||
* @param theValidationSupport
|
||||
* The validation support
|
||||
*/
|
||||
public FhirInstanceValidator(IValidationSupport theValidationSupport) {
|
||||
myDocBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
myDocBuilderFactory.setNamespaceAware(true);
|
||||
myValidationSupport = theValidationSupport;
|
||||
}
|
||||
/**
|
||||
* Constructor which uses the given validation support
|
||||
*
|
||||
* @param theValidationSupport The validation support
|
||||
*/
|
||||
public FhirInstanceValidator(IValidationSupport theValidationSupport) {
|
||||
myDocBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
myDocBuilderFactory.setNamespaceAware(true);
|
||||
myValidationSupport = theValidationSupport;
|
||||
}
|
||||
|
||||
private String determineResourceName(Document theDocument) {
|
||||
Element root = null;
|
||||
private String determineResourceName(Document theDocument) {
|
||||
Element root = null;
|
||||
|
||||
NodeList list = theDocument.getChildNodes();
|
||||
for (int i = 0; i < list.getLength(); i++) {
|
||||
if (list.item(i) instanceof Element) {
|
||||
root = (Element) list.item(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
root = theDocument.getDocumentElement();
|
||||
return root.getLocalName();
|
||||
}
|
||||
NodeList list = theDocument.getChildNodes();
|
||||
for (int i = 0; i < list.getLength(); i++) {
|
||||
if (list.item(i) instanceof Element) {
|
||||
root = (Element) list.item(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
root = theDocument.getDocumentElement();
|
||||
return root.getLocalName();
|
||||
}
|
||||
|
||||
private StructureDefinition findStructureDefinitionForResourceName(final FhirContext theCtx, String resourceName) {
|
||||
String sdName = "http://hl7.org/fhir/StructureDefinition/" + resourceName;
|
||||
StructureDefinition profile = myStructureDefintion != null ? myStructureDefintion : myValidationSupport.fetchStructureDefinition(theCtx, sdName);
|
||||
return profile;
|
||||
}
|
||||
private StructureDefinition findStructureDefinitionForResourceName(final FhirContext theCtx, String resourceName) {
|
||||
String sdName = "http://hl7.org/fhir/StructureDefinition/" + resourceName;
|
||||
StructureDefinition profile = myStructureDefintion != null ? myStructureDefintion : myValidationSupport.fetchStructureDefinition(theCtx, sdName);
|
||||
return profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "best practice" warning level (default is {@link BestPracticeWarningLevel#Hint}).
|
||||
* <p>
|
||||
* The FHIR Instance Validator has a number of checks for best practices in terms of FHIR usage. If this setting is
|
||||
* set to {@link BestPracticeWarningLevel#Error}, any resource data which does not meet these best practices will be
|
||||
* reported at the ERROR level. If this setting is set to {@link BestPracticeWarningLevel#Ignore}, best practice
|
||||
* guielines will be ignored.
|
||||
* </p>
|
||||
*
|
||||
* @see {@link #setBestPracticeWarningLevel(BestPracticeWarningLevel)}
|
||||
*/
|
||||
public BestPracticeWarningLevel getBestPracticeWarningLevel() {
|
||||
return myBestPracticeWarningLevel;
|
||||
}
|
||||
/**
|
||||
* Returns the "best practice" warning level (default is {@link BestPracticeWarningLevel#Hint}).
|
||||
* <p>
|
||||
* The FHIR Instance Validator has a number of checks for best practices in terms of FHIR usage. If this setting is
|
||||
* set to {@link BestPracticeWarningLevel#Error}, any resource data which does not meet these best practices will be
|
||||
* reported at the ERROR level. If this setting is set to {@link BestPracticeWarningLevel#Ignore}, best practice
|
||||
* guielines will be ignored.
|
||||
* </p>
|
||||
*
|
||||
* @see {@link #setBestPracticeWarningLevel(BestPracticeWarningLevel)}
|
||||
*/
|
||||
public BestPracticeWarningLevel getBestPracticeWarningLevel() {
|
||||
return myBestPracticeWarningLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link IValidationSupport validation support} in use by this validator. Default is an instance of
|
||||
* {@link DefaultProfileValidationSupport} if the no-arguments constructor for this object was used.
|
||||
*/
|
||||
public IValidationSupport getValidationSupport() {
|
||||
return myValidationSupport;
|
||||
}
|
||||
/**
|
||||
* Sets the "best practice warning level". When validating, any deviations from best practices will be reported at
|
||||
* this level.
|
||||
* <p>
|
||||
* The FHIR Instance Validator has a number of checks for best practices in terms of FHIR usage. If this setting is
|
||||
* set to {@link BestPracticeWarningLevel#Error}, any resource data which does not meet these best practices will be
|
||||
* reported at the ERROR level. If this setting is set to {@link BestPracticeWarningLevel#Ignore}, best practice
|
||||
* guielines will be ignored.
|
||||
* </p>
|
||||
*
|
||||
* @param theBestPracticeWarningLevel The level, must not be <code>null</code>
|
||||
*/
|
||||
public void setBestPracticeWarningLevel(BestPracticeWarningLevel theBestPracticeWarningLevel) {
|
||||
Validate.notNull(theBestPracticeWarningLevel);
|
||||
myBestPracticeWarningLevel = theBestPracticeWarningLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@literal true} (default is true) extensions which are not known to the
|
||||
* validator (e.g. because they have not been explicitly declared in a profile) will
|
||||
* be validated but will not cause an error.
|
||||
*/
|
||||
public boolean isAnyExtensionsAllowed() {
|
||||
return myAnyExtensionsAllowed;
|
||||
}
|
||||
/**
|
||||
* Returns the {@link IValidationSupport validation support} in use by this validator. Default is an instance of
|
||||
* {@link DefaultProfileValidationSupport} if the no-arguments constructor for this object was used.
|
||||
*/
|
||||
public IValidationSupport getValidationSupport() {
|
||||
return myValidationSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@literal true} (default is true) extensions which are not known to the
|
||||
* validator (e.g. because they have not been explicitly declared in a profile) will
|
||||
* be validated but will not cause an error.
|
||||
*/
|
||||
public void setAnyExtensionsAllowed(boolean theAnyExtensionsAllowed) {
|
||||
myAnyExtensionsAllowed = theAnyExtensionsAllowed;
|
||||
}
|
||||
/**
|
||||
* Sets the {@link IValidationSupport validation support} in use by this validator. Default is an instance of
|
||||
* {@link DefaultProfileValidationSupport} if the no-arguments constructor for this object was used.
|
||||
*/
|
||||
public void setValidationSupport(IValidationSupport theValidationSupport) {
|
||||
myValidationSupport = theValidationSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@literal true} (default is false) the valueSet will not be validate
|
||||
*/
|
||||
public boolean isNoTerminologyChecks() {
|
||||
return noTerminologyChecks;
|
||||
}
|
||||
/**
|
||||
* If set to {@literal true} (default is true) extensions which are not known to the
|
||||
* validator (e.g. because they have not been explicitly declared in a profile) will
|
||||
* be validated but will not cause an error.
|
||||
*/
|
||||
public boolean isAnyExtensionsAllowed() {
|
||||
return myAnyExtensionsAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@literal true} (default is false) the valueSet will not be validate
|
||||
*/
|
||||
public void setNoTerminologyChecks(final boolean theNoTerminologyChecks) {
|
||||
noTerminologyChecks = theNoTerminologyChecks;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@literal true} (default is true) extensions which are not known to the
|
||||
* validator (e.g. because they have not been explicitly declared in a profile) will
|
||||
* be validated but will not cause an error.
|
||||
*/
|
||||
public void setAnyExtensionsAllowed(boolean theAnyExtensionsAllowed) {
|
||||
myAnyExtensionsAllowed = theAnyExtensionsAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "best practice warning level". When validating, any deviations from best practices will be reported at
|
||||
* this level.
|
||||
* <p>
|
||||
* The FHIR Instance Validator has a number of checks for best practices in terms of FHIR usage. If this setting is
|
||||
* set to {@link BestPracticeWarningLevel#Error}, any resource data which does not meet these best practices will be
|
||||
* reported at the ERROR level. If this setting is set to {@link BestPracticeWarningLevel#Ignore}, best practice
|
||||
* guielines will be ignored.
|
||||
* </p>
|
||||
*
|
||||
* @param theBestPracticeWarningLevel
|
||||
* The level, must not be <code>null</code>
|
||||
*/
|
||||
public void setBestPracticeWarningLevel(BestPracticeWarningLevel theBestPracticeWarningLevel) {
|
||||
Validate.notNull(theBestPracticeWarningLevel);
|
||||
myBestPracticeWarningLevel = theBestPracticeWarningLevel;
|
||||
}
|
||||
/**
|
||||
* If set to {@literal true} (default is false) the valueSet will not be validate
|
||||
*/
|
||||
public boolean isNoTerminologyChecks() {
|
||||
return noTerminologyChecks;
|
||||
}
|
||||
|
||||
public void setStructureDefintion(StructureDefinition theStructureDefintion) {
|
||||
myStructureDefintion = theStructureDefintion;
|
||||
}
|
||||
/**
|
||||
* If set to {@literal true} (default is false) the valueSet will not be validate
|
||||
*/
|
||||
public void setNoTerminologyChecks(final boolean theNoTerminologyChecks) {
|
||||
noTerminologyChecks = theNoTerminologyChecks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link IValidationSupport validation support} in use by this validator. Default is an instance of
|
||||
* {@link DefaultProfileValidationSupport} if the no-arguments constructor for this object was used.
|
||||
*/
|
||||
public void setValidationSupport(IValidationSupport theValidationSupport) {
|
||||
myValidationSupport = theValidationSupport;
|
||||
}
|
||||
public void setStructureDefintion(StructureDefinition theStructureDefintion) {
|
||||
myStructureDefintion = theStructureDefintion;
|
||||
}
|
||||
|
||||
protected List<ValidationMessage> validate(final FhirContext theCtx, String theInput, EncodingEnum theEncoding) {
|
||||
HapiWorkerContext workerContext = new HapiWorkerContext(theCtx, myValidationSupport);
|
||||
protected List<ValidationMessage> validate(final FhirContext theCtx, String theInput, EncodingEnum theEncoding) {
|
||||
HapiWorkerContext workerContext = new HapiWorkerContext(theCtx, myValidationSupport);
|
||||
WorkerContextWrapper wrappedWorkerContext = new WorkerContextWrapper(workerContext);
|
||||
|
||||
InstanceValidator v;
|
||||
IEvaluationContext evaluationCtx = new NullEvaluationContext();
|
||||
try {
|
||||
v = new InstanceValidator(workerContext, evaluationCtx);
|
||||
} catch (Exception e) {
|
||||
throw new ConfigurationException(e);
|
||||
}
|
||||
InstanceValidator v;
|
||||
FHIRPathEngine.IEvaluationContext evaluationCtx = new org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator.NullEvaluationContext();
|
||||
try {
|
||||
v = new InstanceValidator(wrappedWorkerContext, evaluationCtx);
|
||||
} catch (Exception e) {
|
||||
throw new ConfigurationException(e);
|
||||
}
|
||||
|
||||
v.setBestPracticeWarningLevel(getBestPracticeWarningLevel());
|
||||
v.setAnyExtensionsAllowed(isAnyExtensionsAllowed());
|
||||
v.setResourceIdRule(IdStatus.OPTIONAL);
|
||||
v.setNoTerminologyChecks(isNoTerminologyChecks());
|
||||
v.setBestPracticeWarningLevel(getBestPracticeWarningLevel());
|
||||
v.setAnyExtensionsAllowed(isAnyExtensionsAllowed());
|
||||
v.setResourceIdRule(IdStatus.OPTIONAL);
|
||||
v.setNoTerminologyChecks(isNoTerminologyChecks());
|
||||
|
||||
List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
|
||||
if (theEncoding == EncodingEnum.XML) {
|
||||
Document document;
|
||||
try {
|
||||
DocumentBuilder builder = myDocBuilderFactory.newDocumentBuilder();
|
||||
InputSource src = new InputSource(new StringReader(theInput));
|
||||
document = builder.parse(src);
|
||||
} catch (Exception e2) {
|
||||
ourLog.error("Failure to parse XML input", e2);
|
||||
ValidationMessage m = new ValidationMessage();
|
||||
m.setLevel(IssueSeverity.FATAL);
|
||||
m.setMessage("Failed to parse input, it does not appear to be valid XML:" + e2.getMessage());
|
||||
return Collections.singletonList(m);
|
||||
}
|
||||
if (theEncoding == EncodingEnum.XML) {
|
||||
Document document;
|
||||
try {
|
||||
DocumentBuilder builder = myDocBuilderFactory.newDocumentBuilder();
|
||||
InputSource src = new InputSource(new StringReader(theInput));
|
||||
document = builder.parse(src);
|
||||
} catch (Exception e2) {
|
||||
ourLog.error("Failure to parse XML input", e2);
|
||||
ValidationMessage m = new ValidationMessage();
|
||||
m.setLevel(IssueSeverity.FATAL);
|
||||
m.setMessage("Failed to parse input, it does not appear to be valid XML:" + e2.getMessage());
|
||||
return Collections.singletonList(m);
|
||||
}
|
||||
|
||||
String resourceName = determineResourceName(document);
|
||||
StructureDefinition profile = findStructureDefinitionForResourceName(theCtx, resourceName);
|
||||
if (profile != null) {
|
||||
try {
|
||||
v.validate(null, messages, document, profile);
|
||||
} catch (Exception e) {
|
||||
throw new InternalErrorException("Unexpected failure while validating resource", e);
|
||||
}
|
||||
}
|
||||
} else if (theEncoding == EncodingEnum.JSON) {
|
||||
Gson gson = new GsonBuilder().create();
|
||||
JsonObject json = gson.fromJson(theInput, JsonObject.class);
|
||||
String resourceName = determineResourceName(document);
|
||||
StructureDefinition profile = findStructureDefinitionForResourceName(theCtx, resourceName);
|
||||
if (profile != null) {
|
||||
try {
|
||||
v.validate(null, messages, document, profile.getUrl());
|
||||
} catch (Exception e) {
|
||||
throw new InternalErrorException("Unexpected failure while validating resource", e);
|
||||
}
|
||||
}
|
||||
} else if (theEncoding == EncodingEnum.JSON) {
|
||||
Gson gson = new GsonBuilder().create();
|
||||
JsonObject json = gson.fromJson(theInput, JsonObject.class);
|
||||
|
||||
String resourceName = json.get("resourceType").getAsString();
|
||||
StructureDefinition profile = findStructureDefinitionForResourceName(theCtx, resourceName);
|
||||
if (profile != null) {
|
||||
try {
|
||||
v.validate(null, messages, json, profile);
|
||||
} catch (Exception e) {
|
||||
throw new InternalErrorException("Unexpected failure while validating resource", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown encoding: " + theEncoding);
|
||||
}
|
||||
String resourceName = json.get("resourceType").getAsString();
|
||||
StructureDefinition profile = findStructureDefinitionForResourceName(theCtx, resourceName);
|
||||
if (profile != null) {
|
||||
try {
|
||||
v.validate(null, messages, json, profile.getUrl());
|
||||
} catch (Exception e) {
|
||||
throw new InternalErrorException("Unexpected failure while validating resource", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown encoding: " + theEncoding);
|
||||
}
|
||||
|
||||
for (int i = 0; i < messages.size(); i++) {
|
||||
ValidationMessage next = messages.get(i);
|
||||
if ("Binding has no source, so can't be checked".equals(next.getMessage())) {
|
||||
messages.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
for (int i = 0; i < messages.size(); i++) {
|
||||
ValidationMessage next = messages.get(i);
|
||||
if ("Binding has no source, so can't be checked".equals(next.getMessage())) {
|
||||
messages.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ValidationMessage> validate(IValidationContext<?> theCtx) {
|
||||
return validate(theCtx.getFhirContext(), theCtx.getResourceAsString(), theCtx.getResourceAsStringEncoding());
|
||||
}
|
||||
@Override
|
||||
protected List<ValidationMessage> validate(IValidationContext<?> theCtx) {
|
||||
return validate(theCtx.getFhirContext(), theCtx.getResourceAsString(), theCtx.getResourceAsStringEncoding());
|
||||
}
|
||||
|
||||
public class NullEvaluationContext implements IEvaluationContext {
|
||||
|
||||
@Override
|
||||
public TypeDetails checkFunction(Object theAppContext, String theFunctionName, List<TypeDetails> theParameters) throws PathEngineException {
|
||||
return null;
|
||||
}
|
||||
private class WorkerContextWrapper implements IWorkerContext {
|
||||
private final HapiWorkerContext myWrap;
|
||||
private final VersionConvertor_30_40 myConverter;
|
||||
private volatile List<org.hl7.fhir.r4.model.StructureDefinition> myAllStructures;
|
||||
|
||||
@Override
|
||||
public List<Base> executeFunction(Object theAppContext, String theFunctionName, List<List<Base>> theParameters) {
|
||||
return null;
|
||||
}
|
||||
public WorkerContextWrapper(HapiWorkerContext theWorkerContext) {
|
||||
myWrap = theWorkerContext;
|
||||
myConverter = new VersionConvertor_30_40();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean log(String theArgument, List<Base> theFocus) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public List<org.hl7.fhir.r4.model.MetadataResource> allConformanceResources() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Base resolveConstant(Object theAppContext, String theName) throws PathEngineException {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public List<org.hl7.fhir.r4.model.StructureDefinition> allStructures() {
|
||||
|
||||
@Override
|
||||
public TypeDetails resolveConstantType(Object theAppContext, String theName) throws PathEngineException {
|
||||
return null;
|
||||
}
|
||||
List<org.hl7.fhir.r4.model.StructureDefinition> retVal = myAllStructures;
|
||||
if (retVal == null) {
|
||||
retVal = new ArrayList<>();
|
||||
for (StructureDefinition next : myWrap.allStructures()) {
|
||||
try {
|
||||
retVal.add(VersionConvertor_30_40.convertStructureDefinition(next));
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
myAllStructures = retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionDetails resolveFunction(String theFunctionName) {
|
||||
return null;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Base resolveReference(Object theAppContext, String theUrl) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public void cacheResource(org.hl7.fhir.r4.model.Resource res) throws FHIRException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
private ValidationResult convertValidationResult(org.hl7.fhir.dstu3.context.IWorkerContext.ValidationResult theResult) {
|
||||
IssueSeverity issueSeverity = theResult.getSeverity();
|
||||
String message = theResult.getMessage();
|
||||
org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent conceptDefinition = null;
|
||||
if (theResult.asConceptDefinition() != null) {
|
||||
try {
|
||||
conceptDefinition = VersionConvertor_30_40.convertConceptDefinitionComponent(theResult.asConceptDefinition());
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
ValidationResult retVal = new ValidationResult(issueSeverity, message, conceptDefinition);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpander.ValueSetExpansionOutcome expandVS(org.hl7.fhir.r4.model.ValueSet source, boolean cacheOk, boolean heiarchical) {
|
||||
ValueSet convertedSource = null;
|
||||
try {
|
||||
convertedSource = VersionConvertor_30_40.convertValueSet(source);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
org.hl7.fhir.dstu3.terminologies.ValueSetExpander.ValueSetExpansionOutcome expanded = myWrap.expandVS(convertedSource, cacheOk, heiarchical);
|
||||
|
||||
org.hl7.fhir.r4.model.ValueSet convertedResult = null;
|
||||
if (expanded.getValueset() != null) {
|
||||
try {
|
||||
convertedResult = VersionConvertor_30_40.convertValueSet(expanded.getValueset());
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
String error = expanded.getError();
|
||||
ValueSetExpander.TerminologyServiceErrorClass result = null;
|
||||
|
||||
return new ValueSetExpander.ValueSetExpansionOutcome(convertedResult, error, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpander.ValueSetExpansionOutcome expandVS(org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent binding, boolean cacheOk, boolean heiarchical) throws FHIRException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent expandVS(org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent inc, boolean heirarchical) throws TerminologyServiceException {
|
||||
ValueSet.ConceptSetComponent convertedInc = null;
|
||||
if (inc != null) {
|
||||
try {
|
||||
convertedInc = VersionConvertor_30_40.convertConceptSetComponent(inc);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
ValueSet.ValueSetExpansionComponent expansion = myWrap.expandVS(convertedInc, heirarchical);
|
||||
org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent retVal = null;
|
||||
if (expansion != null) {
|
||||
try {
|
||||
retVal = VersionConvertor_30_40.convertValueSetExpansionComponent(expansion);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.hl7.fhir.r4.model.CodeSystem fetchCodeSystem(String system) {
|
||||
CodeSystem fetched = myWrap.fetchCodeSystem(system);
|
||||
if (fetched == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return VersionConvertor_30_40.convertCodeSystem(fetched);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends org.hl7.fhir.r4.model.Resource> T fetchResource(Class<T> class_, String uri) {
|
||||
org.hl7.fhir.dstu3.model.Resource fetched;
|
||||
switch (class_.getSimpleName()) {
|
||||
case "StructureDefinition":
|
||||
fetched = myWrap.fetchResource(StructureDefinition.class, uri);
|
||||
break;
|
||||
case "ValueSet":
|
||||
fetched = myWrap.fetchResource(ValueSet.class, uri);
|
||||
break;
|
||||
case "CodeSystem":
|
||||
fetched = myWrap.fetchResource(CodeSystem.class, uri);
|
||||
break;
|
||||
case "Questionnaire":
|
||||
fetched = myWrap.fetchResource(Questionnaire.class, uri);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Don't know how to fetch " + class_.getSimpleName());
|
||||
}
|
||||
|
||||
if (fetched == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return (T) VersionConvertor_30_40.convertResource(fetched);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.hl7.fhir.r4.model.Resource fetchResourceById(String type, String uri) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends org.hl7.fhir.r4.model.Resource> T fetchResourceWithException(Class<T> class_, String uri) throws FHIRException {
|
||||
T retVal = fetchResource(class_, uri);
|
||||
if (retVal == null) {
|
||||
throw new FHIRException("Can not find resource of type " + class_.getSimpleName() + " with uri " + uri);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<org.hl7.fhir.r4.model.ConceptMap> findMapsForSource(String url) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAbbreviation(String name) {
|
||||
return myWrap.getAbbreviation(name);
|
||||
}
|
||||
|
||||
public VersionConvertor_30_40 getConverter() {
|
||||
return myConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.hl7.fhir.r4.model.ExpansionProfile getExpansionProfile() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpansionProfile(org.hl7.fhir.r4.model.ExpansionProfile expProfile) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public INarrativeGenerator getNarrativeGenerator(String prefix, String basePath) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IParser getParser(ParserType type) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IParser getParser(String type) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getResourceNames() {
|
||||
return myWrap.getResourceNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getResourceNamesAsSet() {
|
||||
return new HashSet<>(myWrap.getResourceNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getTypeNames() {
|
||||
return myWrap.getTypeNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return myWrap.getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCache() {
|
||||
return myWrap.hasCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends org.hl7.fhir.r4.model.Resource> boolean hasResource(Class<T> class_, String uri) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNoTerminologyServer() {
|
||||
return myWrap.isNoTerminologyServer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IParser newJsonParser() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IResourceValidator newValidator() throws FHIRException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IParser newXmlParser() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String oid2Uri(String code) {
|
||||
return myWrap.oid2Uri(code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogger(ILoggingService logger) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSystem(String system) throws TerminologyServiceException {
|
||||
return myWrap.supportsSystem(system);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TranslationServices translator() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> typeTails() {
|
||||
return myWrap.typeTails();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(String system, String code, String display) {
|
||||
org.hl7.fhir.dstu3.context.IWorkerContext.ValidationResult result = myWrap.validateCode(system, code, display);
|
||||
return convertValidationResult(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(String system, String code, String display, org.hl7.fhir.r4.model.ValueSet vs) {
|
||||
ValueSet convertedVs = null;
|
||||
|
||||
try {
|
||||
if (vs != null) {
|
||||
convertedVs = VersionConvertor_30_40.convertValueSet(vs);
|
||||
}
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
|
||||
org.hl7.fhir.dstu3.context.IWorkerContext.ValidationResult result = myWrap.validateCode(system, code, display, convertedVs);
|
||||
return convertValidationResult(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(org.hl7.fhir.r4.model.Coding code, org.hl7.fhir.r4.model.ValueSet vs) {
|
||||
Coding convertedCode = null;
|
||||
ValueSet convertedVs = null;
|
||||
|
||||
try {
|
||||
if (code != null) {
|
||||
convertedCode = VersionConvertor_30_40.convertCoding(code);
|
||||
}
|
||||
if (vs != null) {
|
||||
convertedVs = VersionConvertor_30_40.convertValueSet(vs);
|
||||
}
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
|
||||
org.hl7.fhir.dstu3.context.IWorkerContext.ValidationResult result = myWrap.validateCode(convertedCode, convertedVs);
|
||||
return convertValidationResult(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(org.hl7.fhir.r4.model.CodeableConcept code, org.hl7.fhir.r4.model.ValueSet vs) {
|
||||
CodeableConcept convertedCode = null;
|
||||
ValueSet convertedVs = null;
|
||||
|
||||
try {
|
||||
if (code != null) {
|
||||
convertedCode = VersionConvertor_30_40.convertCodeableConcept(code);
|
||||
}
|
||||
if (vs != null) {
|
||||
convertedVs = VersionConvertor_30_40.convertValueSet(vs);
|
||||
}
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
|
||||
org.hl7.fhir.dstu3.context.IWorkerContext.ValidationResult result = myWrap.validateCode(convertedCode, convertedVs);
|
||||
return convertValidationResult(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(String system, String code, String display, org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent vsi) {
|
||||
ValueSet.ConceptSetComponent conceptSetComponent = null;
|
||||
if (vsi != null) {
|
||||
try {
|
||||
conceptSetComponent = VersionConvertor_30_40.convertConceptSetComponent(vsi);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
org.hl7.fhir.dstu3.context.IWorkerContext.ValidationResult result = myWrap.validateCode(system, code, display, conceptSetComponent);
|
||||
return convertValidationResult(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -241,7 +241,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
|||
return validate(theCtx.getFhirContext(), theCtx.getResourceAsString(), theCtx.getResourceAsStringEncoding());
|
||||
}
|
||||
|
||||
public class NullEvaluationContext implements IEvaluationContext {
|
||||
public static class NullEvaluationContext implements IEvaluationContext {
|
||||
|
||||
@Override
|
||||
public TypeDetails checkFunction(Object theAppContext, String theFunctionName, List<TypeDetails> theParameters) throws PathEngineException {
|
||||
|
|
|
@ -286,7 +286,6 @@ public class ResponseValidatingInterceptorDstu3Test {
|
|||
* Ignored until #264 is fixed
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testSearchJsonInvalidNoValidatorsSpecified() throws Exception {
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
@ -305,7 +304,6 @@ public class ResponseValidatingInterceptorDstu3Test {
|
|||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
Assert.assertEquals(422, status.getStatusLine().getStatusCode());
|
||||
Assert.assertThat(status.toString(), Matchers.containsString("X-FHIR-Response-Validation"));
|
||||
Assert.assertThat(responseContent, Matchers.containsString("<severity value=\"error\"/>"));
|
||||
}
|
||||
|
||||
|
@ -384,7 +382,6 @@ public class ResponseValidatingInterceptorDstu3Test {
|
|||
* Ignored until #264 is fixed
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testSearchXmlInvalidNoValidatorsSpecified() throws Exception {
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
@ -403,7 +400,7 @@ public class ResponseValidatingInterceptorDstu3Test {
|
|||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
Assert.assertEquals(422, status.getStatusLine().getStatusCode());
|
||||
Assert.assertThat(status.toString(), Matchers.containsString("X-FHIR-Response-Validation"));
|
||||
Assert.assertThat(responseContent, Matchers.containsString("<severity value=\"error\"/>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
|||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
||||
|
@ -283,7 +284,6 @@ public class ResponseValidatingInterceptorR4Test {
|
|||
* Ignored until #264 is fixed
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testSearchJsonInvalidNoValidatorsSpecified() throws Exception {
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
@ -302,7 +302,6 @@ public class ResponseValidatingInterceptorR4Test {
|
|||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(422, status.getStatusLine().getStatusCode());
|
||||
assertThat(status.toString(), containsString("X-FHIR-Response-Validation"));
|
||||
assertThat(responseContent, containsString("<severity value=\"error\"/>"));
|
||||
}
|
||||
|
||||
|
@ -381,7 +380,6 @@ public class ResponseValidatingInterceptorR4Test {
|
|||
* Ignored until #264 is fixed
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testSearchXmlInvalidNoValidatorsSpecified() throws Exception {
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
@ -400,7 +398,7 @@ public class ResponseValidatingInterceptorR4Test {
|
|||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(422, status.getStatusLine().getStatusCode());
|
||||
assertThat(status.toString(), containsString("X-FHIR-Response-Validation"));
|
||||
Assert.assertThat(responseContent, Matchers.containsString("<severity value=\"error\"/>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -506,12 +506,11 @@ public class FhirInstanceValidatorDstu3Test {
|
|||
|
||||
@Test
|
||||
public void testValidateRawXmlResourceWithEmptyPrimitive() {
|
||||
// @formatter:off
|
||||
String input = "<Patient xmlns=\"http://hl7.org/fhir\"><name><given/></name></Patient>";
|
||||
// @formatter:on
|
||||
|
||||
ValidationResult output = myVal.validateWithResult(input);
|
||||
assertEquals(output.toString(), 2, output.getMessages().size());
|
||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output.toOperationOutcome()));
|
||||
assertEquals(output.toString(), 3, output.getMessages().size());
|
||||
assertThat(output.getMessages().get(0).getMessage(), containsString("Element must have some content"));
|
||||
assertThat(output.getMessages().get(1).getMessage(), containsString("primitive types must have a value or must have child extensions"));
|
||||
}
|
||||
|
@ -677,7 +676,7 @@ public class FhirInstanceValidatorDstu3Test {
|
|||
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
||||
|
||||
assertThat(errors.toString(), containsString("Element 'Observation.subject': minimum required = 1, but only found 0"));
|
||||
assertThat(errors.toString(), containsString("Element 'Observation.context: max allowed = 0, but found 1"));
|
||||
assertThat(errors.toString(), containsString("Element 'Observation.context': max allowed = 0, but found 1"));
|
||||
assertThat(errors.toString(), containsString("Element 'Observation.device': minimum required = 1, but only found 0"));
|
||||
assertThat(errors.toString(), containsString(""));
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
ValidationResult errors = myVal.validateWithResult(qa);
|
||||
|
||||
ourLog.info(errors.toString());
|
||||
assertThat(errors.toString(), containsString("minimum required = 1, but only found 0 - QuestionnaireResponse.item"));
|
||||
assertThat(errors.toString(), containsString("No LinkId, so can't be validated"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -287,7 +287,6 @@ public class ResourceValidatorDstu3Test {
|
|||
* TODO: re-enable this
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testValidateQuestionnaireWithCanonicalUrl() {
|
||||
String input = "{\n" +
|
||||
" \"resourceType\": \"Questionnaire\",\n" +
|
||||
|
@ -377,16 +376,15 @@ public class ResourceValidatorDstu3Test {
|
|||
PatientProfileDstu3 myPatient = new PatientProfileDstu3();
|
||||
myPatient.setId("1");
|
||||
myPatient.setColorPrimary(new CodeableConcept().addCoding(new Coding().setSystem("http://example.com#animalColor").setCode("furry-grey")));
|
||||
myPatient.setColorSecondary(new CodeableConcept().addCoding(new Coding().setSystem("http://example.com#animalColor").setSystem("furry-white")));
|
||||
myPatient.setColorSecondary(new CodeableConcept().addCoding(new Coding().setSystem("http://example.com#animalColor").setCode("furry-white")));
|
||||
myPatient.setOwningOrganization(new Reference("Organization/2.25.79433498044103547197447759549862032393"));
|
||||
myPatient.addName().setFamily("FamilyName");
|
||||
myPatient.addExtension().setUrl("http://foo.com/example").setValue(new StringType("String Extension"));
|
||||
|
||||
IParser p = ourCtx.newJsonParser().setPrettyPrint(true);
|
||||
String messageString = p.encodeResourceToString(myPatient);
|
||||
ourLog.info(messageString);
|
||||
// ourLog.info(messageString);
|
||||
|
||||
//@formatter:off
|
||||
assertThat(messageString, stringContainsInOrder(
|
||||
"meta",
|
||||
"String Extension",
|
||||
|
@ -399,7 +397,6 @@ public class ResourceValidatorDstu3Test {
|
|||
"extension",
|
||||
"meta"
|
||||
)));
|
||||
//@formatter:on
|
||||
|
||||
FhirValidator val = ourCtx.newValidator();
|
||||
val.registerValidatorModule(new SchemaBaseValidator(ourCtx));
|
||||
|
@ -426,7 +423,7 @@ public class ResourceValidatorDstu3Test {
|
|||
PatientProfileDstu3 myPatient = new PatientProfileDstu3();
|
||||
myPatient.setId("1");
|
||||
myPatient.setColorPrimary(new CodeableConcept().addCoding(new Coding().setSystem("http://example.com#animalColor").setCode("furry-grey")));
|
||||
myPatient.setColorSecondary(new CodeableConcept().addCoding(new Coding().setSystem("http://example.com#animalColor").setSystem("furry-white")));
|
||||
myPatient.setColorSecondary(new CodeableConcept().addCoding(new Coding().setSystem("http://example.com#animalColor").setCode("furry-white")));
|
||||
myPatient.setOwningOrganization(new Reference("Organization/2.25.79433498044103547197447759549862032393"));
|
||||
myPatient.addName().setFamily("FamilyName");
|
||||
myPatient.addExtension().setUrl("http://foo.com/example").setValue(new StringType("String Extension"));
|
||||
|
|
|
@ -8,20 +8,9 @@
|
|||
<body>
|
||||
<release version="3.3.0" date="TBD">
|
||||
<action type="add">
|
||||
The version of a few dependencies have been bumped to the
|
||||
latest versions (dependent HAPI modules listed in brackets):
|
||||
<![CDATA[
|
||||
<ul>
|
||||
<li>Hibernate (JPA): 5.2.10.Final -> 5.2.12.Final</li>
|
||||
<li>Spring (JPA): 5.0.0 -> 5.0.3</li>
|
||||
<li>Thymeleaf (Web Tespage Overlay): 3.0.7.RELEASE -> 3.0.9.RELEASE</li>
|
||||
</ul>
|
||||
]]>
|
||||
</action>
|
||||
<action type="add">
|
||||
This release corrects an inefficiency in the JPA Server, but requires a schema
|
||||
change in order to update. Prior to this version of HAPI FHIR, a CLOB column
|
||||
containing the complete resource body was stored in two
|
||||
containing the complete resource body was stored in two
|
||||
tables: HFJ_RESOURCE and HFJ_RES_VER. Because the same content was stored in two
|
||||
places, the database consumed more space than is needed to.
|
||||
<![CDATA[<br/><br/>]]>
|
||||
|
@ -32,6 +21,26 @@
|
|||
set them to nullable if you want an easy means of rolling back). Naturally
|
||||
you should back your database up prior to making this change.
|
||||
</action>
|
||||
<action type="fix">
|
||||
The validation module has been refactored to use the R4 (currently maintained)
|
||||
validator even for DSTU3 validation. This is done by using an automatic
|
||||
converter which converts StructureDefinition/ValueSet/CodeSystem resources
|
||||
which are used as inputs to the validator. This change should fix a number
|
||||
of known issues with the validator, as they have been fixed in R4 but
|
||||
not in DSTU3. This also makes our validator much more maintainable
|
||||
since it is now one codebase.
|
||||
</action>
|
||||
<action type="add">
|
||||
The version of a few dependencies have been bumped to the
|
||||
latest versions (dependent HAPI modules listed in brackets):
|
||||
<![CDATA[
|
||||
<ul>
|
||||
<li>Hibernate (JPA): 5.2.10.Final -> 5.2.12.Final</li>
|
||||
<li>Spring (JPA): 5.0.0 -> 5.0.3</li>
|
||||
<li>Thymeleaf (Web Tespage Overlay): 3.0.7.RELEASE -> 3.0.9.RELEASE</li>
|
||||
</ul>
|
||||
]]>
|
||||
</action>
|
||||
<action type="fix">
|
||||
Fix a crash in the JSON parser when parsing extensions on repeatable
|
||||
elements (e.g. Patient.address.line) where there is an extension on the
|
||||
|
|
Loading…
Reference in New Issue