Merge branch 'master' of github.com:jamesagnew/hapi-fhir

This commit is contained in:
jamesagnew 2016-05-05 07:00:07 -04:00
commit ed4a506542
37 changed files with 4535 additions and 93 deletions

View File

@ -43,6 +43,7 @@ import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseConformance;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
@ -169,7 +170,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
@Override
public BaseConformance conformance() {
public IBaseConformance conformance() {
if (myContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU2_HL7ORG)) {
throw new IllegalArgumentException("Must call fetchConformance() instead of conformance() for RI/DSTU3+ structures");
}
@ -183,7 +184,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
Class<BaseConformance> conformance = (Class<BaseConformance>) myContext.getResourceDefinition("Conformance").getImplementingClass();
ResourceResponseHandler<? extends BaseConformance> binding = new ResourceResponseHandler<BaseConformance>(conformance);
BaseConformance resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse);
IBaseConformance resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse);
return resp;
}
@ -2325,7 +2326,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
public MethodOutcome execute() {
BaseHttpClientInvocation invocation = ValidateMethodBindingDstu2.createValidateInvocation(myContext, myResource);
ResourceResponseHandler<BaseOperationOutcome> handler = new ResourceResponseHandler<BaseOperationOutcome>(null, null);
BaseOperationOutcome outcome = invoke(null, handler, invocation);
IBaseOperationOutcome outcome = invoke(null, handler, invocation);
MethodOutcome retVal = new MethodOutcome();
retVal.setOperationOutcome(outcome);
return retVal;

View File

@ -23,6 +23,7 @@ package ca.uhn.fhir.rest.client;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseConformance;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.model.api.Bundle;
@ -58,7 +59,7 @@ public interface IGenericClient extends IRestfulClient {
* @deprecated Use {@link #fetchConformance()} instead
*/
@Deprecated
BaseConformance conformance();
IBaseConformance conformance();
/**
* Fluent method for the "create" operation, which creates a new resource instance on the server

View File

@ -0,0 +1,84 @@
package ca.uhn.fhir.rest.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* 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.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.param.ResourceParameter;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.util.ParametersUtil;
public class ValidateMethodBindingDstu3 extends OperationMethodBinding {
public ValidateMethodBindingDstu3(Class<?> theReturnResourceType, Class<? extends IBaseResource> theReturnTypeFromRp, Method theMethod, FhirContext theContext, Object theProvider,
Validate theAnnotation) {
super(theReturnResourceType, theReturnTypeFromRp, theMethod, theContext, theProvider, true, Constants.EXTOP_VALIDATE, theAnnotation.type(), new OperationParam[0], BundleTypeEnum.COLLECTION);
List<IParameter> newParams = new ArrayList<IParameter>();
int idx = 0;
for (IParameter next : getParameters()) {
if (next instanceof ResourceParameter) {
if (IBaseResource.class.isAssignableFrom(((ResourceParameter) next).getResourceType())) {
Class<?> parameterType = theMethod.getParameterTypes()[idx];
if (String.class.equals(parameterType) || EncodingEnum.class.equals(parameterType)) {
newParams.add(next);
} else {
OperationParameter parameter = new OperationParameter(theContext, Constants.EXTOP_VALIDATE, Constants.EXTOP_VALIDATE_RESOURCE, 0, 1);
parameter.initializeTypes(theMethod, null, null, parameterType);
newParams.add(parameter);
}
} else {
newParams.add(next);
}
} else {
newParams.add(next);
}
idx++;
}
setParameters(newParams);
}
public static BaseHttpClientInvocation createValidateInvocation(FhirContext theContext, IBaseResource theResource) {
IBaseParameters parameters = (IBaseParameters) theContext.getResourceDefinition("Parameters").newInstance();
ParametersUtil.addParameterToParameters(theContext, parameters, theResource, "resource");
String resourceName = theContext.getResourceDefinition(theResource).getName();
String resourceId = theResource.getIdElement().getIdPart();
BaseHttpClientInvocation retVal = createOperationInvocation(theContext, resourceName, resourceId, Constants.EXTOP_VALIDATE, parameters, false);
return retVal;
}
}

View File

@ -151,7 +151,7 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
* </p>
*/
public void addHeadersToResponse(HttpServletResponse theHttpResponse) {
theHttpResponse.addHeader("X-Powered-By", "HAPI FHIR " + VersionUtil.getVersion() + " RESTful Server");
theHttpResponse.addHeader("X-Powered-By", "HAPI FHIR " + VersionUtil.getVersion() + " REST Server (FHIR Server; FHIR " + myFhirContext.getVersion().getVersion().name() + ")");
}
private void addLocationHeader(RequestDetails theRequest, HttpServletResponse theResponse, MethodOutcome response, String headerLocation, String resourceName) {
@ -570,6 +570,12 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
Map<String, String[]> params = null;
if (StringUtils.isNotBlank(theRequest.getQueryString())) {
completeUrl = requestUrl + "?" + theRequest.getQueryString();
/*
* By default, we manually parse the request params (the URL params, or the body for
* POST form queries) since Java containers can't be trusted to use UTF-8 encoding
* when parsing. Specifically Tomcat 7 and Glassfish 4.0 use 8859-1 for some dumb
* reason.... grr.....
*/
if (isIgnoreServerParsedRequestParameters()) {
String contentType = theRequest.getHeader(Constants.HEADER_CONTENT_TYPE);
if (theRequestType == RequestTypeEnum.POST && isNotBlank(contentType) && contentType.startsWith(Constants.CT_X_FORM_URLENCODED)) {

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.rest.server.interceptor;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.IOException;
/*
@ -31,12 +33,10 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.text.StrLookup;
import org.apache.commons.lang3.text.StrSubstitutor;
import org.apache.http.util.EncodingUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -58,15 +58,18 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
* </tr>
* <tr>
* <td>${idOrResourceName}</td>
* <td>The resource ID associated with this request, or the resource name if the request applies to a type but not an instance, or "" otherwise</td>
* <td>The resource ID associated with this request, or the resource name if the request applies to a type but not an
* instance, or "" otherwise</td>
* </tr>
* <tr>
* <td>${operationName}</td>
* <td>If the request is an extended operation (e.g. "$validate") this value will be the operation name, or "" otherwise</td>
* <td>If the request is an extended operation (e.g. "$validate") this value will be the operation name, or ""
* otherwise</td>
* </tr>
* <tr>
* <td>${operationType}</td>
* <td>A code indicating the operation type for this request, e.g. "read", "history-instance", "extended-operation-instance", etc.)</td>
* <td>A code indicating the operation type for this request, e.g. "read", "history-instance",
* "extended-operation-instance", etc.)</td>
* </tr>
* <tr>
* <td>${remoteAddr}</td>
@ -74,7 +77,8 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
* </tr>
* <tr>
* <td>${requestHeader.XXXX}</td>
* <td>The value of the HTTP request header named XXXX. For example, a substitution variable named "${requestHeader.x-forwarded-for} will yield the value of the first header named "x-forwarded-for
* <td>The value of the HTTP request header named XXXX. For example, a substitution variable named
* "${requestHeader.x-forwarded-for} will yield the value of the first header named "x-forwarded-for
* ", or "" if none.</td>
* </tr>
* <tr>
@ -83,15 +87,18 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
* </tr>
* <tr>
* <td>${responseEncodingNoDefault}</td>
* <td>The encoding format requested by the client via the _format parameter or the Accept header. Value will be "json" or "xml", or "" if the client did not explicitly request a format</td>
* <td>The encoding format requested by the client via the _format parameter or the Accept header. Value will be "json"
* or "xml", or "" if the client did not explicitly request a format</td>
* </tr>
* <tr>
* <td>${servletPath}</td>
* <td>The part of thre requesting URL that corresponds to the particular Servlet being called (see {@link HttpServletRequest#getServletPath()})</td>
* <td>The part of thre requesting URL that corresponds to the particular Servlet being called (see
* {@link HttpServletRequest#getServletPath()})</td>
* </tr>
* <tr>
* <td>${requestBodyFhir}</td>
* <td>The complete body of the request if the request has a FHIR content-type (this can be quite large!). Will emit an empty string if the content type is not a FHIR content type</td>
* <td>The complete body of the request if the request has a FHIR content-type (this can be quite large!). Will emit an
* empty string if the content type is not a FHIR content type</td>
* </tr>
* <tr>
* <td>${requestUrl}</td>
@ -122,10 +129,9 @@ public class LoggingInterceptor extends InterceptorAdapter {
public String getErrorMessageFormat() {
return myErrorMessageFormat;
}
@Override
public boolean handleException(RequestDetails theRequestDetails, BaseServerResponseException theException, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse)
throws ServletException, IOException {
public boolean handleException(RequestDetails theRequestDetails, BaseServerResponseException theException, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws ServletException, IOException {
if (myLogExceptions) {
// Perform any string substitutions from the message format
StrLookup<?> lookup = new MyLookup(theServletRequest, theException, theRequestDetails);
@ -187,7 +193,8 @@ public class LoggingInterceptor extends InterceptorAdapter {
}
/**
* Sets the message format itself. See the {@link LoggingInterceptor class documentation} for information on the format
* Sets the message format itself. See the {@link LoggingInterceptor class documentation} for information on the
* format
*/
public void setMessageFormat(String theMessageFormat) {
Validate.notBlank(theMessageFormat, "Message format can not be null/empty");
@ -290,16 +297,18 @@ public class LoggingInterceptor extends InterceptorAdapter {
return myRequest.getMethod();
} else if (theKey.equals("requestBodyFhir")) {
String contentType = myRequest.getContentType();
int colonIndex = contentType.indexOf(';');
if (colonIndex != -1) {
contentType = contentType.substring(0, colonIndex);
}
contentType = contentType.trim();
EncodingEnum encoding = EncodingEnum.forContentType(contentType);
if (encoding != null) {
byte[] requestContents = myRequestDetails.loadRequestContents();
return new String(requestContents, Charsets.UTF_8);
if (isNotBlank(contentType)) {
int colonIndex = contentType.indexOf(';');
if (colonIndex != -1) {
contentType = contentType.substring(0, colonIndex);
}
contentType = contentType.trim();
EncodingEnum encoding = EncodingEnum.forContentType(contentType);
if (encoding != null) {
byte[] requestContents = myRequestDetails.loadRequestContents();
return new String(requestContents, Charsets.UTF_8);
}
}
return "";
}

View File

@ -103,8 +103,10 @@ public class ServletRequestDetails extends RequestDetails {
String contentEncoding = myServletRequest.getHeader(Constants.HEADER_CONTENT_ENCODING);
if ("gzip".equals(contentEncoding)) {
ourLog.debug("Uncompressing (GZip) incoming content");
GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(requestContents));
requestContents = IOUtils.toByteArray(gis);
if (requestContents.length > 0) {
GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(requestContents));
requestContents = IOUtils.toByteArray(gis);
}
}
}

View File

@ -289,14 +289,17 @@ public class UrlUtil {
if (theString == null) {
return null;
}
if (theString.indexOf('%') == -1) {
return theString;
}
try {
return URLDecoder.decode(theString, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new Error("UTF-8 not supported, this shouldn't happen", e);
for (int i = 0; i < theString.length(); i++) {
char nextChar = theString.charAt(i);
if (nextChar == '%' || nextChar == '+') {
try {
return URLDecoder.decode(theString, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new Error("UTF-8 not supported, this shouldn't happen", e);
}
}
}
return theString;
}
public static class UrlParts {

View File

@ -40,6 +40,11 @@
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.6-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu3</artifactId>
<version>1.6-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>

View File

@ -39,12 +39,16 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.dstu3.hapi.rest.server.ServerConformanceProvider;
import org.hl7.fhir.dstu3.model.Conformance;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.LoggerFactory;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
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;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
@ -56,7 +60,6 @@ import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.IRestfulResponse;
import ca.uhn.fhir.rest.server.ResourceBinding;
import ca.uhn.fhir.rest.server.RestulfulServerConfiguration;
import ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider;
import ca.uhn.fhir.util.ReflectionUtil;
/**
@ -78,7 +81,8 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
private RestulfulServerConfiguration serverConfiguration = new RestulfulServerConfiguration();
/** the conformance. It is created once during startup */
private Conformance myConformance;
private Conformance myDstu3Conformance;
private ca.uhn.fhir.model.dstu2.resource.Conformance myDstu2Conformance;
/**
* Constructor allowing the description, servername and server to be set
@ -92,6 +96,21 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
serverConfiguration.setServerName(StringUtils.defaultIfEmpty(serverName, ""));
serverConfiguration.setServerVersion(StringUtils.defaultIfEmpty(serverVersion, ""));
}
/**
* Constructor allowing the description, servername and server to be set
* @param ctx the {@link FhirContext} instance.
* @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(FhirContext ctx, String implementationDescription, String serverName, String serverVersion) {
super(ctx);
serverConfiguration.setFhirContext(ctx);
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
@ -112,9 +131,15 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
HardcodedServerAddressStrategy hardcodedServerAddressStrategy = new HardcodedServerAddressStrategy();
hardcodedServerAddressStrategy.setValue(getBaseForServer());
serverConfiguration.setServerAddressStrategy(hardcodedServerAddressStrategy);
ServerConformanceProvider serverConformanceProvider = new ServerConformanceProvider(serverConfiguration);
serverConformanceProvider.initializeOperations();
myConformance = serverConformanceProvider.getServerConformance(null);
if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) {
ServerConformanceProvider serverConformanceProvider = new ServerConformanceProvider(serverConfiguration);
serverConformanceProvider.initializeOperations();
myDstu3Conformance = serverConformanceProvider.getServerConformance(null);
} else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2)) {
ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider serverConformanceProvider = new ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider(serverConfiguration);
serverConformanceProvider.initializeOperations();
myDstu2Conformance = serverConformanceProvider.getServerConformance(null);
}
}
/**
@ -145,7 +170,12 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
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());
if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) {
return (Response) response.returnResponse(ParseAction.create(myDstu3Conformance), Constants.STATUS_HTTP_200_OK, true, null, getResourceType().getSimpleName());
} else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2)) {
return (Response) response.returnResponse(ParseAction.create(myDstu2Conformance), Constants.STATUS_HTTP_200_OK, true, null, getResourceType().getSimpleName());
}
return (Response) response.returnResponse(null, Constants.STATUS_HTTP_500_INTERNAL_ERROR, true, null, getResourceType().getSimpleName());
}
/**
@ -217,9 +247,15 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
return count;
}
@SuppressWarnings("unchecked")
@Override
public Class<Conformance> getResourceType() {
return Conformance.class;
public Class<IBaseResource> getResourceType() {
if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) {
return Class.class.cast(Conformance.class);
} else if (super.getFhirContext().getVersion().getVersion().equals(FhirVersionEnum.DSTU2)) {
return Class.class.cast(ca.uhn.fhir.model.dstu2.resource.Conformance.class);
}
return null;
}
}

View File

@ -31,6 +31,7 @@ import javax.ws.rs.QueryParam;
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.interceptor.JaxRsResponseException;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
@ -65,6 +66,19 @@ public abstract class AbstractJaxRsPageProvider extends AbstractJaxRsProvider im
}
}
/**
* Provides the ability to set the {@link FhirContext} instance.
* @param ctx the {@link FhirContext} instance.
*/
protected AbstractJaxRsPageProvider(FhirContext ctx) {
super(ctx);
try {
myBinding = new PageMethodBinding(getFhirContext(), PageProvider.class.getMethod("getPage"));
} catch (Exception e) {
throw new ca.uhn.fhir.context.ConfigurationException(e);
}
}
@Override
public String getBaseForRequest() {
try {

View File

@ -53,8 +53,7 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
*/
public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
/** a static initialization for the fhircontext. Only DSTU2 is supported */
private static final FhirContext CTX = FhirContext.forDstu2();
private final FhirContext CTX;
/** the uri info */
@Context
@ -67,7 +66,22 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
public FhirContext getFhirContext() {
return CTX;
}
/**
* Default is DSTU2. Use {@link AbstractJaxRsProvider#AbstractJaxRsProvider(FhirContext)} to specify a DSTU3 context.
*/
protected AbstractJaxRsProvider() {
CTX = FhirContext.forDstu2();
}
/**
*
* @param ctx the {@link FhirContext} to support.
*/
protected AbstractJaxRsProvider(FhirContext ctx) {
CTX = ctx;
}
/**
* This method returns the query parameters
* @return the query parameters

View File

@ -22,8 +22,6 @@ package ca.uhn.fhir.jaxrs.server;
import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import javax.interceptor.Interceptors;
import javax.ws.rs.Consumes;
@ -37,12 +35,14 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.hl7.fhir.instance.model.api.IBaseResource;
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.JaxRsMethodBindings;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest.Builder;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.method.BaseMethodBinding;
@ -51,7 +51,6 @@ 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.interceptor.IServerInterceptor;
/**
* This server is the abstract superclass for all resource providers. It exposes
@ -62,7 +61,7 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
@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
public abstract class AbstractJaxRsResourceProvider<R extends IBaseResource> extends AbstractJaxRsProvider
implements IRestfulServer<JaxRsRequest>, IResourceProvider {
/** the method bindings for this class */
@ -73,9 +72,19 @@ public abstract class AbstractJaxRsResourceProvider<R extends IResource> extends
* being constructed.
*/
protected AbstractJaxRsResourceProvider() {
super();
theBindings = JaxRsMethodBindings.getMethodBindings(this, getClass());
}
/**
* Provides the ability to specify the {@link FhirContext}.
* @param ctx the {@link FhirContext} instance.
*/
protected AbstractJaxRsResourceProvider(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
@ -85,9 +94,24 @@ public abstract class AbstractJaxRsResourceProvider<R extends IResource> extends
* @param theProviderClass the interface of the class
*/
protected AbstractJaxRsResourceProvider(Class<? extends AbstractJaxRsProvider> theProviderClass) {
super();
theBindings = JaxRsMethodBindings.getMethodBindings(this, theProviderClass);
}
/**
* 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 ctx the {@link FhirContext} instance.
* @param theProviderClass the interface of the class
*/
protected AbstractJaxRsResourceProvider(FhirContext ctx, Class<? extends AbstractJaxRsProvider> theProviderClass) {
super(ctx);
theBindings = JaxRsMethodBindings.getMethodBindings(this, theProviderClass);
}
/**
* The base for request for a resource provider has the following form:</br>
* {@link AbstractJaxRsResourceProvider#getBaseForServer()

View File

@ -31,7 +31,9 @@ import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.dstu3.model.IdType;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsProvider;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
@ -129,18 +131,33 @@ public class JaxRsRequest extends RequestDetails {
throw new InvalidRequestException("Don't know how to handle request path: "
+ myServer.getUriInfo().getRequestUri().toASCIIString());
}
FhirVersionEnum fhirContextVersion = myServer.getFhirContext().getVersion().getVersion();
if (StringUtils.isNotBlank(myVersion)) {
result.setId(
new IdDt(myServer.getBaseForRequest(), UrlUtil.unescape(myId), UrlUtil.unescape(myVersion)));
if (FhirVersionEnum.DSTU3.equals(fhirContextVersion)) {
result.setId(
new IdType(myServer.getBaseForRequest(), UrlUtil.unescape(myId), UrlUtil.unescape(myVersion)));
} else if (FhirVersionEnum.DSTU2.equals(fhirContextVersion)) {
result.setId(
new IdDt(myServer.getBaseForRequest(), UrlUtil.unescape(myId), UrlUtil.unescape(myVersion)));
}
} else if (StringUtils.isNotBlank(myId)) {
result.setId(new IdDt(myServer.getBaseForRequest(), UrlUtil.unescape(myId)));
if (FhirVersionEnum.DSTU3.equals(fhirContextVersion)) {
result.setId(new IdType(myServer.getBaseForRequest(), UrlUtil.unescape(myId)));
} else if (FhirVersionEnum.DSTU2.equals(fhirContextVersion)) {
result.setId(new IdDt(myServer.getBaseForRequest(), UrlUtil.unescape(myId)));
}
}
if (myRestOperation == RestOperationTypeEnum.UPDATE) {
String contentLocation = result.getHeader(Constants.HEADER_CONTENT_LOCATION);
if (contentLocation != null) {
result.setId(new IdDt(contentLocation));
if (FhirVersionEnum.DSTU3.equals(fhirContextVersion)) {
result.setId(new IdType(contentLocation));
} else if (FhirVersionEnum.DSTU2.equals(fhirContextVersion)) {
result.setId(new IdDt(contentLocation));
}
}
}

View File

@ -0,0 +1,110 @@
package ca.uhn.fhir.jaxrs.server;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.net.URI;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.glassfish.jersey.internal.MapPropertiesDelegate;
import org.glassfish.jersey.server.ContainerRequest;
import org.junit.Before;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProvider;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProviderDstu3;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IResourceProvider;
public class AbstractJaxRsConformanceProviderDstu3Test {
private static final String BASEURI = "http://basiuri";
private static final String REQUESTURI = BASEURI + "/metadata";
AbstractJaxRsConformanceProvider provider;
private ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> providers;
private ContainerRequest headers;
private MultivaluedHashMap<String, String> queryParameters;
@Before
public void setUp() throws Exception {
// headers
headers = new ContainerRequest(new URI(BASEURI), new URI(REQUESTURI), HttpMethod.GET, null,
new MapPropertiesDelegate());
// uri info
queryParameters = new MultivaluedHashMap<String, String>();
providers = new ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider>();
provider = createConformanceProvider(providers);
}
@Test
public void testConformance() throws Exception {
providers.put(AbstractJaxRsConformanceProvider.class, provider);
providers.put(TestJaxRsDummyPatientProvider.class, new TestJaxRsDummyPatientProvider());
Response response = createConformanceProvider(providers).conformance();
System.out.println(response);
}
@Test
public void testConformanceUsingOptions() throws Exception {
providers.put(AbstractJaxRsConformanceProvider.class, provider);
providers.put(TestJaxRsDummyPatientProvider.class, new TestJaxRsDummyPatientProvider());
Response response = createConformanceProvider(providers).conformanceUsingOptions();
System.out.println(response);
}
@Test
public void testConformanceWithMethods() throws Exception {
providers.put(AbstractJaxRsConformanceProvider.class, provider);
providers.put(TestJaxRsMockPatientRestProviderDstu3.class, new TestJaxRsMockPatientRestProviderDstu3());
Response response = createConformanceProvider(providers).conformance();
assertEquals(Constants.STATUS_HTTP_200_OK, response.getStatus());
assertTrue(response.getEntity().toString().contains("\"type\":\"Patient\""));
assertTrue(response.getEntity().toString().contains("\"$someCustomOperation"));
System.out.println(response);
System.out.println(response.getEntity());
}
@Test
public void testConformanceInXml() throws Exception {
queryParameters.put(Constants.PARAM_FORMAT, Arrays.asList(Constants.CT_XML));
providers.put(AbstractJaxRsConformanceProvider.class, provider);
providers.put(TestJaxRsMockPatientRestProviderDstu3.class, new TestJaxRsMockPatientRestProviderDstu3());
Response response = createConformanceProvider(providers).conformance();
assertEquals(Constants.STATUS_HTTP_200_OK, response.getStatus());
System.out.println(response.getEntity());
assertTrue(response.getEntity().toString().contains(" <type value=\"Patient\"/>"));
assertTrue(response.getEntity().toString().contains("\"$someCustomOperation"));
System.out.println(response.getEntity());
}
private AbstractJaxRsConformanceProvider createConformanceProvider(final ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> providers)
throws Exception {
AbstractJaxRsConformanceProvider result = new AbstractJaxRsConformanceProvider(FhirContext.forDstu3(), null, null, null) {
@Override
protected ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> getProviders() {
return providers;
}
};
// mocks
UriInfo uriInfo = mock(UriInfo.class);
when(uriInfo.getQueryParameters()).thenReturn(queryParameters);
when(uriInfo.getBaseUri()).thenReturn(new URI(BASEURI));
when(uriInfo.getRequestUri()).thenReturn(new URI(BASEURI + "/foo"));
result.setUriInfo(uriInfo);
result.setHeaders(headers);
result.setUpPostConstruct();
return result;
}
}

View File

@ -0,0 +1,443 @@
package ca.uhn.fhir.jaxrs.server;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Conformance;
import org.hl7.fhir.dstu3.model.DateType;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Identifier;
import org.hl7.fhir.dstu3.model.Parameters;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Resource;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Matchers;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jaxrs.client.JaxRsRestfulClientFactory;
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsResponseException;
import ca.uhn.fhir.jaxrs.server.test.RandomServerPortProvider;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsConformanceRestProviderDstu3;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPageProviderDstu3;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProviderDstu3;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.client.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.method.SearchStyleEnum;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class AbstractJaxRsResourceProviderDstu3Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(AbstractJaxRsResourceProviderDstu3Test.class);
private static IGenericClient client;
private static final FhirContext ourCtx = FhirContext.forDstu3();
private static final String PATIENT_NAME = "Van Houte";
private static int ourPort;
private static String serverBase;
private static Server jettyServer;
private TestJaxRsMockPatientRestProviderDstu3 mock;
private ArgumentCaptor<IdType> idCaptor;
private ArgumentCaptor<Patient> patientCaptor;
private void compareResultId(int id, IBaseResource resource) {
assertEquals(id, Integer.parseInt(resource.getIdElement().getIdPart()));
}
private void compareResultUrl(String url, IBaseResource resource) {
assertEquals(url, resource.getIdElement().getValueAsString().substring(serverBase.length() - 1));
}
private Patient createPatient(long id) {
Patient theResource = new Patient();
theResource.setId(new IdType(id));
return theResource;
}
private List<Patient> createPatients(int firstId, int lastId) {
List<Patient> result = new ArrayList<Patient>(lastId - firstId);
for (long i = firstId; i <= lastId; i++) {
result.add(createPatient(i));
}
return result;
}
/** Find By Id */
@Test
public void findUsingGenericClientById() {
when(mock.find(any(IdType.class))).thenReturn(createPatient(1));
Patient result = client.read(Patient.class, "1");
compareResultId(1, result);
compareResultUrl("/Patient/1", result);
reset(mock);
when(mock.find(eq(result.getIdElement()))).thenReturn(createPatient(1));
result = (Patient) client.read(new UriDt(result.getId()));
compareResultId(1, result);
compareResultUrl("/Patient/1", result);
}
private Bundle getPatientBundle(int size) {
Bundle result = new Bundle();
for (long i = 0; i < size; i++) {
Patient patient = createPatient(i);
BundleEntryComponent entry = new BundleEntryComponent();
entry.setResource(patient);
result.addEntry(entry);
}
return result;
}
@Before
public void setUp() {
this.mock = TestJaxRsMockPatientRestProviderDstu3.mock;
idCaptor = ArgumentCaptor.forClass(IdType.class);
patientCaptor = ArgumentCaptor.forClass(Patient.class);
reset(mock);
}
/** Conditional Creates */
@Test
public void testConditionalCreate() throws Exception {
Patient toCreate = createPatient(1);
MethodOutcome outcome = new MethodOutcome();
toCreate.getIdentifier().add(new Identifier().setValue("myIdentifier"));
outcome.setResource(toCreate);
when(mock.create(patientCaptor.capture(), eq("Patient?_format=json&identifier=2"))).thenReturn(outcome);
client.setEncoding(EncodingEnum.JSON);
MethodOutcome response = client.create().resource(toCreate).conditional()
.where(Patient.IDENTIFIER.exactly().identifier("2")).prefer(PreferReturnEnum.REPRESENTATION).execute();
assertEquals("myIdentifier", patientCaptor.getValue().getIdentifier().get(0).getValue());
IBaseResource resource = response.getResource();
compareResultId(1, resource);
}
/** Conformance - Server */
@Test
public void testConformance() {
final Conformance conf = client.fetchConformance().ofType(Conformance.class).execute();
assertEquals(conf.getRest().get(0).getResource().get(0).getType().toString(), "Patient");
}
@Test
public void testCreatePatient() throws Exception {
Patient toCreate = createPatient(1);
MethodOutcome outcome = new MethodOutcome();
toCreate.getIdentifier().add(new Identifier().setValue("myIdentifier"));
outcome.setResource(toCreate);
when(mock.create(patientCaptor.capture(), isNull(String.class))).thenReturn(outcome);
client.setEncoding(EncodingEnum.JSON);
final MethodOutcome response = client.create().resource(toCreate).prefer(PreferReturnEnum.REPRESENTATION)
.execute();
IBaseResource resource = (IBaseResource) response.getResource();
compareResultId(1, resource);
assertEquals("myIdentifier", patientCaptor.getValue().getIdentifier().get(0).getValue());
}
@Test
public void testDeletePatient() {
when(mock.delete(idCaptor.capture())).thenReturn(new MethodOutcome());
final BaseOperationOutcome results = client.delete().resourceById("Patient", "1").execute();
assertEquals("1", idCaptor.getValue().getIdPart());
}
/** Extended Operations */
@Test
public void testExtendedOperations() {
// prepare mock
Parameters resultParameters = new Parameters();
resultParameters.addParameter().setName("return").setResource(createPatient(1)).setValue(new StringType("outputValue"));
when(mock.someCustomOperation(any(IdType.class), argThat(new StringTypeMatcher(new StringType("myAwesomeDummyValue"))))).thenReturn(resultParameters);
// Create the input parameters to pass to the server
Parameters inParams = new Parameters();
inParams.addParameter().setName("start").setValue(new DateType("2001-01-01"));
inParams.addParameter().setName("end").setValue(new DateType("2015-03-01"));
inParams.addParameter().setName("dummy").setValue(new StringType("myAwesomeDummyValue"));
//invoke
Parameters outParams = client.operation().onInstance(new IdType("Patient", "1")).named("$someCustomOperation")
.withParameters(inParams).execute();
//verify
assertEquals("outputValue", ((StringType)outParams.getParameter().get(0).getValue()).getValueAsString());
}
class StringTypeMatcher extends ArgumentMatcher<StringType> {
private StringType myStringType;
public StringTypeMatcher(StringType stringType) {
myStringType = stringType;
}
@Override
public boolean matches(Object argument) {
return myStringType.getValue().equals(((StringType)argument).getValue());
}
}
@Test
public void testExtendedOperationsUsingGet() {
// prepare mock
Parameters resultParameters = new Parameters();
resultParameters.addParameter().setName("return").setResource(createPatient(1)).setValue(new StringType("outputValue"));
when(mock.someCustomOperation(any(IdType.class), argThat(new StringTypeMatcher(new StringType("myAwesomeDummyValue"))))).thenReturn(resultParameters);
// Create the input parameters to pass to the server
Parameters inParams = new Parameters();
inParams.addParameter().setName("start").setValue(new DateType("2001-01-01"));
inParams.addParameter().setName("end").setValue(new DateType("2015-03-01"));
inParams.addParameter().setName("dummy").setValue(new StringType("myAwesomeDummyValue"));
// invoke
Parameters outParams = client.operation().onInstance(new IdType("Patient", "1")).named("$someCustomOperation")
.withParameters(inParams).useHttpGet().execute();
// verify
assertEquals("outputValue", ((StringType)outParams.getParameter().get(0).getValue()).getValueAsString());
}
/** Search using other query options */
public void testOther() {
// missing
}
@Test
public void testRead() {
when(mock.find(idCaptor.capture())).thenReturn(createPatient(1));
final Patient patient = client.read(Patient.class, "1");
compareResultId(1, patient);
compareResultUrl("/Patient/1", patient);
assertEquals("1", idCaptor.getValue().getIdPart());
}
/** Search - Compartments */
@Test
public void testSearchCompartements() {
when(mock.searchCompartment(any(IdType.class))).thenReturn(Arrays.asList((IBaseResource) createPatient(1)));
org.hl7.fhir.dstu3.model.Bundle response = client.search().forResource(Patient.class).withIdAndCompartment("1", "Condition")
.returnBundle(org.hl7.fhir.dstu3.model.Bundle.class).execute();
Resource resource = response.getEntry().get(0).getResource();
compareResultId(1, resource);
compareResultUrl("/Patient/1", resource);
}
/** */
@Test
public void testSearchPost() {
when(mock.search(any(StringParam.class), Matchers.isNull(StringAndListParam.class)))
.thenReturn(createPatients(1, 13));
org.hl7.fhir.dstu3.model.Bundle result = client.search().forResource("Patient").usingStyle(SearchStyleEnum.POST)
.returnBundle(org.hl7.fhir.dstu3.model.Bundle.class).execute();
Resource resource = result.getEntry().get(0).getResource();
compareResultId(1, resource);
compareResultUrl("/Patient/1", resource);
}
/** Search/Query - Type */
@Test
public void testSearchUsingGenericClientBySearch() {
// Perform a search
when(mock.search(any(StringParam.class), Matchers.isNull(StringAndListParam.class)))
.thenReturn(Arrays.asList(createPatient(1)));
final Bundle results = client.search().forResource(Patient.class)
.where(Patient.NAME.matchesExactly().value(PATIENT_NAME)).returnBundle(Bundle.class).execute();
verify(mock).search(any(StringParam.class), Matchers.isNull(StringAndListParam.class));
IBaseResource resource = results.getEntry().get(0).getResource();
compareResultId(1, resource);
compareResultUrl("/Patient/1", resource);
}
/** Search - Multi-valued Parameters (ANY/OR) */
@Test
public void testSearchUsingGenericClientBySearchWithMultiValues() {
when(mock.search(any(StringParam.class), Matchers.isNotNull(StringAndListParam.class)))
.thenReturn(Arrays.asList(createPatient(1)));
final Bundle results = client.search().forResource(Patient.class)
.where(Patient.ADDRESS.matches().values("Toronto")).and(Patient.ADDRESS.matches().values("Ontario"))
.and(Patient.ADDRESS.matches().values("Canada"))
.where(Patient.IDENTIFIER.exactly().systemAndIdentifier("SHORTNAME", "TOYS")).returnBundle(Bundle.class).execute();
IBaseResource resource = results.getEntry().get(0).getResource();
compareResultId(1, resource);
compareResultUrl("/Patient/1", resource);
}
/** Search - Paging */
@Test
public void testSearchWithPaging() {
// Perform a search
when(mock.search(any(StringParam.class), Matchers.isNull(StringAndListParam.class)))
.thenReturn(createPatients(1, 13));
final org.hl7.fhir.dstu3.model.Bundle results = client.search().forResource(Patient.class).count(8).returnBundle(org.hl7.fhir.dstu3.model.Bundle.class)
.execute();
assertEquals(results.getEntry().size(), 8);
IBaseResource resource = results.getEntry().get(0).getResource();
compareResultId(1, resource);
compareResultUrl("/Patient/1", resource);
compareResultId(8, results.getEntry().get(7).getResource());
// ourLog.info("Next: " + results.getLink("next").getUrl());
// String url = results.getLink("next").getUrl().replace("?", "Patient?");
// results.getLink("next").setUrl(url);
// ourLog.info("New Next: " + results.getLink("next").getUrl());
// load next page
final org.hl7.fhir.dstu3.model.Bundle nextPage = client.loadPage().next(results).execute();
resource = nextPage.getEntry().get(0).getResource();
compareResultId(9, resource);
compareResultUrl("/Patient/9", resource);
assertNull(nextPage.getLink(org.hl7.fhir.dstu3.model.Bundle.LINK_NEXT));
}
/** Search - Subsetting (_summary and _elements) */
@Test
@Ignore
public void testSummary() {
Object response = client.search().forResource(Patient.class)
.returnBundle(org.hl7.fhir.dstu3.model.Bundle.class).execute();
}
/** Transaction - Server */
// @Ignore
// @Test
// public void testTransaction() {
// ca.uhn.fhir.model.api.Bundle bundle = new ca.uhn.fhir.model.api.Bundle();
// BundleEntry entry = bundle.addEntry();
// final Patient existing = new Patient();
// existing.getName().get(0).addFamily("Created with bundle");
// entry.setResource(existing);
//
// BoundCodeDt<BundleEntryTransactionMethodEnum> theTransactionOperation = new BoundCodeDt(
// BundleEntryTransactionMethodEnum.VALUESET_BINDER, BundleEntryTransactionMethodEnum.POST);
// entry.setTransactionMethod(theTransactionOperation);
// ca.uhn.fhir.model.api.Bundle response = client.transaction().withBundle(bundle).execute();
// }
@Test
public void testUpdateById() throws Exception {
when(mock.update(idCaptor.capture(), patientCaptor.capture())).thenReturn(new MethodOutcome());
client.update("1", createPatient(1));
assertEquals("1", idCaptor.getValue().getIdPart());
compareResultId(1, patientCaptor.getValue());
}
@SuppressWarnings("unchecked")
@Ignore
@Test
public void testResourceNotFound() throws Exception {
when(mock.update(idCaptor.capture(), patientCaptor.capture())).thenThrow(ResourceNotFoundException.class);
try {
client.update("1", createPatient(2));
fail();
} catch (ResourceNotFoundException e) {
// good
}
}
@Test
public void testVRead() {
when(mock.findHistory(idCaptor.capture())).thenReturn(createPatient(1));
final Patient patient = client.vread(Patient.class, "1", "2");
compareResultId(1, patient);
compareResultUrl("/Patient/1", patient);
assertEquals("1", idCaptor.getValue().getIdPart());
assertEquals("2", idCaptor.getValue().getVersionIdPart());
}
@Test
public void testXFindUnknownPatient() {
try {
JaxRsResponseException notFoundException = new JaxRsResponseException(new ResourceNotFoundException(new IdType("999955541264")));
when(mock.find(idCaptor.capture())).thenThrow(notFoundException);
client.read(Patient.class, "999955541264");
fail();
} catch (final ResourceNotFoundException e) {
assertEquals(ResourceNotFoundException.STATUS_CODE, e.getStatusCode());
assertTrue(e.getMessage().contains("999955541264"));
}
}
@BeforeClass
public static void setUpClass() throws Exception {
ourPort = RandomServerPortProvider.findFreePort();
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
System.out.println(ourPort);
jettyServer = new Server(ourPort);
jettyServer.setHandler(context);
ServletHolder jerseyServlet = context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, "/*");
jerseyServlet.setInitOrder(0);
//@formatter:off
jerseyServlet.setInitParameter("jersey.config.server.provider.classnames",
StringUtils.join(Arrays.asList(
TestJaxRsMockPatientRestProviderDstu3.class.getCanonicalName(),
JaxRsExceptionInterceptor.class.getCanonicalName(),
TestJaxRsConformanceRestProviderDstu3.class.getCanonicalName(),
TestJaxRsMockPageProviderDstu3.class.getCanonicalName()
), ";"));
//@formatter:on
jettyServer.start();
ourCtx.setRestfulClientFactory(new JaxRsRestfulClientFactory(ourCtx));
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
serverBase = "http://localhost:" + ourPort + "/";
client = ourCtx.newRestfulGenericClient(serverBase);
client.setEncoding(EncodingEnum.JSON);
client.registerInterceptor(new LoggingInterceptor(true));
}
@AfterClass
public static void tearDownClass() throws Exception {
try {
jettyServer.destroy();
} catch (Exception e) {
}
}
}

View File

@ -0,0 +1,34 @@
package ca.uhn.fhir.jaxrs.server.test;
import java.util.concurrent.ConcurrentHashMap;
import javax.ejb.Stateless;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsConformanceProvider;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IResourceProvider;
/**
* A conformance provider exposes the mock patient and this provider
*/
@Path("")
@Stateless
@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML })
public class TestJaxRsConformanceRestProviderDstu3 extends AbstractJaxRsConformanceProvider {
public TestJaxRsConformanceRestProviderDstu3() {
super(FhirContext.forDstu3(), "description", "name", "version");
}
@Override
protected ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> getProviders() {
ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> map = new ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider>();
map.put(TestJaxRsMockPatientRestProviderDstu3.class, new TestJaxRsMockPatientRestProviderDstu3());
map.put(TestJaxRsConformanceRestProviderDstu3.class, new TestJaxRsConformanceRestProviderDstu3());
return map;
}
}

View File

@ -0,0 +1,21 @@
package ca.uhn.fhir.jaxrs.server.test;
import org.hl7.fhir.dstu3.model.Patient;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
/**
* A dummy patient provider exposing no methods
*/
public class TestJaxRsDummyPatientProviderDstu3 extends AbstractJaxRsResourceProvider<Patient> {
public TestJaxRsDummyPatientProviderDstu3() {
super(FhirContext.forDstu3());
}
@Override
public Class<Patient> getResourceType() {
return Patient.class;
}
}

View File

@ -0,0 +1,26 @@
package ca.uhn.fhir.jaxrs.server.test;
import javax.ejb.Stateless;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsPageProvider;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IPagingProvider;
@Path("/")
@Stateless
@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML })
public class TestJaxRsMockPageProviderDstu3 extends AbstractJaxRsPageProvider {
public TestJaxRsMockPageProviderDstu3() {
super(FhirContext.forDstu3());
}
@Override
public IPagingProvider getPagingProvider() {
return TestJaxRsMockPatientRestProviderDstu3.PAGING_PROVIDER;
}
}

View File

@ -0,0 +1,141 @@
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;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Parameters;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.mockito.Mockito;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.Delete;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
import ca.uhn.fhir.rest.server.IPagingProvider;
/**
* A test server delegating each call to a mock
*/
@Path(TestJaxRsMockPatientRestProviderDstu3.PATH)
@Stateless
@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML })
@Interceptors(JaxRsExceptionInterceptor.class)
public class TestJaxRsMockPatientRestProviderDstu3 extends AbstractJaxRsResourceProvider<Patient> {
static final String PATH = "/Patient";
public static final TestJaxRsMockPatientRestProviderDstu3 mock = Mockito.mock(TestJaxRsMockPatientRestProviderDstu3.class);
public static final FifoMemoryPagingProvider PAGING_PROVIDER;
static
{
PAGING_PROVIDER = new FifoMemoryPagingProvider(10);
PAGING_PROVIDER.setDefaultPageSize(10);
PAGING_PROVIDER.setMaximumPageSize(100);
}
/**
* Constructor
*/
public TestJaxRsMockPatientRestProviderDstu3() {
super(FhirContext.forDstu3());
}
@Search
public List<Patient> search(@RequiredParam(name = Patient.SP_NAME) final StringParam name, @RequiredParam(name=Patient.SP_ADDRESS) StringAndListParam theAddressParts) {
return mock.search(name, theAddressParts);
}
@Update
public MethodOutcome update(@IdParam final IdType theId, @ResourceParam final Patient patient) throws Exception {
return mock.update(theId, patient);
}
@Read
public Patient find(@IdParam final IdType theId) {
return mock.find(theId);
}
@Read(version = true)
public Patient findHistory(@IdParam final IdType theId) {
return mock.findHistory(theId);
}
@Create
public MethodOutcome create(@ResourceParam final Patient patient, @ConditionalUrlParam String theConditional)
throws Exception {
return mock.create(patient, theConditional);
}
@Delete
public MethodOutcome delete(@IdParam final IdType theId) {
return mock.delete(theId);
}
@Search(compartmentName = "Condition")
public List<IBaseResource> searchCompartment(@IdParam IdType thePatientId) {
return mock.searchCompartment(thePatientId);
}
@GET
@Path("/{id}/$someCustomOperation")
public Response someCustomOperationUsingGet(@PathParam("id") String id, String resource) throws Exception {
return customOperation(resource, RequestTypeEnum.GET, id, "$someCustomOperation",
RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
}
@POST
@Path("/{id}/$someCustomOperation")
public Response someCustomOperationUsingPost(@PathParam("id") String id, String resource) throws Exception {
return customOperation(resource, RequestTypeEnum.POST, id, "$someCustomOperation",
RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
}
@Operation(name = "someCustomOperation", idempotent = true, returnParameters = {
@OperationParam(name = "return", type = StringType.class) })
public Parameters someCustomOperation(@IdParam IdType myId, @OperationParam(name = "dummy") StringType dummyInput) {
return mock.someCustomOperation(myId, dummyInput);
}
@Override
public Class<Patient> getResourceType() {
return Patient.class;
}
@Override
public IPagingProvider getPagingProvider() {
return PAGING_PROVIDER;
}
}

View File

@ -0,0 +1,129 @@
package ca.uhn.fhir.jaxrs.server.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.List;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Parameters;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.StringType;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProviderDstu3;
import ca.uhn.fhir.jaxrs.server.util.JaxRsMethodBindings;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException;
@FixMethodOrder(MethodSorters.DEFAULT)
public class JaxRsMethodBindingsDstu3Test {
@Before
public void setUp() {
JaxRsMethodBindings.getClassBindings().clear();
}
@Test(expected = NotImplementedOperationException.class)
public void testFindMethodsForProviderNotDefinedMappingMethods() {
new TestJaxRsDummyPatientProviderDstu3().getBindings().getBinding(RestOperationTypeEnum.UPDATE, "");
}
@Test
public void testFindMethodsForProviderWithMethods() {
class TestFindPatientProvider extends TestJaxRsDummyPatientProviderDstu3 {
@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());
}
@Test
public void testFindMethodsFor2ProvidersWithMethods() {
class TestFindPatientProvider extends TestJaxRsDummyPatientProviderDstu3 {
@Search
public List<Patient> search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) {
return null;
}
}
class TestUpdatePatientProvider extends TestJaxRsDummyPatientProviderDstu3 {
@Update
public MethodOutcome update(@IdParam final IdType 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());
}
@Test
public void testFindMethodsWithDoubleMethodsDeclaration() {
class TestDoubleSearchProvider extends TestJaxRsDummyPatientProviderDstu3 {
@Search
public List<Patient> search1(@RequiredParam(name = Patient.SP_NAME) final StringParam name) {
return null;
}
@Search
public List<Patient> search2(@RequiredParam(name = Patient.SP_NAME) final StringParam name) {
return null;
}
}
try {
new TestDoubleSearchProvider();
fail();
} catch(IllegalArgumentException e) {
assertTrue(e.getMessage().contains("search1"));
assertTrue(e.getMessage().contains("search2"));
}
}
@Test
public void testFindMethodsWithMultipleMethods() {
class TestFindPatientProvider extends TestJaxRsDummyPatientProviderDstu3 {
@Search
public List<Patient> search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) {
return null;
}
@Update
public MethodOutcome update(@IdParam final IdType theId, @ResourceParam final Patient patient) {
return null;
}
@Operation(name = "firstMethod", idempotent = true, returnParameters = { @OperationParam(name = "return", type = StringType.class) })
public Parameters firstMethod(@OperationParam(name = "dummy") StringType dummyInput) {
return null;
}
@Operation(name = "secondMethod", returnParameters = { @OperationParam(name = "return", type = StringType.class) })
public Parameters secondMethod(@OperationParam(name = "dummy") StringType dummyInput) {
return null;
}
}
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 {
bindings.getBinding(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE, "$thirdMethod");
fail();
} catch(NotImplementedOperationException e){
}
}
}

View File

@ -0,0 +1,119 @@
package ca.uhn.fhir.jaxrs.server.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang3.StringUtils;
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.test.TestJaxRsDummyPatientProvider;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProviderDstu3;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
import ca.uhn.fhir.jaxrs.server.util.JaxRsResponse;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
public class JaxRsRequestDstu3Test {
private static final String RESOURCE_STRING = "</Patient>";
private static final String BASEURI = "http://baseuri";
private static final String REQUESTURI = "http://baseuri/test";
private JaxRsRequest details;
private MultivaluedMap<String, String> queryParameters = new MultivaluedHashMap<String, String>();
private ContainerRequest headers;
private TestJaxRsDummyPatientProviderDstu3 provider;
@Before
public void setUp() throws URISyntaxException {
details = createRequestDetails();
}
@Test
public void testGetHeader() {
String headerKey = "key";
String headerValue = "location_value";
String headerValue2 = "location_value_2";
assertTrue(StringUtils.isBlank(details.getHeader(headerKey)));
headers.header(headerKey, headerValue);
assertEquals(headerValue, details.getHeader(headerKey));
assertEquals(Arrays.asList(headerValue), details.getHeaders(headerKey));
headers.header(headerKey, headerValue2);
assertEquals(headerValue, details.getHeader(headerKey));
assertEquals(Arrays.asList(headerValue, headerValue2), details.getHeaders(headerKey));
}
@Test
public void testGetByteStreamRequestContents() {
assertEquals(RESOURCE_STRING, new String(details.getByteStreamRequestContents()));
}
@Test
public void testServerBaseForRequest() {
assertEquals(BASEURI, new String(details.getServerBaseForRequest()));
}
@Test
public void testGetResponse() {
JaxRsResponse response = (JaxRsResponse) details.getResponse();
assertEquals(details, response.getRequestDetails());
assertTrue(response == details.getResponse());
}
@Test(expected = UnsupportedOperationException.class)
public void testGetReader() throws IOException {
details.getReader();
}
@Test(expected = UnsupportedOperationException.class)
public void testGetInputStream() {
details.getInputStream();
}
@Test
public void testGetServerBaseForRequest() {
assertEquals(JaxRsRequestDstu3Test.BASEURI, details.getFhirServerBase());
}
@Test
public void testGetServer() {
assertEquals(this.provider, details.getServer());
}
public JaxRsRequest createRequestDetails() throws URISyntaxException {
//headers
headers = new ContainerRequest(new URI(BASEURI), new URI(REQUESTURI), HttpMethod.GET, null, new MapPropertiesDelegate());
//uri info
UriInfo uriInfo = mock(UriInfo.class);
when(uriInfo.getQueryParameters()).thenReturn(queryParameters);
//mocks
provider = spy(TestJaxRsDummyPatientProviderDstu3.class);
doReturn(uriInfo).when(provider).getUriInfo();
doReturn(BASEURI).when(provider).getBaseForRequest();
doReturn(BASEURI).when(provider).getBaseForServer();
doReturn(headers).when(provider).getHeaders();
return new JaxRsRequest(provider, RESOURCE_STRING, RequestTypeEnum.GET, RestOperationTypeEnum.HISTORY_TYPE);
}
}

View File

@ -0,0 +1,159 @@
package ca.uhn.fhir.jaxrs.server.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Set;
import javax.ws.rs.core.Response;
import org.hl7.fhir.dstu3.model.Binary;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.Before;
import org.junit.Test;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
import ca.uhn.fhir.jaxrs.server.util.JaxRsResponse;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.method.ParseAction;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.RestfulServerUtils;
public class JaxRsResponseDstu3Test {
private JaxRsResponse response;
private JaxRsRequest request;
private Bundle bundle;
private Set<SummaryEnum> theSummaryMode;
@Before
public void setUp() throws URISyntaxException {
request = new JaxRsRequestDstu3Test().createRequestDetails();
this.response = (JaxRsResponse) request.getResponse();
bundle = getSinglePatientResource();
theSummaryMode = Collections.<SummaryEnum>emptySet();
}
@Test
public void testGetResponseWriterNoZipNoBrowser() throws IOException {
boolean theRequestIsBrowser = false;
boolean respondGzip = false;
Set<SummaryEnum> theSummaryMode = Collections.<SummaryEnum>emptySet();
boolean theAddContentLocationHeader = false;
Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), bundle, theSummaryMode, 200, theAddContentLocationHeader, respondGzip, request);
assertEquals(200, result.getStatus());
assertEquals(Constants.CT_FHIR_JSON+Constants.CHARSET_UTF8_CTSUFFIX, result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
assertTrue(result.getEntity().toString().contains("Patient"));
assertTrue(result.getEntity().toString().contains("15"));
}
@Test
public void testSendAttachmentResponse() throws IOException {
boolean theRequestIsBrowser = true;
boolean respondGzip = true;
IBaseBinary binary = new Binary();
String contentType = "foo";
byte[] content = new byte[] { 1, 2, 3, 4 };
binary.setContentType(contentType);
binary.setContent(content);
boolean theAddContentLocationHeader = false;
Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), binary, theSummaryMode, 200, theAddContentLocationHeader, respondGzip, this.request);
assertEquals(200, result.getStatus());
assertEquals(contentType, result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
assertEquals(content, result.getEntity());
}
@Test
public void testSendAttachmentResponseNoContent() throws IOException {
boolean theRequestIsBrowser = true;
boolean respondGzip = true;
IBaseBinary binary = new Binary();
binary.setContent(new byte[]{});
boolean theAddContentLocationHeader = false;
Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), binary, theSummaryMode, 200, theAddContentLocationHeader, respondGzip, this.request);
assertEquals(200, result.getStatus());
assertEquals(null, result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
assertEquals(null, result.getEntity());
}
@Test
public void testSendAttachmentResponseEmptyContent() throws IOException {
boolean theRequestIsBrowser = true;
boolean respondGzip = true;
IBaseBinary binary = new Binary();
boolean theAddContentLocationHeader = false;
Response result = (Response) RestfulServerUtils.streamResponseAsResource(request.getServer(), binary, theSummaryMode, 200, theAddContentLocationHeader, respondGzip, this.request);
assertEquals(200, result.getStatus());
assertEquals(null, result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
assertEquals(null, result.getEntity());
}
@Test
public void testReturnResponse() throws IOException {
IdType theId = new IdType(15L);
ParseAction<?> outcome = ParseAction.create(createPatient());
int operationStatus = 200;
boolean allowPrefer = true;
String resourceName = "Patient";
MethodOutcome methodOutcome = new MethodOutcome(theId);
Response result = response.returnResponse(outcome, operationStatus, allowPrefer, methodOutcome, resourceName);
assertEquals(200, result.getStatus());
assertEquals(Constants.CT_JSON+Constants.CHARSET_UTF8_CTSUFFIX, result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
System.out.println(result.getEntity().toString());
assertTrue(result.getEntity().toString().contains("resourceType\":\"Patient"));
assertTrue(result.getEntity().toString().contains("15"));
}
@Test
public void testReturnResponseAsXml() throws IOException {
IdType theId = new IdType(15L);
ParseAction<?> outcome = ParseAction.create(createPatient());
int operationStatus = 200;
boolean allowPrefer = true;
String resourceName = "Patient";
MethodOutcome methodOutcome = new MethodOutcome(theId);
response.getRequestDetails().getParameters().put(Constants.PARAM_FORMAT, new String[]{Constants.CT_XML});
Response result = response.returnResponse(outcome, operationStatus, allowPrefer, methodOutcome, resourceName);
assertEquals(200, result.getStatus());
assertEquals(Constants.CT_XML+Constants.CHARSET_UTF8_CTSUFFIX, result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
assertTrue(result.getEntity().toString().contains("<Patient"));
assertTrue(result.getEntity().toString().contains("15"));
}
@Test
public void testNoOutcomeXml() throws IOException {
ParseAction<?> outcome = ParseAction.create((IBaseResource) null);
int operationStatus = Constants.STATUS_HTTP_204_NO_CONTENT;
boolean allowPrefer = true;
String resourceName = "Patient";
MethodOutcome methodOutcome = new MethodOutcome(null);
response.getRequestDetails().getParameters().put(Constants.PARAM_FORMAT, new String[]{Constants.CT_XML});
Response result = response.returnResponse(outcome, operationStatus, allowPrefer, methodOutcome, resourceName);
assertEquals(204, result.getStatus());
assertEquals(Constants.CT_XML+Constants.CHARSET_UTF8_CTSUFFIX, result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
}
private Bundle getSinglePatientResource() {
Patient theResource = createPatient();
Bundle bundle = new Bundle();
bundle.addEntry().setResource(theResource);
return bundle;
}
private Patient createPatient() {
Patient theResource = new Patient();
theResource.setId(new IdType(15L));
return theResource;
}
}

View File

@ -0,0 +1,46 @@
package ca.uhn.fhir.jaxrs.server.example;
import java.util.concurrent.ConcurrentHashMap;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsConformanceProvider;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IResourceProvider;
/**
* Conformance Rest Service
*
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
*/
@Path("")
@Stateless
@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML })
public class JaxRsConformanceProviderDstu3 extends AbstractJaxRsConformanceProvider {
private static final String SERVER_VERSION = "1.0.0";
private static final String SERVER_DESCRIPTION = "Jax-Rs Test Example Description";
private static final String SERVER_NAME = "Jax-Rs Test Example";
@Inject
private JaxRsPatientRestProvider patientProvider;
/**
* Standard Constructor
*/
public JaxRsConformanceProviderDstu3() {
super(FhirContext.forDstu3(), SERVER_VERSION, SERVER_DESCRIPTION, SERVER_NAME);
}
@Override
protected ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> getProviders() {
ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> map = new ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider>();
map.put(JaxRsConformanceProviderDstu3.class, this);
map.put(JaxRsPatientRestProvider.class, patientProvider);
return map;
}
}

View File

@ -0,0 +1,27 @@
package ca.uhn.fhir.jaxrs.server.example;
import javax.ejb.Stateless;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsPageProvider;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IPagingProvider;
@Path("/")
@Stateless
@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML })
public class JaxRsPageProviderDstu3 extends AbstractJaxRsPageProvider {
public JaxRsPageProviderDstu3() {
super(FhirContext.forDstu3());
}
@Override
public IPagingProvider getPagingProvider() {
return JaxRsPatientRestProviderDstu3.PAGE_PROVIDER;
}
}

View File

@ -0,0 +1,258 @@
package ca.uhn.fhir.jaxrs.server.example;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.hl7.fhir.dstu3.model.Condition;
import org.hl7.fhir.dstu3.model.HumanName;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Parameters;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.Delete;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.AddProfileTagEnum;
import ca.uhn.fhir.rest.server.BundleInclusionRule;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.ETagSupportEnum;
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
import ca.uhn.fhir.rest.server.IPagingProvider;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
/**
* A demo JaxRs Patient Rest Provider
*
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
*/
@Local
@Path(JaxRsPatientRestProviderDstu3.PATH)
@Stateless
@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML })
public class JaxRsPatientRestProviderDstu3 extends AbstractJaxRsResourceProvider<Patient> {
private static Long counter = 1L;
/**
* The HAPI paging provider for this server
*/
public static final IPagingProvider PAGE_PROVIDER;
static final String PATH = "/Patient";
private static final ConcurrentHashMap<String, List<Patient>> patients = new ConcurrentHashMap<String, List<Patient>>();
static {
PAGE_PROVIDER = new FifoMemoryPagingProvider(10);
}
static {
patients.put(String.valueOf(counter), createPatient("Van Houte"));
patients.put(String.valueOf(counter), createPatient("Agnew"));
for (int i = 0; i < 20; i++) {
patients.put(String.valueOf(counter), createPatient("Random Patient " + counter));
}
}
public JaxRsPatientRestProviderDstu3() {
super(FhirContext.forDstu3(), JaxRsPatientRestProviderDstu3.class);
}
@Create
public MethodOutcome create(@ResourceParam final Patient patient, @ConditionalUrlParam String theConditional) throws Exception {
patients.put("" + counter, createPatient(patient));
final MethodOutcome result = new MethodOutcome().setCreated(true);
result.setResource(patient);
result.setId(new IdType(patient.getId()));
return result;
}
@Delete
public MethodOutcome delete(@IdParam final IdType theId) {
final Patient deletedPatient = find(theId);
patients.remove(deletedPatient.getIdElement().getIdPart());
final MethodOutcome result = new MethodOutcome().setCreated(true);
result.setResource(deletedPatient);
return result;
}
@Read
public Patient find(@IdParam final IdType theId) {
if (patients.containsKey(theId.getIdPart())) {
return getLast(patients.get(theId.getIdPart()));
} else {
throw new ResourceNotFoundException(theId);
}
}
@Read(version = true)
public Patient findHistory(@IdParam final IdType theId) {
if (patients.containsKey(theId.getIdPart())) {
final List<Patient> list = patients.get(theId.getIdPart());
for (final Patient patient : list) {
if (patient.getIdElement().getVersionIdPartAsLong().equals(theId.getVersionIdPartAsLong())) {
return patient;
}
}
}
throw new ResourceNotFoundException(theId);
}
@Operation(name = "firstVersion", idempotent = true, returnParameters = { @OperationParam(name = "return", type = StringType.class) })
public Parameters firstVersion(@IdParam final IdType theId, @OperationParam(name = "dummy") StringType dummyInput) {
Parameters parameters = new Parameters();
Patient patient = find(new IdType(theId.getResourceType(), theId.getIdPart(), "0"));
parameters.addParameter().setName("return").setResource(patient).setValue(new StringType((counter - 1) + "" + "inputVariable [ " + dummyInput.getValue() + "]"));
return parameters;
}
@Override
public AddProfileTagEnum getAddProfileTag() {
return AddProfileTagEnum.NEVER;
}
@Override
public BundleInclusionRule getBundleInclusionRule() {
return BundleInclusionRule.BASED_ON_INCLUDES;
}
@Override
public ETagSupportEnum getETagSupport() {
return ETagSupportEnum.DISABLED;
}
/** THE DEFAULTS */
@Override
public List<IServerInterceptor> getInterceptors() {
return Collections.emptyList();
}
private Patient getLast(final List<Patient> list) {
return list.get(list.size() - 1);
}
@Override
public IPagingProvider getPagingProvider() {
return PAGE_PROVIDER;
}
@Override
public Class<Patient> getResourceType() {
return Patient.class;
}
@Override
public boolean isDefaultPrettyPrint() {
return true;
}
@Override
public boolean isUseBrowserFriendlyContentTypes() {
return true;
}
@GET
@Path("/{id}/$firstVersion")
public Response operationFirstVersionUsingGet(@PathParam("id") String id) throws IOException {
return customOperation(null, RequestTypeEnum.GET, id, "$firstVersion", RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
}
@POST
@Path("/{id}/$firstVersion")
public Response operationFirstVersionUsingGet(@PathParam("id") String id, final String resource) throws Exception {
return customOperation(resource, RequestTypeEnum.POST, id, "$firstVersion", RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
}
@Search
public List<Patient> search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) {
final List<Patient> result = new LinkedList<Patient>();
for (final List<Patient> patientIterator : patients.values()) {
Patient single = null;
for (Patient patient : patientIterator) {
if (name == null || patient.getName().get(0).getFamily().get(0).getValueNotNull().equals(name.getValueNotNull())) {
single = patient;
}
}
if (single != null) {
result.add(single);
}
}
return result;
}
@Search(compartmentName = "Condition")
public List<IBaseResource> searchCompartment(@IdParam IdType thePatientId) {
List<IBaseResource> retVal = new ArrayList<IBaseResource>();
Condition condition = new Condition();
condition.setId(new IdType("665577"));
retVal.add(condition);
return retVal;
}
@Update
public MethodOutcome update(@IdParam final IdType theId, @ResourceParam final Patient patient) {
final String idPart = theId.getIdPart();
if (patients.containsKey(idPart)) {
final List<Patient> patientList = patients.get(idPart);
final Patient lastPatient = getLast(patientList);
patient.setId(createId(theId.getIdPartAsLong(), lastPatient.getIdElement().getVersionIdPartAsLong() + 1));
patientList.add(patient);
final MethodOutcome result = new MethodOutcome().setCreated(false);
result.setResource(patient);
result.setId(new IdType(patient.getId()));
return result;
} else {
throw new ResourceNotFoundException(theId);
}
}
private static IdType createId(final Long id, final Long theVersionId) {
return new IdType("Patient", "" + id, "" + theVersionId);
}
private static List<Patient> createPatient(final Patient patient) {
patient.setId(createId(counter, 1L));
final LinkedList<Patient> list = new LinkedList<Patient>();
list.add(patient);
counter++;
return list;
}
private static List<Patient> createPatient(final String name) {
final Patient patient = new Patient();
patient.getName().add(new HumanName().addFamily(name));
return createPatient(patient);
}
}

View File

@ -0,0 +1,315 @@
package ca.uhn.fhir.jaxrs.server.example;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Conformance;
import org.hl7.fhir.dstu3.model.DateType;
import org.hl7.fhir.dstu3.model.HumanName;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Parameters;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.StringType;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jaxrs.client.JaxRsRestfulClientFactory;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.primitive.BoundCodeDt;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.client.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.method.SearchStyleEnum;
import ca.uhn.fhir.rest.server.EncodingEnum;
public class JaxRsPatientProviderDstu3Test {
private static IGenericClient client;
private static final FhirContext ourCtx = FhirContext.forDstu3();
private static final String PATIENT_NAME = "Van Houte";
private static int ourPort;
private static Server jettyServer;
@BeforeClass
public static void setUpClass()
throws Exception {
ourPort = RandomServerPortProvider.findFreePort();
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
System.out.println(ourPort);
jettyServer = new Server(ourPort);
jettyServer.setHandler(context);
ServletHolder jerseyServlet = context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, "/*");
jerseyServlet.setInitOrder(0);
//@formatter:off
jerseyServlet.setInitParameter("jersey.config.server.provider.classnames",
StringUtils.join(Arrays.asList(
JaxRsConformanceProviderDstu3.class.getCanonicalName(),
JaxRsPatientRestProviderDstu3.class.getCanonicalName(),
JaxRsPageProviderDstu3.class.getCanonicalName()
), ";"));
//@formatter:on
jettyServer.start();
ourCtx.setRestfulClientFactory(new JaxRsRestfulClientFactory(ourCtx));
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/");
client.setEncoding(EncodingEnum.JSON);
client.registerInterceptor(new LoggingInterceptor(true));
}
@AfterClass
public static void tearDownClass()
throws Exception {
try {
jettyServer.destroy();
}
catch (Exception e) {
}
}
/** Search/Query - Type */
@Test
public void findUsingGenericClientBySearch() {
// Perform a search
final Bundle results = client.search().forResource(Patient.class)
.where(Patient.NAME.matchesExactly().value(PATIENT_NAME)).returnBundle(Bundle.class).execute();
System.out.println(results.getEntry().get(0));
assertEquals(results.getEntry().size(), 1);
}
/** Search - Multi-valued Parameters (ANY/OR) */
@Test
public void findUsingGenericClientBySearchWithMultiValues() {
final Bundle response = client.search().forResource(Patient.class)
.where(Patient.ADDRESS.matches().values("Toronto")).and(Patient.ADDRESS.matches().values("Ontario"))
.and(Patient.ADDRESS.matches().values("Canada"))
.where(Patient.IDENTIFIER.exactly().systemAndIdentifier("SHORTNAME", "TOYS")).returnBundle(Bundle.class).execute();
System.out.println(response.getEntry().get(0));
}
/** Search - Paging */
@Test
public void findWithPaging() {
// Perform a search
final Bundle results = client.search().forResource(Patient.class).limitTo(8).returnBundle(Bundle.class).execute();
System.out.println(results.getEntry().size());
if (results.getLink(Bundle.LINK_NEXT) != null) {
// load next page
final Bundle nextPage = client.loadPage().next(results).execute();
System.out.println(nextPage.getEntry().size());
}
}
/** Search using other query options */
public void testOther() {
//missing
}
/** */
@Test
public void testSearchPost() {
Bundle response = client.search()
.forResource("Patient")
.usingStyle(SearchStyleEnum.POST)
.returnBundle(Bundle.class)
.execute();
assertTrue(response.getEntry().size() > 0);
}
/** Search - Compartments */
@Test
public void testSearchCompartements() {
Bundle response = client.search()
.forResource(Patient.class)
.withIdAndCompartment("1", "Condition")
.returnBundle(Bundle.class)
.execute();
assertTrue(response.getEntry().size() > 0);
}
/** Search - Subsetting (_summary and _elements) */
@Test
@Ignore
public void testSummary() {
client.search()
.forResource(Patient.class)
.returnBundle(Bundle.class)
.execute();
}
@Test
public void testCreatePatient() {
final Patient existing = new Patient();
existing.setId((IdType) null);
existing.getName().add(new HumanName().addFamily("Created Patient 54"));
client.setEncoding(EncodingEnum.JSON);
final MethodOutcome results = client.create().resource(existing).prefer(PreferReturnEnum.REPRESENTATION).execute();
System.out.println(results.getId());
final Patient patient = (Patient) results.getResource();
System.out.println(patient);
assertNotNull(client.read(Patient.class, patient.getId()));
client.setEncoding(EncodingEnum.JSON);
}
/** Conditional Creates */
@Test
public void testConditionalCreate() {
final Patient existing = new Patient();
existing.setId((IdType) null);
existing.getName().add(new HumanName().addFamily("Created Patient 54"));
client.setEncoding(EncodingEnum.XML);
final MethodOutcome results = client.create().resource(existing).prefer(PreferReturnEnum.REPRESENTATION).execute();
System.out.println(results.getId());
final Patient patient = (Patient) results.getResource();
client.create()
.resource(patient)
.conditional()
.where(Patient.IDENTIFIER.exactly().identifier(patient.getId()))
.execute();
}
/** Find By Id */
@Test
public void findUsingGenericClientById() {
final Patient results = client.read(Patient.class, "1");
assertEquals(results.getIdElement().getIdPartAsLong().longValue(), 1L);
}
@Test
public void testUpdateById() {
final Patient existing = client.read(Patient.class, "1");
final List<HumanName> name = existing.getName();
name.get(0).addSuffix("The Second");
existing.getName().addAll(name);
client.setEncoding(EncodingEnum.XML);
final MethodOutcome results = client.update("1", existing);
}
@Test
public void testDeletePatient() {
final Patient existing = new Patient();
existing.getName().add(new HumanName().addFamily("Created Patient XYZ"));
final MethodOutcome results = client.create().resource(existing).prefer(PreferReturnEnum.REPRESENTATION).execute();
System.out.println(results.getId());
final Patient patient = (Patient) results.getResource();
client.delete(Patient.class, patient.getId());
try {
client.read(Patient.class, patient.getId());
fail();
}
catch (final Exception e) {
//assertEquals(e.getStatusCode(), Constants.STATUS_HTTP_404_NOT_FOUND);
}
}
/** Transaction - Server */
@Ignore
@Test
public void testTransaction() {
Bundle bundle = new Bundle();
BundleEntryComponent entry = bundle.addEntry();
final Patient existing = new Patient();
existing.getName().get(0).addFamily("Created with bundle");
entry.setResource(existing);
// FIXME ?
// BoundCodeDt<BundleEntryTransactionMethodEnum> theTransactionOperation =
// new BoundCodeDt(
// BundleEntryTransactionMethodEnum.VALUESET_BINDER,
// BundleEntryTransactionMethodEnum.POST);
// entry.setTransactionMethod(theTransactionOperation);
Bundle response = client.transaction().withBundle(bundle).execute();
}
/** Conformance - Server */
@Test
@Ignore
public void testConformance() {
final Conformance conf = client.fetchConformance().ofType(Conformance.class).execute();
System.out.println(conf.getRest().get(0).getResource().get(0).getType());
assertEquals(conf.getRest().get(0).getResource().get(0).getType().toString(), "Patient");
}
/** Extended Operations */
// Create a client to talk to the HeathIntersections server
@Test
public void testExtendedOperations() {
client.registerInterceptor(new LoggingInterceptor(true));
// Create the input parameters to pass to the server
Parameters inParams = new Parameters();
inParams.addParameter().setName("start").setValue(new DateType("2001-01-01"));
inParams.addParameter().setName("end").setValue(new DateType("2015-03-01"));
inParams.addParameter().setName("dummy").setValue(new StringType("myAwesomeDummyValue"));
// Invoke $everything on "Patient/1"
Parameters outParams = client
.operation()
.onInstance(new IdType("Patient", "1"))
.named("$firstVersion")
.withParameters(inParams)
//.useHttpGet() // Use HTTP GET instead of POST
.execute();
String resultValue = outParams.getParameter().get(0).getValue().toString();
System.out.println(resultValue);
assertEquals("expected but found : "+ resultValue, resultValue.contains("myAwesomeDummyValue"), true);
}
@Test
public void testExtendedOperationsUsingGet() {
// Create the input parameters to pass to the server
Parameters inParams = new Parameters();
inParams.addParameter().setName("start").setValue(new DateType("2001-01-01"));
inParams.addParameter().setName("end").setValue(new DateType("2015-03-01"));
inParams.addParameter().setName("dummy").setValue(new StringType("myAwesomeDummyValue"));
// Invoke $everything on "Patient/1"
Parameters outParams = client
.operation()
.onInstance(new IdType("Patient", "1"))
.named("$firstVersion")
.withParameters(inParams)
.useHttpGet() // Use HTTP GET instead of POST
.execute();
String resultValue = outParams.getParameter().get(0).getValue().toString();
System.out.println(resultValue);
assertEquals("expected but found : "+ resultValue, resultValue.contains("myAwesomeDummyValue"), true);
}
@Test
public void testVRead() {
final Patient patient = client.vread(Patient.class, "1", "1");
System.out.println(patient);
}
@Test
public void testRead() {
final Patient patient = client.read(Patient.class, "1");
System.out.println(patient);
}
}

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA 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%
*/
public class PathAndRef {
private final String myPath;

View File

@ -9,6 +9,7 @@ import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@ -32,6 +33,9 @@ import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.hamcrest.Matchers;
import org.hamcrest.core.StringContains;
import org.hl7.fhir.dstu3.model.BaseResource;
@ -118,7 +122,6 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
TestUtil.clearAllStaticFieldsForUnitTest();
}
private void assertGone(IIdType theId) {
try {
assertNotGone(theId);
@ -240,7 +243,6 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
}
}
@Test
public void testChoiceParamDate() {
Observation o2 = new Observation();
@ -254,7 +256,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
assertEquals(id2, found.getResources(0, 1).get(0).getIdElement());
}
}
@Test
public void testCreateDifferentTypesWithSameForcedId() {
String idName = "forcedId";
@ -264,17 +266,17 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
pat.addName().addFamily("FAM");
IIdType patId = myPatientDao.update(pat, mySrd).getId();
assertEquals("Patient/" + idName, patId.toUnqualifiedVersionless().getValue());
Observation obs = new Observation();
obs.setId(idName);
obs.getCode().addCoding().setSystem("foo").setCode("testCreateDifferentTypesWithSameForcedId");
IIdType obsId = myObservationDao.update(obs, mySrd).getId();
assertEquals("Observation/" + idName, obsId.toUnqualifiedVersionless().getValue());
pat = myPatientDao.read(patId.toUnqualifiedVersionless(), mySrd);
obs = myObservationDao.read(obsId.toUnqualifiedVersionless(), mySrd);
}
@Test
public void testChoiceParamDateAlt() {
Observation o2 = new Observation();
@ -468,7 +470,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
NamingSystem res = myFhirCtx.newXmlParser().parseResource(NamingSystem.class, input);
IIdType id = myNamingSystemDao.create(res, mySrd).getId().toUnqualifiedVersionless();
assertThat(toUnqualifiedVersionlessIdValues(myNamingSystemDao.search(NamingSystem.SP_NAME, new StringParam("NDF"))), contains(id.getValue()));
}
@ -497,7 +499,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
assertEquals("my message", oo.getIssue().get(0).getDiagnostics());
assertEquals(IssueType.INCOMPLETE, oo.getIssue().get(0).getCode());
}
@Test
public void testCreateOperationOutcomeInfo() {
FhirResourceDaoDstu3<Bundle> dao = new FhirResourceDaoDstu3<Bundle>();
@ -593,7 +595,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
myBundleDao.create(bundle, mySrd);
}
@Test
public void testCreateWithIfNoneExistBasic() {
String methodName = "testCreateWithIfNoneExistBasic";
@ -773,7 +775,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
// Lose typing so we can put the wrong type in
@SuppressWarnings("rawtypes")
IFhirResourceDao dao = myNamingSystemDao;
Patient resource = new Patient();
resource.addName().addFamily("My Name");
try {
@ -1473,10 +1475,10 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
@Test
public void testHistoryWithFutureSinceDate() throws Exception {
Date before = new Date();
Thread.sleep(10);
Patient inPatient = new Patient();
inPatient.addName().addFamily("version1");
inPatient.getMeta().addProfile("http://example.com/1");
@ -1484,18 +1486,18 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
Thread.sleep(10);
Date after = new Date();
// No since
IBundleProvider history = myPatientDao.history(null, mySrd);
assertEquals(1, history.size());
Patient outPatient = (Patient) history.getResources(0, 1).get(0);
assertEquals("version1", inPatient.getName().get(0).getFamilyAsSingleString());
List<String> profiles = toStringList(outPatient.getMeta().getProfile());
assertThat(profiles, contains("http://example.com/1"));
// Before since
history = myPatientDao.history(before, mySrd);
assertEquals(1, history.size());
outPatient = (Patient) history.getResources(0, 1).get(0);
@ -1504,12 +1506,12 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
assertThat(profiles, contains("http://example.com/1"));
// After since
history = myPatientDao.history(after, mySrd);
assertEquals(0, history.size());
}
@Test
public void testHistoryReflectsMetaOperations() throws Exception {
Patient inPatient = new Patient();
@ -1523,25 +1525,25 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
assertEquals("version1", inPatient.getName().get(0).getFamilyAsSingleString());
List<String> profiles = toStringList(outPatient.getMeta().getProfile());
assertThat(profiles, contains("http://example.com/1"));
/*
* Change metadata
*/
inPatient.getMeta().addProfile("http://example.com/2");
myPatientDao.metaAddOperation(id, inPatient.getMeta(), mySrd);
history = myPatientDao.history(null, mySrd);
assertEquals(1, history.size());
outPatient = (Patient) history.getResources(0, 1).get(0);
assertEquals("version1", inPatient.getName().get(0).getFamilyAsSingleString());
profiles = toStringList(outPatient.getMeta().getProfile());
assertThat(profiles, containsInAnyOrder("http://example.com/1", "http://example.com/2"));
/*
* Do an update
*/
inPatient.setId(id);
inPatient.getMeta().addProfile("http://example.com/3");
inPatient.getName().get(0).addFamily("version2");
@ -1559,7 +1561,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
assertEquals("version1", outPatient.getName().get(0).getFamilyAsSingleString());
profiles = toStringList(outPatient.getMeta().getProfile());
assertThat(profiles, containsInAnyOrder("http://example.com/1", "http://example.com/2"));
}
}
@Test
public void testHistoryWithDeletedResource() throws Exception {
@ -1603,7 +1605,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
assertEquals("Resource Patient/FOOFOOFOO is not known", e.getMessage());
}
}
@Test
public void testIdParam() {
Patient patient = new Patient();

View File

@ -1,12 +1,23 @@
package ca.uhn.fhir.jpa.provider.dstu3;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.Collection;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.hl7.fhir.dstu3.model.DecimalType;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Questionnaire;
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType;
@ -17,6 +28,7 @@ import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
@ -99,5 +111,77 @@ public class ResourceProviderQuestionnaireResponseDstu3Test extends BaseResource
assertThat(e.toString(), containsString("Answer value must be of type string"));
}
}
@Test
public void testSaveQuestionnaire() throws Exception {
String input = "<QuestionnaireResponse xmlns=\"http://hl7.org/fhir\">\n" +
" <status value=\"completed\"/>\n" +
" <authored value=\"2016-05-03T13:05:20-04:00\"/>\n" +
" <item>\n" +
" <linkId value=\"breast-feeding-intention\"/>\n" +
" <text value=\"Breast Feeding Intention:\"/>\n" +
" <answer>\n" +
" <valueCoding>\n" +
" <system value=\"http://example.org/codesystem-breastfeeding-intention\"/>\n" +
" <code value=\"true\"/>\n" +
" <display value=\"Mother wants to provide formula exclusively\"/>\n" +
" </valueCoding>\n" +
" </answer>\n" +
" </item>\n" +
" <item>\n" +
" <linkId value=\"breast-feeding-education\"/>\n" +
" <text value=\"Answer if not exclusive BM:\"/>\n" +
" <answer>\n" +
" <valueCoding>\n" +
" <system value=\"http://example.org/codesystem-breastfeeding-education\"/>\n" +
" <code value=\"true\"/>\n" +
" <display value=\"Mother not given comprehensive education per protocol\"/>\n" +
" </valueCoding>\n" +
" </answer>\n" +
" </item>\n" +
" <item>\n" +
" <linkId value=\"breast-feeding-exclusion\"/>\n" +
" <text value=\"Exclusion Criteria:\"/>\n" +
" <answer>\n" +
" <valueCoding>\n" +
" <system value=\"http://example.org/codesystem-breastfeeding-exclusion\"/>\n" +
" <code value=\"true\"/>\n" +
" <display\n" +
" value=\"Maternal use of drugs of abuse, antimetabolites, chemotherapeutic agents, or radioisotopes\"\n" +
" />\n" +
" </valueCoding>\n" +
" </answer>\n" +
" </item>\n" +
"</QuestionnaireResponse>";
HttpPost post = new HttpPost(ourServerBase + "/QuestionnaireResponse");
post.setEntity(new StringEntity(input, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
CloseableHttpResponse response = ourHttpClient.execute(post);
final IdType id2;
try {
String responseString = IOUtils.toString(response.getEntity().getContent());
ourLog.info("Response: {}", responseString);
assertEquals(201, response.getStatusLine().getStatusCode());
String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue();
assertThat(newIdString, startsWith(ourServerBase + "/QuestionnaireResponse/"));
id2 = new IdType(newIdString);
} finally {
IOUtils.closeQuietly(response);
}
HttpGet get = new HttpGet(ourServerBase + "/QuestionnaireResponse/" + id2.getIdPart() + "?_format=xml&_pretty=true");
response = ourHttpClient.execute(get);
try {
String responseString = IOUtils.toString(response.getEntity().getContent());
ourLog.info("Response: {}", responseString);
assertThat(responseString, containsString("Exclusion Criteria"));
} finally {
IOUtils.closeQuietly(response);
}
}
}

View File

@ -30,7 +30,7 @@ public class CommonConfig {
public IServerInterceptor requestLoggingInterceptor() {
LoggingInterceptor retVal = new LoggingInterceptor();
retVal.setLoggerName("fhirtest.request");
retVal.setMessageFormat("Path[${servletPath}] ${requestBodyFhir}");
retVal.setMessageFormat("${requestVerb} ${servletPath} -\n${requestBodyFhir}");
retVal.setLogExceptions(false);
return retVal;
}

View File

@ -73,7 +73,7 @@
</triggeringPolicy>
<encoder>
<!-- [%file:%line] -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %msg%n</pattern>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %msg%n</pattern>
</encoder>
</appender>

View File

@ -81,6 +81,17 @@ public class ServerSearchDstu2Test {
assertEquals("param2value", ourLastRef.getValue());
}
@Test
public void testSearchParamWithSpace() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/?param2=param+value&foo=bar");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals("searchParam2", ourLastMethod);
assertEquals("param value", ourLastRef.getValue());
}
@Test
public void testUnknownSearchParam() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/?foo=bar");

View File

@ -70,11 +70,13 @@ public class LoggingInterceptorDstu2Test {
private static Server ourServer;
private static RestfulServer servlet;
private IServerInterceptor myInterceptor;
private static Exception ourThrowException;
@Before
public void before() {
myInterceptor = mock(IServerInterceptor.class);
servlet.setInterceptors(Collections.singletonList(myInterceptor));
ourThrowException = null;
}
@Test
@ -139,7 +141,48 @@ public class LoggingInterceptorDstu2Test {
}
@Test
public void testCreate() throws Exception {
public void testRequestBodyRead() throws Exception {
LoggingInterceptor interceptor = new LoggingInterceptor();
interceptor.setMessageFormat("${operationType} - ${operationName} - ${idOrResourceName} - ${requestBodyFhir}");
servlet.setInterceptors(Collections.singletonList((IServerInterceptor) interceptor));
Logger logger = mock(Logger.class);
interceptor.setLogger(logger);
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
HttpResponse status = ourClient.execute(httpGet);
IOUtils.closeQuietly(status.getEntity().getContent());
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(logger, times(1)).info(captor.capture());
assertEquals("read - - Patient/1 - ", captor.getValue());
}
@Test
public void testRequestBodyReadWithContentTypeHeader() throws Exception {
LoggingInterceptor interceptor = new LoggingInterceptor();
interceptor.setMessageFormat("${operationType} - ${operationName} - ${idOrResourceName} - ${requestBodyFhir}");
servlet.setInterceptors(Collections.singletonList((IServerInterceptor) interceptor));
Logger logger = mock(Logger.class);
interceptor.setLogger(logger);
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
httpGet.addHeader(Constants.HEADER_CONTENT_TYPE, Constants.CT_FHIR_XML);
HttpResponse status = ourClient.execute(httpGet);
IOUtils.closeQuietly(status.getEntity().getContent());
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(logger, times(1)).info(captor.capture());
assertEquals("read - - Patient/1 - ", captor.getValue());
}
@Test
public void testRequestBodyCreate() throws Exception {
LoggingInterceptor interceptor = new LoggingInterceptor();
interceptor.setMessageFormat("${operationType} - ${operationName} - ${idOrResourceName} - ${requestBodyFhir}");
@ -151,10 +194,37 @@ public class LoggingInterceptorDstu2Test {
Patient p = new Patient();
p.addIdentifier().setValue("VAL");
String input = ourCtx.newXmlParser().encodeResourceToString(p);
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(input, ContentType.parse(Constants.CT_FHIR_XML+";charset=utf-8")));
httpPost.setEntity(new StringEntity(input, ContentType.parse(Constants.CT_FHIR_XML + ";charset=utf-8")));
HttpResponse status = ourClient.execute(httpPost);
IOUtils.closeQuietly(status.getEntity().getContent());
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(logger, times(1)).info(captor.capture());
assertEquals("create - - Patient - <Patient xmlns=\"http://hl7.org/fhir\"><identifier><value value=\"VAL\"/></identifier></Patient>", captor.getValue());
}
@Test
public void testRequestBodyCreateException() throws Exception {
LoggingInterceptor interceptor = new LoggingInterceptor();
interceptor.setMessageFormat("${operationType} - ${operationName} - ${idOrResourceName} - ${requestBodyFhir}");
servlet.setInterceptors(Collections.singletonList((IServerInterceptor) interceptor));
Logger logger = mock(Logger.class);
interceptor.setLogger(logger);
Patient p = new Patient();
p.addIdentifier().setValue("VAL");
String input = ourCtx.newXmlParser().encodeResourceToString(p);
ourThrowException = new NullPointerException("FOO");
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
httpPost.setEntity(new StringEntity(input, ContentType.parse(Constants.CT_FHIR_XML + ";charset=utf-8")));
HttpResponse status = ourClient.execute(httpPost);
IOUtils.closeQuietly(status.getEntity().getContent());
@ -348,10 +418,13 @@ public class LoggingInterceptorDstu2Test {
}
@Create
public MethodOutcome create(@ResourceParam Patient thePatient) {
public MethodOutcome create(@ResourceParam Patient thePatient) throws Exception {
if (ourThrowException != null) {
throw ourThrowException;
}
return new MethodOutcome(new IdDt("Patient/1"));
}
@Operation(name = "$everything", idempotent = true)
public Bundle patientTypeOperation(@OperationParam(name = "start") DateDt theStart, @OperationParam(name = "end") DateDt theEnd) {

View File

@ -12,6 +12,7 @@ import java.util.Map;
import java.util.Set;
import org.apache.commons.io.Charsets;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.CodeSystem;
@ -89,6 +90,8 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
@SuppressWarnings("unchecked")
@Override
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
Validate.notBlank(theUri, "theUri must not be null or blank");
if (theUri.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
return (T) fetchStructureDefinition(theContext, theUri);
}

View File

@ -1541,7 +1541,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private void validateQuestionannaireResponse(List<ValidationMessage> errors, Element element, NodeStack stack) {
Element q = element.getNamedChild("questionnaire");
if (hint(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), q != null, "No questionnaire is identified, so no validation can be performed against the base questionnaire")) {
if (hint(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), q != null && isNotBlank(q.getNamedChildValue("reference")), "No questionnaire is identified, so no validation can be performed against the base questionnaire")) {
long t = System.nanoTime();
Questionnaire qsrc = context.fetchResource(Questionnaire.class, q.getNamedChildValue("reference"));
sdTime = sdTime + (System.nanoTime() - t);

View File

@ -120,14 +120,14 @@ public class XmlParserDstu3Test {
}
@Test
public void testEncodeContained() throws Exception {
public void testEncodeContainedWithNonLocalId() throws Exception {
Patient p = new Patient();
p.setId("Patient1");
p.setBirthDate(new SimpleDateFormat("yyyy-mm-dd HH:mm:ss").parse("2016-04-15 10:15:30"));
ProcedureRequest pr = new ProcedureRequest();
pr.setId("#1234567");
pr.setId("1234567");
pr.setSubject(new Reference(p));
pr.setCode(new CodeableConcept().addCoding(new Coding("breastfeeding-readiness-assessment", "Breastfeeding Readiness Assessment", "Breastfeeding Readiness Assessment")));
// pr.setReason(new StringType("Single Live Birth"));