Merge pull request #367 from SRiviere/jaxrs-sever-evolution
Jaxrs server evolution
This commit is contained in:
commit
cd18ee4fde
|
@ -0,0 +1,196 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JAX-RS Server
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2016 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.interceptor.Interceptors;
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
|
||||||
|
import ca.uhn.fhir.jaxrs.server.util.JaxRsMethodBindings;
|
||||||
|
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.method.BaseMethodBinding;
|
||||||
|
import ca.uhn.fhir.rest.server.BundleInclusionRule;
|
||||||
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.IPagingProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.IRestfulServer;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This server is the abstract superclass for all bundle providers. It exposes
|
||||||
|
* a large amount of the fhir api functionality using JAXRS
|
||||||
|
*
|
||||||
|
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("javadoc")
|
||||||
|
@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 AbstractJaxRsBundleProvider extends AbstractJaxRsProvider implements IRestfulServer<JaxRsRequest>, IBundleProvider {
|
||||||
|
|
||||||
|
/** the method bindings for this class */
|
||||||
|
private final JaxRsMethodBindings theBindings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default constructor. The method bindings are retrieved from the class
|
||||||
|
* being constructed.
|
||||||
|
*/
|
||||||
|
protected AbstractJaxRsBundleProvider() {
|
||||||
|
super();
|
||||||
|
theBindings = JaxRsMethodBindings.getMethodBindings(this, getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the ability to specify the {@link FhirContext}.
|
||||||
|
* @param ctx the {@link FhirContext} instance.
|
||||||
|
*/
|
||||||
|
protected AbstractJaxRsBundleProvider(final FhirContext ctx) {
|
||||||
|
super(ctx);
|
||||||
|
theBindings = JaxRsMethodBindings.getMethodBindings(this, getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 AbstractJaxRsBundleProvider(final Class<? extends AbstractJaxRsProvider> theProviderClass) {
|
||||||
|
theBindings = JaxRsMethodBindings.getMethodBindings(this, theProviderClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create all resources in one transaction
|
||||||
|
*
|
||||||
|
* @param resource the body of the post method containing the bundle of the resources 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 IOException {
|
||||||
|
return execute(getRequest(RequestTypeEnum.POST, RestOperationTypeEnum.TRANSACTION).resource(resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
public Response search()
|
||||||
|
throws IOException {
|
||||||
|
return execute(getRequest(RequestTypeEnum.GET, RestOperationTypeEnum.SEARCH_TYPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(final Builder theRequestBuilder, final String methodKey)
|
||||||
|
throws IOException {
|
||||||
|
final JaxRsRequest theRequest = theRequestBuilder.build();
|
||||||
|
final BaseMethodBinding<?> method = getBinding(theRequest.getRestOperationType(), methodKey);
|
||||||
|
try {
|
||||||
|
return (Response) method.invokeServer(this, theRequest);
|
||||||
|
}
|
||||||
|
catch (final Throwable theException) {
|
||||||
|
return handleException(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(final 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(final RestOperationTypeEnum restOperation, final 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the bindings defined in this resource provider
|
||||||
|
*
|
||||||
|
* @return the jax-rs method bindings
|
||||||
|
*/
|
||||||
|
public JaxRsMethodBindings getBindings() {
|
||||||
|
return theBindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package ca.uhn.fhir.jaxrs.server;
|
package ca.uhn.fhir.jaxrs.server;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.io.IOException;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR JAX-RS Server
|
* HAPI FHIR JAX-RS Server
|
||||||
|
@ -21,7 +20,7 @@ import java.util.Collections;
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -30,11 +29,18 @@ import java.util.Map.Entry;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.HttpHeaders;
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
|
||||||
|
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsResponseException;
|
||||||
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
|
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
|
||||||
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest.Builder;
|
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest.Builder;
|
||||||
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.server.AddProfileTagEnum;
|
import ca.uhn.fhir.rest.server.AddProfileTagEnum;
|
||||||
|
@ -43,7 +49,9 @@ import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||||
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
|
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
|
||||||
import ca.uhn.fhir.rest.server.IRestfulServerDefaults;
|
import ca.uhn.fhir.rest.server.IRestfulServerDefaults;
|
||||||
import ca.uhn.fhir.rest.server.IServerAddressStrategy;
|
import ca.uhn.fhir.rest.server.IServerAddressStrategy;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||||
|
import ca.uhn.fhir.util.OperationOutcomeUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the abstract superclass for all jaxrs providers. It contains some defaults implementing
|
* This is the abstract superclass for all jaxrs providers. It contains some defaults implementing
|
||||||
|
@ -55,6 +63,11 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
|
||||||
|
|
||||||
private final FhirContext CTX;
|
private final FhirContext CTX;
|
||||||
|
|
||||||
|
/** The default exception interceptor */
|
||||||
|
private static final JaxRsExceptionInterceptor DEFAULT_EXCEPTION_HANDLER = new JaxRsExceptionInterceptor();
|
||||||
|
private static final String PROCESSING = "processing";
|
||||||
|
private static final String ERROR = "error";
|
||||||
|
|
||||||
/** the uri info */
|
/** the uri info */
|
||||||
@Context
|
@Context
|
||||||
private UriInfo theUriInfo;
|
private UriInfo theUriInfo;
|
||||||
|
@ -78,7 +91,7 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
|
||||||
*
|
*
|
||||||
* @param ctx the {@link FhirContext} to support.
|
* @param ctx the {@link FhirContext} to support.
|
||||||
*/
|
*/
|
||||||
protected AbstractJaxRsProvider(FhirContext ctx) {
|
protected AbstractJaxRsProvider(final FhirContext ctx) {
|
||||||
CTX = ctx;
|
CTX = ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,9 +100,9 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
|
||||||
* @return the query parameters
|
* @return the query parameters
|
||||||
*/
|
*/
|
||||||
public Map<String, String[]> getParameters() {
|
public Map<String, String[]> getParameters() {
|
||||||
MultivaluedMap<String, String> queryParameters = getUriInfo().getQueryParameters();
|
final MultivaluedMap<String, String> queryParameters = getUriInfo().getQueryParameters();
|
||||||
HashMap<String, String[]> params = new HashMap<String, String[]>();
|
final HashMap<String, String[]> params = new HashMap<String, String[]>();
|
||||||
for (Entry<String, List<String>> paramEntry : queryParameters.entrySet()) {
|
for (final Entry<String, List<String>> paramEntry : queryParameters.entrySet()) {
|
||||||
params.put(paramEntry.getKey(), paramEntry.getValue().toArray(new String[paramEntry.getValue().size()]));
|
params.put(paramEntry.getKey(), paramEntry.getValue().toArray(new String[paramEntry.getValue().size()]));
|
||||||
}
|
}
|
||||||
return params;
|
return params;
|
||||||
|
@ -101,7 +114,7 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public IServerAddressStrategy getServerAddressStrategy() {
|
public IServerAddressStrategy getServerAddressStrategy() {
|
||||||
HardcodedServerAddressStrategy addressStrategy = new HardcodedServerAddressStrategy();
|
final HardcodedServerAddressStrategy addressStrategy = new HardcodedServerAddressStrategy();
|
||||||
addressStrategy.setValue(getBaseForRequest());
|
addressStrategy.setValue(getBaseForRequest());
|
||||||
return addressStrategy;
|
return addressStrategy;
|
||||||
}
|
}
|
||||||
|
@ -147,7 +160,7 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
|
||||||
* Set the Uri Info
|
* Set the Uri Info
|
||||||
* @param uriInfo the uri info
|
* @param uriInfo the uri info
|
||||||
*/
|
*/
|
||||||
public void setUriInfo(UriInfo uriInfo) {
|
public void setUriInfo(final UriInfo uriInfo) {
|
||||||
this.theUriInfo = uriInfo;
|
this.theUriInfo = uriInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,18 +176,29 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
|
||||||
* Set the headers
|
* Set the headers
|
||||||
* @param headers the headers to set
|
* @param headers the headers to set
|
||||||
*/
|
*/
|
||||||
public void setHeaders(HttpHeaders headers) {
|
public void setHeaders(final HttpHeaders headers) {
|
||||||
this.theHeaders = headers;
|
this.theHeaders = headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the requestbuilder for the server
|
||||||
|
* @param requestType the type of the request
|
||||||
|
* @param restOperation the rest operation type
|
||||||
|
* @param theResourceName the resource name
|
||||||
|
* @return the requestbuilder
|
||||||
|
*/
|
||||||
|
public Builder getRequest(final RequestTypeEnum requestType, final RestOperationTypeEnum restOperation, final String theResourceName) {
|
||||||
|
return new JaxRsRequest.Builder(this, requestType, restOperation, theUriInfo.getRequestUri().toString(), theResourceName);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the requestbuilder for the server
|
* Return the requestbuilder for the server
|
||||||
* @param requestType the type of the request
|
* @param requestType the type of the request
|
||||||
* @param restOperation the rest operation type
|
* @param restOperation the rest operation type
|
||||||
* @return the requestbuilder
|
* @return the requestbuilder
|
||||||
*/
|
*/
|
||||||
public Builder getRequest(RequestTypeEnum requestType, RestOperationTypeEnum restOperation) {
|
public Builder getRequest(final RequestTypeEnum requestType, final RestOperationTypeEnum restOperation) {
|
||||||
return new JaxRsRequest.Builder(this, requestType, restOperation, theUriInfo.getRequestUri().toString());
|
return getRequest(requestType, restOperation, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -217,4 +241,37 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEFAULT = false
|
||||||
|
*/
|
||||||
|
public boolean withStackTrace() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an exception to a response
|
||||||
|
* @param theRequest the incoming request
|
||||||
|
* @param theException the exception to convert
|
||||||
|
* @return response
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public Response handleException(final JaxRsRequest theRequest, final Throwable theException)
|
||||||
|
throws IOException {
|
||||||
|
if (theException instanceof JaxRsResponseException) {
|
||||||
|
return DEFAULT_EXCEPTION_HANDLER.convertExceptionIntoResponse(theRequest, (JaxRsResponseException) theException);
|
||||||
|
} else if (theException instanceof DataFormatException) {
|
||||||
|
return DEFAULT_EXCEPTION_HANDLER.convertExceptionIntoResponse(theRequest, new JaxRsResponseException(
|
||||||
|
new InvalidRequestException(theException.getMessage(), createOutcome((DataFormatException) theException))));
|
||||||
|
} else {
|
||||||
|
return DEFAULT_EXCEPTION_HANDLER.convertExceptionIntoResponse(theRequest,
|
||||||
|
DEFAULT_EXCEPTION_HANDLER.convertException(this, theException));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IBaseOperationOutcome createOutcome(final DataFormatException theException) {
|
||||||
|
final IBaseOperationOutcome oo = OperationOutcomeUtil.newInstance(getFhirContext());
|
||||||
|
final String detailsValue = theException.getMessage() + "\n\n" + ExceptionUtils.getStackTrace(theException);
|
||||||
|
OperationOutcomeUtil.addIssue(getFhirContext(), oo, ERROR, detailsValue, null, PROCESSING);
|
||||||
|
return oo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
|
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.JaxRsMethodBindings;
|
||||||
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
|
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
|
||||||
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest.Builder;
|
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest.Builder;
|
||||||
|
@ -58,10 +57,10 @@ import ca.uhn.fhir.rest.server.IRestfulServer;
|
||||||
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
|
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
|
||||||
*/
|
*/
|
||||||
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN })
|
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN })
|
||||||
@Consumes({ MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON,
|
@Consumes({ MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML })
|
||||||
Constants.CT_FHIR_XML })
|
|
||||||
@Interceptors(JaxRsExceptionInterceptor.class)
|
@Interceptors(JaxRsExceptionInterceptor.class)
|
||||||
public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> extends AbstractJaxRsProvider
|
public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> extends AbstractJaxRsProvider
|
||||||
|
|
||||||
implements IRestfulServer<JaxRsRequest>, IResourceProvider {
|
implements IRestfulServer<JaxRsRequest>, IResourceProvider {
|
||||||
|
|
||||||
/** the method bindings for this class */
|
/** the method bindings for this class */
|
||||||
|
@ -80,7 +79,7 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
* Provides the ability to specify the {@link FhirContext}.
|
* Provides the ability to specify the {@link FhirContext}.
|
||||||
* @param ctx the {@link FhirContext} instance.
|
* @param ctx the {@link FhirContext} instance.
|
||||||
*/
|
*/
|
||||||
protected AbstractJaxRsResourceProvider(FhirContext ctx) {
|
protected AbstractJaxRsResourceProvider(final FhirContext ctx) {
|
||||||
super(ctx);
|
super(ctx);
|
||||||
theBindings = JaxRsMethodBindings.getMethodBindings(this, getClass());
|
theBindings = JaxRsMethodBindings.getMethodBindings(this, getClass());
|
||||||
}
|
}
|
||||||
|
@ -93,7 +92,7 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
*
|
*
|
||||||
* @param theProviderClass the interface of the class
|
* @param theProviderClass the interface of the class
|
||||||
*/
|
*/
|
||||||
protected AbstractJaxRsResourceProvider(Class<? extends AbstractJaxRsProvider> theProviderClass) {
|
protected AbstractJaxRsResourceProvider(final Class<? extends AbstractJaxRsProvider> theProviderClass) {
|
||||||
super();
|
super();
|
||||||
theBindings = JaxRsMethodBindings.getMethodBindings(this, theProviderClass);
|
theBindings = JaxRsMethodBindings.getMethodBindings(this, theProviderClass);
|
||||||
}
|
}
|
||||||
|
@ -107,7 +106,7 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
* @param ctx the {@link FhirContext} instance.
|
* @param ctx the {@link FhirContext} instance.
|
||||||
* @param theProviderClass the interface of the class
|
* @param theProviderClass the interface of the class
|
||||||
*/
|
*/
|
||||||
protected AbstractJaxRsResourceProvider(FhirContext ctx, Class<? extends AbstractJaxRsProvider> theProviderClass) {
|
protected AbstractJaxRsResourceProvider(final FhirContext ctx, final Class<? extends AbstractJaxRsProvider> theProviderClass) {
|
||||||
super(ctx);
|
super(ctx);
|
||||||
theBindings = JaxRsMethodBindings.getMethodBindings(this, theProviderClass);
|
theBindings = JaxRsMethodBindings.getMethodBindings(this, theProviderClass);
|
||||||
}
|
}
|
||||||
|
@ -123,7 +122,8 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
public String getBaseForRequest() {
|
public String getBaseForRequest() {
|
||||||
try {
|
try {
|
||||||
return new URL(getUriInfo().getBaseUri().toURL(), getResourceType().getSimpleName()).toExternalForm();
|
return new URL(getUriInfo().getBaseUri().toURL(), getResourceType().getSimpleName()).toExternalForm();
|
||||||
} catch (Exception e) {
|
}
|
||||||
|
catch (final Exception e) {
|
||||||
// cannot happen
|
// cannot happen
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -137,8 +137,9 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
* @see <a href="https://www.hl7.org/fhir/http.html#create">https://www.hl7. org/fhir/http.html#create</a>
|
* @see <a href="https://www.hl7.org/fhir/http.html#create">https://www.hl7. org/fhir/http.html#create</a>
|
||||||
*/
|
*/
|
||||||
@POST
|
@POST
|
||||||
public Response create(final String resource) throws IOException {
|
public Response create(final String resource)
|
||||||
return execute(getRequest(RequestTypeEnum.POST, RestOperationTypeEnum.CREATE).resource(resource));
|
throws IOException {
|
||||||
|
return execute(getResourceRequest(RequestTypeEnum.POST, RestOperationTypeEnum.CREATE).resource(resource));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -149,8 +150,9 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
*/
|
*/
|
||||||
@POST
|
@POST
|
||||||
@Path("/_search")
|
@Path("/_search")
|
||||||
public Response searchWithPost() throws IOException {
|
public Response searchWithPost()
|
||||||
return execute(getRequest(RequestTypeEnum.POST, RestOperationTypeEnum.SEARCH_TYPE));
|
throws IOException {
|
||||||
|
return execute(getResourceRequest(RequestTypeEnum.POST, RestOperationTypeEnum.SEARCH_TYPE));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -160,8 +162,21 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
* @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/http.html#search">https://www.hl7.org/fhir/http.html#search</a>
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
public Response search() throws IOException {
|
public Response search()
|
||||||
return execute(getRequest(RequestTypeEnum.GET, RestOperationTypeEnum.SEARCH_TYPE));
|
throws IOException {
|
||||||
|
return execute(getResourceRequest(RequestTypeEnum.GET, RestOperationTypeEnum.SEARCH_TYPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an existing resource based on the given condition
|
||||||
|
* @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
|
||||||
|
public Response conditionalUpdate(final String resource)
|
||||||
|
throws IOException {
|
||||||
|
return execute(getResourceRequest(RequestTypeEnum.PUT, RestOperationTypeEnum.UPDATE).resource(resource));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -174,8 +189,21 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
*/
|
*/
|
||||||
@PUT
|
@PUT
|
||||||
@Path("/{id}")
|
@Path("/{id}")
|
||||||
public Response update(@PathParam("id") final String id, final String resource) throws IOException {
|
public Response update(@PathParam("id") final String id, final String resource)
|
||||||
return execute(getRequest(RequestTypeEnum.PUT, RestOperationTypeEnum.UPDATE).id(id).resource(resource));
|
throws IOException {
|
||||||
|
return execute(getResourceRequest(RequestTypeEnum.PUT, RestOperationTypeEnum.UPDATE).id(id).resource(resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a resource based on the given condition
|
||||||
|
*
|
||||||
|
* @return the response
|
||||||
|
* @see <a href="https://www.hl7.org/fhir/http.html#delete">https://www.hl7.org/fhir/http.html#delete</a>
|
||||||
|
*/
|
||||||
|
@DELETE
|
||||||
|
public Response delete()
|
||||||
|
throws IOException {
|
||||||
|
return execute(getResourceRequest(RequestTypeEnum.DELETE, RestOperationTypeEnum.DELETE));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -187,8 +215,9 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
*/
|
*/
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("/{id}")
|
@Path("/{id}")
|
||||||
public Response delete(@PathParam("id") final String id) throws IOException {
|
public Response delete(@PathParam("id") final String id)
|
||||||
return execute(getRequest(RequestTypeEnum.DELETE, RestOperationTypeEnum.DELETE).id(id));
|
throws IOException {
|
||||||
|
return execute(getResourceRequest(RequestTypeEnum.DELETE, RestOperationTypeEnum.DELETE).id(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -200,8 +229,9 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Path("/{id}")
|
@Path("/{id}")
|
||||||
public Response find(@PathParam("id") final String id) throws IOException {
|
public Response find(@PathParam("id") final String id)
|
||||||
return execute(getRequest(RequestTypeEnum.GET, RestOperationTypeEnum.READ).id(id));
|
throws IOException {
|
||||||
|
return execute(getResourceRequest(RequestTypeEnum.GET, RestOperationTypeEnum.READ).id(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -215,9 +245,10 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
* @return the response
|
* @return the response
|
||||||
* @see <a href="https://www.hl7.org/fhir/operations.html">https://www.hl7.org/fhir/operations.html</a>
|
* @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,
|
protected Response customOperation(final String resource, final RequestTypeEnum requestType, final String id,
|
||||||
String operationName, RestOperationTypeEnum operationType) throws IOException {
|
final String operationName, final RestOperationTypeEnum operationType)
|
||||||
Builder request = getRequest(requestType, operationType).resource(resource).id(id);
|
throws IOException {
|
||||||
|
final Builder request = getResourceRequest(requestType, operationType).resource(resource).id(id);
|
||||||
return execute(request, operationName);
|
return execute(request, operationName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,8 +264,7 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
@Path("/{id}/_history/{version}")
|
@Path("/{id}/_history/{version}")
|
||||||
public Response findHistory(@PathParam("id") final String id, @PathParam("version") final String version)
|
public Response findHistory(@PathParam("id") final String id, @PathParam("version") final String version)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Builder theRequest = getRequest(RequestTypeEnum.GET, RestOperationTypeEnum.VREAD).id(id)
|
final Builder theRequest = getResourceRequest(RequestTypeEnum.GET, RestOperationTypeEnum.VREAD).id(id).version(version);
|
||||||
.version(version);
|
|
||||||
return execute(theRequest);
|
return execute(theRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,10 +279,10 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Path("/{id}/{compartment}")
|
@Path("/{id}/{compartment}")
|
||||||
public Response findCompartment(@PathParam("id") final String id,
|
public Response findCompartment(@PathParam("id") final String id, @PathParam("compartment") final String compartment)
|
||||||
@PathParam("compartment") final String compartment) throws IOException {
|
throws IOException {
|
||||||
Builder theRequest = getRequest(RequestTypeEnum.GET, RestOperationTypeEnum.SEARCH_TYPE).id(id)
|
final Builder theRequest = getResourceRequest(RequestTypeEnum.GET, RestOperationTypeEnum.SEARCH_TYPE).id(id).compartment(
|
||||||
.compartment(compartment);
|
compartment);
|
||||||
return execute(theRequest, compartment);
|
return execute(theRequest, compartment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,13 +293,15 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
* @param methodKey the key determining the method to be executed
|
* @param methodKey the key determining the method to be executed
|
||||||
* @return the response
|
* @return the response
|
||||||
*/
|
*/
|
||||||
private Response execute(Builder theRequestBuilder, String methodKey) throws IOException {
|
private Response execute(final Builder theRequestBuilder, final String methodKey)
|
||||||
JaxRsRequest theRequest = theRequestBuilder.build();
|
throws IOException {
|
||||||
BaseMethodBinding<?> method = getBinding(theRequest.getRestOperationType(), methodKey);
|
final JaxRsRequest theRequest = theRequestBuilder.build();
|
||||||
|
final BaseMethodBinding<?> method = getBinding(theRequest.getRestOperationType(), methodKey);
|
||||||
try {
|
try {
|
||||||
return (Response) method.invokeServer(this, theRequest);
|
return (Response) method.invokeServer(this, theRequest);
|
||||||
} catch (JaxRsResponseException theException) {
|
}
|
||||||
return new JaxRsExceptionInterceptor().convertExceptionIntoResponse(theRequest, theException);
|
catch (final Throwable theException) {
|
||||||
|
return handleException(theRequest, theException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +311,8 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
* @param theRequestBuilder the requestBuilder that contains the information about the request
|
* @param theRequestBuilder the requestBuilder that contains the information about the request
|
||||||
* @return the response
|
* @return the response
|
||||||
*/
|
*/
|
||||||
private Response execute(Builder theRequestBuilder) throws IOException {
|
private Response execute(final Builder theRequestBuilder)
|
||||||
|
throws IOException {
|
||||||
return execute(theRequestBuilder, JaxRsMethodBindings.DEFAULT_METHOD_KEY);
|
return execute(theRequestBuilder, JaxRsMethodBindings.DEFAULT_METHOD_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,7 +323,7 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
* @param theBindingKey the key determining the method to be executed (needed for e.g. custom operation)
|
* @param theBindingKey the key determining the method to be executed (needed for e.g. custom operation)
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected BaseMethodBinding<?> getBinding(RestOperationTypeEnum restOperation, String theBindingKey) {
|
protected BaseMethodBinding<?> getBinding(final RestOperationTypeEnum restOperation, final String theBindingKey) {
|
||||||
return getBindings().getBinding(restOperation, theBindingKey);
|
return getBindings().getBinding(restOperation, theBindingKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,4 +359,13 @@ public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> ext
|
||||||
return theBindings;
|
return theBindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the request builder based on the resource name for the server
|
||||||
|
* @param requestType the type of the request
|
||||||
|
* @param restOperation the rest operation type
|
||||||
|
* @return the requestbuilder
|
||||||
|
*/
|
||||||
|
private Builder getResourceRequest(final RequestTypeEnum requestType, final RestOperationTypeEnum restOperation) {
|
||||||
|
return getRequest(requestType, restOperation, getResourceType().getSimpleName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ import ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor;
|
||||||
public class JaxRsExceptionInterceptor {
|
public class JaxRsExceptionInterceptor {
|
||||||
|
|
||||||
/** the existing exception handler which is able to convert exception into responses*/
|
/** the existing exception handler which is able to convert exception into responses*/
|
||||||
private ExceptionHandlingInterceptor exceptionHandler;
|
private final ExceptionHandlingInterceptor exceptionHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default constructor
|
* The default constructor
|
||||||
|
@ -54,7 +54,7 @@ public class JaxRsExceptionInterceptor {
|
||||||
* A utility constructor for unit testing
|
* A utility constructor for unit testing
|
||||||
* @param exceptionHandler the handler for the exception conversion
|
* @param exceptionHandler the handler for the exception conversion
|
||||||
*/
|
*/
|
||||||
JaxRsExceptionInterceptor(ExceptionHandlingInterceptor exceptionHandler) {
|
JaxRsExceptionInterceptor(final ExceptionHandlingInterceptor exceptionHandler) {
|
||||||
this.exceptionHandler = exceptionHandler;
|
this.exceptionHandler = exceptionHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,18 +65,29 @@ public class JaxRsExceptionInterceptor {
|
||||||
* @throws JaxRsResponseException an exception that can be handled by a jee container
|
* @throws JaxRsResponseException an exception that can be handled by a jee container
|
||||||
*/
|
*/
|
||||||
@AroundInvoke
|
@AroundInvoke
|
||||||
public Object intercept(final InvocationContext ctx) throws JaxRsResponseException {
|
public Object intercept(final InvocationContext ctx)
|
||||||
|
throws JaxRsResponseException {
|
||||||
try {
|
try {
|
||||||
return ctx.proceed();
|
return ctx.proceed();
|
||||||
} catch(final Exception theException) {
|
}
|
||||||
AbstractJaxRsProvider theServer = (AbstractJaxRsProvider) ctx.getTarget();
|
catch (final Exception theException) {
|
||||||
|
final AbstractJaxRsProvider theServer = (AbstractJaxRsProvider) ctx.getTarget();
|
||||||
throw convertException(theServer, theException);
|
throw convertException(theServer, theException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JaxRsResponseException convertException(final AbstractJaxRsProvider theServer, final Exception theException) {
|
/**
|
||||||
JaxRsRequest requestDetails = theServer.getRequest(null, null).build();
|
* This method convert an exception to a JaxRsResponseException
|
||||||
BaseServerResponseException convertedException = preprocessException(theException, requestDetails);
|
* @param theServer the provider
|
||||||
|
* @param theException the exception to convert
|
||||||
|
* @return JaxRsResponseException
|
||||||
|
*/
|
||||||
|
public JaxRsResponseException convertException(final AbstractJaxRsProvider theServer, final Throwable theException) {
|
||||||
|
if (theServer.withStackTrace()) {
|
||||||
|
exceptionHandler.setReturnStackTracesForExceptionTypes(Throwable.class);
|
||||||
|
}
|
||||||
|
final JaxRsRequest requestDetails = theServer.getRequest(null, null).build();
|
||||||
|
final BaseServerResponseException convertedException = preprocessException(theException, requestDetails);
|
||||||
return new JaxRsResponseException(convertedException);
|
return new JaxRsResponseException(convertedException);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,24 +98,31 @@ public class JaxRsExceptionInterceptor {
|
||||||
* @return the response describing the error
|
* @return the response describing the error
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public Response convertExceptionIntoResponse(JaxRsRequest theRequest, JaxRsResponseException theException)
|
public Response convertExceptionIntoResponse(final JaxRsRequest theRequest, final JaxRsResponseException theException)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return handleExceptionWithoutServletError(theRequest, theException);
|
return handleExceptionWithoutServletError(theRequest, theException);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BaseServerResponseException preprocessException(final Exception theException, JaxRsRequest requestDetails) {
|
private BaseServerResponseException preprocessException(final Throwable theException, final JaxRsRequest requestDetails) {
|
||||||
try {
|
try {
|
||||||
return exceptionHandler.preProcessOutgoingException(requestDetails, theException, null);
|
Throwable theExceptionToConvert = theException;
|
||||||
} catch(ServletException e) {
|
if (!(theException instanceof BaseServerResponseException) && (theException.getCause() instanceof BaseServerResponseException)) {
|
||||||
|
theExceptionToConvert = theException.getCause();
|
||||||
|
}
|
||||||
|
return exceptionHandler.preProcessOutgoingException(requestDetails, theExceptionToConvert, null);
|
||||||
|
}
|
||||||
|
catch (final ServletException e) {
|
||||||
return new InternalErrorException(e);
|
return new InternalErrorException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Response handleExceptionWithoutServletError(JaxRsRequest theRequest, BaseServerResponseException theException) throws IOException {
|
private Response handleExceptionWithoutServletError(final JaxRsRequest theRequest, final BaseServerResponseException theException)
|
||||||
|
throws IOException {
|
||||||
try {
|
try {
|
||||||
return (Response) exceptionHandler.handleException(theRequest, theException);
|
return (Response) exceptionHandler.handleException(theRequest, theException);
|
||||||
} catch (ServletException e) {
|
}
|
||||||
BaseServerResponseException newException = preprocessException(new InternalErrorException(e), theRequest);
|
catch (final ServletException e) {
|
||||||
|
final BaseServerResponseException newException = preprocessException(new InternalErrorException(e), theRequest);
|
||||||
return handleExceptionWithoutServletError(theRequest, newException);
|
return handleExceptionWithoutServletError(theRequest, newException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ public class JaxRsRequest extends RequestDetails {
|
||||||
private String myVersion;
|
private String myVersion;
|
||||||
private String myCompartment;
|
private String myCompartment;
|
||||||
private String myRequestUrl;
|
private String myRequestUrl;
|
||||||
|
private final String myResourceName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility Constructor
|
* Utility Constructor
|
||||||
|
@ -73,11 +74,12 @@ public class JaxRsRequest extends RequestDetails {
|
||||||
* @param theRequestUrl
|
* @param theRequestUrl
|
||||||
*/
|
*/
|
||||||
public Builder(AbstractJaxRsProvider theServer, RequestTypeEnum theRequestType,
|
public Builder(AbstractJaxRsProvider theServer, RequestTypeEnum theRequestType,
|
||||||
RestOperationTypeEnum theRestOperation, String theRequestUrl) {
|
RestOperationTypeEnum theRestOperation, String theRequestUrl, String theResourceName) {
|
||||||
this.myServer = theServer;
|
this.myServer = theServer;
|
||||||
this.myRequestType = theRequestType;
|
this.myRequestType = theRequestType;
|
||||||
this.myRestOperation = theRestOperation;
|
this.myRestOperation = theRestOperation;
|
||||||
this.myRequestUrl = theRequestUrl;
|
this.myRequestUrl = theRequestUrl;
|
||||||
|
this.myResourceName = theResourceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,6 +165,7 @@ public class JaxRsRequest extends RequestDetails {
|
||||||
|
|
||||||
result.setCompartmentName(myCompartment);
|
result.setCompartmentName(myCompartment);
|
||||||
result.setCompleteUrl(myRequestUrl);
|
result.setCompleteUrl(myRequestUrl);
|
||||||
|
result.setResourceName(myResourceName);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server;
|
||||||
|
|
||||||
|
@SuppressWarnings("javadoc")
|
||||||
|
public class AbstractJaxRsProviderMock extends AbstractJaxRsProvider {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsResponseException;
|
||||||
|
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
|
||||||
|
import ca.uhn.fhir.jaxrs.server.util.JaxRsResponse;
|
||||||
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
import ca.uhn.fhir.rest.server.IRestfulResponse;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
|
||||||
|
@SuppressWarnings("javadoc")
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class AbstractJaxRsProviderTest {
|
||||||
|
|
||||||
|
private AbstractJaxRsProviderMock provider;
|
||||||
|
@Mock
|
||||||
|
private JaxRsRequest theRequest;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
provider = new AbstractJaxRsProviderMock();
|
||||||
|
final IRestfulResponse response = new JaxRsResponse(theRequest);
|
||||||
|
doReturn(provider).when(theRequest).getServer();
|
||||||
|
doReturn(response).when(theRequest).getResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithStackTrace() {
|
||||||
|
assertFalse(provider.withStackTrace());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHandleExceptionJaxRsResponseException() throws IOException {
|
||||||
|
final ResourceNotFoundException base = new ResourceNotFoundException(new IdDt(1L));
|
||||||
|
final JaxRsResponseException theException = new JaxRsResponseException(base);
|
||||||
|
final Response result = provider.handleException(theRequest, theException);
|
||||||
|
assertNotNull(result);
|
||||||
|
assertEquals(base.getStatusCode(), result.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHandleExceptionDataFormatException() throws IOException {
|
||||||
|
final DataFormatException theException = new DataFormatException();
|
||||||
|
final Response result = provider.handleException(theRequest, theException);
|
||||||
|
assertNotNull(result);
|
||||||
|
assertEquals(Constants.STATUS_HTTP_400_BAD_REQUEST, result.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHandleExceptionRuntimeException() throws IOException, URISyntaxException {
|
||||||
|
final RuntimeException theException = new RuntimeException();
|
||||||
|
final UriInfo mockUriInfo = mock(UriInfo.class);
|
||||||
|
final MultivaluedMap<String, String> mockMap = mock(MultivaluedMap.class);
|
||||||
|
when(mockUriInfo.getBaseUri()).thenReturn(new URI("http://www.test.com"));
|
||||||
|
when(mockUriInfo.getRequestUri()).thenReturn(new URI("http://www.test.com/test"));
|
||||||
|
when(mockUriInfo.getQueryParameters()).thenReturn(mockMap);
|
||||||
|
|
||||||
|
provider.setUriInfo(mockUriInfo);
|
||||||
|
final Response result = provider.handleException(theRequest, theException);
|
||||||
|
assertNotNull(result);
|
||||||
|
assertEquals(Constants.STATUS_HTTP_500_INTERNAL_ERROR, result.getStatus());
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,10 +4,12 @@ import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.argThat;
|
import static org.mockito.Matchers.argThat;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Matchers.isNull;
|
import static org.mockito.Matchers.isNull;
|
||||||
|
|
||||||
import static org.mockito.Mockito.reset;
|
import static org.mockito.Mockito.reset;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
@ -78,6 +80,7 @@ public class AbstractJaxRsResourceProviderDstu3Test {
|
||||||
private static Server jettyServer;
|
private static Server jettyServer;
|
||||||
private TestJaxRsMockPatientRestProviderDstu3 mock;
|
private TestJaxRsMockPatientRestProviderDstu3 mock;
|
||||||
private ArgumentCaptor<IdType> idCaptor;
|
private ArgumentCaptor<IdType> idCaptor;
|
||||||
|
private ArgumentCaptor<String> conditionalCaptor;
|
||||||
private ArgumentCaptor<Patient> patientCaptor;
|
private ArgumentCaptor<Patient> patientCaptor;
|
||||||
|
|
||||||
private void compareResultId(int id, IBaseResource resource) {
|
private void compareResultId(int id, IBaseResource resource) {
|
||||||
|
@ -132,6 +135,7 @@ public class AbstractJaxRsResourceProviderDstu3Test {
|
||||||
this.mock = TestJaxRsMockPatientRestProviderDstu3.mock;
|
this.mock = TestJaxRsMockPatientRestProviderDstu3.mock;
|
||||||
idCaptor = ArgumentCaptor.forClass(IdType.class);
|
idCaptor = ArgumentCaptor.forClass(IdType.class);
|
||||||
patientCaptor = ArgumentCaptor.forClass(Patient.class);
|
patientCaptor = ArgumentCaptor.forClass(Patient.class);
|
||||||
|
conditionalCaptor = ArgumentCaptor.forClass(String.class);
|
||||||
reset(mock);
|
reset(mock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,11 +183,18 @@ public class AbstractJaxRsResourceProviderDstu3Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeletePatient() {
|
public void testDeletePatient() {
|
||||||
when(mock.delete(idCaptor.capture())).thenReturn(new MethodOutcome());
|
when(mock.delete(idCaptor.capture(), conditionalCaptor.capture())).thenReturn(new MethodOutcome());
|
||||||
final BaseOperationOutcome results = client.delete().resourceById("Patient", "1").execute();
|
final BaseOperationOutcome results = client.delete().resourceById("Patient", "1").execute();
|
||||||
assertEquals("1", idCaptor.getValue().getIdPart());
|
assertEquals("1", idCaptor.getValue().getIdPart());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConditionalDelete() throws Exception {
|
||||||
|
when(mock.delete(idCaptor.capture(), conditionalCaptor.capture())).thenReturn(new MethodOutcome());
|
||||||
|
client.delete().resourceConditionalByType("Patient").where(Patient.IDENTIFIER.exactly().identifier("2")).execute();
|
||||||
|
assertEquals("Patient?identifier=2&_format=json", conditionalCaptor.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
/** Extended Operations */
|
/** Extended Operations */
|
||||||
@Test
|
@Test
|
||||||
public void testExtendedOperations() {
|
public void testExtendedOperations() {
|
||||||
|
@ -357,17 +368,27 @@ public class AbstractJaxRsResourceProviderDstu3Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateById() throws Exception {
|
public void testUpdateById() throws Exception {
|
||||||
when(mock.update(idCaptor.capture(), patientCaptor.capture())).thenReturn(new MethodOutcome());
|
when(mock.update(idCaptor.capture(), patientCaptor.capture(), conditionalCaptor.capture())).thenReturn(new MethodOutcome());
|
||||||
client.update("1", createPatient(1));
|
client.update("1", createPatient(1));
|
||||||
assertEquals("1", idCaptor.getValue().getIdPart());
|
assertEquals("1", idCaptor.getValue().getIdPart());
|
||||||
compareResultId(1, patientCaptor.getValue());
|
compareResultId(1, patientCaptor.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConditionalUpdate() throws Exception {
|
||||||
|
when(mock.update(idCaptor.capture(), patientCaptor.capture(), conditionalCaptor.capture())).thenReturn(new MethodOutcome());
|
||||||
|
client.update().resource(createPatient(1)).conditional().where(Patient.IDENTIFIER.exactly().identifier("2")).execute();
|
||||||
|
|
||||||
|
compareResultId(1, patientCaptor.getValue());
|
||||||
|
assertEquals("Patient?identifier=2&_format=json", conditionalCaptor.getValue());
|
||||||
|
compareResultId(1, patientCaptor.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Ignore
|
@Ignore
|
||||||
@Test
|
@Test
|
||||||
public void testResourceNotFound() throws Exception {
|
public void testResourceNotFound() throws Exception {
|
||||||
when(mock.update(idCaptor.capture(), patientCaptor.capture())).thenThrow(ResourceNotFoundException.class);
|
when(mock.update(idCaptor.capture(), patientCaptor.capture(), conditionalCaptor.capture())).thenThrow(ResourceNotFoundException.class);
|
||||||
try {
|
try {
|
||||||
client.update("1", createPatient(2));
|
client.update("1", createPatient(2));
|
||||||
fail();
|
fail();
|
||||||
|
|
|
@ -80,6 +80,7 @@ public class AbstractJaxRsResourceProviderTest {
|
||||||
private static Server jettyServer;
|
private static Server jettyServer;
|
||||||
private TestJaxRsMockPatientRestProvider mock;
|
private TestJaxRsMockPatientRestProvider mock;
|
||||||
private ArgumentCaptor<IdDt> idCaptor;
|
private ArgumentCaptor<IdDt> idCaptor;
|
||||||
|
private ArgumentCaptor<String> conditionalCaptor;
|
||||||
private ArgumentCaptor<Patient> patientCaptor;
|
private ArgumentCaptor<Patient> patientCaptor;
|
||||||
|
|
||||||
private void compareResultId(int id, IResource resource) {
|
private void compareResultId(int id, IResource resource) {
|
||||||
|
@ -133,6 +134,7 @@ public class AbstractJaxRsResourceProviderTest {
|
||||||
this.mock = TestJaxRsMockPatientRestProvider.mock;
|
this.mock = TestJaxRsMockPatientRestProvider.mock;
|
||||||
idCaptor = ArgumentCaptor.forClass(IdDt.class);
|
idCaptor = ArgumentCaptor.forClass(IdDt.class);
|
||||||
patientCaptor = ArgumentCaptor.forClass(Patient.class);
|
patientCaptor = ArgumentCaptor.forClass(Patient.class);
|
||||||
|
conditionalCaptor = ArgumentCaptor.forClass(String.class);
|
||||||
reset(mock);
|
reset(mock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,11 +182,18 @@ public class AbstractJaxRsResourceProviderTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeletePatient() {
|
public void testDeletePatient() {
|
||||||
when(mock.delete(idCaptor.capture())).thenReturn(new MethodOutcome());
|
when(mock.delete(idCaptor.capture(), conditionalCaptor.capture())).thenReturn(new MethodOutcome());
|
||||||
final BaseOperationOutcome results = client.delete().resourceById("Patient", "1").execute();
|
final BaseOperationOutcome results = client.delete().resourceById("Patient", "1").execute();
|
||||||
assertEquals("1", idCaptor.getValue().getIdPart());
|
assertEquals("1", idCaptor.getValue().getIdPart());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConditionalDelete() throws Exception {
|
||||||
|
when(mock.delete(idCaptor.capture(), conditionalCaptor.capture())).thenReturn(new MethodOutcome());
|
||||||
|
client.delete().resourceConditionalByType("Patient").where(Patient.IDENTIFIER.exactly().identifier("2")).execute();
|
||||||
|
assertEquals("Patient?identifier=2&_format=json", conditionalCaptor.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
/** Extended Operations */
|
/** Extended Operations */
|
||||||
@Test
|
@Test
|
||||||
public void testExtendedOperations() {
|
public void testExtendedOperations() {
|
||||||
|
@ -344,17 +353,28 @@ public class AbstractJaxRsResourceProviderTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateById() throws Exception {
|
public void testUpdateById() throws Exception {
|
||||||
when(mock.update(idCaptor.capture(), patientCaptor.capture())).thenReturn(new MethodOutcome());
|
when(mock.update(idCaptor.capture(), patientCaptor.capture(), conditionalCaptor.capture())).thenReturn(new MethodOutcome());
|
||||||
client.update("1", createPatient(1));
|
client.update("1", createPatient(1));
|
||||||
assertEquals("1", idCaptor.getValue().getIdPart());
|
assertEquals("1", idCaptor.getValue().getIdPart());
|
||||||
compareResultId(1, patientCaptor.getValue());
|
compareResultId(1, patientCaptor.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConditionalUpdate() throws Exception {
|
||||||
|
when(mock.update(idCaptor.capture(), patientCaptor.capture(), conditionalCaptor.capture())).thenReturn(new MethodOutcome());
|
||||||
|
client.update().resource(createPatient(1)).conditional().where(Patient.IDENTIFIER.exactly().identifier("2")).execute();
|
||||||
|
|
||||||
|
assertEquals("1", patientCaptor.getValue().getId().getIdPart());
|
||||||
|
assertEquals("Patient?identifier=2&_format=json", conditionalCaptor.getValue());
|
||||||
|
compareResultId(1, patientCaptor.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Ignore
|
@Ignore
|
||||||
@Test
|
@Test
|
||||||
public void testResourceNotFound() throws Exception {
|
public void testResourceNotFound() throws Exception {
|
||||||
when(mock.update(idCaptor.capture(), patientCaptor.capture())).thenThrow(ResourceNotFoundException.class);
|
when(mock.update(idCaptor.capture(), patientCaptor.capture(), conditionalCaptor.capture())).thenThrow(ResourceNotFoundException.class);
|
||||||
try {
|
try {
|
||||||
client.update("1", createPatient(2));
|
client.update("1", createPatient(2));
|
||||||
fail();
|
fail();
|
||||||
|
|
|
@ -76,8 +76,8 @@ public class TestJaxRsMockPatientRestProvider extends AbstractJaxRsResourceProvi
|
||||||
}
|
}
|
||||||
|
|
||||||
@Update
|
@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,@ConditionalUrlParam final String theConditional) throws Exception {
|
||||||
return mock.update(theId, patient);
|
return mock.update(theId, patient, theConditional);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Read
|
@Read
|
||||||
|
@ -97,8 +97,8 @@ public class TestJaxRsMockPatientRestProvider extends AbstractJaxRsResourceProvi
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
public MethodOutcome delete(@IdParam final IdDt theId) {
|
public MethodOutcome delete(@IdParam final IdDt theId, @ConditionalUrlParam final String theConditional) {
|
||||||
return mock.delete(theId);
|
return mock.delete(theId, theConditional);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Search(compartmentName = "Condition")
|
@Search(compartmentName = "Condition")
|
||||||
|
|
|
@ -78,8 +78,8 @@ public class TestJaxRsMockPatientRestProviderDstu3 extends AbstractJaxRsResource
|
||||||
}
|
}
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
public MethodOutcome update(@IdParam final IdType theId, @ResourceParam final Patient patient) throws Exception {
|
public MethodOutcome update(@IdParam final IdType theId, @ResourceParam final Patient patient,@ConditionalUrlParam final String theConditional) throws Exception {
|
||||||
return mock.update(theId, patient);
|
return mock.update(theId, patient, theConditional);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Read
|
@Read
|
||||||
|
@ -99,8 +99,8 @@ public class TestJaxRsMockPatientRestProviderDstu3 extends AbstractJaxRsResource
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
public MethodOutcome delete(@IdParam final IdType theId) {
|
public MethodOutcome delete(@IdParam final IdType theId, @ConditionalUrlParam final String theConditional) {
|
||||||
return mock.delete(theId);
|
return mock.delete(theId, theConditional);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Search(compartmentName = "Condition")
|
@Search(compartmentName = "Condition")
|
||||||
|
|
Loading…
Reference in New Issue