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.fhir hapi-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 {