- add site-documentation for jaxrs base
- set example for operation on instance level - remove not thrown exceptions
This commit is contained in:
parent
26a801edcb
commit
94f309114b
|
@ -40,6 +40,24 @@
|
|||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- jax rs server -->
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-jaxrsserver-base</artifactId>
|
||||
<version>1.3-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.ws.rs</groupId>
|
||||
<artifactId>javax.ws.rs-api</artifactId>
|
||||
<version>2.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.ejb</groupId>
|
||||
<artifactId>ejb-api</artifactId>
|
||||
<version>3.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<reporting>
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package example;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.ejb.EJB;
|
||||
import javax.ejb.Stateless;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsConformanceProvider;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
|
||||
/**
|
||||
* Conformance Rest Service
|
||||
*
|
||||
* @author Peter Van Houte
|
||||
*/
|
||||
// START SNIPPET: jax-rs-conformance
|
||||
@Path("")
|
||||
@Stateless
|
||||
@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML })
|
||||
public class JaxRsConformanceProvider extends AbstractJaxRsConformanceProvider {
|
||||
|
||||
@EJB
|
||||
private JaxRsPatientRestProvider provider;
|
||||
|
||||
public JaxRsConformanceProvider() {
|
||||
super("My Server Version", "My Server Description", "My Server Name");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> getProviders() {
|
||||
ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> map = new ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider>();
|
||||
map.put(JaxRsConformanceProvider.class, this);
|
||||
map.put(JaxRsPatientRestProvider.class, provider);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
// END SNIPPET: jax-rs-conformance
|
|
@ -0,0 +1,82 @@
|
|||
package example;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import javax.ejb.Local;
|
||||
import javax.ejb.Stateless;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Parameters;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Operation;
|
||||
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
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.server.Constants;
|
||||
|
||||
/**
|
||||
* A demo JaxRs Patient Rest Provider
|
||||
*/
|
||||
@Local
|
||||
@Stateless
|
||||
// START SNIPPET: jax-rs-provider-construction
|
||||
@Path("/Patient")
|
||||
@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML })
|
||||
public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider<Patient> {
|
||||
|
||||
public JaxRsPatientRestProvider() {
|
||||
super(JaxRsPatientRestProvider.class);
|
||||
}
|
||||
// END SNIPPET: jax-rs-provider-construction
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
|
||||
@Create
|
||||
public MethodOutcome create(@ResourceParam final Patient patient, @ConditionalUrlParam String theConditional) {
|
||||
// create the patient ...
|
||||
return new MethodOutcome(new IdDt(1L)).setCreated(true);
|
||||
}
|
||||
|
||||
// START SNIPPET: jax-rs-provider-operation
|
||||
@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);
|
||||
}
|
||||
|
||||
@Operation(name = "someCustomOperation", idempotent = true, returnParameters = {
|
||||
@OperationParam(name = "return", type = StringDt.class) })
|
||||
public Parameters someCustomOperation(@IdParam IdDt myId, @OperationParam(name = "dummy") StringDt dummyInput) {
|
||||
Parameters parameters = new Parameters();
|
||||
parameters.addParameter().setName("return").setValue(new StringDt("My Dummy Result"));
|
||||
return parameters;
|
||||
}
|
||||
// END SNIPPET: jax-rs-provider-operation
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
|
@ -300,7 +300,7 @@ public class AbstractJaxRsResourceProviderTest {
|
|||
// prepare mock
|
||||
Parameters resultParameters = new Parameters();
|
||||
resultParameters.addParameter().setName("return").setResource(createPatient(1)).setValue(new StringDt("outputValue"));
|
||||
when(mock.someCustomOperation(eq(new StringDt("myAwesomeDummyValue")))).thenReturn(resultParameters);
|
||||
when(mock.someCustomOperation(any(IdDt.class), eq(new StringDt("myAwesomeDummyValue")))).thenReturn(resultParameters);
|
||||
// Create the input parameters to pass to the server
|
||||
Parameters inParams = new Parameters();
|
||||
inParams.addParameter().setName("start").setValue(new DateDt("2001-01-01"));
|
||||
|
@ -318,7 +318,7 @@ public class AbstractJaxRsResourceProviderTest {
|
|||
// prepare mock
|
||||
Parameters resultParameters = new Parameters();
|
||||
resultParameters.addParameter().setName("return").setResource(createPatient(1)).setValue(new StringDt("outputValue"));
|
||||
when(mock.someCustomOperation(eq(new StringDt("myAwesomeDummyValue")))).thenReturn(resultParameters);
|
||||
when(mock.someCustomOperation(any(IdDt.class), eq(new StringDt("myAwesomeDummyValue")))).thenReturn(resultParameters);
|
||||
// Create the input parameters to pass to the server
|
||||
Parameters inParams = new Parameters();
|
||||
inParams.addParameter().setName("start").setValue(new DateDt("2001-01-01"));
|
||||
|
|
|
@ -89,29 +89,29 @@ public class TestJaxRsMockPatientRestProvider extends AbstractJaxRsResourceProvi
|
|||
return mock.delete(theId);
|
||||
}
|
||||
|
||||
@Search(compartmentName = "Condition")
|
||||
public List<IResource> searchCompartment(@IdParam IdDt 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_TYPE);
|
||||
RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
|
||||
}
|
||||
|
||||
@Search(compartmentName = "Condition")
|
||||
public List<IResource> searchCompartment(@IdParam IdDt thePatientId) {
|
||||
return mock.searchCompartment(thePatientId);
|
||||
}
|
||||
|
||||
@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_TYPE);
|
||||
RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
|
||||
}
|
||||
|
||||
@Operation(name = "someCustomOperation", idempotent = true, returnParameters = {
|
||||
@OperationParam(name = "return", type = StringDt.class) })
|
||||
public Parameters someCustomOperation(@OperationParam(name = "dummy") StringDt dummyInput) {
|
||||
return mock.someCustomOperation(dummyInput);
|
||||
public Parameters someCustomOperation(@IdParam IdDt myId, @OperationParam(name = "dummy") StringDt dummyInput) {
|
||||
return mock.someCustomOperation(myId, dummyInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package ca.uhn.fhir.jaxrs.server.example;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -113,7 +114,7 @@ public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider<Pati
|
|||
}
|
||||
|
||||
@Update
|
||||
public MethodOutcome update(@IdParam final IdDt theId, @ResourceParam final Patient patient) throws Exception {
|
||||
public MethodOutcome update(@IdParam final IdDt theId, @ResourceParam final Patient patient) {
|
||||
final String idPart = theId.getIdPart();
|
||||
if (patients.containsKey(idPart)) {
|
||||
final List<Patient> patientList = patients.get(idPart);
|
||||
|
@ -130,7 +131,7 @@ public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider<Pati
|
|||
}
|
||||
|
||||
@Read
|
||||
public Patient find(@IdParam final IdDt theId) throws InvocationTargetException {
|
||||
public Patient find(@IdParam final IdDt theId) {
|
||||
if (patients.containsKey(theId.getIdPart())) {
|
||||
return getLast(patients.get(theId.getIdPart()));
|
||||
} else {
|
||||
|
@ -166,21 +167,13 @@ public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider<Pati
|
|||
}
|
||||
|
||||
@Delete
|
||||
public MethodOutcome delete(@IdParam final IdDt theId) throws InvocationTargetException {
|
||||
public MethodOutcome delete(@IdParam final IdDt theId) {
|
||||
final Patient deletedPatient = find(theId);
|
||||
patients.remove(deletedPatient.getId().getIdPart());
|
||||
final MethodOutcome result = new MethodOutcome().setCreated(true);
|
||||
result.setResource(deletedPatient);
|
||||
return result;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{id}/$last")
|
||||
public Response operationLastGet(@PathParam("id") String id) throws Exception {
|
||||
return customOperation(null, RequestTypeEnum.GET, id, "$last",
|
||||
RestOperationTypeEnum.EXTENDED_OPERATION_TYPE);
|
||||
}
|
||||
|
||||
@Search(compartmentName = "Condition")
|
||||
public List<IResource> searchCompartment(@IdParam IdDt thePatientId) {
|
||||
List<IResource> retVal = new ArrayList<IResource>();
|
||||
|
@ -190,18 +183,24 @@ public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider<Pati
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/{id}/$last")
|
||||
public Response operationLast(final String resource) throws Exception {
|
||||
return customOperation(resource, RequestTypeEnum.POST, null, "$last",
|
||||
RestOperationTypeEnum.EXTENDED_OPERATION_TYPE);
|
||||
@GET
|
||||
@Path("/{id}/$firstVersion")
|
||||
public Response operationFirstVersionUsingGet(@PathParam("id") String id) throws IOException {
|
||||
return customOperation(null, RequestTypeEnum.GET, id, "$firstVersion", RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
|
||||
}
|
||||
|
||||
@Operation(name = "last", idempotent = true, returnParameters = {
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Operation(name = "firstVersion", idempotent = true, returnParameters = {
|
||||
@OperationParam(name = "return", type = StringDt.class) })
|
||||
public Parameters last(@OperationParam(name = "dummy") StringDt dummyInput) throws InvocationTargetException {
|
||||
public Parameters firstVersion(@IdParam final IdDt theId, @OperationParam(name = "dummy") StringDt dummyInput) {
|
||||
Parameters parameters = new Parameters();
|
||||
Patient patient = find(new IdDt(counter.intValue() - 1));
|
||||
Patient patient = find(new IdDt(theId.getResourceType(), theId.getIdPart(), "0"));
|
||||
parameters.addParameter().setName("return").setResource(patient)
|
||||
.setValue(new StringDt((counter - 1) + "" + "inputVariable [ " + dummyInput.getValue() + "]"));
|
||||
return parameters;
|
||||
|
|
|
@ -261,7 +261,7 @@ public class JaxRsPatientProviderTest {
|
|||
Parameters outParams = client
|
||||
.operation()
|
||||
.onInstance(new IdDt("Patient", "1"))
|
||||
.named("$last")
|
||||
.named("$firstVersion")
|
||||
.withParameters(inParams)
|
||||
//.useHttpGet() // Use HTTP GET instead of POST
|
||||
.execute();
|
||||
|
@ -282,7 +282,7 @@ public class JaxRsPatientProviderTest {
|
|||
Parameters outParams = client
|
||||
.operation()
|
||||
.onInstance(new IdDt("Patient", "1"))
|
||||
.named("$last")
|
||||
.named("$firstVersion")
|
||||
.withParameters(inParams)
|
||||
.useHttpGet() // Use HTTP GET instead of POST
|
||||
.execute();
|
||||
|
|
1
pom.xml
1
pom.xml
|
@ -1293,6 +1293,7 @@
|
|||
<module>hapi-fhir-structures-dstu2</module>
|
||||
<module>hapi-fhir-structures-hl7org-dstu2</module>
|
||||
<module>hapi-fhir-jpaserver-base</module>
|
||||
<module>hapi-fhir-jaxrsserver-base</module>
|
||||
<!-- <module>hapi-fhir-cobertura</module> -->
|
||||
<module>examples</module>
|
||||
</modules>
|
||||
|
|
|
@ -598,6 +598,75 @@
|
|||
|
||||
</section>
|
||||
|
||||
<section name="JAX-RS Server">
|
||||
<p>
|
||||
The standard server is implemented using Servlet technology. A <a href="https://github.com/jamesagnew/hapi-fhir/tree/master/hapi-fhir-jaxrsserver-base">module</a>
|
||||
exists which implements the server using <a href="https://jax-rs-spec.java.net/nonav/2.0/apidocs/index.html">JAX-RS</a> technology.
|
||||
This enables the usage of existing Java EE interceptors and annotations. This module does not provide the full set of features.
|
||||
|
||||
The server currently supports
|
||||
<a href="./doc_rest_server.html#ConformanceMetadata_Statement">Conformance Statements</a>,
|
||||
<a href="./apidocs/ca/uhn/fhir/rest/annotation/Read.html">@Read</a>,
|
||||
<a href="./apidocs/ca/uhn/fhir/rest/annotation/Search.html">@Search</a>,
|
||||
<a href="./apidocs/ca/uhn/fhir/rest/annotation/Create.html">@Create</a>,
|
||||
<a href="./apidocs/ca/uhn/fhir/rest/annotation/Update.html">@Update</a>,
|
||||
<a href="./apidocs/ca/uhn/fhir/rest/annotation/Delete.html">@Delete</a> and
|
||||
<a href="./apidocs/ca/uhn/fhir/rest/annotation/Operation.html">@Operation</a>.
|
||||
</p>
|
||||
<p>
|
||||
The primary intention for this project is to ensure that other web technologies (JAX-RS in this case) can be used together with the base-server functionality.
|
||||
An example server can be found in the Git repo <a href="https://github.com/jamesagnew/hapi-fhir/tree/master/hapi-fhir-jaxrsserver-example">here</a>.
|
||||
</p>
|
||||
|
||||
<subsection name="JAX-RS Implementation specifics">
|
||||
<p>
|
||||
The set-up of a JAX-RS server goes beyond the scope of this documentation. The implementation of the server follows the same pattern as the standard server. It is required
|
||||
to put the correct <a href="./doc_rest_operations.html">annotation</a> on the methods in the <a href="#Defining_Resource_Providers">Resource Providers</a> in order to be able to call them.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Implementing a JAX-RS Resource Provider requires some JAX-RS annotations. The <code><a href="https://docs.oracle.com/javaee/6/api/javax/ws/rs/Path.html">@Path</a></code>
|
||||
annotation needs to define the resource path. The <code><a href="https://docs.oracle.com/javaee/6/api/javax/ws/rs/Produces.html">@Produces</a></code> annotation
|
||||
needs to declare the produced formats. The constructor needs to pass the class of the object explicitely in order to avoid problems with proxy classes in a Java EE environment.
|
||||
It is necessary to extend the abstract class
|
||||
<code><a href="http://jamesagnew.github.io/hapi-fhir/apidocs/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.html">AbstractJaxRsResourceProvider</a></code>.
|
||||
<macro name="snippet">
|
||||
<param name="id" value="jax-rs-provider-construction" />
|
||||
<param name="file" value="examples/src/main/java/example/JaxRsPatientRestProvider.java" />
|
||||
</macro>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
<a href="./doc_rest_operations.html#Extended_Operations">Extended Operations</a> require the correct JAX-RS (
|
||||
<code><a href="https://docs.oracle.com/javaee/6/api/javax/ws/rs/Path.html">@Path</a></code>,
|
||||
<code><a href="https://docs.oracle.com/javaee/6/api/javax/ws/rs/GET.html">@GET</a></code> or
|
||||
<code><a href="https://docs.oracle.com/javaee/6/api/javax/ws/rs/POST.html">@POST</a></code>) annotations. The body of the method needs to call the
|
||||
method <code><a href="http://jamesagnew.github.io/hapi-fhir/apidocs/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.html#customOperation-java.lang.String-ca.uhn.fhir.rest.api.RequestTypeEnum-java.lang.String-java.lang.String-ca.uhn.fhir.rest.api.RestOperationTypeEnum">AbstractJaxRsResourceProvider#customOperation</a></code>
|
||||
with the correct parameters. The server will then call the method with corresponding name.
|
||||
<macro name="snippet">
|
||||
<param name="id" value="jax-rs-provider-operation" />
|
||||
<param name="file" value="examples/src/main/java/example/JaxRsPatientRestProvider.java" />
|
||||
</macro>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In order to create the conformance profile, a conformance provider class needs to be deployed which exports the provider's conformance statements.
|
||||
These providers need to be returned as the result of
|
||||
the method <code><a href="http://jamesagnew.github.io/hapi-fhir/apidocs/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.html#getProviders">AbstractJaxRsResourceProvider#getProviders</a></code>.
|
||||
This method is called once, during <code><a href="https://docs.oracle.com/javaee/6/api/javax/annotation/PostConstruct.html">PostConstruct</a></code>.
|
||||
<macro name="snippet">
|
||||
<param name="id" value="jax-rs-conformance" />
|
||||
<param name="file" value="examples/src/main/java/example/JaxRsConformanceProvider.java" />
|
||||
</macro>
|
||||
</p>
|
||||
|
||||
|
||||
</subsection>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</document>
|
||||
|
|
Loading…
Reference in New Issue