add javadoc + create builder for jaxrsrequest
This commit is contained in:
parent
63db1b646f
commit
5a7d2b40e8
|
@ -18,11 +18,12 @@ import javax.ws.rs.Produces;
|
|||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
|
||||
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest.Builder;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Conformance;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
|
@ -39,28 +40,43 @@ import ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider;
|
|||
import ca.uhn.fhir.util.ReflectionUtil;
|
||||
|
||||
/**
|
||||
* Conformance Rest Service
|
||||
* This is the conformance provider for the jax rs servers. It requires all providers to be registered
|
||||
* during startup because the conformance profile is generated during the postconstruct phase.
|
||||
* @author Peter Van Houte
|
||||
*/
|
||||
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProvider {
|
||||
public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProvider implements IResourceProvider {
|
||||
|
||||
public static final String PATH = "/";
|
||||
/** the logger */
|
||||
private static final org.slf4j.Logger ourLog = LoggerFactory.getLogger(AbstractJaxRsConformanceProvider.class);
|
||||
|
||||
/** the server bindings */
|
||||
private ResourceBinding myServerBinding = new ResourceBinding();
|
||||
/** the resource bindings */
|
||||
private ConcurrentHashMap<String, ResourceBinding> myResourceNameToBinding = new ConcurrentHashMap<String, ResourceBinding>();
|
||||
/** the server configuration */
|
||||
private RestulfulServerConfiguration serverConfiguration = new RestulfulServerConfiguration();
|
||||
|
||||
|
||||
/** the conformance. It is created once during startup */
|
||||
private Conformance myConformance;
|
||||
|
||||
public AbstractJaxRsConformanceProvider(String implementationDescription, String serverName, String serverVersion) {
|
||||
/**
|
||||
* Constructor allowing the description, servername and server to be set
|
||||
* @param implementationDescription the implementation description. If null, "" is used
|
||||
* @param serverName the server name. If null, "" is used
|
||||
* @param serverVersion the server version. If null, "" is used
|
||||
*/
|
||||
protected AbstractJaxRsConformanceProvider(String implementationDescription, String serverName, String serverVersion) {
|
||||
serverConfiguration.setFhirContext(getFhirContext());
|
||||
serverConfiguration.setImplementationDescription(implementationDescription);
|
||||
serverConfiguration.setServerName(serverName);
|
||||
serverConfiguration.setServerVersion(serverVersion);
|
||||
serverConfiguration.setImplementationDescription(StringUtils.defaultIfEmpty(implementationDescription, ""));
|
||||
serverConfiguration.setServerName(StringUtils.defaultIfEmpty(serverName, ""));
|
||||
serverConfiguration.setServerVersion(StringUtils.defaultIfEmpty(serverVersion, ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will set the conformance during the postconstruct phase. The
|
||||
* method {@link AbstractJaxRsConformanceProvider#getProviders()} is used to
|
||||
* get all the resource providers include in the conformance
|
||||
*/
|
||||
@PostConstruct
|
||||
protected void setUpPostConstruct() {
|
||||
for (Entry<Class<? extends IResourceProvider>, IResourceProvider> provider : getProviders().entrySet()) {
|
||||
|
@ -80,24 +96,45 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
|
|||
myConformance = serverConformanceProvider.getServerConformance(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method must return all the resource providers which need to be included in the conformance
|
||||
* @return a map of the resource providers and their corresponding classes. This class needs to be given
|
||||
* explicitly because retrieving the interface using {@link Object#getClass()} may not give the correct
|
||||
* interface in a jee environment.
|
||||
*/
|
||||
protected abstract ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> getProviders();
|
||||
|
||||
/**
|
||||
* This method will retrieve the conformance using the http OPTIONS method
|
||||
* @return the response containing the conformance
|
||||
*/
|
||||
@OPTIONS
|
||||
@Path("/metadata")
|
||||
public Response conformanceUsingOptions() throws IOException {
|
||||
return conformance();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will retrieve the conformance using the http GET method
|
||||
* @return the response containing the conformance
|
||||
*/
|
||||
@GET
|
||||
@Path("/metadata")
|
||||
public Response conformance() throws IOException {
|
||||
JaxRsRequest request = createRequestDetails(null, RequestTypeEnum.OPTIONS, RestOperationTypeEnum.METADATA);
|
||||
IRestfulResponse response = request.getResponse();
|
||||
Builder request = getRequest(RequestTypeEnum.OPTIONS, RestOperationTypeEnum.METADATA);
|
||||
IRestfulResponse response = request.build().getResponse();
|
||||
response.addHeader(Constants.HEADER_CORS_ALLOW_ORIGIN, "*");
|
||||
return (Response) response.returnResponse(ParseAction.create(myConformance), Constants.STATUS_HTTP_200_OK, true, null, getResourceType().getSimpleName());
|
||||
}
|
||||
|
||||
public int addProvider(Object theProvider, Class<?> theProviderInterface) throws ConfigurationException {
|
||||
/**
|
||||
* This method will add a provider to the conformance. This method is almost an exact copy of {@link ca.uhn.fhir.rest.server.RestfulServer#findResourceMethods }
|
||||
* @param theProvider an instance of the provider interface
|
||||
* @param theProviderInterface the class describing the providers interface
|
||||
* @return the numbers of basemethodbindings added
|
||||
* @see ca.uhn.fhir.rest.server.RestfulServer#findResourceMethods
|
||||
*/
|
||||
public int addProvider(IResourceProvider theProvider, Class<? extends IResourceProvider> theProviderInterface) throws ConfigurationException {
|
||||
int count = 0;
|
||||
|
||||
for (Method m : ReflectionUtil.getDeclaredMethods(theProviderInterface)) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.jaxrs.server;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.ws.rs.core.Context;
|
||||
|
@ -11,27 +12,30 @@ import javax.ws.rs.core.UriInfo;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
|
||||
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest.Builder;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.server.AddProfileTagEnum;
|
||||
import ca.uhn.fhir.rest.server.ETagSupportEnum;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.IRestfulServerDefaults;
|
||||
import ca.uhn.fhir.rest.server.IServerAddressStrategy;
|
||||
|
||||
/**
|
||||
* Abstract Jax Rs Rest Server
|
||||
* This is the abstract superclass for all jaxrs providers. It contains some defaults implementing
|
||||
* the IRestfulServerDefaults interface and exposes the uri and headers.
|
||||
* @author Peter Van Houte
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults, IResourceProvider {
|
||||
public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
|
||||
|
||||
public static FhirContext CTX = FhirContext.forDstu2();
|
||||
/** a static initialization for the fhircontext. Only DSTU2 is supported */
|
||||
private static final FhirContext CTX = FhirContext.forDstu2();
|
||||
|
||||
/** the uri info */
|
||||
@Context
|
||||
private UriInfo theUriInfo;
|
||||
/** the http headers */
|
||||
@Context
|
||||
private HttpHeaders theHeaders;
|
||||
|
||||
|
@ -40,10 +44,11 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults, I
|
|||
return CTX;
|
||||
}
|
||||
|
||||
/**
|
||||
* param and query methods
|
||||
/**
|
||||
* This method returns the query parameters
|
||||
* @return the query parameters
|
||||
*/
|
||||
public HashMap<String, String[]> getQueryMap() {
|
||||
public Map<String, String[]> getParameters() {
|
||||
MultivaluedMap<String, String> queryParameters = getUriInfo().getQueryParameters();
|
||||
HashMap<String, String[]> params = new HashMap<String, String[]>();
|
||||
for (Entry<String, List<String>> paramEntry : queryParameters.entrySet()) {
|
||||
|
@ -52,25 +57,36 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults, I
|
|||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the default server address strategy. The default strategy return the
|
||||
* base uri for the request {@link AbstractJaxRsProvider#getBaseForRequest() getBaseForRequest()}
|
||||
* @return
|
||||
*/
|
||||
public IServerAddressStrategy getServerAddressStrategy() {
|
||||
HardcodedServerAddressStrategy addressStrategy = new HardcodedServerAddressStrategy();
|
||||
addressStrategy.setValue(getBaseForRequest());
|
||||
return addressStrategy;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method returns the server base, independent of the request or resource.
|
||||
* @see javax.ws.rs.core.UriInfo#getBaseUri()
|
||||
* @return the ascii string for the server base
|
||||
*/
|
||||
public String getBaseForServer() {
|
||||
return getUriInfo().getBaseUri().toASCIIString();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the server base, including the resource path.
|
||||
* {@link javax.ws.rs.core.UriInfo#getBaseUri() UriInfo#getBaseUri()}
|
||||
* @return the ascii string for the base resource provider path
|
||||
*/
|
||||
public String getBaseForRequest() {
|
||||
return getBaseForServer();
|
||||
}
|
||||
|
||||
protected JaxRsRequest createRequestDetails(final String resourceString, RequestTypeEnum requestType, RestOperationTypeEnum restOperation) {
|
||||
return new JaxRsRequest(this, resourceString, requestType, restOperation);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Get the uriInfo
|
||||
* @return the uri info
|
||||
*/
|
||||
|
@ -101,30 +117,52 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults, I
|
|||
public void setHeaders(HttpHeaders headers) {
|
||||
this.theHeaders = headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the requestbuilder for the server
|
||||
* @param requestType the type of the request
|
||||
* @param restOperation the rest operation type
|
||||
* @return the requestbuilder
|
||||
*/
|
||||
public Builder getRequest(RequestTypeEnum requestType, RestOperationTypeEnum restOperation) {
|
||||
return new JaxRsRequest.Builder(this, requestType, restOperation);
|
||||
}
|
||||
|
||||
/**
|
||||
* DEFAULT VALUES
|
||||
* DEFAULT = EncodingEnum.JSON
|
||||
*/
|
||||
@Override
|
||||
public EncodingEnum getDefaultResponseEncoding() {
|
||||
return EncodingEnum.JSON;
|
||||
}
|
||||
|
||||
/**
|
||||
* DEFAULT = true
|
||||
*/
|
||||
@Override
|
||||
public boolean isDefaultPrettyPrint() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* DEFAULT = ETagSupportEnum.DISABLED
|
||||
*/
|
||||
@Override
|
||||
public ETagSupportEnum getETagSupport() {
|
||||
return ETagSupportEnum.DISABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* DEFAULT = AddProfileTagEnum.NEVER
|
||||
*/
|
||||
@Override
|
||||
public AddProfileTagEnum getAddProfileTag() {
|
||||
return AddProfileTagEnum.NEVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* DEFAULT = false
|
||||
*/
|
||||
@Override
|
||||
public boolean isUseBrowserFriendlyContentTypes() {
|
||||
return true;
|
||||
|
|
|
@ -17,187 +17,279 @@ import javax.ws.rs.Produces;
|
|||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import ca.uhn.fhir.jaxrs.server.interceptor.BaseServerRuntimeResponseException;
|
||||
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
|
||||
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsResponseException;
|
||||
import ca.uhn.fhir.jaxrs.server.util.JaxRsMethodBindings;
|
||||
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
|
||||
import ca.uhn.fhir.jaxrs.server.util.MethodBindings;
|
||||
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest.Builder;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.BundleInclusionRule;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.IPagingProvider;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.IRestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
||||
/**
|
||||
* Fhir Physician Rest Service
|
||||
* @author axmpm
|
||||
*
|
||||
* This server is the abstract superclass for all resource providers. It exposes
|
||||
* a large amount of the fhir api functionality using JAXRS
|
||||
* @author Peter Van Houte
|
||||
*/
|
||||
@Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN})
|
||||
@Consumes({MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML})
|
||||
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN })
|
||||
@Consumes({ MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON,
|
||||
Constants.CT_FHIR_XML })
|
||||
@Interceptors(JaxRsExceptionInterceptor.class)
|
||||
public abstract class AbstractJaxRsResourceProvider<R extends IResource> extends AbstractJaxRsProvider implements IRestfulServer<JaxRsRequest> {
|
||||
|
||||
private static final ExceptionHandlingInterceptor EXCEPTION_HANDLING_INTERCEPTOR = new ExceptionHandlingInterceptor();
|
||||
private final MethodBindings bindings;
|
||||
|
||||
public abstract class AbstractJaxRsResourceProvider<R extends IResource> extends AbstractJaxRsProvider
|
||||
implements IRestfulServer<JaxRsRequest>, IResourceProvider {
|
||||
|
||||
/** the method bindings for this class */
|
||||
private final JaxRsMethodBindings theBindings;
|
||||
|
||||
/**
|
||||
* The default constructor. The method bindings are retrieved from the class
|
||||
* being constructed.
|
||||
*/
|
||||
protected AbstractJaxRsResourceProvider() {
|
||||
bindings = MethodBindings.getMethodBindings(this, getClass());
|
||||
}
|
||||
theBindings = JaxRsMethodBindings.getMethodBindings(this, getClass());
|
||||
}
|
||||
|
||||
protected AbstractJaxRsResourceProvider(Class<?> subclass) {
|
||||
bindings = MethodBindings.getMethodBindings(this, subclass);
|
||||
}
|
||||
/**
|
||||
* This constructor takes in an explicit interface class. This subclass
|
||||
* should be identical to the class being constructed but is given
|
||||
* explicitly in order to avoid issues with proxy classes in a jee
|
||||
* environment.
|
||||
*
|
||||
* @param theProviderClass the interface of the class
|
||||
*/
|
||||
protected AbstractJaxRsResourceProvider(Class<? extends AbstractJaxRsProvider> theProviderClass) {
|
||||
theBindings = JaxRsMethodBindings.getMethodBindings(this, theProviderClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* The base for request for a resource provider has the following form:</br>
|
||||
* {@link AbstractJaxRsResourceProvider#getBaseForServer()
|
||||
* getBaseForServer()} + "/" +
|
||||
* {@link AbstractJaxRsResourceProvider#getResourceType() getResourceType()}
|
||||
* .{@link java.lang.Class#getSimpleName() getSimpleName()}
|
||||
*/
|
||||
@Override
|
||||
public String getBaseForRequest() {
|
||||
try {
|
||||
return new URL(getUriInfo().getBaseUri().toURL(), getResourceType().getSimpleName()).toExternalForm();
|
||||
} catch(Exception e) {
|
||||
// cannot happen
|
||||
return null;
|
||||
}
|
||||
}
|
||||
try {
|
||||
return new URL(getUriInfo().getBaseUri().toURL(), getResourceType().getSimpleName()).toExternalForm();
|
||||
} catch (Exception e) {
|
||||
// cannot happen
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@POST
|
||||
@Interceptors(JaxRsExceptionInterceptor.class)
|
||||
public Response create(final String resourceString)
|
||||
throws Exception {
|
||||
return executeMethod(resourceString, RequestTypeEnum.POST, RestOperationTypeEnum.CREATE, null);
|
||||
}
|
||||
/**
|
||||
* Create a new resource with a server assigned id
|
||||
*
|
||||
* @param resource the body of the post method containing resource being created in a xml/json form
|
||||
* @return the response
|
||||
* @see <a href="https://www.hl7.org/fhir/http.html#create">https://www.hl7. org/fhir/http.html#create</a>
|
||||
*/
|
||||
@POST
|
||||
public Response create(final String resource) throws Exception {
|
||||
return execute(getRequest(RequestTypeEnum.POST, RestOperationTypeEnum.CREATE).resource(resource));
|
||||
}
|
||||
|
||||
@POST
|
||||
@Interceptors(JaxRsExceptionInterceptor.class)
|
||||
@Path("/_search")
|
||||
public Response searchWithPost() throws Exception {
|
||||
return executeMethod(null, RequestTypeEnum.POST, RestOperationTypeEnum.SEARCH_TYPE, null);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Interceptors(JaxRsExceptionInterceptor.class)
|
||||
public Response search() throws Exception {
|
||||
return executeMethod(null, RequestTypeEnum.GET, RestOperationTypeEnum.SEARCH_TYPE, null);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("/{id}")
|
||||
@Interceptors(JaxRsExceptionInterceptor.class)
|
||||
public Response update(@PathParam("id") final String id, final String resourceString)
|
||||
throws Exception {
|
||||
return executeMethod(resourceString, RequestTypeEnum.PUT, RestOperationTypeEnum.UPDATE, id);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
@Interceptors(JaxRsExceptionInterceptor.class)
|
||||
public Response delete(@PathParam("id") final String id) throws Exception {
|
||||
return executeMethod(null, RequestTypeEnum.DELETE, RestOperationTypeEnum.DELETE, id);
|
||||
}
|
||||
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
@Interceptors(JaxRsExceptionInterceptor.class)
|
||||
public Response find(@PathParam("id") final String id) throws Exception {
|
||||
return executeMethod(null, RequestTypeEnum.GET, RestOperationTypeEnum.READ, id);
|
||||
}
|
||||
|
||||
protected Response customOperation(final String resource, RequestTypeEnum requestType, String id, String operationName, RestOperationTypeEnum operationType)
|
||||
throws Exception {
|
||||
Validate.notNull(resource, "resource may not be null");
|
||||
return executeMethod(resource, requestType, operationType, id, getBindings().getBinding(operationType, operationName));
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{id}/_history/{version}")
|
||||
@Interceptors(JaxRsExceptionInterceptor.class)
|
||||
public Response findHistory(@PathParam("id") final String id, @PathParam("version") final String versionString)
|
||||
throws BaseServerResponseException, IOException {
|
||||
BaseMethodBinding<?> method = getBindings().getBinding(RestOperationTypeEnum.VREAD);
|
||||
final RequestDetails theRequest = createRequestDetails(null, RequestTypeEnum.GET, RestOperationTypeEnum.VREAD);
|
||||
if (id == null) {
|
||||
throw new InvalidRequestException("Don't know how to handle request path: " + getUriInfo().getRequestUri().toASCIIString());
|
||||
}
|
||||
theRequest.setId(new IdDt(getBaseForRequest(), id, UrlUtil.unescape(versionString)));
|
||||
return (Response) method.invokeServer(this, theRequest);
|
||||
}
|
||||
/**
|
||||
* Search the resource type based on some filter criteria
|
||||
*
|
||||
* @return the response
|
||||
* @see <a href="https://www.hl7.org/fhir/http.html#search">https://www.hl7.org/fhir/http.html#search</a>
|
||||
*/
|
||||
@POST
|
||||
@Path("/_search")
|
||||
public Response searchWithPost() throws Exception {
|
||||
return execute(getRequest(RequestTypeEnum.POST, RestOperationTypeEnum.SEARCH_TYPE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the resource type based on some filter criteria
|
||||
*
|
||||
* @return the response
|
||||
* @see <a href="https://www.hl7.org/fhir/http.html#search">https://www.hl7.org/fhir/http.html#search</a>
|
||||
*/
|
||||
@GET
|
||||
@Path("/{id}/{compartment}")
|
||||
@Interceptors(JaxRsExceptionInterceptor.class)
|
||||
public Response findCompartment(@PathParam("id") final String id, @PathParam("compartment") final String compartment) throws BaseServerResponseException, IOException {
|
||||
BaseMethodBinding<?> method = getBindings().getBinding(RestOperationTypeEnum.SEARCH_TYPE, compartment);
|
||||
final RequestDetails theRequest = createRequestDetails(null, RequestTypeEnum.GET, RestOperationTypeEnum.VREAD);
|
||||
if (id == null) {
|
||||
throw new InvalidRequestException("Don't know how to handle request path: " + getUriInfo().getRequestUri().toASCIIString());
|
||||
}
|
||||
theRequest.setCompartmentName(compartment);
|
||||
theRequest.setId(new IdDt(getBaseForRequest(), id));
|
||||
return (Response) method.invokeServer(this, theRequest);
|
||||
}
|
||||
|
||||
private <T extends BaseMethodBinding<?>> Response executeMethod(final String resourceString, RequestTypeEnum requestType, RestOperationTypeEnum restOperation, String id)
|
||||
throws BaseServerResponseException, IOException {
|
||||
BaseMethodBinding<?> method = getBindings().getBinding(restOperation);
|
||||
return executeMethod(resourceString, requestType, restOperation, id, method);
|
||||
}
|
||||
public Response search() throws Exception {
|
||||
return execute(getRequest(RequestTypeEnum.GET, RestOperationTypeEnum.SEARCH_TYPE));
|
||||
}
|
||||
|
||||
private Response executeMethod(final String resourceString, RequestTypeEnum requestType, RestOperationTypeEnum restOperation, String id,
|
||||
BaseMethodBinding<?> method)
|
||||
throws IOException {
|
||||
final JaxRsRequest theRequest = createRequestDetails(resourceString, requestType, restOperation, id);
|
||||
try {
|
||||
return (Response) method.invokeServer(this, theRequest);
|
||||
} catch(BaseServerRuntimeResponseException theException) {
|
||||
return new JaxRsExceptionInterceptor().handleException(theRequest, theException);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected JaxRsRequest createRequestDetails(final String resourceString, RequestTypeEnum requestType, RestOperationTypeEnum restOperation, String id) {
|
||||
JaxRsRequest theRequest = super.createRequestDetails(resourceString, requestType, restOperation);
|
||||
theRequest.setId(StringUtils.isBlank(id) ? null : new IdDt(getResourceType().getName(), UrlUtil.unescape(id)));
|
||||
if(restOperation == RestOperationTypeEnum.UPDATE) {
|
||||
String contentLocation = theRequest.getHeader(Constants.HEADER_CONTENT_LOCATION);
|
||||
if (contentLocation != null) {
|
||||
theRequest.setId(new IdDt(contentLocation));
|
||||
}
|
||||
}
|
||||
return theRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Update an existing resource by its id (or create it if it is new)
|
||||
*
|
||||
* @param id the id of the resource
|
||||
* @param resource the body contents for the put method
|
||||
* @return the response
|
||||
* @see <a href="https://www.hl7.org/fhir/http.html#update">https://www.hl7.org/fhir/http.html#update</a>
|
||||
*/
|
||||
@PUT
|
||||
@Path("/{id}")
|
||||
public Response update(@PathParam("id") final String id, final String resource) throws Exception {
|
||||
return execute(getRequest(RequestTypeEnum.PUT, RestOperationTypeEnum.UPDATE).id(id).resource(resource));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a resource
|
||||
*
|
||||
* @param id the id of the resource to delete
|
||||
* @return the response
|
||||
* @see <a href="https://www.hl7.org/fhir/http.html#delete">https://www.hl7.org/fhir/http.html#delete</a>
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
public Response delete(@PathParam("id") final String id) throws Exception {
|
||||
return execute(getRequest(RequestTypeEnum.DELETE, RestOperationTypeEnum.DELETE).id(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the current state of the resource
|
||||
*
|
||||
* @param id the id of the resource to read
|
||||
* @return the response
|
||||
* @see <a href="https://www.hl7.org/fhir/http.html#read">https://www.hl7.org/fhir/http.html#read</a>
|
||||
*/
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
public Response find(@PathParam("id") final String id) throws Exception {
|
||||
return execute(getRequest(RequestTypeEnum.GET, RestOperationTypeEnum.READ).id(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a custom operation
|
||||
*
|
||||
* @param resource the resource to create
|
||||
* @param requestType the type of request
|
||||
* @param id the id of the resource on which to perform the operation
|
||||
* @param operationName the name of the operation to execute
|
||||
* @param operationType the rest operation type
|
||||
* @return the response
|
||||
* @see <a href="https://www.hl7.org/fhir/operations.html">https://www.hl7.org/fhir/operations.html</a>
|
||||
*/
|
||||
protected Response customOperation(final String resource, RequestTypeEnum requestType, String id,
|
||||
String operationName, RestOperationTypeEnum operationType) throws Exception {
|
||||
Builder request = getRequest(requestType, operationType).resource(resource).id(id);
|
||||
return execute(request, operationName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the update history for a particular resource
|
||||
*
|
||||
* @param id the id of the resource
|
||||
* @param version the version of the resource
|
||||
* @return the response
|
||||
* @see <a href="https://www.hl7.org/fhir/http.html#history">https://www.hl7.org/fhir/http.html#history</a>
|
||||
*/
|
||||
@GET
|
||||
@Path("/{id}/_history/{version}")
|
||||
public Response findHistory(@PathParam("id") final String id, @PathParam("version") final String version)
|
||||
throws IOException {
|
||||
Builder theRequest = getRequest(RequestTypeEnum.GET, RestOperationTypeEnum.VREAD).id(id)
|
||||
.version(version);
|
||||
return execute(theRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compartment Based Access
|
||||
*
|
||||
* @param id the resource to which the compartment belongs
|
||||
* @param compartment the compartment
|
||||
* @return the repsonse
|
||||
* @see <a href="https://www.hl7.org/fhir/http.html#search">https://www.hl7.org/fhir/http.html#search</a>
|
||||
* @see <a href="https://www.hl7.org/fhir/compartments.html#compartment">https://www.hl7.org/fhir/compartments.html#compartment</a>
|
||||
*/
|
||||
@GET
|
||||
@Path("/{id}/{compartment}")
|
||||
public Response findCompartment(@PathParam("id") final String id,
|
||||
@PathParam("compartment") final String compartment) throws IOException {
|
||||
Builder theRequest = getRequest(RequestTypeEnum.GET, RestOperationTypeEnum.SEARCH_TYPE).id(id)
|
||||
.compartment(compartment);
|
||||
return execute(theRequest, compartment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the method described by the requestBuilder and methodKey
|
||||
*
|
||||
* @param theRequestBuilder the requestBuilder that contains the information about the request
|
||||
* @param methodKey the key determining the method to be executed
|
||||
* @return the response
|
||||
*/
|
||||
private Response execute(Builder theRequestBuilder, String methodKey) throws IOException {
|
||||
JaxRsRequest theRequest = theRequestBuilder.build();
|
||||
BaseMethodBinding<?> method = getBinding(theRequest.getRestOperationType(), methodKey);
|
||||
try {
|
||||
return (Response) method.invokeServer(this, theRequest);
|
||||
} catch (JaxRsResponseException theException) {
|
||||
return new JaxRsExceptionInterceptor().convertExceptionIntoResponse(theRequest, theException);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the method described by the requestBuilder
|
||||
*
|
||||
* @param theRequestBuilder the requestBuilder that contains the information about the request
|
||||
* @return the response
|
||||
*/
|
||||
private Response execute(Builder theRequestBuilder) throws IOException {
|
||||
return execute(theRequestBuilder, JaxRsMethodBindings.DEFAULT_METHOD_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the method binding for the given rest operation
|
||||
*
|
||||
* @param restOperation the rest operation to retrieve
|
||||
* @param theBindingKey the key determining the method to be executed (needed for e.g. custom operation)
|
||||
* @return
|
||||
*/
|
||||
protected BaseMethodBinding<?> getBinding(RestOperationTypeEnum restOperation, String theBindingKey) {
|
||||
return getBindings().getBinding(restOperation, theBindingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default: an empty list of interceptors
|
||||
*
|
||||
* @see ca.uhn.fhir.rest.server.IRestfulServer#getInterceptors()
|
||||
*/
|
||||
@Override
|
||||
public List<IServerInterceptor> getInterceptors() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default: no paging provider
|
||||
*/
|
||||
@Override
|
||||
public IPagingProvider getPagingProvider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default: BundleInclusionRule.BASED_ON_INCLUDES
|
||||
*/
|
||||
@Override
|
||||
public BundleInclusionRule getBundleInclusionRule() {
|
||||
return BundleInclusionRule.BASED_ON_INCLUDES;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The resource type should return conform to the generic resource included
|
||||
* in the topic
|
||||
*/
|
||||
@Override
|
||||
public abstract Class<R> getResourceType();
|
||||
public abstract Class<R> getResourceType();
|
||||
|
||||
public MethodBindings getBindings() {
|
||||
return bindings;
|
||||
/**
|
||||
* Return the bindings defined in this resource provider
|
||||
*
|
||||
* @return the jax-rs method bindings
|
||||
*/
|
||||
public JaxRsMethodBindings getBindings() {
|
||||
return theBindings;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,55 +5,67 @@ import java.io.IOException;
|
|||
import javax.interceptor.AroundInvoke;
|
||||
import javax.interceptor.InvocationContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor;
|
||||
|
||||
/**
|
||||
* An interceptor that catches the jax-rs exceptions
|
||||
* @author Peter Van Houte
|
||||
*/
|
||||
public class JaxRsExceptionInterceptor {
|
||||
|
||||
/** the existing exception handler which is able to convert exception into responses*/
|
||||
private ExceptionHandlingInterceptor exceptionHandler;
|
||||
@Context
|
||||
private UriInfo info;
|
||||
@Context
|
||||
private HttpHeaders headers;
|
||||
|
||||
AbstractJaxRsProvider theServer;
|
||||
|
||||
FhirContext fhirContext = AbstractJaxRsProvider.CTX;
|
||||
|
||||
/**
|
||||
* The default constructor
|
||||
*/
|
||||
public JaxRsExceptionInterceptor() {
|
||||
this.exceptionHandler = new ExceptionHandlingInterceptor();
|
||||
}
|
||||
|
||||
public JaxRsExceptionInterceptor(ExceptionHandlingInterceptor exceptionHandler) {
|
||||
/**
|
||||
* A utility constructor for unit testing
|
||||
* @param exceptionHandler the handler for the exception conversion
|
||||
*/
|
||||
JaxRsExceptionInterceptor(ExceptionHandlingInterceptor exceptionHandler) {
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* This interceptor will catch all exception and convert them using the exceptionhandler
|
||||
* @param ctx the invocation context
|
||||
* @return the result
|
||||
* @throws JaxRsResponseException an exception that can be handled by a jee container
|
||||
*/
|
||||
@AroundInvoke
|
||||
public Object intercept(final InvocationContext ctx) throws Throwable {
|
||||
public Object intercept(final InvocationContext ctx) throws JaxRsResponseException {
|
||||
try {
|
||||
return ctx.proceed();
|
||||
} catch(final Exception theException) {
|
||||
theServer = (AbstractJaxRsProvider) ctx.getTarget();
|
||||
AbstractJaxRsProvider theServer = (AbstractJaxRsProvider) ctx.getTarget();
|
||||
throw convertException(theServer, theException);
|
||||
}
|
||||
}
|
||||
|
||||
public BaseServerRuntimeResponseException convertException(final AbstractJaxRsProvider theServer, final Exception theException) {
|
||||
JaxRsRequest requestDetails = new JaxRsRequest(theServer, null, null, null);
|
||||
private JaxRsResponseException convertException(final AbstractJaxRsProvider theServer, final Exception theException) {
|
||||
JaxRsRequest requestDetails = theServer.getRequest(null, null).build();
|
||||
BaseServerResponseException convertedException = preprocessException(theException, requestDetails);
|
||||
return new BaseServerRuntimeResponseException(convertedException);
|
||||
return new JaxRsResponseException(convertedException);
|
||||
}
|
||||
|
||||
public Response handleException(JaxRsRequest theRequest, BaseServerRuntimeResponseException theException)
|
||||
/**
|
||||
* This method converts an exception into a response
|
||||
* @param theRequest the request
|
||||
* @param theException the thrown exception
|
||||
* @return the response describing the error
|
||||
*/
|
||||
public Response convertExceptionIntoResponse(JaxRsRequest theRequest, JaxRsResponseException theException)
|
||||
throws IOException {
|
||||
return handleExceptionWithoutServletError(theRequest, theException);
|
||||
}
|
||||
|
|
|
@ -4,12 +4,21 @@ import javax.ejb.ApplicationException;
|
|||
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
|
||||
/**
|
||||
* A JEE wrapper exception that will not force a rollback.
|
||||
* @author Peter Van Houte
|
||||
*/
|
||||
@ApplicationException(rollback=false)
|
||||
public class BaseServerRuntimeResponseException extends BaseServerResponseException {
|
||||
public class JaxRsResponseException extends BaseServerResponseException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public BaseServerRuntimeResponseException(BaseServerResponseException base) {
|
||||
/**
|
||||
* Utility constructor
|
||||
*
|
||||
* @param base the base exception
|
||||
*/
|
||||
public JaxRsResponseException(BaseServerResponseException base) {
|
||||
super(base.getStatusCode(), base.getMessage(), base.getCause(), base.getOperationOutcome());
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
package ca.uhn.fhir.jaxrs.server.util;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsProvider;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
||||
import ca.uhn.fhir.rest.method.OperationMethodBinding;
|
||||
import ca.uhn.fhir.rest.method.SearchMethodBinding;
|
||||
import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException;
|
||||
import ca.uhn.fhir.util.ReflectionUtil;
|
||||
|
||||
/**
|
||||
* Class that contains the method bindings defined by a ResourceProvider
|
||||
* @author Peter Van Houte
|
||||
*/
|
||||
public class JaxRsMethodBindings {
|
||||
|
||||
/** DEFAULT_METHOD_KEY="" */
|
||||
public static final String DEFAULT_METHOD_KEY = "";
|
||||
/** Static collection of bindings mapped to a class*/
|
||||
private static final ConcurrentHashMap<Class<?>, JaxRsMethodBindings> classBindings = new ConcurrentHashMap<Class<?>, JaxRsMethodBindings>();
|
||||
/** Static collection of operationBindings mapped to a class */
|
||||
private ConcurrentHashMap<RestOperationTypeEnum, ConcurrentHashMap<String, BaseMethodBinding<?>>> operationBindings = new ConcurrentHashMap<RestOperationTypeEnum, ConcurrentHashMap<String,BaseMethodBinding<?>>>();
|
||||
|
||||
/**
|
||||
* The constructor
|
||||
* @param theProvider the provider which is an implementation of the theProviderClass
|
||||
* @param theProviderClass the class definition contaning the operations
|
||||
*/
|
||||
public JaxRsMethodBindings(AbstractJaxRsProvider theProvider, Class<? extends AbstractJaxRsProvider> theProviderClass) {
|
||||
for (final Method m : ReflectionUtil.getDeclaredMethods(theProviderClass)) {
|
||||
final BaseMethodBinding<?> foundMethodBinding = BaseMethodBinding.bindMethod(m, theProvider.getFhirContext(), theProvider);
|
||||
if (foundMethodBinding == null) {
|
||||
continue;
|
||||
}
|
||||
String bindingKey = getBindingKey(foundMethodBinding);
|
||||
addMethodBinding(bindingKey, foundMethodBinding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key for the baseMethodBinding. This is:
|
||||
* <ul>
|
||||
* <li>the compartName for SearchMethodBindings
|
||||
* <li>the methodName for OperationMethodBindings
|
||||
* <li> {@link #DEFAULT_METHOD_KEY} for all other MethodBindings
|
||||
* </ul>
|
||||
* @param theBinding the methodbinding
|
||||
* @return the key for the methodbinding.
|
||||
*/
|
||||
private String getBindingKey(final BaseMethodBinding<?> theBinding) {
|
||||
if (theBinding instanceof OperationMethodBinding) {
|
||||
return ((OperationMethodBinding) theBinding).getName();
|
||||
} else if (theBinding instanceof SearchMethodBinding) {
|
||||
Search search = theBinding.getMethod().getAnnotation(Search.class);
|
||||
return search.compartmentName();
|
||||
} else {
|
||||
return DEFAULT_METHOD_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
private void addMethodBinding(String key, BaseMethodBinding<?> binding) {
|
||||
ConcurrentHashMap<String, BaseMethodBinding<?>> mapByOperation = getMapForOperation(binding.getRestOperationType());
|
||||
if (mapByOperation.containsKey(key)) {
|
||||
throw new IllegalArgumentException("Multiple Search Method Bindings Found : " + mapByOperation.get(key) + " -- " + binding.getMethod());
|
||||
}
|
||||
mapByOperation.put(key, binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map for the given operation type. If no map exists for this operation type, create a new hashmap for this
|
||||
* operation type and add it to the operation bindings.
|
||||
*
|
||||
* @param operationType the operation type.
|
||||
* @return the map defined in the operation bindings
|
||||
*/
|
||||
private ConcurrentHashMap<String, BaseMethodBinding<?>> getMapForOperation(RestOperationTypeEnum operationType) {
|
||||
ConcurrentHashMap<String, BaseMethodBinding<?>> result = operationBindings.get(operationType);
|
||||
if(result == null) {
|
||||
operationBindings.putIfAbsent(operationType, new ConcurrentHashMap<String, BaseMethodBinding<?>>());
|
||||
return getMapForOperation(operationType);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the binding
|
||||
*
|
||||
* @param operationType the type of operation
|
||||
* @param theBindingKey the binding key
|
||||
* @return the binding defined
|
||||
* @throws NotImplementedOperationException cannot be found
|
||||
*/
|
||||
public BaseMethodBinding<?> getBinding(RestOperationTypeEnum operationType, String theBindingKey) {
|
||||
String bindingKey = StringUtils.defaultIfBlank(theBindingKey, DEFAULT_METHOD_KEY);
|
||||
ConcurrentHashMap<String, BaseMethodBinding<?>> map = operationBindings.get(operationType);
|
||||
if(map == null || !map.containsKey(bindingKey)) {
|
||||
throw new NotImplementedOperationException("Operation not implemented");
|
||||
} else {
|
||||
return map.get(bindingKey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the method bindings for the given class. If this class is not yet contained in the classBindings, they will be added for this class
|
||||
*
|
||||
* @param theProvider the implementation class
|
||||
* @param theProviderClass the provider class
|
||||
* @return the methodBindings for this class
|
||||
*/
|
||||
public static JaxRsMethodBindings getMethodBindings(AbstractJaxRsProvider theProvider, Class<? extends AbstractJaxRsProvider> theProviderClass) {
|
||||
if(!getClassBindings().containsKey(theProviderClass)) {
|
||||
JaxRsMethodBindings foundBindings = new JaxRsMethodBindings(theProvider, theProviderClass);
|
||||
getClassBindings().putIfAbsent(theProviderClass, foundBindings);
|
||||
}
|
||||
return getClassBindings().get(theProviderClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the classBindings
|
||||
*/
|
||||
static ConcurrentHashMap<Class<?>, JaxRsMethodBindings> getClassBindings() {
|
||||
return classBindings;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -11,21 +11,118 @@ import javax.ws.rs.core.HttpHeaders;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsProvider;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.ResourceParameter;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.IRestfulResponse;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
||||
/**
|
||||
* The JaxRsRequest is a jax-rs specific implementation of the RequestDetails.
|
||||
*
|
||||
* @author Peter Van Houte
|
||||
*/
|
||||
public class JaxRsRequest extends RequestDetails {
|
||||
|
||||
/**
|
||||
* An implementation of the builder pattern for the JaxRsRequest
|
||||
*/
|
||||
public static class Builder {
|
||||
private String theResource;
|
||||
private AbstractJaxRsProvider theServer;
|
||||
private RequestTypeEnum theRequestType;
|
||||
private RestOperationTypeEnum theRestOperation;
|
||||
private String theId;
|
||||
private String theVersion;
|
||||
private String theCompartment;
|
||||
|
||||
public Builder(AbstractJaxRsProvider theServer, RequestTypeEnum theRequestType,
|
||||
RestOperationTypeEnum theRestOperation) {
|
||||
this.theServer = theServer;
|
||||
this.theRequestType = theRequestType;
|
||||
this.theRestOperation = theRestOperation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource
|
||||
* @param resource the body contents of an http method
|
||||
* @return the builder
|
||||
*/
|
||||
public Builder resource(String resource) {
|
||||
this.theResource = resource;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the id
|
||||
* @param id the resource id
|
||||
* @return the builder
|
||||
*/
|
||||
public Builder id(String id) {
|
||||
this.theId = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the id version
|
||||
* @param version the version of the resource
|
||||
* @return the builder
|
||||
*/
|
||||
public Builder version(String version) {
|
||||
this.theVersion = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the compartment
|
||||
* @param compartment the compartment
|
||||
* @return the builder
|
||||
*/
|
||||
public Builder compartment(String compartment) {
|
||||
this.theCompartment = compartment;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the jax-rs request
|
||||
* @return the jax-rs request
|
||||
*/
|
||||
public JaxRsRequest build() {
|
||||
JaxRsRequest result = new JaxRsRequest(theServer, theResource, theRequestType, theRestOperation);
|
||||
if ((StringUtils.isNotBlank(theVersion) || StringUtils.isNotBlank(theCompartment))
|
||||
&& StringUtils.isBlank(theId)) {
|
||||
throw new InvalidRequestException("Don't know how to handle request path: "
|
||||
+ theServer.getUriInfo().getRequestUri().toASCIIString());
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(theVersion)) {
|
||||
result.setId(
|
||||
new IdDt(theServer.getBaseForRequest(), UrlUtil.unescape(theId), UrlUtil.unescape(theVersion)));
|
||||
} else if (StringUtils.isNotBlank(theId)) {
|
||||
result.setId(new IdDt(theServer.getBaseForRequest(), UrlUtil.unescape(theId)));
|
||||
}
|
||||
|
||||
if (theRestOperation == RestOperationTypeEnum.UPDATE) {
|
||||
String contentLocation = result.getHeader(Constants.HEADER_CONTENT_LOCATION);
|
||||
if (contentLocation != null) {
|
||||
result.setId(new IdDt(contentLocation));
|
||||
}
|
||||
}
|
||||
|
||||
result.setCompartmentName(theCompartment);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private String theResourceString;
|
||||
private HttpHeaders headers;
|
||||
private AbstractJaxRsProvider myServer;
|
||||
|
||||
public JaxRsRequest() {
|
||||
}
|
||||
|
||||
public JaxRsRequest(AbstractJaxRsProvider server, String resourceString, RequestTypeEnum requestType,
|
||||
RestOperationTypeEnum restOperation) {
|
||||
this.headers = server.getHeaders();
|
||||
|
@ -33,7 +130,7 @@ public class JaxRsRequest extends RequestDetails {
|
|||
this.setRestOperationType(restOperation);
|
||||
setServer(server);
|
||||
setFhirServerBase(server.getBaseForServer());
|
||||
setParameters(server.getQueryMap());
|
||||
setParameters(server.getParameters());
|
||||
setRequestType(requestType);
|
||||
}
|
||||
|
||||
|
@ -65,7 +162,8 @@ public class JaxRsRequest extends RequestDetails {
|
|||
|
||||
@Override
|
||||
protected byte[] getByteStreamRequestContents() {
|
||||
return StringUtils.defaultIfEmpty(theResourceString, "").getBytes(ResourceParameter.determineRequestCharset(this));
|
||||
return StringUtils.defaultIfEmpty(theResourceString, "")
|
||||
.getBytes(ResourceParameter.determineRequestCharset(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,6 +13,7 @@ import javax.ws.rs.core.Response.ResponseBuilder;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.method.ParseAction;
|
||||
|
@ -21,12 +22,26 @@ import ca.uhn.fhir.rest.server.EncodingEnum;
|
|||
import ca.uhn.fhir.rest.server.RestfulResponse;
|
||||
import ca.uhn.fhir.rest.server.RestfulServerUtils;
|
||||
|
||||
/**
|
||||
* The JaxRsResponse is a jax-rs specific implementation of the RestfulResponse.
|
||||
*
|
||||
* @author Peter Van Houte
|
||||
*/
|
||||
public class JaxRsResponse extends RestfulResponse<JaxRsRequest> {
|
||||
|
||||
public JaxRsResponse(JaxRsRequest jaxRsRequestDetails) {
|
||||
super(jaxRsRequestDetails);
|
||||
/**
|
||||
* The constructor
|
||||
*
|
||||
* @param request the JaxRs Request
|
||||
*/
|
||||
public JaxRsResponse(JaxRsRequest request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* The response writer is a simple String Writer. All output is configured
|
||||
* by the server.
|
||||
*/
|
||||
@Override
|
||||
public Writer getResponseWriter(int statusCode, String contentType, String charset, boolean respondGzip)
|
||||
throws UnsupportedEncodingException, IOException {
|
||||
|
@ -55,8 +70,8 @@ public class JaxRsResponse extends RestfulResponse<JaxRsRequest> {
|
|||
MethodOutcome response, String resourceName) throws IOException {
|
||||
StringWriter writer = new StringWriter();
|
||||
if (outcome != null) {
|
||||
IParser parser = RestfulServerUtils.getNewParser(getRequestDetails().getServer().getFhirContext(),
|
||||
getRequestDetails());
|
||||
FhirContext fhirContext = getRequestDetails().getServer().getFhirContext();
|
||||
IParser parser = RestfulServerUtils.getNewParser(fhirContext, getRequestDetails());
|
||||
outcome.execute(parser, writer);
|
||||
}
|
||||
return sendWriterResponse(operationStatus, getParserType(), null, writer);
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
package ca.uhn.fhir.jaxrs.server.util;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
||||
import ca.uhn.fhir.rest.method.OperationMethodBinding;
|
||||
import ca.uhn.fhir.rest.method.SearchMethodBinding;
|
||||
import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException;
|
||||
import ca.uhn.fhir.util.ReflectionUtil;
|
||||
|
||||
/**
|
||||
* @author Peter Van Houte
|
||||
* Class that contains the method bindings defined by a ResourceProvider
|
||||
*/
|
||||
public class MethodBindings {
|
||||
|
||||
/** Static collection of bindings mapped to a class*/
|
||||
private static final ConcurrentHashMap<Class<?>, MethodBindings> classBindings = new ConcurrentHashMap<Class<?>, MethodBindings>();
|
||||
/** Static collection of operationBindings mapped to a class */
|
||||
private ConcurrentHashMap<RestOperationTypeEnum, ConcurrentHashMap<String, BaseMethodBinding<?>>> operationBindings = new ConcurrentHashMap<RestOperationTypeEnum, ConcurrentHashMap<String,BaseMethodBinding<?>>>();
|
||||
|
||||
public <T extends AbstractJaxRsResourceProvider<?>> MethodBindings(T theProvider, Class<?> clazz) {
|
||||
for (final Method m : ReflectionUtil.getDeclaredMethods(clazz)) {
|
||||
final BaseMethodBinding<?> foundMethodBinding = BaseMethodBinding.bindMethod(m, theProvider.getFhirContext(), theProvider);
|
||||
if (foundMethodBinding == null) {
|
||||
continue;
|
||||
}
|
||||
String bindingKey = getBindingKey(foundMethodBinding);
|
||||
putIfAbsent(bindingKey, foundMethodBinding);
|
||||
}
|
||||
}
|
||||
|
||||
private String getBindingKey(final BaseMethodBinding<?> foundMethodBinding) {
|
||||
if (foundMethodBinding instanceof OperationMethodBinding) {
|
||||
return ((OperationMethodBinding) foundMethodBinding).getName();
|
||||
} else if (foundMethodBinding instanceof SearchMethodBinding) {
|
||||
Search search = foundMethodBinding.getMethod().getAnnotation(Search.class);
|
||||
return search.compartmentName();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private void putIfAbsent(String key, BaseMethodBinding<?> binding) {
|
||||
operationBindings.putIfAbsent(binding.getRestOperationType(), new ConcurrentHashMap<String, BaseMethodBinding<?>>());
|
||||
ConcurrentHashMap<String, BaseMethodBinding<?>> map = operationBindings.get(binding.getRestOperationType());
|
||||
if (map.containsKey(key)) {
|
||||
throw new IllegalArgumentException("Multiple Search Method Bindings Found : " + map.get(key) + " -- " + binding.getMethod());
|
||||
}
|
||||
map.put(key, binding);
|
||||
}
|
||||
|
||||
public BaseMethodBinding<?> getBinding(RestOperationTypeEnum operationType) {
|
||||
return getBinding(operationType, "");
|
||||
}
|
||||
|
||||
public BaseMethodBinding<?> getBinding(RestOperationTypeEnum operationType, String qualifier) {
|
||||
String nonEmptyQualifier = StringUtils.defaultIfBlank(qualifier, "");
|
||||
ConcurrentHashMap<String, BaseMethodBinding<?>> map = operationBindings.get(operationType);
|
||||
if(map == null || !map.containsKey(nonEmptyQualifier)) {
|
||||
throw new NotImplementedOperationException("Operation not implemented");
|
||||
} else {
|
||||
return map.get(nonEmptyQualifier);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T extends AbstractJaxRsResourceProvider<?>> MethodBindings getMethodBindings(T theProvider, Class<?> clazz) {
|
||||
if(!getClassBindings().containsKey(clazz)) {
|
||||
MethodBindings foundBindings = new MethodBindings(theProvider, clazz);
|
||||
getClassBindings().putIfAbsent(clazz, foundBindings);
|
||||
}
|
||||
return getClassBindings().get(clazz);
|
||||
}
|
||||
|
||||
public static ConcurrentHashMap<Class<?>, MethodBindings> getClassBindings() {
|
||||
return classBindings;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -19,8 +19,8 @@ import org.glassfish.jersey.server.ContainerRequest;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.jaxrs.server.example.TestDummyPatientProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.example.TestJaxRsMockPatientRestProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProvider;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
|
||||
|
@ -49,10 +49,18 @@ public class AbstractJaxRsConformanceProviderTest {
|
|||
@Test
|
||||
public void testConformance() throws Exception {
|
||||
providers.put(AbstractJaxRsConformanceProvider.class, provider);
|
||||
providers.put(TestDummyPatientProvider.class, new TestDummyPatientProvider());
|
||||
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 {
|
||||
|
|
|
@ -33,10 +33,10 @@ import org.mockito.ArgumentCaptor;
|
|||
import org.mockito.Matchers;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jaxrs.server.example.RandomServerPortProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.example.TestJaxRsConformanceRestProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.example.TestJaxRsMockPatientRestProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.interceptor.BaseServerRuntimeResponseException;
|
||||
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsResponseException;
|
||||
import ca.uhn.fhir.jaxrs.server.test.RandomServerPortProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsConformanceRestProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
|
||||
import ca.uhn.fhir.model.api.BundleEntry;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
|
@ -353,7 +353,7 @@ public class AbstractJaxRsResourceProviderTest {
|
|||
@Test
|
||||
public void testXFindUnknownPatient() {
|
||||
try {
|
||||
BaseServerRuntimeResponseException notFoundException = new BaseServerRuntimeResponseException(new ResourceNotFoundException(new IdDt("999955541264")));
|
||||
JaxRsResponseException notFoundException = new JaxRsResponseException(new ResourceNotFoundException(new IdDt("999955541264")));
|
||||
when(mock.find(idCaptor.capture())).thenThrow(notFoundException);
|
||||
client.read(Patient.class, "999955541264");
|
||||
fail();
|
||||
|
|
|
@ -24,7 +24,7 @@ import org.junit.Before;
|
|||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.example.TestDummyPatientProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
|
@ -41,10 +41,10 @@ public class JaxRsExceptionInterceptorTest {
|
|||
public void setUp() {
|
||||
interceptor = new JaxRsExceptionInterceptor();
|
||||
context = mock(InvocationContext.class);
|
||||
TestDummyPatientProvider provider = spy(TestDummyPatientProvider.class);
|
||||
TestJaxRsDummyPatientProvider provider = spy(TestJaxRsDummyPatientProvider.class);
|
||||
when(context.getTarget()).thenReturn(provider);
|
||||
doReturn("http://baseUri").when(provider).getBaseForServer();
|
||||
doReturn(new HashMap<String, String[]>()).when(provider).getQueryMap();
|
||||
doReturn(new HashMap<String, String[]>()).when(provider).getParameters();
|
||||
doReturn(mock(HttpHeaders.class)).when(provider).getHeaders();
|
||||
}
|
||||
|
||||
|
@ -85,20 +85,17 @@ public class JaxRsExceptionInterceptorTest {
|
|||
|
||||
@Test
|
||||
public void testHandleExceptionWithServletError() throws Throwable {
|
||||
JaxRsRequest request = new JaxRsRequest((AbstractJaxRsProvider) context.getTarget(), null, null, null);
|
||||
JaxRsRequest request = ((AbstractJaxRsProvider) context.getTarget()).getRequest(null, null).build();
|
||||
|
||||
ExceptionHandlingInterceptor exceptionHandler = spy(ExceptionHandlingInterceptor.class);
|
||||
doThrow(new ServletException("someMessage")).when(exceptionHandler).preProcessOutgoingException(any(RequestDetails.class), any(Throwable.class),
|
||||
isNull(HttpServletRequest.class));
|
||||
|
||||
interceptor = new JaxRsExceptionInterceptor(exceptionHandler);
|
||||
|
||||
when(context.proceed()).thenThrow(new ServletException());
|
||||
|
||||
BaseServerRuntimeResponseException thrownException = new BaseServerRuntimeResponseException(new NotImplementedOperationException("not implemented"));
|
||||
JaxRsResponseException thrownException = new JaxRsResponseException(new NotImplementedOperationException("not implemented"));
|
||||
doThrow(new javax.servlet.ServletException("someMessage")).when(exceptionHandler).handleException(request, thrownException);
|
||||
BaseServerRuntimeResponseException internalException = thrownException;
|
||||
Response result = interceptor.handleException(request, internalException);
|
||||
Response result = interceptor.convertExceptionIntoResponse(request, thrownException);
|
||||
assertEquals(InternalErrorException.STATUS_CODE, result.getStatus());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package ca.uhn.fhir.jaxrs.server.interceptor;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import javax.ejb.ApplicationException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
||||
|
||||
public class JaxRsResponseExceptionTest {
|
||||
|
||||
@Test
|
||||
public void testException() {
|
||||
ForbiddenOperationException wrappedException = new ForbiddenOperationException("someMessage");
|
||||
JaxRsResponseException response = new JaxRsResponseException(wrappedException);
|
||||
assertEquals(response.getMessage(), wrappedException.getMessage());
|
||||
assertEquals(response.getStatusCode(), wrappedException.getStatusCode());
|
||||
assertNotNull(response.getClass().getAnnotation(ApplicationException.class));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package ca.uhn.fhir.jaxrs.server.example;
|
||||
package ca.uhn.fhir.jaxrs.server.test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
|
@ -1,4 +1,4 @@
|
|||
package ca.uhn.fhir.jaxrs.server.example;
|
||||
package ca.uhn.fhir.jaxrs.server.test;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
@ -12,18 +12,15 @@ import ca.uhn.fhir.rest.server.Constants;
|
|||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
|
||||
/**
|
||||
* Fhir Physician Rest Service
|
||||
*
|
||||
* @author axmpm
|
||||
*
|
||||
* A conformance provider exposes the mock patient and this provider
|
||||
*/
|
||||
@Path(TestJaxRsConformanceRestProvider.PATH)
|
||||
@Path("")
|
||||
@Stateless
|
||||
@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML })
|
||||
public class TestJaxRsConformanceRestProvider extends AbstractJaxRsConformanceProvider {
|
||||
|
||||
public TestJaxRsConformanceRestProvider() {
|
||||
super("", "", "");
|
||||
super("description", "name", "version");
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,9 +1,12 @@
|
|||
package ca.uhn.fhir.jaxrs.server.example;
|
||||
package ca.uhn.fhir.jaxrs.server.test;
|
||||
|
||||
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
|
||||
public class TestDummyPatientProvider extends AbstractJaxRsResourceProvider<Patient> {
|
||||
/**
|
||||
* A dummy patient provider exposing no methods
|
||||
*/
|
||||
public class TestJaxRsDummyPatientProvider extends AbstractJaxRsResourceProvider<Patient> {
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
|
@ -1,9 +1,8 @@
|
|||
package ca.uhn.fhir.jaxrs.server.example;
|
||||
package ca.uhn.fhir.jaxrs.server.test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.interceptor.Interceptors;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
|
@ -15,7 +14,6 @@ import javax.ws.rs.core.Response;
|
|||
import org.mockito.Mockito;
|
||||
|
||||
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Parameters;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
|
@ -42,10 +40,7 @@ import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
|
|||
import ca.uhn.fhir.rest.server.IPagingProvider;
|
||||
|
||||
/**
|
||||
* Fhir Physician Rest Service
|
||||
*
|
||||
* @author axmpm
|
||||
*
|
||||
* A test server delegating each call to a mock
|
||||
*/
|
||||
@Path(TestJaxRsMockPatientRestProvider.PATH)
|
||||
@Stateless
|
||||
|
@ -96,7 +91,6 @@ public class TestJaxRsMockPatientRestProvider extends AbstractJaxRsResourceProvi
|
|||
|
||||
@GET
|
||||
@Path("/{id}/$someCustomOperation")
|
||||
@Interceptors(JaxRsExceptionInterceptor.class)
|
||||
public Response someCustomOperationUsingGet(@PathParam("id") String id, String resource) throws Exception {
|
||||
return customOperation(resource, RequestTypeEnum.GET, id, "$someCustomOperation",
|
||||
RestOperationTypeEnum.EXTENDED_OPERATION_TYPE);
|
||||
|
@ -109,7 +103,6 @@ public class TestJaxRsMockPatientRestProvider extends AbstractJaxRsResourceProvi
|
|||
|
||||
@POST
|
||||
@Path("/{id}/$someCustomOperation")
|
||||
@Interceptors(JaxRsExceptionInterceptor.class)
|
||||
public Response someCustomOperationUsingPost(@PathParam("id") String id, String resource) throws Exception {
|
||||
return customOperation(resource, RequestTypeEnum.POST, id, "$someCustomOperation",
|
||||
RestOperationTypeEnum.EXTENDED_OPERATION_TYPE);
|
|
@ -11,7 +11,7 @@ import org.junit.FixMethodOrder;
|
|||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
|
||||
import ca.uhn.fhir.jaxrs.server.example.TestDummyPatientProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProvider;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Parameters;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
|
@ -29,51 +29,51 @@ import ca.uhn.fhir.rest.param.StringParam;
|
|||
import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException;
|
||||
|
||||
@FixMethodOrder(MethodSorters.DEFAULT)
|
||||
public class MethodBindingsTest {
|
||||
public class JaxRsMethodBindingsTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MethodBindings.getClassBindings().clear();
|
||||
JaxRsMethodBindings.getClassBindings().clear();
|
||||
}
|
||||
|
||||
@Test(expected = NotImplementedOperationException.class)
|
||||
public void testFindMethodsForProviderNotDefinedMappingMethods() {
|
||||
new TestDummyPatientProvider().getBindings().getBinding(RestOperationTypeEnum.UPDATE, "");
|
||||
new TestJaxRsDummyPatientProvider().getBindings().getBinding(RestOperationTypeEnum.UPDATE, "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindMethodsForProviderWithMethods() {
|
||||
class TestFindPatientProvider extends TestDummyPatientProvider {
|
||||
class TestFindPatientProvider extends TestJaxRsDummyPatientProvider {
|
||||
@Search
|
||||
public List<Patient> search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
new TestFindPatientProvider();
|
||||
assertEquals(TestFindPatientProvider.class, new TestFindPatientProvider().getBindings().getBinding(RestOperationTypeEnum.SEARCH_TYPE).getMethod().getDeclaringClass());
|
||||
assertEquals(TestFindPatientProvider.class, new TestFindPatientProvider().getBindings().getBinding(RestOperationTypeEnum.SEARCH_TYPE, "").getMethod().getDeclaringClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindMethodsFor2ProvidersWithMethods() {
|
||||
class TestFindPatientProvider extends TestDummyPatientProvider {
|
||||
class TestFindPatientProvider extends TestJaxRsDummyPatientProvider {
|
||||
@Search
|
||||
public List<Patient> search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
class TestUpdatePatientProvider extends TestDummyPatientProvider {
|
||||
class TestUpdatePatientProvider extends TestJaxRsDummyPatientProvider {
|
||||
@Update
|
||||
public MethodOutcome update(@IdParam final IdDt theId, @ResourceParam final Patient patient) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
assertEquals(TestFindPatientProvider.class, new TestFindPatientProvider().getBindings().getBinding(RestOperationTypeEnum.SEARCH_TYPE).getMethod().getDeclaringClass());
|
||||
assertEquals(TestUpdatePatientProvider.class, new TestUpdatePatientProvider().getBindings().getBinding(RestOperationTypeEnum.UPDATE).getMethod().getDeclaringClass());
|
||||
assertEquals(TestFindPatientProvider.class, new TestFindPatientProvider().getBindings().getBinding(RestOperationTypeEnum.SEARCH_TYPE, "").getMethod().getDeclaringClass());
|
||||
assertEquals(TestUpdatePatientProvider.class, new TestUpdatePatientProvider().getBindings().getBinding(RestOperationTypeEnum.UPDATE, "").getMethod().getDeclaringClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindMethodsWithDoubleMethodsDeclaration() {
|
||||
class TestDoubleSearchProvider extends TestDummyPatientProvider {
|
||||
class TestDoubleSearchProvider extends TestJaxRsDummyPatientProvider {
|
||||
@Search
|
||||
public List<Patient> search1(@RequiredParam(name = Patient.SP_NAME) final StringParam name) {
|
||||
return null;
|
||||
|
@ -95,7 +95,7 @@ public class MethodBindingsTest {
|
|||
|
||||
@Test
|
||||
public void testFindMethodsWithMultipleMethods() {
|
||||
class TestFindPatientProvider extends TestDummyPatientProvider {
|
||||
class TestFindPatientProvider extends TestJaxRsDummyPatientProvider {
|
||||
@Search
|
||||
public List<Patient> search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) {
|
||||
return null;
|
||||
|
@ -113,9 +113,9 @@ public class MethodBindingsTest {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
MethodBindings bindings = new TestFindPatientProvider().getBindings();
|
||||
assertEquals("search", bindings.getBinding(RestOperationTypeEnum.SEARCH_TYPE).getMethod().getName());
|
||||
assertEquals("update", bindings.getBinding(RestOperationTypeEnum.UPDATE).getMethod().getName());
|
||||
JaxRsMethodBindings bindings = new TestFindPatientProvider().getBindings();
|
||||
assertEquals("search", bindings.getBinding(RestOperationTypeEnum.SEARCH_TYPE, "").getMethod().getName());
|
||||
assertEquals("update", bindings.getBinding(RestOperationTypeEnum.UPDATE, "").getMethod().getName());
|
||||
assertEquals("firstMethod", bindings.getBinding(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE, "$firstMethod").getMethod().getName());
|
||||
assertEquals("secondMethod", bindings.getBinding(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE, "$secondMethod").getMethod().getName());
|
||||
try {
|
|
@ -18,13 +18,12 @@ import javax.ws.rs.core.MultivaluedMap;
|
|||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.glassfish.jersey.internal.MapPropertiesDelegate;
|
||||
import org.glassfish.jersey.server.ContainerRequest;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.jaxrs.server.example.TestDummyPatientProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProvider;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
|
||||
|
@ -37,7 +36,7 @@ public class JaxRsRequestTest {
|
|||
private JaxRsRequest details;
|
||||
private MultivaluedMap<String, String> queryParameters = new MultivaluedHashMap<String, String>();
|
||||
private ContainerRequest headers;
|
||||
private TestDummyPatientProvider provider;
|
||||
private TestJaxRsDummyPatientProvider provider;
|
||||
|
||||
@Before
|
||||
public void setUp() throws URISyntaxException {
|
||||
|
@ -96,11 +95,6 @@ public class JaxRsRequestTest {
|
|||
assertEquals(this.provider, details.getServer());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJaxRsRequestDetails() {
|
||||
Validate.notNull(new JaxRsRequest());
|
||||
}
|
||||
|
||||
public JaxRsRequest createRequestDetails() throws URISyntaxException {
|
||||
//headers
|
||||
headers = new ContainerRequest(new URI(BASEURI), new URI(REQUESTURI), HttpMethod.GET, null, new MapPropertiesDelegate());
|
||||
|
@ -110,7 +104,7 @@ public class JaxRsRequestTest {
|
|||
when(uriInfo.getQueryParameters()).thenReturn(queryParameters);
|
||||
|
||||
//mocks
|
||||
provider = spy(TestDummyPatientProvider.class);
|
||||
provider = spy(TestJaxRsDummyPatientProvider.class);
|
||||
doReturn(uriInfo).when(provider).getUriInfo();
|
||||
doReturn(BASEURI).when(provider).getBaseForRequest();
|
||||
doReturn(BASEURI).when(provider).getBaseForServer();
|
||||
|
|
|
@ -3,12 +3,10 @@ package ca.uhn.fhir.jaxrs.server.util;
|
|||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
|
@ -153,22 +151,6 @@ public class JaxRsResponseTest {
|
|||
assertEquals(Constants.CT_XML+Constants.CHARSET_UTF8_CTSUFFIX, result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
|
||||
}
|
||||
|
||||
private String unzip(Object entity) throws IOException {
|
||||
byte[] compressed = ((String) entity).getBytes(Constants.CHARSET_NAME_UTF8);
|
||||
final int BUFFER_SIZE = 32;
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(compressed);
|
||||
GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
|
||||
StringBuilder string = new StringBuilder();
|
||||
byte[] data = new byte[BUFFER_SIZE];
|
||||
int bytesRead;
|
||||
while ((bytesRead = gis.read(data)) != -1) {
|
||||
string.append(new String(data, 0, bytesRead));
|
||||
}
|
||||
gis.close();
|
||||
is.close();
|
||||
return string.toString();
|
||||
}
|
||||
|
||||
private Bundle getSinglePatientResource() {
|
||||
Patient theResource = createPatient();
|
||||
Bundle bundle = Bundle.withSingleResource(theResource);
|
||||
|
|
|
@ -5,6 +5,7 @@ import javax.ws.rs.core.Application;
|
|||
|
||||
/**
|
||||
* Fhir Patient Demo Application
|
||||
*
|
||||
* @author Peter Van Houte
|
||||
*/
|
||||
@ApplicationPath(value=FhirPatientDemoApplication.PATH)
|
||||
|
|
|
@ -9,7 +9,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
|
||||
import javax.ejb.Local;
|
||||
import javax.ejb.Stateless;
|
||||
import javax.interceptor.Interceptors;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
|
@ -19,7 +18,6 @@ import javax.ws.rs.core.MediaType;
|
|||
import javax.ws.rs.core.Response;
|
||||
|
||||
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
|
||||
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Condition;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Parameters;
|
||||
|
@ -51,10 +49,7 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
|||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
|
||||
/**
|
||||
* Fhir Physician Rest Service
|
||||
*
|
||||
* @author axmpm
|
||||
*
|
||||
* A demo JaxRs Patient Rest Provider
|
||||
*/
|
||||
@Local
|
||||
@Path(JaxRsPatientRestProvider.PATH)
|
||||
|
@ -72,10 +67,10 @@ public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider<Pati
|
|||
}
|
||||
|
||||
static {
|
||||
patients.put("" + counter, createPatient("Van Houte"));
|
||||
patients.put("" + (counter), createPatient("Agnew"));
|
||||
patients.put(String.valueOf(counter), createPatient("Van Houte"));
|
||||
patients.put(String.valueOf(counter), createPatient("Agnew"));
|
||||
for (int i = 0; i < 20; i++) {
|
||||
patients.put("" + (counter), createPatient("Random Patient " + counter));
|
||||
patients.put(String.valueOf(counter), createPatient("Random Patient " + counter));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,7 +128,6 @@ public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider<Pati
|
|||
}
|
||||
|
||||
@Read
|
||||
@Interceptors(JaxRsExceptionInterceptor.class)
|
||||
public Patient find(@IdParam final IdDt theId) throws InvocationTargetException {
|
||||
if (patients.containsKey(theId.getIdPart())) {
|
||||
return getLast(patients.get(theId.getIdPart()));
|
||||
|
@ -180,9 +174,8 @@ public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider<Pati
|
|||
|
||||
@GET
|
||||
@Path("/{id}/$last")
|
||||
@Interceptors(JaxRsExceptionInterceptor.class)
|
||||
public Response operationLastGet(@PathParam("id") String id, String resource) throws Exception {
|
||||
return customOperation(resource, RequestTypeEnum.GET, id, "$last",
|
||||
public Response operationLastGet(@PathParam("id") String id) throws Exception {
|
||||
return customOperation(null, RequestTypeEnum.GET, id, "$last",
|
||||
RestOperationTypeEnum.EXTENDED_OPERATION_TYPE);
|
||||
}
|
||||
|
||||
|
@ -197,7 +190,6 @@ public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider<Pati
|
|||
|
||||
@POST
|
||||
@Path("/{id}/$last")
|
||||
@Interceptors(JaxRsExceptionInterceptor.class)
|
||||
public Response operationLast(final String resource) throws Exception {
|
||||
return customOperation(resource, RequestTypeEnum.POST, null, "$last",
|
||||
RestOperationTypeEnum.EXTENDED_OPERATION_TYPE);
|
||||
|
@ -206,7 +198,6 @@ public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider<Pati
|
|||
@Operation(name = "last", idempotent = true, returnParameters = {
|
||||
@OperationParam(name = "return", type = StringDt.class) })
|
||||
public Parameters last(@OperationParam(name = "dummy") StringDt dummyInput) throws InvocationTargetException {
|
||||
System.out.println("inputparameter");
|
||||
Parameters parameters = new Parameters();
|
||||
Patient patient = find(new IdDt(counter.intValue() - 1));
|
||||
parameters.addParameter().setName("return").setResource(patient)
|
||||
|
|
|
@ -63,8 +63,7 @@ public class JaxRsPatientProviderTest {
|
|||
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||
//client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/");
|
||||
client = ourCtx.newRestfulGenericClient("http://localhost:8580/hapi-fhir-jaxrsserver-example/jaxrs-demo/");
|
||||
client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/");
|
||||
client.setEncoding(EncodingEnum.JSON);
|
||||
client.registerInterceptor(new LoggingInterceptor(true));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue