Work on common FluentPath interface
This commit is contained in:
parent
5846ce4518
commit
03935be97f
|
@ -23,34 +23,23 @@ import java.lang.reflect.Method;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.hl7.fhir.instance.model.api.IBase;
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||||
|
import ca.uhn.fhir.fluentpath.IFluentPath;
|
||||||
import ca.uhn.fhir.i18n.HapiLocalizer;
|
import ca.uhn.fhir.i18n.HapiLocalizer;
|
||||||
import ca.uhn.fhir.model.api.IElement;
|
import ca.uhn.fhir.model.api.IElement;
|
||||||
import ca.uhn.fhir.model.api.IFhirVersion;
|
import ca.uhn.fhir.model.api.IFhirVersion;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.view.ViewGenerator;
|
import ca.uhn.fhir.model.view.ViewGenerator;
|
||||||
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import ca.uhn.fhir.parser.*;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
|
||||||
import ca.uhn.fhir.parser.IParserErrorHandler;
|
|
||||||
import ca.uhn.fhir.parser.JsonParser;
|
|
||||||
import ca.uhn.fhir.parser.LenientErrorHandler;
|
|
||||||
import ca.uhn.fhir.parser.XmlParser;
|
|
||||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||||
import ca.uhn.fhir.rest.client.IRestfulClientFactory;
|
import ca.uhn.fhir.rest.client.IRestfulClientFactory;
|
||||||
import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
|
import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
|
||||||
|
@ -106,6 +95,52 @@ public class FhirContext {
|
||||||
private final IFhirVersion myVersion;
|
private final IFhirVersion myVersion;
|
||||||
private Map<FhirVersionEnum, Map<String, Class<? extends IBaseResource>>> myVersionToNameToResourceType = Collections.emptyMap();
|
private Map<FhirVersionEnum, Map<String, Class<? extends IBaseResource>>> myVersionToNameToResourceType = Collections.emptyMap();
|
||||||
private boolean myInitializing;
|
private boolean myInitializing;
|
||||||
|
private IContextValidationSupport<?, ?, ?, ?, ?, ?> myValidationSupport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the validation support module configured for this context, creating a default
|
||||||
|
* implementation if no module has been passed in via the {@link #setValidationSupport(IContextValidationSupport)}
|
||||||
|
* method
|
||||||
|
* @see #setValidationSupport(IContextValidationSupport)
|
||||||
|
*/
|
||||||
|
public IContextValidationSupport<?, ?, ?, ?, ?, ?> getValidationSupport() {
|
||||||
|
if (myValidationSupport == null) {
|
||||||
|
myValidationSupport = myVersion.createValidationSupport();
|
||||||
|
}
|
||||||
|
return myValidationSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new FluentPath engine which can be used to exvaluate
|
||||||
|
* path expressions over FHIR resources. Note that this engine will use the
|
||||||
|
* {@link IContextValidationSupport context validation support} module which is
|
||||||
|
* configured on the context at the time this method is called.
|
||||||
|
* <p>
|
||||||
|
* In other words, call {@link #setValidationSupport(IContextValidationSupport)} before
|
||||||
|
* calling {@link #newFluentPath()}
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Note that this feature was added for FHIR DSTU3 and is not available
|
||||||
|
* for contexts configured to use an older version of FHIR. Calling this method
|
||||||
|
* on a context for a previous version of fhir will result in an
|
||||||
|
* {@link UnsupportedOperationException}
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
public IFluentPath newFluentPath() {
|
||||||
|
return myVersion.createFluentPathExecutor(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the validation support module to use for this context. The validation support module
|
||||||
|
* is used to supply underlying infrastructure such as conformance resources (StructureDefinition, ValueSet, etc)
|
||||||
|
* as well as to provide terminology services to modules such as the validator and FluentPath executor
|
||||||
|
*/
|
||||||
|
public void setValidationSupport(IContextValidationSupport<?, ?, ?, ?, ?, ?> theValidationSupport) {
|
||||||
|
myValidationSupport = theValidationSupport;
|
||||||
|
}
|
||||||
|
|
||||||
private ParserOptions myParserOptions = new ParserOptions();
|
private ParserOptions myParserOptions = new ParserOptions();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
package ca.uhn.fhir.context.support;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
|
||||||
|
public interface IContextValidationSupport<EVS_IN, EVS_OUT, SDT, CST, CDCT, IST> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expands the given portion of a ValueSet
|
||||||
|
*
|
||||||
|
* @param theInclude
|
||||||
|
* The portion to include
|
||||||
|
* @return The expansion
|
||||||
|
*/
|
||||||
|
EVS_OUT expandValueSet(FhirContext theContext, EVS_IN theInclude);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load and return all possible structure definitions
|
||||||
|
*/
|
||||||
|
List<SDT> fetchAllStructureDefinitions(FhirContext theContext);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a code system by ID
|
||||||
|
*
|
||||||
|
* @param theSystem
|
||||||
|
* The code system
|
||||||
|
* @return The valueset (must not be null, but can be an empty ValueSet)
|
||||||
|
*/
|
||||||
|
CST fetchCodeSystem(FhirContext theContext, String theSystem);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a resource needed by the validation (a StructureDefinition, or a
|
||||||
|
* ValueSet)
|
||||||
|
*
|
||||||
|
* @param theContext
|
||||||
|
* The HAPI FHIR Context object current in use by the validator
|
||||||
|
* @param theClass
|
||||||
|
* The type of the resource to load
|
||||||
|
* @param theUri
|
||||||
|
* The resource URI
|
||||||
|
* @return Returns the resource, or <code>null</code> if no resource with the
|
||||||
|
* given URI can be found
|
||||||
|
*/
|
||||||
|
<T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri);
|
||||||
|
|
||||||
|
SDT fetchStructureDefinition(FhirContext theCtx, String theUrl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns <code>true</code> if codes in the given code system can be expanded
|
||||||
|
* or validated
|
||||||
|
*
|
||||||
|
* @param theSystem
|
||||||
|
* The URI for the code system, e.g. <code>"http://loinc.org"</code>
|
||||||
|
* @return Returns <code>true</code> if codes in the given code system can be
|
||||||
|
* validated
|
||||||
|
*/
|
||||||
|
boolean isCodeSystemSupported(FhirContext theContext, String theSystem);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates that the given code exists and if possible returns a display
|
||||||
|
* name. This method is called to check codes which are found in "example"
|
||||||
|
* binding fields (e.g. <code>Observation.code</code> in the default profile.
|
||||||
|
*
|
||||||
|
* @param theCodeSystem
|
||||||
|
* The code system, e.g. "<code>http://loinc.org</code>"
|
||||||
|
* @param theCode
|
||||||
|
* The code, e.g. "<code>1234-5</code>"
|
||||||
|
* @param theDisplay
|
||||||
|
* The display name, if it should also be validated
|
||||||
|
* @return Returns a validation result object
|
||||||
|
*/
|
||||||
|
CodeValidationResult<CDCT, IST> validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay);
|
||||||
|
|
||||||
|
public class CodeValidationResult<CDCT, IST> {
|
||||||
|
private CDCT definition;
|
||||||
|
private String message;
|
||||||
|
private IST severity;
|
||||||
|
|
||||||
|
public CodeValidationResult(CDCT theNext) {
|
||||||
|
this.definition = theNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CodeValidationResult(IST severity, String message) {
|
||||||
|
this.severity = severity;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CodeValidationResult(IST severity, String message, CDCT definition) {
|
||||||
|
this.severity = severity;
|
||||||
|
this.message = message;
|
||||||
|
this.definition = definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CDCT asConceptDefinition() {
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IST getSeverity() {
|
||||||
|
return severity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOk() {
|
||||||
|
return definition != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package ca.uhn.fhir.fluentpath;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This exception is thrown if a FluentPath expression can not be executed successfully
|
||||||
|
* for any reason
|
||||||
|
*/
|
||||||
|
public class FluentPathExecutionException extends InternalErrorException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public FluentPathExecutionException(Throwable theCause) {
|
||||||
|
super(theCause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluentPathExecutionException(String theMessage) {
|
||||||
|
super(theMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package ca.uhn.fhir.fluentpath;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
|
|
||||||
|
public interface IFluentPath {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the given FluentPath expression against the given input and return
|
||||||
|
* all results in a list
|
||||||
|
*
|
||||||
|
* @param theInput The input object (generally a resource or datatype)
|
||||||
|
* @param thePath The fluent path expression
|
||||||
|
* @param theReturnType The type to return (in order to avoid casting)
|
||||||
|
*/
|
||||||
|
<T extends IBase> List<T> evaluate(IBase theInput, String thePath, Class<T> theReturnType);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -31,6 +31,8 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||||
|
import ca.uhn.fhir.fluentpath.IFluentPath;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
|
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
|
||||||
import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory;
|
import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory;
|
||||||
|
@ -62,4 +64,8 @@ public interface IFhirVersion {
|
||||||
|
|
||||||
IIdType newIdType();
|
IIdType newIdType();
|
||||||
|
|
||||||
|
IContextValidationSupport<?, ?, ?, ?, ?, ?> createValidationSupport();
|
||||||
|
|
||||||
|
IFluentPath createFluentPathExecutor(FhirContext theFhirContext);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,7 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
|
||||||
retVal.setFound(true);
|
retVal.setFound(true);
|
||||||
retVal.setSearchedForCode(code);
|
retVal.setSearchedForCode(code);
|
||||||
retVal.setSearchedForSystem(system);
|
retVal.setSearchedForSystem(system);
|
||||||
retVal.setCodeDisplay(result.getDisplay());
|
retVal.setCodeDisplay(result.asConceptDefinition().getDisplay());
|
||||||
retVal.setCodeSystemDisplayName("Unknown");
|
retVal.setCodeSystemDisplayName("Unknown");
|
||||||
retVal.setCodeSystemVersion("");
|
retVal.setCodeSystemVersion("");
|
||||||
return retVal;
|
return retVal;
|
||||||
|
|
|
@ -59,6 +59,8 @@ import ca.uhn.fhir.context.RuntimeCompositeDatatypeDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition;
|
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceBlockDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceBlockDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||||
|
import ca.uhn.fhir.fluentpath.IFluentPath;
|
||||||
import ca.uhn.fhir.model.api.ICompositeDatatype;
|
import ca.uhn.fhir.model.api.ICompositeDatatype;
|
||||||
import ca.uhn.fhir.model.api.IFhirVersion;
|
import ca.uhn.fhir.model.api.IFhirVersion;
|
||||||
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
||||||
|
@ -393,5 +395,15 @@ public class FhirDstu1 implements IFhirVersion {
|
||||||
return new IdDt();
|
return new IdDt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IContextValidationSupport<?, ?, ?, ?, ?, ?> createValidationSupport() {
|
||||||
|
throw new UnsupportedOperationException("Validation support is not supported in DSTU1 contexts");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IFluentPath createFluentPathExecutor(FhirContext theFhirContext) {
|
||||||
|
throw new UnsupportedOperationException("FluentPath is not supported in DSTU1 contexts");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@ import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||||
|
import ca.uhn.fhir.fluentpath.IFluentPath;
|
||||||
import ca.uhn.fhir.model.api.IFhirVersion;
|
import ca.uhn.fhir.model.api.IFhirVersion;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||||
|
@ -131,4 +133,15 @@ public class FhirDstu2 implements IFhirVersion {
|
||||||
return new IdDt();
|
return new IdDt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IContextValidationSupport<?, ?, ?, ?, ?, ?> createValidationSupport() {
|
||||||
|
throw new UnsupportedOperationException("Validation support is not supported in DSTU2 contexts");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IFluentPath createFluentPathExecutor(FhirContext theFhirContext) {
|
||||||
|
throw new UnsupportedOperationException("FluentPath is not supported in DSTU2 contexts");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,11 @@ import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.fluentpath.FluentPathDstu3;
|
||||||
import org.hl7.fhir.dstu3.hapi.rest.server.Dstu3BundleFactory;
|
import org.hl7.fhir.dstu3.hapi.rest.server.Dstu3BundleFactory;
|
||||||
import org.hl7.fhir.dstu3.hapi.rest.server.ServerCapabilityStatementProvider;
|
import org.hl7.fhir.dstu3.hapi.rest.server.ServerCapabilityStatementProvider;
|
||||||
import org.hl7.fhir.dstu3.hapi.rest.server.ServerProfileProvider;
|
import org.hl7.fhir.dstu3.hapi.rest.server.ServerProfileProvider;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.validation.DefaultProfileValidationSupport;
|
||||||
import org.hl7.fhir.dstu3.model.Coding;
|
import org.hl7.fhir.dstu3.model.Coding;
|
||||||
import org.hl7.fhir.dstu3.model.IdType;
|
import org.hl7.fhir.dstu3.model.IdType;
|
||||||
import org.hl7.fhir.dstu3.model.Reference;
|
import org.hl7.fhir.dstu3.model.Reference;
|
||||||
|
@ -43,6 +45,8 @@ import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||||
|
import ca.uhn.fhir.fluentpath.IFluentPath;
|
||||||
import ca.uhn.fhir.model.api.IFhirVersion;
|
import ca.uhn.fhir.model.api.IFhirVersion;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
@ -131,4 +135,14 @@ public class FhirDstu3 implements IFhirVersion {
|
||||||
return new IdType();
|
return new IdType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IContextValidationSupport<?, ?, ?, ?, ?, ?> createValidationSupport() {
|
||||||
|
return new DefaultProfileValidationSupport();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IFluentPath createFluentPathExecutor(FhirContext theFhirContext) {
|
||||||
|
return new FluentPathDstu3(theFhirContext);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package org.hl7.fhir.dstu3.hapi.fluentpath;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hl7.fhir.dstu3.hapi.validation.HapiWorkerContext;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
|
||||||
|
import org.hl7.fhir.dstu3.model.Base;
|
||||||
|
import org.hl7.fhir.dstu3.utils.FluentPathEngine;
|
||||||
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.fluentpath.FluentPathExecutionException;
|
||||||
|
import ca.uhn.fhir.fluentpath.IFluentPath;
|
||||||
|
|
||||||
|
public class FluentPathDstu3 implements IFluentPath {
|
||||||
|
|
||||||
|
private FluentPathEngine myEngine;
|
||||||
|
|
||||||
|
public FluentPathDstu3(FhirContext theCtx) {
|
||||||
|
if (!(theCtx.getValidationSupport() instanceof IValidationSupport)) {
|
||||||
|
throw new IllegalStateException("Validation support module configured on context appears to be for the wrong FHIR version- Does not extend " + IValidationSupport.class.getName());
|
||||||
|
}
|
||||||
|
IValidationSupport validationSupport = (IValidationSupport) theCtx.getValidationSupport();
|
||||||
|
myEngine = new FluentPathEngine(new HapiWorkerContext(theCtx, validationSupport));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public <T extends IBase> List<T> evaluate(IBase theInput, String thePath, Class<T> theReturnType) {
|
||||||
|
List<Base> result;
|
||||||
|
try {
|
||||||
|
result = myEngine.evaluate((Base)theInput, thePath);
|
||||||
|
} catch (FHIRException e) {
|
||||||
|
throw new FluentPathExecutionException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Base next : result) {
|
||||||
|
if (!theReturnType.isAssignableFrom(next.getClass())) {
|
||||||
|
throw new FluentPathExecutionException("FluentPath expression \"" + thePath + "\" returned unexpected type " + next.getClass().getSimpleName() + " - Expected " + theReturnType.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (List<T>) result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -11,8 +11,10 @@ import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||||
|
|
||||||
public interface IValidationSupport {
|
public interface IValidationSupport
|
||||||
|
extends ca.uhn.fhir.context.support.IContextValidationSupport<ConceptSetComponent, ValueSetExpansionComponent, StructureDefinition, CodeSystem, ConceptDefinitionComponent, IssueSeverity> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expands the given portion of a ValueSet
|
* Expands the given portion of a ValueSet
|
||||||
|
@ -21,14 +23,15 @@ public interface IValidationSupport {
|
||||||
* The portion to include
|
* The portion to include
|
||||||
* @return The expansion
|
* @return The expansion
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude);
|
ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load and return all possible structure definitions
|
* Load and return all possible structure definitions
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext);
|
List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch a code system by ID
|
* Fetch a code system by ID
|
||||||
*
|
*
|
||||||
|
@ -36,6 +39,7 @@ public interface IValidationSupport {
|
||||||
* The code system
|
* The code system
|
||||||
* @return The valueset (must not be null, but can be an empty ValueSet)
|
* @return The valueset (must not be null, but can be an empty ValueSet)
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem);
|
CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,8 +55,10 @@ public interface IValidationSupport {
|
||||||
* @return Returns the resource, or <code>null</code> if no resource with the
|
* @return Returns the resource, or <code>null</code> if no resource with the
|
||||||
* given URI can be found
|
* given URI can be found
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
<T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri);
|
<T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri);
|
||||||
|
|
||||||
|
@Override
|
||||||
StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl);
|
StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,9 +70,10 @@ public interface IValidationSupport {
|
||||||
* @return Returns <code>true</code> if codes in the given code system can be
|
* @return Returns <code>true</code> if codes in the given code system can be
|
||||||
* validated
|
* validated
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
boolean isCodeSystemSupported(FhirContext theContext, String theSystem);
|
boolean isCodeSystemSupported(FhirContext theContext, String theSystem);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates that the given code exists and if possible returns a display
|
* Validates that the given code exists and if possible returns a display
|
||||||
* name. This method is called to check codes which are found in "example"
|
* name. This method is called to check codes which are found in "example"
|
||||||
* binding fields (e.g. <code>Observation.code</code> in the default profile.
|
* binding fields (e.g. <code>Observation.code</code> in the default profile.
|
||||||
|
@ -79,46 +86,21 @@ public interface IValidationSupport {
|
||||||
* The display name, if it should also be validated
|
* The display name, if it should also be validated
|
||||||
* @return Returns a validation result object
|
* @return Returns a validation result object
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay);
|
CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay);
|
||||||
|
|
||||||
public class CodeValidationResult {
|
public class CodeValidationResult extends IContextValidationSupport.CodeValidationResult<ConceptDefinitionComponent, IssueSeverity> {
|
||||||
private ConceptDefinitionComponent definition;
|
|
||||||
private String message;
|
|
||||||
private IssueSeverity severity;
|
|
||||||
|
|
||||||
public CodeValidationResult(ConceptDefinitionComponent theNext) {
|
public CodeValidationResult(ConceptDefinitionComponent theNext) {
|
||||||
this.definition = theNext;
|
super(theNext);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeValidationResult(IssueSeverity severity, String message) {
|
public CodeValidationResult(IssueSeverity theSeverity, String theMessage) {
|
||||||
this.severity = severity;
|
super(theSeverity, theMessage);
|
||||||
this.message = message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeValidationResult(IssueSeverity severity, String message, ConceptDefinitionComponent definition) {
|
public CodeValidationResult(IssueSeverity severity, String message, ConceptDefinitionComponent definition) {
|
||||||
this.severity = severity;
|
super(severity, message, definition);
|
||||||
this.message = message;
|
|
||||||
this.definition = definition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConceptDefinitionComponent asConceptDefinition() {
|
|
||||||
return definition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDisplay() {
|
|
||||||
return definition == null ? "??" : definition.getDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IssueSeverity getSeverity() {
|
|
||||||
return severity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOk() {
|
|
||||||
return definition != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
package ca.uhn.fhir.fluentpath;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hl7.fhir.dstu3.model.HumanName;
|
||||||
|
import org.hl7.fhir.dstu3.model.Patient;
|
||||||
|
import org.hl7.fhir.dstu3.model.StringType;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
|
||||||
|
public class FluentPathTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEvaluateNormal() {
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.addName().addFamily("N1F1").addGiven("N1G1").addGiven("N1G2");
|
||||||
|
p.addName().addFamily("N2F1").addGiven("N2G1").addGiven("N2G2");
|
||||||
|
|
||||||
|
IFluentPath fp = ourCtx.newFluentPath();
|
||||||
|
List<HumanName> names = fp.evaluate(p, "Patient.name", HumanName.class);
|
||||||
|
assertEquals(2, names.size());
|
||||||
|
assertEquals("N1F1", names.get(0).getFamilyAsSingleString());
|
||||||
|
assertEquals("N1G1 N1G2", names.get(0).getGivenAsSingleString());
|
||||||
|
assertEquals("N2F1", names.get(1).getFamilyAsSingleString());
|
||||||
|
assertEquals("N2G1 N2G2", names.get(1).getGivenAsSingleString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEvaluateUnknownPath() {
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.addName().addFamily("N1F1").addGiven("N1G1").addGiven("N1G2");
|
||||||
|
p.addName().addFamily("N2F1").addGiven("N2G1").addGiven("N2G2");
|
||||||
|
|
||||||
|
IFluentPath fp = ourCtx.newFluentPath();
|
||||||
|
List<HumanName> names = fp.evaluate(p, "Patient.nameFOO", HumanName.class);
|
||||||
|
assertEquals(0, names.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEvaluateInvalidPath() {
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.addName().addFamily("N1F1").addGiven("N1G1").addGiven("N1G2");
|
||||||
|
p.addName().addFamily("N2F1").addGiven("N2G1").addGiven("N2G2");
|
||||||
|
|
||||||
|
IFluentPath fp = ourCtx.newFluentPath();
|
||||||
|
try {
|
||||||
|
fp.evaluate(p, "Patient....nameFOO", HumanName.class);
|
||||||
|
} catch (FluentPathExecutionException e) {
|
||||||
|
assertEquals("org.hl7.fhir.dstu3.utils.FHIRLexer$FHIRLexerException: Error in Patient....nameFOO at 1, 1: Found . expecting a token name", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEvaluateWrongType() {
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.addName().addFamily("N1F1").addGiven("N1G1").addGiven("N1G2");
|
||||||
|
p.addName().addFamily("N2F1").addGiven("N2G1").addGiven("N2G2");
|
||||||
|
|
||||||
|
IFluentPath fp = ourCtx.newFluentPath();
|
||||||
|
try {
|
||||||
|
fp.evaluate(p, "Patient.name", StringType.class);
|
||||||
|
} catch (FluentPathExecutionException e) {
|
||||||
|
assertEquals("FluentPath expression \"Patient.name\" returned unexpected type HumanName - Expected org.hl7.fhir.dstu3.model.StringType", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() {
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -39,6 +39,8 @@ import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||||
|
import ca.uhn.fhir.fluentpath.IFluentPath;
|
||||||
import ca.uhn.fhir.model.api.IFhirVersion;
|
import ca.uhn.fhir.model.api.IFhirVersion;
|
||||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
@ -129,4 +131,16 @@ public class FhirDstu2Hl7Org implements IFhirVersion {
|
||||||
return new IdType();
|
return new IdType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IContextValidationSupport<?, ?, ?, ?, ?, ?> createValidationSupport() {
|
||||||
|
throw new UnsupportedOperationException("Validation support is not supported in DSTU2 contexts");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IFluentPath createFluentPathExecutor(FhirContext theFhirContext) {
|
||||||
|
throw new UnsupportedOperationException("FluentPath is not supported in DSTU2 contexts");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue