diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java
index b0e7d69c9ac..f9bf329011f 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java
@@ -3,7 +3,7 @@ package ca.uhn.fhir.context;
import ca.uhn.fhir.context.api.AddProfileTagEnum;
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
import ca.uhn.fhir.context.support.IValidationSupport;
-import ca.uhn.fhir.fluentpath.IFluentPath;
+import ca.uhn.fhir.fhirpath.IFhirPath;
import ca.uhn.fhir.i18n.HapiLocalizer;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IFhirVersion;
@@ -625,12 +625,21 @@ public class FhirContext {
}
/**
- * Creates a new FluentPath engine which can be used to exvaluate
+ * @since 2.2
+ * @deprecated Deprecated in HAPI FHIR 5.0.0. Use {@link #newFhirPath()} instead.
+ */
+ @Deprecated
+ public IFhirPath newFluentPath() {
+ return newFhirPath();
+ }
+
+ /**
+ * Creates a new FhirPath engine which can be used to evaluate
* path expressions over FHIR resources. Note that this engine will use the
* {@link IValidationSupport context validation support} module which is
* configured on the context at the time this method is called.
*
- * In other words, call {@link #setValidationSupport(IValidationSupport)} before
+ * In other words, you may wish to call {@link #setValidationSupport(IValidationSupport)} before
* calling {@link #newFluentPath()}
*
*
@@ -640,9 +649,9 @@ public class FhirContext {
* {@link UnsupportedOperationException}
*
*
- * @since 2.2
+ * @since 5.0.0
*/
- public IFluentPath newFluentPath() {
+ public IFhirPath newFhirPath() {
return myVersion.createFluentPathExecutor(this);
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/fluentpath/FluentPathExecutionException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/fhirpath/FhirPathExecutionException.java
similarity index 73%
rename from hapi-fhir-base/src/main/java/ca/uhn/fhir/fluentpath/FluentPathExecutionException.java
rename to hapi-fhir-base/src/main/java/ca/uhn/fhir/fhirpath/FhirPathExecutionException.java
index 8cd3e96f0a6..04413995318 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/fluentpath/FluentPathExecutionException.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/fhirpath/FhirPathExecutionException.java
@@ -1,4 +1,4 @@
-package ca.uhn.fhir.fluentpath;
+package ca.uhn.fhir.fhirpath;
/*
* #%L
@@ -23,18 +23,18 @@ 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
+ * This exception is thrown if a FHIRPath expression can not be executed successfully
* for any reason
*/
-public class FluentPathExecutionException extends InternalErrorException {
+public class FhirPathExecutionException extends InternalErrorException {
private static final long serialVersionUID = 1L;
- public FluentPathExecutionException(Throwable theCause) {
+ public FhirPathExecutionException(Throwable theCause) {
super(theCause);
}
- public FluentPathExecutionException(String theMessage) {
+ public FhirPathExecutionException(String theMessage) {
super(theMessage);
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/fluentpath/IFluentPath.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/fhirpath/IFhirPath.java
similarity index 96%
rename from hapi-fhir-base/src/main/java/ca/uhn/fhir/fluentpath/IFluentPath.java
rename to hapi-fhir-base/src/main/java/ca/uhn/fhir/fhirpath/IFhirPath.java
index 8d225b20c27..a15f716c37f 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/fluentpath/IFluentPath.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/fhirpath/IFhirPath.java
@@ -1,4 +1,4 @@
-package ca.uhn.fhir.fluentpath;
+package ca.uhn.fhir.fhirpath;
/*
* #%L
@@ -25,7 +25,7 @@ import java.util.Optional;
import org.hl7.fhir.instance.model.api.IBase;
-public interface IFluentPath {
+public interface IFhirPath {
/**
* Apply the given FluentPath expression against the given input and return
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/IFhirVersion.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/IFhirVersion.java
index f3e8c02542d..164f5969b9b 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/IFhirVersion.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/IFhirVersion.java
@@ -23,10 +23,10 @@ package ca.uhn.fhir.model.api;
import java.io.InputStream;
import java.util.Date;
+import ca.uhn.fhir.fhirpath.IFhirPath;
import org.hl7.fhir.instance.model.api.*;
import ca.uhn.fhir.context.*;
-import ca.uhn.fhir.fluentpath.IFluentPath;
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
/**
@@ -38,7 +38,7 @@ import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
*/
public interface IFhirVersion {
- IFluentPath createFluentPathExecutor(FhirContext theFhirContext);
+ IFhirPath createFluentPathExecutor(FhirContext theFhirContext);
IBaseResource generateProfile(RuntimeResourceDefinition theRuntimeResourceDefinition, String theServerBase);
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/narrative2/BaseNarrativeGenerator.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/narrative2/BaseNarrativeGenerator.java
index f8a4193cf16..c73c545c407 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/narrative2/BaseNarrativeGenerator.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/narrative2/BaseNarrativeGenerator.java
@@ -24,7 +24,7 @@ import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
-import ca.uhn.fhir.fluentpath.IFluentPath;
+import ca.uhn.fhir.fhirpath.IFhirPath;
import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.hl7.fhir.instance.model.api.IBase;
@@ -120,7 +120,7 @@ public abstract class BaseNarrativeGenerator implements INarrativeGenerator {
if (theFhirContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
return Collections.singletonList(theResource);
}
- IFluentPath fhirPath = theFhirContext.newFluentPath();
+ IFhirPath fhirPath = theFhirContext.newFluentPath();
return fhirPath.evaluate(theResource, theContextPath, IBase.class);
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java
index 50aec5b8393..8678d76cae8 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java
@@ -259,6 +259,7 @@ public class Constants {
*
*/
public static final String EXT_META_SOURCE = "http://hapifhir.io/fhir/StructureDefinition/resource-meta-source";
+ public static final String PARAM_FHIRPATH = "_fhirpath";
static {
CHARSET_UTF8 = StandardCharsets.UTF_8;
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ParametersUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ParametersUtil.java
index f4db4b682c2..42292361c26 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ParametersUtil.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ParametersUtil.java
@@ -238,7 +238,7 @@ public class ParametersUtil {
addPart(theContext, theParameter, theName, coding);
}
- private static void addPart(FhirContext theContext, IBase theParameter, String theName, IBase theValue) {
+ public static void addPart(FhirContext theContext, IBase theParameter, String theName, IBase theValue) {
BaseRuntimeElementCompositeDefinition> def = (BaseRuntimeElementCompositeDefinition>) theContext.getElementDefinition(theParameter.getClass());
BaseRuntimeChildDefinition partChild = def.getChildByName("part");
@@ -252,4 +252,19 @@ public class ParametersUtil {
partChildElem.getChildByName("value[x]").getMutator().addValue(part, theValue);
}
+
+ public static void addPartResource(FhirContext theContext, IBase theParameter, String theName, IBaseResource theValue) {
+ BaseRuntimeElementCompositeDefinition> def = (BaseRuntimeElementCompositeDefinition>) theContext.getElementDefinition(theParameter.getClass());
+ BaseRuntimeChildDefinition partChild = def.getChildByName("part");
+
+ BaseRuntimeElementCompositeDefinition> partChildElem = (BaseRuntimeElementCompositeDefinition>) partChild.getChildByName("part");
+ IBase part = partChildElem.newInstance();
+ partChild.getMutator().addValue(theParameter, part);
+
+ IPrimitiveType name = (IPrimitiveType) theContext.getElementDefinition("string").newInstance();
+ name.setValue(theName);
+ partChildElem.getChildByName("name").getMutator().addValue(part, name);
+
+ partChildElem.getChildByName("resource").getMutator().addValue(part, theValue);
+ }
}
diff --git a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ServletExamples.java b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ServletExamples.java
index 96803d8bda2..eaf84d6ce1f 100644
--- a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ServletExamples.java
+++ b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ServletExamples.java
@@ -32,11 +32,11 @@ import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import java.util.Arrays;
-@SuppressWarnings("serial")
+@SuppressWarnings({"serial", "RedundantThrows", "InnerClassMayBeStatic"})
public class ServletExamples {
// START SNIPPET: loggingInterceptor
- @WebServlet(urlPatterns = { "/fhir/*" }, displayName = "FHIR Server")
+ @WebServlet(urlPatterns = { "/fhir/*" }, displayName = "FHIR Server")
public class RestfulServerWithLogging extends RestfulServer {
@Override
@@ -121,6 +121,24 @@ public class ServletExamples {
}
// END SNIPPET: exceptionInterceptor
+ // START SNIPPET: fhirPathInterceptor
+ @WebServlet(urlPatterns = { "/fhir/*" }, displayName = "FHIR Server")
+ public class RestfulServerWithFhirPath extends RestfulServer {
+
+ @Override
+ protected void initialize() throws ServletException {
+
+ // ... define your resource providers here ...
+
+ // Now register the interceptor
+ FhirPathFilterInterceptor interceptor = new FhirPathFilterInterceptor();
+ registerInterceptor(interceptor);
+
+ }
+
+ }
+ // END SNIPPET: fhirPathInterceptor
+
// START SNIPPET: responseHighlighterInterceptor
@WebServlet(urlPatterns = { "/fhir/*" }, displayName = "FHIR Server")
public class RestfulServerWithResponseHighlighter extends RestfulServer {
diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_3_0/1769-add-fhirpath-interceptor.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_3_0/1769-add-fhirpath-interceptor.yaml
new file mode 100644
index 00000000000..c6e9a32c0d5
--- /dev/null
+++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_3_0/1769-add-fhirpath-interceptor.yaml
@@ -0,0 +1,6 @@
+---
+type: add
+issue: 1769
+title: A new built-in server interceptor called FhirPathFilterInterceptor has been added. This interceptor
+ evaluates an arbitrary FHIRPath expression against the resource being returned and replaces the response
+ with a Parameters resource containing the results of the evaluation.
diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_3_0/changes.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_3_0/changes.yaml
index aa375e46680..08691d1826a 100644
--- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_3_0/changes.yaml
+++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_3_0/changes.yaml
@@ -17,3 +17,11 @@
[Migrating to HAPI FHIR 5.x](/hapi-fhir/docs/validation/instance_validator.html#migrating-to-hapi-fhir-5x)
for details on how to account for this change in your code.
"
+- item:
+ issue: "1769"
+ type: "change"
+ title: "**Breaking Change**:
+ The `IFluentPath` interface has been renamed to `IFhirPath`, and the `FhirContext#newFluentPath()` method
+ has been replaced with an equivalent `FhirContext.newFhirPath()`. The FhirPath expression language was initially
+ called FluentPath before being renamed, so this change brings HAPI FHIR inline with the correct naming.
+ "
diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md
index 6c166e8cce9..35f20dc14ca 100644
--- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md
+++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md
@@ -50,6 +50,52 @@ The following example shows how to register the ExceptionHandlingInterceptor.
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ServletExamples.java|exceptionInterceptor}}
```
+# Response Customizing: Evaluate FHIRPath
+
+The FhirPathFilterInterceptor looks for a request URL parameter in the form `_fhirpath=(expression)` in all REST requests. If this parameter is found, the value is treated as a [FHIRPath](http://hl7.org/fhirpath/) expression. The response resource will be replaced with a [Parameters](hl7.org/fhir/parameters.html) resource containing the results of the given expression applied against the response resource.
+
+* [FhirPathFilterInterceptor JavaDoc](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/interceptor/FhirPathFilterInterceptor.html)
+* [FhirPathFilterInterceptor Source](https://github.com/jamesagnew/hapi-fhir/blob/master/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/FhirPathFilterInterceptor.java)
+
+The following example shows how to register the ExceptionHandlingInterceptor.
+
+```java
+{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ServletExamples.java|exceptionInterceptor}}
+```
+
+An example URL to invoke this function is shown below:
+
+```url
+https://hapi.fhir.org/baseR4/Patient?_fhirpath=Bundle.entry.resource.as(Patient).name&_pretty=true
+```
+
+A sample response to this query is shown below:
+
+```json
+{
+ "resourceType": "Parameters",
+ "parameter": [ {
+ "name": "result",
+ "part": [ {
+ "name": "expression",
+ "valueString": "Bundle.entry.resource.as(Patient).name"
+ }, {
+ "name": "result",
+ "valueHumanName": {
+ "family": "Simpson",
+ "given": [ "Homer", "Jay" ]
+ }
+ }, {
+ "name": "result",
+ "valueHumanName": {
+ "family": "Simpson",
+ "given": [ "Grandpa" ]
+ }
+ } ]
+ } ]
+}
+```
+
# Validation: Request and Response Validation
HAPI FHIR provides a pair of interceptors that can be used to validate incoming requests received by the server, as well as outgoing responses generated by the server.
diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java
index e2a164287b9..4a767f35d5f 100644
--- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java
+++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java
@@ -28,6 +28,7 @@ import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.BanUnsupportedHttpMethodsInterceptor;
import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor;
+import ca.uhn.fhir.rest.server.interceptor.FhirPathFilterInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
import ca.uhn.fhirtest.config.TestDstu2Config;
import ca.uhn.fhirtest.config.TestDstu3Config;
@@ -198,6 +199,11 @@ public class TestRestfulServer extends RestfulServer {
CorsInterceptor corsInterceptor = new CorsInterceptor();
registerInterceptor(corsInterceptor);
+ /*
+ * Enable FHIRPath evaluation
+ */
+ registerInterceptor(new FhirPathFilterInterceptor());
+
/*
* Enable version conversion
*/
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/FhirPathFilterInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/FhirPathFilterInterceptor.java
new file mode 100644
index 00000000000..c254be28f19
--- /dev/null
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/FhirPathFilterInterceptor.java
@@ -0,0 +1,70 @@
+package ca.uhn.fhir.rest.server.interceptor;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.fhirpath.FhirPathExecutionException;
+import ca.uhn.fhir.fhirpath.IFhirPath;
+import ca.uhn.fhir.interceptor.api.Hook;
+import ca.uhn.fhir.interceptor.api.Pointcut;
+import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.rest.api.server.RequestDetails;
+import ca.uhn.fhir.rest.api.server.ResponseDetails;
+import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
+import ca.uhn.fhir.util.ParametersUtil;
+import org.hl7.fhir.instance.model.api.IBase;
+import org.hl7.fhir.instance.model.api.IBaseParameters;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+
+import java.util.List;
+
+import static org.apache.commons.lang3.StringUtils.isNotBlank;
+
+/**
+ * This interceptor looks for a URL parameter on requests called _fhirpath
and
+ * replaces the resource being returned with a Parameters resource containing the results of
+ * the given FHIRPath expression evaluated against the resource that would otherwise
+ * have been returned.
+ *
+ * @see Interceptors - Response Customization: Evaluate FHIRPath
+ * @since 5.0.0
+ */
+public class FhirPathFilterInterceptor {
+
+ @Hook(Pointcut.SERVER_OUTGOING_RESPONSE)
+ public void preProcessOutgoingResponse(RequestDetails theRequestDetails, ResponseDetails theResponseDetails) {
+ IBaseResource responseResource = theResponseDetails.getResponseResource();
+ if (responseResource != null) {
+ String[] fhirPathParams = theRequestDetails.getParameters().get(Constants.PARAM_FHIRPATH);
+ if (fhirPathParams != null) {
+
+ FhirContext ctx = theRequestDetails.getFhirContext();
+ IBaseParameters responseParameters = ParametersUtil.newInstance(ctx);
+
+ for (String expression : fhirPathParams) {
+ if (isNotBlank(expression)) {
+ IBase resultPart = ParametersUtil.addParameterToParameters(ctx, responseParameters, "result");
+ ParametersUtil.addPartString(ctx, resultPart, "expression", expression);
+
+ IFhirPath fhirPath = ctx.newFhirPath();
+ List outputs;
+ try {
+ outputs = fhirPath.evaluate(responseResource, expression, IBase.class);
+ } catch (FhirPathExecutionException e) {
+ throw new InvalidRequestException("Error parsing FHIRPath expression: " + e.getMessage());
+ }
+
+ for (IBase nextOutput : outputs) {
+ if (nextOutput instanceof IBaseResource) {
+ ParametersUtil.addPartResource(ctx, resultPart, "result", (IBaseResource) nextOutput);
+ } else {
+ ParametersUtil.addPart(ctx, resultPart, "result", nextOutput);
+ }
+ }
+ }
+ }
+
+ theResponseDetails.setResponseResource(responseParameters);
+ }
+ }
+ }
+
+}
diff --git a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java
index 6ed05ffa58a..731db1e8a57 100644
--- a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java
+++ b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java
@@ -60,7 +60,7 @@ import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition;
import ca.uhn.fhir.context.RuntimeResourceBlockDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.support.IContextValidationSupport;
-import ca.uhn.fhir.fluentpath.IFluentPath;
+import ca.uhn.fhir.fhirpath.IFluentPath;
import ca.uhn.fhir.model.api.ICompositeDatatype;
import ca.uhn.fhir.model.api.IFhirVersion;
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu2016may/hapi/ctx/FhirDstu2_1.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu2016may/hapi/ctx/FhirDstu2_1.java
index 250d7170d10..dd9a1c39a1c 100644
--- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu2016may/hapi/ctx/FhirDstu2_1.java
+++ b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu2016may/hapi/ctx/FhirDstu2_1.java
@@ -30,7 +30,7 @@ import org.hl7.fhir.dstu2016may.model.*;
import org.hl7.fhir.instance.model.api.*;
import ca.uhn.fhir.context.*;
-import ca.uhn.fhir.fluentpath.IFluentPath;
+import ca.uhn.fhir.fhirpath.IFhirPath;
import ca.uhn.fhir.model.api.IFhirVersion;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
@@ -41,7 +41,7 @@ public class FhirDstu2_1 implements IFhirVersion {
private String myId;
@Override
- public IFluentPath createFluentPathExecutor(FhirContext theFhirContext) {
+ public IFhirPath createFluentPathExecutor(FhirContext theFhirContext) {
throw new UnsupportedOperationException("FluentPath is not supported in DSTU2 contexts");
}
diff --git a/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java b/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java
index ea7ad545b30..53b45ab795a 100644
--- a/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java
+++ b/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java
@@ -23,11 +23,11 @@ package ca.uhn.fhir.model.dstu2;
import java.io.InputStream;
import java.util.Date;
+import ca.uhn.fhir.fhirpath.IFhirPath;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.*;
import ca.uhn.fhir.context.*;
-import ca.uhn.fhir.fluentpath.IFluentPath;
import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.base.composite.*;
import ca.uhn.fhir.model.dstu2.composite.*;
@@ -42,7 +42,7 @@ public class FhirDstu2 implements IFhirVersion {
private String myId;
@Override
- public IFluentPath createFluentPathExecutor(FhirContext theFhirContext) {
+ public IFhirPath createFluentPathExecutor(FhirContext theFhirContext) {
throw new UnsupportedOperationException("FluentPath is not supported in DSTU2 contexts");
}
diff --git a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/ctx/FhirDstu3.java b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/ctx/FhirDstu3.java
index a2037e1d788..1980ce93b25 100644
--- a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/ctx/FhirDstu3.java
+++ b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/ctx/FhirDstu3.java
@@ -24,13 +24,13 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
-import ca.uhn.fhir.fluentpath.IFluentPath;
+import ca.uhn.fhir.fhirpath.IFhirPath;
import ca.uhn.fhir.model.api.IFhirVersion;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
import ca.uhn.fhir.util.ReflectionUtil;
import org.apache.commons.lang3.StringUtils;
-import org.hl7.fhir.dstu3.hapi.fluentpath.FluentPathDstu3;
+import org.hl7.fhir.dstu3.hapi.fluentpath.FhirPathDstu3;
import org.hl7.fhir.dstu3.hapi.rest.server.Dstu3BundleFactory;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.instance.model.api.*;
@@ -44,8 +44,8 @@ public class FhirDstu3 implements IFhirVersion {
private String myId;
@Override
- public IFluentPath createFluentPathExecutor(FhirContext theFhirContext) {
- return new FluentPathDstu3(theFhirContext);
+ public IFhirPath createFluentPathExecutor(FhirContext theFhirContext) {
+ return new FhirPathDstu3(theFhirContext);
}
@Override
diff --git a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/fluentpath/FluentPathDstu3.java b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/fluentpath/FhirPathDstu3.java
similarity index 74%
rename from hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/fluentpath/FluentPathDstu3.java
rename to hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/fluentpath/FhirPathDstu3.java
index 9eb25f1d369..84bbca753dc 100644
--- a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/fluentpath/FluentPathDstu3.java
+++ b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/fluentpath/FhirPathDstu3.java
@@ -2,8 +2,8 @@ package org.hl7.fhir.dstu3.hapi.fluentpath;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.support.IValidationSupport;
-import ca.uhn.fhir.fluentpath.FluentPathExecutionException;
-import ca.uhn.fhir.fluentpath.IFluentPath;
+import ca.uhn.fhir.fhirpath.FhirPathExecutionException;
+import ca.uhn.fhir.fhirpath.IFhirPath;
import org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext;
import org.hl7.fhir.dstu3.model.Base;
import org.hl7.fhir.dstu3.utils.FHIRPathEngine;
@@ -13,11 +13,11 @@ import org.hl7.fhir.instance.model.api.IBase;
import java.util.List;
import java.util.Optional;
-public class FluentPathDstu3 implements IFluentPath {
+public class FhirPathDstu3 implements IFhirPath {
private FHIRPathEngine myEngine;
- public FluentPathDstu3(FhirContext theCtx) {
+ public FhirPathDstu3(FhirContext theCtx) {
IValidationSupport validationSupport = theCtx.getValidationSupport();
myEngine = new FHIRPathEngine(new HapiWorkerContext(theCtx, validationSupport));
}
@@ -29,12 +29,12 @@ public class FluentPathDstu3 implements IFluentPath {
try {
result = myEngine.evaluate((Base)theInput, thePath);
} catch (FHIRException e) {
- throw new FluentPathExecutionException(e);
+ throw new FhirPathExecutionException(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());
+ throw new FhirPathExecutionException("FluentPath expression \"" + thePath + "\" returned unexpected type " + next.getClass().getSimpleName() + " - Expected " + theReturnType.getName());
}
}
diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/dstu2/hapi/ctx/FhirDstu2Hl7Org.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/dstu2/hapi/ctx/FhirDstu2Hl7Org.java
index 6048745858f..dfc192139b1 100644
--- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/dstu2/hapi/ctx/FhirDstu2Hl7Org.java
+++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/dstu2/hapi/ctx/FhirDstu2Hl7Org.java
@@ -24,12 +24,12 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
+import ca.uhn.fhir.fhirpath.IFhirPath;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.dstu2.model.*;
import org.hl7.fhir.instance.model.api.*;
import ca.uhn.fhir.context.*;
-import ca.uhn.fhir.fluentpath.IFluentPath;
import ca.uhn.fhir.model.api.IFhirVersion;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
@@ -41,7 +41,7 @@ public class FhirDstu2Hl7Org implements IFhirVersion {
private String myId;
@Override
- public IFluentPath createFluentPathExecutor(FhirContext theFhirContext) {
+ public IFhirPath createFluentPathExecutor(FhirContext theFhirContext) {
throw new UnsupportedOperationException("FluentPath is not supported in DSTU2 contexts");
}
diff --git a/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/ctx/FhirR4.java b/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/ctx/FhirR4.java
index cb1eeeb2358..1014f31e2b4 100644
--- a/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/ctx/FhirR4.java
+++ b/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/ctx/FhirR4.java
@@ -26,12 +26,12 @@ import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.*;
-import org.hl7.fhir.r4.hapi.fluentpath.FluentPathR4;
+import org.hl7.fhir.r4.hapi.fluentpath.FhirPathR4;
import org.hl7.fhir.r4.hapi.rest.server.R4BundleFactory;
import org.hl7.fhir.r4.model.*;
import ca.uhn.fhir.context.*;
-import ca.uhn.fhir.fluentpath.IFluentPath;
+import ca.uhn.fhir.fhirpath.IFhirPath;
import ca.uhn.fhir.model.api.IFhirVersion;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
@@ -42,8 +42,8 @@ public class FhirR4 implements IFhirVersion {
private String myId;
@Override
- public IFluentPath createFluentPathExecutor(FhirContext theFhirContext) {
- return new FluentPathR4(theFhirContext);
+ public IFhirPath createFluentPathExecutor(FhirContext theFhirContext) {
+ return new FhirPathR4(theFhirContext);
}
@Override
diff --git a/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/fluentpath/FluentPathR4.java b/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/fluentpath/FhirPathR4.java
similarity index 75%
rename from hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/fluentpath/FluentPathR4.java
rename to hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/fluentpath/FhirPathR4.java
index 5a34d3d8ff3..eb1ca366b43 100644
--- a/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/fluentpath/FluentPathR4.java
+++ b/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/fluentpath/FhirPathR4.java
@@ -2,8 +2,8 @@ package org.hl7.fhir.r4.hapi.fluentpath;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.support.IValidationSupport;
-import ca.uhn.fhir.fluentpath.FluentPathExecutionException;
-import ca.uhn.fhir.fluentpath.IFluentPath;
+import ca.uhn.fhir.fhirpath.FhirPathExecutionException;
+import ca.uhn.fhir.fhirpath.IFhirPath;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
@@ -13,11 +13,11 @@ import org.hl7.fhir.r4.utils.FHIRPathEngine;
import java.util.List;
import java.util.Optional;
-public class FluentPathR4 implements IFluentPath {
+public class FhirPathR4 implements IFhirPath {
private FHIRPathEngine myEngine;
- public FluentPathR4(FhirContext theCtx) {
+ public FhirPathR4(FhirContext theCtx) {
IValidationSupport validationSupport = theCtx.getValidationSupport();
myEngine = new FHIRPathEngine(new HapiWorkerContext(theCtx, validationSupport));
}
@@ -29,12 +29,12 @@ public class FluentPathR4 implements IFluentPath {
try {
result = myEngine.evaluate((Base) theInput, thePath);
} catch (FHIRException e) {
- throw new FluentPathExecutionException(e);
+ throw new FhirPathExecutionException(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());
+ throw new FhirPathExecutionException("FluentPath expression \"" + thePath + "\" returned unexpected type " + next.getClass().getSimpleName() + " - Expected " + theReturnType.getName());
}
}
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/FhirPathFilterInterceptorTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/FhirPathFilterInterceptorTest.java
new file mode 100644
index 00000000000..68bc9ad406d
--- /dev/null
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/FhirPathFilterInterceptorTest.java
@@ -0,0 +1,170 @@
+package ca.uhn.fhir.rest.server.interceptor;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.rest.client.api.IGenericClient;
+import ca.uhn.fhir.test.utilities.HttpClientRule;
+import ca.uhn.fhir.test.utilities.server.HashMapResourceProviderRule;
+import ca.uhn.fhir.test.utilities.server.RestfulServerRule;
+import ca.uhn.fhir.util.UrlUtil;
+import com.google.common.base.Charsets;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.hl7.fhir.instance.model.api.IIdType;
+import org.hl7.fhir.r4.model.Patient;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+public class FhirPathFilterInterceptorTest {
+
+ private static final Logger ourLog = LoggerFactory.getLogger(FhirPathFilterInterceptorTest.class);
+ @ClassRule
+ public static HttpClientRule ourClientRule = new HttpClientRule();
+ private static FhirContext ourCtx = FhirContext.forR4();
+ @ClassRule
+ public static RestfulServerRule ourServerRule = new RestfulServerRule(ourCtx);
+ @ClassRule
+ public static HashMapResourceProviderRule ourProviderRule = new HashMapResourceProviderRule<>(ourServerRule, Patient.class);
+ private IGenericClient myClient;
+ private String myBaseUrl;
+ private CloseableHttpClient myHttpClient;
+ private IIdType myPatientId;
+
+ @Before
+ public void before() {
+ ourProviderRule.clear();
+ ourServerRule.getRestfulServer().getInterceptorService().unregisterAllInterceptors();
+ ourServerRule.getRestfulServer().getInterceptorService().registerInterceptor(new FhirPathFilterInterceptor());
+
+ myClient = ourServerRule.getFhirClient();
+ myBaseUrl = "http://localhost:" + ourServerRule.getPort();
+ myHttpClient = ourClientRule.getClient();
+ }
+
+ @Test
+ public void testUnfilteredResponse() throws IOException {
+ createPatient();
+
+ HttpGet request = new HttpGet(myPatientId.getValue());
+ try (CloseableHttpResponse response = myHttpClient.execute(request)) {
+ String responseText = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
+ ourLog.info("Response:\n{}", responseText);
+ assertThat(responseText, containsString("\"system\": \"http://identifiers/1\""));
+ assertThat(responseText, containsString("\"given\": [ \"Homer\", \"Jay\" ]"));
+ }
+ }
+
+
+ @Test
+ public void testUnfilteredResponse_WithResponseHighlightingInterceptor() throws IOException {
+ ourServerRule.getRestfulServer().registerInterceptor(new ResponseHighlighterInterceptor());
+ createPatient();
+
+ HttpGet request = new HttpGet(myPatientId.getValue() + "?_format=" + Constants.FORMATS_HTML_JSON);
+ try (CloseableHttpResponse response = myHttpClient.execute(request)) {
+ String responseText = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
+ ourLog.info("Response:\n{}", responseText);
+ assertThat(responseText, containsString(""system": "http://identifiers/1""));
+ assertThat(responseText, containsString(""given": [ "Homer", "Jay" ]"));
+ }
+ }
+
+ @Test
+ public void testFilteredResponse() throws IOException {
+ createPatient();
+
+ HttpGet request = new HttpGet(myPatientId + "?_fhirpath=Patient.identifier&_pretty=true");
+ try (CloseableHttpResponse response = myHttpClient.execute(request)) {
+ String responseText = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
+ ourLog.info("Response:\n{}", responseText);
+ assertThat(responseText, containsString("\"system\": \"http://identifiers/1\""));
+ assertThat(responseText, not(containsString("\"given\": [ \"Homer\", \"Jay\" ]")));
+ }
+
+ }
+
+ @Test
+ public void testFilteredResponse_ExpressionReturnsResource() throws IOException {
+ createPatient();
+
+ HttpGet request = new HttpGet(myPatientId + "?_fhirpath=Patient&_pretty=true");
+ try (CloseableHttpResponse response = myHttpClient.execute(request)) {
+ String responseText = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
+ ourLog.info("Response:\n{}", responseText);
+ assertThat(responseText, containsString("\"resource\": {"));
+ assertThat(responseText, containsString("\"system\": \"http://identifiers/1\""));
+ assertThat(responseText, containsString("\"given\": [ \"Homer\", \"Jay\" ]"));
+ }
+
+ }
+
+ @Test
+ public void testFilteredResponse_ExpressionIsInvalid() throws IOException {
+ createPatient();
+
+ HttpGet request = new HttpGet(myPatientId + "?_fhirpath=" + UrlUtil.escapeUrlParam("***"));
+ try (CloseableHttpResponse response = myHttpClient.execute(request)) {
+ String responseText = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
+ ourLog.info("Response:\n{}", responseText);
+ assertEquals(400, response.getStatusLine().getStatusCode());
+ assertThat(responseText, containsString("Error parsing FHIRPath expression: Error performing *: left operand has more than one value"));
+ }
+
+ }
+
+ @Test
+ public void testFilteredResponseBundle() throws IOException {
+ createPatient();
+
+ HttpGet request = new HttpGet(myBaseUrl + "/Patient?_fhirpath=Bundle.entry.resource.as(Patient).name&_pretty=true");
+ try (CloseableHttpResponse response = myHttpClient.execute(request)) {
+ String responseText = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
+ ourLog.info("Response:\n{}", responseText);
+ assertThat(responseText, containsString(
+ " \"valueHumanName\": {\n" +
+ " \"family\": \"Simpson\",\n" +
+ " \"given\": [ \"Homer\", \"Jay\" ]\n" +
+ " }"
+ ));
+ }
+
+ }
+
+ @Test
+ public void testFilteredResponse_WithResponseHighlightingInterceptor() throws IOException {
+ ourServerRule.getRestfulServer().registerInterceptor(new ResponseHighlighterInterceptor());
+ createPatient();
+
+ HttpGet request = new HttpGet(myPatientId + "?_fhirpath=Patient.identifier&_format=" + Constants.FORMATS_HTML_JSON);
+ try (CloseableHttpResponse response = myHttpClient.execute(request)) {
+ String responseText = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
+ ourLog.info("Response:\n{}", responseText);
+ assertThat(responseText, containsString(""system": "http://identifiers/1""));
+ assertThat(responseText, not(containsString(""given": [ "Homer", "Jay" ]")));
+ }
+
+ }
+
+ private void createPatient() {
+ Patient p = new Patient();
+ p.setActive(true);
+ p.addIdentifier().setSystem("http://identifiers/1").setValue("value-1");
+ p.addIdentifier().setSystem("http://identifiers/2").setValue("value-2");
+ p.addName().setFamily("Simpson").addGiven("Homer").addGiven("Jay");
+ p.addName().setFamily("Simpson").addGiven("Grandpa");
+ myPatientId = myClient.create().resource(p).execute().getId().withServerBase(myBaseUrl, "Patient");
+ }
+
+}
diff --git a/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/ctx/FhirR5.java b/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/ctx/FhirR5.java
index c4c2e210235..c303fd18107 100644
--- a/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/ctx/FhirR5.java
+++ b/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/ctx/FhirR5.java
@@ -24,7 +24,7 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
-import ca.uhn.fhir.fluentpath.IFluentPath;
+import ca.uhn.fhir.fhirpath.IFhirPath;
import ca.uhn.fhir.model.api.IFhirVersion;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
@@ -52,7 +52,7 @@ public class FhirR5 implements IFhirVersion {
private String myId;
@Override
- public IFluentPath createFluentPathExecutor(FhirContext theFhirContext) {
+ public IFhirPath createFluentPathExecutor(FhirContext theFhirContext) {
return new FhirPathR5(theFhirContext);
}
diff --git a/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/fhirpath/FhirPathR5.java b/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/fhirpath/FhirPathR5.java
index 1aab76cf9ed..d82be431bc1 100644
--- a/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/fhirpath/FhirPathR5.java
+++ b/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/fhirpath/FhirPathR5.java
@@ -2,8 +2,8 @@ package org.hl7.fhir.r5.hapi.fhirpath;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.support.IValidationSupport;
-import ca.uhn.fhir.fluentpath.FluentPathExecutionException;
-import ca.uhn.fhir.fluentpath.IFluentPath;
+import ca.uhn.fhir.fhirpath.FhirPathExecutionException;
+import ca.uhn.fhir.fhirpath.IFhirPath;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.r5.hapi.ctx.HapiWorkerContext;
@@ -13,7 +13,7 @@ import org.hl7.fhir.r5.utils.FHIRPathEngine;
import java.util.List;
import java.util.Optional;
-public class FhirPathR5 implements IFluentPath {
+public class FhirPathR5 implements IFhirPath {
private FHIRPathEngine myEngine;
@@ -29,12 +29,12 @@ public class FhirPathR5 implements IFluentPath {
try {
result = myEngine.evaluate((Base) theInput, thePath);
} catch (FHIRException e) {
- throw new FluentPathExecutionException(e);
+ throw new FhirPathExecutionException(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());
+ throw new FhirPathExecutionException("FluentPath expression \"" + thePath + "\" returned unexpected type " + next.getClass().getSimpleName() + " - Expected " + theReturnType.getName());
}
}
diff --git a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/HttpClientRule.java b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/HttpClientRule.java
new file mode 100644
index 00000000000..4c834c1eff4
--- /dev/null
+++ b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/HttpClientRule.java
@@ -0,0 +1,58 @@
+package ca.uhn.fhir.test.utilities;
+
+/*-
+ * #%L
+ * HAPI FHIR Test Utilities
+ * %%
+ * Copyright (C) 2014 - 2020 University Health Network
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+public class HttpClientRule implements TestRule {
+ private CloseableHttpClient myClient;
+
+ @Override
+ public Statement apply(Statement theBase, Description theDescription) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ startClient();
+ theBase.evaluate();
+ stopClient();
+ }
+ };
+ }
+
+
+ private void stopClient() throws Exception {
+ myClient.close();
+ }
+
+ private void startClient() {
+ myClient = HttpClientBuilder
+ .create()
+ .build();
+ }
+
+ public CloseableHttpClient getClient() {
+ return myClient;
+ }
+}
diff --git a/hapi-fhir-validation/src/test/java/ca/uhn/fhir/fluentpath/FluentPathTest.java b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/fhirpath/FluentPathTest.java
similarity index 88%
rename from hapi-fhir-validation/src/test/java/ca/uhn/fhir/fluentpath/FluentPathTest.java
rename to hapi-fhir-validation/src/test/java/ca/uhn/fhir/fhirpath/FluentPathTest.java
index 4acf3a2d406..6bc7da3d654 100644
--- a/hapi-fhir-validation/src/test/java/ca/uhn/fhir/fluentpath/FluentPathTest.java
+++ b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/fhirpath/FluentPathTest.java
@@ -1,4 +1,4 @@
-package ca.uhn.fhir.fluentpath;
+package ca.uhn.fhir.fhirpath;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.util.TestUtil;
@@ -21,7 +21,7 @@ public class FluentPathTest {
p.addName().setFamily("N1F1").addGiven("N1G1").addGiven("N1G2");
p.addName().setFamily("N2F1").addGiven("N2G1").addGiven("N2G2");
- IFluentPath fp = ourCtx.newFluentPath();
+ IFhirPath fp = ourCtx.newFluentPath();
List names = fp.evaluate(p, "Patient.name", HumanName.class);
assertEquals(2, names.size());
assertEquals("N1F1", names.get(0).getFamily());
@@ -36,7 +36,7 @@ public class FluentPathTest {
p.addName().setFamily("N1F1").addGiven("N1G1").addGiven("N1G2");
p.addName().setFamily("N2F1").addGiven("N2G1").addGiven("N2G2");
- IFluentPath fp = ourCtx.newFluentPath();
+ IFhirPath fp = ourCtx.newFluentPath();
List names = fp.evaluate(p, "Patient.nameFOO", HumanName.class);
assertEquals(0, names.size());
}
@@ -47,10 +47,10 @@ public class FluentPathTest {
p.addName().setFamily("N1F1").addGiven("N1G1").addGiven("N1G2");
p.addName().setFamily("N2F1").addGiven("N2G1").addGiven("N2G2");
- IFluentPath fp = ourCtx.newFluentPath();
+ IFhirPath fp = ourCtx.newFluentPath();
try {
fp.evaluate(p, "Patient....nameFOO", HumanName.class);
- } catch (FluentPathExecutionException e) {
+ } catch (FhirPathExecutionException e) {
assertThat(e.getMessage(), containsString("termination at unexpected token"));
}
}
@@ -61,10 +61,10 @@ public class FluentPathTest {
p.addName().setFamily("N1F1").addGiven("N1G1").addGiven("N1G2");
p.addName().setFamily("N2F1").addGiven("N2G1").addGiven("N2G2");
- IFluentPath fp = ourCtx.newFluentPath();
+ IFhirPath fp = ourCtx.newFluentPath();
try {
fp.evaluate(p, "Patient.name", StringType.class);
- } catch (FluentPathExecutionException e) {
+ } catch (FhirPathExecutionException e) {
assertEquals("FluentPath expression \"Patient.name\" returned unexpected type HumanName - Expected org.hl7.fhir.dstu3.model.StringType", e.getMessage());
}
}
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java
index 06a10a7948b..a95a1109967 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java
@@ -23,11 +23,11 @@ package ca.uhn.fhir.model.dstu2;
import java.io.InputStream;
import java.util.Date;
+import ca.uhn.fhir.fhirpath.IFhirPath;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.*;
import ca.uhn.fhir.context.*;
-import ca.uhn.fhir.fluentpath.IFluentPath;
import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.base.composite.*;
import ca.uhn.fhir.model.dstu2.composite.*;
@@ -41,7 +41,7 @@ public class FhirDstu2 implements IFhirVersion {
private String myId;
@Override
- public IFluentPath createFluentPathExecutor(FhirContext theFhirContext) {
+ public IFhirPath createFluentPathExecutor(FhirContext theFhirContext) {
throw new UnsupportedOperationException("FluentPath is not supported in DSTU2 contexts");
}