From c0c5714d36984194c15ced9c8f7692326ac8085d Mon Sep 17 00:00:00 2001 From: Seth Rylan Gainey Date: Tue, 30 Jul 2019 10:01:05 -0400 Subject: [PATCH] Fix for https://github.com/jamesagnew/hapi-fhir/issues/1402. Add historyForInstance and historyForType to AbstractJaxRsResourceProvider with non-ambiguous @Path values. --- .../server/AbstractJaxRsResourceProvider.java | 41 ++- .../AbstractJaxRsResourceProviderTest.java | 30 +- .../TestJaxRsMockPatientRestProvider.java | 21 +- .../example/JaxRsPatientRestProvider.java | 16 +- .../JaxRsPatientRestProviderDstu3.java | 15 +- .../example/JaxRsPatientRestProviderR4.java | 241 ++++++++++++++ .../JaxRsPatientProviderDstu3Test.java | 13 + .../example/JaxRsPatientProviderR4Test.java | 308 ++++++++++++++++++ .../example/JaxRsPatientProviderTest.java | 11 + 9 files changed, 685 insertions(+), 11 deletions(-) create mode 100644 hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientRestProviderR4.java create mode 100644 hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderR4Test.java diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.java index 54f84001f80..3a8aac982a9 100644 --- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.java +++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.java @@ -220,7 +220,7 @@ implements IRestfulServer, IResourceProvider { * @see https://www.hl7.org/fhir/http.html#read */ @GET - @Path("/{id}") + @Path("/{id : ((?!_history).)*}") public Response find(@PathParam("id") final String id) throws IOException { return execute(getResourceRequest(RequestTypeEnum.GET, RestOperationTypeEnum.READ).id(id)); @@ -245,7 +245,7 @@ implements IRestfulServer, IResourceProvider { } /** - * Retrieve the update history for a particular resource + * Retrieve a version of a resource * * @param id the id of the resource * @param version the version of the resource @@ -254,13 +254,42 @@ implements IRestfulServer, IResourceProvider { */ @GET @Path("/{id}/_history/{version}") - public Response findHistory(@PathParam("id") final String id, @PathParam("version") final String version) + public Response findVersion(@PathParam("id") final String id, @PathParam("version") final String version) throws IOException { final Builder theRequest = getResourceRequest(RequestTypeEnum.GET, RestOperationTypeEnum.VREAD).id(id).version(version); return execute(theRequest); } - /** + /** + * Retrieve the update history for a particular resource + * + * @param id the id of the resource + * @return the response + * @see https://www.hl7.org/fhir/http.html#history + */ + @GET + @Path("/{id}/_history") + public Response historyForInstance(@PathParam("id") final String id) + throws IOException { + final Builder theRequest = getResourceRequest(RequestTypeEnum.GET, RestOperationTypeEnum.HISTORY_INSTANCE).id(id); + return execute(theRequest); + } + + /** + * Retrieve the update history for a particular type + * + * @return the response + * @see https://www.hl7.org/fhir/http.html#history + */ + @GET + @Path("/_history") + public Response historyForType() + throws IOException { + final Builder theRequest = getResourceRequest(RequestTypeEnum.GET, RestOperationTypeEnum.HISTORY_TYPE); + return execute(theRequest); + } + + /** * Compartment Based Access * * @param id the resource to which the compartment belongs @@ -270,8 +299,8 @@ implements IRestfulServer, IResourceProvider { * @see https://www.hl7.org/fhir/compartments.html#compartment */ @GET - @Path("/{id}/{compartment}") - public Response findCompartment(@PathParam("id") final String id, @PathParam("compartment") final String compartment) + @Path("/{id}/{compartment : ((?!_history).)*}") + public Response findCompartment(@PathParam("id") final String id, @PathParam("compartment") final String compartment) throws IOException { final Builder theRequest = getResourceRequest(RequestTypeEnum.GET, RestOperationTypeEnum.SEARCH_TYPE).id(id).compartment( compartment); diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderTest.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderTest.java index f2704d7dcad..09a3f051dd0 100644 --- a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderTest.java +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProviderTest.java @@ -22,6 +22,7 @@ import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; import ca.uhn.fhir.rest.param.StringAndListParam; import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.SimpleBundleProvider; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.util.TestUtil; import org.apache.commons.lang3.StringUtils; @@ -36,6 +37,7 @@ import org.mockito.Matchers; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import static org.junit.Assert.*; @@ -83,6 +85,12 @@ public class AbstractJaxRsResourceProviderTest { return theResource; } + private Patient createPatient(long id, String version) { + Patient theResource = new Patient(); + theResource.setId(new IdDt(id).withVersion(version)); + return theResource; + } + private List createPatients(int firstId, int lastId) { List result = new ArrayList(lastId - firstId); for (long i = firstId; i <= lastId; i++) { @@ -341,7 +349,7 @@ public class AbstractJaxRsResourceProviderTest { @Test public void testVRead() { - when(mock.findHistory(idCaptor.capture())).thenReturn(createPatient(1)); + when(mock.findVersion(idCaptor.capture())).thenReturn(createPatient(1)); final Patient patient = client.vread(Patient.class, "1", "2"); compareResultId(1, patient); compareResultUrl("/Patient/1", patient); @@ -349,6 +357,26 @@ public class AbstractJaxRsResourceProviderTest { assertEquals("2", idCaptor.getValue().getVersionIdPart()); } + @Test + public void testInstanceHistory() { + when(mock.getHistoryForInstance(idCaptor.capture())).thenReturn(new SimpleBundleProvider(Collections.singletonList(createPatient(1, "1")))); + final Bundle bundle = client.history().onInstance(new IdDt("Patient", 1L)).returnBundle(Bundle.class).execute(); + Patient patient = (Patient) bundle.getEntryFirstRep().getResource(); + compareResultId(1, patient); + compareResultUrl("/Patient/1/_history/1", patient); + assertEquals("1", idCaptor.getValue().getIdPart()); + assertNull(idCaptor.getValue().getVersionIdPart()); + } + + @Test + public void testTypeHistory() { + when(mock.getHistoryForType()).thenReturn(new SimpleBundleProvider(Collections.singletonList(createPatient(1, "1")))); + final Bundle bundle = client.history().onType(Patient.class).returnBundle(Bundle.class).execute(); + Patient patient = (Patient) bundle.getEntryFirstRep().getResource(); + compareResultId(1, patient); + compareResultUrl("/Patient/1/_history/1", patient); + } + @Test public void testXFindUnknownPatient() { try { diff --git a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProvider.java b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProvider.java index 8bfc26cc4d2..0f3d26d6fec 100644 --- a/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProvider.java +++ b/hapi-fhir-jaxrsserver-base/src/test/java/ca/uhn/fhir/jaxrs/server/test/TestJaxRsMockPatientRestProvider.java @@ -1,5 +1,7 @@ package ca.uhn.fhir.jaxrs.server.test; +import java.util.Collections; +import java.util.Date; import java.util.List; import javax.ejb.Stateless; @@ -8,6 +10,11 @@ import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.server.SimpleBundleProvider; +import org.hl7.fhir.instance.model.api.IIdType; import org.mockito.Mockito; import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider; @@ -68,8 +75,18 @@ public class TestJaxRsMockPatientRestProvider extends AbstractJaxRsResourceProvi } @Read(version = true) - public Patient findHistory(@IdParam final IdDt theId) { - return mock.findHistory(theId); + public Patient findVersion(@IdParam final IdDt theId) { + return mock.findVersion(theId); + } + + @History + public IBundleProvider getHistoryForInstance(@IdParam IIdType theId) { + return mock.getHistoryForInstance(theId); + } + + @History + public IBundleProvider getHistoryForType() { + return mock.getHistoryForType(); } @Create diff --git a/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientRestProvider.java b/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientRestProvider.java index 633fc4c72c2..8d13cae062b 100644 --- a/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientRestProvider.java +++ b/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientRestProvider.java @@ -19,6 +19,9 @@ import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.rest.annotation.*; import ca.uhn.fhir.rest.api.*; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.param.DateRangeParam; import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.server.*; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; @@ -89,7 +92,7 @@ public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider list = patients.get(theId.getIdPart()); for (final Patient patient : list) { @@ -101,6 +104,17 @@ public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider list = patients.get(theId.getIdPart()); for (final Patient patient : list) { @@ -102,6 +105,16 @@ public class JaxRsPatientRestProviderDstu3 extends AbstractJaxRsResourceProvider throw new ResourceNotFoundException(theId); } + @History + public IBundleProvider getHistoryForInstance(@IdParam IdType theId, @Since Date theSince, @At DateRangeParam theAt, RequestDetails theRequestDetails) { + return new SimpleBundleProvider(Collections.emptyList(), "myTestId"); + } + + @History + public IBundleProvider getHistoryForType(@Since Date theSince, @At DateRangeParam theAt, RequestDetails theRequestDetails) { + return new SimpleBundleProvider(Collections.emptyList(), "myTestId"); + } + @Operation(name = "firstVersion", idempotent = true, returnParameters = { @OperationParam(name = "return", type = StringType.class) }) public Parameters firstVersion(@IdParam final IdType theId, @OperationParam(name = "dummy") StringType dummyInput) { Parameters parameters = new Parameters(); diff --git a/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientRestProviderR4.java b/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientRestProviderR4.java new file mode 100644 index 00000000000..7b0352e86ca --- /dev/null +++ b/hapi-fhir-jaxrsserver-example/src/main/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientRestProviderR4.java @@ -0,0 +1,241 @@ +package ca.uhn.fhir.jaxrs.server.example; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.api.AddProfileTagEnum; +import ca.uhn.fhir.context.api.BundleInclusionRule; +import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider; +import ca.uhn.fhir.rest.annotation.*; +import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.api.RequestTypeEnum; +import ca.uhn.fhir.rest.api.RestOperationTypeEnum; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.ETagSupportEnum; +import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider; +import ca.uhn.fhir.rest.server.IPagingProvider; +import ca.uhn.fhir.rest.server.SimpleBundleProvider; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.*; + +import javax.ejb.Local; +import javax.ejb.Stateless; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * A demo JaxRs Patient Rest Provider + */ +@Local +@Path(JaxRsPatientRestProviderR4.PATH) +@Stateless +@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML }) +public class JaxRsPatientRestProviderR4 extends AbstractJaxRsResourceProvider { + + private static Long counter = 1L; + + /** + * The HAPI paging provider for this server + */ + public static final IPagingProvider PAGE_PROVIDER; + + static final String PATH = "/Patient"; + private static final ConcurrentHashMap> patients = new ConcurrentHashMap>(); + + static { + PAGE_PROVIDER = new FifoMemoryPagingProvider(10); + } + + static { + patients.put(String.valueOf(counter), createPatient("Van Houte")); + patients.put(String.valueOf(counter), createPatient("Agnew")); + for (int i = 0; i < 20; i++) { + patients.put(String.valueOf(counter), createPatient("Random Patient " + counter)); + } + } + + public JaxRsPatientRestProviderR4() { + super(FhirContext.forDstu3(), JaxRsPatientRestProviderR4.class); + } + + @Create + public MethodOutcome create(@ResourceParam final Patient patient, @ConditionalUrlParam String theConditional) throws Exception { + patients.put("" + counter, createPatient(patient)); + final MethodOutcome result = new MethodOutcome().setCreated(true); + result.setResource(patient); + result.setId(new IdType(patient.getId())); + return result; + } + + @Delete + public MethodOutcome delete(@IdParam final IdType theId) { + final Patient deletedPatient = find(theId); + patients.remove(deletedPatient.getIdElement().getIdPart()); + final MethodOutcome result = new MethodOutcome().setCreated(true); + result.setResource(deletedPatient); + return result; + } + + @Read + public Patient find(@IdParam final IdType theId) { + if (patients.containsKey(theId.getIdPart())) { + return getLast(patients.get(theId.getIdPart())); + } else { + throw new ResourceNotFoundException(theId); + } + } + + @Read(version = true) + public Patient findVersion(@IdParam final IdType theId) { + if (patients.containsKey(theId.getIdPart())) { + final List list = patients.get(theId.getIdPart()); + for (final Patient patient : list) { + if (patient.getIdElement().getVersionIdPartAsLong().equals(theId.getVersionIdPartAsLong())) { + return patient; + } + } + } + throw new ResourceNotFoundException(theId); + } + + @History + public IBundleProvider getHistoryForInstance(@IdParam IdType theId, @Since Date theSince, @At DateRangeParam theAt, RequestDetails theRequestDetails) { + return new SimpleBundleProvider(Collections.emptyList(), "myTestId"); + } + + @History + public IBundleProvider getHistoryForType(@Since Date theSince, @At DateRangeParam theAt, RequestDetails theRequestDetails) { + return new SimpleBundleProvider(Collections.emptyList(), "myTestId"); + } + + @Operation(name = "firstVersion", idempotent = true, returnParameters = { @OperationParam(name = "return", type = StringType.class) }) + public Parameters firstVersion(@IdParam final IdType theId, @OperationParam(name = "dummy") StringType dummyInput) { + Parameters parameters = new Parameters(); + Patient patient = find(new IdType(theId.getResourceType(), theId.getIdPart(), "0")); + parameters.addParameter().setName("return").setResource(patient).setValue(new StringType((counter - 1) + "" + "inputVariable [ " + dummyInput.getValue() + "]")); + return parameters; + } + + @Override + public AddProfileTagEnum getAddProfileTag() { + return AddProfileTagEnum.NEVER; + } + + @Override + public BundleInclusionRule getBundleInclusionRule() { + return BundleInclusionRule.BASED_ON_INCLUDES; + } + + @Override + public ETagSupportEnum getETagSupport() { + return ETagSupportEnum.DISABLED; + } + + /** THE DEFAULTS */ + + @Override + public List getInterceptors_() { + return Collections.emptyList(); + } + + private Patient getLast(final List list) { + return list.get(list.size() - 1); + } + + @Override + public IPagingProvider getPagingProvider() { + return PAGE_PROVIDER; + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Override + public boolean isDefaultPrettyPrint() { + return true; + } + + @GET + @Path("/{id}/$firstVersion") + public Response operationFirstVersionUsingGet(@PathParam("id") String id) throws IOException { + return customOperation(null, RequestTypeEnum.GET, id, "$firstVersion", RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE); + } + + @POST + @Path("/{id}/$firstVersion") + public Response operationFirstVersionUsingGet(@PathParam("id") String id, final String resource) throws Exception { + return customOperation(resource, RequestTypeEnum.POST, id, "$firstVersion", RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE); + } + + @Search + public List search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) { + final List result = new LinkedList(); + for (final List patientIterator : patients.values()) { + Patient single = null; + for (Patient patient : patientIterator) { + if (name == null || patient.getName().get(0).getFamilyElement().getValueNotNull().equals(name.getValueNotNull())) { + single = patient; + } + } + if (single != null) { + result.add(single); + } + } + return result; + } + + @Search(compartmentName = "Condition") + public List searchCompartment(@IdParam IdType thePatientId) { + List retVal = new ArrayList(); + Condition condition = new Condition(); + condition.setId(new IdType("665577")); + retVal.add(condition); + return retVal; + } + + @Update + public MethodOutcome update(@IdParam final IdType theId, @ResourceParam final Patient patient) { + final String idPart = theId.getIdPart(); + if (patients.containsKey(idPart)) { + final List patientList = patients.get(idPart); + final Patient lastPatient = getLast(patientList); + patient.setId(createId(theId.getIdPartAsLong(), lastPatient.getIdElement().getVersionIdPartAsLong() + 1)); + patientList.add(patient); + final MethodOutcome result = new MethodOutcome().setCreated(false); + result.setResource(patient); + result.setId(new IdType(patient.getId())); + return result; + } else { + throw new ResourceNotFoundException(theId); + } + } + + private static IdType createId(final Long id, final Long theVersionId) { + return new IdType("Patient", "" + id, "" + theVersionId); + } + + private static List createPatient(final Patient patient) { + patient.setId(createId(counter, 1L)); + final LinkedList list = new LinkedList(); + list.add(patient); + counter++; + return list; + } + + private static List createPatient(final String name) { + final Patient patient = new Patient(); + patient.getName().add(new HumanName().setFamily(name)); + return createPatient(patient); + } + +} diff --git a/hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderDstu3Test.java b/hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderDstu3Test.java index c1646079242..9c3db5e1244 100644 --- a/hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderDstu3Test.java +++ b/hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderDstu3Test.java @@ -5,6 +5,7 @@ import static org.junit.Assert.*; import java.util.Arrays; import java.util.List; +import ca.uhn.fhir.model.primitive.IdDt; import org.apache.commons.lang3.StringUtils; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; @@ -285,4 +286,16 @@ public class JaxRsPatientProviderDstu3Test { System.out.println(patient); } + @Test + public void testInstanceHistory() { + final Bundle history = client.history().onInstance(new IdDt("Patient", 1L)).returnBundle(Bundle.class).execute(); + assertEquals("myTestId", history.getIdElement().getIdPart()); + } + + @Test + public void testTypeHistory() { + final Bundle history = client.history().onType(Patient.class).returnBundle(Bundle.class).execute(); + assertEquals("myTestId", history.getIdElement().getIdPart()); + } + } diff --git a/hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderR4Test.java b/hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderR4Test.java new file mode 100644 index 00000000000..9fdae9b45b9 --- /dev/null +++ b/hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderR4Test.java @@ -0,0 +1,308 @@ +package ca.uhn.fhir.jaxrs.server.example; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jaxrs.client.JaxRsRestfulClientFactory; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum; +import ca.uhn.fhir.rest.api.EncodingEnum; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.api.PreferReturnEnum; +import ca.uhn.fhir.rest.api.SearchStyleEnum; +import ca.uhn.fhir.rest.client.api.IGenericClient; +import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; +import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; +import ca.uhn.fhir.test.utilities.JettyUtil; +import ca.uhn.fhir.util.TestUtil; +import org.apache.commons.lang3.StringUtils; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.hl7.fhir.r4.model.*; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.*; + +public class JaxRsPatientProviderR4Test { + + private static IGenericClient client; + private static FhirContext ourCtx = FhirContext.forR4(); + private static final String PATIENT_NAME = "Van Houte"; + private static int ourPort; + private static Server jettyServer; + + @AfterClass + public static void afterClassClearContext() throws Exception { + JettyUtil.closeServer(jettyServer); + TestUtil.clearAllStaticFieldsForUnitTest(); + } + + @BeforeClass + public static void setUpClass() + throws Exception { + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/"); + jettyServer = new Server(0); + jettyServer.setHandler(context); + ServletHolder jerseyServlet = context.addServlet(org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.class, "/*"); + jerseyServlet.setInitOrder(0); + //@formatter:off + jerseyServlet.setInitParameter("resteasy.resources", + StringUtils.join(Arrays.asList( + JaxRsConformanceProvider.class.getCanonicalName(), + JaxRsPatientRestProvider.class.getCanonicalName(), + JaxRsPageProvider.class.getCanonicalName() + ), ",")); + //@formatter:on + JettyUtil.startServer(jettyServer); + ourPort = JettyUtil.getPortForStartedServer(jettyServer); + + ourCtx.setRestfulClientFactory(new JaxRsRestfulClientFactory(ourCtx)); + ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); + ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); + client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/"); + client.setEncoding(EncodingEnum.JSON); + client.registerInterceptor(new LoggingInterceptor(true)); + } + + /** Search/Query - Type */ + @Test + public void findUsingGenericClientBySearch() { + // Perform a search + final Bundle results = client + .search() + .forResource(Patient.class) + .where(Patient.NAME.matchesExactly().value(PATIENT_NAME)) + .returnBundle(Bundle.class) + .execute(); + System.out.println(results.getEntry().get(0)); + assertEquals(results.getEntry().size(), 1); + } + + /** Search - Multi-valued Parameters (ANY/OR) */ + @Test + public void findUsingGenericClientBySearchWithMultiValues() { + final Bundle response = client + .search() + .forResource(Patient.class) + .where(Patient.ADDRESS.matches().values("Toronto")).and(Patient.ADDRESS.matches().values("Ontario")) + .and(Patient.ADDRESS.matches().values("Canada")) + .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("SHORTNAME", "TOYS")) + .returnBundle(Bundle.class) + .execute(); + System.out.println(response.getEntry().get(0)); + } + + /** Search - Paging */ + @Test + public void findWithPaging() { + // Perform a search + final Bundle results = client.search().forResource(Patient.class).limitTo(8).returnBundle(Bundle.class).execute(); + System.out.println(results.getEntry().size()); + + if (results.getLink(Bundle.LINK_NEXT) != null) { + + // load next page + final Bundle nextPage = client.loadPage().next(results).execute(); + System.out.println(nextPage.getEntry().size()); + } + } + + /** */ + @Test + public void testSearchPost() { + Bundle response = client.search() + .forResource("Patient") + .usingStyle(SearchStyleEnum.POST) + .returnBundle(Bundle.class) + .execute(); + assertTrue(response.getEntry().size() > 0); + } + + /** Search - Compartments */ + @Test + public void testSearchCompartements() { + Bundle response = client.search() + .forResource(Patient.class) + .withIdAndCompartment("1", "Condition") + .returnBundle(Bundle.class) + .execute(); + assertTrue(response.getEntry().size() > 0); + } + + /** Search - Subsetting (_summary and _elements) */ + @Test + @Ignore + public void testSummary() { + client.search() + .forResource(Patient.class) + .returnBundle(Bundle.class) + .execute(); + } + + @Test + public void testCreatePatient() { + final Patient existing = new Patient(); + existing.setId((IdDt) null); + existing.getNameFirstRep().setFamily("Created Patient 54"); + client.setEncoding(EncodingEnum.JSON); + final MethodOutcome results = client.create().resource(existing).prefer(PreferReturnEnum.REPRESENTATION).execute(); + System.out.println(results.getId()); + final Patient patient = (Patient) results.getResource(); + System.out.println(patient); + assertNotNull(client.read().resource(Patient.class).withId(patient.getId())); + client.setEncoding(EncodingEnum.JSON); + } + + /** Conditional Creates */ + @Test + public void testConditionalCreate() { + final Patient existing = new Patient(); + existing.setId((IdDt) null); + existing.getNameFirstRep().setFamily("Created Patient 54"); + client.setEncoding(EncodingEnum.XML); + final MethodOutcome results = client.create().resource(existing).prefer(PreferReturnEnum.REPRESENTATION).execute(); + System.out.println(results.getId()); + final Patient patient = (Patient) results.getResource(); + + client.create() + .resource(patient) + .conditional() + .where(Patient.IDENTIFIER.exactly().identifier(patient.getIdentifierFirstRep().toString())) + .execute(); + } + + /** Find By Id */ + @Test + public void findUsingGenericClientById() { + final Patient results = client.read().resource(Patient.class).withId("1").execute(); + assertEquals(results.getIdElement().getIdPartAsLong().longValue(), 1L); + } + + @Test + public void testUpdateById() { + final Patient existing = client.read().resource(Patient.class).withId("1").execute(); + final List name = existing.getName(); + name.get(0).addSuffix("The Second"); + existing.setName(name); + client.setEncoding(EncodingEnum.XML); + final MethodOutcome results = client.update().resource(existing).withId("1").execute(); + } + + @Test + public void testDeletePatient() { + final Patient existing = new Patient(); + existing.getNameFirstRep().setFamily("Created Patient XYZ"); + final MethodOutcome results = client.create().resource(existing).prefer(PreferReturnEnum.REPRESENTATION).execute(); + System.out.println(results.getId()); + final Patient patient = (Patient) results.getResource(); + client.delete().resource(patient).execute(); + try { + client.read().resource(Patient.class).withId(patient.getId()).execute(); + fail(); + } catch (final Exception e) { + // assertEquals(e.getStatusCode(), Constants.STATUS_HTTP_404_NOT_FOUND); + } + } + + /** Transaction - Server */ + @Ignore + @Test + public void testTransaction() { + Bundle bundle = new Bundle(); + Bundle.BundleEntryComponent entry = bundle.addEntry(); + final Patient existing = new Patient(); + existing.getNameFirstRep().setFamily("Created with bundle"); + entry.setResource(existing); + + BoundCodeDt theTransactionOperation = new BoundCodeDt( + BundleEntryTransactionMethodEnum.VALUESET_BINDER, + BundleEntryTransactionMethodEnum.POST); + Bundle response = client.transaction().withBundle(bundle).execute(); + } + + /** Conformance - Server */ + @Test + @Ignore + public void testConformance() { + final CapabilityStatement caps = client.capabilities().ofType(CapabilityStatement.class).execute(); + System.out.println(caps.getRest().get(0).getResource().get(0).getType()); + assertEquals(caps.getRest().get(0).getResource().get(0).getType().toString(), "Patient"); + } + + /** Extended Operations */ + // Create a client to talk to the HeathIntersections server + @Test + public void testExtendedOperations() { + client.registerInterceptor(new LoggingInterceptor(true)); + + // Create the input parameters to pass to the server + Parameters inParams = new Parameters(); + inParams.addParameter().setName("start").setValue(new DateTimeType("2001-01-01")); + inParams.addParameter().setName("end").setValue(new DateTimeType("2015-03-01")); + inParams.addParameter().setName("dummy").setValue(new StringType("myAwesomeDummyValue")); + + // Invoke $everything on "Patient/1" + Parameters outParams = client + .operation() + .onInstance(new IdDt("Patient", "1")) + .named("$firstVersion") + .withParameters(inParams) + // .useHttpGet() // Use HTTP GET instead of POST + .execute(); + String resultValue = outParams.getParameter().get(0).getValue().toString(); + System.out.println(resultValue); + assertEquals("expected but found : " + resultValue, resultValue.contains("myAwesomeDummyValue"), true); + } + + @Test + public void testExtendedOperationsUsingGet() { + // Create the input parameters to pass to the server + Parameters inParams = new Parameters(); + inParams.addParameter().setName("start").setValue(new DateTimeType("2001-01-01")); + inParams.addParameter().setName("end").setValue(new DateTimeType("2015-03-01")); + inParams.addParameter().setName("dummy").setValue(new StringType("myAwesomeDummyValue")); + + // Invoke $everything on "Patient/1" + Parameters outParams = client + .operation() + .onInstance(new IdDt("Patient", "1")) + .named("$firstVersion") + .withParameters(inParams) + .useHttpGet() // Use HTTP GET instead of POST + .execute(); + String resultValue = outParams.getParameter().get(0).getValue().toString(); + System.out.println(resultValue); + assertEquals("expected but found : " + resultValue, resultValue.contains("myAwesomeDummyValue"), true); + } + + @Test + public void testVRead() { + final Patient patient = client.read().resource(Patient.class).withIdAndVersion("1", "1").execute(); + System.out.println(patient); + } + + @Test + public void testRead() { + final Patient patient = client.read().resource(Patient.class).withId("1").execute(); + System.out.println(patient); + } + + @Test + public void testInstanceHistory() { + final Bundle history = client.history().onInstance(new IdDt("Patient", 1L)).returnBundle(Bundle.class).execute(); + assertEquals("myTestId", history.getIdElement().getIdPart()); + } + + @Test + public void testTypeHistory() { + final Bundle history = client.history().onType(Patient.class).returnBundle(Bundle.class).execute(); + assertEquals("myTestId", history.getIdElement().getIdPart()); + } +} diff --git a/hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderTest.java b/hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderTest.java index 7bd85124d9e..215ba2bf300 100644 --- a/hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderTest.java +++ b/hapi-fhir-jaxrsserver-example/src/test/java/ca/uhn/fhir/jaxrs/server/example/JaxRsPatientProviderTest.java @@ -291,4 +291,15 @@ public class JaxRsPatientProviderTest { System.out.println(patient); } + @Test + public void testInstanceHistory() { + final Bundle history = client.history().onInstance(new IdDt("Patient", 1L)).returnBundle(Bundle.class).execute(); + assertEquals("myTestId", history.getId().getIdPart()); + } + + @Test + public void testTypeHistory() { + final Bundle history = client.history().onType(Patient.class).returnBundle(Bundle.class).execute(); + assertEquals("myTestId", history.getId().getIdPart()); + } }