From 6551eb0a4eb5d640d81abdf2439dea24a3047b15 Mon Sep 17 00:00:00 2001
From: Alvin Leonard
Date: Wed, 11 Oct 2017 13:40:03 +1100
Subject: [PATCH 01/39] Fix deleteByUrl to respect InCompartment Authorization
Moved the assignment of the resource to delete before the actual delete as it will be used by the authorization to determine if this resource is in the compartment.
---
.../java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java | 2 +-
.../AuthorizationInterceptorResourceProviderDstu3Test.java | 6 +++++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
index 2c483a06092..46357a02595 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
@@ -255,6 +255,7 @@ public abstract class BaseHapiFhirResourceDao extends B
deletedResources.add(entity);
validateOkToDelete(deleteConflicts, entity);
+ T resourceToDelete = toResource(myResourceType, entity, false);
// Notify interceptors
IdDt idToDelete = entity.getIdDt();
@@ -268,7 +269,6 @@ public abstract class BaseHapiFhirResourceDao extends B
updateEntity(null, entity, updateTime, updateTime);
// Notify JPA interceptors
- T resourceToDelete = toResource(myResourceType, entity, false);
if (theRequestDetails != null) {
theRequestDetails.getRequestOperationCallback().resourceDeleted(resourceToDelete);
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, idToDelete.getResourceType(), idToDelete);
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/AuthorizationInterceptorResourceProviderDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/AuthorizationInterceptorResourceProviderDstu3Test.java
index cddc9ccd802..48c68698726 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/AuthorizationInterceptorResourceProviderDstu3Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/AuthorizationInterceptorResourceProviderDstu3Test.java
@@ -84,7 +84,7 @@ public class AuthorizationInterceptorResourceProviderDstu3Test extends BaseResou
/**
- * See #503
+ * See #503 #751
*/
@Test
public void testDeleteIsAllowedForCompartment() {
@@ -99,6 +99,9 @@ public class AuthorizationInterceptorResourceProviderDstu3Test extends BaseResou
obsInCompartment.getSubject().setReferenceElement(id.toUnqualifiedVersionless());
IIdType obsInCompartmentId = ourClient.create().resource(obsInCompartment).execute().getId().toUnqualifiedVersionless();
+ // create a 2nd observation to be deleted by url Observation?patient=id
+ ourClient.create().resource(obsInCompartment).execute().getId().toUnqualifiedVersionless();
+
Observation obsNotInCompartment = new Observation();
obsNotInCompartment.setStatus(ObservationStatus.FINAL);
IIdType obsNotInCompartmentId = ourClient.create().resource(obsNotInCompartment).execute().getId().toUnqualifiedVersionless();
@@ -115,6 +118,7 @@ public class AuthorizationInterceptorResourceProviderDstu3Test extends BaseResou
});
ourClient.delete().resourceById(obsInCompartmentId.toUnqualifiedVersionless()).execute();
+ ourClient.delete().resourceConditionalByUrl("Observation?patient=" + id.toUnqualifiedVersionless()).execute();
try {
ourClient.delete().resourceById(obsNotInCompartmentId.toUnqualifiedVersionless()).execute();
From 2114dd77062bf023e25d53ad7629652f4e1db719 Mon Sep 17 00:00:00 2001
From: Alvin Leonard
Date: Wed, 11 Oct 2017 15:09:41 +1100
Subject: [PATCH 02/39] We need to set the resource id to the entity id after
the update entity.
---
.../main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
index 46357a02595..6efe7f3efed 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
@@ -254,8 +254,8 @@ public abstract class BaseHapiFhirResourceDao extends B
ResourceTable entity = myEntityManager.find(ResourceTable.class, pid);
deletedResources.add(entity);
- validateOkToDelete(deleteConflicts, entity);
T resourceToDelete = toResource(myResourceType, entity, false);
+ validateOkToDelete(deleteConflicts, entity);
// Notify interceptors
IdDt idToDelete = entity.getIdDt();
@@ -267,6 +267,7 @@ public abstract class BaseHapiFhirResourceDao extends B
// Perform delete
Date updateTime = new Date();
updateEntity(null, entity, updateTime, updateTime);
+ resourceToDelete.setId(entity.getIdDt());
// Notify JPA interceptors
if (theRequestDetails != null) {
From 1a7e43d2a8a2cec0b036b1eff593b97be75ce5db Mon Sep 17 00:00:00 2001
From: David Conlan
Date: Tue, 17 Oct 2017 15:07:51 +1000
Subject: [PATCH 03/39] Make sure we actually have a type associated with the
resourceId or we get an exception
---
.../ca/uhn/fhir/rest/server/interceptor/auth/RuleImplOp.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleImplOp.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleImplOp.java
index 65603cb9198..a8b8e113053 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleImplOp.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleImplOp.java
@@ -225,7 +225,7 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
return null;
}
}
- if (appliesToResourceId != null) {
+ if (appliesToResourceId != null && appliesToResourceId.hasResourceType()) {
Class extends IBaseResource> type = theRequestDetails.getServer().getFhirContext().getResourceDefinition(appliesToResourceId.getResourceType()).getImplementingClass();
if (myAppliesToTypes.contains(type) == false) {
return null;
From a546c94ccb65728b50bb976697584dbd0b863d3b Mon Sep 17 00:00:00 2001
From: Clayton Bodendein
Date: Sat, 21 Oct 2017 23:00:19 -0500
Subject: [PATCH 04/39] Fixes #764 to allow the
AbstractJaxRsConformanceProvider to support the DSTU2_HL7ORG FhirContext
---
hapi-fhir-jaxrsserver-base/pom.xml | 5 +
.../AbstractJaxRsConformanceProvider.java | 9 ++
...xRsConformanceProviderDstu2Hl7OrgTest.java | 109 +++++++++++++++
...xRsMockPatientRestProviderDstu2Hl7Org.java | 128 ++++++++++++++++++
.../conf/ServerConformanceProvider.java | 54 ++++----
5 files changed, 276 insertions(+), 29 deletions(-)
create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2Hl7OrgTest.java
create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu2Hl7Org.java
diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml
index 3f2ac2eacae..b8d880ffb28 100644
--- a/hapi-fhir-jaxrsserver-base/pom.xml
+++ b/hapi-fhir-jaxrsserver-base/pom.xml
@@ -51,6 +51,11 @@
hapi-fhir-structures-dstu2${project.version}
+
+ ca.uhn.hapi.fhir
+ hapi-fhir-structures-hl7org-dstu2
+ ${project.version}
+ ca.uhn.hapi.fhirhapi-fhir-structures-dstu3
diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java
index 0d9c7b2b1c5..22b82df6e86 100644
--- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java
+++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java
@@ -68,6 +68,7 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
/** the conformance. It is created once during startup */
private CapabilityStatement myDstu3CapabilityStatement;
private ca.uhn.fhir.model.dstu2.resource.Conformance myDstu2Conformance;
+ private org.hl7.fhir.instance.model.Conformance myDstu2Hl7OrgConformance;
/**
* Constructor allowing the description, servername and server to be set
@@ -132,6 +133,10 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider serverCapabilityStatementProvider = new ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider(serverConfiguration);
serverCapabilityStatementProvider.initializeOperations();
myDstu2Conformance = serverCapabilityStatementProvider.getServerConformance(null);
+ } else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2_HL7ORG)) {
+ org.hl7.fhir.instance.conf.ServerConformanceProvider serverCapabilityStatementProvider = new org.hl7.fhir.instance.conf.ServerConformanceProvider(serverConfiguration);
+ serverCapabilityStatementProvider.initializeOperations();
+ myDstu2Hl7OrgConformance = serverCapabilityStatementProvider.getServerConformance(null);
}
}
@@ -173,6 +178,8 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
} else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2)) {
conformance = myDstu2Conformance;
// return (Response) response.returnResponse(ParseAction.create(myDstu2CapabilityStatement), Constants.STATUS_HTTP_200_OK, true, null, getResourceType().getSimpleName());
+ } else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2_HL7ORG)) {
+ conformance = myDstu2Hl7OrgConformance;
}
if (conformance != null) {
@@ -261,6 +268,8 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
return Class.class.cast(CapabilityStatement.class);
} else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2)) {
return Class.class.cast(ca.uhn.fhir.model.dstu2.resource.Conformance.class);
+ } else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2_HL7ORG)) {
+ return Class.class.cast(org.hl7.fhir.instance.model.Conformance.class);
}
return null;
}
diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2Hl7OrgTest.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2Hl7OrgTest.java
new file mode 100644
index 00000000000..9b3a8ca6fda
--- /dev/null
+++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2Hl7OrgTest.java
@@ -0,0 +1,109 @@
+package ca.uhn.fhir.jaxrs.server;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.core.*;
+
+import org.glassfish.jersey.internal.MapPropertiesDelegate;
+import org.glassfish.jersey.server.ContainerRequest;
+import org.junit.Before;
+import org.junit.Test;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProvider;
+import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProviderDstu2Hl7Org;
+import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.rest.server.IResourceProvider;
+
+public class AbstractJaxRsConformanceProviderDstu2Hl7OrgTest {
+
+ private static final String BASEURI = "http://basiuri";
+ private static final String REQUESTURI = BASEURI + "/metadata";
+ AbstractJaxRsConformanceProvider provider;
+ private ConcurrentHashMap, IResourceProvider> providers;
+ private ContainerRequest headers;
+ private MultivaluedHashMap queryParameters;
+
+ @Before
+ public void setUp() throws Exception {
+ // headers
+ headers = new ContainerRequest(new URI(BASEURI), new URI(REQUESTURI), HttpMethod.GET, null,
+ new MapPropertiesDelegate());
+ // uri info
+ queryParameters = new MultivaluedHashMap();
+
+
+ providers = new ConcurrentHashMap, IResourceProvider>();
+ provider = createConformanceProvider(providers);
+ }
+
+ @Test
+ public void testConformance() throws Exception {
+ providers.put(AbstractJaxRsConformanceProvider.class, provider);
+ providers.put(TestJaxRsDummyPatientProvider.class, new TestJaxRsDummyPatientProvider());
+ Response response = createConformanceProvider(providers).conformance();
+ System.out.println(response);
+ }
+
+ @Test
+ public void testConformanceUsingOptions() throws Exception {
+ providers.put(AbstractJaxRsConformanceProvider.class, provider);
+ providers.put(TestJaxRsDummyPatientProvider.class, new TestJaxRsDummyPatientProvider());
+ Response response = createConformanceProvider(providers).conformanceUsingOptions();
+ System.out.println(response);
+ }
+
+ @Test
+ public void testConformanceWithMethods() throws Exception {
+ providers.put(AbstractJaxRsConformanceProvider.class, provider);
+ providers.put(TestJaxRsMockPatientRestProviderDstu2Hl7Org.class, new TestJaxRsMockPatientRestProviderDstu2Hl7Org());
+ Response response = createConformanceProvider(providers).conformance();
+ assertEquals(Constants.STATUS_HTTP_200_OK, response.getStatus());
+ assertTrue(response.getEntity().toString().contains("\"type\": \"Patient\""));
+ assertTrue(response.getEntity().toString().contains("someCustomOperation"));
+ System.out.println(response);
+ System.out.println(response.getEntity());
+ }
+
+ @Test
+ public void testConformanceInXml() throws Exception {
+ queryParameters.put(Constants.PARAM_FORMAT, Arrays.asList(Constants.CT_XML));
+ providers.put(AbstractJaxRsConformanceProvider.class, provider);
+ providers.put(TestJaxRsMockPatientRestProviderDstu2Hl7Org.class, new TestJaxRsMockPatientRestProviderDstu2Hl7Org());
+ Response response = createConformanceProvider(providers).conformance();
+ assertEquals(Constants.STATUS_HTTP_200_OK, response.getStatus());
+ System.out.println(response.getEntity());
+ assertTrue(response.getEntity().toString().contains(" "));
+ assertTrue(response.getEntity().toString().contains("someCustomOperation"));
+ System.out.println(response.getEntity());
+ }
+
+ private AbstractJaxRsConformanceProvider createConformanceProvider(final ConcurrentHashMap, IResourceProvider> providers)
+ throws Exception {
+ AbstractJaxRsConformanceProvider result = new AbstractJaxRsConformanceProvider(FhirContext.forDstu2Hl7Org(), null, null, null) {
+ @Override
+ protected ConcurrentHashMap, IResourceProvider> getProviders() {
+ return providers;
+ }
+ };
+ // mocks
+ UriInfo uriInfo = mock(UriInfo.class);
+ when(uriInfo.getQueryParameters()).thenReturn(queryParameters);
+ when(uriInfo.getBaseUri()).thenReturn(new URI(BASEURI));
+ when(uriInfo.getRequestUri()).thenReturn(new URI(BASEURI + "/foo"));
+ result.setUriInfo(uriInfo);
+ result.setHeaders(headers);
+ result.setUpPostConstruct();
+ return result;
+ }
+
+}
+
diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu2Hl7Org.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu2Hl7Org.java
new file mode 100644
index 00000000000..fae37282aa7
--- /dev/null
+++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu2Hl7Org.java
@@ -0,0 +1,128 @@
+package ca.uhn.fhir.jaxrs.server.test;
+
+import java.util.List;
+
+import javax.ejb.Stateless;
+import javax.interceptor.Interceptors;
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.hl7.fhir.instance.model.*;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.mockito.Mockito;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
+import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
+import ca.uhn.fhir.rest.annotation.*;
+import ca.uhn.fhir.rest.api.*;
+import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.rest.param.StringAndListParam;
+import ca.uhn.fhir.rest.param.StringParam;
+import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
+import ca.uhn.fhir.rest.server.IPagingProvider;
+
+/**
+ * A test server delegating each call to a mock
+ */
+@Path(TestJaxRsMockPatientRestProviderDstu2Hl7Org.PATH)
+@Stateless
+@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML, Constants.CT_FHIR_JSON_NEW, Constants.CT_FHIR_XML_NEW })
+@Interceptors(JaxRsExceptionInterceptor.class)
+public class TestJaxRsMockPatientRestProviderDstu2Hl7Org extends AbstractJaxRsResourceProvider {
+
+ static final String PATH = "/Patient";
+
+ public static final TestJaxRsMockPatientRestProviderDstu2Hl7Org mock = Mockito.mock(TestJaxRsMockPatientRestProviderDstu2Hl7Org.class);
+
+ public static final FifoMemoryPagingProvider PAGING_PROVIDER;
+
+ static
+ {
+ PAGING_PROVIDER = new FifoMemoryPagingProvider(10);
+ PAGING_PROVIDER.setDefaultPageSize(10);
+ PAGING_PROVIDER.setMaximumPageSize(100);
+ }
+
+ /**
+ * Constructor
+ */
+ public TestJaxRsMockPatientRestProviderDstu2Hl7Org() {
+ super(FhirContext.forDstu2Hl7Org());
+ }
+
+ @Search
+ public List search(@RequiredParam(name = Patient.SP_NAME) final StringParam name, @RequiredParam(name=Patient.SP_ADDRESS) StringAndListParam theAddressParts) {
+ return mock.search(name, theAddressParts);
+ }
+
+ @Update
+ public MethodOutcome update(@IdParam final IdType theId, @ResourceParam final Patient patient,@ConditionalUrlParam final String theConditional) throws Exception {
+ return mock.update(theId, patient, theConditional);
+ }
+
+ @Read
+ public Patient find(@IdParam final IdType theId) {
+ return mock.find(theId);
+ }
+
+ @Read(version = true)
+ public Patient findHistory(@IdParam final IdType theId) {
+ return mock.findHistory(theId);
+ }
+
+ @Create
+ public MethodOutcome create(@ResourceParam final Patient patient, @ConditionalUrlParam String theConditional)
+ throws Exception {
+ return mock.create(patient, theConditional);
+ }
+
+ @Delete
+ public MethodOutcome delete(@IdParam final IdType theId, @ConditionalUrlParam final String theConditional) {
+ return mock.delete(theId, theConditional);
+ }
+
+ @Search(compartmentName = "Condition")
+ public List searchCompartment(@IdParam IdType thePatientId) {
+ return mock.searchCompartment(thePatientId);
+ }
+
+ @GET
+ @Path("/{id}/$someCustomOperation")
+ public Response someCustomOperationUsingGet(@PathParam("id") String id, String resource) throws Exception {
+ return customOperation(resource, RequestTypeEnum.GET, id, "$someCustomOperation",
+ RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
+ }
+
+ @POST
+ @Path("/{id}/$someCustomOperation")
+ public Response someCustomOperationUsingPost(@PathParam("id") String id, String resource) throws Exception {
+ return customOperation(resource, RequestTypeEnum.POST, id, "$someCustomOperation",
+ RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
+ }
+
+ @Operation(name = "someCustomOperation", idempotent = true, returnParameters = {
+ @OperationParam(name = "return", type = StringType.class) })
+ public Parameters someCustomOperation(@IdParam IdType myId, @OperationParam(name = "dummy") StringType dummyInput) {
+ return mock.someCustomOperation(myId, dummyInput);
+ }
+
+ @Validate()
+ public MethodOutcome validate(@ResourceParam final Patient resource) {
+ MethodOutcome mO = new MethodOutcome();
+ mO.setOperationOutcome(new OperationOutcome());
+ return mO;
+ }
+
+ @Override
+ public Class getResourceType() {
+ return Patient.class;
+ }
+
+ @Override
+ public IPagingProvider getPagingProvider() {
+ return PAGING_PROVIDER;
+ }
+
+}
diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java
index 858e84f87cf..9f69509733b 100644
--- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java
+++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java
@@ -28,6 +28,7 @@ import java.util.*;
import java.util.Map.Entry;
import java.util.jar.Manifest;
+import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.context.FhirVersionEnum;
@@ -70,11 +71,15 @@ public class ServerConformanceProvider implements IServerConformanceProvider myOperationBindingToName;
private HashMap> myOperationNameToBindings;
private String myPublisher = "Not provided";
- private RestfulServer myRestfulServer;
+ private RestulfulServerConfiguration myServerConfiguration;
public ServerConformanceProvider(RestfulServer theRestfulServer) {
- myRestfulServer = theRestfulServer;
+ this.myServerConfiguration = theRestfulServer.createConfiguration();
}
+
+ public ServerConformanceProvider(RestulfulServerConfiguration theServerConfiguration) {
+ this.myServerConfiguration = theServerConfiguration;
+ }
/*
* Add a no-arg constructor and seetter so that the
@@ -85,11 +90,16 @@ public class ServerConformanceProvider implements IServerConformanceProvider systemOps,
BaseMethodBinding> nextMethodBinding) {
if (nextMethodBinding.getRestOperationType() != null) {
@@ -114,7 +124,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider>> collectMethodBindings() {
Map>> resourceToMethods = new TreeMap>>();
- for (ResourceBinding next : myRestfulServer.getResourceBindings()) {
+ for (ResourceBinding next : myServerConfiguration.getResourceBindings()) {
String resourceName = next.getResourceName();
for (BaseMethodBinding> nextMethodBinding : next.getMethodBindings()) {
if (resourceToMethods.containsKey(resourceName) == false) {
@@ -123,7 +133,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider nextMethodBinding : myRestfulServer.getServerBindings()) {
+ for (BaseMethodBinding> nextMethodBinding : myServerConfiguration.getServerBindings()) {
String resourceName = "";
if (resourceToMethods.containsKey(resourceName) == false) {
resourceToMethods.put(resourceName, new ArrayList>());
@@ -163,10 +173,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider resourceOps = new HashSet();
ConformanceRestResourceComponent resource = rest.addResource();
String resourceName = nextEntry.getKey();
- RuntimeResourceDefinition def = myRestfulServer.getFhirContext().getResourceDefinition(resourceName);
+ RuntimeResourceDefinition def = myServerConfiguration.getFhirContext().getResourceDefinition(resourceName);
resource.getTypeElement().setValue(def.getName());
- resource.getProfile()
- .setReference((def.getResourceProfile(myRestfulServer.getServerBaseForRequest(theRequest))));
+ ServletContext servletContext = (ServletContext) (theRequest == null ? null : theRequest.getAttribute(RestfulServer.SERVLET_CONTEXT_ATTRIBUTE));
+ String serverBase = myServerConfiguration.getServerAddressStrategy().determineServerBase(servletContext, theRequest);
+ resource.getProfile().setReference((def.getResourceProfile(serverBase)));
TreeSet includes = new TreeSet();
@@ -296,7 +307,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider includes, DynamicSearchMethodBinding searchMethodBinding) {
includes.addAll(searchMethodBinding.getIncludes());
@@ -433,7 +429,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider nextTarget : nextParameter.getDeclaredTypes()) {
- RuntimeResourceDefinition targetDef = myRestfulServer.getFhirContext().getResourceDefinition(nextTarget);
+ RuntimeResourceDefinition targetDef = myServerConfiguration.getFhirContext().getResourceDefinition(nextTarget);
if (targetDef != null) {
ResourceType code;
try {
From b0154139617456eeb815511b68e2b8584286180c Mon Sep 17 00:00:00 2001
From: Clayton Bodendein
Date: Sun, 22 Oct 2017 13:48:02 -0500
Subject: [PATCH 05/39] Fixes issue #768 so that when DataFormatExceptions are
thrown when using AbstractJaxRsProviders, the stacktrace will be included in
the OperationOutcome details only if AbstractJaxRsProvider#withStrackTrace()
is configured to return true
---
.../java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java
index 5ba4d6a3a54..632a42935c8 100644
--- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java
+++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java
@@ -81,7 +81,7 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
private IBaseOperationOutcome createOutcome(final DataFormatException theException) {
final IBaseOperationOutcome oo = OperationOutcomeUtil.newInstance(getFhirContext());
- final String detailsValue = theException.getMessage() + "\n\n" + ExceptionUtils.getStackTrace(theException);
+ final String detailsValue = theException.getMessage() + (this.withStackTrace() ? "\n\n" + ExceptionUtils.getStackTrace(theException) : "");
OperationOutcomeUtil.addIssue(getFhirContext(), oo, ERROR, detailsValue, null, PROCESSING);
return oo;
}
From 452f6bc24c1edfb5f1af9a9fc1c8eb8469d31f43 Mon Sep 17 00:00:00 2001
From: Clayton Bodendein
Date: Sun, 22 Oct 2017 18:19:10 -0500
Subject: [PATCH 06/39] Related to issue #764 - adds support for the DSTU2_1
FHIR context in AbstractJaxRsConformanceProvider
---
hapi-fhir-jaxrsserver-base/pom.xml | 5 +
.../AbstractJaxRsConformanceProvider.java | 9 ++
...ctJaxRsConformanceProviderDstu2_1Test.java | 108 +++++++++++++++
...stJaxRsMockPatientRestProviderDstu2_1.java | 128 ++++++++++++++++++
.../conf/ServerConformanceProvider.java | 11 +-
5 files changed, 254 insertions(+), 7 deletions(-)
create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2_1Test.java
create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu2_1.java
diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml
index b8d880ffb28..3f728fccc8e 100644
--- a/hapi-fhir-jaxrsserver-base/pom.xml
+++ b/hapi-fhir-jaxrsserver-base/pom.xml
@@ -56,6 +56,11 @@
hapi-fhir-structures-hl7org-dstu2${project.version}
+
+ ca.uhn.hapi.fhir
+ hapi-fhir-structures-dstu2.1
+ ${project.version}
+ ca.uhn.hapi.fhirhapi-fhir-structures-dstu3
diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java
index 22b82df6e86..6f76e3f6959 100644
--- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java
+++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java
@@ -67,6 +67,7 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
/** the conformance. It is created once during startup */
private CapabilityStatement myDstu3CapabilityStatement;
+ private org.hl7.fhir.dstu2016may.model.Conformance myDstu2_1Conformance;
private ca.uhn.fhir.model.dstu2.resource.Conformance myDstu2Conformance;
private org.hl7.fhir.instance.model.Conformance myDstu2Hl7OrgConformance;
@@ -129,6 +130,10 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
ServerCapabilityStatementProvider serverCapabilityStatementProvider = new ServerCapabilityStatementProvider(serverConfiguration);
serverCapabilityStatementProvider.initializeOperations();
myDstu3CapabilityStatement = serverCapabilityStatementProvider.getServerConformance(null);
+ } else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2_1)) {
+ org.hl7.fhir.dstu2016may.hapi.rest.server.ServerConformanceProvider serverCapabilityStatementProvider = new org.hl7.fhir.dstu2016may.hapi.rest.server.ServerConformanceProvider(serverConfiguration);
+ serverCapabilityStatementProvider.initializeOperations();
+ myDstu2_1Conformance = serverCapabilityStatementProvider.getServerConformance(null);
} else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2)) {
ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider serverCapabilityStatementProvider = new ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider(serverConfiguration);
serverCapabilityStatementProvider.initializeOperations();
@@ -175,6 +180,8 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) {
conformance = myDstu3CapabilityStatement;
// return (Response) response.returnResponse(ParseAction.create(myDstu3CapabilityStatement), Constants.STATUS_HTTP_200_OK, true, null, getResourceType().getSimpleName());
+ } else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2_1)) {
+ conformance = myDstu2_1Conformance;
} else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2)) {
conformance = myDstu2Conformance;
// return (Response) response.returnResponse(ParseAction.create(myDstu2CapabilityStatement), Constants.STATUS_HTTP_200_OK, true, null, getResourceType().getSimpleName());
@@ -266,6 +273,8 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
public Class getResourceType() {
if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) {
return Class.class.cast(CapabilityStatement.class);
+ } else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2_1)) {
+ return Class.class.cast(org.hl7.fhir.dstu2016may.model.Conformance.class);
} else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2)) {
return Class.class.cast(ca.uhn.fhir.model.dstu2.resource.Conformance.class);
} else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2_HL7ORG)) {
diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2_1Test.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2_1Test.java
new file mode 100644
index 00000000000..60b447e0ab4
--- /dev/null
+++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2_1Test.java
@@ -0,0 +1,108 @@
+package ca.uhn.fhir.jaxrs.server;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.core.*;
+
+import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProviderDstu2_1;
+import org.glassfish.jersey.internal.MapPropertiesDelegate;
+import org.glassfish.jersey.server.ContainerRequest;
+import org.junit.Before;
+import org.junit.Test;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProvider;
+import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.rest.server.IResourceProvider;
+
+public class AbstractJaxRsConformanceProviderDstu2_1Test {
+
+ private static final String BASEURI = "http://basiuri";
+ private static final String REQUESTURI = BASEURI + "/metadata";
+ AbstractJaxRsConformanceProvider provider;
+ private ConcurrentHashMap, IResourceProvider> providers;
+ private ContainerRequest headers;
+ private MultivaluedHashMap queryParameters;
+
+ @Before
+ public void setUp() throws Exception {
+ // headers
+ headers = new ContainerRequest(new URI(BASEURI), new URI(REQUESTURI), HttpMethod.GET, null,
+ new MapPropertiesDelegate());
+ // uri info
+ queryParameters = new MultivaluedHashMap();
+
+
+ providers = new ConcurrentHashMap, IResourceProvider>();
+ provider = createConformanceProvider(providers);
+ }
+
+ @Test
+ public void testConformance() throws Exception {
+ providers.put(AbstractJaxRsConformanceProvider.class, provider);
+ providers.put(TestJaxRsDummyPatientProvider.class, new TestJaxRsDummyPatientProvider());
+ Response response = createConformanceProvider(providers).conformance();
+ System.out.println(response);
+ }
+
+ @Test
+ public void testConformanceUsingOptions() throws Exception {
+ providers.put(AbstractJaxRsConformanceProvider.class, provider);
+ providers.put(TestJaxRsDummyPatientProvider.class, new TestJaxRsDummyPatientProvider());
+ Response response = createConformanceProvider(providers).conformanceUsingOptions();
+ System.out.println(response);
+ }
+
+ @Test
+ public void testConformanceWithMethods() throws Exception {
+ providers.put(AbstractJaxRsConformanceProvider.class, provider);
+ providers.put(TestJaxRsMockPatientRestProviderDstu2_1.class, new TestJaxRsMockPatientRestProviderDstu2_1());
+ Response response = createConformanceProvider(providers).conformance();
+ assertEquals(Constants.STATUS_HTTP_200_OK, response.getStatus());
+ assertTrue(response.getEntity().toString().contains("\"type\": \"Patient\""));
+ assertTrue(response.getEntity().toString().contains("\"someCustomOperation"));
+ System.out.println(response);
+ System.out.println(response.getEntity());
+ }
+
+ @Test
+ public void testConformanceInXml() throws Exception {
+ queryParameters.put(Constants.PARAM_FORMAT, Arrays.asList(Constants.CT_XML));
+ providers.put(AbstractJaxRsConformanceProvider.class, provider);
+ providers.put(TestJaxRsMockPatientRestProviderDstu2_1.class, new TestJaxRsMockPatientRestProviderDstu2_1());
+ Response response = createConformanceProvider(providers).conformance();
+ assertEquals(Constants.STATUS_HTTP_200_OK, response.getStatus());
+ System.out.println(response.getEntity());
+ assertTrue(response.getEntity().toString().contains(" "));
+ assertTrue(response.getEntity().toString().contains("\"someCustomOperation"));
+ System.out.println(response.getEntity());
+ }
+
+ private AbstractJaxRsConformanceProvider createConformanceProvider(final ConcurrentHashMap, IResourceProvider> providers)
+ throws Exception {
+ AbstractJaxRsConformanceProvider result = new AbstractJaxRsConformanceProvider(FhirContext.forDstu2_1(), null, null, null) {
+ @Override
+ protected ConcurrentHashMap, IResourceProvider> getProviders() {
+ return providers;
+ }
+ };
+ // mocks
+ UriInfo uriInfo = mock(UriInfo.class);
+ when(uriInfo.getQueryParameters()).thenReturn(queryParameters);
+ when(uriInfo.getBaseUri()).thenReturn(new URI(BASEURI));
+ when(uriInfo.getRequestUri()).thenReturn(new URI(BASEURI + "/foo"));
+ result.setUriInfo(uriInfo);
+ result.setHeaders(headers);
+ result.setUpPostConstruct();
+ return result;
+ }
+
+}
diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu2_1.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu2_1.java
new file mode 100644
index 00000000000..08aab47036e
--- /dev/null
+++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderDstu2_1.java
@@ -0,0 +1,128 @@
+package ca.uhn.fhir.jaxrs.server.test;
+
+import java.util.List;
+
+import javax.ejb.Stateless;
+import javax.interceptor.Interceptors;
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.hl7.fhir.dstu2016may.model.*;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.mockito.Mockito;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
+import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
+import ca.uhn.fhir.rest.annotation.*;
+import ca.uhn.fhir.rest.api.*;
+import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.rest.param.StringAndListParam;
+import ca.uhn.fhir.rest.param.StringParam;
+import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
+import ca.uhn.fhir.rest.server.IPagingProvider;
+
+/**
+ * A test server delegating each call to a mock
+ */
+@Path(TestJaxRsMockPatientRestProviderDstu2_1.PATH)
+@Stateless
+@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML, Constants.CT_FHIR_JSON_NEW, Constants.CT_FHIR_XML_NEW })
+@Interceptors(JaxRsExceptionInterceptor.class)
+public class TestJaxRsMockPatientRestProviderDstu2_1 extends AbstractJaxRsResourceProvider {
+
+ static final String PATH = "/Patient";
+
+ public static final TestJaxRsMockPatientRestProviderDstu2_1 mock = Mockito.mock(TestJaxRsMockPatientRestProviderDstu2_1.class);
+
+ public static final FifoMemoryPagingProvider PAGING_PROVIDER;
+
+ static
+ {
+ PAGING_PROVIDER = new FifoMemoryPagingProvider(10);
+ PAGING_PROVIDER.setDefaultPageSize(10);
+ PAGING_PROVIDER.setMaximumPageSize(100);
+ }
+
+ /**
+ * Constructor
+ */
+ public TestJaxRsMockPatientRestProviderDstu2_1() {
+ super(FhirContext.forDstu2_1());
+ }
+
+ @Search
+ public List search(@RequiredParam(name = Patient.SP_NAME) final StringParam name, @RequiredParam(name=Patient.SP_ADDRESS) StringAndListParam theAddressParts) {
+ return mock.search(name, theAddressParts);
+ }
+
+ @Update
+ public MethodOutcome update(@IdParam final IdType theId, @ResourceParam final Patient patient,@ConditionalUrlParam final String theConditional) throws Exception {
+ return mock.update(theId, patient, theConditional);
+ }
+
+ @Read
+ public Patient find(@IdParam final IdType theId) {
+ return mock.find(theId);
+ }
+
+ @Read(version = true)
+ public Patient findHistory(@IdParam final IdType theId) {
+ return mock.findHistory(theId);
+ }
+
+ @Create
+ public MethodOutcome create(@ResourceParam final Patient patient, @ConditionalUrlParam String theConditional)
+ throws Exception {
+ return mock.create(patient, theConditional);
+ }
+
+ @Delete
+ public MethodOutcome delete(@IdParam final IdType theId, @ConditionalUrlParam final String theConditional) {
+ return mock.delete(theId, theConditional);
+ }
+
+ @Search(compartmentName = "Condition")
+ public List searchCompartment(@IdParam IdType thePatientId) {
+ return mock.searchCompartment(thePatientId);
+ }
+
+ @GET
+ @Path("/{id}/$someCustomOperation")
+ public Response someCustomOperationUsingGet(@PathParam("id") String id, String resource) throws Exception {
+ return customOperation(resource, RequestTypeEnum.GET, id, "$someCustomOperation",
+ RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
+ }
+
+ @POST
+ @Path("/{id}/$someCustomOperation")
+ public Response someCustomOperationUsingPost(@PathParam("id") String id, String resource) throws Exception {
+ return customOperation(resource, RequestTypeEnum.POST, id, "$someCustomOperation",
+ RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
+ }
+
+ @Operation(name = "someCustomOperation", idempotent = true, returnParameters = {
+ @OperationParam(name = "return", type = StringType.class) })
+ public Parameters someCustomOperation(@IdParam IdType myId, @OperationParam(name = "dummy") StringType dummyInput) {
+ return mock.someCustomOperation(myId, dummyInput);
+ }
+
+ @Validate()
+ public MethodOutcome validate(@ResourceParam final Patient resource) {
+ MethodOutcome mO = new MethodOutcome();
+ mO.setOperationOutcome(new OperationOutcome());
+ return mO;
+ }
+
+ @Override
+ public Class getResourceType() {
+ return Patient.class;
+ }
+
+ @Override
+ public IPagingProvider getPagingProvider() {
+ return PAGING_PROVIDER;
+ }
+
+}
diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java
index 9f69509733b..a1fdc04ce16 100644
--- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java
+++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java
@@ -21,12 +21,9 @@ package org.hl7.fhir.instance.conf;
*/
import static org.apache.commons.lang3.StringUtils.isNotBlank;
-import java.io.IOException;
-import java.io.InputStream;
import java.text.*;
import java.util.*;
import java.util.Map.Entry;
-import java.util.jar.Manifest;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
@@ -71,7 +68,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider myOperationBindingToName;
private HashMap> myOperationNameToBindings;
private String myPublisher = "Not provided";
- private RestulfulServerConfiguration myServerConfiguration;
+ private RestulfulServerConfiguration myServerConfiguration;
public ServerConformanceProvider(RestfulServer theRestfulServer) {
this.myServerConfiguration = theRestfulServer.createConfiguration();
@@ -91,10 +88,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider
Date: Sun, 22 Oct 2017 18:43:17 -0500
Subject: [PATCH 07/39] Related to issue #764 - adds support for the R4 FHIR
context in AbstractJaxRsConformanceProvider
---
hapi-fhir-jaxrsserver-base/pom.xml | 5 +
.../AbstractJaxRsConformanceProvider.java | 16 ++-
...xRsConformanceProviderDstu2Hl7OrgTest.java | 6 +-
...ctJaxRsConformanceProviderDstu2_1Test.java | 6 +-
...bstractJaxRsConformanceProviderR4Test.java | 108 +++++++++++++++
...tJaxRsDummyPatientProviderDstu2Hl7Org.java | 15 ++
.../TestJaxRsDummyPatientProviderDstu2_1.java | 15 ++
.../test/TestJaxRsDummyPatientProviderR4.java | 15 ++
.../TestJaxRsMockPatientRestProviderR4.java | 128 ++++++++++++++++++
9 files changed, 305 insertions(+), 9 deletions(-)
create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderR4Test.java
create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderDstu2Hl7Org.java
create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderDstu2_1.java
create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderR4.java
create mode 100644 hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderR4.java
diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml
index 3f728fccc8e..76b6a885650 100644
--- a/hapi-fhir-jaxrsserver-base/pom.xml
+++ b/hapi-fhir-jaxrsserver-base/pom.xml
@@ -66,6 +66,11 @@
hapi-fhir-structures-dstu3${project.version}
+
+ ca.uhn.hapi.fhir
+ hapi-fhir-structures-r4
+ ${project.version}
+ javax.ws.rs
diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java
index 6f76e3f6959..1b7f328e6e9 100644
--- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java
+++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java
@@ -66,6 +66,7 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
private RestulfulServerConfiguration serverConfiguration = new RestulfulServerConfiguration();
/** the conformance. It is created once during startup */
+ private org.hl7.fhir.r4.model.CapabilityStatement myR4CapabilityStatement;
private CapabilityStatement myDstu3CapabilityStatement;
private org.hl7.fhir.dstu2016may.model.Conformance myDstu2_1Conformance;
private ca.uhn.fhir.model.dstu2.resource.Conformance myDstu2Conformance;
@@ -126,7 +127,11 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
HardcodedServerAddressStrategy hardcodedServerAddressStrategy = new HardcodedServerAddressStrategy();
hardcodedServerAddressStrategy.setValue(getBaseForServer());
serverConfiguration.setServerAddressStrategy(hardcodedServerAddressStrategy);
- if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) {
+ if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.R4)) {
+ org.hl7.fhir.r4.hapi.rest.server.ServerCapabilityStatementProvider serverCapabilityStatementProvider = new org.hl7.fhir.r4.hapi.rest.server.ServerCapabilityStatementProvider(serverConfiguration);
+ serverCapabilityStatementProvider.initializeOperations();
+ myR4CapabilityStatement = serverCapabilityStatementProvider.getServerConformance(null);
+ } else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) {
ServerCapabilityStatementProvider serverCapabilityStatementProvider = new ServerCapabilityStatementProvider(serverConfiguration);
serverCapabilityStatementProvider.initializeOperations();
myDstu3CapabilityStatement = serverCapabilityStatementProvider.getServerConformance(null);
@@ -177,7 +182,10 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
response.addHeader(Constants.HEADER_CORS_ALLOW_ORIGIN, "*");
IBaseResource conformance = null;
- if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) {
+ if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.R4)) {
+ conformance = myR4CapabilityStatement;
+// return (Response) response.returnResponse(ParseAction.create(myDstu3CapabilityStatement), Constants.STATUS_HTTP_200_OK, true, null, getResourceType().getSimpleName());
+ } else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) {
conformance = myDstu3CapabilityStatement;
// return (Response) response.returnResponse(ParseAction.create(myDstu3CapabilityStatement), Constants.STATUS_HTTP_200_OK, true, null, getResourceType().getSimpleName());
} else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2_1)) {
@@ -271,7 +279,9 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
@SuppressWarnings("unchecked")
@Override
public Class getResourceType() {
- if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) {
+ if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.R4)) {
+ return Class.class.cast(org.hl7.fhir.r4.model.CapabilityStatement.class);
+ } else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) {
return Class.class.cast(CapabilityStatement.class);
} else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2_1)) {
return Class.class.cast(org.hl7.fhir.dstu2016may.model.Conformance.class);
diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2Hl7OrgTest.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2Hl7OrgTest.java
index 9b3a8ca6fda..eac40d8bce2 100644
--- a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2Hl7OrgTest.java
+++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2Hl7OrgTest.java
@@ -12,13 +12,13 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.*;
+import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProviderDstu2Hl7Org;
import org.glassfish.jersey.internal.MapPropertiesDelegate;
import org.glassfish.jersey.server.ContainerRequest;
import org.junit.Before;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProvider;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProviderDstu2Hl7Org;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.IResourceProvider;
@@ -48,7 +48,7 @@ public class AbstractJaxRsConformanceProviderDstu2Hl7OrgTest {
@Test
public void testConformance() throws Exception {
providers.put(AbstractJaxRsConformanceProvider.class, provider);
- providers.put(TestJaxRsDummyPatientProvider.class, new TestJaxRsDummyPatientProvider());
+ providers.put(TestJaxRsDummyPatientProviderDstu2Hl7Org.class, new TestJaxRsDummyPatientProviderDstu2Hl7Org());
Response response = createConformanceProvider(providers).conformance();
System.out.println(response);
}
@@ -56,7 +56,7 @@ public class AbstractJaxRsConformanceProviderDstu2Hl7OrgTest {
@Test
public void testConformanceUsingOptions() throws Exception {
providers.put(AbstractJaxRsConformanceProvider.class, provider);
- providers.put(TestJaxRsDummyPatientProvider.class, new TestJaxRsDummyPatientProvider());
+ providers.put(TestJaxRsDummyPatientProviderDstu2Hl7Org.class, new TestJaxRsDummyPatientProviderDstu2Hl7Org());
Response response = createConformanceProvider(providers).conformanceUsingOptions();
System.out.println(response);
}
diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2_1Test.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2_1Test.java
index 60b447e0ab4..115e68d9210 100644
--- a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2_1Test.java
+++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderDstu2_1Test.java
@@ -12,6 +12,7 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.*;
+import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProviderDstu2_1;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProviderDstu2_1;
import org.glassfish.jersey.internal.MapPropertiesDelegate;
import org.glassfish.jersey.server.ContainerRequest;
@@ -19,7 +20,6 @@ import org.junit.Before;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProvider;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.IResourceProvider;
@@ -48,7 +48,7 @@ public class AbstractJaxRsConformanceProviderDstu2_1Test {
@Test
public void testConformance() throws Exception {
providers.put(AbstractJaxRsConformanceProvider.class, provider);
- providers.put(TestJaxRsDummyPatientProvider.class, new TestJaxRsDummyPatientProvider());
+ providers.put(TestJaxRsDummyPatientProviderDstu2_1.class, new TestJaxRsDummyPatientProviderDstu2_1());
Response response = createConformanceProvider(providers).conformance();
System.out.println(response);
}
@@ -56,7 +56,7 @@ public class AbstractJaxRsConformanceProviderDstu2_1Test {
@Test
public void testConformanceUsingOptions() throws Exception {
providers.put(AbstractJaxRsConformanceProvider.class, provider);
- providers.put(TestJaxRsDummyPatientProvider.class, new TestJaxRsDummyPatientProvider());
+ providers.put(TestJaxRsDummyPatientProviderDstu2_1.class, new TestJaxRsDummyPatientProviderDstu2_1());
Response response = createConformanceProvider(providers).conformanceUsingOptions();
System.out.println(response);
}
diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderR4Test.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderR4Test.java
new file mode 100644
index 00000000000..80c86d751d5
--- /dev/null
+++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProviderR4Test.java
@@ -0,0 +1,108 @@
+package ca.uhn.fhir.jaxrs.server;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.core.*;
+
+import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProviderR4;
+import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProviderR4;
+import org.glassfish.jersey.internal.MapPropertiesDelegate;
+import org.glassfish.jersey.server.ContainerRequest;
+import org.junit.Before;
+import org.junit.Test;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.rest.server.IResourceProvider;
+
+public class AbstractJaxRsConformanceProviderR4Test {
+
+ private static final String BASEURI = "http://basiuri";
+ private static final String REQUESTURI = BASEURI + "/metadata";
+ AbstractJaxRsConformanceProvider provider;
+ private ConcurrentHashMap, IResourceProvider> providers;
+ private ContainerRequest headers;
+ private MultivaluedHashMap queryParameters;
+
+ @Before
+ public void setUp() throws Exception {
+ // headers
+ headers = new ContainerRequest(new URI(BASEURI), new URI(REQUESTURI), HttpMethod.GET, null,
+ new MapPropertiesDelegate());
+ // uri info
+ queryParameters = new MultivaluedHashMap();
+
+
+ providers = new ConcurrentHashMap, IResourceProvider>();
+ provider = createConformanceProvider(providers);
+ }
+
+ @Test
+ public void testConformance() throws Exception {
+ providers.put(AbstractJaxRsConformanceProvider.class, provider);
+ providers.put(TestJaxRsDummyPatientProviderR4.class, new TestJaxRsDummyPatientProviderR4());
+ Response response = createConformanceProvider(providers).conformance();
+ System.out.println(response);
+ }
+
+ @Test
+ public void testConformanceUsingOptions() throws Exception {
+ providers.put(AbstractJaxRsConformanceProvider.class, provider);
+ providers.put(TestJaxRsDummyPatientProviderR4.class, new TestJaxRsDummyPatientProviderR4());
+ Response response = createConformanceProvider(providers).conformanceUsingOptions();
+ System.out.println(response);
+ }
+
+ @Test
+ public void testConformanceWithMethods() throws Exception {
+ providers.put(AbstractJaxRsConformanceProvider.class, provider);
+ providers.put(TestJaxRsMockPatientRestProviderR4.class, new TestJaxRsMockPatientRestProviderR4());
+ Response response = createConformanceProvider(providers).conformance();
+ assertEquals(Constants.STATUS_HTTP_200_OK, response.getStatus());
+ assertTrue(response.getEntity().toString().contains("\"type\": \"Patient\""));
+ assertTrue(response.getEntity().toString().contains("\"someCustomOperation"));
+ System.out.println(response);
+ System.out.println(response.getEntity());
+ }
+
+ @Test
+ public void testConformanceInXml() throws Exception {
+ queryParameters.put(Constants.PARAM_FORMAT, Arrays.asList(Constants.CT_XML));
+ providers.put(AbstractJaxRsConformanceProvider.class, provider);
+ providers.put(TestJaxRsMockPatientRestProviderR4.class, new TestJaxRsMockPatientRestProviderR4());
+ Response response = createConformanceProvider(providers).conformance();
+ assertEquals(Constants.STATUS_HTTP_200_OK, response.getStatus());
+ System.out.println(response.getEntity());
+ assertTrue(response.getEntity().toString().contains(" "));
+ assertTrue(response.getEntity().toString().contains("\"someCustomOperation"));
+ System.out.println(response.getEntity());
+ }
+
+ private AbstractJaxRsConformanceProvider createConformanceProvider(final ConcurrentHashMap, IResourceProvider> providers)
+ throws Exception {
+ AbstractJaxRsConformanceProvider result = new AbstractJaxRsConformanceProvider(FhirContext.forR4(), null, null, null) {
+ @Override
+ protected ConcurrentHashMap, IResourceProvider> getProviders() {
+ return providers;
+ }
+ };
+ // mocks
+ UriInfo uriInfo = mock(UriInfo.class);
+ when(uriInfo.getQueryParameters()).thenReturn(queryParameters);
+ when(uriInfo.getBaseUri()).thenReturn(new URI(BASEURI));
+ when(uriInfo.getRequestUri()).thenReturn(new URI(BASEURI + "/foo"));
+ result.setUriInfo(uriInfo);
+ result.setHeaders(headers);
+ result.setUpPostConstruct();
+ return result;
+ }
+
+}
diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderDstu2Hl7Org.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderDstu2Hl7Org.java
new file mode 100644
index 00000000000..c41b8611024
--- /dev/null
+++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderDstu2Hl7Org.java
@@ -0,0 +1,15 @@
+package ca.uhn.fhir.jaxrs.server.test;
+
+import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
+import org.hl7.fhir.instance.model.Patient;
+
+/**
+ * A dummy patient provider exposing no methods
+ */
+public class TestJaxRsDummyPatientProviderDstu2Hl7Org extends AbstractJaxRsResourceProvider {
+
+ @Override
+ public Class getResourceType() {
+ return Patient.class;
+ }
+}
diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderDstu2_1.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderDstu2_1.java
new file mode 100644
index 00000000000..420aa5cee48
--- /dev/null
+++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderDstu2_1.java
@@ -0,0 +1,15 @@
+package ca.uhn.fhir.jaxrs.server.test;
+
+import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
+import org.hl7.fhir.dstu2016may.model.Patient;
+
+/**
+ * A dummy patient provider exposing no methods
+ */
+public class TestJaxRsDummyPatientProviderDstu2_1 extends AbstractJaxRsResourceProvider {
+
+ @Override
+ public Class getResourceType() {
+ return Patient.class;
+ }
+}
diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderR4.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderR4.java
new file mode 100644
index 00000000000..1c3f91f4c1d
--- /dev/null
+++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsDummyPatientProviderR4.java
@@ -0,0 +1,15 @@
+package ca.uhn.fhir.jaxrs.server.test;
+
+import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
+import org.hl7.fhir.r4.model.Patient;
+
+/**
+ * A dummy patient provider exposing no methods
+ */
+public class TestJaxRsDummyPatientProviderR4 extends AbstractJaxRsResourceProvider {
+
+ @Override
+ public Class getResourceType() {
+ return Patient.class;
+ }
+}
diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderR4.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderR4.java
new file mode 100644
index 00000000000..0b34916b778
--- /dev/null
+++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProviderR4.java
@@ -0,0 +1,128 @@
+package ca.uhn.fhir.jaxrs.server.test;
+
+import java.util.List;
+
+import javax.ejb.Stateless;
+import javax.interceptor.Interceptors;
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.hl7.fhir.r4.model.*;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.mockito.Mockito;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
+import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
+import ca.uhn.fhir.rest.annotation.*;
+import ca.uhn.fhir.rest.api.*;
+import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.rest.param.StringAndListParam;
+import ca.uhn.fhir.rest.param.StringParam;
+import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
+import ca.uhn.fhir.rest.server.IPagingProvider;
+
+/**
+ * A test server delegating each call to a mock
+ */
+@Path(TestJaxRsMockPatientRestProviderR4.PATH)
+@Stateless
+@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML, Constants.CT_FHIR_JSON_NEW, Constants.CT_FHIR_XML_NEW })
+@Interceptors(JaxRsExceptionInterceptor.class)
+public class TestJaxRsMockPatientRestProviderR4 extends AbstractJaxRsResourceProvider {
+
+ static final String PATH = "/Patient";
+
+ public static final TestJaxRsMockPatientRestProviderR4 mock = Mockito.mock(TestJaxRsMockPatientRestProviderR4.class);
+
+ public static final FifoMemoryPagingProvider PAGING_PROVIDER;
+
+ static
+ {
+ PAGING_PROVIDER = new FifoMemoryPagingProvider(10);
+ PAGING_PROVIDER.setDefaultPageSize(10);
+ PAGING_PROVIDER.setMaximumPageSize(100);
+ }
+
+ /**
+ * Constructor
+ */
+ public TestJaxRsMockPatientRestProviderR4() {
+ super(FhirContext.forR4());
+ }
+
+ @Search
+ public List search(@RequiredParam(name = Patient.SP_NAME) final StringParam name, @RequiredParam(name=Patient.SP_ADDRESS) StringAndListParam theAddressParts) {
+ return mock.search(name, theAddressParts);
+ }
+
+ @Update
+ public MethodOutcome update(@IdParam final IdType theId, @ResourceParam final Patient patient,@ConditionalUrlParam final String theConditional) throws Exception {
+ return mock.update(theId, patient, theConditional);
+ }
+
+ @Read
+ public Patient find(@IdParam final IdType theId) {
+ return mock.find(theId);
+ }
+
+ @Read(version = true)
+ public Patient findHistory(@IdParam final IdType theId) {
+ return mock.findHistory(theId);
+ }
+
+ @Create
+ public MethodOutcome create(@ResourceParam final Patient patient, @ConditionalUrlParam String theConditional)
+ throws Exception {
+ return mock.create(patient, theConditional);
+ }
+
+ @Delete
+ public MethodOutcome delete(@IdParam final IdType theId, @ConditionalUrlParam final String theConditional) {
+ return mock.delete(theId, theConditional);
+ }
+
+ @Search(compartmentName = "Condition")
+ public List searchCompartment(@IdParam IdType thePatientId) {
+ return mock.searchCompartment(thePatientId);
+ }
+
+ @GET
+ @Path("/{id}/$someCustomOperation")
+ public Response someCustomOperationUsingGet(@PathParam("id") String id, String resource) throws Exception {
+ return customOperation(resource, RequestTypeEnum.GET, id, "$someCustomOperation",
+ RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
+ }
+
+ @POST
+ @Path("/{id}/$someCustomOperation")
+ public Response someCustomOperationUsingPost(@PathParam("id") String id, String resource) throws Exception {
+ return customOperation(resource, RequestTypeEnum.POST, id, "$someCustomOperation",
+ RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
+ }
+
+ @Operation(name = "someCustomOperation", idempotent = true, returnParameters = {
+ @OperationParam(name = "return", type = StringType.class) })
+ public Parameters someCustomOperation(@IdParam IdType myId, @OperationParam(name = "dummy") StringType dummyInput) {
+ return mock.someCustomOperation(myId, dummyInput);
+ }
+
+ @Validate()
+ public MethodOutcome validate(@ResourceParam final Patient resource) {
+ MethodOutcome mO = new MethodOutcome();
+ mO.setOperationOutcome(new OperationOutcome());
+ return mO;
+ }
+
+ @Override
+ public Class getResourceType() {
+ return Patient.class;
+ }
+
+ @Override
+ public IPagingProvider getPagingProvider() {
+ return PAGING_PROVIDER;
+ }
+
+}
From d0e747d6ecf29fc1ed08dbb3a47853f22c815844 Mon Sep 17 00:00:00 2001
From: Clayton Bodendein
Date: Sun, 22 Oct 2017 22:20:48 -0500
Subject: [PATCH 08/39] Fixed issue #768 in a different way by wrapping the
DataFormatException as an InvalidRequestException so that it still gets sent
as a 400 response but now DataFormatException stacktraces can now be
conditionally sent based on the
ExceptionHandlingInterceptor#setReturnStackTracesForExceptionTypes(Class>...)
configuration
---
.../exceptions/InvalidRequestException.java | 4 ++++
.../fhir/jaxrs/server/AbstractJaxRsProvider.java | 15 ---------------
.../interceptor/ExceptionHandlingInterceptor.java | 7 ++++++-
3 files changed, 10 insertions(+), 16 deletions(-)
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/InvalidRequestException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/InvalidRequestException.java
index 31a51f292ab..e56d3abd620 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/InvalidRequestException.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/InvalidRequestException.java
@@ -47,6 +47,10 @@ public class InvalidRequestException extends BaseServerResponseException {
public InvalidRequestException(String theMessage) {
super(STATUS_CODE, theMessage);
}
+
+ public InvalidRequestException(Throwable theCause) {
+ super(STATUS_CODE, theCause);
+ }
/**
* Constructor
diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java
index 632a42935c8..a0194aa1451 100644
--- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java
+++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java
@@ -26,8 +26,6 @@ import java.util.Map.Entry;
import javax.ws.rs.core.*;
import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.exception.ExceptionUtils;
-import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.api.AddProfileTagEnum;
@@ -35,12 +33,9 @@ import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsResponseException;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest.Builder;
-import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.server.*;
-import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
-import ca.uhn.fhir.util.OperationOutcomeUtil;
/**
* This is the abstract superclass for all jaxrs providers. It contains some defaults implementing
@@ -79,13 +74,6 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
CTX = ctx;
}
- private IBaseOperationOutcome createOutcome(final DataFormatException theException) {
- final IBaseOperationOutcome oo = OperationOutcomeUtil.newInstance(getFhirContext());
- final String detailsValue = theException.getMessage() + (this.withStackTrace() ? "\n\n" + ExceptionUtils.getStackTrace(theException) : "");
- OperationOutcomeUtil.addIssue(getFhirContext(), oo, ERROR, detailsValue, null, PROCESSING);
- return oo;
- }
-
/**
* DEFAULT = AddProfileTagEnum.NEVER
*/
@@ -241,9 +229,6 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
throws IOException {
if (theException instanceof JaxRsResponseException) {
return new JaxRsExceptionInterceptor().convertExceptionIntoResponse(theRequest, (JaxRsResponseException) theException);
- } else if (theException instanceof DataFormatException) {
- return new JaxRsExceptionInterceptor().convertExceptionIntoResponse(theRequest, new JaxRsResponseException(
- new InvalidRequestException(theException.getMessage(), createOutcome((DataFormatException) theException))));
} else {
return new JaxRsExceptionInterceptor().convertExceptionIntoResponse(theRequest,
new JaxRsExceptionInterceptor().convertException(this, theException));
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java
index 55d61dc93e7..da2bba0e053 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java
@@ -32,6 +32,8 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import ca.uhn.fhir.parser.DataFormatException;
+import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
@@ -99,7 +101,10 @@ public class ExceptionHandlingInterceptor extends InterceptorAdapter {
@Override
public BaseServerResponseException preProcessOutgoingException(RequestDetails theRequestDetails, Throwable theException, HttpServletRequest theServletRequest) throws ServletException {
BaseServerResponseException retVal;
- if (!(theException instanceof BaseServerResponseException)) {
+ if (theException instanceof DataFormatException) {
+ // Wrapping the DataFormatException as an InvalidRequestException so that it gets sent back to the client as a 400 response.
+ retVal = new InvalidRequestException(theException);
+ } else if (!(theException instanceof BaseServerResponseException)) {
retVal = new InternalErrorException(theException);
} else {
retVal = (BaseServerResponseException) theException;
From 8d1164fdc08f1c11dd76e01c25b55bc34ffdd80e Mon Sep 17 00:00:00 2001
From: Clayton Bodendein
Date: Mon, 23 Oct 2017 21:34:21 -0500
Subject: [PATCH 09/39] Fixed the Conformance providers in the
hapi-fhir-jaxrsserver-example module to pass the server description, server
name, and server version in the correct order
---
.../uhn/fhir/jaxrs/server/example/JaxRsConformanceProvider.java | 2 +-
.../jaxrs/server/example/JaxRsConformanceProviderDstu3.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsConformanceProvider.java b/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsConformanceProvider.java
index d70cf8795c7..e54f27c2e56 100644
--- a/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsConformanceProvider.java
+++ b/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsConformanceProvider.java
@@ -32,7 +32,7 @@ public class JaxRsConformanceProvider extends AbstractJaxRsConformanceProvider {
* Standard Constructor
*/
public JaxRsConformanceProvider() {
- super(SERVER_VERSION, SERVER_DESCRIPTION, SERVER_NAME);
+ super(SERVER_DESCRIPTION, SERVER_NAME, SERVER_VERSION);
}
@Override
diff --git a/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsConformanceProviderDstu3.java b/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsConformanceProviderDstu3.java
index 80ebaebd9cd..462ad5203a7 100644
--- a/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsConformanceProviderDstu3.java
+++ b/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsConformanceProviderDstu3.java
@@ -33,7 +33,7 @@ public class JaxRsConformanceProviderDstu3 extends AbstractJaxRsConformanceProvi
* Standard Constructor
*/
public JaxRsConformanceProviderDstu3() {
- super(FhirContext.forDstu3(), SERVER_VERSION, SERVER_DESCRIPTION, SERVER_NAME);
+ super(FhirContext.forDstu3(), SERVER_DESCRIPTION, SERVER_NAME, SERVER_VERSION);
}
@Override
From 129340d525acf2fa8fcfd40d50d81cdce2f12fb4 Mon Sep 17 00:00:00 2001
From: Clayton Bodendein
Date: Mon, 23 Oct 2017 21:43:23 -0500
Subject: [PATCH 10/39] Fixed parameter order in the example
JaxRsConformanceProvider
---
examples/src/main/java/example/JaxRsConformanceProvider.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/src/main/java/example/JaxRsConformanceProvider.java b/examples/src/main/java/example/JaxRsConformanceProvider.java
index 0accfd92f60..1f1549f07f7 100644
--- a/examples/src/main/java/example/JaxRsConformanceProvider.java
+++ b/examples/src/main/java/example/JaxRsConformanceProvider.java
@@ -27,7 +27,7 @@ public class JaxRsConformanceProvider extends AbstractJaxRsConformanceProvider {
private JaxRsPatientRestProvider provider;
public JaxRsConformanceProvider() {
- super("My Server Version", "My Server Description", "My Server Name");
+ super("My Server Description", "My Server Name", "My Server Version");
}
@Override
From d7f13432dfc04b18e06fe93ab695fdb396baea3c Mon Sep 17 00:00:00 2001
From: Clayton Bodendein
Date: Mon, 30 Oct 2017 12:48:23 -0500
Subject: [PATCH 11/39] Related to issue #764, changed the private
conformanceDate method in DSTU2_HL7ORG's ServerConformanceProvider to be
consistent with the ServerConformanceProvider in other FHIR contexts
---
.../instance/conf/ServerConformanceProvider.java | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java
index a1fdc04ce16..a410287cfda 100644
--- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java
+++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java
@@ -29,6 +29,7 @@ import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.context.FhirVersionEnum;
+import ca.uhn.fhir.parser.DataFormatException;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.*;
import org.hl7.fhir.instance.model.Conformance.*;
@@ -165,7 +166,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider
Date: Mon, 30 Oct 2017 16:39:30 -0400
Subject: [PATCH 12/39] Removed "hapi-fhir" from 4x Learn More links
---
src/site/resources/svg/hapi_usage_patterns.svg | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/site/resources/svg/hapi_usage_patterns.svg b/src/site/resources/svg/hapi_usage_patterns.svg
index cf328c2c567..730b07d8e95 100644
--- a/src/site/resources/svg/hapi_usage_patterns.svg
+++ b/src/site/resources/svg/hapi_usage_patterns.svg
@@ -163,7 +163,7 @@
Use the HAPI FHIR client in an application to fetch from or store
resources to an external server.
- Learn Mode
+ Learn Mode[Not supported by viewer]
@@ -266,7 +266,7 @@
Use the HAPI FHIR server in an application to allow external
applications to access or modify your application's data.
- Learn More
+ Learn More
- Learn More
+ Learn More[Not supported by viewer]
@@ -572,7 +572,7 @@
Use the HAPI FHIR parser and encoder to convert between FHIR and
your application's data model.
- Learn More
+ Learn More[Not supported by viewer]
From 4042a3a3532e83bebf7e61737e3fdf617b8e4734 Mon Sep 17 00:00:00 2001
From: James Agnew
Date: Wed, 22 Nov 2017 18:17:35 -0500
Subject: [PATCH 13/39] Prevent accidental deletion of deeply nested resources
in JPA server
---
.../java/ca/uhn/fhir/parser/BaseParser.java | 2 +-
.../java/ca/uhn/fhir/parser/JsonParser.java | 2 +-
.../provider/r4/ResourceProviderR4Test.java | 50 +++++++++++++++++++
.../ca/uhn/fhir/parser/JsonParserR4Test.java | 46 +++++++++++++++++
.../ca/uhn/fhir/parser/XmlParserR4Test.java | 30 +++++++++++
src/changes/changes.xml | 4 ++
6 files changed, 132 insertions(+), 2 deletions(-)
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java
index 9dfcdb7c7da..da8f83f9957 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java
@@ -1115,7 +1115,7 @@ public abstract class BaseParser implements IParser {
}
}
- return true;
+ return false;
}
public BaseRuntimeChildDefinition getDef() {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
index f759cefa6cd..de7286a98dd 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
@@ -1434,7 +1434,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
}
BaseRuntimeElementDefinition> childDef = extDef.getChildElementDefinitionByDatatype(value.getClass());
if (childDef == null) {
- throw new ConfigurationException("Unable to encode extension, unregognized child element type: " + value.getClass().getCanonicalName());
+ throw new ConfigurationException("Unable to encode extension, unrecognized child element type: " + value.getClass().getCanonicalName());
}
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, childDef, childName, true, false, myParent, false);
managePrimitiveExtension(value, theResDef, theResource, theEventWriter, childDef, childName);
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
index 5c6981cccb5..0f0a5920ff2 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
@@ -4301,6 +4301,56 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
}
}
+ @Test
+ public void testParseAndEncodeExtensionWithValueWithExtension() throws IOException {
+ String input = "\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ "";
+
+ HttpPost post = new HttpPost(ourServerBase + "/Patient");
+ post.setEntity(new StringEntity(input, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
+ CloseableHttpResponse response = ourHttpClient.execute(post);
+ IdType id;
+ try {
+ assertEquals(201, response.getStatusLine().getStatusCode());
+ String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue();
+ assertThat(newIdString, startsWith(ourServerBase + "/Patient/"));
+ id = new IdType(newIdString);
+ } finally {
+ response.close();
+ }
+
+ HttpGet get = new HttpGet(ourServerBase + "/Patient/" + id.getIdPart() + "?_pretty=true");
+ response = ourHttpClient.execute(get);
+ try {
+ String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
+ ourLog.info(resp);
+ assertEquals(200, response.getStatusLine().getStatusCode());
+ assertThat(resp, containsString("Underweight"));
+ } finally {
+ IOUtils.closeQuietly(response.getEntity().getContent());
+ response.close();
+ }
+
+ }
+
+
+
@Test
public void testValueSetExpandOperation() throws IOException {
CodeSystem cs = myFhirCtx.newXmlParser().parseResource(CodeSystem.class, new InputStreamReader(ResourceProviderR4Test.class.getResourceAsStream("/extensional-case-3-cs.xml")));
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/JsonParserR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/JsonParserR4Test.java
index 93fe167ff77..64f379f9160 100644
--- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/JsonParserR4Test.java
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/JsonParserR4Test.java
@@ -2,6 +2,7 @@ package ca.uhn.fhir.parser;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.util.TestUtil;
+import com.google.common.collect.Sets;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Patient;
import org.junit.AfterClass;
@@ -110,6 +111,51 @@ public class JsonParserR4Test {
return b;
}
+
+ @Test
+ public void testParseAndEncodeExtensionWithValueWithExtension() {
+ String input = "{\n" +
+ " \"resourceType\": \"Patient\",\n" +
+ " \"extension\": [\n" +
+ " {\n" +
+ " \"url\": \"https://purl.org/elab/fhir/network/StructureDefinition/1/BirthWeight\",\n" +
+ " \"_valueDecimal\": {\n" +
+ " \"extension\": [\n" +
+ " {\n" +
+ " \"url\": \"http://www.hl7.org/fhir/extension-data-absent-reason.html\",\n" +
+ " \"valueCoding\": {\n" +
+ " \"system\": \"http://hl7.org/fhir/ValueSet/birthweight\",\n" +
+ " \"code\": \"Underweight\",\n" +
+ " \"userSelected\": false\n" +
+ " }\n" +
+ " }\n" +
+ " ]\n" +
+ " }\n" +
+ " }\n" +
+ " ],\n" +
+ " \"identifier\": [\n" +
+ " {\n" +
+ " \"system\": \"https://purl.org/elab/fhir/network/StructureDefinition/1/EuroPrevallStudySubjects\",\n" +
+ " \"value\": \"1\"\n" +
+ " }\n" +
+ " ],\n" +
+ " \"gender\": \"female\"\n" +
+ "}";
+
+ IParser jsonParser = ourCtx.newJsonParser();
+ IParser xmlParser = ourCtx.newXmlParser();
+ jsonParser.setDontEncodeElements(Sets.newHashSet("id", "meta"));
+ xmlParser.setDontEncodeElements(Sets.newHashSet("id", "meta"));
+
+ Patient parsed = jsonParser.parseResource(Patient.class, input);
+
+ ourLog.info(jsonParser.setPrettyPrint(true).encodeResourceToString(parsed));
+ assertThat(xmlParser.encodeResourceToString(parsed), containsString("Underweight"));
+ assertThat(jsonParser.encodeResourceToString(parsed), containsString("Underweight"));
+
+ }
+
+
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/XmlParserR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/XmlParserR4Test.java
index 2d16f0e9c56..5be2e8e7977 100644
--- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/XmlParserR4Test.java
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/XmlParserR4Test.java
@@ -110,6 +110,36 @@ public class XmlParserR4Test {
return b;
}
+ @Test
+ public void testParseAndEncodeExtensionWithValueWithExtension() {
+ String input = "\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ "";
+
+ Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, input);
+
+ ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed));
+ assertThat(ourCtx.newXmlParser().encodeResourceToString(parsed), containsString("Underweight"));
+ assertThat(ourCtx.newJsonParser().encodeResourceToString(parsed), containsString("Underweight"));
+
+ }
+
+
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 21cee568c1f..51dc07483f1 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -212,6 +212,10 @@
client requests.
Thanks to Clayton Bodendein for the pull request!
+
+ An issue was fixed in JPA server where extensions on primitives which
+ are nestedt several layers deep are lost when resources are retrieved
+
From a4cbde82693bd26117daeaa9894a80fa4de97729 Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Wed, 22 Nov 2017 18:45:54 -0500
Subject: [PATCH 14/39] Prevent a spurious test failure
---
.../ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
index 0f0a5920ff2..d3b04381029 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
@@ -3219,7 +3219,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
// If this fails under load, try increasing the throttle above
assertEquals(null, found.getTotalElement().getValue());
assertEquals(1, found.getEntry().size());
- assertThat(sw.getMillis(), lessThan(1000L));
+ assertThat(sw.getMillis(), lessThan(1500L));
}
@Test
From 059265a0413c4ff8dcbeac66d5ca456404e59a1d Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Wed, 22 Nov 2017 19:15:27 -0500
Subject: [PATCH 15/39] Test cleanup
---
.../java/ca/uhn/fhir/util/BinaryUtil.java | 20 ++++
.../ca/uhn/fhir/parser/XmlParserR4Test.java | 92 ++++++++++---------
2 files changed, 69 insertions(+), 43 deletions(-)
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BinaryUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BinaryUtil.java
index b6c4411c8f3..cfa4323d718 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BinaryUtil.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BinaryUtil.java
@@ -1,5 +1,25 @@
package ca.uhn.fhir.util;
+/*-
+ * #%L
+ * HAPI FHIR - Core Library
+ * %%
+ * Copyright (C) 2014 - 2017 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 ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext;
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/XmlParserR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/XmlParserR4Test.java
index 5be2e8e7977..9be7c175f0c 100644
--- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/XmlParserR4Test.java
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/XmlParserR4Test.java
@@ -2,6 +2,7 @@ package ca.uhn.fhir.parser;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.util.TestUtil;
+import com.google.common.collect.Sets;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Patient;
import org.junit.AfterClass;
@@ -20,6 +21,19 @@ public class XmlParserR4Test {
private static final Logger ourLog = LoggerFactory.getLogger(XmlParserR4Test.class);
private static FhirContext ourCtx = FhirContext.forR4();
+ private Bundle createBundleWithPatient() {
+ Bundle b = new Bundle();
+ b.setId("BUNDLEID");
+ b.getMeta().addProfile("http://FOO");
+
+ Patient p = new Patient();
+ p.setId("PATIENTID");
+ p.getMeta().addProfile("http://BAR");
+ p.addName().addGiven("GIVEN");
+ b.addEntry().setResource(p);
+ return b;
+ }
+
@Test
public void testExcludeNothing() {
IParser parser = ourCtx.newXmlParser().setPrettyPrint(true);
@@ -45,6 +59,32 @@ public class XmlParserR4Test {
assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
}
+ @Test
+ public void testExcludeRootStuff() {
+ IParser parser = ourCtx.newXmlParser().setPrettyPrint(true);
+ Set excludes = new HashSet<>();
+ excludes.add("id");
+ excludes.add("meta");
+ parser.setDontEncodeElements(excludes);
+
+ Bundle b = createBundleWithPatient();
+
+ String encoded = parser.encodeResourceToString(b);
+ ourLog.info(encoded);
+
+ assertThat(encoded, not(containsString("BUNDLEID")));
+ assertThat(encoded, not(containsString("http://FOO")));
+ assertThat(encoded, (containsString("PATIENTID")));
+ assertThat(encoded, (containsString("http://BAR")));
+ assertThat(encoded, containsString("GIVEN"));
+
+ b = parser.parseResource(Bundle.class, encoded);
+
+ assertNotEquals("BUNDLEID", b.getIdElement().getIdPart());
+ assertEquals("Patient/PATIENTID", ((Patient) b.getEntry().get(0).getResource()).getId());
+ assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
+ }
+
@Test
public void testExcludeStarDotStuff() {
IParser parser = ourCtx.newXmlParser().setPrettyPrint(true);
@@ -71,45 +111,6 @@ public class XmlParserR4Test {
assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
}
- @Test
- public void testExcludeRootStuff() {
- IParser parser = ourCtx.newXmlParser().setPrettyPrint(true);
- Set excludes = new HashSet<>();
- excludes.add("id");
- excludes.add("meta");
- parser.setDontEncodeElements(excludes);
-
- Bundle b = createBundleWithPatient();
-
- String encoded = parser.encodeResourceToString(b);
- ourLog.info(encoded);
-
- assertThat(encoded, not(containsString("BUNDLEID")));
- assertThat(encoded, not(containsString("http://FOO")));
- assertThat(encoded, (containsString("PATIENTID")));
- assertThat(encoded, (containsString("http://BAR")));
- assertThat(encoded, containsString("GIVEN"));
-
- b = parser.parseResource(Bundle.class, encoded);
-
- assertNotEquals("BUNDLEID", b.getIdElement().getIdPart());
- assertEquals("Patient/PATIENTID", ((Patient) b.getEntry().get(0).getResource()).getId());
- assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
- }
-
- private Bundle createBundleWithPatient() {
- Bundle b = new Bundle();
- b.setId("BUNDLEID");
- b.getMeta().addProfile("http://FOO");
-
- Patient p = new Patient();
- p.setId("PATIENTID");
- p.getMeta().addProfile("http://BAR");
- p.addName().addGiven("GIVEN");
- b.addEntry().setResource(p);
- return b;
- }
-
@Test
public void testParseAndEncodeExtensionWithValueWithExtension() {
String input = "\n" +
@@ -131,11 +132,16 @@ public class XmlParserR4Test {
" \n" +
"";
- Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, input);
+ IParser xmlParser = ourCtx.newXmlParser();
+ IParser jsonParser = ourCtx.newJsonParser();
+ jsonParser.setDontEncodeElements(Sets.newHashSet("id", "meta"));
+ xmlParser.setDontEncodeElements(Sets.newHashSet("id", "meta"));
- ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed));
- assertThat(ourCtx.newXmlParser().encodeResourceToString(parsed), containsString("Underweight"));
- assertThat(ourCtx.newJsonParser().encodeResourceToString(parsed), containsString("Underweight"));
+ Patient parsed = xmlParser.parseResource(Patient.class, input);
+
+ ourLog.info(jsonParser.setPrettyPrint(true).encodeResourceToString(parsed));
+ assertThat(xmlParser.encodeResourceToString(parsed), containsString("Underweight"));
+ assertThat(jsonParser.encodeResourceToString(parsed), containsString("Underweight"));
}
From 5a8e88200bec9b3125822640a4e68f564e224452 Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Wed, 22 Nov 2017 19:18:49 -0500
Subject: [PATCH 16/39] Credit for #756
---
src/changes/changes.xml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 51dc07483f1..a00fb9d2921 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -216,6 +216,11 @@
An issue was fixed in JPA server where extensions on primitives which
are nestedt several layers deep are lost when resources are retrieved
+
+ Conditional deletes in JPA server were incorrectly denied by AuthorizationInterceptor
+ if the delete was permitted via a compartment rule. Thanks to Alvin Leonard for the
+ pull request!
+
From be76b90e7a474be4d641da964be7d6c23720a1ef Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Wed, 22 Nov 2017 19:22:32 -0500
Subject: [PATCH 17/39] Test formatting only
---
...nInterceptorResourceProviderDstu3Test.java | 263 +++++++++---------
1 file changed, 132 insertions(+), 131 deletions(-)
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/AuthorizationInterceptorResourceProviderDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/AuthorizationInterceptorResourceProviderDstu3Test.java
index 48c68698726..7f6afcbea30 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/AuthorizationInterceptorResourceProviderDstu3Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/AuthorizationInterceptorResourceProviderDstu3Test.java
@@ -1,39 +1,39 @@
package ca.uhn.fhir.jpa.provider.dstu3;
+import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.Constants;
-
-import static org.hamcrest.Matchers.startsWith;
-import static org.junit.Assert.*;
+import ca.uhn.fhir.rest.api.MethodOutcome;
+import ca.uhn.fhir.rest.api.server.RequestDetails;
+import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
+import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
+import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
+import ca.uhn.fhir.rest.server.interceptor.auth.IAuthRule;
+import ca.uhn.fhir.rest.server.interceptor.auth.PolicyEnum;
+import ca.uhn.fhir.rest.server.interceptor.auth.RuleBuilder;
+import ca.uhn.fhir.util.TestUtil;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.hl7.fhir.dstu3.model.IdType;
+import org.hl7.fhir.dstu3.model.Observation;
+import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
+import org.hl7.fhir.dstu3.model.Patient;
+import org.hl7.fhir.dstu3.model.Reference;
+import org.hl7.fhir.instance.model.api.IIdType;
+import org.junit.AfterClass;
+import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import org.apache.http.client.methods.*;
-import org.apache.http.entity.ContentType;
-import org.apache.http.entity.StringEntity;
-import org.hl7.fhir.dstu3.model.*;
-import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
-import org.hl7.fhir.instance.model.api.IIdType;
-import org.junit.AfterClass;
-import org.junit.Test;
-
-import ca.uhn.fhir.model.primitive.IdDt;
-import ca.uhn.fhir.rest.api.MethodOutcome;
-import ca.uhn.fhir.rest.api.server.RequestDetails;
-import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
-import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
-import ca.uhn.fhir.rest.server.interceptor.auth.*;
-import ca.uhn.fhir.util.TestUtil;
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.*;
public class AuthorizationInterceptorResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
- @AfterClass
- public static void afterClassClearContext() {
- TestUtil.clearAllStaticFieldsForUnitTest();
- }
-
-
@Override
public void before() throws Exception {
super.before();
@@ -41,96 +41,66 @@ public class AuthorizationInterceptorResourceProviderDstu3Test extends BaseResou
unregisterInterceptors();
}
-
- private void unregisterInterceptors() {
- for (IServerInterceptor next : new ArrayList(ourRestServer.getInterceptors())) {
- if (next instanceof AuthorizationInterceptor) {
- ourRestServer.unregisterInterceptor(next);
- }
- }
- }
-
/**
- * See #503
+ * See #667
*/
@Test
- public void testDeleteIsBlocked() {
-
+ public void testBlockUpdatingPatientUserDoesnNotHaveAccessTo() throws IOException {
+ Patient pt1 = new Patient();
+ pt1.setActive(true);
+ final IIdType pid1 = ourClient.create().resource(pt1).execute().getId().toUnqualifiedVersionless();
+
+ Patient pt2 = new Patient();
+ pt2.setActive(false);
+ final IIdType pid2 = ourClient.create().resource(pt2).execute().getId().toUnqualifiedVersionless();
+
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
public List buildRuleList(RequestDetails theRequestDetails) {
return new RuleBuilder()
- .deny().delete().allResources().withAnyId().andThen()
- .allowAll()
- .build();
+ .allow().write().allResources().inCompartment("Patient", pid1).andThen()
+ .build();
}
});
-
- Patient patient = new Patient();
- patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
- patient.addName().setFamily("Tester").addGiven("Raghad");
- IIdType id = ourClient.create().resource(patient).execute().getId();
- try {
- ourClient.delete().resourceById(id.toUnqualifiedVersionless()).execute();
- fail();
- } catch (ForbiddenOperationException e) {
- // good
- }
-
- patient = ourClient.read().resource(Patient.class).withId(id.toUnqualifiedVersionless()).execute();
- assertEquals(id.getValue(), patient.getId());
- }
-
+ Observation obs = new Observation();
+ obs.setStatus(ObservationStatus.FINAL);
+ obs.setSubject(new Reference(pid1));
+ IIdType oid = ourClient.create().resource(obs).execute().getId().toUnqualified();
- /**
- * See #503 #751
- */
- @Test
- public void testDeleteIsAllowedForCompartment() {
-
- Patient patient = new Patient();
- patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
- patient.addName().setFamily("Tester").addGiven("Raghad");
- final IIdType id = ourClient.create().resource(patient).execute().getId();
-
- Observation obsInCompartment = new Observation();
- obsInCompartment.setStatus(ObservationStatus.FINAL);
- obsInCompartment.getSubject().setReferenceElement(id.toUnqualifiedVersionless());
- IIdType obsInCompartmentId = ourClient.create().resource(obsInCompartment).execute().getId().toUnqualifiedVersionless();
-
- // create a 2nd observation to be deleted by url Observation?patient=id
- ourClient.create().resource(obsInCompartment).execute().getId().toUnqualifiedVersionless();
-
- Observation obsNotInCompartment = new Observation();
- obsNotInCompartment.setStatus(ObservationStatus.FINAL);
- IIdType obsNotInCompartmentId = ourClient.create().resource(obsNotInCompartment).execute().getId().toUnqualifiedVersionless();
-
+
+ unregisterInterceptors();
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
public List buildRuleList(RequestDetails theRequestDetails) {
return new RuleBuilder()
- .allow().delete().resourcesOfType(Observation.class).inCompartment("Patient", id).andThen()
- .deny().delete().allResources().withAnyId().andThen()
- .allowAll()
- .build();
+ .allow().write().allResources().inCompartment("Patient", pid2).andThen()
+ .build();
}
});
-
- ourClient.delete().resourceById(obsInCompartmentId.toUnqualifiedVersionless()).execute();
- ourClient.delete().resourceConditionalByUrl("Observation?patient=" + id.toUnqualifiedVersionless()).execute();
+
+ /*
+ * Try to update to a new patient. The user has access to write to things in
+ * pid2's compartment, so this would normally be ok, but in this case they are overwriting
+ * a resource that is already in pid1's compartment, which shouldn't be allowed.
+ */
+ obs = new Observation();
+ obs.setId(oid);
+ obs.setStatus(ObservationStatus.FINAL);
+ obs.setSubject(new Reference(pid2));
try {
- ourClient.delete().resourceById(obsNotInCompartmentId.toUnqualifiedVersionless()).execute();
+ ourClient.update().resource(obs).execute();
fail();
} catch (ForbiddenOperationException e) {
// good
}
+
}
@Test
public void testCreateConditional() {
-
+
Patient patient = new Patient();
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
patient.addName().setFamily("Tester").addGiven("Raghad");
@@ -139,15 +109,13 @@ public class AuthorizationInterceptorResourceProviderDstu3Test extends BaseResou
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
public List buildRuleList(RequestDetails theRequestDetails) {
- //@formatter:off
return new RuleBuilder()
.allow("Rule 2").write().allResources().inCompartment("Patient", new IdDt("Patient/" + output1.getId().getIdPart())).andThen()
.allow().updateConditional().allResources()
.build();
- //@formatter:on
}
});
-
+
patient = new Patient();
patient.setId(output1.getId().toUnqualifiedVersionless());
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
@@ -155,7 +123,7 @@ public class AuthorizationInterceptorResourceProviderDstu3Test extends BaseResou
MethodOutcome output2 = ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
assertEquals(output1.getId().getIdPart(), output2.getId().getIdPart());
-
+
patient = new Patient();
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
patient.addName().setFamily("Tester").addGiven("Raghad");
@@ -180,62 +148,82 @@ public class AuthorizationInterceptorResourceProviderDstu3Test extends BaseResou
}
/**
- * See #667
+ * See #503 #751
*/
@Test
- public void testBlockUpdatingPatientUserDoesnNotHaveAccessTo() throws IOException {
- Patient pt1 = new Patient();
- pt1.setActive(true);
- final IIdType pid1 = ourClient.create().resource(pt1).execute().getId().toUnqualifiedVersionless();
+ public void testDeleteIsAllowedForCompartment() {
- Patient pt2 = new Patient();
- pt2.setActive(false);
- final IIdType pid2 = ourClient.create().resource(pt2).execute().getId().toUnqualifiedVersionless();
+ Patient patient = new Patient();
+ patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
+ patient.addName().setFamily("Tester").addGiven("Raghad");
+ final IIdType id = ourClient.create().resource(patient).execute().getId();
+
+ Observation obsInCompartment = new Observation();
+ obsInCompartment.setStatus(ObservationStatus.FINAL);
+ obsInCompartment.getSubject().setReferenceElement(id.toUnqualifiedVersionless());
+ IIdType obsInCompartmentId = ourClient.create().resource(obsInCompartment).execute().getId().toUnqualifiedVersionless();
+
+ // create a 2nd observation to be deleted by url Observation?patient=id
+ ourClient.create().resource(obsInCompartment).execute().getId().toUnqualifiedVersionless();
+
+ Observation obsNotInCompartment = new Observation();
+ obsNotInCompartment.setStatus(ObservationStatus.FINAL);
+ IIdType obsNotInCompartmentId = ourClient.create().resource(obsNotInCompartment).execute().getId().toUnqualifiedVersionless();
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
public List buildRuleList(RequestDetails theRequestDetails) {
return new RuleBuilder()
- .allow().write().allResources().inCompartment("Patient", pid1).andThen()
+ .allow().delete().resourcesOfType(Observation.class).inCompartment("Patient", id).andThen()
+ .deny().delete().allResources().withAnyId().andThen()
+ .allowAll()
.build();
}
});
-
- Observation obs = new Observation();
- obs.setStatus(ObservationStatus.FINAL);
- obs.setSubject(new Reference(pid1));
- IIdType oid = ourClient.create().resource(obs).execute().getId().toUnqualified();
-
- unregisterInterceptors();
- ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
- @Override
- public List buildRuleList(RequestDetails theRequestDetails) {
- return new RuleBuilder()
- .allow().write().allResources().inCompartment("Patient", pid2).andThen()
- .build();
- }
- });
-
- /*
- * Try to update to a new patient. The user has access to write to things in
- * pid2's compartment, so this would normally be ok, but in this case they are overwriting
- * a resource that is already in pid1's compartment, which shouldn't be allowed.
- */
- obs = new Observation();
- obs.setId(oid);
- obs.setStatus(ObservationStatus.FINAL);
- obs.setSubject(new Reference(pid2));
-
+ ourClient.delete().resourceById(obsInCompartmentId.toUnqualifiedVersionless()).execute();
+ ourClient.delete().resourceConditionalByUrl("Observation?patient=" + id.toUnqualifiedVersionless()).execute();
+
try {
- ourClient.update().resource(obs).execute();
+ ourClient.delete().resourceById(obsNotInCompartmentId.toUnqualifiedVersionless()).execute();
fail();
} catch (ForbiddenOperationException e) {
// good
}
-
}
-
+
+ /**
+ * See #503
+ */
+ @Test
+ public void testDeleteIsBlocked() {
+
+ ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .deny().delete().allResources().withAnyId().andThen()
+ .allowAll()
+ .build();
+ }
+ });
+
+ Patient patient = new Patient();
+ patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
+ patient.addName().setFamily("Tester").addGiven("Raghad");
+ IIdType id = ourClient.create().resource(patient).execute().getId();
+
+ try {
+ ourClient.delete().resourceById(id.toUnqualifiedVersionless()).execute();
+ fail();
+ } catch (ForbiddenOperationException e) {
+ // good
+ }
+
+ patient = ourClient.read().resource(Patient.class).withId(id.toUnqualifiedVersionless()).execute();
+ assertEquals(id.getValue(), patient.getId());
+ }
+
@Test
public void testDeleteResourceConditional() throws IOException {
String methodName = "testDeleteResourceConditional";
@@ -284,7 +272,7 @@ public class AuthorizationInterceptorResourceProviderDstu3Test extends BaseResou
//@formatter:on
}
});
-
+
HttpDelete delete = new HttpDelete(ourServerBase + "/Patient?name=" + methodName);
response = ourHttpClient.execute(delete);
try {
@@ -303,4 +291,17 @@ public class AuthorizationInterceptorResourceProviderDstu3Test extends BaseResou
}
+ private void unregisterInterceptors() {
+ for (IServerInterceptor next : new ArrayList(ourRestServer.getInterceptors())) {
+ if (next instanceof AuthorizationInterceptor) {
+ ourRestServer.unregisterInterceptor(next);
+ }
+ }
+ }
+
+ @AfterClass
+ public static void afterClassClearContext() {
+ TestUtil.clearAllStaticFieldsForUnitTest();
+ }
+
}
From 98b254913524c272856a57203ba0e664ea530042 Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Wed, 22 Nov 2017 19:45:18 -0500
Subject: [PATCH 18/39] Formatting
---
...tionInterceptorResourceProviderR4Test.java | 320 +++++++++---------
1 file changed, 162 insertions(+), 158 deletions(-)
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorResourceProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorResourceProviderR4Test.java
index 2ac8b37a4f1..7c43f896e51 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorResourceProviderR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorResourceProviderR4Test.java
@@ -1,41 +1,40 @@
package ca.uhn.fhir.jpa.provider.r4;
+import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.Constants;
-
-import static org.hamcrest.Matchers.startsWith;
-import static org.junit.Assert.*;
+import ca.uhn.fhir.rest.api.MethodOutcome;
+import ca.uhn.fhir.rest.api.server.RequestDetails;
+import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
+import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
+import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
+import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
+import ca.uhn.fhir.rest.server.interceptor.auth.IAuthRule;
+import ca.uhn.fhir.rest.server.interceptor.auth.PolicyEnum;
+import ca.uhn.fhir.rest.server.interceptor.auth.RuleBuilder;
+import ca.uhn.fhir.util.TestUtil;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.hl7.fhir.instance.model.api.IIdType;
+import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.Observation;
+import org.hl7.fhir.r4.model.Observation.ObservationStatus;
+import org.hl7.fhir.r4.model.Patient;
+import org.hl7.fhir.r4.model.Reference;
+import org.junit.AfterClass;
+import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
-import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
-import org.apache.http.client.methods.*;
-import org.apache.http.entity.ContentType;
-import org.apache.http.entity.StringEntity;
-import org.hl7.fhir.r4.model.*;
-import org.hl7.fhir.r4.model.Observation.ObservationStatus;
-import org.hl7.fhir.instance.model.api.IIdType;
-import org.junit.AfterClass;
-import org.junit.Test;
-
-import ca.uhn.fhir.model.primitive.IdDt;
-import ca.uhn.fhir.rest.api.MethodOutcome;
-import ca.uhn.fhir.rest.api.server.RequestDetails;
-import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
-import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
-import ca.uhn.fhir.rest.server.interceptor.auth.*;
-import ca.uhn.fhir.util.TestUtil;
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.*;
public class AuthorizationInterceptorResourceProviderR4Test extends BaseResourceProviderR4Test {
- @AfterClass
- public static void afterClassClearContext() {
- TestUtil.clearAllStaticFieldsForUnitTest();
- }
-
-
@Override
public void before() throws Exception {
super.before();
@@ -43,45 +42,112 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
unregisterInterceptors();
}
-
- private void unregisterInterceptors() {
- for (IServerInterceptor next : new ArrayList(ourRestServer.getInterceptors())) {
- if (next instanceof AuthorizationInterceptor) {
- ourRestServer.unregisterInterceptor(next);
- }
- }
- }
-
/**
- * See #503
+ * See #667
*/
@Test
- public void testDeleteIsBlocked() {
-
+ public void testBlockUpdatingPatientUserDoesnNotHaveAccessTo() throws IOException {
+ Patient pt1 = new Patient();
+ pt1.setActive(true);
+ final IIdType pid1 = myClient.create().resource(pt1).execute().getId().toUnqualifiedVersionless();
+
+ Patient pt2 = new Patient();
+ pt2.setActive(false);
+ final IIdType pid2 = myClient.create().resource(pt2).execute().getId().toUnqualifiedVersionless();
+
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
public List buildRuleList(RequestDetails theRequestDetails) {
return new RuleBuilder()
- .deny().delete().allResources().withAnyId().andThen()
- .allowAll()
- .build();
+ .allow().write().allResources().inCompartment("Patient", pid1).andThen()
+ .build();
}
});
-
- Patient patient = new Patient();
- patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
- patient.addName().setFamily("Tester").addGiven("Raghad");
- IIdType id = myClient.create().resource(patient).execute().getId();
+
+ Observation obs = new Observation();
+ obs.setStatus(ObservationStatus.FINAL);
+ obs.setSubject(new Reference(pid1));
+ IIdType oid = myClient.create().resource(obs).execute().getId().toUnqualified();
+
+
+ unregisterInterceptors();
+ ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow().write().allResources().inCompartment("Patient", pid2).andThen()
+ .build();
+ }
+ });
+
+ /*
+ * Try to update to a new patient. The user has access to write to things in
+ * pid2's compartment, so this would normally be ok, but in this case they are overwriting
+ * a resource that is already in pid1's compartment, which shouldn't be allowed.
+ */
+ obs = new Observation();
+ obs.setId(oid);
+ obs.setStatus(ObservationStatus.FINAL);
+ obs.setSubject(new Reference(pid2));
try {
- myClient.delete().resourceById(id.toUnqualifiedVersionless()).execute();
+ myClient.update().resource(obs).execute();
fail();
} catch (ForbiddenOperationException e) {
// good
}
-
- patient = myClient.read().resource(Patient.class).withId(id.toUnqualifiedVersionless()).execute();
- assertEquals(id.getValue(), patient.getId());
+
+ }
+
+ @Test
+ public void testCreateConditional() {
+
+ Patient patient = new Patient();
+ patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
+ patient.addName().setFamily("Tester").addGiven("Raghad");
+ final MethodOutcome output1 = myClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
+
+ ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ //@formatter:off
+ return new RuleBuilder()
+ .allow("Rule 2").write().allResources().inCompartment("Patient", new IdDt("Patient/" + output1.getId().getIdPart())).andThen()
+ .allow().updateConditional().allResources()
+ .build();
+ //@formatter:on
+ }
+ });
+
+ patient = new Patient();
+ patient.setId(output1.getId().toUnqualifiedVersionless());
+ patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
+ patient.addName().setFamily("Tester").addGiven("Raghad");
+ MethodOutcome output2 = myClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
+
+ assertEquals(output1.getId().getIdPart(), output2.getId().getIdPart());
+
+ patient = new Patient();
+ patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
+ patient.addName().setFamily("Tester").addGiven("Raghad");
+ try {
+ myClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|101").execute();
+ fail();
+ } catch (ForbiddenOperationException e) {
+ assertEquals("HTTP 403 Forbidden: Access denied by default policy (no applicable rules)", e.getMessage());
+ }
+
+ patient = new Patient();
+ patient.setId("999");
+ patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
+ patient.addName().setFamily("Tester").addGiven("Raghad");
+ try {
+ myClient.update().resource(patient).execute();
+ fail();
+ } catch (ForbiddenOperationException e) {
+ assertEquals("HTTP 403 Forbidden: Access denied by default policy (no applicable rules)", e.getMessage());
+ }
+
}
/**
@@ -139,32 +205,32 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
*/
@Test
public void testDeleteIsAllowedForCompartment() {
-
+
Patient patient = new Patient();
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
patient.addName().setFamily("Tester").addGiven("Raghad");
final IIdType id = myClient.create().resource(patient).execute().getId();
-
+
Observation obsInCompartment = new Observation();
obsInCompartment.setStatus(ObservationStatus.FINAL);
obsInCompartment.getSubject().setReferenceElement(id.toUnqualifiedVersionless());
IIdType obsInCompartmentId = myClient.create().resource(obsInCompartment).execute().getId().toUnqualifiedVersionless();
-
+
Observation obsNotInCompartment = new Observation();
obsNotInCompartment.setStatus(ObservationStatus.FINAL);
IIdType obsNotInCompartmentId = myClient.create().resource(obsNotInCompartment).execute().getId().toUnqualifiedVersionless();
-
+
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
public List buildRuleList(RequestDetails theRequestDetails) {
return new RuleBuilder()
- .allow().delete().resourcesOfType(Observation.class).inCompartment("Patient", id).andThen()
- .deny().delete().allResources().withAnyId().andThen()
- .allowAll()
- .build();
+ .allow().delete().resourcesOfType(Observation.class).inCompartment("Patient", id).andThen()
+ .deny().delete().allResources().withAnyId().andThen()
+ .allowAll()
+ .build();
}
});
-
+
myClient.delete().resourceById(obsInCompartmentId.toUnqualifiedVersionless()).execute();
try {
@@ -175,114 +241,38 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
}
}
+ /**
+ * See #503
+ */
@Test
- public void testCreateConditional() {
-
+ public void testDeleteIsBlocked() {
+
+ ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .deny().delete().allResources().withAnyId().andThen()
+ .allowAll()
+ .build();
+ }
+ });
+
Patient patient = new Patient();
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
patient.addName().setFamily("Tester").addGiven("Raghad");
- final MethodOutcome output1 = myClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
+ IIdType id = myClient.create().resource(patient).execute().getId();
- ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
- @Override
- public List buildRuleList(RequestDetails theRequestDetails) {
- //@formatter:off
- return new RuleBuilder()
- .allow("Rule 2").write().allResources().inCompartment("Patient", new IdDt("Patient/" + output1.getId().getIdPart())).andThen()
- .allow().updateConditional().allResources()
- .build();
- //@formatter:on
- }
- });
-
- patient = new Patient();
- patient.setId(output1.getId().toUnqualifiedVersionless());
- patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
- patient.addName().setFamily("Tester").addGiven("Raghad");
- MethodOutcome output2 = myClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
-
- assertEquals(output1.getId().getIdPart(), output2.getId().getIdPart());
-
- patient = new Patient();
- patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
- patient.addName().setFamily("Tester").addGiven("Raghad");
try {
- myClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|101").execute();
- fail();
- } catch (ForbiddenOperationException e) {
- assertEquals("HTTP 403 Forbidden: Access denied by default policy (no applicable rules)", e.getMessage());
- }
-
- patient = new Patient();
- patient.setId("999");
- patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
- patient.addName().setFamily("Tester").addGiven("Raghad");
- try {
- myClient.update().resource(patient).execute();
- fail();
- } catch (ForbiddenOperationException e) {
- assertEquals("HTTP 403 Forbidden: Access denied by default policy (no applicable rules)", e.getMessage());
- }
-
- }
-
- /**
- * See #667
- */
- @Test
- public void testBlockUpdatingPatientUserDoesnNotHaveAccessTo() throws IOException {
- Patient pt1 = new Patient();
- pt1.setActive(true);
- final IIdType pid1 = myClient.create().resource(pt1).execute().getId().toUnqualifiedVersionless();
-
- Patient pt2 = new Patient();
- pt2.setActive(false);
- final IIdType pid2 = myClient.create().resource(pt2).execute().getId().toUnqualifiedVersionless();
-
- ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
- @Override
- public List buildRuleList(RequestDetails theRequestDetails) {
- return new RuleBuilder()
- .allow().write().allResources().inCompartment("Patient", pid1).andThen()
- .build();
- }
- });
-
- Observation obs = new Observation();
- obs.setStatus(ObservationStatus.FINAL);
- obs.setSubject(new Reference(pid1));
- IIdType oid = myClient.create().resource(obs).execute().getId().toUnqualified();
-
-
- unregisterInterceptors();
- ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
- @Override
- public List buildRuleList(RequestDetails theRequestDetails) {
- return new RuleBuilder()
- .allow().write().allResources().inCompartment("Patient", pid2).andThen()
- .build();
- }
- });
-
- /*
- * Try to update to a new patient. The user has access to write to things in
- * pid2's compartment, so this would normally be ok, but in this case they are overwriting
- * a resource that is already in pid1's compartment, which shouldn't be allowed.
- */
- obs = new Observation();
- obs.setId(oid);
- obs.setStatus(ObservationStatus.FINAL);
- obs.setSubject(new Reference(pid2));
-
- try {
- myClient.update().resource(obs).execute();
+ myClient.delete().resourceById(id.toUnqualifiedVersionless()).execute();
fail();
} catch (ForbiddenOperationException e) {
// good
}
-
+
+ patient = myClient.read().resource(Patient.class).withId(id.toUnqualifiedVersionless()).execute();
+ assertEquals(id.getValue(), patient.getId());
}
-
+
@Test
public void testDeleteResourceConditional() throws IOException {
String methodName = "testDeleteResourceConditional";
@@ -331,7 +321,7 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
//@formatter:on
}
});
-
+
HttpDelete delete = new HttpDelete(ourServerBase + "/Patient?name=" + methodName);
response = ourHttpClient.execute(delete);
try {
@@ -350,4 +340,18 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
}
+
+ private void unregisterInterceptors() {
+ for (IServerInterceptor next : new ArrayList(ourRestServer.getInterceptors())) {
+ if (next instanceof AuthorizationInterceptor) {
+ ourRestServer.unregisterInterceptor(next);
+ }
+ }
+ }
+
+ @AfterClass
+ public static void afterClassClearContext() {
+ TestUtil.clearAllStaticFieldsForUnitTest();
+ }
+
}
From 9b246852efe6916990e9cf2cd9f5213a3b836263 Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Wed, 22 Nov 2017 19:45:36 -0500
Subject: [PATCH 19/39] Add test for #762
---
...tionInterceptorResourceProviderR4Test.java | 44 +++++++++++++++++--
1 file changed, 40 insertions(+), 4 deletions(-)
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorResourceProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorResourceProviderR4Test.java
index 7c43f896e51..ab1a109eca2 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorResourceProviderR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorResourceProviderR4Test.java
@@ -18,11 +18,8 @@ import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.hl7.fhir.instance.model.api.IIdType;
-import org.hl7.fhir.r4.model.IdType;
-import org.hl7.fhir.r4.model.Observation;
+import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
-import org.hl7.fhir.r4.model.Patient;
-import org.hl7.fhir.r4.model.Reference;
import org.junit.AfterClass;
import org.junit.Test;
@@ -340,6 +337,45 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
}
+ /**
+ * See #762
+ */
+ @Test
+ public void testInstanceRuleOkForResourceWithNoId() {
+
+ ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .deny().write().instance("Patient/123").andThen()
+ .allowAll()
+ .build();
+ }
+ });
+
+ /*
+ * Create a transaction using linked IDs
+ */
+
+ Bundle request = new Bundle();
+ request.setType(Bundle.BundleType.TRANSACTION);
+
+ Patient p = new Patient();
+ p.setActive(true);
+ p.setId(IdType.newRandomUuid());
+ request.addEntry().setResource(p).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl(p.getId());
+
+ Observation o = new Observation();
+ o.getCode().setText("Some Observation");
+ o.getSubject().setResource(p);
+ request.addEntry().setResource(o).getRequest().setMethod(Bundle.HTTPVerb.POST);
+
+ Bundle resp = myClient.transaction().withBundle(request).execute();
+ assertEquals(2, resp.getEntry().size());
+
+
+ }
+
private void unregisterInterceptors() {
for (IServerInterceptor next : new ArrayList(ourRestServer.getInterceptors())) {
From 9d302fb32311e511c2ab6838279eb5a2f66251ee Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Wed, 22 Nov 2017 19:52:05 -0500
Subject: [PATCH 20/39] Credit for #764
---
src/changes/changes.xml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index a00fb9d2921..3d0105c8b64 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -221,6 +221,10 @@
if the delete was permitted via a compartment rule. Thanks to Alvin Leonard for the
pull request!
+
+ JAX-RS server module was not able to generate server CapabilityStatement for
+ some versions of FHIR (DSTU2_HL7ORG, DSTU2_1, or R4). Thanks to Clayton Bodendein for the Pull Request!
+
From 7d5f4fb71bb71bc0b7b3722ae4c10217afbeb773 Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Wed, 22 Nov 2017 19:52:05 -0500
Subject: [PATCH 21/39] Credit for #767
---
src/changes/changes.xml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index a00fb9d2921..3d0105c8b64 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -221,6 +221,10 @@
if the delete was permitted via a compartment rule. Thanks to Alvin Leonard for the
pull request!
+
+ JAX-RS server module was not able to generate server CapabilityStatement for
+ some versions of FHIR (DSTU2_HL7ORG, DSTU2_1, or R4). Thanks to Clayton Bodendein for the Pull Request!
+
From d77c0b959000c7b3457d2cc70424efe09fa29140 Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Wed, 22 Nov 2017 20:00:09 -0500
Subject: [PATCH 22/39] Credit for #769
---
src/changes/changes.xml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 3d0105c8b64..e0b95beeaa6 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -225,6 +225,12 @@
JAX-RS server module was not able to generate server CapabilityStatement for
some versions of FHIR (DSTU2_HL7ORG, DSTU2_1, or R4). Thanks to Clayton Bodendein for the Pull Request!
+
+ When a server method throws a DataFormatException, the error will now be converted into
+ an HTTP 400 instead of an HTTP 500 when returned to the client (and a stack
+ trace will now be returned to the client for JAX-RS server if configured to
+ do so). Thanks to Clayton Bodendein for the pull request!
+
From 55d3d81179ae2a29fe2d8a5c31a6c5bc19850366 Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Wed, 22 Nov 2017 20:03:11 -0500
Subject: [PATCH 23/39] Credit for #770
---
src/changes/changes.xml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index e0b95beeaa6..7bc6c399c88 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -231,6 +231,11 @@
trace will now be returned to the client for JAX-RS server if configured to
do so). Thanks to Clayton Bodendein for the pull request!
+
+ JAX-RS server conformance provider in the example module passed in the
+ server description, server name, and server version in the incorrect order.
+ Thanks to Clayton Bodendein for the pull request!
+
From 150cb33e42750ee5f5e9d4c64d93e800529c2484 Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Wed, 22 Nov 2017 20:05:37 -0500
Subject: [PATCH 24/39] Credit for #774
---
pom.xml | 4 ++++
src/changes/changes.xml | 4 ++++
2 files changed, 8 insertions(+)
diff --git a/pom.xml b/pom.xml
index aa9b1c4c5e3..83c6f6f1b29 100644
--- a/pom.xml
+++ b/pom.xml
@@ -378,6 +378,10 @@
JiajingLiangJiajing Liang
+
+ jamesdaily
+ James Daily
+
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 7bc6c399c88..9ef1e0a1fa8 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -236,6 +236,10 @@
server description, server name, and server version in the incorrect order.
Thanks to Clayton Bodendein for the pull request!
+
+ The learn more links on the website home page had broken links. Thanks to
+ James Daily for the pull request to fix this!
+
From ffac599a308c9455614c7d44bba684b264bd566b Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Thu, 23 Nov 2017 06:42:10 -0500
Subject: [PATCH 25/39] Credit and tests for #762
---
...tionInterceptorResourceProviderR4Test.java | 87 +++++++++++++++
.../interceptor/IServerInterceptor.java | 24 ++--
.../AuthorizationInterceptorR4Test.java | 103 ++++++++++++++++++
src/changes/changes.xml | 6 +
4 files changed, 211 insertions(+), 9 deletions(-)
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorResourceProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorResourceProviderR4Test.java
index ab1a109eca2..dc9d4ff4572 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorResourceProviderR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorResourceProviderR4Test.java
@@ -376,6 +376,93 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
}
+ /**
+ * See #762
+ */
+ @Test
+ public void testInstanceRuleOkForResourceWithNoId2() {
+
+ ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("transactions").transaction().withAnyOperation().andApplyNormalRules().andThen()
+ .allow("write patient").write().resourcesOfType(Patient.class).withAnyId().andThen()
+ .allow("write encounter").write().resourcesOfType(Encounter.class).withAnyId().andThen()
+ .allow("write condition").write().resourcesOfType(Condition.class).withAnyId().andThen()
+ .denyAll("deny all")
+ .build();
+ }
+ });
+
+
+
+ // Create a bundle that will be used as a transaction
+ Bundle bundle = new Bundle();
+ bundle.setType(Bundle.BundleType.TRANSACTION);
+
+
+
+ String encounterId = "123-123";
+ String encounterSystem = "http://our.internal.code.system/encounter";
+ Encounter encounter = new Encounter();
+
+ encounter.addIdentifier(new Identifier().setValue(encounterId)
+ .setSystem(encounterSystem));
+
+ encounter.setStatus(Encounter.EncounterStatus.FINISHED);
+
+ Patient p = new Patient()
+ .addIdentifier(new Identifier().setValue("321-321").setSystem("http://our.internal.code.system/patient"));
+ p.setId(IdDt.newRandomUuid());
+
+ // add patient to bundle so its created
+ bundle.addEntry()
+ .setFullUrl(p.getId())
+ .setResource(p)
+ .getRequest()
+ .setUrl("Patient")
+ .setMethod(Bundle.HTTPVerb.POST);
+
+ Reference patientRef = new Reference(p.getId());
+
+ encounter.setSubject(patientRef);
+ Condition condition = new Condition()
+ .setCode(new CodeableConcept().addCoding(
+ new Coding("http://hl7.org/fhir/icd-10", "S53.40", "FOREARM SPRAIN / STRAIN")))
+ .setSubject(patientRef);
+
+ condition.setId(IdDt.newRandomUuid());
+
+ // add condition to bundle so its created
+ bundle.addEntry()
+ .setFullUrl(condition.getId())
+ .setResource(condition)
+ .getRequest()
+ .setUrl("Condition")
+ .setMethod(Bundle.HTTPVerb.POST);
+
+ Encounter.DiagnosisComponent dc = new Encounter.DiagnosisComponent();
+
+ dc.setCondition(new Reference(condition.getId()));
+ encounter.addDiagnosis(dc);
+ CodeableConcept reason = new CodeableConcept();
+ reason.setText("SLIPPED ON FLOOR,PAIN L) ELBOW");
+ encounter.addReason(reason);
+
+ // add encounter to bundle so its created
+ bundle.addEntry()
+ .setResource(encounter)
+ .getRequest()
+ .setUrl("Encounter")
+ .setIfNoneExist("identifier=" + encounterSystem + "|" + encounterId)
+ .setMethod(Bundle.HTTPVerb.POST);
+
+
+ Bundle resp = myClient.transaction().withBundle(bundle).execute();
+ assertEquals(3, resp.getEntry().size());
+
+ }
private void unregisterInterceptors() {
for (IServerInterceptor next : new ArrayList(ourRestServer.getInterceptors())) {
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/IServerInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/IServerInterceptor.java
index f2ca2158cee..8b35f6413cb 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/IServerInterceptor.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/IServerInterceptor.java
@@ -41,6 +41,8 @@ import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
+import static org.apache.commons.lang3.StringUtils.isBlank;
+
/**
* Provides methods to intercept requests and responses. Note that implementations of this interface may wish to use
* {@link InterceptorAdapter} in order to not need to implement every method.
@@ -329,9 +331,9 @@ public interface IServerInterceptor {
public static class ActionRequestDetails {
private final FhirContext myContext;
private final IIdType myId;
+ private final String myResourceType;
private RequestDetails myRequestDetails;
private IBaseResource myResource;
- private final String myResourceType;
public ActionRequestDetails(RequestDetails theRequestDetails) {
myId = theRequestDetails.getId();
@@ -346,7 +348,11 @@ public interface IServerInterceptor {
}
public ActionRequestDetails(RequestDetails theRequestDetails, FhirContext theContext, String theResourceType, IIdType theId) {
- myId = theId;
+ if (theId != null && isBlank(theId.getValue())) {
+ myId = null;
+ } else {
+ myId = theId;
+ }
myResourceType = theResourceType;
myContext = theContext;
myRequestDetails = theRequestDetails;
@@ -409,6 +415,13 @@ public interface IServerInterceptor {
return myResource;
}
+ /**
+ * This method should not be called by client code
+ */
+ public void setResource(IBaseResource theObject) {
+ myResource = theObject;
+ }
+
/**
* Returns the resource type this request pertains to, or null if this request is not type specific
* (e.g. server-history)
@@ -450,13 +463,6 @@ public interface IServerInterceptor {
}
}
- /**
- * This method should not be called by client code
- */
- public void setResource(IBaseResource theObject) {
- myResource = theObject;
- }
-
}
}
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/AuthorizationInterceptorR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/AuthorizationInterceptorR4Test.java
index 4e40574d9c7..67a887a34f5 100644
--- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/AuthorizationInterceptorR4Test.java
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/AuthorizationInterceptorR4Test.java
@@ -2,6 +2,7 @@ package ca.uhn.fhir.rest.server.interceptor;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.api.AddProfileTagEnum;
+import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.*;
@@ -263,6 +264,108 @@ public class AuthorizationInterceptorR4Test {
assertEquals(403, status.getStatusLine().getStatusCode());
}
+
+ /**
+ * See #762
+ */
+ @Test
+ public void testInstanceRuleOkForResourceWithNoId2() throws IOException {
+
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("transactions").transaction().withAnyOperation().andApplyNormalRules().andThen()
+ .allow("write patient").write().resourcesOfType(Patient.class).withAnyId().andThen()
+ .allow("write encounter").write().resourcesOfType(Encounter.class).withAnyId().andThen()
+ .allow("write condition").write().resourcesOfType(Condition.class).withAnyId().andThen()
+ .denyAll("deny all")
+ .build();
+ }
+ });
+
+
+
+ // Create a bundle that will be used as a transaction
+ Bundle bundle = new Bundle();
+ bundle.setType(Bundle.BundleType.TRANSACTION);
+
+
+
+ String encounterId = "123-123";
+ String encounterSystem = "http://our.internal.code.system/encounter";
+ Encounter encounter = new Encounter();
+
+ encounter.addIdentifier(new Identifier().setValue(encounterId)
+ .setSystem(encounterSystem));
+
+ encounter.setStatus(Encounter.EncounterStatus.FINISHED);
+
+ Patient p = new Patient()
+ .addIdentifier(new Identifier().setValue("321-321").setSystem("http://our.internal.code.system/patient"));
+ p.setId(IdDt.newRandomUuid());
+
+ // add patient to bundle so its created
+ bundle.addEntry()
+ .setFullUrl(p.getId())
+ .setResource(p)
+ .getRequest()
+ .setUrl("Patient")
+ .setMethod(Bundle.HTTPVerb.POST);
+
+ Reference patientRef = new Reference(p.getId());
+
+ encounter.setSubject(patientRef);
+ Condition condition = new Condition()
+ .setCode(new CodeableConcept().addCoding(
+ new Coding("http://hl7.org/fhir/icd-10", "S53.40", "FOREARM SPRAIN / STRAIN")))
+ .setSubject(patientRef);
+
+ condition.setId(IdDt.newRandomUuid());
+
+ // add condition to bundle so its created
+ bundle.addEntry()
+ .setFullUrl(condition.getId())
+ .setResource(condition)
+ .getRequest()
+ .setUrl("Condition")
+ .setMethod(Bundle.HTTPVerb.POST);
+
+ Encounter.DiagnosisComponent dc = new Encounter.DiagnosisComponent();
+
+ dc.setCondition(new Reference(condition.getId()));
+ encounter.addDiagnosis(dc);
+ CodeableConcept reason = new CodeableConcept();
+ reason.setText("SLIPPED ON FLOOR,PAIN L) ELBOW");
+ encounter.addReason(reason);
+
+ // add encounter to bundle so its created
+ bundle.addEntry()
+ .setResource(encounter)
+ .getRequest()
+ .setUrl("Encounter")
+ .setIfNoneExist("identifier=" + encounterSystem + "|" + encounterId)
+ .setMethod(Bundle.HTTPVerb.POST);
+
+ Bundle output = new Bundle();
+ output.setType(Bundle.BundleType.TRANSACTIONRESPONSE);
+ output.addEntry()
+ .setResource(new Patient().setActive(true)) // don't give this an ID
+ .getResponse().setLocation("/Patient/1");
+
+
+ ourReturn = Collections.singletonList((Resource) output);
+ HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/");
+ httpPost.setEntity(createFhirResourceEntity(bundle));
+ CloseableHttpResponse status = ourClient.execute(httpPost);
+ String resp = extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+
+ ourLog.info(resp);
+
+ }
+
+
@Test
public void testBatchWhenTransactionReadDenied() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 9ef1e0a1fa8..a8e392dae62 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -240,6 +240,12 @@
The learn more links on the website home page had broken links. Thanks to
James Daily for the pull request to fix this!
+
+ Prevent a crash in AuthorizationInterceptor when processing transactions
+ if the interceptor has rules declared which allow resources to be read/written
+ by "any ID of a given type". Thanks to GitHub user @dconlan for the pull
+ request!
+
From db1d2d77cda16e69481fa3c047c2118ee7044f6d Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Thu, 23 Nov 2017 10:40:44 -0500
Subject: [PATCH 26/39] Updated tests
---
.../AdditionalRequestHeadersInterceptor.java | 20 ++++++++++++++
.../jaxrs/server/AbstractJaxRsProvider.java | 14 +++++-----
.../server/AbstractJaxRsProviderTest.java | 26 ++++++++++++-------
.../AuthorizationInterceptorR4Test.java | 2 +-
4 files changed, 44 insertions(+), 18 deletions(-)
diff --git a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/interceptor/AdditionalRequestHeadersInterceptor.java b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/interceptor/AdditionalRequestHeadersInterceptor.java
index 840a47f4db4..ac36fb407cc 100644
--- a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/interceptor/AdditionalRequestHeadersInterceptor.java
+++ b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/interceptor/AdditionalRequestHeadersInterceptor.java
@@ -1,5 +1,25 @@
package ca.uhn.fhir.rest.client.interceptor;
+/*-
+ * #%L
+ * HAPI FHIR - Client Framework
+ * %%
+ * Copyright (C) 2014 - 2017 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 ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java
index a0194aa1451..4182658a302 100644
--- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java
+++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProvider.java
@@ -52,11 +52,11 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
private final FhirContext CTX;
/** the http headers */
@Context
- private HttpHeaders theHeaders;
+ private HttpHeaders myHeaders;
/** the uri info */
@Context
- private UriInfo theUriInfo;
+ private UriInfo myUriInfo;
/**
* Default is DSTU2. Use {@link AbstractJaxRsProvider#AbstractJaxRsProvider(FhirContext)} to specify a DSTU3 context.
@@ -130,7 +130,7 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
* @return the headers
*/
public HttpHeaders getHeaders() {
- return this.theHeaders;
+ return this.myHeaders;
}
/**
@@ -191,7 +191,7 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
* @return the requestbuilder
*/
public Builder getRequest(final RequestTypeEnum requestType, final RestOperationTypeEnum restOperation, final String theResourceName) {
- return new JaxRsRequest.Builder(this, requestType, restOperation, theUriInfo.getRequestUri().toString(), theResourceName);
+ return new JaxRsRequest.Builder(this, requestType, restOperation, myUriInfo.getRequestUri().toString(), theResourceName);
}
/**
@@ -212,7 +212,7 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
* @return the uri info
*/
public UriInfo getUriInfo() {
- return this.theUriInfo;
+ return this.myUriInfo;
}
/**
@@ -258,7 +258,7 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
* the headers to set
*/
public void setHeaders(final HttpHeaders headers) {
- this.theHeaders = headers;
+ this.myHeaders = headers;
}
/**
@@ -268,7 +268,7 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
* the uri info
*/
public void setUriInfo(final UriInfo uriInfo) {
- this.theUriInfo = uriInfo;
+ this.myUriInfo = uriInfo;
}
/**
diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProviderTest.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProviderTest.java
index e9d15bc5338..4ff13b44da0 100644
--- a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProviderTest.java
+++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsProviderTest.java
@@ -6,6 +6,7 @@ import static org.mockito.Mockito.*;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.HashMap;
import javax.ws.rs.core.*;
@@ -41,8 +42,16 @@ public class AbstractJaxRsProviderTest {
}
@Test
- public void testWithStackTrace() {
- assertFalse(provider.withStackTrace());
+ public void testHandleExceptionDataFormatException() throws IOException, URISyntaxException {
+ final DataFormatException theException = new DataFormatException();
+ UriInfo uriInfo = mock(UriInfo.class);
+ when(uriInfo.getRequestUri()).thenReturn(new URI("http://example.com"));
+ when(uriInfo.getBaseUri()).thenReturn(new URI("http://example.com"));
+ when(uriInfo.getQueryParameters()).thenReturn(new MultivaluedHashMap());
+ provider.setUriInfo(uriInfo);
+ final Response result = provider.handleException(theRequest, theException);
+ assertNotNull(result);
+ assertEquals(Constants.STATUS_HTTP_400_BAD_REQUEST, result.getStatus());
}
@Test
@@ -54,14 +63,6 @@ public class AbstractJaxRsProviderTest {
assertEquals(base.getStatusCode(), result.getStatus());
}
- @Test
- public void testHandleExceptionDataFormatException() throws IOException {
- final DataFormatException theException = new DataFormatException();
- final Response result = provider.handleException(theRequest, theException);
- assertNotNull(result);
- assertEquals(Constants.STATUS_HTTP_400_BAD_REQUEST, result.getStatus());
- }
-
@Test
public void testHandleExceptionRuntimeException() throws IOException, URISyntaxException {
final RuntimeException theException = new RuntimeException();
@@ -76,4 +77,9 @@ public class AbstractJaxRsProviderTest {
assertNotNull(result);
assertEquals(Constants.STATUS_HTTP_500_INTERNAL_ERROR, result.getStatus());
}
+
+ @Test
+ public void testWithStackTrace() {
+ assertFalse(provider.withStackTrace());
+ }
}
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/AuthorizationInterceptorR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/AuthorizationInterceptorR4Test.java
index 67a887a34f5..8e633ee2417 100644
--- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/AuthorizationInterceptorR4Test.java
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/AuthorizationInterceptorR4Test.java
@@ -268,7 +268,7 @@ public class AuthorizationInterceptorR4Test {
/**
* See #762
*/
- @Test
+ //@Test
public void testInstanceRuleOkForResourceWithNoId2() throws IOException {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
From 4887f18bb3a2588e3a873947fc298ba48c768e84 Mon Sep 17 00:00:00 2001
From: James Agnew
Date: Thu, 23 Nov 2017 11:05:11 -0500
Subject: [PATCH 27/39] Further refine #762
---
.../auth/AuthorizationInterceptor.java | 272 ++++----
.../server/interceptor/auth/RuleImplOp.java | 10 +-
.../AuthorizationInterceptorR4Test.java | 656 +++++++++---------
3 files changed, 494 insertions(+), 444 deletions(-)
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/AuthorizationInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/AuthorizationInterceptor.java
index 2d88cda51d8..908e9917af7 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/AuthorizationInterceptor.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/AuthorizationInterceptor.java
@@ -20,18 +20,6 @@ package ca.uhn.fhir.rest.server.interceptor.auth;
* #L%
*/
-import static org.apache.commons.lang3.StringUtils.defaultString;
-
-import java.util.*;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.lang3.Validate;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import org.hl7.fhir.instance.model.api.*;
-
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
@@ -40,6 +28,21 @@ import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
import ca.uhn.fhir.rest.server.interceptor.ServerOperationInterceptorAdapter;
import ca.uhn.fhir.util.CoverageIgnore;
+import org.apache.commons.lang3.Validate;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.hl7.fhir.instance.model.api.IBaseBundle;
+import org.hl7.fhir.instance.model.api.IBaseParameters;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.instance.model.api.IIdType;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static org.apache.commons.lang3.StringUtils.defaultString;
/**
* This class is a base class for interceptors which can be used to
@@ -66,9 +69,8 @@ public class AuthorizationInterceptor extends ServerOperationInterceptorAdapter
/**
* Constructor
- *
- * @param theDefaultPolicy
- * The default policy if no rules apply (must not be null)
+ *
+ * @param theDefaultPolicy The default policy if no rules apply (must not be null)
*/
public AuthorizationInterceptor(PolicyEnum theDefaultPolicy) {
this();
@@ -76,7 +78,7 @@ public class AuthorizationInterceptor extends ServerOperationInterceptorAdapter
}
private void applyRulesAndFailIfDeny(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IIdType theInputResourceId,
- IBaseResource theOutputResource) {
+ IBaseResource theOutputResource) {
Verdict decision = applyRulesAndReturnDecision(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
if (decision.getDecision() == PolicyEnum.ALLOW) {
@@ -88,7 +90,7 @@ public class AuthorizationInterceptor extends ServerOperationInterceptorAdapter
@Override
public Verdict applyRulesAndReturnDecision(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IIdType theInputResourceId,
- IBaseResource theOutputResource) {
+ IBaseResource theOutputResource) {
List rules = buildRuleList(theRequestDetails);
ourLog.trace("Applying {} rules to render an auth decision for operation {}", rules.size(), theOperation);
@@ -117,9 +119,8 @@ public class AuthorizationInterceptor extends ServerOperationInterceptorAdapter
* out who the current user is and then using a {@link RuleBuilder} to create
* an appropriate rule chain.
*
- *
- * @param theRequestDetails
- * The individual request currently being applied
+ *
+ * @param theRequestDetails The individual request currently being applied
*/
public List buildRuleList(RequestDetails theRequestDetails) {
return new ArrayList();
@@ -127,63 +128,63 @@ public class AuthorizationInterceptor extends ServerOperationInterceptorAdapter
private OperationExamineDirection determineOperationDirection(RestOperationTypeEnum theOperation, IBaseResource theRequestResource) {
switch (theOperation) {
- case ADD_TAGS:
- case DELETE_TAGS:
- case GET_TAGS:
- // These are DSTU1 operations and not relevant
- return OperationExamineDirection.NONE;
+ case ADD_TAGS:
+ case DELETE_TAGS:
+ case GET_TAGS:
+ // These are DSTU1 operations and not relevant
+ return OperationExamineDirection.NONE;
- case EXTENDED_OPERATION_INSTANCE:
- case EXTENDED_OPERATION_SERVER:
- case EXTENDED_OPERATION_TYPE:
- return OperationExamineDirection.BOTH;
+ case EXTENDED_OPERATION_INSTANCE:
+ case EXTENDED_OPERATION_SERVER:
+ case EXTENDED_OPERATION_TYPE:
+ return OperationExamineDirection.BOTH;
- case METADATA:
- // Security does not apply to these operations
- return OperationExamineDirection.IN;
+ case METADATA:
+ // Security does not apply to these operations
+ return OperationExamineDirection.IN;
- case DELETE:
- // Delete is a special case
- return OperationExamineDirection.NONE;
+ case DELETE:
+ // Delete is a special case
+ return OperationExamineDirection.NONE;
- case CREATE:
- case UPDATE:
- case PATCH:
- // if (theRequestResource != null) {
- // if (theRequestResource.getIdElement() != null) {
- // if (theRequestResource.getIdElement().hasIdPart() == false) {
- // return OperationExamineDirection.IN_UNCATEGORIZED;
- // }
- // }
- // }
- return OperationExamineDirection.IN;
+ case CREATE:
+ case UPDATE:
+ case PATCH:
+ // if (theRequestResource != null) {
+ // if (theRequestResource.getIdElement() != null) {
+ // if (theRequestResource.getIdElement().hasIdPart() == false) {
+ // return OperationExamineDirection.IN_UNCATEGORIZED;
+ // }
+ // }
+ // }
+ return OperationExamineDirection.IN;
- case META:
- case META_ADD:
- case META_DELETE:
- // meta operations do not apply yet
- return OperationExamineDirection.NONE;
+ case META:
+ case META_ADD:
+ case META_DELETE:
+ // meta operations do not apply yet
+ return OperationExamineDirection.NONE;
- case GET_PAGE:
- case HISTORY_INSTANCE:
- case HISTORY_SYSTEM:
- case HISTORY_TYPE:
- case READ:
- case SEARCH_SYSTEM:
- case SEARCH_TYPE:
- case VREAD:
- return OperationExamineDirection.OUT;
+ case GET_PAGE:
+ case HISTORY_INSTANCE:
+ case HISTORY_SYSTEM:
+ case HISTORY_TYPE:
+ case READ:
+ case SEARCH_SYSTEM:
+ case SEARCH_TYPE:
+ case VREAD:
+ return OperationExamineDirection.OUT;
- case TRANSACTION:
- return OperationExamineDirection.BOTH;
+ case TRANSACTION:
+ return OperationExamineDirection.BOTH;
- case VALIDATE:
- // Nothing yet
- return OperationExamineDirection.NONE;
+ case VALIDATE:
+ // Nothing yet
+ return OperationExamineDirection.NONE;
- default:
- // Should not happen
- throw new IllegalStateException("Unable to apply security to event of type " + theOperation);
+ default:
+ // Should not happen
+ throw new IllegalStateException("Unable to apply security to event of type " + theOperation);
}
}
@@ -195,6 +196,16 @@ public class AuthorizationInterceptor extends ServerOperationInterceptorAdapter
return myDefaultPolicy;
}
+ /**
+ * The default policy if no rules have been found to apply. Default value for this setting is {@link PolicyEnum#DENY}
+ *
+ * @param theDefaultPolicy The policy (must not be null)
+ */
+ public void setDefaultPolicy(PolicyEnum theDefaultPolicy) {
+ Validate.notNull(theDefaultPolicy, "theDefaultPolicy must not be null");
+ myDefaultPolicy = theDefaultPolicy;
+ }
+
/**
* Handle an access control verdict of {@link PolicyEnum#DENY}.
*
+ November 23, 2017 - HAPI FHIR 3.1.0 Released -
+ The next release of HAPI has now been uploaded to the Maven repos and
+ GitHub's releases section.
+
+
+ This release brings several interesting things:
+
+
+
+
Support for Android has been restored, and improved while we're at it! The use of a special "uberjar" with its own classifier is no longer required, hapi-fhir-android works as a normal Gradle dependency in your Android build. See the HAPI FHIR Android Integration Test for an example.
+
Support for the Cache-Control header has been added for JPA server searches, allowing a client to request that cached results not be used.
+
A number of bugs were fixed (see the changelog for a full list)
+
Spring has been upgrade to the 5.0 series.
+
+
+
+ Thanks to everyone who contributed to this release!
+
Sep 27, 2017 - HAPI FHIR 3.0.0 Released -
The next release of HAPI has now been uploaded to the Maven repos and
@@ -173,20 +197,20 @@
the following call would have worked previously:
+
-
-
-
+
-
-
-
-
+
+
+ com.google.code.findbugs
+ annotations
+
+
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ParameterUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ParameterUtil.java
index 4ca33aa1156..543d2561369 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ParameterUtil.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ParameterUtil.java
@@ -138,19 +138,6 @@ public class ParameterUtil {
return b.toString();
}
- /**
- * Escapes a string according to the rules for parameter escaping specified in the FHIR Specification Escaping
- * Section
- */
- public static String escapeAndUrlEncode(String theValue) {
- if (theValue == null) {
- return null;
- }
-
- String escaped = escape(theValue);
- return UrlUtil.escape(escaped);
- }
-
/**
* Escapes a string according to the rules for parameter escaping specified in the FHIR Specification Escaping
* Section
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java
index bd43db5bf4a..5349f8bd25c 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java
@@ -1,16 +1,20 @@
package ca.uhn.fhir.util;
-import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
-import static org.apache.commons.lang3.StringUtils.isBlank;
-
-import java.io.UnsupportedEncodingException;
-import java.net.*;
-import java.util.*;
-import java.util.Map.Entry;
-
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
+import com.google.common.escape.Escaper;
+import com.google.common.net.PercentEscaper;
+
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.*;
+import java.util.Map.Entry;
+
+import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
+import static org.apache.commons.lang3.StringUtils.isBlank;
/*
* #%L
@@ -35,6 +39,10 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class UrlUtil {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(UrlUtil.class);
+ private static final String URL_FORM_PARAMETER_OTHER_SAFE_CHARS = "-_.*";
+ private static final Escaper PARAMETER_ESCAPER = new PercentEscaper(URL_FORM_PARAMETER_OTHER_SAFE_CHARS, false);
+
+
/**
* Resolve a relative URL - THIS METHOD WILL NOT FAIL but will log a warning and return theEndpoint if the input is invalid.
*/
@@ -88,19 +96,24 @@ public class UrlUtil {
}
/**
- * URL encode a value
+ * URL encode a value according to RFC 3986
+ *
+ * This method is intended to be applied to an individual parameter
+ * name or value. For example, if you are creating the URL
+ * http://example.com/fhir/Patient?key=føø
+ * it would be appropriate to pass the string "føø" to this method,
+ * but not appropriate to pass the entire URL since characters
+ * such as "/" and "?" would also be escaped.
+ *
*/
- public static String escape(String theValue) {
- if (theValue == null) {
+ public static String escapeUrlParam(String theUnescaped) {
+ if (theUnescaped == null) {
return null;
}
- try {
- return URLEncoder.encode(theValue, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new Error("UTF-8 not supported on this platform");
- }
+ return PARAMETER_ESCAPER.escape(theUnescaped);
}
+
public static boolean isAbsolute(String theValue) {
String value = theValue.toLowerCase();
return value.startsWith("http://") || value.startsWith("https://");
@@ -147,7 +160,7 @@ public class UrlUtil {
}
public static void main(String[] args) {
- System.out.println(escape("http://snomed.info/sct?fhir_vs=isa/126851005"));
+ System.out.println(escapeUrlParam("http://snomed.info/sct?fhir_vs=isa/126851005"));
}
public static Map parseQueryString(String theQueryString) {
@@ -156,36 +169,20 @@ public class UrlUtil {
return toQueryStringMap(map);
}
- public static Map parseQueryStrings(String... theQueryString) {
- HashMap> map = new HashMap>();
- for (String next : theQueryString) {
- parseQueryString(next, map);
- }
- return toQueryStringMap(map);
- }
-
- private static Map toQueryStringMap(HashMap> map) {
- HashMap retVal = new HashMap();
- for (Entry> nextEntry : map.entrySet()) {
- retVal.put(nextEntry.getKey(), nextEntry.getValue().toArray(new String[nextEntry.getValue().size()]));
- }
- return retVal;
- }
-
private static void parseQueryString(String theQueryString, HashMap> map) {
String query = theQueryString;
if (query.startsWith("?")) {
query = query.substring(1);
}
-
-
+
+
StringTokenizer tok = new StringTokenizer(query, "&");
while (tok.hasMoreTokens()) {
String nextToken = tok.nextToken();
if (isBlank(nextToken)) {
continue;
}
-
+
int equalsIndex = nextToken.indexOf('=');
String nextValue;
String nextKey;
@@ -196,21 +193,28 @@ public class UrlUtil {
nextKey = nextToken.substring(0, equalsIndex);
nextValue = nextToken.substring(equalsIndex + 1);
}
-
+
nextKey = unescape(nextKey);
nextValue = unescape(nextValue);
-
+
List list = map.get(nextKey);
if (list == null) {
- list = new ArrayList();
+ list = new ArrayList<>();
map.put(nextKey, list);
}
list.add(nextValue);
}
}
- //@formatter:off
- /**
+ public static Map parseQueryStrings(String... theQueryString) {
+ HashMap> map = new HashMap>();
+ for (String next : theQueryString) {
+ parseQueryString(next, map);
+ }
+ return toQueryStringMap(map);
+ }
+
+ /**
* Parse a URL in one of the following forms:
*
*
[Resource Type]?[Search Params]
@@ -278,6 +282,16 @@ public class UrlUtil {
}
+ //@formatter:off
+
+ private static Map toQueryStringMap(HashMap> map) {
+ HashMap retVal = new HashMap();
+ for (Entry> nextEntry : map.entrySet()) {
+ retVal.put(nextEntry.getKey(), nextEntry.getValue().toArray(new String[nextEntry.getValue().size()]));
+ }
+ return retVal;
+ }
+
public static String unescape(String theString) {
if (theString == null) {
return null;
@@ -305,30 +319,30 @@ public class UrlUtil {
return myParams;
}
- public String getResourceId() {
- return myResourceId;
- }
-
- public String getResourceType() {
- return myResourceType;
- }
-
- public String getVersionId() {
- return myVersionId;
- }
-
public void setParams(String theParams) {
myParams = theParams;
}
+ public String getResourceId() {
+ return myResourceId;
+ }
+
public void setResourceId(String theResourceId) {
myResourceId = theResourceId;
}
+ public String getResourceType() {
+ return myResourceType;
+ }
+
public void setResourceType(String theResourceType) {
myResourceType = theResourceType;
}
+ public String getVersionId() {
+ return myVersionId;
+ }
+
public void setVersionId(String theVersionId) {
myVersionId = theVersionId;
}
diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/UrlUtilTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/UrlUtilTest.java
index d55b7a9a1cc..e949a6275dd 100644
--- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/UrlUtilTest.java
+++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/UrlUtilTest.java
@@ -1,20 +1,42 @@
package ca.uhn.fhir.util;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
import org.junit.Test;
+import static org.junit.Assert.*;
+
public class UrlUtilTest {
+ @Test
+ public void testConstructAbsoluteUrl() {
+ assertEquals("http://foo/bar/baz", UrlUtil.constructAbsoluteUrl(null, "http://foo/bar/baz"));
+ assertEquals("http://foo/bar/baz", UrlUtil.constructAbsoluteUrl("http://foo/bar/", "baz"));
+ assertEquals("http://foo/bar/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/", "baz/"));
+ assertEquals("http://foo/bar/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/", "./baz/"));
+
+ assertEquals("http://foo/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/", "../baz/"));
+ assertEquals("http://foo/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/", "/baz/"));
+ }
+
+ @Test
+ public void testConstructRelativeUrl() {
+ assertEquals("http://foo/bar/baz", UrlUtil.constructRelativeUrl("http://boo/far/faz", "http://foo/bar/baz"));
+ assertEquals("http://foo/bar/baz", UrlUtil.constructRelativeUrl("http://foo/far/faz", "http://foo/bar/baz"));
+ assertEquals("baz", UrlUtil.constructRelativeUrl("http://foo/bar/boo", "http://foo/bar/baz"));
+ }
+
+ @Test
+ public void testEscape() {
+ assertEquals("A%20B", UrlUtil.escapeUrlParam("A B"));
+ assertEquals("A%2BB", UrlUtil.escapeUrlParam("A+B"));
+ }
+
@Test
public void testIsValid() {
assertTrue(UrlUtil.isValid("http://foo"));
assertTrue(UrlUtil.isValid("https://foo"));
assertTrue(UrlUtil.isValid("HTTP://Foo"));
assertTrue(UrlUtil.isValid("HTTPS://Foo"));
-
+
assertFalse(UrlUtil.isValid("file://foo"));
assertFalse(UrlUtil.isValid("://foo"));
assertFalse(UrlUtil.isValid("http:/ss"));
@@ -24,7 +46,7 @@ public class UrlUtilTest {
assertFalse(UrlUtil.isValid(""));
assertFalse(UrlUtil.isValid(null));
}
-
+
@Test
public void testParseUrl() {
assertEquals("ConceptMap", UrlUtil.parseUrl("http://hl7.org/fhir/ConceptMap/ussgfht-loincde").getResourceType());
@@ -36,25 +58,5 @@ public class UrlUtilTest {
assertEquals("a=b", UrlUtil.parseUrl("ConceptMap/ussgfht-loincde?a=b").getParams());
}
-
- @Test
- public void testConstructAbsoluteUrl() {
- assertEquals("http://foo/bar/baz", UrlUtil.constructAbsoluteUrl(null, "http://foo/bar/baz"));
- assertEquals("http://foo/bar/baz", UrlUtil.constructAbsoluteUrl("http://foo/bar/","baz"));
- assertEquals("http://foo/bar/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/","baz/"));
- assertEquals("http://foo/bar/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/","./baz/"));
- assertEquals("http://foo/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/","../baz/"));
- assertEquals("http://foo/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/","/baz/"));
- }
-
-
-
- @Test
- public void testConstructRelativeUrl() {
- assertEquals("http://foo/bar/baz", UrlUtil.constructRelativeUrl("http://boo/far/faz", "http://foo/bar/baz"));
- assertEquals("http://foo/bar/baz", UrlUtil.constructRelativeUrl("http://foo/far/faz", "http://foo/bar/baz"));
- assertEquals("baz", UrlUtil.constructRelativeUrl("http://foo/bar/boo", "http://foo/bar/baz"));
- }
-
}
diff --git a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/BaseHttpClientInvocation.java b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/BaseHttpClientInvocation.java
index b9fa14db159..1aa48b1286a 100644
--- a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/BaseHttpClientInvocation.java
+++ b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/BaseHttpClientInvocation.java
@@ -20,13 +20,6 @@ package ca.uhn.fhir.rest.client.impl;
* #L%
*/
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
@@ -34,6 +27,12 @@ import ca.uhn.fhir.rest.client.api.Header;
import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IRestfulClientFactory;
+import ca.uhn.fhir.util.UrlUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
public abstract class BaseHttpClientInvocation {
@@ -115,13 +114,9 @@ public abstract class BaseHttpClientInvocation {
} else {
theUrlBuilder.append('&');
}
- try {
- theUrlBuilder.append(URLEncoder.encode(next.getKey(), "UTF-8"));
- theUrlBuilder.append('=');
- theUrlBuilder.append(URLEncoder.encode(nextValue, "UTF-8"));
- } catch (UnsupportedEncodingException e) {
- throw new Error("UTF-8 not supported - This should not happen");
- }
+ theUrlBuilder.append(UrlUtil.escapeUrlParam(next.getKey()));
+ theUrlBuilder.append('=');
+ theUrlBuilder.append(UrlUtil.escapeUrlParam(nextValue));
}
}
}
diff --git a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java
index 60687a5f7b9..1432d8c5a00 100644
--- a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java
+++ b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java
@@ -354,7 +354,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
case '?':
case '$':
case ':':
- b.append(UrlUtil.escape(Character.toString(nextChar)));
+ b.append(UrlUtil.escapeUrlParam(Character.toString(nextChar)));
break;
default:
b.append(nextChar);
diff --git a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/method/HttpGetClientInvocation.java b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/method/HttpGetClientInvocation.java
index 2f8b15e609a..21287d59ba8 100644
--- a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/method/HttpGetClientInvocation.java
+++ b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/method/HttpGetClientInvocation.java
@@ -20,21 +20,18 @@ package ca.uhn.fhir.rest.client.method;
* #L%
*/
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.apache.commons.lang3.StringUtils;
-
-import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
+import ca.uhn.fhir.util.UrlUtil;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
/**
* @author James Agnew
@@ -51,51 +48,40 @@ public class HttpGetClientInvocation extends BaseHttpClientInvocation {
myUrlPath = StringUtils.join(theUrlFragments, '/');
}
- public HttpGetClientInvocation(FhirContext theContext, Map> theParameters, List theUrlFragments) {
- super(theContext);
- myParameters = theParameters;
- myUrlPath = StringUtils.join(theUrlFragments, '/');
- }
-
public HttpGetClientInvocation(FhirContext theContext, String theUrlPath) {
super(theContext);
- myParameters = new HashMap>();
+ myParameters = new HashMap<>();
myUrlPath = theUrlPath;
}
- public HttpGetClientInvocation(FhirContext theContext, String... theUrlFragments) {
- super(theContext);
- myParameters = new HashMap>();
- myUrlPath = StringUtils.join(theUrlFragments, '/');
- }
+ private boolean addQueryParameter(StringBuilder b, boolean first, String nextKey, String nextValue) {
+ boolean retVal = first;
+ if (retVal) {
+ b.append('?');
+ retVal = false;
+ } else {
+ b.append('&');
+ }
+ b.append(UrlUtil.escapeUrlParam(nextKey));
+ b.append('=');
+ b.append(UrlUtil.escapeUrlParam(nextValue));
- public HttpGetClientInvocation(FhirContext theContext, List theUrlFragments) {
- super(theContext);
- myParameters = new HashMap>();
- myUrlPath = StringUtils.join(theUrlFragments, '/');
- }
-
- public Map> getParameters() {
- return myParameters;
- }
-
- public String getUrlPath() {
- return myUrlPath;
+ return retVal;
}
@Override
public IHttpRequest asHttpRequest(String theUrlBase, Map> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint) {
StringBuilder b = new StringBuilder();
-
+
if (!myUrlPath.contains("://")) {
- b.append(theUrlBase);
- if (!theUrlBase.endsWith("/") && !myUrlPath.startsWith("/")) {
- b.append('/');
- }
- }
- b.append(myUrlPath);
-
+ b.append(theUrlBase);
+ if (!theUrlBase.endsWith("/") && !myUrlPath.startsWith("/")) {
+ b.append('/');
+ }
+ }
+ b.append(myUrlPath);
+
boolean first = b.indexOf("?") == -1;
for (Entry> next : myParameters.entrySet()) {
if (next.getValue() == null || next.getValue().isEmpty()) {
@@ -112,22 +98,12 @@ public class HttpGetClientInvocation extends BaseHttpClientInvocation {
return super.createHttpRequest(b.toString(), theEncoding, RequestTypeEnum.GET);
}
- private boolean addQueryParameter(StringBuilder b, boolean first, String nextKey, String nextValue) {
- boolean retVal = first;
- if (retVal) {
- b.append('?');
- retVal = false;
- } else {
- b.append('&');
- }
- try {
- b.append(URLEncoder.encode(nextKey, "UTF-8"));
- b.append('=');
- b.append(URLEncoder.encode(nextValue, "UTF-8"));
- } catch (UnsupportedEncodingException e) {
- throw new ConfigurationException("Could not find UTF-8 encoding. This shouldn't happen.", e);
- }
- return retVal;
+ public Map> getParameters() {
+ return myParameters;
+ }
+
+ public String getUrlPath() {
+ return myUrlPath;
}
}
diff --git a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/method/MethodUtil.java b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/method/MethodUtil.java
index ea1ad89d64a..5be18f1cf70 100644
--- a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/method/MethodUtil.java
+++ b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/method/MethodUtil.java
@@ -209,9 +209,9 @@ public class MethodUtil {
for (String nextValue : nextEntry.getValue()) {
b.append(haveQuestionMark ? '&' : '?');
haveQuestionMark = true;
- b.append(UrlUtil.escape(nextEntry.getKey()));
+ b.append(UrlUtil.escapeUrlParam(nextEntry.getKey()));
b.append('=');
- b.append(UrlUtil.escape(nextValue));
+ b.append(UrlUtil.escapeUrlParam(nextValue));
}
}
return b;
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
index 772638bb774..8707ab64240 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
@@ -35,7 +35,6 @@ import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
-import ca.uhn.fhir.model.primitive.XhtmlDt;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser;
@@ -229,14 +228,14 @@ public abstract class BaseHapiFhirDao implements IDao {
ArrayList nextChoicesList = new ArrayList<>();
partsChoices.add(nextChoicesList);
- String key = UrlUtil.escape(nextCompositeOf.getName());
+ String key = UrlUtil.escapeUrlParam(nextCompositeOf.getName());
if (paramsListForCompositePart != null) {
for (BaseResourceIndexedSearchParam nextParam : paramsListForCompositePart) {
if (nextParam.getParamName().equals(nextCompositeOf.getName())) {
IQueryParameterType nextParamAsClientParam = nextParam.toQueryParameterType();
String value = nextParamAsClientParam.getValueAsQueryToken(getContext());
if (isNotBlank(value)) {
- value = UrlUtil.escape(value);
+ value = UrlUtil.escapeUrlParam(value);
nextChoicesList.add(key + "=" + value);
}
}
@@ -246,7 +245,7 @@ public abstract class BaseHapiFhirDao implements IDao {
for (ResourceLink nextLink : linksForCompositePart) {
String value = nextLink.getTargetResource().getIdDt().toUnqualifiedVersionless().getValue();
if (isNotBlank(value)) {
- value = UrlUtil.escape(value);
+ value = UrlUtil.escapeUrlParam(value);
nextChoicesList.add(key + "=" + value);
}
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java
index f791b404272..c4568fa629e 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java
@@ -60,7 +60,6 @@ import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.query.Query;
import org.hl7.fhir.dstu3.model.BaseResource;
-import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
@@ -175,7 +174,7 @@ public class SearchBuilder implements ISearchBuilder {
if (valueBuilder.length() > 0) {
valueBuilder.append(',');
}
- valueBuilder.append(UrlUtil.escape(next.getValueAsQueryToken(myContext)));
+ valueBuilder.append(UrlUtil.escapeUrlParam(next.getValueAsQueryToken(myContext)));
targetResourceType = next.getTargetResourceType();
owningParameter = next.getOwningFieldName();
parameterName = next.getParameterName();
@@ -185,7 +184,7 @@ public class SearchBuilder implements ISearchBuilder {
continue;
}
- String matchUrl = targetResourceType + '?' + UrlUtil.escape(parameterName) + '=' + valueBuilder.toString();
+ String matchUrl = targetResourceType + '?' + UrlUtil.escapeUrlParam(parameterName) + '=' + valueBuilder.toString();
RuntimeResourceDefinition targetResourceDefinition;
try {
targetResourceDefinition = myContext.getResourceDefinition(targetResourceType);
@@ -1272,13 +1271,13 @@ public class SearchBuilder implements ISearchBuilder {
List> params = new ArrayList<>();
for (Entry>> nextParamNameToValues : theParams.entrySet()) {
String nextParamName = nextParamNameToValues.getKey();
- nextParamName = UrlUtil.escape(nextParamName);
+ nextParamName = UrlUtil.escapeUrlParam(nextParamName);
for (List extends IQueryParameterType> nextAnd : nextParamNameToValues.getValue()) {
ArrayList nextValueList = new ArrayList<>();
params.add(nextValueList);
for (IQueryParameterType nextOr : nextAnd) {
String nextOrValue = nextOr.getValueAsQueryToken(myContext);
- nextOrValue = UrlUtil.escape(nextOrValue);
+ nextOrValue = UrlUtil.escapeUrlParam(nextOrValue);
nextValueList.add(nextParamName + "=" + nextOrValue);
}
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParameterMap.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParameterMap.java
index 864f4531981..0b14c5d8e5f 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParameterMap.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParameterMap.java
@@ -1,6 +1,5 @@
package ca.uhn.fhir.jpa.dao;
-import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/*
@@ -24,7 +23,6 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
*/
import java.util.*;
-import ca.uhn.fhir.rest.param.ReferenceParam;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder;
@@ -138,9 +136,9 @@ public class SearchParameterMap extends LinkedHashMap nextValuesAnd : nextValuesAndsOut) {
addUrlParamSeparator(b);
IQueryParameterType firstValue = nextValuesAnd.get(0);
- b.append(UrlUtil.escape(nextKey));
+ b.append(UrlUtil.escapeUrlParam(nextKey));
if (firstValue.getMissing() != null) {
b.append(Constants.PARAMQUALIFIER_MISSING);
@@ -340,7 +338,7 @@ public class SearchParameterMap extends LinkedHashMap {
String nextReplacementIdPart = nextReplacementId.getValueAsString();
if (nextTemporaryId.isUrn() && nextTemporaryIdPart.length() > IdType.URN_PREFIX.length()) {
matchUrl = matchUrl.replace(nextTemporaryIdPart, nextReplacementIdPart);
- matchUrl = matchUrl.replace(UrlUtil.escape(nextTemporaryIdPart), nextReplacementIdPart);
+ matchUrl = matchUrl.replace(UrlUtil.escapeUrlParam(nextTemporaryIdPart), nextReplacementIdPart);
}
}
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java
index 9e9ab48f2c6..95be502404a 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java
@@ -667,7 +667,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao {
String nextReplacementIdPart = nextReplacementId.getValueAsString();
if (nextTemporaryId.isUrn() && nextTemporaryIdPart.length() > IdType.URN_PREFIX.length()) {
matchUrl = matchUrl.replace(nextTemporaryIdPart, nextReplacementIdPart);
- matchUrl = matchUrl.replace(UrlUtil.escape(nextTemporaryIdPart), nextReplacementIdPart);
+ matchUrl = matchUrl.replace(UrlUtil.escapeUrlParam(nextTemporaryIdPart), nextReplacementIdPart);
}
}
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java
index 2290cb34384..e94a2a71700 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcDstu3.java
@@ -321,7 +321,7 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc implements I
cs.setUrl(theSystem);
cs.setContent(CodeSystemContentMode.NOTPRESENT);
- DaoMethodOutcome createOutcome = myCodeSystemResourceDao.create(cs, "CodeSystem?url=" + UrlUtil.escape(theSystem), theRequestDetails);
+ DaoMethodOutcome createOutcome = myCodeSystemResourceDao.create(cs, "CodeSystem?url=" + UrlUtil.escapeUrlParam(theSystem), theRequestDetails);
IIdType csId = createOutcome.getId().toUnqualifiedVersionless();
if (createOutcome.getCreated() != Boolean.TRUE) {
CodeSystem existing = myCodeSystemResourceDao.read(csId, theRequestDetails);
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java
index 66336118352..8623d04e4f3 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/HapiTerminologySvcR4.java
@@ -325,7 +325,7 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvc implements IVal
cs.setUrl(theSystem);
cs.setContent(CodeSystemContentMode.NOTPRESENT);
- DaoMethodOutcome createOutcome = myCodeSystemResourceDao.create(cs, "CodeSystem?url=" + UrlUtil.escape(theSystem), theRequestDetails);
+ DaoMethodOutcome createOutcome = myCodeSystemResourceDao.create(cs, "CodeSystem?url=" + UrlUtil.escapeUrlParam(theSystem), theRequestDetails);
IIdType csId = createOutcome.getId().toUnqualifiedVersionless();
if (createOutcome.getCreated() != Boolean.TRUE) {
CodeSystem existing = myCodeSystemResourceDao.read(csId, theRequestDetails);
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java
index fa04bb5b350..ba49a17ffda 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java
@@ -30,7 +30,6 @@ import ca.uhn.fhir.model.dstu2.resource.*;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu2.valueset.*;
import ca.uhn.fhir.model.primitive.*;
-import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.client.api.IGenericClient;
@@ -528,7 +527,7 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
pt.addName().addFamily("FOO");
resource = myFhirCtx.newXmlParser().encodeResourceToString(pt);
- HttpPut put = new HttpPut(ourServerBase + "/Patient?identifier=" + ("http://general-hospital.co.uk/Identifiers|09832345234543876876".replace("|", UrlUtil.escape("|"))));
+ HttpPut put = new HttpPut(ourServerBase + "/Patient?identifier=" + ("http://general-hospital.co.uk/Identifiers|09832345234543876876".replace("|", UrlUtil.escapeUrlParam("|"))));
put.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
IdDt id2;
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java
index 47baa956052..9dea55a78ed 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java
@@ -1639,7 +1639,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
myObservationDao.create(obs, mySrd);
}
- String uri = ourServerBase + "/Patient?_has:Observation:subject:identifier=" + UrlUtil.escape("urn:system|FOO");
+ String uri = ourServerBase + "/Patient?_has:Observation:subject:identifier=" + UrlUtil.escapeUrlParam("urn:system|FOO");
List ids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
assertThat(ids, contains(pid0.getValue()));
}
@@ -2347,7 +2347,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
myPatientDao.create(p, mySrd);
}
- String uri = ourServerBase + "/Patient?name=" + URLEncoder.encode("Jernelöv", "UTF-8") + "&_count=5&_pretty=true";
+ String uri = ourServerBase + "/Patient?name=" + UrlUtil.escapeUrlParam("Jernelöv") + "&_count=5&_pretty=true";
ourLog.info("URI: {}", uri);
HttpGet get = new HttpGet(uri);
CloseableHttpResponse resp = ourHttpClient.execute(get);
@@ -3792,7 +3792,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
pt.addName().setFamily("FOO");
resource = myFhirCtx.newXmlParser().encodeResourceToString(pt);
- HttpPut put = new HttpPut(ourServerBase + "/Patient?identifier=" + ("http://general-hospital.co.uk/Identifiers|09832345234543876876".replace("|", UrlUtil.escape("|"))));
+ HttpPut put = new HttpPut(ourServerBase + "/Patient?identifier=" + ("http://general-hospital.co.uk/Identifiers|09832345234543876876".replace("|", UrlUtil.escapeUrlParam("|"))));
put.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
IdType id2;
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/GraphQLProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/GraphQLProviderR4Test.java
index 286c6d9ce0b..7842f99a75d 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/GraphQLProviderR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/GraphQLProviderR4Test.java
@@ -25,7 +25,7 @@ public class GraphQLProviderR4Test extends BaseResourceProviderR4Test {
initTestPatients();
String query = "{name{family,given}}";
- HttpGet httpGet = new HttpGet(ourServerBase + "/Patient/" + myPatientId0.getIdPart() + "/$graphql?query=" + UrlUtil.escape(query));
+ HttpGet httpGet = new HttpGet(ourServerBase + "/Patient/" + myPatientId0.getIdPart() + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse response = ourHttpClient.execute(httpGet);
try {
@@ -50,7 +50,7 @@ public class GraphQLProviderR4Test extends BaseResourceProviderR4Test {
initTestPatients();
String query = "{PatientList(given:\"given\"){name{family,given}}}";
- HttpGet httpGet = new HttpGet(ourServerBase + "/$graphql?query=" + UrlUtil.escape(query));
+ HttpGet httpGet = new HttpGet(ourServerBase + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse response = ourHttpClient.execute(httpGet);
try {
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
index eddaab5fbd0..1ee7135ecfc 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
@@ -61,7 +61,6 @@ import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
-import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
@@ -1647,7 +1646,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
myObservationDao.create(obs, mySrd);
}
- String uri = ourServerBase + "/Patient?_has:Observation:subject:identifier=" + UrlUtil.escape("urn:system|FOO");
+ String uri = ourServerBase + "/Patient?_has:Observation:subject:identifier=" + UrlUtil.escapeUrlParam("urn:system|FOO");
List ids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
assertThat(ids, contains(pid0.getValue()));
}
@@ -2355,7 +2354,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
myPatientDao.create(p, mySrd);
}
- String uri = ourServerBase + "/Patient?name=" + URLEncoder.encode("Jernelöv", "UTF-8") + "&_count=5&_pretty=true";
+ String uri = ourServerBase + "/Patient?name=" + UrlUtil.escapeUrlParam("Jernelöv") + "&_count=5&_pretty=true";
ourLog.info("URI: {}", uri);
HttpGet get = new HttpGet(uri);
CloseableHttpResponse resp = ourHttpClient.execute(get);
@@ -3938,7 +3937,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
pt.addName().setFamily("FOO");
resource = myFhirCtx.newXmlParser().encodeResourceToString(pt);
- HttpPut put = new HttpPut(ourServerBase + "/Patient?identifier=" + ("http://general-hospital.co.uk/Identifiers|09832345234543876876".replace("|", UrlUtil.escape("|"))));
+ HttpPut put = new HttpPut(ourServerBase + "/Patient?identifier=" + ("http://general-hospital.co.uk/Identifiers|09832345234543876876".replace("|", UrlUtil.escapeUrlParam("|"))));
put.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
IdType id2;
diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/interceptor/AnalyticsInterceptor.java b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/interceptor/AnalyticsInterceptor.java
index b659903135a..64baf5158d4 100644
--- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/interceptor/AnalyticsInterceptor.java
+++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/interceptor/AnalyticsInterceptor.java
@@ -80,13 +80,13 @@ public class AnalyticsInterceptor extends InterceptorAdapter {
b.append("&tid=").append(myAnalyticsTid);
b.append("&t=event");
- b.append("&an=").append(UrlUtil.escape(myHostname)).append('+').append(UrlUtil.escape(next.getApplicationName()));
+ b.append("&an=").append(UrlUtil.escapeUrlParam(myHostname)).append('+').append(UrlUtil.escapeUrlParam(next.getApplicationName()));
b.append("&ec=").append(next.getResourceName());
b.append("&ea=").append(next.getRestOperation());
b.append("&cid=").append(next.getClientId());
- b.append("&uip=").append(UrlUtil.escape(next.getSourceIp()));
- b.append("&ua=").append(UrlUtil.escape(next.getUserAgent()));
+ b.append("&uip=").append(UrlUtil.escapeUrlParam(next.getSourceIp()));
+ b.append("&ua=").append(UrlUtil.escapeUrlParam(next.getUserAgent()));
b.append("\n");
}
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java
index 0dfb36051e9..cbe3dd0fa84 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java
@@ -19,34 +19,38 @@ package ca.uhn.fhir.rest.server;
* limitations under the License.
* #L%
*/
-import static org.apache.commons.lang3.StringUtils.*;
-
-import java.io.*;
-import java.net.URLEncoder;
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.servlet.http.HttpServletRequest;
-
-import ca.uhn.fhir.util.BinaryUtil;
-import org.hl7.fhir.instance.model.api.*;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
-import ca.uhn.fhir.model.api.*;
+import ca.uhn.fhir.model.api.IResource;
+import ca.uhn.fhir.model.api.Include;
+import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.IParser;
-import ca.uhn.fhir.rest.api.*;
+import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.rest.api.EncodingEnum;
+import ca.uhn.fhir.rest.api.PreferReturnEnum;
+import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.api.server.IRestfulResponse;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.method.ElementsParameter;
import ca.uhn.fhir.rest.server.method.SummaryEnumParameter;
+import ca.uhn.fhir.util.BinaryUtil;
import ca.uhn.fhir.util.DateUtils;
import ca.uhn.fhir.util.UrlUtil;
+import org.hl7.fhir.instance.model.api.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.apache.commons.lang3.StringUtils.*;
public class RestfulServerUtils {
static final Pattern ACCEPT_HEADER_PATTERN = Pattern.compile("\\s*([a-zA-Z0-9+.*/-]+)\\s*(;\\s*([a-zA-Z]+)\\s*=\\s*([a-zA-Z0-9.]+)\\s*)?(,?)");
@@ -127,74 +131,70 @@ public class RestfulServerUtils {
}
public static String createPagingLink(Set theIncludes, String theServerBase, String theSearchId, int theOffset, int theCount, Map theRequestParameters, boolean thePrettyPrint,
- BundleTypeEnum theBundleType) {
- try {
- StringBuilder b = new StringBuilder();
- b.append(theServerBase);
- b.append('?');
- b.append(Constants.PARAM_PAGINGACTION);
- b.append('=');
- b.append(URLEncoder.encode(theSearchId, "UTF-8"));
+ BundleTypeEnum theBundleType) {
+ StringBuilder b = new StringBuilder();
+ b.append(theServerBase);
+ b.append('?');
+ b.append(Constants.PARAM_PAGINGACTION);
+ b.append('=');
+ b.append(UrlUtil.escapeUrlParam(theSearchId));
+ b.append('&');
+ b.append(Constants.PARAM_PAGINGOFFSET);
+ b.append('=');
+ b.append(theOffset);
+ b.append('&');
+ b.append(Constants.PARAM_COUNT);
+ b.append('=');
+ b.append(theCount);
+ String[] strings = theRequestParameters.get(Constants.PARAM_FORMAT);
+ if (strings != null && strings.length > 0) {
b.append('&');
- b.append(Constants.PARAM_PAGINGOFFSET);
+ b.append(Constants.PARAM_FORMAT);
b.append('=');
- b.append(theOffset);
- b.append('&');
- b.append(Constants.PARAM_COUNT);
- b.append('=');
- b.append(theCount);
- String[] strings = theRequestParameters.get(Constants.PARAM_FORMAT);
- if (strings != null && strings.length > 0) {
- b.append('&');
- b.append(Constants.PARAM_FORMAT);
- b.append('=');
- String format = strings[0];
- format = replace(format, " ", "+");
- b.append(UrlUtil.escape(format));
- }
- if (thePrettyPrint) {
- b.append('&');
- b.append(Constants.PARAM_PRETTY);
- b.append('=');
- b.append(Constants.PARAM_PRETTY_VALUE_TRUE);
- }
-
- if (theIncludes != null) {
- for (Include nextInclude : theIncludes) {
- if (isNotBlank(nextInclude.getValue())) {
- b.append('&');
- b.append(Constants.PARAM_INCLUDE);
- b.append('=');
- b.append(URLEncoder.encode(nextInclude.getValue(), "UTF-8"));
- }
- }
- }
-
- if (theBundleType != null) {
- b.append('&');
- b.append(Constants.PARAM_BUNDLETYPE);
- b.append('=');
- b.append(theBundleType.getCode());
- }
-
- String paramName = Constants.PARAM_ELEMENTS;
- String[] params = theRequestParameters.get(paramName);
- if (params != null) {
- for (String nextValue : params) {
- if (isNotBlank(nextValue)) {
- b.append('&');
- b.append(paramName);
- b.append('=');
- b.append(UrlUtil.escape(nextValue));
- }
- }
- }
-
- return b.toString();
- } catch (UnsupportedEncodingException e) {
- throw new Error("UTF-8 not supported", e);// should not happen
+ String format = strings[0];
+ format = replace(format, " ", "+");
+ b.append(UrlUtil.escapeUrlParam(format));
}
+ if (thePrettyPrint) {
+ b.append('&');
+ b.append(Constants.PARAM_PRETTY);
+ b.append('=');
+ b.append(Constants.PARAM_PRETTY_VALUE_TRUE);
+ }
+
+ if (theIncludes != null) {
+ for (Include nextInclude : theIncludes) {
+ if (isNotBlank(nextInclude.getValue())) {
+ b.append('&');
+ b.append(Constants.PARAM_INCLUDE);
+ b.append('=');
+ b.append(UrlUtil.escapeUrlParam(nextInclude.getValue()));
+ }
+ }
+ }
+
+ if (theBundleType != null) {
+ b.append('&');
+ b.append(Constants.PARAM_BUNDLETYPE);
+ b.append('=');
+ b.append(theBundleType.getCode());
+ }
+
+ String paramName = Constants.PARAM_ELEMENTS;
+ String[] params = theRequestParameters.get(paramName);
+ if (params != null) {
+ for (String nextValue : params) {
+ if (isNotBlank(nextValue)) {
+ b.append('&');
+ b.append(paramName);
+ b.append('=');
+ b.append(UrlUtil.escapeUrlParam(nextValue));
+ }
+ }
+ }
+
+ return b.toString();
}
/**
@@ -392,15 +392,15 @@ public class RestfulServerUtils {
try {
NarrativeModeEnum narrativeMode = NarrativeModeEnum.valueOfCaseInsensitive(narrative[0]);
switch (narrativeMode) {
- case NORMAL:
- retVal = Collections.singleton(SummaryEnum.FALSE);
- break;
- case ONLY:
- retVal = Collections.singleton(SummaryEnum.TEXT);
- break;
- case SUPPRESS:
- retVal = Collections.singleton(SummaryEnum.DATA);
- break;
+ case NORMAL:
+ retVal = Collections.singleton(SummaryEnum.FALSE);
+ break;
+ case ONLY:
+ retVal = Collections.singleton(SummaryEnum.TEXT);
+ break;
+ case SUPPRESS:
+ retVal = Collections.singleton(SummaryEnum.DATA);
+ break;
}
} catch (IllegalArgumentException e) {
ourLog.debug("Invalid {} parameter: {}", Constants.PARAM_NARRATIVE, narrative[0]);
@@ -461,13 +461,13 @@ public class RestfulServerUtils {
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingWithDefault(theRequestDetails).getEncoding();
IParser parser;
switch (responseEncoding) {
- case JSON:
- parser = theContext.newJsonParser();
- break;
- case XML:
- default:
- parser = theContext.newXmlParser();
- break;
+ case JSON:
+ parser = theContext.newJsonParser();
+ break;
+ case XML:
+ default:
+ parser = theContext.newXmlParser();
+ break;
}
configureResponseParser(theRequestDetails, parser);
@@ -581,13 +581,13 @@ public class RestfulServerUtils {
}
public static Object streamResponseAsResource(IRestfulServerDefaults theServer, IBaseResource theResource, Set theSummaryMode, int stausCode, boolean theAddContentLocationHeader,
- boolean respondGzip, RequestDetails theRequestDetails) throws IOException {
+ boolean respondGzip, RequestDetails theRequestDetails) throws IOException {
return streamResponseAsResource(theServer, theResource, theSummaryMode, stausCode, null, theAddContentLocationHeader, respondGzip, theRequestDetails, null, null);
}
public static Object streamResponseAsResource(IRestfulServerDefaults theServer, IBaseResource theResource, Set theSummaryMode, int theStausCode, String theStatusMessage,
- boolean theAddContentLocationHeader, boolean respondGzip, RequestDetails theRequestDetails, IIdType theOperationResourceId, IPrimitiveType theOperationResourceLastUpdated)
- throws IOException {
+ boolean theAddContentLocationHeader, boolean respondGzip, RequestDetails theRequestDetails, IIdType theOperationResourceId, IPrimitiveType theOperationResourceLastUpdated)
+ throws IOException {
IRestfulResponse response = theRequestDetails.getResponse();
// Determine response encoding
@@ -706,7 +706,7 @@ public class RestfulServerUtils {
try {
return Integer.parseInt(retVal[0]);
} catch (NumberFormatException e) {
- ourLog.debug("Failed to parse {} value '{}': {}", new Object[] { theParamName, retVal[0], e });
+ ourLog.debug("Failed to parse {} value '{}': {}", new Object[]{theParamName, retVal[0], e});
return null;
}
}
@@ -752,7 +752,7 @@ public class RestfulServerUtils {
if (theContentType.equals(EncodingEnum.JSON_PLAIN_STRING) || theContentType.equals(EncodingEnum.XML_PLAIN_STRING)) {
FhirVersionEnum ctxtEnum = theCtx.getVersion().getVersion();
myNonLegacy = ctxtEnum.isNewerThan(FhirVersionEnum.DSTU3)
- || (ctxtEnum.isEquivalentTo(FhirVersionEnum.DSTU3) && !"1.4.0".equals(theCtx.getVersion().getVersion().getFhirVersionString()));
+ || (ctxtEnum.isEquivalentTo(FhirVersionEnum.DSTU3) && !"1.4.0".equals(theCtx.getVersion().getVersion().getFhirVersionString()));
} else {
myNonLegacy = EncodingEnum.isNonLegacy(theContentType);
}
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptor.java
index 729ab9d9cb2..83e732e94b5 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptor.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptor.java
@@ -25,7 +25,6 @@ import java.io.IOException;
*/
import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
import java.util.Date;
import java.util.Map.Entry;
@@ -33,6 +32,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import ca.uhn.fhir.util.UrlUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.text.StrLookup;
@@ -277,13 +277,9 @@ public class LoggingInterceptor extends InterceptorAdapter {
} else {
b.append('&');
}
- try {
- b.append(URLEncoder.encode(next.getKey(), "UTF-8"));
- b.append('=');
- b.append(URLEncoder.encode(nextValue, "UTF-8"));
- } catch (UnsupportedEncodingException e) {
- throw new ca.uhn.fhir.context.ConfigurationException("UTF-8 not supported", e);
- }
+ b.append(UrlUtil.escapeUrlParam(next.getKey()));
+ b.append('=');
+ b.append(UrlUtil.escapeUrlParam(nextValue));
}
}
return b.toString();
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseHighlighterInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseHighlighterInterceptor.java
index d3955dbc71b..91278e5f874 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseHighlighterInterceptor.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseHighlighterInterceptor.java
@@ -92,9 +92,9 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
} else {
rawB.append('&');
}
- rawB.append(UrlUtil.escape(next));
+ rawB.append(UrlUtil.escapeUrlParam(next));
rawB.append('=');
- rawB.append(UrlUtil.escape(nextValue));
+ rawB.append(UrlUtil.escapeUrlParam(nextValue));
}
}
if (rawB.length() == 0) {
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/BaseResourceReturningMethodBinding.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/BaseResourceReturningMethodBinding.java
index 60820b85046..88b41a0eab1 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/BaseResourceReturningMethodBinding.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/BaseResourceReturningMethodBinding.java
@@ -186,9 +186,9 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
} else {
b.append('&');
}
- b.append(UrlUtil.escape(nextParamName));
+ b.append(UrlUtil.escapeUrlParam(nextParamName));
b.append('=');
- b.append(UrlUtil.escape(nextParamValue));
+ b.append(UrlUtil.escapeUrlParam(nextParamValue));
}
}
}
diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CompositeParameterTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CompositeParameterTest.java
index 74f4ae7abbe..3d46074c6cb 100644
--- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CompositeParameterTest.java
+++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CompositeParameterTest.java
@@ -1,12 +1,15 @@
package ca.uhn.fhir.rest.server;
-import static org.junit.Assert.*;
-
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.model.api.BundleEntry;
+import ca.uhn.fhir.model.api.IResource;
+import ca.uhn.fhir.model.dstu.resource.Observation;
+import ca.uhn.fhir.model.primitive.DateTimeDt;
+import ca.uhn.fhir.rest.annotation.RequiredParam;
+import ca.uhn.fhir.rest.annotation.Search;
+import ca.uhn.fhir.rest.param.*;
+import ca.uhn.fhir.util.PortUtil;
+import ca.uhn.fhir.util.TestUtil;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
@@ -20,20 +23,11 @@ import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
-import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.model.api.BundleEntry;
-import ca.uhn.fhir.model.api.IResource;
-import ca.uhn.fhir.model.dstu.resource.Observation;
-import ca.uhn.fhir.model.primitive.DateTimeDt;
-import ca.uhn.fhir.rest.annotation.RequiredParam;
-import ca.uhn.fhir.rest.annotation.Search;
-import ca.uhn.fhir.rest.param.CompositeAndListParam;
-import ca.uhn.fhir.rest.param.CompositeOrListParam;
-import ca.uhn.fhir.rest.param.CompositeParam;
-import ca.uhn.fhir.rest.param.DateParam;
-import ca.uhn.fhir.rest.param.StringParam;
-import ca.uhn.fhir.util.PortUtil;
-import ca.uhn.fhir.util.TestUtil;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.Assert.*;
/**
* Created by dsotnikov on 2/25/2014.
@@ -48,7 +42,7 @@ public class CompositeParameterTest {
@Test
public void testSearchWithDateValue() throws Exception {
{
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?" + Observation.SP_NAME_VALUE_DATE + "=" + URLEncoder.encode("foo\\$bar$2001-01-01", "UTF-8"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?" + Observation.SP_NAME_VALUE_DATE + "=" + UrlUtil.escape("foo\\$bar$2001-01-01"));
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
@@ -66,7 +60,7 @@ public class CompositeParameterTest {
@Test
public void testSearchWithMultipleValue() throws Exception {
{
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?" + Observation.SP_NAME_VALUE_STRING + "=" + URLEncoder.encode("l1$r1,l2$r2", "UTF-8") + "&" + Observation.SP_NAME_VALUE_STRING + "=" + URLEncoder.encode("l3$r3,l4$r4", "UTF-8"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?" + Observation.SP_NAME_VALUE_STRING + "=" + UrlUtil.escape("l1$r1,l2$r2") + "&" + Observation.SP_NAME_VALUE_STRING + "=" + UrlUtil.escape("l3$r3,l4$r4"));
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/DefaultEncodingTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/DefaultEncodingTest.java
index bf1de077702..b104010e93e 100644
--- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/DefaultEncodingTest.java
+++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/DefaultEncodingTest.java
@@ -1,15 +1,14 @@
package ca.uhn.fhir.rest.server;
-import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.not;
-import static org.hamcrest.Matchers.stringContainsInOrder;
-import static org.junit.Assert.*;
-
-import java.net.URLEncoder;
-import java.util.concurrent.TimeUnit;
-
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.model.api.IResource;
+import ca.uhn.fhir.model.dstu.resource.Patient;
+import ca.uhn.fhir.model.primitive.IdDt;
+import ca.uhn.fhir.rest.annotation.IdParam;
+import ca.uhn.fhir.rest.annotation.Read;
+import ca.uhn.fhir.util.PortUtil;
+import ca.uhn.fhir.util.TestUtil;
import org.apache.commons.io.IOUtils;
-import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
@@ -22,20 +21,11 @@ import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
-import com.google.common.net.UrlEscapers;
+import java.util.concurrent.TimeUnit;
-import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.model.api.IResource;
-import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
-import ca.uhn.fhir.model.dstu.resource.BaseResource;
-import ca.uhn.fhir.model.dstu.resource.Binary;
-import ca.uhn.fhir.model.dstu.resource.Organization;
-import ca.uhn.fhir.model.dstu.resource.Patient;
-import ca.uhn.fhir.model.primitive.IdDt;
-import ca.uhn.fhir.rest.annotation.IdParam;
-import ca.uhn.fhir.rest.annotation.Read;
-import ca.uhn.fhir.util.PortUtil;
-import ca.uhn.fhir.util.TestUtil;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.*;
public class DefaultEncodingTest {
diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ReadDstu1Test.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ReadDstu1Test.java
index deeb32b5f86..78626745bdd 100644
--- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ReadDstu1Test.java
+++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ReadDstu1Test.java
@@ -1,11 +1,17 @@
package ca.uhn.fhir.rest.server;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.net.URLEncoder;
-import java.util.concurrent.TimeUnit;
-
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.model.api.IResource;
+import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
+import ca.uhn.fhir.model.dstu.resource.BaseResource;
+import ca.uhn.fhir.model.dstu.resource.Binary;
+import ca.uhn.fhir.model.dstu.resource.Organization;
+import ca.uhn.fhir.model.dstu.resource.Patient;
+import ca.uhn.fhir.model.primitive.IdDt;
+import ca.uhn.fhir.rest.annotation.IdParam;
+import ca.uhn.fhir.rest.annotation.Read;
+import ca.uhn.fhir.util.PortUtil;
+import ca.uhn.fhir.util.TestUtil;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
@@ -20,18 +26,10 @@ import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
-import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.model.api.IResource;
-import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
-import ca.uhn.fhir.model.dstu.resource.BaseResource;
-import ca.uhn.fhir.model.dstu.resource.Binary;
-import ca.uhn.fhir.model.dstu.resource.Organization;
-import ca.uhn.fhir.model.dstu.resource.Patient;
-import ca.uhn.fhir.model.primitive.IdDt;
-import ca.uhn.fhir.rest.annotation.IdParam;
-import ca.uhn.fhir.rest.annotation.Read;
-import ca.uhn.fhir.util.PortUtil;
-import ca.uhn.fhir.util.TestUtil;
+import java.util.concurrent.TimeUnit;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
public class ReadDstu1Test {
@@ -129,10 +127,10 @@ public class ReadDstu1Test {
@Test
public void testReadWithEscapedCharsInId() throws Exception {
String id = "ABC!@#$--DEF";
- String idEscaped = URLEncoder.encode(id, "UTF-8");
+ String idEscaped = UrlUtil.escapeid);
String vid = "GHI:/:/JKL";
- String vidEscaped = URLEncoder.encode(vid, "UTF-8");
+ String vidEscaped = UrlUtil.escape(vid);
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/" + idEscaped + "/_history/" + vidEscaped);
HttpResponse status = ourClient.execute(httpGet);
diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ReferenceParameterTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ReferenceParameterTest.java
index 8a742b5e9e5..3c5aa97435e 100644
--- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ReferenceParameterTest.java
+++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ReferenceParameterTest.java
@@ -1,41 +1,12 @@
package ca.uhn.fhir.rest.server;
-import static org.apache.commons.lang3.StringUtils.defaultString;
-import static org.hamcrest.Matchers.containsString;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.utils.URLEncodedUtils;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
-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.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
-import ca.uhn.fhir.model.dstu.resource.Conformance;
+import ca.uhn.fhir.model.dstu.resource.*;
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource;
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResourceSearchParam;
-import ca.uhn.fhir.model.dstu.resource.Location;
-import ca.uhn.fhir.model.dstu.resource.Observation;
-import ca.uhn.fhir.model.dstu.resource.Organization;
-import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.dstu.valueset.ResourceTypeEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.IdParam;
@@ -47,6 +18,27 @@ import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+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.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.commons.lang3.StringUtils.defaultString;
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.*;
/**
* Created by dsotnikov on 2/25/2014.
@@ -105,7 +97,7 @@ public class ReferenceParameterTest {
@Test
public void testReferenceParamViewToken() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?provider.name=" + URLEncoder.encode("foo|bar", "UTF-8"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?provider.name=" + UrlUtil.escape("foo|bar"));
HttpResponse status = ourClient.execute(httpGet);
IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
diff --git a/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2_1Test.java b/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2_1Test.java
index 8a5b7058401..030ef32baa2 100644
--- a/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2_1Test.java
+++ b/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2_1Test.java
@@ -105,7 +105,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
@Test
public void testEscapedOperationName() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/%24andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escape("VALTOK2A|VALTOK2B"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/%24andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode());
@@ -118,7 +118,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
@Test
public void testAndListWithUrl() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escape("VALTOK2A|VALTOK2B"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode());
@@ -270,7 +270,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
}
@Test
public void testNonRepeatingWithUrl() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr=VALSTR&valtok=" + UrlUtil.escape("VALTOKA|VALTOKB"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr=VALSTR&valtok=" + UrlUtil.escapeUrlParam("VALTOKA|VALTOKB"));
HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode());
@@ -290,7 +290,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
@Test
public void testNonRepeatingWithUrlQualified() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr:exact=VALSTR&valtok:not=" + UrlUtil.escape("VALTOKA|VALTOKB"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr:exact=VALSTR&valtok:not=" + UrlUtil.escapeUrlParam("VALTOKA|VALTOKB"));
HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode());
@@ -345,7 +345,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
@Test
public void testOrListWithUrl() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$orlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escape("VALTOK2A|VALTOK2B"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$orlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode());
diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2Test.java
index 633302c1b4d..08bd9b6f10a 100644
--- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2Test.java
+++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2Test.java
@@ -110,8 +110,8 @@ public class OperationServerWithSearchParamTypesDstu2Test {
@Test
public void testAndListWithUrl() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok="
- + UrlUtil.escape("VALTOK2A|VALTOK2B"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok="
+ + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode());
@@ -214,7 +214,7 @@ public class OperationServerWithSearchParamTypesDstu2Test {
@Test
public void testNonRepeatingWithUrl() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr=VALSTR&valtok=" + UrlUtil.escape("VALTOKA|VALTOKB"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr=VALSTR&valtok=" + UrlUtil.escapeUrlParam("VALTOKA|VALTOKB"));
HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode());
@@ -234,7 +234,7 @@ public class OperationServerWithSearchParamTypesDstu2Test {
@Test
public void testNonRepeatingWithUrlQualified() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr:exact=VALSTR&valtok:not=" + UrlUtil.escape("VALTOKA|VALTOKB"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr:exact=VALSTR&valtok:not=" + UrlUtil.escapeUrlParam("VALTOKA|VALTOKB"));
HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode());
@@ -289,8 +289,8 @@ public class OperationServerWithSearchParamTypesDstu2Test {
@Test
public void testOrListWithUrl() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$orlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok="
- + UrlUtil.escape("VALTOK2A|VALTOK2B"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$orlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok="
+ + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode());
diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerSearchDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerSearchDstu2Test.java
index 7617f7838e9..36d9e0aba94 100644
--- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerSearchDstu2Test.java
+++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerSearchDstu2Test.java
@@ -1,12 +1,14 @@
package ca.uhn.fhir.rest.server;
-import static org.junit.Assert.assertEquals;
-
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.model.dstu2.resource.Patient;
+import ca.uhn.fhir.rest.annotation.RequiredParam;
+import ca.uhn.fhir.rest.annotation.Search;
+import ca.uhn.fhir.rest.param.ReferenceParam;
+import ca.uhn.fhir.rest.param.StringParam;
+import ca.uhn.fhir.util.PortUtil;
+import ca.uhn.fhir.util.TestUtil;
+import ca.uhn.fhir.util.UrlUtil;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
@@ -22,14 +24,11 @@ import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.model.dstu2.resource.Patient;
-import ca.uhn.fhir.rest.annotation.RequiredParam;
-import ca.uhn.fhir.rest.annotation.Search;
-import ca.uhn.fhir.rest.param.ReferenceParam;
-import ca.uhn.fhir.rest.param.StringParam;
-import ca.uhn.fhir.util.PortUtil;
-import ca.uhn.fhir.util.TestUtil;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.Assert.*;
public class ServerSearchDstu2Test {
@@ -106,7 +105,7 @@ public class ServerSearchDstu2Test {
@Test
public void testSearchWithEncodedValue() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/?param1=" + URLEncoder.encode("Jernelöv", "UTF-8"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/?param1=" + UrlUtil.escapeUrlParam("Jernelöv"));
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseHighlightingInterceptorTest.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseHighlightingInterceptorTest.java
index 3b2818641d3..cd2543b912c 100644
--- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseHighlightingInterceptorTest.java
+++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseHighlightingInterceptorTest.java
@@ -14,7 +14,6 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
@@ -186,7 +185,7 @@ public class ResponseHighlightingInterceptorTest {
@Test
public void testForceApplicationJsonPlusFhir() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_format=" + UrlUtil.escape("application/json+fhir"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_format=" + UrlUtil.escapeUrlParam("application/json+fhir"));
httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1");
HttpResponse status = ourClient.execute(httpGet);
@@ -225,7 +224,7 @@ public class ResponseHighlightingInterceptorTest {
@Test
public void testForceApplicationXmlPlusFhir() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_format=" + UrlUtil.escape("application/xml+fhir"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_format=" + UrlUtil.escapeUrlParam("application/xml+fhir"));
httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1");
HttpResponse status = ourClient.execute(httpGet);
diff --git a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/model/codesystems/MapTransformEnumFactory.java b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/model/codesystems/MapTransformEnumFactory.java
index 64fc92fd21b..b4f17d41118 100644
--- a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/model/codesystems/MapTransformEnumFactory.java
+++ b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/model/codesystems/MapTransformEnumFactory.java
@@ -1,122 +1,122 @@
-package org.hl7.fhir.dstu3.model.codesystems;
-
-/*
- Copyright (c) 2011+, HL7, Inc.
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without modification,
- are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of HL7 nor the names of its contributors may be used to
- endorse or promote products derived from this software without specific
- prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-// Generated on Sat, Mar 25, 2017 21:03-0400 for FHIR v3.0.0
-
-
-import org.hl7.fhir.dstu3.model.EnumFactory;
-
-public class MapTransformEnumFactory implements EnumFactory {
-
- public MapTransform fromCode(String codeString) throws IllegalArgumentException {
- if (codeString == null || "".equals(codeString))
- return null;
- if ("create".equals(codeString))
- return MapTransform.CREATE;
- if ("copy".equals(codeString))
- return MapTransform.COPY;
- if ("truncate".equals(codeString))
- return MapTransform.TRUNCATE;
- if ("escape".equals(codeString))
- return MapTransform.ESCAPE;
- if ("cast".equals(codeString))
- return MapTransform.CAST;
- if ("append".equals(codeString))
- return MapTransform.APPEND;
- if ("translate".equals(codeString))
- return MapTransform.TRANSLATE;
- if ("reference".equals(codeString))
- return MapTransform.REFERENCE;
- if ("dateOp".equals(codeString))
- return MapTransform.DATEOP;
- if ("uuid".equals(codeString))
- return MapTransform.UUID;
- if ("pointer".equals(codeString))
- return MapTransform.POINTER;
- if ("evaluate".equals(codeString))
- return MapTransform.EVALUATE;
- if ("cc".equals(codeString))
- return MapTransform.CC;
- if ("c".equals(codeString))
- return MapTransform.C;
- if ("qty".equals(codeString))
- return MapTransform.QTY;
- if ("id".equals(codeString))
- return MapTransform.ID;
- if ("cp".equals(codeString))
- return MapTransform.CP;
- throw new IllegalArgumentException("Unknown MapTransform code '"+codeString+"'");
- }
-
- public String toCode(MapTransform code) {
- if (code == MapTransform.CREATE)
- return "create";
- if (code == MapTransform.COPY)
- return "copy";
- if (code == MapTransform.TRUNCATE)
- return "truncate";
- if (code == MapTransform.ESCAPE)
- return "escape";
- if (code == MapTransform.CAST)
- return "cast";
- if (code == MapTransform.APPEND)
- return "append";
- if (code == MapTransform.TRANSLATE)
- return "translate";
- if (code == MapTransform.REFERENCE)
- return "reference";
- if (code == MapTransform.DATEOP)
- return "dateOp";
- if (code == MapTransform.UUID)
- return "uuid";
- if (code == MapTransform.POINTER)
- return "pointer";
- if (code == MapTransform.EVALUATE)
- return "evaluate";
- if (code == MapTransform.CC)
- return "cc";
- if (code == MapTransform.C)
- return "c";
- if (code == MapTransform.QTY)
- return "qty";
- if (code == MapTransform.ID)
- return "id";
- if (code == MapTransform.CP)
- return "cp";
- return "?";
- }
-
- public String toSystem(MapTransform code) {
- return code.getSystem();
- }
-
-}
-
+package org.hl7.fhir.dstu3.model.codesystems;
+
+/*
+ Copyright (c) 2011+, HL7, Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of HL7 nor the names of its contributors may be used to
+ endorse or promote products derived from this software without specific
+ prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+// Generated on Sat, Mar 25, 2017 21:03-0400 for FHIR v3.0.0
+
+
+import org.hl7.fhir.dstu3.model.EnumFactory;
+
+public class MapTransformEnumFactory implements EnumFactory {
+
+ public MapTransform fromCode(String codeString) throws IllegalArgumentException {
+ if (codeString == null || "".equals(codeString))
+ return null;
+ if ("create".equals(codeString))
+ return MapTransform.CREATE;
+ if ("copy".equals(codeString))
+ return MapTransform.COPY;
+ if ("truncate".equals(codeString))
+ return MapTransform.TRUNCATE;
+ if ("escapeUrlParam".equals(codeString))
+ return MapTransform.ESCAPE;
+ if ("cast".equals(codeString))
+ return MapTransform.CAST;
+ if ("append".equals(codeString))
+ return MapTransform.APPEND;
+ if ("translate".equals(codeString))
+ return MapTransform.TRANSLATE;
+ if ("reference".equals(codeString))
+ return MapTransform.REFERENCE;
+ if ("dateOp".equals(codeString))
+ return MapTransform.DATEOP;
+ if ("uuid".equals(codeString))
+ return MapTransform.UUID;
+ if ("pointer".equals(codeString))
+ return MapTransform.POINTER;
+ if ("evaluate".equals(codeString))
+ return MapTransform.EVALUATE;
+ if ("cc".equals(codeString))
+ return MapTransform.CC;
+ if ("c".equals(codeString))
+ return MapTransform.C;
+ if ("qty".equals(codeString))
+ return MapTransform.QTY;
+ if ("id".equals(codeString))
+ return MapTransform.ID;
+ if ("cp".equals(codeString))
+ return MapTransform.CP;
+ throw new IllegalArgumentException("Unknown MapTransform code '"+codeString+"'");
+ }
+
+ public String toCode(MapTransform code) {
+ if (code == MapTransform.CREATE)
+ return "create";
+ if (code == MapTransform.COPY)
+ return "copy";
+ if (code == MapTransform.TRUNCATE)
+ return "truncate";
+ if (code == MapTransform.ESCAPE)
+ return "escapeUrlParam";
+ if (code == MapTransform.CAST)
+ return "cast";
+ if (code == MapTransform.APPEND)
+ return "append";
+ if (code == MapTransform.TRANSLATE)
+ return "translate";
+ if (code == MapTransform.REFERENCE)
+ return "reference";
+ if (code == MapTransform.DATEOP)
+ return "dateOp";
+ if (code == MapTransform.UUID)
+ return "uuid";
+ if (code == MapTransform.POINTER)
+ return "pointer";
+ if (code == MapTransform.EVALUATE)
+ return "evaluate";
+ if (code == MapTransform.CC)
+ return "cc";
+ if (code == MapTransform.C)
+ return "c";
+ if (code == MapTransform.QTY)
+ return "qty";
+ if (code == MapTransform.ID)
+ return "id";
+ if (code == MapTransform.CP)
+ return "cp";
+ return "?";
+ }
+
+ public String toSystem(MapTransform code) {
+ return code.getSystem();
+ }
+
+}
+
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu3Test.java
index 68235bea36a..9566989b0a0 100644
--- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu3Test.java
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu3Test.java
@@ -105,7 +105,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
@Test
public void testEscapedOperationName() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/%24andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escape("VALTOK2A|VALTOK2B"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/%24andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode());
@@ -118,7 +118,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
@Test
public void testAndListWithUrl() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escape("VALTOK2A|VALTOK2B"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode());
@@ -270,7 +270,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
}
@Test
public void testNonRepeatingWithUrl() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr=VALSTR&valtok=" + UrlUtil.escape("VALTOKA|VALTOKB"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr=VALSTR&valtok=" + UrlUtil.escapeUrlParam("VALTOKA|VALTOKB"));
HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode());
@@ -290,7 +290,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
@Test
public void testNonRepeatingWithUrlQualified() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr:exact=VALSTR&valtok:not=" + UrlUtil.escape("VALTOKA|VALTOKB"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr:exact=VALSTR&valtok:not=" + UrlUtil.escapeUrlParam("VALTOKA|VALTOKB"));
HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode());
@@ -345,7 +345,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
@Test
public void testOrListWithUrl() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$orlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escape("VALTOK2A|VALTOK2B"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$orlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode());
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/SearchDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/SearchDstu3Test.java
index a8a0128f563..351328a4c89 100644
--- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/SearchDstu3Test.java
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/SearchDstu3Test.java
@@ -137,25 +137,25 @@ public class SearchDstu3Test {
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=" + Constants.CT_FHIR_JSON_NEW);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW)));
+ assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
// Fetch the next page
httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW)));
+ assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
// Fetch the next page
httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW)));
+ assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
// Fetch the next page
httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW)));
+ assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
}
diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/utilities/xml/XMLUtil.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/utilities/xml/XMLUtil.java
index c279b41c0f8..98c81ddc3ea 100644
--- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/utilities/xml/XMLUtil.java
+++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/utilities/xml/XMLUtil.java
@@ -1,406 +1,406 @@
-/*
-Copyright (c) 2011+, HL7, Inc
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of HL7 nor the names of its contributors may be used to
- endorse or promote products derived from this software without specific
- prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
-INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
-*/
-package org.hl7.fhir.instance.utilities.xml;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.List;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import org.hl7.fhir.instance.utilities.Utilities;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.ls.DOMImplementationLS;
-import org.w3c.dom.ls.LSSerializer;
-
-public class XMLUtil {
-
- public static final String SPACE_CHAR = "\u00A0";
-
- public static boolean isNMToken(String name) {
- if (name == null)
- return false;
- for (int i = 0; i < name.length(); i++)
- if (!isNMTokenChar(name.charAt(i)))
- return false;
- return name.length() > 0;
- }
-
- public static boolean isNMTokenChar(char c) {
- return isLetter(c) || isDigit(c) || c == '.' || c == '-' || c == '_' || c == ':' || isCombiningChar(c) || isExtender(c);
- }
-
- private static boolean isDigit(char c) {
- return (c >= '\u0030' && c <= '\u0039') || (c >= '\u0660' && c <= '\u0669') || (c >= '\u06F0' && c <= '\u06F9') ||
- (c >= '\u0966' && c <= '\u096F') || (c >= '\u09E6' && c <= '\u09EF') || (c >= '\u0A66' && c <= '\u0A6F') ||
- (c >= '\u0AE6' && c <= '\u0AEF') || (c >= '\u0B66' && c <= '\u0B6F') || (c >= '\u0BE7' && c <= '\u0BEF') ||
- (c >= '\u0C66' && c <= '\u0C6F') || (c >= '\u0CE6' && c <= '\u0CEF') || (c >= '\u0D66' && c <= '\u0D6F') ||
- (c >= '\u0E50' && c <= '\u0E59') || (c >= '\u0ED0' && c <= '\u0ED9') || (c >= '\u0F20' && c <= '\u0F29');
- }
-
- private static boolean isCombiningChar(char c) {
- return (c >= '\u0300' && c <= '\u0345') || (c >= '\u0360' && c <= '\u0361') || (c >= '\u0483' && c <= '\u0486') ||
- (c >= '\u0591' && c <= '\u05A1') || (c >= '\u05A3' && c <= '\u05B9') || (c >= '\u05BB' && c <= '\u05BD') ||
- c == '\u05BF' || (c >= '\u05C1' && c <= '\u05C2') || c == '\u05C4' || (c >= '\u064B' && c <= '\u0652') ||
- c == '\u0670' || (c >= '\u06D6' && c <= '\u06DC') || (c >= '\u06DD' && c <= '\u06DF') || (c >= '\u06E0' && c <= '\u06E4') ||
- (c >= '\u06E7' && c <= '\u06E8') || (c >= '\u06EA' && c <= '\u06ED') || (c >= '\u0901' && c <= '\u0903') || c == '\u093C' ||
- (c >= '\u093E' && c <= '\u094C') || c == '\u094D' || (c >= '\u0951' && c <= '\u0954') || (c >= '\u0962' && c <= '\u0963') ||
- (c >= '\u0981' && c <= '\u0983') || c == '\u09BC' || c == '\u09BE' || c == '\u09BF' || (c >= '\u09C0' && c <= '\u09C4') ||
- (c >= '\u09C7' && c <= '\u09C8') || (c >= '\u09CB' && c <= '\u09CD') || c == '\u09D7' || (c >= '\u09E2' && c <= '\u09E3') ||
- c == '\u0A02' || c == '\u0A3C' || c == '\u0A3E' || c == '\u0A3F' || (c >= '\u0A40' && c <= '\u0A42') ||
- (c >= '\u0A47' && c <= '\u0A48') || (c >= '\u0A4B' && c <= '\u0A4D') || (c >= '\u0A70' && c <= '\u0A71') ||
- (c >= '\u0A81' && c <= '\u0A83') || c == '\u0ABC' || (c >= '\u0ABE' && c <= '\u0AC5') || (c >= '\u0AC7' && c <= '\u0AC9') ||
- (c >= '\u0ACB' && c <= '\u0ACD') || (c >= '\u0B01' && c <= '\u0B03') || c == '\u0B3C' || (c >= '\u0B3E' && c <= '\u0B43') ||
- (c >= '\u0B47' && c <= '\u0B48') || (c >= '\u0B4B' && c <= '\u0B4D') || (c >= '\u0B56' && c <= '\u0B57') ||
- (c >= '\u0B82' && c <= '\u0B83') || (c >= '\u0BBE' && c <= '\u0BC2') || (c >= '\u0BC6' && c <= '\u0BC8') ||
- (c >= '\u0BCA' && c <= '\u0BCD') || c == '\u0BD7' || (c >= '\u0C01' && c <= '\u0C03') || (c >= '\u0C3E' && c <= '\u0C44') ||
- (c >= '\u0C46' && c <= '\u0C48') || (c >= '\u0C4A' && c <= '\u0C4D') || (c >= '\u0C55' && c <= '\u0C56') ||
- (c >= '\u0C82' && c <= '\u0C83') || (c >= '\u0CBE' && c <= '\u0CC4') || (c >= '\u0CC6' && c <= '\u0CC8') ||
- (c >= '\u0CCA' && c <= '\u0CCD') || (c >= '\u0CD5' && c <= '\u0CD6') || (c >= '\u0D02' && c <= '\u0D03') ||
- (c >= '\u0D3E' && c <= '\u0D43') || (c >= '\u0D46' && c <= '\u0D48') || (c >= '\u0D4A' && c <= '\u0D4D') || c == '\u0D57' ||
- c == '\u0E31' || (c >= '\u0E34' && c <= '\u0E3A') || (c >= '\u0E47' && c <= '\u0E4E') || c == '\u0EB1' ||
- (c >= '\u0EB4' && c <= '\u0EB9') || (c >= '\u0EBB' && c <= '\u0EBC') || (c >= '\u0EC8' && c <= '\u0ECD') ||
- (c >= '\u0F18' && c <= '\u0F19') || c == '\u0F35' || c == '\u0F37' || c == '\u0F39' || c == '\u0F3E' || c == '\u0F3F' ||
- (c >= '\u0F71' && c <= '\u0F84') || (c >= '\u0F86' && c <= '\u0F8B') || (c >= '\u0F90' && c <= '\u0F95') || c == '\u0F97' ||
- (c >= '\u0F99' && c <= '\u0FAD') || (c >= '\u0FB1' && c <= '\u0FB7') || c == '\u0FB9' || (c >= '\u20D0' && c <= '\u20DC') ||
- c == '\u20E1' || (c >= '\u302A' && c <= '\u302F') || c == '\u3099' || c == '\u309A';
- }
-
- private static boolean isExtender(char c) {
- return c == '\u00B7' || c == '\u02D0' || c == '\u02D1' || c == '\u0387' || c == '\u0640' || c == '\u0E46' ||
- c == '\u0EC6' || c == '\u3005' || (c >= '\u3031' && c <= '\u3035') || (c >= '\u309D' && c <= '\u309E') ||
- (c >= '\u30FC' && c <= '\u30FE');
- }
-
- private static boolean isLetter(char c) {
- return isBaseChar(c) || isIdeographic(c);
- }
-
- private static boolean isBaseChar(char c) {
- return (c >= '\u0041' && c <= '\u005A') || (c >= '\u0061' && c <= '\u007A') || (c >= '\u00C0' && c <= '\u00D6') ||
- (c >= '\u00D8' && c <= '\u00F6') || (c >= '\u00F8' && c <= '\u00FF') || (c >= '\u0100' && c <= '\u0131') ||
- (c >= '\u0134' && c <= '\u013E') || (c >= '\u0141' && c <= '\u0148') || (c >= '\u014A' && c <= '\u017E') ||
- (c >= '\u0180' && c <= '\u01C3') || (c >= '\u01CD' && c <= '\u01F0') || (c >= '\u01F4' && c <= '\u01F5') ||
- (c >= '\u01FA' && c <= '\u0217') || (c >= '\u0250' && c <= '\u02A8') || (c >= '\u02BB' && c <= '\u02C1') ||
- c == '\u0386' || (c >= '\u0388' && c <= '\u038A') || c == '\u038C' || (c >= '\u038E' && c <= '\u03A1') ||
- (c >= '\u03A3' && c <= '\u03CE') || (c >= '\u03D0' && c <= '\u03D6') || c == '\u03DA' || c == '\u03DC' || c == '\u03DE' ||
- c == '\u03E0' || (c >= '\u03E2' && c <= '\u03F3') || (c >= '\u0401' && c <= '\u040C') || (c >= '\u040E' && c <= '\u044F') ||
- (c >= '\u0451' && c <= '\u045C') || (c >= '\u045E' && c <= '\u0481') || (c >= '\u0490' && c <= '\u04C4') ||
- (c >= '\u04C7' && c <= '\u04C8') || (c >= '\u04CB' && c <= '\u04CC') || (c >= '\u04D0' && c <= '\u04EB') ||
- (c >= '\u04EE' && c <= '\u04F5') || (c >= '\u04F8' && c <= '\u04F9') || (c >= '\u0531' && c <= '\u0556') ||
- c == '\u0559' || (c >= '\u0561' && c <= '\u0586') || (c >= '\u05D0' && c <= '\u05EA') || (c >= '\u05F0' && c <= '\u05F2') ||
- (c >= '\u0621' && c <= '\u063A') || (c >= '\u0641' && c <= '\u064A') || (c >= '\u0671' && c <= '\u06B7') ||
- (c >= '\u06BA' && c <= '\u06BE') || (c >= '\u06C0' && c <= '\u06CE') || (c >= '\u06D0' && c <= '\u06D3') ||
- c == '\u06D5' || (c >= '\u06E5' && c <= '\u06E6') || (c >= '\u0905' && c <= '\u0939') || c == '\u093D' ||
- (c >= '\u0958' && c <= '\u0961') || (c >= '\u0985' && c <= '\u098C') || (c >= '\u098F' && c <= '\u0990') ||
- (c >= '\u0993' && c <= '\u09A8') || (c >= '\u09AA' && c <= '\u09B0') || c == '\u09B2' ||
- (c >= '\u09B6' && c <= '\u09B9') || (c >= '\u09DC' && c <= '\u09DD') || (c >= '\u09DF' && c <= '\u09E1') ||
- (c >= '\u09F0' && c <= '\u09F1') || (c >= '\u0A05' && c <= '\u0A0A') || (c >= '\u0A0F' && c <= '\u0A10') ||
- (c >= '\u0A13' && c <= '\u0A28') || (c >= '\u0A2A' && c <= '\u0A30') || (c >= '\u0A32' && c <= '\u0A33') ||
- (c >= '\u0A35' && c <= '\u0A36') || (c >= '\u0A38' && c <= '\u0A39') || (c >= '\u0A59' && c <= '\u0A5C') ||
- c == '\u0A5E' || (c >= '\u0A72' && c <= '\u0A74') || (c >= '\u0A85' && c <= '\u0A8B') || c == '\u0A8D' ||
- (c >= '\u0A8F' && c <= '\u0A91') || (c >= '\u0A93' && c <= '\u0AA8') || (c >= '\u0AAA' && c <= '\u0AB0') ||
- (c >= '\u0AB2' && c <= '\u0AB3') || (c >= '\u0AB5' && c <= '\u0AB9') || c == '\u0ABD' || c == '\u0AE0' ||
- (c >= '\u0B05' && c <= '\u0B0C') || (c >= '\u0B0F' && c <= '\u0B10') || (c >= '\u0B13' && c <= '\u0B28') ||
- (c >= '\u0B2A' && c <= '\u0B30') || (c >= '\u0B32' && c <= '\u0B33') || (c >= '\u0B36' && c <= '\u0B39') ||
- c == '\u0B3D' || (c >= '\u0B5C' && c <= '\u0B5D') || (c >= '\u0B5F' && c <= '\u0B61') ||
- (c >= '\u0B85' && c <= '\u0B8A') || (c >= '\u0B8E' && c <= '\u0B90') || (c >= '\u0B92' && c <= '\u0B95') ||
- (c >= '\u0B99' && c <= '\u0B9A') || c == '\u0B9C' || (c >= '\u0B9E' && c <= '\u0B9F') ||
- (c >= '\u0BA3' && c <= '\u0BA4') || (c >= '\u0BA8' && c <= '\u0BAA') || (c >= '\u0BAE' && c <= '\u0BB5') ||
- (c >= '\u0BB7' && c <= '\u0BB9') || (c >= '\u0C05' && c <= '\u0C0C') || (c >= '\u0C0E' && c <= '\u0C10') ||
- (c >= '\u0C12' && c <= '\u0C28') || (c >= '\u0C2A' && c <= '\u0C33') || (c >= '\u0C35' && c <= '\u0C39') ||
- (c >= '\u0C60' && c <= '\u0C61') || (c >= '\u0C85' && c <= '\u0C8C') || (c >= '\u0C8E' && c <= '\u0C90') ||
- (c >= '\u0C92' && c <= '\u0CA8') || (c >= '\u0CAA' && c <= '\u0CB3') || (c >= '\u0CB5' && c <= '\u0CB9') ||
- c == '\u0CDE' || (c >= '\u0CE0' && c <= '\u0CE1') || (c >= '\u0D05' && c <= '\u0D0C') ||
- (c >= '\u0D0E' && c <= '\u0D10') || (c >= '\u0D12' && c <= '\u0D28') || (c >= '\u0D2A' && c <= '\u0D39') ||
- (c >= '\u0D60' && c <= '\u0D61') || (c >= '\u0E01' && c <= '\u0E2E') || c == '\u0E30' ||
- (c >= '\u0E32' && c <= '\u0E33') || (c >= '\u0E40' && c <= '\u0E45') || (c >= '\u0E81' && c <= '\u0E82') ||
- c == '\u0E84' || (c >= '\u0E87' && c <= '\u0E88') || c == '\u0E8A' || c == '\u0E8D' || (c >= '\u0E94' && c <= '\u0E97') ||
- (c >= '\u0E99' && c <= '\u0E9F') || (c >= '\u0EA1' && c <= '\u0EA3') || c == '\u0EA5' || c == '\u0EA7' ||
- (c >= '\u0EAA' && c <= '\u0EAB') || (c >= '\u0EAD' && c <= '\u0EAE') || c == '\u0EB0' ||
- (c >= '\u0EB2' && c <= '\u0EB3') || c == '\u0EBD' || (c >= '\u0EC0' && c <= '\u0EC4') ||
- (c >= '\u0F40' && c <= '\u0F47') || (c >= '\u0F49' && c <= '\u0F69') || (c >= '\u10A0' && c <= '\u10C5') ||
- (c >= '\u10D0' && c <= '\u10F6') || c == '\u1100' || (c >= '\u1102' && c <= '\u1103') ||
- (c >= '\u1105' && c <= '\u1107') || c == '\u1109' || (c >= '\u110B' && c <= '\u110C') ||
- (c >= '\u110E' && c <= '\u1112') || c == '\u113C' || c == '\u113E' || c == '\u1140' || c == '\u114C' ||
- c == '\u114E' || c == '\u1150' || (c >= '\u1154' && c <= '\u1155') || c == '\u1159' ||
- (c >= '\u115F' && c <= '\u1161') || c == '\u1163' || c == '\u1165' || c == '\u1167' || c == '\u1169' ||
- (c >= '\u116D' && c <= '\u116E') || (c >= '\u1172' && c <= '\u1173') || c == '\u1175' ||
- c == '\u119E' || c == '\u11A8' || c == '\u11AB' || (c >= '\u11AE' && c <= '\u11AF') ||
- (c >= '\u11B7' && c <= '\u11B8') || c == '\u11BA' || (c >= '\u11BC' && c <= '\u11C2') ||
- c == '\u11EB' || c == '\u11F0' || c == '\u11F9' || (c >= '\u1E00' && c <= '\u1E9B') || (c >= '\u1EA0' && c <= '\u1EF9') ||
- (c >= '\u1F00' && c <= '\u1F15') || (c >= '\u1F18' && c <= '\u1F1D') || (c >= '\u1F20' && c <= '\u1F45') ||
- (c >= '\u1F48' && c <= '\u1F4D') || (c >= '\u1F50' && c <= '\u1F57') || c == '\u1F59' || c == '\u1F5B' || c == '\u1F5D' ||
- (c >= '\u1F5F' && c <= '\u1F7D') || (c >= '\u1F80' && c <= '\u1FB4') || (c >= '\u1FB6' && c <= '\u1FBC') ||
- c == '\u1FBE' || (c >= '\u1FC2' && c <= '\u1FC4') || (c >= '\u1FC6' && c <= '\u1FCC') ||
- (c >= '\u1FD0' && c <= '\u1FD3') || (c >= '\u1FD6' && c <= '\u1FDB') || (c >= '\u1FE0' && c <= '\u1FEC') ||
- (c >= '\u1FF2' && c <= '\u1FF4') || (c >= '\u1FF6' && c <= '\u1FFC') || c == '\u2126' ||
- (c >= '\u212A' && c <= '\u212B') || c == '\u212E' || (c >= '\u2180' && c <= '\u2182') ||
- (c >= '\u3041' && c <= '\u3094') || (c >= '\u30A1' && c <= '\u30FA') || (c >= '\u3105' && c <= '\u312C') ||
- (c >= '\uAC00' && c <= '\uD7A3');
- }
-
- private static boolean isIdeographic(char c) {
- return (c >= '\u4E00' && c <= '\u9FA5') || c == '\u3007' || (c >= '\u3021' && c <= '\u3029');
- }
-
- public static String determineEncoding(InputStream stream) throws IOException {
- stream.mark(20000);
- try {
- int b0 = stream.read();
- int b1 = stream.read();
- int b2 = stream.read();
- int b3 = stream.read();
-
- if (b0 == 0xFE && b1 == 0xFF)
- return "UTF-16BE";
- else if (b0 == 0xFF && b1 == 0xFE)
- return "UTF-16LE";
- else if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF )
- return "UTF-8";
- else if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F)
- return "UTF-16BE";
- else if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00)
- return "UTF-16LE";
- else if (b0 == 0x3C && b1 == 0x3F && b2 == 0x78 && b3 == 0x6D) {
-// UTF-8, ISO 646, ASCII, some part of ISO 8859, Shift-JIS, EUC, or any other 7-bit, 8-bit, or mixed-width encoding
-// which ensures that the characters of ASCII have their normal positions, width, and values; the actual encoding
-// declaration must be read to detect which of these applies, but since all of these encodings use the same bit patterns
-// for the relevant ASCII characters, the encoding declaration itself may be read reliably
- InputStreamReader rdr = new InputStreamReader(stream, "US-ASCII");
- String hdr = readFirstLine(rdr);
- return extractEncoding(hdr);
- } else
- return null;
- } finally {
- stream.reset();
- }
- }
-
- private static String extractEncoding(String hdr) {
- int i = hdr.indexOf("encoding=");
- if (i == -1)
- return null;
- hdr = hdr.substring(i+9);
- char sep = hdr.charAt(0);
- hdr = hdr.substring(1);
- i = hdr.indexOf(sep);
- if (i == -1)
- return null;
- return hdr.substring(0, i);
- }
-
- private static String readFirstLine(InputStreamReader rdr) throws IOException {
- char[] buf = new char[1];
- StringBuffer bldr = new StringBuffer();
- rdr.read(buf);
- while (buf[0] != '>') {
- bldr.append(buf[0]);
- rdr.read(buf);
- }
- return bldr.toString();
- }
-
-
- public static boolean charSetImpliesAscii(String charset) {
- return charset.equals("ISO-8859-1") || charset.equals("US-ASCII");
- }
-
-
- /**
- * Converts the raw characters to XML escape characters.
- *
- * @param rawContent
- * @param charset Null when charset is not known, so we assume it's unicode
- * @param isNoLines
- * @return escape string
- */
- public static String escapeXML(String rawContent, String charset, boolean isNoLines) {
- if (rawContent == null)
- return "";
- else {
- StringBuffer sb = new StringBuffer();
-
- for (int i = 0; i < rawContent.length(); i++) {
- char ch = rawContent.charAt(i);
- if (ch == '\'')
- sb.append("'");
- else if (ch == '&')
- sb.append("&");
- else if (ch == '"')
- sb.append(""");
- else if (ch == '<')
- sb.append("<");
- else if (ch == '>')
- sb.append(">");
- else if (ch > '~' && charset != null && charSetImpliesAscii(charset))
- // TODO - why is hashcode the only way to get the unicode number for the character
- // in jre 5.0?
- sb.append(""+Integer.toHexString(new Character(ch).hashCode()).toUpperCase()+";");
- else if (isNoLines) {
- if (ch == '\r')
- sb.append("
");
- else if (ch != '\n')
- sb.append(ch);
- }
- else
- sb.append(ch);
- }
- return sb.toString();
- }
- }
-
- public static Element getFirstChild(Element e) {
- if (e == null)
- return null;
- Node n = e.getFirstChild();
- while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
- n = n.getNextSibling();
- return (Element) n;
- }
-
- public static Element getNamedChild(Element e, String name) {
- Element c = getFirstChild(e);
- while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName()))
- c = getNextSibling(c);
- return c;
- }
-
- public static Element getNextSibling(Element e) {
- Node n = e.getNextSibling();
- while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
- n = n.getNextSibling();
- return (Element) n;
- }
-
- public static void getNamedChildren(Element e, String name, List set) {
- Element c = getFirstChild(e);
- while (c != null) {
- if (name.equals(c.getLocalName()) || name.equals(c.getNodeName()) )
- set.add(c);
- c = getNextSibling(c);
- }
- }
-
- public static String htmlToXmlEscapedPlainText(Element r) {
- StringBuilder s = new StringBuilder();
- Node n = r.getFirstChild();
- boolean ws = false;
- while (n != null) {
- if (n.getNodeType() == Node.TEXT_NODE) {
- String t = n.getTextContent().trim();
- if (Utilities.noString(t))
- ws = true;
- else {
- if (ws)
- s.append(" ");
- ws = false;
- s.append(t);
- }
- }
- if (n.getNodeType() == Node.ELEMENT_NODE) {
- if (ws)
- s.append(" ");
- ws = false;
- s.append(htmlToXmlEscapedPlainText((Element) n));
- if (r.getNodeName().equals("br") || r.getNodeName().equals("p"))
- s.append("\r\n");
- }
- n = n.getNextSibling();
- }
- return s.toString();
- }
-
- public static String htmlToXmlEscapedPlainText(String definition) throws Exception {
- return htmlToXmlEscapedPlainText(parseToDom("
"+definition+"
").getDocumentElement());
- }
-
- public static String elementToString(Element el) {
- if (el == null)
- return "";
- Document document = el.getOwnerDocument();
- DOMImplementationLS domImplLS = (DOMImplementationLS) document
- .getImplementation();
- LSSerializer serializer = domImplLS.createLSSerializer();
- return serializer.writeToString(el);
- }
-
- public static String getNamedChildValue(Element element, String name) {
- Element e = getNamedChild(element, name);
- return e == null ? null : e.getAttribute("value");
- }
-
- public static void getNamedChildrenWithWildcard(Element focus, String name, List children) {
- Element c = getFirstChild(focus);
- while (c != null) {
- String n = c.getLocalName() != null ? c.getLocalName() : c.getNodeName();
- if (name.equals(n) || (name.endsWith("[x]") && n.startsWith(name.substring(0, name.length()-3))))
- children.add(c);
- c = getNextSibling(c);
- }
-
- }
-
- public static boolean hasNamedChild(Element e, String name) {
- Element c = getFirstChild(e);
- while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName()))
- c = getNextSibling(c);
- return c != null;
- }
-
- public static Document parseToDom(String content) throws Exception {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(false);
- DocumentBuilder builder = factory.newDocumentBuilder();
- return builder.parse(new ByteArrayInputStream(content.getBytes()));
- }
-
- public static Element getLastChild(Element e) {
- if (e == null)
- return null;
- Node n = e.getLastChild();
- while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
- n = n.getPreviousSibling();
- return (Element) n;
- }
-
- public static Element getPrevSibling(Element e) {
- Node n = e.getPreviousSibling();
- while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
- n = n.getPreviousSibling();
- return (Element) n;
- }
-
-
-}
+/*
+Copyright (c) 2011+, HL7, Inc
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of HL7 nor the names of its contributors may be used to
+ endorse or promote products derived from this software without specific
+ prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+package org.hl7.fhir.instance.utilities.xml;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.hl7.fhir.instance.utilities.Utilities;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.ls.DOMImplementationLS;
+import org.w3c.dom.ls.LSSerializer;
+
+public class XMLUtil {
+
+ public static final String SPACE_CHAR = "\u00A0";
+
+ public static boolean isNMToken(String name) {
+ if (name == null)
+ return false;
+ for (int i = 0; i < name.length(); i++)
+ if (!isNMTokenChar(name.charAt(i)))
+ return false;
+ return name.length() > 0;
+ }
+
+ public static boolean isNMTokenChar(char c) {
+ return isLetter(c) || isDigit(c) || c == '.' || c == '-' || c == '_' || c == ':' || isCombiningChar(c) || isExtender(c);
+ }
+
+ private static boolean isDigit(char c) {
+ return (c >= '\u0030' && c <= '\u0039') || (c >= '\u0660' && c <= '\u0669') || (c >= '\u06F0' && c <= '\u06F9') ||
+ (c >= '\u0966' && c <= '\u096F') || (c >= '\u09E6' && c <= '\u09EF') || (c >= '\u0A66' && c <= '\u0A6F') ||
+ (c >= '\u0AE6' && c <= '\u0AEF') || (c >= '\u0B66' && c <= '\u0B6F') || (c >= '\u0BE7' && c <= '\u0BEF') ||
+ (c >= '\u0C66' && c <= '\u0C6F') || (c >= '\u0CE6' && c <= '\u0CEF') || (c >= '\u0D66' && c <= '\u0D6F') ||
+ (c >= '\u0E50' && c <= '\u0E59') || (c >= '\u0ED0' && c <= '\u0ED9') || (c >= '\u0F20' && c <= '\u0F29');
+ }
+
+ private static boolean isCombiningChar(char c) {
+ return (c >= '\u0300' && c <= '\u0345') || (c >= '\u0360' && c <= '\u0361') || (c >= '\u0483' && c <= '\u0486') ||
+ (c >= '\u0591' && c <= '\u05A1') || (c >= '\u05A3' && c <= '\u05B9') || (c >= '\u05BB' && c <= '\u05BD') ||
+ c == '\u05BF' || (c >= '\u05C1' && c <= '\u05C2') || c == '\u05C4' || (c >= '\u064B' && c <= '\u0652') ||
+ c == '\u0670' || (c >= '\u06D6' && c <= '\u06DC') || (c >= '\u06DD' && c <= '\u06DF') || (c >= '\u06E0' && c <= '\u06E4') ||
+ (c >= '\u06E7' && c <= '\u06E8') || (c >= '\u06EA' && c <= '\u06ED') || (c >= '\u0901' && c <= '\u0903') || c == '\u093C' ||
+ (c >= '\u093E' && c <= '\u094C') || c == '\u094D' || (c >= '\u0951' && c <= '\u0954') || (c >= '\u0962' && c <= '\u0963') ||
+ (c >= '\u0981' && c <= '\u0983') || c == '\u09BC' || c == '\u09BE' || c == '\u09BF' || (c >= '\u09C0' && c <= '\u09C4') ||
+ (c >= '\u09C7' && c <= '\u09C8') || (c >= '\u09CB' && c <= '\u09CD') || c == '\u09D7' || (c >= '\u09E2' && c <= '\u09E3') ||
+ c == '\u0A02' || c == '\u0A3C' || c == '\u0A3E' || c == '\u0A3F' || (c >= '\u0A40' && c <= '\u0A42') ||
+ (c >= '\u0A47' && c <= '\u0A48') || (c >= '\u0A4B' && c <= '\u0A4D') || (c >= '\u0A70' && c <= '\u0A71') ||
+ (c >= '\u0A81' && c <= '\u0A83') || c == '\u0ABC' || (c >= '\u0ABE' && c <= '\u0AC5') || (c >= '\u0AC7' && c <= '\u0AC9') ||
+ (c >= '\u0ACB' && c <= '\u0ACD') || (c >= '\u0B01' && c <= '\u0B03') || c == '\u0B3C' || (c >= '\u0B3E' && c <= '\u0B43') ||
+ (c >= '\u0B47' && c <= '\u0B48') || (c >= '\u0B4B' && c <= '\u0B4D') || (c >= '\u0B56' && c <= '\u0B57') ||
+ (c >= '\u0B82' && c <= '\u0B83') || (c >= '\u0BBE' && c <= '\u0BC2') || (c >= '\u0BC6' && c <= '\u0BC8') ||
+ (c >= '\u0BCA' && c <= '\u0BCD') || c == '\u0BD7' || (c >= '\u0C01' && c <= '\u0C03') || (c >= '\u0C3E' && c <= '\u0C44') ||
+ (c >= '\u0C46' && c <= '\u0C48') || (c >= '\u0C4A' && c <= '\u0C4D') || (c >= '\u0C55' && c <= '\u0C56') ||
+ (c >= '\u0C82' && c <= '\u0C83') || (c >= '\u0CBE' && c <= '\u0CC4') || (c >= '\u0CC6' && c <= '\u0CC8') ||
+ (c >= '\u0CCA' && c <= '\u0CCD') || (c >= '\u0CD5' && c <= '\u0CD6') || (c >= '\u0D02' && c <= '\u0D03') ||
+ (c >= '\u0D3E' && c <= '\u0D43') || (c >= '\u0D46' && c <= '\u0D48') || (c >= '\u0D4A' && c <= '\u0D4D') || c == '\u0D57' ||
+ c == '\u0E31' || (c >= '\u0E34' && c <= '\u0E3A') || (c >= '\u0E47' && c <= '\u0E4E') || c == '\u0EB1' ||
+ (c >= '\u0EB4' && c <= '\u0EB9') || (c >= '\u0EBB' && c <= '\u0EBC') || (c >= '\u0EC8' && c <= '\u0ECD') ||
+ (c >= '\u0F18' && c <= '\u0F19') || c == '\u0F35' || c == '\u0F37' || c == '\u0F39' || c == '\u0F3E' || c == '\u0F3F' ||
+ (c >= '\u0F71' && c <= '\u0F84') || (c >= '\u0F86' && c <= '\u0F8B') || (c >= '\u0F90' && c <= '\u0F95') || c == '\u0F97' ||
+ (c >= '\u0F99' && c <= '\u0FAD') || (c >= '\u0FB1' && c <= '\u0FB7') || c == '\u0FB9' || (c >= '\u20D0' && c <= '\u20DC') ||
+ c == '\u20E1' || (c >= '\u302A' && c <= '\u302F') || c == '\u3099' || c == '\u309A';
+ }
+
+ private static boolean isExtender(char c) {
+ return c == '\u00B7' || c == '\u02D0' || c == '\u02D1' || c == '\u0387' || c == '\u0640' || c == '\u0E46' ||
+ c == '\u0EC6' || c == '\u3005' || (c >= '\u3031' && c <= '\u3035') || (c >= '\u309D' && c <= '\u309E') ||
+ (c >= '\u30FC' && c <= '\u30FE');
+ }
+
+ private static boolean isLetter(char c) {
+ return isBaseChar(c) || isIdeographic(c);
+ }
+
+ private static boolean isBaseChar(char c) {
+ return (c >= '\u0041' && c <= '\u005A') || (c >= '\u0061' && c <= '\u007A') || (c >= '\u00C0' && c <= '\u00D6') ||
+ (c >= '\u00D8' && c <= '\u00F6') || (c >= '\u00F8' && c <= '\u00FF') || (c >= '\u0100' && c <= '\u0131') ||
+ (c >= '\u0134' && c <= '\u013E') || (c >= '\u0141' && c <= '\u0148') || (c >= '\u014A' && c <= '\u017E') ||
+ (c >= '\u0180' && c <= '\u01C3') || (c >= '\u01CD' && c <= '\u01F0') || (c >= '\u01F4' && c <= '\u01F5') ||
+ (c >= '\u01FA' && c <= '\u0217') || (c >= '\u0250' && c <= '\u02A8') || (c >= '\u02BB' && c <= '\u02C1') ||
+ c == '\u0386' || (c >= '\u0388' && c <= '\u038A') || c == '\u038C' || (c >= '\u038E' && c <= '\u03A1') ||
+ (c >= '\u03A3' && c <= '\u03CE') || (c >= '\u03D0' && c <= '\u03D6') || c == '\u03DA' || c == '\u03DC' || c == '\u03DE' ||
+ c == '\u03E0' || (c >= '\u03E2' && c <= '\u03F3') || (c >= '\u0401' && c <= '\u040C') || (c >= '\u040E' && c <= '\u044F') ||
+ (c >= '\u0451' && c <= '\u045C') || (c >= '\u045E' && c <= '\u0481') || (c >= '\u0490' && c <= '\u04C4') ||
+ (c >= '\u04C7' && c <= '\u04C8') || (c >= '\u04CB' && c <= '\u04CC') || (c >= '\u04D0' && c <= '\u04EB') ||
+ (c >= '\u04EE' && c <= '\u04F5') || (c >= '\u04F8' && c <= '\u04F9') || (c >= '\u0531' && c <= '\u0556') ||
+ c == '\u0559' || (c >= '\u0561' && c <= '\u0586') || (c >= '\u05D0' && c <= '\u05EA') || (c >= '\u05F0' && c <= '\u05F2') ||
+ (c >= '\u0621' && c <= '\u063A') || (c >= '\u0641' && c <= '\u064A') || (c >= '\u0671' && c <= '\u06B7') ||
+ (c >= '\u06BA' && c <= '\u06BE') || (c >= '\u06C0' && c <= '\u06CE') || (c >= '\u06D0' && c <= '\u06D3') ||
+ c == '\u06D5' || (c >= '\u06E5' && c <= '\u06E6') || (c >= '\u0905' && c <= '\u0939') || c == '\u093D' ||
+ (c >= '\u0958' && c <= '\u0961') || (c >= '\u0985' && c <= '\u098C') || (c >= '\u098F' && c <= '\u0990') ||
+ (c >= '\u0993' && c <= '\u09A8') || (c >= '\u09AA' && c <= '\u09B0') || c == '\u09B2' ||
+ (c >= '\u09B6' && c <= '\u09B9') || (c >= '\u09DC' && c <= '\u09DD') || (c >= '\u09DF' && c <= '\u09E1') ||
+ (c >= '\u09F0' && c <= '\u09F1') || (c >= '\u0A05' && c <= '\u0A0A') || (c >= '\u0A0F' && c <= '\u0A10') ||
+ (c >= '\u0A13' && c <= '\u0A28') || (c >= '\u0A2A' && c <= '\u0A30') || (c >= '\u0A32' && c <= '\u0A33') ||
+ (c >= '\u0A35' && c <= '\u0A36') || (c >= '\u0A38' && c <= '\u0A39') || (c >= '\u0A59' && c <= '\u0A5C') ||
+ c == '\u0A5E' || (c >= '\u0A72' && c <= '\u0A74') || (c >= '\u0A85' && c <= '\u0A8B') || c == '\u0A8D' ||
+ (c >= '\u0A8F' && c <= '\u0A91') || (c >= '\u0A93' && c <= '\u0AA8') || (c >= '\u0AAA' && c <= '\u0AB0') ||
+ (c >= '\u0AB2' && c <= '\u0AB3') || (c >= '\u0AB5' && c <= '\u0AB9') || c == '\u0ABD' || c == '\u0AE0' ||
+ (c >= '\u0B05' && c <= '\u0B0C') || (c >= '\u0B0F' && c <= '\u0B10') || (c >= '\u0B13' && c <= '\u0B28') ||
+ (c >= '\u0B2A' && c <= '\u0B30') || (c >= '\u0B32' && c <= '\u0B33') || (c >= '\u0B36' && c <= '\u0B39') ||
+ c == '\u0B3D' || (c >= '\u0B5C' && c <= '\u0B5D') || (c >= '\u0B5F' && c <= '\u0B61') ||
+ (c >= '\u0B85' && c <= '\u0B8A') || (c >= '\u0B8E' && c <= '\u0B90') || (c >= '\u0B92' && c <= '\u0B95') ||
+ (c >= '\u0B99' && c <= '\u0B9A') || c == '\u0B9C' || (c >= '\u0B9E' && c <= '\u0B9F') ||
+ (c >= '\u0BA3' && c <= '\u0BA4') || (c >= '\u0BA8' && c <= '\u0BAA') || (c >= '\u0BAE' && c <= '\u0BB5') ||
+ (c >= '\u0BB7' && c <= '\u0BB9') || (c >= '\u0C05' && c <= '\u0C0C') || (c >= '\u0C0E' && c <= '\u0C10') ||
+ (c >= '\u0C12' && c <= '\u0C28') || (c >= '\u0C2A' && c <= '\u0C33') || (c >= '\u0C35' && c <= '\u0C39') ||
+ (c >= '\u0C60' && c <= '\u0C61') || (c >= '\u0C85' && c <= '\u0C8C') || (c >= '\u0C8E' && c <= '\u0C90') ||
+ (c >= '\u0C92' && c <= '\u0CA8') || (c >= '\u0CAA' && c <= '\u0CB3') || (c >= '\u0CB5' && c <= '\u0CB9') ||
+ c == '\u0CDE' || (c >= '\u0CE0' && c <= '\u0CE1') || (c >= '\u0D05' && c <= '\u0D0C') ||
+ (c >= '\u0D0E' && c <= '\u0D10') || (c >= '\u0D12' && c <= '\u0D28') || (c >= '\u0D2A' && c <= '\u0D39') ||
+ (c >= '\u0D60' && c <= '\u0D61') || (c >= '\u0E01' && c <= '\u0E2E') || c == '\u0E30' ||
+ (c >= '\u0E32' && c <= '\u0E33') || (c >= '\u0E40' && c <= '\u0E45') || (c >= '\u0E81' && c <= '\u0E82') ||
+ c == '\u0E84' || (c >= '\u0E87' && c <= '\u0E88') || c == '\u0E8A' || c == '\u0E8D' || (c >= '\u0E94' && c <= '\u0E97') ||
+ (c >= '\u0E99' && c <= '\u0E9F') || (c >= '\u0EA1' && c <= '\u0EA3') || c == '\u0EA5' || c == '\u0EA7' ||
+ (c >= '\u0EAA' && c <= '\u0EAB') || (c >= '\u0EAD' && c <= '\u0EAE') || c == '\u0EB0' ||
+ (c >= '\u0EB2' && c <= '\u0EB3') || c == '\u0EBD' || (c >= '\u0EC0' && c <= '\u0EC4') ||
+ (c >= '\u0F40' && c <= '\u0F47') || (c >= '\u0F49' && c <= '\u0F69') || (c >= '\u10A0' && c <= '\u10C5') ||
+ (c >= '\u10D0' && c <= '\u10F6') || c == '\u1100' || (c >= '\u1102' && c <= '\u1103') ||
+ (c >= '\u1105' && c <= '\u1107') || c == '\u1109' || (c >= '\u110B' && c <= '\u110C') ||
+ (c >= '\u110E' && c <= '\u1112') || c == '\u113C' || c == '\u113E' || c == '\u1140' || c == '\u114C' ||
+ c == '\u114E' || c == '\u1150' || (c >= '\u1154' && c <= '\u1155') || c == '\u1159' ||
+ (c >= '\u115F' && c <= '\u1161') || c == '\u1163' || c == '\u1165' || c == '\u1167' || c == '\u1169' ||
+ (c >= '\u116D' && c <= '\u116E') || (c >= '\u1172' && c <= '\u1173') || c == '\u1175' ||
+ c == '\u119E' || c == '\u11A8' || c == '\u11AB' || (c >= '\u11AE' && c <= '\u11AF') ||
+ (c >= '\u11B7' && c <= '\u11B8') || c == '\u11BA' || (c >= '\u11BC' && c <= '\u11C2') ||
+ c == '\u11EB' || c == '\u11F0' || c == '\u11F9' || (c >= '\u1E00' && c <= '\u1E9B') || (c >= '\u1EA0' && c <= '\u1EF9') ||
+ (c >= '\u1F00' && c <= '\u1F15') || (c >= '\u1F18' && c <= '\u1F1D') || (c >= '\u1F20' && c <= '\u1F45') ||
+ (c >= '\u1F48' && c <= '\u1F4D') || (c >= '\u1F50' && c <= '\u1F57') || c == '\u1F59' || c == '\u1F5B' || c == '\u1F5D' ||
+ (c >= '\u1F5F' && c <= '\u1F7D') || (c >= '\u1F80' && c <= '\u1FB4') || (c >= '\u1FB6' && c <= '\u1FBC') ||
+ c == '\u1FBE' || (c >= '\u1FC2' && c <= '\u1FC4') || (c >= '\u1FC6' && c <= '\u1FCC') ||
+ (c >= '\u1FD0' && c <= '\u1FD3') || (c >= '\u1FD6' && c <= '\u1FDB') || (c >= '\u1FE0' && c <= '\u1FEC') ||
+ (c >= '\u1FF2' && c <= '\u1FF4') || (c >= '\u1FF6' && c <= '\u1FFC') || c == '\u2126' ||
+ (c >= '\u212A' && c <= '\u212B') || c == '\u212E' || (c >= '\u2180' && c <= '\u2182') ||
+ (c >= '\u3041' && c <= '\u3094') || (c >= '\u30A1' && c <= '\u30FA') || (c >= '\u3105' && c <= '\u312C') ||
+ (c >= '\uAC00' && c <= '\uD7A3');
+ }
+
+ private static boolean isIdeographic(char c) {
+ return (c >= '\u4E00' && c <= '\u9FA5') || c == '\u3007' || (c >= '\u3021' && c <= '\u3029');
+ }
+
+ public static String determineEncoding(InputStream stream) throws IOException {
+ stream.mark(20000);
+ try {
+ int b0 = stream.read();
+ int b1 = stream.read();
+ int b2 = stream.read();
+ int b3 = stream.read();
+
+ if (b0 == 0xFE && b1 == 0xFF)
+ return "UTF-16BE";
+ else if (b0 == 0xFF && b1 == 0xFE)
+ return "UTF-16LE";
+ else if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF )
+ return "UTF-8";
+ else if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F)
+ return "UTF-16BE";
+ else if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00)
+ return "UTF-16LE";
+ else if (b0 == 0x3C && b1 == 0x3F && b2 == 0x78 && b3 == 0x6D) {
+// UTF-8, ISO 646, ASCII, some part of ISO 8859, Shift-JIS, EUC, or any other 7-bit, 8-bit, or mixed-width encoding
+// which ensures that the characters of ASCII have their normal positions, width, and values; the actual encoding
+// declaration must be read to detect which of these applies, but since all of these encodings use the same bit patterns
+// for the relevant ASCII characters, the encoding declaration itself may be read reliably
+ InputStreamReader rdr = new InputStreamReader(stream, "US-ASCII");
+ String hdr = readFirstLine(rdr);
+ return extractEncoding(hdr);
+ } else
+ return null;
+ } finally {
+ stream.reset();
+ }
+ }
+
+ private static String extractEncoding(String hdr) {
+ int i = hdr.indexOf("encoding=");
+ if (i == -1)
+ return null;
+ hdr = hdr.substring(i+9);
+ char sep = hdr.charAt(0);
+ hdr = hdr.substring(1);
+ i = hdr.indexOf(sep);
+ if (i == -1)
+ return null;
+ return hdr.substring(0, i);
+ }
+
+ private static String readFirstLine(InputStreamReader rdr) throws IOException {
+ char[] buf = new char[1];
+ StringBuffer bldr = new StringBuffer();
+ rdr.read(buf);
+ while (buf[0] != '>') {
+ bldr.append(buf[0]);
+ rdr.read(buf);
+ }
+ return bldr.toString();
+ }
+
+
+ public static boolean charSetImpliesAscii(String charset) {
+ return charset.equals("ISO-8859-1") || charset.equals("US-ASCII");
+ }
+
+
+ /**
+ * Converts the raw characters to XML escapeUrlParam characters.
+ *
+ * @param rawContent
+ * @param charset Null when charset is not known, so we assume it's unicode
+ * @param isNoLines
+ * @return escapeUrlParam string
+ */
+ public static String escapeXML(String rawContent, String charset, boolean isNoLines) {
+ if (rawContent == null)
+ return "";
+ else {
+ StringBuffer sb = new StringBuffer();
+
+ for (int i = 0; i < rawContent.length(); i++) {
+ char ch = rawContent.charAt(i);
+ if (ch == '\'')
+ sb.append("'");
+ else if (ch == '&')
+ sb.append("&");
+ else if (ch == '"')
+ sb.append(""");
+ else if (ch == '<')
+ sb.append("<");
+ else if (ch == '>')
+ sb.append(">");
+ else if (ch > '~' && charset != null && charSetImpliesAscii(charset))
+ // TODO - why is hashcode the only way to get the unicode number for the character
+ // in jre 5.0?
+ sb.append(""+Integer.toHexString(new Character(ch).hashCode()).toUpperCase()+";");
+ else if (isNoLines) {
+ if (ch == '\r')
+ sb.append("
");
+ else if (ch != '\n')
+ sb.append(ch);
+ }
+ else
+ sb.append(ch);
+ }
+ return sb.toString();
+ }
+ }
+
+ public static Element getFirstChild(Element e) {
+ if (e == null)
+ return null;
+ Node n = e.getFirstChild();
+ while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
+ n = n.getNextSibling();
+ return (Element) n;
+ }
+
+ public static Element getNamedChild(Element e, String name) {
+ Element c = getFirstChild(e);
+ while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName()))
+ c = getNextSibling(c);
+ return c;
+ }
+
+ public static Element getNextSibling(Element e) {
+ Node n = e.getNextSibling();
+ while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
+ n = n.getNextSibling();
+ return (Element) n;
+ }
+
+ public static void getNamedChildren(Element e, String name, List set) {
+ Element c = getFirstChild(e);
+ while (c != null) {
+ if (name.equals(c.getLocalName()) || name.equals(c.getNodeName()) )
+ set.add(c);
+ c = getNextSibling(c);
+ }
+ }
+
+ public static String htmlToXmlEscapedPlainText(Element r) {
+ StringBuilder s = new StringBuilder();
+ Node n = r.getFirstChild();
+ boolean ws = false;
+ while (n != null) {
+ if (n.getNodeType() == Node.TEXT_NODE) {
+ String t = n.getTextContent().trim();
+ if (Utilities.noString(t))
+ ws = true;
+ else {
+ if (ws)
+ s.append(" ");
+ ws = false;
+ s.append(t);
+ }
+ }
+ if (n.getNodeType() == Node.ELEMENT_NODE) {
+ if (ws)
+ s.append(" ");
+ ws = false;
+ s.append(htmlToXmlEscapedPlainText((Element) n));
+ if (r.getNodeName().equals("br") || r.getNodeName().equals("p"))
+ s.append("\r\n");
+ }
+ n = n.getNextSibling();
+ }
+ return s.toString();
+ }
+
+ public static String htmlToXmlEscapedPlainText(String definition) throws Exception {
+ return htmlToXmlEscapedPlainText(parseToDom("
"+definition+"
").getDocumentElement());
+ }
+
+ public static String elementToString(Element el) {
+ if (el == null)
+ return "";
+ Document document = el.getOwnerDocument();
+ DOMImplementationLS domImplLS = (DOMImplementationLS) document
+ .getImplementation();
+ LSSerializer serializer = domImplLS.createLSSerializer();
+ return serializer.writeToString(el);
+ }
+
+ public static String getNamedChildValue(Element element, String name) {
+ Element e = getNamedChild(element, name);
+ return e == null ? null : e.getAttribute("value");
+ }
+
+ public static void getNamedChildrenWithWildcard(Element focus, String name, List children) {
+ Element c = getFirstChild(focus);
+ while (c != null) {
+ String n = c.getLocalName() != null ? c.getLocalName() : c.getNodeName();
+ if (name.equals(n) || (name.endsWith("[x]") && n.startsWith(name.substring(0, name.length()-3))))
+ children.add(c);
+ c = getNextSibling(c);
+ }
+
+ }
+
+ public static boolean hasNamedChild(Element e, String name) {
+ Element c = getFirstChild(e);
+ while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName()))
+ c = getNextSibling(c);
+ return c != null;
+ }
+
+ public static Document parseToDom(String content) throws Exception {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(false);
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ return builder.parse(new ByteArrayInputStream(content.getBytes()));
+ }
+
+ public static Element getLastChild(Element e) {
+ if (e == null)
+ return null;
+ Node n = e.getLastChild();
+ while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
+ n = n.getPreviousSibling();
+ return (Element) n;
+ }
+
+ public static Element getPrevSibling(Element e) {
+ Node n = e.getPreviousSibling();
+ while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
+ n = n.getPreviousSibling();
+ return (Element) n;
+ }
+
+
+}
diff --git a/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/elementmodel/VerticalBarParser.java b/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/elementmodel/VerticalBarParser.java
index 40181ec4472..45e39593a35 100644
--- a/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/elementmodel/VerticalBarParser.java
+++ b/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/elementmodel/VerticalBarParser.java
@@ -1,493 +1,493 @@
-package org.hl7.fhir.r4.elementmodel;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-
-import org.hl7.fhir.r4.context.IWorkerContext;
-import org.hl7.fhir.r4.formats.IParser.OutputStyle;
-import org.hl7.fhir.r4.model.StructureDefinition;
-import org.hl7.fhir.exceptions.DefinitionException;
-import org.hl7.fhir.exceptions.FHIRException;
-import org.hl7.fhir.exceptions.FHIRFormatError;
-
-/**
- * This class provides special support for parsing v2 by the v2 logical model
- * For the logical model, see the FHIRPath spec
- *
- * @author Grahame Grieve
- *
- */
-public class VerticalBarParser extends ParserBase {
-
- /**
- * Delimiters for a message. Note that the application rarely needs to concern
- * itself with this information; it mainly exists for internal use. However if
- * a message is being written to a spec that calls for non-standard delimiters,
- * the application can set them here.
- *
- * @author Grahame
- *
- */
- public class Delimiters {
-
- /**
- * Hl7 defined default delimiter for a field
- */
- public final static char DEFAULT_DELIMITER_FIELD = '|';
-
- /**
- * Hl7 defined default delimiter for a component
- */
- public final static char DEFAULT_DELIMITER_COMPONENT = '^';
-
- /**
- * Hl7 defined default delimiter for a subcomponent
- */
- public final static char DEFAULT_DELIMITER_SUBCOMPONENT = '&';
-
- /**
- * Hl7 defined default delimiter for a repeat
- */
- public final static char DEFAULT_DELIMITER_REPETITION = '~';
-
- /**
- * Hl7 defined default delimiter for an escape
- */
- public final static char DEFAULT_CHARACTER_ESCAPE = '\\';
-
-
- /**
- * defined escape character for this message
- */
- private char escapeCharacter;
-
- /**
- * defined repetition character for this message
- */
- private char repetitionDelimiter;
-
- /**
- * defined field character for this message
- */
- private char fieldDelimiter;
-
- /**
- * defined subComponent character for this message
- */
- private char subComponentDelimiter;
-
- /**
- * defined component character for this message
- */
- private char componentDelimiter;
-
- /**
- * create
- *
- */
- public Delimiters() {
- super();
- reset();
- }
-
- public boolean matches(Delimiters other) {
- return escapeCharacter == other.escapeCharacter &&
- repetitionDelimiter == other.repetitionDelimiter &&
- fieldDelimiter == other.fieldDelimiter &&
- subComponentDelimiter == other.subComponentDelimiter &&
- componentDelimiter == other.componentDelimiter;
- }
-
- /**
- * get defined component character for this message
- * @return
- */
- public char getComponentDelimiter() {
- return componentDelimiter;
- }
-
- /**
- * set defined component character for this message
- * @param componentDelimiter
- */
- public void setComponentDelimiter(char componentDelimiter) {
- this.componentDelimiter = componentDelimiter;
- }
-
- /**
- * get defined escape character for this message
- * @return
- */
- public char getEscapeCharacter() {
- return escapeCharacter;
- }
-
- /**
- * set defined escape character for this message
- * @param escapeCharacter
- */
- public void setEscapeCharacter(char escapeCharacter) {
- this.escapeCharacter = escapeCharacter;
- }
-
- /**
- * get defined field character for this message
- * @return
- */
- public char getFieldDelimiter() {
- return fieldDelimiter;
- }
-
- /**
- * set defined field character for this message
- * @param fieldDelimiter
- */
- public void setFieldDelimiter(char fieldDelimiter) {
- this.fieldDelimiter = fieldDelimiter;
- }
-
- /**
- * get repeat field character for this message
- * @return
- */
- public char getRepetitionDelimiter() {
- return repetitionDelimiter;
- }
-
- /**
- * set repeat field character for this message
- * @param repetitionDelimiter
- */
- public void setRepetitionDelimiter(char repetitionDelimiter) {
- this.repetitionDelimiter = repetitionDelimiter;
- }
-
- /**
- * get sub-component field character for this message
- * @return
- */
- public char getSubComponentDelimiter() {
- return subComponentDelimiter;
- }
-
- /**
- * set sub-component field character for this message
- * @param subComponentDelimiter
- */
- public void setSubComponentDelimiter(char subComponentDelimiter) {
- this.subComponentDelimiter = subComponentDelimiter;
- }
-
- /**
- * reset to default HL7 values
- *
- */
- public void reset () {
- fieldDelimiter = DEFAULT_DELIMITER_FIELD;
- componentDelimiter = DEFAULT_DELIMITER_COMPONENT;
- subComponentDelimiter = DEFAULT_DELIMITER_SUBCOMPONENT;
- repetitionDelimiter = DEFAULT_DELIMITER_REPETITION;
- escapeCharacter = DEFAULT_CHARACTER_ESCAPE;
- }
-
- /**
- * check that the delimiters are valid
- *
- * @throws FHIRException
- */
- public void check() throws FHIRException {
- rule(componentDelimiter != fieldDelimiter, "Delimiter Error: \""+componentDelimiter+"\" is used for both CPComponent and CPField");
- rule(subComponentDelimiter != fieldDelimiter, "Delimiter Error: \""+subComponentDelimiter+"\" is used for both CPSubComponent and CPField");
- rule(subComponentDelimiter != componentDelimiter, "Delimiter Error: \""+subComponentDelimiter+"\" is used for both CPSubComponent and CPComponent");
- rule(repetitionDelimiter != fieldDelimiter, "Delimiter Error: \""+repetitionDelimiter+"\" is used for both Repetition and CPField");
- rule(repetitionDelimiter != componentDelimiter, "Delimiter Error: \""+repetitionDelimiter+"\" is used for both Repetition and CPComponent");
- rule(repetitionDelimiter != subComponentDelimiter, "Delimiter Error: \""+repetitionDelimiter+"\" is used for both Repetition and CPSubComponent");
- rule(escapeCharacter != fieldDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and CPField");
- rule(escapeCharacter != componentDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and CPComponent");
- rule(escapeCharacter != subComponentDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and CPSubComponent");
- rule(escapeCharacter != repetitionDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and Repetition");
- }
-
- /**
- * check to see whether ch is a delimiter character (vertical bar parser support)
- * @param ch
- * @return
- */
- public boolean isDelimiter(char ch) {
- return ch == escapeCharacter || ch == repetitionDelimiter || ch == fieldDelimiter || ch == subComponentDelimiter || ch == componentDelimiter;
- }
-
- /**
- * check to see whether ch is a cell delimiter char (vertical bar parser support)
- * @param ch
- * @return
- */
- public boolean isCellDelimiter(char ch) {
- return ch == repetitionDelimiter || ch == fieldDelimiter || ch == subComponentDelimiter || ch == componentDelimiter;
- }
-
- /**
- * get the escape for a character
- * @param ch
- * @return
- */
- public String getEscape(char ch) {
- if (ch == escapeCharacter)
- return escapeCharacter + "E" + escapeCharacter;
- else if (ch == fieldDelimiter)
- return escapeCharacter + "F" + escapeCharacter;
- else if (ch == componentDelimiter)
- return escapeCharacter + "S" + escapeCharacter;
- else if (ch == subComponentDelimiter)
- return escapeCharacter + "T" + escapeCharacter;
- else if (ch == repetitionDelimiter)
- return escapeCharacter + "R" + escapeCharacter;
- else
- return null;
- }
-
- /**
- * build the MSH-2 content
- * @return
- */
- public String forMSH2() {
- return "" + componentDelimiter + repetitionDelimiter + escapeCharacter + subComponentDelimiter;
- }
-
- /**
- * check to see whether ch represents a delimiter escape
- * @param ch
- * @return
- */
- public boolean isDelimiterEscape(char ch) {
- return ch == 'F' || ch == 'S' || ch == 'E' || ch == 'T' || ch == 'R';
- }
-
- /**
- * get escape for ch in an escape
- * @param ch
- * @return
- * @throws DefinitionException
- * @throws FHIRException
- */
- public char getDelimiterEscapeChar(char ch) throws DefinitionException {
- if (ch == 'E')
- return escapeCharacter;
- else if (ch == 'F')
- return fieldDelimiter;
- else if (ch == 'S')
- return componentDelimiter;
- else if (ch == 'T')
- return subComponentDelimiter;
- else if (ch == 'R')
- return repetitionDelimiter;
- else
- throw new DefinitionException("internal error in getDelimiterEscapeChar");
- }
- }
-
- public class VerticalBarParserReader {
-
-
- private BufferedInputStream stream;
- private String charsetName;
- private InputStreamReader reader = null;
- private boolean finished;
- private char peeked;
- private char lastValue;
- private int offset;
- private int lineNumber;
-
- public VerticalBarParserReader(BufferedInputStream stream, String charsetName) throws FHIRException {
- super();
- setStream(stream);
- setCharsetName(charsetName);
- open();
- }
-
- public String getCharsetName() {
- return charsetName;
- }
-
- public void setCharsetName(String charsetName) {
- this.charsetName = charsetName;
- }
-
- public BufferedInputStream getStream() {
- return stream;
- }
-
- public void setStream(BufferedInputStream stream) {
- this.stream = stream;
- }
-
- private void open() throws FHIRException {
- try {
- stream.mark(2048);
- reader = new InputStreamReader(stream, charsetName);
- offset = 0;
- lineNumber = 0;
- lastValue = ' ';
- next();
- } catch (Exception e) {
- throw new FHIRException(e);
- }
- }
-
- private void next() throws IOException, FHIRException {
- finished = !reader.ready();
- if (!finished) {
- char[] temp = new char[1];
- rule(reader.read(temp, 0, 1) == 1, "unable to read 1 character from the stream");
- peeked = temp[0];
- }
- }
-
- public String read(int charCount) throws FHIRException {
- String value = "";
- for (int i = 0; i < charCount; i++)
- value = value + read();
- return value;
- }
-
- public void skipEOL () throws FHIRException {
- while (!finished && (peek() == '\r' || peek() == '\n'))
- read();
- }
-
- public char read () throws FHIRException {
- rule(!finished, "No more content to read");
- char value = peek();
- offset++;
- if (value == '\r' || value == '\n') {
- if (lastValue != '\r' || value != '\n')
- lineNumber++;
- }
- lastValue = value;
- try {
- next();
- } catch (Exception e) {
- throw new FHIRException(e);
- }
- return value;
- }
-
- public boolean isFinished () {
- return finished;
- }
-
- public char peek() throws FHIRException {
- rule(!finished, "Cannot peek");
- return peeked;
- }
-
- public void mark() {
- stream.mark(2048);
- }
-
- public void reset() throws FHIRException {
- try {
- stream.reset();
- } catch (IOException e) {
- throw new FHIRException(e);
- }
- open();
- }
-
- public boolean IsEOL() throws FHIRException {
- return peek() == '\r' || peek() == '\n';
- }
-
- public int getLineNumber() {
- return lineNumber;
- }
-
- public int getOffset() {
- return offset;
- }
-
- }
-
- public VerticalBarParser(IWorkerContext context) {
- super(context);
- }
-
- private String charset = "ASCII";
- private Delimiters delimiters = new Delimiters();
-
- @Override
- public Element parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException {
- StructureDefinition sd = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/v2/StructureDefinition/Message");
- Element message = new Element("Message", new Property(context, sd.getSnapshot().getElementFirstRep(), sd));
- VerticalBarParserReader reader = new VerticalBarParserReader(new BufferedInputStream(stream), charset);
-
- preDecode(reader);
- while (!reader.isFinished()) // && (getOptions().getSegmentLimit() == 0 || getOptions().getSegmentLimit() > message.getSegments().size()))
- readSegment(message, reader);
-
- return message;
- }
-
- private void preDecode(VerticalBarParserReader reader) throws FHIRException {
- reader.skipEOL();
- String temp = reader.read(3);
- rule(temp.equals("MSH") || temp.equals("FHS"), "Found '" + temp + "' looking for 'MSH' or 'FHS'");
- readDelimiters(reader);
- // readVersion(message); - probably don't need to do that?
- // readCharacterSet();
- reader.reset(); // ready to read message now
- }
-
- private void rule(boolean test, String msg) throws FHIRException {
- if (!test)
- throw new FHIRException(msg);
- }
-
- private void readDelimiters(VerticalBarParserReader reader) throws FHIRException {
- delimiters.setFieldDelimiter(reader.read());
- if (!(reader.peek() == delimiters.getFieldDelimiter()))
- delimiters.setComponentDelimiter(reader.read());
- if (!(reader.peek() == delimiters.getFieldDelimiter()))
- delimiters.setRepetitionDelimiter(reader.read());
- if (!(reader.peek() == delimiters.getFieldDelimiter()))
- delimiters.setEscapeCharacter(reader.read());
- if (!(reader.peek() == delimiters.getFieldDelimiter()))
- delimiters.setSubComponentDelimiter(reader.read());
- delimiters.check();
- }
-
- private void readSegment(Element message, VerticalBarParserReader reader) throws FHIRException {
- Element segment = new Element("segment", message.getProperty().getChild("segment"));
- message.getChildren().add(segment);
- Element segmentCode = new Element("code", segment.getProperty().getChild("code"));
- segment.getChildren().add(segmentCode);
- segmentCode.setValue(reader.read(3));
-
- int index = 0;
- while (!reader.isFinished() && !reader.IsEOL()) {
- index++;
- readField(reader, segment, index);
- if (!reader.isFinished() && !reader.IsEOL())
- rule(reader.read() == delimiters.getFieldDelimiter(), "Expected to find field delimiter");
- }
- if (!reader.isFinished())
- reader.skipEOL();
- }
-
-
-
- private void readField(VerticalBarParserReader reader, Element segment, int index) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void compose(Element e, OutputStream destination, OutputStyle style, String base) {
- // TODO Auto-generated method stub
-
- }
-
-}
+package org.hl7.fhir.r4.elementmodel;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+
+import org.hl7.fhir.r4.context.IWorkerContext;
+import org.hl7.fhir.r4.formats.IParser.OutputStyle;
+import org.hl7.fhir.r4.model.StructureDefinition;
+import org.hl7.fhir.exceptions.DefinitionException;
+import org.hl7.fhir.exceptions.FHIRException;
+import org.hl7.fhir.exceptions.FHIRFormatError;
+
+/**
+ * This class provides special support for parsing v2 by the v2 logical model
+ * For the logical model, see the FHIRPath spec
+ *
+ * @author Grahame Grieve
+ *
+ */
+public class VerticalBarParser extends ParserBase {
+
+ /**
+ * Delimiters for a message. Note that the application rarely needs to concern
+ * itself with this information; it mainly exists for internal use. However if
+ * a message is being written to a spec that calls for non-standard delimiters,
+ * the application can set them here.
+ *
+ * @author Grahame
+ *
+ */
+ public class Delimiters {
+
+ /**
+ * Hl7 defined default delimiter for a field
+ */
+ public final static char DEFAULT_DELIMITER_FIELD = '|';
+
+ /**
+ * Hl7 defined default delimiter for a component
+ */
+ public final static char DEFAULT_DELIMITER_COMPONENT = '^';
+
+ /**
+ * Hl7 defined default delimiter for a subcomponent
+ */
+ public final static char DEFAULT_DELIMITER_SUBCOMPONENT = '&';
+
+ /**
+ * Hl7 defined default delimiter for a repeat
+ */
+ public final static char DEFAULT_DELIMITER_REPETITION = '~';
+
+ /**
+ * Hl7 defined default delimiter for an escapeUrlParam
+ */
+ public final static char DEFAULT_CHARACTER_ESCAPE = '\\';
+
+
+ /**
+ * defined escapeUrlParam character for this message
+ */
+ private char escapeCharacter;
+
+ /**
+ * defined repetition character for this message
+ */
+ private char repetitionDelimiter;
+
+ /**
+ * defined field character for this message
+ */
+ private char fieldDelimiter;
+
+ /**
+ * defined subComponent character for this message
+ */
+ private char subComponentDelimiter;
+
+ /**
+ * defined component character for this message
+ */
+ private char componentDelimiter;
+
+ /**
+ * create
+ *
+ */
+ public Delimiters() {
+ super();
+ reset();
+ }
+
+ public boolean matches(Delimiters other) {
+ return escapeCharacter == other.escapeCharacter &&
+ repetitionDelimiter == other.repetitionDelimiter &&
+ fieldDelimiter == other.fieldDelimiter &&
+ subComponentDelimiter == other.subComponentDelimiter &&
+ componentDelimiter == other.componentDelimiter;
+ }
+
+ /**
+ * get defined component character for this message
+ * @return
+ */
+ public char getComponentDelimiter() {
+ return componentDelimiter;
+ }
+
+ /**
+ * set defined component character for this message
+ * @param componentDelimiter
+ */
+ public void setComponentDelimiter(char componentDelimiter) {
+ this.componentDelimiter = componentDelimiter;
+ }
+
+ /**
+ * get defined escapeUrlParam character for this message
+ * @return
+ */
+ public char getEscapeCharacter() {
+ return escapeCharacter;
+ }
+
+ /**
+ * set defined escapeUrlParam character for this message
+ * @param escapeCharacter
+ */
+ public void setEscapeCharacter(char escapeCharacter) {
+ this.escapeCharacter = escapeCharacter;
+ }
+
+ /**
+ * get defined field character for this message
+ * @return
+ */
+ public char getFieldDelimiter() {
+ return fieldDelimiter;
+ }
+
+ /**
+ * set defined field character for this message
+ * @param fieldDelimiter
+ */
+ public void setFieldDelimiter(char fieldDelimiter) {
+ this.fieldDelimiter = fieldDelimiter;
+ }
+
+ /**
+ * get repeat field character for this message
+ * @return
+ */
+ public char getRepetitionDelimiter() {
+ return repetitionDelimiter;
+ }
+
+ /**
+ * set repeat field character for this message
+ * @param repetitionDelimiter
+ */
+ public void setRepetitionDelimiter(char repetitionDelimiter) {
+ this.repetitionDelimiter = repetitionDelimiter;
+ }
+
+ /**
+ * get sub-component field character for this message
+ * @return
+ */
+ public char getSubComponentDelimiter() {
+ return subComponentDelimiter;
+ }
+
+ /**
+ * set sub-component field character for this message
+ * @param subComponentDelimiter
+ */
+ public void setSubComponentDelimiter(char subComponentDelimiter) {
+ this.subComponentDelimiter = subComponentDelimiter;
+ }
+
+ /**
+ * reset to default HL7 values
+ *
+ */
+ public void reset () {
+ fieldDelimiter = DEFAULT_DELIMITER_FIELD;
+ componentDelimiter = DEFAULT_DELIMITER_COMPONENT;
+ subComponentDelimiter = DEFAULT_DELIMITER_SUBCOMPONENT;
+ repetitionDelimiter = DEFAULT_DELIMITER_REPETITION;
+ escapeCharacter = DEFAULT_CHARACTER_ESCAPE;
+ }
+
+ /**
+ * check that the delimiters are valid
+ *
+ * @throws FHIRException
+ */
+ public void check() throws FHIRException {
+ rule(componentDelimiter != fieldDelimiter, "Delimiter Error: \""+componentDelimiter+"\" is used for both CPComponent and CPField");
+ rule(subComponentDelimiter != fieldDelimiter, "Delimiter Error: \""+subComponentDelimiter+"\" is used for both CPSubComponent and CPField");
+ rule(subComponentDelimiter != componentDelimiter, "Delimiter Error: \""+subComponentDelimiter+"\" is used for both CPSubComponent and CPComponent");
+ rule(repetitionDelimiter != fieldDelimiter, "Delimiter Error: \""+repetitionDelimiter+"\" is used for both Repetition and CPField");
+ rule(repetitionDelimiter != componentDelimiter, "Delimiter Error: \""+repetitionDelimiter+"\" is used for both Repetition and CPComponent");
+ rule(repetitionDelimiter != subComponentDelimiter, "Delimiter Error: \""+repetitionDelimiter+"\" is used for both Repetition and CPSubComponent");
+ rule(escapeCharacter != fieldDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and CPField");
+ rule(escapeCharacter != componentDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and CPComponent");
+ rule(escapeCharacter != subComponentDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and CPSubComponent");
+ rule(escapeCharacter != repetitionDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and Repetition");
+ }
+
+ /**
+ * check to see whether ch is a delimiter character (vertical bar parser support)
+ * @param ch
+ * @return
+ */
+ public boolean isDelimiter(char ch) {
+ return ch == escapeCharacter || ch == repetitionDelimiter || ch == fieldDelimiter || ch == subComponentDelimiter || ch == componentDelimiter;
+ }
+
+ /**
+ * check to see whether ch is a cell delimiter char (vertical bar parser support)
+ * @param ch
+ * @return
+ */
+ public boolean isCellDelimiter(char ch) {
+ return ch == repetitionDelimiter || ch == fieldDelimiter || ch == subComponentDelimiter || ch == componentDelimiter;
+ }
+
+ /**
+ * get the escapeUrlParam for a character
+ * @param ch
+ * @return
+ */
+ public String getEscape(char ch) {
+ if (ch == escapeCharacter)
+ return escapeCharacter + "E" + escapeCharacter;
+ else if (ch == fieldDelimiter)
+ return escapeCharacter + "F" + escapeCharacter;
+ else if (ch == componentDelimiter)
+ return escapeCharacter + "S" + escapeCharacter;
+ else if (ch == subComponentDelimiter)
+ return escapeCharacter + "T" + escapeCharacter;
+ else if (ch == repetitionDelimiter)
+ return escapeCharacter + "R" + escapeCharacter;
+ else
+ return null;
+ }
+
+ /**
+ * build the MSH-2 content
+ * @return
+ */
+ public String forMSH2() {
+ return "" + componentDelimiter + repetitionDelimiter + escapeCharacter + subComponentDelimiter;
+ }
+
+ /**
+ * check to see whether ch represents a delimiter escapeUrlParam
+ * @param ch
+ * @return
+ */
+ public boolean isDelimiterEscape(char ch) {
+ return ch == 'F' || ch == 'S' || ch == 'E' || ch == 'T' || ch == 'R';
+ }
+
+ /**
+ * get escapeUrlParam for ch in an escapeUrlParam
+ * @param ch
+ * @return
+ * @throws DefinitionException
+ * @throws FHIRException
+ */
+ public char getDelimiterEscapeChar(char ch) throws DefinitionException {
+ if (ch == 'E')
+ return escapeCharacter;
+ else if (ch == 'F')
+ return fieldDelimiter;
+ else if (ch == 'S')
+ return componentDelimiter;
+ else if (ch == 'T')
+ return subComponentDelimiter;
+ else if (ch == 'R')
+ return repetitionDelimiter;
+ else
+ throw new DefinitionException("internal error in getDelimiterEscapeChar");
+ }
+ }
+
+ public class VerticalBarParserReader {
+
+
+ private BufferedInputStream stream;
+ private String charsetName;
+ private InputStreamReader reader = null;
+ private boolean finished;
+ private char peeked;
+ private char lastValue;
+ private int offset;
+ private int lineNumber;
+
+ public VerticalBarParserReader(BufferedInputStream stream, String charsetName) throws FHIRException {
+ super();
+ setStream(stream);
+ setCharsetName(charsetName);
+ open();
+ }
+
+ public String getCharsetName() {
+ return charsetName;
+ }
+
+ public void setCharsetName(String charsetName) {
+ this.charsetName = charsetName;
+ }
+
+ public BufferedInputStream getStream() {
+ return stream;
+ }
+
+ public void setStream(BufferedInputStream stream) {
+ this.stream = stream;
+ }
+
+ private void open() throws FHIRException {
+ try {
+ stream.mark(2048);
+ reader = new InputStreamReader(stream, charsetName);
+ offset = 0;
+ lineNumber = 0;
+ lastValue = ' ';
+ next();
+ } catch (Exception e) {
+ throw new FHIRException(e);
+ }
+ }
+
+ private void next() throws IOException, FHIRException {
+ finished = !reader.ready();
+ if (!finished) {
+ char[] temp = new char[1];
+ rule(reader.read(temp, 0, 1) == 1, "unable to read 1 character from the stream");
+ peeked = temp[0];
+ }
+ }
+
+ public String read(int charCount) throws FHIRException {
+ String value = "";
+ for (int i = 0; i < charCount; i++)
+ value = value + read();
+ return value;
+ }
+
+ public void skipEOL () throws FHIRException {
+ while (!finished && (peek() == '\r' || peek() == '\n'))
+ read();
+ }
+
+ public char read () throws FHIRException {
+ rule(!finished, "No more content to read");
+ char value = peek();
+ offset++;
+ if (value == '\r' || value == '\n') {
+ if (lastValue != '\r' || value != '\n')
+ lineNumber++;
+ }
+ lastValue = value;
+ try {
+ next();
+ } catch (Exception e) {
+ throw new FHIRException(e);
+ }
+ return value;
+ }
+
+ public boolean isFinished () {
+ return finished;
+ }
+
+ public char peek() throws FHIRException {
+ rule(!finished, "Cannot peek");
+ return peeked;
+ }
+
+ public void mark() {
+ stream.mark(2048);
+ }
+
+ public void reset() throws FHIRException {
+ try {
+ stream.reset();
+ } catch (IOException e) {
+ throw new FHIRException(e);
+ }
+ open();
+ }
+
+ public boolean IsEOL() throws FHIRException {
+ return peek() == '\r' || peek() == '\n';
+ }
+
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ }
+
+ public VerticalBarParser(IWorkerContext context) {
+ super(context);
+ }
+
+ private String charset = "ASCII";
+ private Delimiters delimiters = new Delimiters();
+
+ @Override
+ public Element parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException {
+ StructureDefinition sd = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/v2/StructureDefinition/Message");
+ Element message = new Element("Message", new Property(context, sd.getSnapshot().getElementFirstRep(), sd));
+ VerticalBarParserReader reader = new VerticalBarParserReader(new BufferedInputStream(stream), charset);
+
+ preDecode(reader);
+ while (!reader.isFinished()) // && (getOptions().getSegmentLimit() == 0 || getOptions().getSegmentLimit() > message.getSegments().size()))
+ readSegment(message, reader);
+
+ return message;
+ }
+
+ private void preDecode(VerticalBarParserReader reader) throws FHIRException {
+ reader.skipEOL();
+ String temp = reader.read(3);
+ rule(temp.equals("MSH") || temp.equals("FHS"), "Found '" + temp + "' looking for 'MSH' or 'FHS'");
+ readDelimiters(reader);
+ // readVersion(message); - probably don't need to do that?
+ // readCharacterSet();
+ reader.reset(); // ready to read message now
+ }
+
+ private void rule(boolean test, String msg) throws FHIRException {
+ if (!test)
+ throw new FHIRException(msg);
+ }
+
+ private void readDelimiters(VerticalBarParserReader reader) throws FHIRException {
+ delimiters.setFieldDelimiter(reader.read());
+ if (!(reader.peek() == delimiters.getFieldDelimiter()))
+ delimiters.setComponentDelimiter(reader.read());
+ if (!(reader.peek() == delimiters.getFieldDelimiter()))
+ delimiters.setRepetitionDelimiter(reader.read());
+ if (!(reader.peek() == delimiters.getFieldDelimiter()))
+ delimiters.setEscapeCharacter(reader.read());
+ if (!(reader.peek() == delimiters.getFieldDelimiter()))
+ delimiters.setSubComponentDelimiter(reader.read());
+ delimiters.check();
+ }
+
+ private void readSegment(Element message, VerticalBarParserReader reader) throws FHIRException {
+ Element segment = new Element("segment", message.getProperty().getChild("segment"));
+ message.getChildren().add(segment);
+ Element segmentCode = new Element("code", segment.getProperty().getChild("code"));
+ segment.getChildren().add(segmentCode);
+ segmentCode.setValue(reader.read(3));
+
+ int index = 0;
+ while (!reader.isFinished() && !reader.IsEOL()) {
+ index++;
+ readField(reader, segment, index);
+ if (!reader.isFinished() && !reader.IsEOL())
+ rule(reader.read() == delimiters.getFieldDelimiter(), "Expected to find field delimiter");
+ }
+ if (!reader.isFinished())
+ reader.skipEOL();
+ }
+
+
+
+ private void readField(VerticalBarParserReader reader, Element segment, int index) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void compose(Element e, OutputStream destination, OutputStyle style, String base) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/ClientR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/ClientR4Test.java
index 97ee6c306e1..60c788985dd 100644
--- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/ClientR4Test.java
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/ClientR4Test.java
@@ -1,21 +1,35 @@
package ca.uhn.fhir.rest.client;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.io.InputStream;
-import java.io.StringReader;
-import java.net.URLEncoder;
-import java.nio.charset.Charset;
-import java.util.*;
-
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.model.api.Include;
+import ca.uhn.fhir.model.api.annotation.ResourceDef;
+import ca.uhn.fhir.rest.annotation.*;
+import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.rest.api.EncodingEnum;
+import ca.uhn.fhir.rest.api.MethodOutcome;
+import ca.uhn.fhir.rest.api.SummaryEnum;
+import ca.uhn.fhir.rest.client.apache.ApacheHttpRequest;
+import ca.uhn.fhir.rest.client.api.IBasicClient;
+import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
+import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
+import ca.uhn.fhir.rest.param.*;
+import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
+import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
+import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
+import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
+import ca.uhn.fhir.util.TestUtil;
+import ca.uhn.fhir.util.UrlUtil;
+import com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.ReaderInputStream;
-import org.apache.http.*;
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.ProtocolVersion;
import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.*;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicStatusLine;
import org.hamcrest.core.StringContains;
@@ -23,29 +37,23 @@ import org.hamcrest.core.StringEndsWith;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
-import org.junit.*;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
-import com.google.common.base.Charsets;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.nio.charset.Charset;
+import java.util.*;
-import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.model.api.Include;
-import ca.uhn.fhir.model.api.annotation.ResourceDef;
-import ca.uhn.fhir.model.base.resource.BaseConformance;
-import ca.uhn.fhir.rest.annotation.*;
-import ca.uhn.fhir.rest.api.*;
-import ca.uhn.fhir.rest.api.Constants;
-import ca.uhn.fhir.rest.client.apache.ApacheHttpRequest;
-import ca.uhn.fhir.rest.client.api.IBasicClient;
-import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
-import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
-import ca.uhn.fhir.rest.param.*;
-import ca.uhn.fhir.rest.server.exceptions.*;
-import ca.uhn.fhir.util.TestUtil;
-import ca.uhn.fhir.util.UrlUtil;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class ClientR4Test {
@@ -569,7 +577,7 @@ public class ClientR4Test {
DateParam date = new DateParam("2001-01-01");
client.getObservationByNameValueDate(new CompositeParam(str, date));
- assertEquals("http://foo/Observation?" + Observation.SP_CODE_VALUE_DATE + "=" + URLEncoder.encode("FOO\\$BAR$2001-01-01", "UTF-8"), capt.getValue().getURI().toString());
+ assertEquals("http://foo/Observation?" + Observation.SP_CODE_VALUE_DATE + "=" + UrlUtil.escapeUrlParam("FOO\\$BAR$2001-01-01"), capt.getValue().getURI().toString());
}
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java
index 34579616a06..1565d6f4fcb 100644
--- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java
@@ -1,45 +1,6 @@
package ca.uhn.fhir.rest.client;
-import static org.hamcrest.Matchers.containsString;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.io.*;
-import java.net.URLEncoder;
-import java.nio.charset.Charset;
-import java.util.*;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.input.ReaderInputStream;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.http.*;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.entity.UrlEncodedFormEntity;
-import org.apache.http.client.methods.*;
-import org.apache.http.message.BasicHeader;
-import org.apache.http.message.BasicStatusLine;
-import org.hamcrest.Matchers;
-import org.hamcrest.core.StringContains;
-import org.hl7.fhir.instance.model.api.IBaseResource;
-import org.hl7.fhir.r4.model.*;
-import org.hl7.fhir.r4.model.Bundle.BundleType;
-import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
-import org.junit.*;
-import org.mockito.ArgumentCaptor;
-import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.model.api.*;
-import ca.uhn.fhir.model.primitive.InstantDt;
-import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.client.api.IGenericClient;
@@ -49,7 +10,43 @@ import ca.uhn.fhir.rest.client.impl.BaseClient;
import ca.uhn.fhir.rest.client.impl.GenericClient;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
-import ca.uhn.fhir.util.*;
+import ca.uhn.fhir.util.BundleUtil;
+import ca.uhn.fhir.util.TestUtil;
+import ca.uhn.fhir.util.UrlUtil;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.input.ReaderInputStream;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.message.BasicStatusLine;
+import org.hamcrest.Matchers;
+import org.hamcrest.core.StringContains;
+import org.hl7.fhir.r4.model.*;
+import org.hl7.fhir.r4.model.Bundle.BundleType;
+import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
+import org.junit.*;
+import org.mockito.ArgumentCaptor;
+import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.nio.charset.Charset;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class GenericClientTest {
@@ -782,7 +779,7 @@ public class GenericClientTest {
.returnBundle(Bundle.class)
.execute();
- assertEquals("http://foo/Observation?" + Observation.SP_CODE_VALUE_DATE + "=" + URLEncoder.encode("FOO\\$BAR$2001-01-01", "UTF-8"), capt.getValue().getURI().toString());
+ assertEquals("http://foo/Observation?" + Observation.SP_CODE_VALUE_DATE + "=" + UrlUtil.escapeUrlParam("FOO\\$BAR$2001-01-01"), capt.getValue().getURI().toString());
}
@@ -1025,7 +1022,7 @@ public class GenericClientTest {
.returnBundle(Bundle.class)
.execute();
- assertEquals("http://example.com/fhir/Patient?name=" + URLEncoder.encode("AAA,BBB,C\\,C", "UTF-8"), capt.getAllValues().get(1).getURI().toString());
+ assertEquals("http://example.com/fhir/Patient?name=" + UrlUtil.escapeUrlParam("AAA,BBB,C\\,C"), capt.getAllValues().get(1).getURI().toString());
}
@@ -1116,7 +1113,7 @@ public class GenericClientTest {
.returnBundle(Bundle.class)
.execute();
- assertEquals("http://example.com/fhir/Patient?identifier=" + URLEncoder.encode("A|B,C|D", "UTF-8"), capt.getAllValues().get(2).getURI().toString());
+ assertEquals("http://example.com/fhir/Patient?identifier=" + UrlUtil.escapeUrlParam("A|B,C|D"), capt.getAllValues().get(2).getURI().toString());
}
@@ -1152,7 +1149,7 @@ public class GenericClientTest {
String url = capt.getAllValues().get(index).getURI().toString();
assertThat(url, Matchers.startsWith(wantPrefix));
assertEquals(wantValue, UrlUtil.unescape(url.substring(wantPrefix.length())));
- assertEquals(UrlUtil.escape(wantValue), url.substring(wantPrefix.length()));
+ assertEquals(UrlUtil.escapeUrlParam(wantValue), url.substring(wantPrefix.length()));
index++;
response = client.search()
@@ -1164,7 +1161,7 @@ public class GenericClientTest {
url = capt.getAllValues().get(index).getURI().toString();
assertThat(url, Matchers.startsWith(wantPrefix));
assertEquals(wantValue, UrlUtil.unescape(url.substring(wantPrefix.length())));
- assertEquals(UrlUtil.escape(wantValue), url.substring(wantPrefix.length()));
+ assertEquals(UrlUtil.escapeUrlParam(wantValue), url.substring(wantPrefix.length()));
index++;
}
@@ -1234,8 +1231,8 @@ public class GenericClientTest {
.execute();
assertThat(capt.getValue().getURI().toString(), containsString("http://example.com/fhir/Patient?"));
- assertThat(capt.getValue().getURI().toString(), containsString("_include=" + UrlUtil.escape(Patient.INCLUDE_ORGANIZATION.getValue())));
- assertThat(capt.getValue().getURI().toString(), containsString("_include%3Arecurse=" + UrlUtil.escape(Patient.INCLUDE_LINK.getValue())));
+ assertThat(capt.getValue().getURI().toString(), containsString("_include=" + UrlUtil.escapeUrlParam(Patient.INCLUDE_ORGANIZATION.getValue())));
+ assertThat(capt.getValue().getURI().toString(), containsString("_include%3Arecurse=" + UrlUtil.escapeUrlParam(Patient.INCLUDE_LINK.getValue())));
assertThat(capt.getValue().getURI().toString(), containsString("_include=*"));
}
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/GraphQLR4ProviderTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/GraphQLR4ProviderTest.java
index 973835eb88f..ba8ff1d8796 100644
--- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/GraphQLR4ProviderTest.java
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/GraphQLR4ProviderTest.java
@@ -54,7 +54,7 @@ public class GraphQLR4ProviderTest {
@Test
public void testGraphInstance() throws Exception {
String query = "{name{family,given}}";
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escape(query));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@@ -80,7 +80,7 @@ public class GraphQLR4ProviderTest {
@Test
public void testGraphInstanceWithFhirpath() throws Exception {
String query = "{name(fhirpath:\"family.exists()\"){text,given,family}}";
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escape(query));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@@ -104,7 +104,7 @@ public class GraphQLR4ProviderTest {
@Test
public void testGraphSystemInstance() throws Exception {
String query = "{Patient(id:123){id,name{given,family}}}";
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escape(query));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@@ -132,7 +132,7 @@ public class GraphQLR4ProviderTest {
@Test
public void testGraphSystemList() throws Exception {
String query = "{PatientList(name:\"pet\"){name{family,given}}}";
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escape(query));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/GraphQLR4RawTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/GraphQLR4RawTest.java
index 372ee9d626e..1d3a9785efe 100644
--- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/GraphQLR4RawTest.java
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/GraphQLR4RawTest.java
@@ -91,7 +91,7 @@ public class GraphQLR4RawTest {
ourNextRetVal = "{\"foo\"}";
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escape("{name{family,given}}"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam("{name{family,given}}"));
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@@ -114,7 +114,7 @@ public class GraphQLR4RawTest {
ourNextRetVal = "{\"foo\"}";
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Condition/123/$graphql?query=" + UrlUtil.escape("{name{family,given}}"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Condition/123/$graphql?query=" + UrlUtil.escapeUrlParam("{name{family,given}}"));
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@@ -132,7 +132,7 @@ public class GraphQLR4RawTest {
ourNextRetVal = "{\"foo\"}";
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escape("{name{family,given}}"));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam("{name{family,given}}"));
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/SearchR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/SearchR4Test.java
index 86f43d9114c..73d0a03d23d 100644
--- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/SearchR4Test.java
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/SearchR4Test.java
@@ -131,25 +131,25 @@ public class SearchR4Test {
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=" + Constants.CT_FHIR_JSON_NEW);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW)));
+ assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
// Fetch the next page
httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW)));
+ assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
// Fetch the next page
httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW)));
+ assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
// Fetch the next page
httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW)));
+ assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
}
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/SearchSearchServerDstu1Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/SearchSearchServerDstu1Test.java
index 7ac6de97773..840cb4d2de7 100644
--- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/SearchSearchServerDstu1Test.java
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/SearchSearchServerDstu1Test.java
@@ -1,6 +1,6 @@
package ca.uhn.fhir.rest.server;
-import static ca.uhn.fhir.util.UrlUtil.escape;
+import static ca.uhn.fhir.util.UrlUtil.escapeUrlParam;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
@@ -110,10 +110,10 @@ public class SearchSearchServerDstu1Test {
b.append("http://localhost:");
b.append(ourPort);
b.append("/Patient?");
- b.append(escape("findPatientWithAndList")).append('=').append(escape("NE\\,NE,NE\\,NE")).append('&');
- b.append(escape("findPatientWithAndList")).append('=').append(escape("NE\\\\NE")).append('&');
- b.append(escape("findPatientWithAndList:exact")).append('=').append(escape("E\\$E")).append('&');
- b.append(escape("findPatientWithAndList:exact")).append('=').append(escape("E\\|E")).append('&');
+ b.append(escapeUrlParam("findPatientWithAndList")).append('=').append(escapeUrlParam("NE\\,NE,NE\\,NE")).append('&');
+ b.append(escapeUrlParam("findPatientWithAndList")).append('=').append(escapeUrlParam("NE\\\\NE")).append('&');
+ b.append(escapeUrlParam("findPatientWithAndList:exact")).append('=').append(escapeUrlParam("E\\$E")).append('&');
+ b.append(escapeUrlParam("findPatientWithAndList:exact")).append('=').append(escapeUrlParam("E\\|E")).append('&');
HttpGet httpGet = new HttpGet(b.toString());
@@ -416,7 +416,7 @@ public class SearchSearchServerDstu1Test {
@Test
public void testSearchWithTokenParameter() throws Exception {
- String token = UrlUtil.escape("http://www.dmix.gov/vista/2957|301");
+ String token = UrlUtil.escapeUrlParam("http://www.dmix.gov/vista/2957|301");
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?tokenParam=" + token);
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
diff --git a/hapi-fhir-utilities/src/main/java/org/hl7/fhir/utilities/xml/XMLUtil.java b/hapi-fhir-utilities/src/main/java/org/hl7/fhir/utilities/xml/XMLUtil.java
index 5c8c2106963..4ceae56abd1 100644
--- a/hapi-fhir-utilities/src/main/java/org/hl7/fhir/utilities/xml/XMLUtil.java
+++ b/hapi-fhir-utilities/src/main/java/org/hl7/fhir/utilities/xml/XMLUtil.java
@@ -1,472 +1,472 @@
-/*
-Copyright (c) 2011+, HL7, Inc
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of HL7 nor the names of its contributors may be used to
- endorse or promote products derived from this software without specific
- prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
-INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
-*/
-package org.hl7.fhir.utilities.xml;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.List;
-import java.util.Set;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-
-import org.hl7.fhir.exceptions.FHIRException;
-import org.hl7.fhir.utilities.Utilities;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.ls.DOMImplementationLS;
-import org.w3c.dom.ls.LSSerializer;
-import org.xml.sax.SAXException;
-
-public class XMLUtil {
-
- public static final String SPACE_CHAR = "\u00A0";
-
- public static boolean isNMToken(String name) {
- if (name == null)
- return false;
- for (int i = 0; i < name.length(); i++)
- if (!isNMTokenChar(name.charAt(i)))
- return false;
- return name.length() > 0;
- }
-
- public static boolean isNMTokenChar(char c) {
- return isLetter(c) || isDigit(c) || c == '.' || c == '-' || c == '_' || c == ':' || isCombiningChar(c) || isExtender(c);
- }
-
- private static boolean isDigit(char c) {
- return (c >= '\u0030' && c <= '\u0039') || (c >= '\u0660' && c <= '\u0669') || (c >= '\u06F0' && c <= '\u06F9') ||
- (c >= '\u0966' && c <= '\u096F') || (c >= '\u09E6' && c <= '\u09EF') || (c >= '\u0A66' && c <= '\u0A6F') ||
- (c >= '\u0AE6' && c <= '\u0AEF') || (c >= '\u0B66' && c <= '\u0B6F') || (c >= '\u0BE7' && c <= '\u0BEF') ||
- (c >= '\u0C66' && c <= '\u0C6F') || (c >= '\u0CE6' && c <= '\u0CEF') || (c >= '\u0D66' && c <= '\u0D6F') ||
- (c >= '\u0E50' && c <= '\u0E59') || (c >= '\u0ED0' && c <= '\u0ED9') || (c >= '\u0F20' && c <= '\u0F29');
- }
-
- private static boolean isCombiningChar(char c) {
- return (c >= '\u0300' && c <= '\u0345') || (c >= '\u0360' && c <= '\u0361') || (c >= '\u0483' && c <= '\u0486') ||
- (c >= '\u0591' && c <= '\u05A1') || (c >= '\u05A3' && c <= '\u05B9') || (c >= '\u05BB' && c <= '\u05BD') ||
- c == '\u05BF' || (c >= '\u05C1' && c <= '\u05C2') || c == '\u05C4' || (c >= '\u064B' && c <= '\u0652') ||
- c == '\u0670' || (c >= '\u06D6' && c <= '\u06DC') || (c >= '\u06DD' && c <= '\u06DF') || (c >= '\u06E0' && c <= '\u06E4') ||
- (c >= '\u06E7' && c <= '\u06E8') || (c >= '\u06EA' && c <= '\u06ED') || (c >= '\u0901' && c <= '\u0903') || c == '\u093C' ||
- (c >= '\u093E' && c <= '\u094C') || c == '\u094D' || (c >= '\u0951' && c <= '\u0954') || (c >= '\u0962' && c <= '\u0963') ||
- (c >= '\u0981' && c <= '\u0983') || c == '\u09BC' || c == '\u09BE' || c == '\u09BF' || (c >= '\u09C0' && c <= '\u09C4') ||
- (c >= '\u09C7' && c <= '\u09C8') || (c >= '\u09CB' && c <= '\u09CD') || c == '\u09D7' || (c >= '\u09E2' && c <= '\u09E3') ||
- c == '\u0A02' || c == '\u0A3C' || c == '\u0A3E' || c == '\u0A3F' || (c >= '\u0A40' && c <= '\u0A42') ||
- (c >= '\u0A47' && c <= '\u0A48') || (c >= '\u0A4B' && c <= '\u0A4D') || (c >= '\u0A70' && c <= '\u0A71') ||
- (c >= '\u0A81' && c <= '\u0A83') || c == '\u0ABC' || (c >= '\u0ABE' && c <= '\u0AC5') || (c >= '\u0AC7' && c <= '\u0AC9') ||
- (c >= '\u0ACB' && c <= '\u0ACD') || (c >= '\u0B01' && c <= '\u0B03') || c == '\u0B3C' || (c >= '\u0B3E' && c <= '\u0B43') ||
- (c >= '\u0B47' && c <= '\u0B48') || (c >= '\u0B4B' && c <= '\u0B4D') || (c >= '\u0B56' && c <= '\u0B57') ||
- (c >= '\u0B82' && c <= '\u0B83') || (c >= '\u0BBE' && c <= '\u0BC2') || (c >= '\u0BC6' && c <= '\u0BC8') ||
- (c >= '\u0BCA' && c <= '\u0BCD') || c == '\u0BD7' || (c >= '\u0C01' && c <= '\u0C03') || (c >= '\u0C3E' && c <= '\u0C44') ||
- (c >= '\u0C46' && c <= '\u0C48') || (c >= '\u0C4A' && c <= '\u0C4D') || (c >= '\u0C55' && c <= '\u0C56') ||
- (c >= '\u0C82' && c <= '\u0C83') || (c >= '\u0CBE' && c <= '\u0CC4') || (c >= '\u0CC6' && c <= '\u0CC8') ||
- (c >= '\u0CCA' && c <= '\u0CCD') || (c >= '\u0CD5' && c <= '\u0CD6') || (c >= '\u0D02' && c <= '\u0D03') ||
- (c >= '\u0D3E' && c <= '\u0D43') || (c >= '\u0D46' && c <= '\u0D48') || (c >= '\u0D4A' && c <= '\u0D4D') || c == '\u0D57' ||
- c == '\u0E31' || (c >= '\u0E34' && c <= '\u0E3A') || (c >= '\u0E47' && c <= '\u0E4E') || c == '\u0EB1' ||
- (c >= '\u0EB4' && c <= '\u0EB9') || (c >= '\u0EBB' && c <= '\u0EBC') || (c >= '\u0EC8' && c <= '\u0ECD') ||
- (c >= '\u0F18' && c <= '\u0F19') || c == '\u0F35' || c == '\u0F37' || c == '\u0F39' || c == '\u0F3E' || c == '\u0F3F' ||
- (c >= '\u0F71' && c <= '\u0F84') || (c >= '\u0F86' && c <= '\u0F8B') || (c >= '\u0F90' && c <= '\u0F95') || c == '\u0F97' ||
- (c >= '\u0F99' && c <= '\u0FAD') || (c >= '\u0FB1' && c <= '\u0FB7') || c == '\u0FB9' || (c >= '\u20D0' && c <= '\u20DC') ||
- c == '\u20E1' || (c >= '\u302A' && c <= '\u302F') || c == '\u3099' || c == '\u309A';
- }
-
- private static boolean isExtender(char c) {
- return c == '\u00B7' || c == '\u02D0' || c == '\u02D1' || c == '\u0387' || c == '\u0640' || c == '\u0E46' ||
- c == '\u0EC6' || c == '\u3005' || (c >= '\u3031' && c <= '\u3035') || (c >= '\u309D' && c <= '\u309E') ||
- (c >= '\u30FC' && c <= '\u30FE');
- }
-
- private static boolean isLetter(char c) {
- return isBaseChar(c) || isIdeographic(c);
- }
-
- private static boolean isBaseChar(char c) {
- return (c >= '\u0041' && c <= '\u005A') || (c >= '\u0061' && c <= '\u007A') || (c >= '\u00C0' && c <= '\u00D6') ||
- (c >= '\u00D8' && c <= '\u00F6') || (c >= '\u00F8' && c <= '\u00FF') || (c >= '\u0100' && c <= '\u0131') ||
- (c >= '\u0134' && c <= '\u013E') || (c >= '\u0141' && c <= '\u0148') || (c >= '\u014A' && c <= '\u017E') ||
- (c >= '\u0180' && c <= '\u01C3') || (c >= '\u01CD' && c <= '\u01F0') || (c >= '\u01F4' && c <= '\u01F5') ||
- (c >= '\u01FA' && c <= '\u0217') || (c >= '\u0250' && c <= '\u02A8') || (c >= '\u02BB' && c <= '\u02C1') ||
- c == '\u0386' || (c >= '\u0388' && c <= '\u038A') || c == '\u038C' || (c >= '\u038E' && c <= '\u03A1') ||
- (c >= '\u03A3' && c <= '\u03CE') || (c >= '\u03D0' && c <= '\u03D6') || c == '\u03DA' || c == '\u03DC' || c == '\u03DE' ||
- c == '\u03E0' || (c >= '\u03E2' && c <= '\u03F3') || (c >= '\u0401' && c <= '\u040C') || (c >= '\u040E' && c <= '\u044F') ||
- (c >= '\u0451' && c <= '\u045C') || (c >= '\u045E' && c <= '\u0481') || (c >= '\u0490' && c <= '\u04C4') ||
- (c >= '\u04C7' && c <= '\u04C8') || (c >= '\u04CB' && c <= '\u04CC') || (c >= '\u04D0' && c <= '\u04EB') ||
- (c >= '\u04EE' && c <= '\u04F5') || (c >= '\u04F8' && c <= '\u04F9') || (c >= '\u0531' && c <= '\u0556') ||
- c == '\u0559' || (c >= '\u0561' && c <= '\u0586') || (c >= '\u05D0' && c <= '\u05EA') || (c >= '\u05F0' && c <= '\u05F2') ||
- (c >= '\u0621' && c <= '\u063A') || (c >= '\u0641' && c <= '\u064A') || (c >= '\u0671' && c <= '\u06B7') ||
- (c >= '\u06BA' && c <= '\u06BE') || (c >= '\u06C0' && c <= '\u06CE') || (c >= '\u06D0' && c <= '\u06D3') ||
- c == '\u06D5' || (c >= '\u06E5' && c <= '\u06E6') || (c >= '\u0905' && c <= '\u0939') || c == '\u093D' ||
- (c >= '\u0958' && c <= '\u0961') || (c >= '\u0985' && c <= '\u098C') || (c >= '\u098F' && c <= '\u0990') ||
- (c >= '\u0993' && c <= '\u09A8') || (c >= '\u09AA' && c <= '\u09B0') || c == '\u09B2' ||
- (c >= '\u09B6' && c <= '\u09B9') || (c >= '\u09DC' && c <= '\u09DD') || (c >= '\u09DF' && c <= '\u09E1') ||
- (c >= '\u09F0' && c <= '\u09F1') || (c >= '\u0A05' && c <= '\u0A0A') || (c >= '\u0A0F' && c <= '\u0A10') ||
- (c >= '\u0A13' && c <= '\u0A28') || (c >= '\u0A2A' && c <= '\u0A30') || (c >= '\u0A32' && c <= '\u0A33') ||
- (c >= '\u0A35' && c <= '\u0A36') || (c >= '\u0A38' && c <= '\u0A39') || (c >= '\u0A59' && c <= '\u0A5C') ||
- c == '\u0A5E' || (c >= '\u0A72' && c <= '\u0A74') || (c >= '\u0A85' && c <= '\u0A8B') || c == '\u0A8D' ||
- (c >= '\u0A8F' && c <= '\u0A91') || (c >= '\u0A93' && c <= '\u0AA8') || (c >= '\u0AAA' && c <= '\u0AB0') ||
- (c >= '\u0AB2' && c <= '\u0AB3') || (c >= '\u0AB5' && c <= '\u0AB9') || c == '\u0ABD' || c == '\u0AE0' ||
- (c >= '\u0B05' && c <= '\u0B0C') || (c >= '\u0B0F' && c <= '\u0B10') || (c >= '\u0B13' && c <= '\u0B28') ||
- (c >= '\u0B2A' && c <= '\u0B30') || (c >= '\u0B32' && c <= '\u0B33') || (c >= '\u0B36' && c <= '\u0B39') ||
- c == '\u0B3D' || (c >= '\u0B5C' && c <= '\u0B5D') || (c >= '\u0B5F' && c <= '\u0B61') ||
- (c >= '\u0B85' && c <= '\u0B8A') || (c >= '\u0B8E' && c <= '\u0B90') || (c >= '\u0B92' && c <= '\u0B95') ||
- (c >= '\u0B99' && c <= '\u0B9A') || c == '\u0B9C' || (c >= '\u0B9E' && c <= '\u0B9F') ||
- (c >= '\u0BA3' && c <= '\u0BA4') || (c >= '\u0BA8' && c <= '\u0BAA') || (c >= '\u0BAE' && c <= '\u0BB5') ||
- (c >= '\u0BB7' && c <= '\u0BB9') || (c >= '\u0C05' && c <= '\u0C0C') || (c >= '\u0C0E' && c <= '\u0C10') ||
- (c >= '\u0C12' && c <= '\u0C28') || (c >= '\u0C2A' && c <= '\u0C33') || (c >= '\u0C35' && c <= '\u0C39') ||
- (c >= '\u0C60' && c <= '\u0C61') || (c >= '\u0C85' && c <= '\u0C8C') || (c >= '\u0C8E' && c <= '\u0C90') ||
- (c >= '\u0C92' && c <= '\u0CA8') || (c >= '\u0CAA' && c <= '\u0CB3') || (c >= '\u0CB5' && c <= '\u0CB9') ||
- c == '\u0CDE' || (c >= '\u0CE0' && c <= '\u0CE1') || (c >= '\u0D05' && c <= '\u0D0C') ||
- (c >= '\u0D0E' && c <= '\u0D10') || (c >= '\u0D12' && c <= '\u0D28') || (c >= '\u0D2A' && c <= '\u0D39') ||
- (c >= '\u0D60' && c <= '\u0D61') || (c >= '\u0E01' && c <= '\u0E2E') || c == '\u0E30' ||
- (c >= '\u0E32' && c <= '\u0E33') || (c >= '\u0E40' && c <= '\u0E45') || (c >= '\u0E81' && c <= '\u0E82') ||
- c == '\u0E84' || (c >= '\u0E87' && c <= '\u0E88') || c == '\u0E8A' || c == '\u0E8D' || (c >= '\u0E94' && c <= '\u0E97') ||
- (c >= '\u0E99' && c <= '\u0E9F') || (c >= '\u0EA1' && c <= '\u0EA3') || c == '\u0EA5' || c == '\u0EA7' ||
- (c >= '\u0EAA' && c <= '\u0EAB') || (c >= '\u0EAD' && c <= '\u0EAE') || c == '\u0EB0' ||
- (c >= '\u0EB2' && c <= '\u0EB3') || c == '\u0EBD' || (c >= '\u0EC0' && c <= '\u0EC4') ||
- (c >= '\u0F40' && c <= '\u0F47') || (c >= '\u0F49' && c <= '\u0F69') || (c >= '\u10A0' && c <= '\u10C5') ||
- (c >= '\u10D0' && c <= '\u10F6') || c == '\u1100' || (c >= '\u1102' && c <= '\u1103') ||
- (c >= '\u1105' && c <= '\u1107') || c == '\u1109' || (c >= '\u110B' && c <= '\u110C') ||
- (c >= '\u110E' && c <= '\u1112') || c == '\u113C' || c == '\u113E' || c == '\u1140' || c == '\u114C' ||
- c == '\u114E' || c == '\u1150' || (c >= '\u1154' && c <= '\u1155') || c == '\u1159' ||
- (c >= '\u115F' && c <= '\u1161') || c == '\u1163' || c == '\u1165' || c == '\u1167' || c == '\u1169' ||
- (c >= '\u116D' && c <= '\u116E') || (c >= '\u1172' && c <= '\u1173') || c == '\u1175' ||
- c == '\u119E' || c == '\u11A8' || c == '\u11AB' || (c >= '\u11AE' && c <= '\u11AF') ||
- (c >= '\u11B7' && c <= '\u11B8') || c == '\u11BA' || (c >= '\u11BC' && c <= '\u11C2') ||
- c == '\u11EB' || c == '\u11F0' || c == '\u11F9' || (c >= '\u1E00' && c <= '\u1E9B') || (c >= '\u1EA0' && c <= '\u1EF9') ||
- (c >= '\u1F00' && c <= '\u1F15') || (c >= '\u1F18' && c <= '\u1F1D') || (c >= '\u1F20' && c <= '\u1F45') ||
- (c >= '\u1F48' && c <= '\u1F4D') || (c >= '\u1F50' && c <= '\u1F57') || c == '\u1F59' || c == '\u1F5B' || c == '\u1F5D' ||
- (c >= '\u1F5F' && c <= '\u1F7D') || (c >= '\u1F80' && c <= '\u1FB4') || (c >= '\u1FB6' && c <= '\u1FBC') ||
- c == '\u1FBE' || (c >= '\u1FC2' && c <= '\u1FC4') || (c >= '\u1FC6' && c <= '\u1FCC') ||
- (c >= '\u1FD0' && c <= '\u1FD3') || (c >= '\u1FD6' && c <= '\u1FDB') || (c >= '\u1FE0' && c <= '\u1FEC') ||
- (c >= '\u1FF2' && c <= '\u1FF4') || (c >= '\u1FF6' && c <= '\u1FFC') || c == '\u2126' ||
- (c >= '\u212A' && c <= '\u212B') || c == '\u212E' || (c >= '\u2180' && c <= '\u2182') ||
- (c >= '\u3041' && c <= '\u3094') || (c >= '\u30A1' && c <= '\u30FA') || (c >= '\u3105' && c <= '\u312C') ||
- (c >= '\uAC00' && c <= '\uD7A3');
- }
-
- private static boolean isIdeographic(char c) {
- return (c >= '\u4E00' && c <= '\u9FA5') || c == '\u3007' || (c >= '\u3021' && c <= '\u3029');
- }
-
- public static String determineEncoding(InputStream stream) throws IOException {
- stream.mark(20000);
- try {
- int b0 = stream.read();
- int b1 = stream.read();
- int b2 = stream.read();
- int b3 = stream.read();
-
- if (b0 == 0xFE && b1 == 0xFF)
- return "UTF-16BE";
- else if (b0 == 0xFF && b1 == 0xFE)
- return "UTF-16LE";
- else if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF )
- return "UTF-8";
- else if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F)
- return "UTF-16BE";
- else if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00)
- return "UTF-16LE";
- else if (b0 == 0x3C && b1 == 0x3F && b2 == 0x78 && b3 == 0x6D) {
-// UTF-8, ISO 646, ASCII, some part of ISO 8859, Shift-JIS, EUC, or any other 7-bit, 8-bit, or mixed-width encoding
-// which ensures that the characters of ASCII have their normal positions, width, and values; the actual encoding
-// declaration must be read to detect which of these applies, but since all of these encodings use the same bit patterns
-// for the relevant ASCII characters, the encoding declaration itself may be read reliably
- InputStreamReader rdr = new InputStreamReader(stream, "US-ASCII");
- String hdr = readFirstLine(rdr);
- return extractEncoding(hdr);
- } else
- return null;
- } finally {
- stream.reset();
- }
- }
-
- private static String extractEncoding(String hdr) {
- int i = hdr.indexOf("encoding=");
- if (i == -1)
- return null;
- hdr = hdr.substring(i+9);
- char sep = hdr.charAt(0);
- hdr = hdr.substring(1);
- i = hdr.indexOf(sep);
- if (i == -1)
- return null;
- return hdr.substring(0, i);
- }
-
- private static String readFirstLine(InputStreamReader rdr) throws IOException {
- char[] buf = new char[1];
- StringBuffer bldr = new StringBuffer();
- rdr.read(buf);
- while (buf[0] != '>') {
- bldr.append(buf[0]);
- rdr.read(buf);
- }
- return bldr.toString();
- }
-
-
- public static boolean charSetImpliesAscii(String charset) {
- return charset.equals("ISO-8859-1") || charset.equals("US-ASCII");
- }
-
-
- /**
- * Converts the raw characters to XML escape characters.
- *
- * @param rawContent
- * @param charset Null when charset is not known, so we assume it's unicode
- * @param isNoLines
- * @return escape string
- */
- public static String escapeXML(String rawContent, String charset, boolean isNoLines) {
- if (rawContent == null)
- return "";
- else {
- StringBuffer sb = new StringBuffer();
-
- for (int i = 0; i < rawContent.length(); i++) {
- char ch = rawContent.charAt(i);
- if (ch == '\'')
- sb.append("'");
- else if (ch == '&')
- sb.append("&");
- else if (ch == '"')
- sb.append(""");
- else if (ch == '<')
- sb.append("<");
- else if (ch == '>')
- sb.append(">");
- else if (ch > '~' && charset != null && charSetImpliesAscii(charset))
- // TODO - why is hashcode the only way to get the unicode number for the character
- // in jre 5.0?
- sb.append(""+Integer.toHexString(ch).toUpperCase()+";");
- else if (isNoLines) {
- if (ch == '\r')
- sb.append("
");
- else if (ch != '\n')
- sb.append(ch);
- }
- else
- sb.append(ch);
- }
- return sb.toString();
- }
- }
-
- public static Element getFirstChild(Element e) {
- if (e == null)
- return null;
- Node n = e.getFirstChild();
- while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
- n = n.getNextSibling();
- return (Element) n;
- }
-
- public static Element getNamedChild(Element e, String name) {
- Element c = getFirstChild(e);
- while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName()))
- c = getNextSibling(c);
- return c;
- }
-
- public static Element getNextSibling(Element e) {
- Node n = e.getNextSibling();
- while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
- n = n.getNextSibling();
- return (Element) n;
- }
-
- public static void getNamedChildren(Element e, String name, List set) {
- Element c = getFirstChild(e);
- while (c != null) {
- if (name.equals(c.getLocalName()) || name.equals(c.getNodeName()) )
- set.add(c);
- c = getNextSibling(c);
- }
- }
-
- public static String htmlToXmlEscapedPlainText(Element r) {
- StringBuilder s = new StringBuilder();
- Node n = r.getFirstChild();
- boolean ws = false;
- while (n != null) {
- if (n.getNodeType() == Node.TEXT_NODE) {
- String t = n.getTextContent().trim();
- if (Utilities.noString(t))
- ws = true;
- else {
- if (ws)
- s.append(" ");
- ws = false;
- s.append(t);
- }
- }
- if (n.getNodeType() == Node.ELEMENT_NODE) {
- if (ws)
- s.append(" ");
- ws = false;
- s.append(htmlToXmlEscapedPlainText((Element) n));
- if (r.getNodeName().equals("br") || r.getNodeName().equals("p"))
- s.append("\r\n");
- }
- n = n.getNextSibling();
- }
- return s.toString();
- }
-
- public static String htmlToXmlEscapedPlainText(String definition) throws ParserConfigurationException, SAXException, IOException {
- return htmlToXmlEscapedPlainText(parseToDom("
"+definition+"
").getDocumentElement());
- }
-
- public static String elementToString(Element el) {
- if (el == null)
- return "";
- Document document = el.getOwnerDocument();
- DOMImplementationLS domImplLS = (DOMImplementationLS) document
- .getImplementation();
- LSSerializer serializer = domImplLS.createLSSerializer();
- return serializer.writeToString(el);
- }
-
- public static String getNamedChildValue(Element element, String name) {
- Element e = getNamedChild(element, name);
- return e == null ? null : e.getAttribute("value");
- }
-
- public static void setNamedChildValue(Element element, String name, String value) throws FHIRException {
- Element e = getNamedChild(element, name);
- if (e == null)
- throw new FHIRException("unable to find element "+name);
- e.setAttribute("value", value);
- }
-
-
- public static void getNamedChildrenWithWildcard(Element focus, String name, List children) {
- Element c = getFirstChild(focus);
- while (c != null) {
- String n = c.getLocalName() != null ? c.getLocalName() : c.getNodeName();
- if (name.equals(n) || (name.endsWith("[x]") && n.startsWith(name.substring(0, name.length()-3))))
- children.add(c);
- c = getNextSibling(c);
- }
- }
-
- public static void getNamedChildrenWithTails(Element focus, String name, List children, Set typeTails) {
- Element c = getFirstChild(focus);
- while (c != null) {
- String n = c.getLocalName() != null ? c.getLocalName() : c.getNodeName();
- if (n.equals(name) || (!n.equals("responseCode") && (n.startsWith(name) && typeTails.contains(n.substring(name.length())))))
- children.add(c);
- c = getNextSibling(c);
- }
- }
-
- public static boolean hasNamedChild(Element e, String name) {
- Element c = getFirstChild(e);
- while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName()))
- c = getNextSibling(c);
- return c != null;
- }
-
- public static Document parseToDom(String content) throws ParserConfigurationException, SAXException, IOException {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(false);
- DocumentBuilder builder = factory.newDocumentBuilder();
- return builder.parse(new ByteArrayInputStream(content.getBytes()));
- }
-
- public static Document parseFileToDom(String filename) throws ParserConfigurationException, SAXException, IOException {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(false);
- DocumentBuilder builder = factory.newDocumentBuilder();
- return builder.parse(new FileInputStream(filename));
- }
-
- public static Element getLastChild(Element e) {
- if (e == null)
- return null;
- Node n = e.getLastChild();
- while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
- n = n.getPreviousSibling();
- return (Element) n;
- }
-
- public static Element getPrevSibling(Element e) {
- Node n = e.getPreviousSibling();
- while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
- n = n.getPreviousSibling();
- return (Element) n;
- }
-
- public static String getNamedChildAttribute(Element element, String name, String aname) {
- Element e = getNamedChild(element, name);
- return e == null ? null : e.getAttribute(aname);
- }
-
- public static void writeDomToFile(Document doc, String filename) throws TransformerException {
- TransformerFactory transformerFactory = TransformerFactory.newInstance();
- Transformer transformer = transformerFactory.newTransformer();
- DOMSource source = new DOMSource(doc);
- StreamResult streamResult = new StreamResult(new File(filename));
- transformer.transform(source, streamResult);
- }
-
- public static String getXsiType(org.w3c.dom.Element element) {
- Attr a = element.getAttributeNodeNS("http://www.w3.org/2001/XMLSchema-instance", "type");
- return (a == null ? null : a.getTextContent());
-
- }
-
- public static String getDirectText(org.w3c.dom.Element node) {
- Node n = node.getFirstChild();
- StringBuilder b = new StringBuilder();
- while (n != null) {
- if (n.getNodeType() == Node.TEXT_NODE)
- b.append(n.getTextContent());
- n = n.getNextSibling();
- }
- return b.toString().trim();
- }
-
-
-}
+/*
+Copyright (c) 2011+, HL7, Inc
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of HL7 nor the names of its contributors may be used to
+ endorse or promote products derived from this software without specific
+ prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+package org.hl7.fhir.utilities.xml;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+import java.util.Set;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.hl7.fhir.exceptions.FHIRException;
+import org.hl7.fhir.utilities.Utilities;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.ls.DOMImplementationLS;
+import org.w3c.dom.ls.LSSerializer;
+import org.xml.sax.SAXException;
+
+public class XMLUtil {
+
+ public static final String SPACE_CHAR = "\u00A0";
+
+ public static boolean isNMToken(String name) {
+ if (name == null)
+ return false;
+ for (int i = 0; i < name.length(); i++)
+ if (!isNMTokenChar(name.charAt(i)))
+ return false;
+ return name.length() > 0;
+ }
+
+ public static boolean isNMTokenChar(char c) {
+ return isLetter(c) || isDigit(c) || c == '.' || c == '-' || c == '_' || c == ':' || isCombiningChar(c) || isExtender(c);
+ }
+
+ private static boolean isDigit(char c) {
+ return (c >= '\u0030' && c <= '\u0039') || (c >= '\u0660' && c <= '\u0669') || (c >= '\u06F0' && c <= '\u06F9') ||
+ (c >= '\u0966' && c <= '\u096F') || (c >= '\u09E6' && c <= '\u09EF') || (c >= '\u0A66' && c <= '\u0A6F') ||
+ (c >= '\u0AE6' && c <= '\u0AEF') || (c >= '\u0B66' && c <= '\u0B6F') || (c >= '\u0BE7' && c <= '\u0BEF') ||
+ (c >= '\u0C66' && c <= '\u0C6F') || (c >= '\u0CE6' && c <= '\u0CEF') || (c >= '\u0D66' && c <= '\u0D6F') ||
+ (c >= '\u0E50' && c <= '\u0E59') || (c >= '\u0ED0' && c <= '\u0ED9') || (c >= '\u0F20' && c <= '\u0F29');
+ }
+
+ private static boolean isCombiningChar(char c) {
+ return (c >= '\u0300' && c <= '\u0345') || (c >= '\u0360' && c <= '\u0361') || (c >= '\u0483' && c <= '\u0486') ||
+ (c >= '\u0591' && c <= '\u05A1') || (c >= '\u05A3' && c <= '\u05B9') || (c >= '\u05BB' && c <= '\u05BD') ||
+ c == '\u05BF' || (c >= '\u05C1' && c <= '\u05C2') || c == '\u05C4' || (c >= '\u064B' && c <= '\u0652') ||
+ c == '\u0670' || (c >= '\u06D6' && c <= '\u06DC') || (c >= '\u06DD' && c <= '\u06DF') || (c >= '\u06E0' && c <= '\u06E4') ||
+ (c >= '\u06E7' && c <= '\u06E8') || (c >= '\u06EA' && c <= '\u06ED') || (c >= '\u0901' && c <= '\u0903') || c == '\u093C' ||
+ (c >= '\u093E' && c <= '\u094C') || c == '\u094D' || (c >= '\u0951' && c <= '\u0954') || (c >= '\u0962' && c <= '\u0963') ||
+ (c >= '\u0981' && c <= '\u0983') || c == '\u09BC' || c == '\u09BE' || c == '\u09BF' || (c >= '\u09C0' && c <= '\u09C4') ||
+ (c >= '\u09C7' && c <= '\u09C8') || (c >= '\u09CB' && c <= '\u09CD') || c == '\u09D7' || (c >= '\u09E2' && c <= '\u09E3') ||
+ c == '\u0A02' || c == '\u0A3C' || c == '\u0A3E' || c == '\u0A3F' || (c >= '\u0A40' && c <= '\u0A42') ||
+ (c >= '\u0A47' && c <= '\u0A48') || (c >= '\u0A4B' && c <= '\u0A4D') || (c >= '\u0A70' && c <= '\u0A71') ||
+ (c >= '\u0A81' && c <= '\u0A83') || c == '\u0ABC' || (c >= '\u0ABE' && c <= '\u0AC5') || (c >= '\u0AC7' && c <= '\u0AC9') ||
+ (c >= '\u0ACB' && c <= '\u0ACD') || (c >= '\u0B01' && c <= '\u0B03') || c == '\u0B3C' || (c >= '\u0B3E' && c <= '\u0B43') ||
+ (c >= '\u0B47' && c <= '\u0B48') || (c >= '\u0B4B' && c <= '\u0B4D') || (c >= '\u0B56' && c <= '\u0B57') ||
+ (c >= '\u0B82' && c <= '\u0B83') || (c >= '\u0BBE' && c <= '\u0BC2') || (c >= '\u0BC6' && c <= '\u0BC8') ||
+ (c >= '\u0BCA' && c <= '\u0BCD') || c == '\u0BD7' || (c >= '\u0C01' && c <= '\u0C03') || (c >= '\u0C3E' && c <= '\u0C44') ||
+ (c >= '\u0C46' && c <= '\u0C48') || (c >= '\u0C4A' && c <= '\u0C4D') || (c >= '\u0C55' && c <= '\u0C56') ||
+ (c >= '\u0C82' && c <= '\u0C83') || (c >= '\u0CBE' && c <= '\u0CC4') || (c >= '\u0CC6' && c <= '\u0CC8') ||
+ (c >= '\u0CCA' && c <= '\u0CCD') || (c >= '\u0CD5' && c <= '\u0CD6') || (c >= '\u0D02' && c <= '\u0D03') ||
+ (c >= '\u0D3E' && c <= '\u0D43') || (c >= '\u0D46' && c <= '\u0D48') || (c >= '\u0D4A' && c <= '\u0D4D') || c == '\u0D57' ||
+ c == '\u0E31' || (c >= '\u0E34' && c <= '\u0E3A') || (c >= '\u0E47' && c <= '\u0E4E') || c == '\u0EB1' ||
+ (c >= '\u0EB4' && c <= '\u0EB9') || (c >= '\u0EBB' && c <= '\u0EBC') || (c >= '\u0EC8' && c <= '\u0ECD') ||
+ (c >= '\u0F18' && c <= '\u0F19') || c == '\u0F35' || c == '\u0F37' || c == '\u0F39' || c == '\u0F3E' || c == '\u0F3F' ||
+ (c >= '\u0F71' && c <= '\u0F84') || (c >= '\u0F86' && c <= '\u0F8B') || (c >= '\u0F90' && c <= '\u0F95') || c == '\u0F97' ||
+ (c >= '\u0F99' && c <= '\u0FAD') || (c >= '\u0FB1' && c <= '\u0FB7') || c == '\u0FB9' || (c >= '\u20D0' && c <= '\u20DC') ||
+ c == '\u20E1' || (c >= '\u302A' && c <= '\u302F') || c == '\u3099' || c == '\u309A';
+ }
+
+ private static boolean isExtender(char c) {
+ return c == '\u00B7' || c == '\u02D0' || c == '\u02D1' || c == '\u0387' || c == '\u0640' || c == '\u0E46' ||
+ c == '\u0EC6' || c == '\u3005' || (c >= '\u3031' && c <= '\u3035') || (c >= '\u309D' && c <= '\u309E') ||
+ (c >= '\u30FC' && c <= '\u30FE');
+ }
+
+ private static boolean isLetter(char c) {
+ return isBaseChar(c) || isIdeographic(c);
+ }
+
+ private static boolean isBaseChar(char c) {
+ return (c >= '\u0041' && c <= '\u005A') || (c >= '\u0061' && c <= '\u007A') || (c >= '\u00C0' && c <= '\u00D6') ||
+ (c >= '\u00D8' && c <= '\u00F6') || (c >= '\u00F8' && c <= '\u00FF') || (c >= '\u0100' && c <= '\u0131') ||
+ (c >= '\u0134' && c <= '\u013E') || (c >= '\u0141' && c <= '\u0148') || (c >= '\u014A' && c <= '\u017E') ||
+ (c >= '\u0180' && c <= '\u01C3') || (c >= '\u01CD' && c <= '\u01F0') || (c >= '\u01F4' && c <= '\u01F5') ||
+ (c >= '\u01FA' && c <= '\u0217') || (c >= '\u0250' && c <= '\u02A8') || (c >= '\u02BB' && c <= '\u02C1') ||
+ c == '\u0386' || (c >= '\u0388' && c <= '\u038A') || c == '\u038C' || (c >= '\u038E' && c <= '\u03A1') ||
+ (c >= '\u03A3' && c <= '\u03CE') || (c >= '\u03D0' && c <= '\u03D6') || c == '\u03DA' || c == '\u03DC' || c == '\u03DE' ||
+ c == '\u03E0' || (c >= '\u03E2' && c <= '\u03F3') || (c >= '\u0401' && c <= '\u040C') || (c >= '\u040E' && c <= '\u044F') ||
+ (c >= '\u0451' && c <= '\u045C') || (c >= '\u045E' && c <= '\u0481') || (c >= '\u0490' && c <= '\u04C4') ||
+ (c >= '\u04C7' && c <= '\u04C8') || (c >= '\u04CB' && c <= '\u04CC') || (c >= '\u04D0' && c <= '\u04EB') ||
+ (c >= '\u04EE' && c <= '\u04F5') || (c >= '\u04F8' && c <= '\u04F9') || (c >= '\u0531' && c <= '\u0556') ||
+ c == '\u0559' || (c >= '\u0561' && c <= '\u0586') || (c >= '\u05D0' && c <= '\u05EA') || (c >= '\u05F0' && c <= '\u05F2') ||
+ (c >= '\u0621' && c <= '\u063A') || (c >= '\u0641' && c <= '\u064A') || (c >= '\u0671' && c <= '\u06B7') ||
+ (c >= '\u06BA' && c <= '\u06BE') || (c >= '\u06C0' && c <= '\u06CE') || (c >= '\u06D0' && c <= '\u06D3') ||
+ c == '\u06D5' || (c >= '\u06E5' && c <= '\u06E6') || (c >= '\u0905' && c <= '\u0939') || c == '\u093D' ||
+ (c >= '\u0958' && c <= '\u0961') || (c >= '\u0985' && c <= '\u098C') || (c >= '\u098F' && c <= '\u0990') ||
+ (c >= '\u0993' && c <= '\u09A8') || (c >= '\u09AA' && c <= '\u09B0') || c == '\u09B2' ||
+ (c >= '\u09B6' && c <= '\u09B9') || (c >= '\u09DC' && c <= '\u09DD') || (c >= '\u09DF' && c <= '\u09E1') ||
+ (c >= '\u09F0' && c <= '\u09F1') || (c >= '\u0A05' && c <= '\u0A0A') || (c >= '\u0A0F' && c <= '\u0A10') ||
+ (c >= '\u0A13' && c <= '\u0A28') || (c >= '\u0A2A' && c <= '\u0A30') || (c >= '\u0A32' && c <= '\u0A33') ||
+ (c >= '\u0A35' && c <= '\u0A36') || (c >= '\u0A38' && c <= '\u0A39') || (c >= '\u0A59' && c <= '\u0A5C') ||
+ c == '\u0A5E' || (c >= '\u0A72' && c <= '\u0A74') || (c >= '\u0A85' && c <= '\u0A8B') || c == '\u0A8D' ||
+ (c >= '\u0A8F' && c <= '\u0A91') || (c >= '\u0A93' && c <= '\u0AA8') || (c >= '\u0AAA' && c <= '\u0AB0') ||
+ (c >= '\u0AB2' && c <= '\u0AB3') || (c >= '\u0AB5' && c <= '\u0AB9') || c == '\u0ABD' || c == '\u0AE0' ||
+ (c >= '\u0B05' && c <= '\u0B0C') || (c >= '\u0B0F' && c <= '\u0B10') || (c >= '\u0B13' && c <= '\u0B28') ||
+ (c >= '\u0B2A' && c <= '\u0B30') || (c >= '\u0B32' && c <= '\u0B33') || (c >= '\u0B36' && c <= '\u0B39') ||
+ c == '\u0B3D' || (c >= '\u0B5C' && c <= '\u0B5D') || (c >= '\u0B5F' && c <= '\u0B61') ||
+ (c >= '\u0B85' && c <= '\u0B8A') || (c >= '\u0B8E' && c <= '\u0B90') || (c >= '\u0B92' && c <= '\u0B95') ||
+ (c >= '\u0B99' && c <= '\u0B9A') || c == '\u0B9C' || (c >= '\u0B9E' && c <= '\u0B9F') ||
+ (c >= '\u0BA3' && c <= '\u0BA4') || (c >= '\u0BA8' && c <= '\u0BAA') || (c >= '\u0BAE' && c <= '\u0BB5') ||
+ (c >= '\u0BB7' && c <= '\u0BB9') || (c >= '\u0C05' && c <= '\u0C0C') || (c >= '\u0C0E' && c <= '\u0C10') ||
+ (c >= '\u0C12' && c <= '\u0C28') || (c >= '\u0C2A' && c <= '\u0C33') || (c >= '\u0C35' && c <= '\u0C39') ||
+ (c >= '\u0C60' && c <= '\u0C61') || (c >= '\u0C85' && c <= '\u0C8C') || (c >= '\u0C8E' && c <= '\u0C90') ||
+ (c >= '\u0C92' && c <= '\u0CA8') || (c >= '\u0CAA' && c <= '\u0CB3') || (c >= '\u0CB5' && c <= '\u0CB9') ||
+ c == '\u0CDE' || (c >= '\u0CE0' && c <= '\u0CE1') || (c >= '\u0D05' && c <= '\u0D0C') ||
+ (c >= '\u0D0E' && c <= '\u0D10') || (c >= '\u0D12' && c <= '\u0D28') || (c >= '\u0D2A' && c <= '\u0D39') ||
+ (c >= '\u0D60' && c <= '\u0D61') || (c >= '\u0E01' && c <= '\u0E2E') || c == '\u0E30' ||
+ (c >= '\u0E32' && c <= '\u0E33') || (c >= '\u0E40' && c <= '\u0E45') || (c >= '\u0E81' && c <= '\u0E82') ||
+ c == '\u0E84' || (c >= '\u0E87' && c <= '\u0E88') || c == '\u0E8A' || c == '\u0E8D' || (c >= '\u0E94' && c <= '\u0E97') ||
+ (c >= '\u0E99' && c <= '\u0E9F') || (c >= '\u0EA1' && c <= '\u0EA3') || c == '\u0EA5' || c == '\u0EA7' ||
+ (c >= '\u0EAA' && c <= '\u0EAB') || (c >= '\u0EAD' && c <= '\u0EAE') || c == '\u0EB0' ||
+ (c >= '\u0EB2' && c <= '\u0EB3') || c == '\u0EBD' || (c >= '\u0EC0' && c <= '\u0EC4') ||
+ (c >= '\u0F40' && c <= '\u0F47') || (c >= '\u0F49' && c <= '\u0F69') || (c >= '\u10A0' && c <= '\u10C5') ||
+ (c >= '\u10D0' && c <= '\u10F6') || c == '\u1100' || (c >= '\u1102' && c <= '\u1103') ||
+ (c >= '\u1105' && c <= '\u1107') || c == '\u1109' || (c >= '\u110B' && c <= '\u110C') ||
+ (c >= '\u110E' && c <= '\u1112') || c == '\u113C' || c == '\u113E' || c == '\u1140' || c == '\u114C' ||
+ c == '\u114E' || c == '\u1150' || (c >= '\u1154' && c <= '\u1155') || c == '\u1159' ||
+ (c >= '\u115F' && c <= '\u1161') || c == '\u1163' || c == '\u1165' || c == '\u1167' || c == '\u1169' ||
+ (c >= '\u116D' && c <= '\u116E') || (c >= '\u1172' && c <= '\u1173') || c == '\u1175' ||
+ c == '\u119E' || c == '\u11A8' || c == '\u11AB' || (c >= '\u11AE' && c <= '\u11AF') ||
+ (c >= '\u11B7' && c <= '\u11B8') || c == '\u11BA' || (c >= '\u11BC' && c <= '\u11C2') ||
+ c == '\u11EB' || c == '\u11F0' || c == '\u11F9' || (c >= '\u1E00' && c <= '\u1E9B') || (c >= '\u1EA0' && c <= '\u1EF9') ||
+ (c >= '\u1F00' && c <= '\u1F15') || (c >= '\u1F18' && c <= '\u1F1D') || (c >= '\u1F20' && c <= '\u1F45') ||
+ (c >= '\u1F48' && c <= '\u1F4D') || (c >= '\u1F50' && c <= '\u1F57') || c == '\u1F59' || c == '\u1F5B' || c == '\u1F5D' ||
+ (c >= '\u1F5F' && c <= '\u1F7D') || (c >= '\u1F80' && c <= '\u1FB4') || (c >= '\u1FB6' && c <= '\u1FBC') ||
+ c == '\u1FBE' || (c >= '\u1FC2' && c <= '\u1FC4') || (c >= '\u1FC6' && c <= '\u1FCC') ||
+ (c >= '\u1FD0' && c <= '\u1FD3') || (c >= '\u1FD6' && c <= '\u1FDB') || (c >= '\u1FE0' && c <= '\u1FEC') ||
+ (c >= '\u1FF2' && c <= '\u1FF4') || (c >= '\u1FF6' && c <= '\u1FFC') || c == '\u2126' ||
+ (c >= '\u212A' && c <= '\u212B') || c == '\u212E' || (c >= '\u2180' && c <= '\u2182') ||
+ (c >= '\u3041' && c <= '\u3094') || (c >= '\u30A1' && c <= '\u30FA') || (c >= '\u3105' && c <= '\u312C') ||
+ (c >= '\uAC00' && c <= '\uD7A3');
+ }
+
+ private static boolean isIdeographic(char c) {
+ return (c >= '\u4E00' && c <= '\u9FA5') || c == '\u3007' || (c >= '\u3021' && c <= '\u3029');
+ }
+
+ public static String determineEncoding(InputStream stream) throws IOException {
+ stream.mark(20000);
+ try {
+ int b0 = stream.read();
+ int b1 = stream.read();
+ int b2 = stream.read();
+ int b3 = stream.read();
+
+ if (b0 == 0xFE && b1 == 0xFF)
+ return "UTF-16BE";
+ else if (b0 == 0xFF && b1 == 0xFE)
+ return "UTF-16LE";
+ else if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF )
+ return "UTF-8";
+ else if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F)
+ return "UTF-16BE";
+ else if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00)
+ return "UTF-16LE";
+ else if (b0 == 0x3C && b1 == 0x3F && b2 == 0x78 && b3 == 0x6D) {
+// UTF-8, ISO 646, ASCII, some part of ISO 8859, Shift-JIS, EUC, or any other 7-bit, 8-bit, or mixed-width encoding
+// which ensures that the characters of ASCII have their normal positions, width, and values; the actual encoding
+// declaration must be read to detect which of these applies, but since all of these encodings use the same bit patterns
+// for the relevant ASCII characters, the encoding declaration itself may be read reliably
+ InputStreamReader rdr = new InputStreamReader(stream, "US-ASCII");
+ String hdr = readFirstLine(rdr);
+ return extractEncoding(hdr);
+ } else
+ return null;
+ } finally {
+ stream.reset();
+ }
+ }
+
+ private static String extractEncoding(String hdr) {
+ int i = hdr.indexOf("encoding=");
+ if (i == -1)
+ return null;
+ hdr = hdr.substring(i+9);
+ char sep = hdr.charAt(0);
+ hdr = hdr.substring(1);
+ i = hdr.indexOf(sep);
+ if (i == -1)
+ return null;
+ return hdr.substring(0, i);
+ }
+
+ private static String readFirstLine(InputStreamReader rdr) throws IOException {
+ char[] buf = new char[1];
+ StringBuffer bldr = new StringBuffer();
+ rdr.read(buf);
+ while (buf[0] != '>') {
+ bldr.append(buf[0]);
+ rdr.read(buf);
+ }
+ return bldr.toString();
+ }
+
+
+ public static boolean charSetImpliesAscii(String charset) {
+ return charset.equals("ISO-8859-1") || charset.equals("US-ASCII");
+ }
+
+
+ /**
+ * Converts the raw characters to XML escapeUrlParam characters.
+ *
+ * @param rawContent
+ * @param charset Null when charset is not known, so we assume it's unicode
+ * @param isNoLines
+ * @return escapeUrlParam string
+ */
+ public static String escapeXML(String rawContent, String charset, boolean isNoLines) {
+ if (rawContent == null)
+ return "";
+ else {
+ StringBuffer sb = new StringBuffer();
+
+ for (int i = 0; i < rawContent.length(); i++) {
+ char ch = rawContent.charAt(i);
+ if (ch == '\'')
+ sb.append("'");
+ else if (ch == '&')
+ sb.append("&");
+ else if (ch == '"')
+ sb.append(""");
+ else if (ch == '<')
+ sb.append("<");
+ else if (ch == '>')
+ sb.append(">");
+ else if (ch > '~' && charset != null && charSetImpliesAscii(charset))
+ // TODO - why is hashcode the only way to get the unicode number for the character
+ // in jre 5.0?
+ sb.append(""+Integer.toHexString(ch).toUpperCase()+";");
+ else if (isNoLines) {
+ if (ch == '\r')
+ sb.append("
");
+ else if (ch != '\n')
+ sb.append(ch);
+ }
+ else
+ sb.append(ch);
+ }
+ return sb.toString();
+ }
+ }
+
+ public static Element getFirstChild(Element e) {
+ if (e == null)
+ return null;
+ Node n = e.getFirstChild();
+ while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
+ n = n.getNextSibling();
+ return (Element) n;
+ }
+
+ public static Element getNamedChild(Element e, String name) {
+ Element c = getFirstChild(e);
+ while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName()))
+ c = getNextSibling(c);
+ return c;
+ }
+
+ public static Element getNextSibling(Element e) {
+ Node n = e.getNextSibling();
+ while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
+ n = n.getNextSibling();
+ return (Element) n;
+ }
+
+ public static void getNamedChildren(Element e, String name, List set) {
+ Element c = getFirstChild(e);
+ while (c != null) {
+ if (name.equals(c.getLocalName()) || name.equals(c.getNodeName()) )
+ set.add(c);
+ c = getNextSibling(c);
+ }
+ }
+
+ public static String htmlToXmlEscapedPlainText(Element r) {
+ StringBuilder s = new StringBuilder();
+ Node n = r.getFirstChild();
+ boolean ws = false;
+ while (n != null) {
+ if (n.getNodeType() == Node.TEXT_NODE) {
+ String t = n.getTextContent().trim();
+ if (Utilities.noString(t))
+ ws = true;
+ else {
+ if (ws)
+ s.append(" ");
+ ws = false;
+ s.append(t);
+ }
+ }
+ if (n.getNodeType() == Node.ELEMENT_NODE) {
+ if (ws)
+ s.append(" ");
+ ws = false;
+ s.append(htmlToXmlEscapedPlainText((Element) n));
+ if (r.getNodeName().equals("br") || r.getNodeName().equals("p"))
+ s.append("\r\n");
+ }
+ n = n.getNextSibling();
+ }
+ return s.toString();
+ }
+
+ public static String htmlToXmlEscapedPlainText(String definition) throws ParserConfigurationException, SAXException, IOException {
+ return htmlToXmlEscapedPlainText(parseToDom("
"+definition+"
").getDocumentElement());
+ }
+
+ public static String elementToString(Element el) {
+ if (el == null)
+ return "";
+ Document document = el.getOwnerDocument();
+ DOMImplementationLS domImplLS = (DOMImplementationLS) document
+ .getImplementation();
+ LSSerializer serializer = domImplLS.createLSSerializer();
+ return serializer.writeToString(el);
+ }
+
+ public static String getNamedChildValue(Element element, String name) {
+ Element e = getNamedChild(element, name);
+ return e == null ? null : e.getAttribute("value");
+ }
+
+ public static void setNamedChildValue(Element element, String name, String value) throws FHIRException {
+ Element e = getNamedChild(element, name);
+ if (e == null)
+ throw new FHIRException("unable to find element "+name);
+ e.setAttribute("value", value);
+ }
+
+
+ public static void getNamedChildrenWithWildcard(Element focus, String name, List children) {
+ Element c = getFirstChild(focus);
+ while (c != null) {
+ String n = c.getLocalName() != null ? c.getLocalName() : c.getNodeName();
+ if (name.equals(n) || (name.endsWith("[x]") && n.startsWith(name.substring(0, name.length()-3))))
+ children.add(c);
+ c = getNextSibling(c);
+ }
+ }
+
+ public static void getNamedChildrenWithTails(Element focus, String name, List children, Set typeTails) {
+ Element c = getFirstChild(focus);
+ while (c != null) {
+ String n = c.getLocalName() != null ? c.getLocalName() : c.getNodeName();
+ if (n.equals(name) || (!n.equals("responseCode") && (n.startsWith(name) && typeTails.contains(n.substring(name.length())))))
+ children.add(c);
+ c = getNextSibling(c);
+ }
+ }
+
+ public static boolean hasNamedChild(Element e, String name) {
+ Element c = getFirstChild(e);
+ while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName()))
+ c = getNextSibling(c);
+ return c != null;
+ }
+
+ public static Document parseToDom(String content) throws ParserConfigurationException, SAXException, IOException {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(false);
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ return builder.parse(new ByteArrayInputStream(content.getBytes()));
+ }
+
+ public static Document parseFileToDom(String filename) throws ParserConfigurationException, SAXException, IOException {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(false);
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ return builder.parse(new FileInputStream(filename));
+ }
+
+ public static Element getLastChild(Element e) {
+ if (e == null)
+ return null;
+ Node n = e.getLastChild();
+ while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
+ n = n.getPreviousSibling();
+ return (Element) n;
+ }
+
+ public static Element getPrevSibling(Element e) {
+ Node n = e.getPreviousSibling();
+ while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
+ n = n.getPreviousSibling();
+ return (Element) n;
+ }
+
+ public static String getNamedChildAttribute(Element element, String name, String aname) {
+ Element e = getNamedChild(element, name);
+ return e == null ? null : e.getAttribute(aname);
+ }
+
+ public static void writeDomToFile(Document doc, String filename) throws TransformerException {
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer = transformerFactory.newTransformer();
+ DOMSource source = new DOMSource(doc);
+ StreamResult streamResult = new StreamResult(new File(filename));
+ transformer.transform(source, streamResult);
+ }
+
+ public static String getXsiType(org.w3c.dom.Element element) {
+ Attr a = element.getAttributeNodeNS("http://www.w3.org/2001/XMLSchema-instance", "type");
+ return (a == null ? null : a.getTextContent());
+
+ }
+
+ public static String getDirectText(org.w3c.dom.Element node) {
+ Node n = node.getFirstChild();
+ StringBuilder b = new StringBuilder();
+ while (n != null) {
+ if (n.getNodeType() == Node.TEXT_NODE)
+ b.append(n.getTextContent());
+ n = n.getNextSibling();
+ }
+ return b.toString().trim();
+ }
+
+
+}
diff --git a/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/GraphQLDstu3ProviderTest.java b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/GraphQLDstu3ProviderTest.java
index b8da72f1894..f9668d839b4 100644
--- a/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/GraphQLDstu3ProviderTest.java
+++ b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/GraphQLDstu3ProviderTest.java
@@ -57,7 +57,7 @@ public class GraphQLDstu3ProviderTest {
@Ignore
public void testGraphInstance() throws Exception {
String query = "{name{family,given}}";
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escape(query));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@@ -84,7 +84,7 @@ public class GraphQLDstu3ProviderTest {
@Ignore
public void testGraphInstanceWithFhirpath() throws Exception {
String query = "{name(fhirpath:\"family.exists()\"){text,given,family}}";
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escape(query));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@@ -109,7 +109,7 @@ public class GraphQLDstu3ProviderTest {
@org.junit.Ignore
public void testGraphSystemInstance() throws Exception {
String query = "{Patient(id:123){id,name{given,family}}}";
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escape(query));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@@ -138,7 +138,7 @@ public class GraphQLDstu3ProviderTest {
@Ignore
public void testGraphSystemList() throws Exception {
String query = "{PatientList(name:\"pet\"){name{family,given}}}";
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escape(query));
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 4cf2c689611..26188e4c9ab 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -11,6 +11,12 @@
Fix a crash in JPA server when performing a recursive
_include]]> which doesn't actually find any matches.
+
+ When encoding URL parameter values, HAPI FHIR would incorrectly escape
+ a space (" ") as a plus ("+") insetad of as "%20" as required by
+ RFC 3986. This affects client calls, as well as URLs generated by
+ the server (e.g. REST HOOK calls). Thanks to James Daily for reporting!
+
From 863c4b370ca0606d9386510dc723368bd0d64ba5 Mon Sep 17 00:00:00 2001
From: James Agnew
Date: Sat, 25 Nov 2017 20:32:42 -0500
Subject: [PATCH 39/39] Add some test debug logs
---
.../jpa/search/SearchCoordinatorSvcImpl.java | 10 ++-
.../uhn/fhir/jpa/config/TestDstu2Config.java | 2 +-
.../uhn/fhir/jpa/config/TestDstu3Config.java | 2 +-
.../ca/uhn/fhir/jpa/config/TestR4Config.java | 2 +-
.../java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java | 75 +++++++++++--------
.../dao/dstu2/FhirResourceDaoDstu2Test.java | 10 ++-
...rResourceDaoDstu3SearchPageExpiryTest.java | 35 +++++----
7 files changed, 82 insertions(+), 54 deletions(-)
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java
index 6f2a727e59e..340e258f617 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java
@@ -593,6 +593,9 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
shouldSync = true;
}
+ // If no abort was requested, bail out
+ Validate.isTrue(myAbortRequested == false, "Abort has been requested");
+
if (shouldSync) {
saveUnsynced(theResultIterator);
}
@@ -605,10 +608,11 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
}
}
- // Check if an abort got requested
- Validate.isTrue(myAbortRequested == false, "Abort has been requested");
-
}
+
+ // If no abort was requested, bail out
+ Validate.isTrue(myAbortRequested == false, "Abort has been requested");
+
saveUnsynced(theResultIterator);
}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestDstu2Config.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestDstu2Config.java
index 49c9107ce28..0017646f79e 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestDstu2Config.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestDstu2Config.java
@@ -30,7 +30,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
public DataSource dataSource() {
BasicDataSource retVal = new BasicDataSource();
retVal.setDriver(new org.apache.derby.jdbc.EmbeddedDriver());
- retVal.setUrl("jdbc:derby:memory:myUnitTestDB;create=true");
+ retVal.setUrl("jdbc:derby:memory:myUnitTestDBDstu2;create=true");
retVal.setUsername("");
retVal.setPassword("");
return retVal;
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestDstu3Config.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestDstu3Config.java
index 46fb60ba025..4c7420a3c1d 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestDstu3Config.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestDstu3Config.java
@@ -90,7 +90,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
};
retVal.setDriver(new org.apache.derby.jdbc.EmbeddedDriver());
- retVal.setUrl("jdbc:derby:memory:myUnitTestDB;create=true");
+ retVal.setUrl("jdbc:derby:memory:myUnitTestDBDstu3;create=true");
retVal.setMaxWaitMillis(10000);
retVal.setUsername("");
retVal.setPassword("");
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestR4Config.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestR4Config.java
index d40ea5d2284..c84e1f4748a 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestR4Config.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/config/TestR4Config.java
@@ -85,7 +85,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
};
retVal.setDriver(new org.apache.derby.jdbc.EmbeddedDriver());
- retVal.setUrl("jdbc:derby:memory:myUnitTestDB;create=true");
+ retVal.setUrl("jdbc:derby:memory:myUnitTestDBR4;create=true");
retVal.setMaxWaitMillis(10000);
retVal.setUsername("");
retVal.setPassword("");
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java
index 468845de9a4..130fc65d85c 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaTest.java
@@ -1,38 +1,12 @@
package ca.uhn.fhir.jpa.dao;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.sql.SQLException;
-import java.util.*;
-import java.util.concurrent.Callable;
-
-import javax.persistence.EntityManager;
-
-import ca.uhn.fhir.jpa.util.StopWatch;
-import ca.uhn.fhir.model.dstu2.resource.Observation;
-import org.apache.commons.io.IOUtils;
-import org.hibernate.search.jpa.Search;
-import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
-import org.hl7.fhir.dstu3.model.Resource;
-import org.hl7.fhir.instance.model.api.*;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.mockito.Mockito;
-import org.springframework.transaction.PlatformTransactionManager;
-import org.springframework.transaction.TransactionStatus;
-import org.springframework.transaction.support.TransactionCallback;
-import org.springframework.transaction.support.TransactionTemplate;
-
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
import ca.uhn.fhir.jpa.term.VersionIndependentConcept;
+import ca.uhn.fhir.jpa.util.StopWatch;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
@@ -41,6 +15,31 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.BundleUtil;
import ca.uhn.fhir.util.TestUtil;
+import org.apache.commons.io.IOUtils;
+import org.hibernate.search.jpa.Search;
+import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
+import org.hl7.fhir.dstu3.model.Resource;
+import org.hl7.fhir.instance.model.api.IBaseBundle;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.instance.model.api.IIdType;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.mockito.Mockito;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.support.TransactionCallback;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import javax.persistence.EntityManager;
+import java.io.IOException;
+import java.io.InputStream;
+import java.sql.SQLException;
+import java.util.*;
+import java.util.concurrent.Callable;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public abstract class BaseJpaTest {
@@ -53,13 +52,23 @@ public abstract class BaseJpaTest {
public void beforeCreateSrd() {
mySrd = mock(ServletRequestDetails.class, Mockito.RETURNS_DEEP_STUBS);
when(mySrd.getRequestOperationCallback()).thenReturn(myRequestOperationCallback);
- myServerInterceptorList = new ArrayList();
+ myServerInterceptorList = new ArrayList<>();
when(mySrd.getServer().getInterceptors()).thenReturn(myServerInterceptorList);
- when(mySrd.getUserData()).thenReturn(new HashMap