add unit tests

This commit is contained in:
petervanhoute 2015-10-28 14:08:14 +01:00
parent 1afaea81d6
commit 9f7a104315
14 changed files with 1258 additions and 291 deletions

View File

@ -39,229 +39,58 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.3-SNAPSHOT</version>
</dependency>
<!-- conformance profile -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>1.3-SNAPSHOT</version>
</dependency>
<!-- UNKNOWN -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.phloc</groupId>
<artifactId>phloc-schematron</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.phloc</groupId>
<artifactId>phloc-commons</artifactId>
<scope>test</scope>
</dependency>
<!-- PREVIOUS TESTING
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
-->
<!-- own api -->
<!--dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>2.2.1.GA</version>
<scope>test</scope>
</dependency-->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>ejb-api</artifactId>
<version>3.0</version>
<scope>provided</scope>
</dependency>
<!-- Jetty -->
<!-- http://stackoverflow.com/questions/10048004/integrating-jetty-with-jax-rs-jersey -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<artifactId>jetty-servlet</artifactId>
<version>${jetty_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<scope>test</scope>
</dependency>
<!-- Jersey (JAX-RS) -->
<!--
<dependency>
<groupId>com.sun.jersey</groupId>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-spring</artifactId>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-test-framework</artifactId>
<version>${jersey_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.grizzly</groupId>
<artifactId>grizzly-servlet-webserver</artifactId>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>${jersey_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-jetty-http</artifactId>
<version>${jersey_version}</version>
<scope>test</scope>
</dependency>
-->
</dependencies>
<!--
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<configuration>
<skipDeploy>true</skipDeploy>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-tinder-plugin</artifactId>
<version>1.3-SNAPSHOT</version>
<executions>
<execution>
<id>build_dstu1</id>
<goals>
<goal>generate-jparest-server</goal>
</goals>
<configuration>
<version>dstu</version>
<packageBase>ca.uhn.fhir.jpa.rp.dstu</packageBase>
<targetResourceSpringBeansFile>hapi-fhir-server-resourceproviders-dstu1.xml</targetResourceSpringBeansFile>
<baseResourceNames/>
</configuration>
</execution>
<execution>
<id>build_dstu2</id>
<goals>
<goal>generate-jparest-server</goal>
</goals>
<configuration>
<version>dstu2</version>
<packageBase>ca.uhn.fhir.jpa.rp.dstu2</packageBase>
<targetResourceSpringBeansFile>hapi-fhir-server-resourceproviders-dstu2.xml</targetResourceSpringBeansFile>
<baseResourceNames/>
<excludeResourceNames>
<excludeResourceName>OperationDefinition</excludeResourceName>
<excludeResourceName>OperationOutcome</excludeResourceName>
</excludeResourceNames>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.3-SNAPSHOT</version>
</dependency>
</dependencies>
</plugin>
</plugins>
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
</resource>
<resource>
<directory>${basedir}/target/generated-sources/tinder</directory>
</resource>
<resource>
<directory>${basedir}/target/generated-resources/tinder</directory>
</resource>
</resources>
</build>
-->
<reporting>
<plugins>
<plugin>

View File

@ -8,7 +8,7 @@ import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequestDetails;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
@ -30,18 +30,19 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
public static FhirContext CTX = FhirContext.forDstu2();
@Context
private UriInfo info;
private UriInfo theUriInfo;
@Context
private HttpHeaders headers;
private HttpHeaders theHeaders;
public FhirContext getFhirContext() {
@Override
public FhirContext getFhirContext() {
return CTX;
}
/**
* param and query methods
*/
protected HashMap<String, String[]> getQueryMap() {
public HashMap<String, String[]> getQueryMap() {
MultivaluedMap<String, String> queryParameters = getInfo().getQueryParameters();
HashMap<String, String[]> params = new HashMap<String, String[]>();
for (String key : queryParameters.keySet()) {
@ -56,48 +57,42 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
return addressStrategy;
}
protected String getBaseUri() {
public String getBaseUri() {
return getInfo().getBaseUri().toASCIIString();
}
/**
* PARSING METHODS
*/
public IParser getParser(JaxRsRequestDetails theRequestDetails) {
public IParser getParser(JaxRsRequest theRequestDetails) {
return RestfulServerUtils.getNewParser(getFhirContext(), theRequestDetails);
}
protected JaxRsRequestDetails createRequestDetails(final String resourceString, RequestTypeEnum requestType, RestOperationTypeEnum restOperation) {
JaxRsRequestDetails theRequest = new JaxRsRequestDetails(headers, resourceString);
theRequest.setFhirServerBase(getBaseUri());
theRequest.setRestOperationType(restOperation);
theRequest.setServer(this);
theRequest.setParameters(getQueryMap());
theRequest.setRequestType(requestType);
return theRequest;
protected JaxRsRequest createRequestDetails(final String resourceString, RequestTypeEnum requestType, RestOperationTypeEnum restOperation) {
return new JaxRsRequest(this, resourceString, requestType, restOperation);
}
/**
* Get the info
* @return the info
*/
public UriInfo getInfo() {
return info;
return theUriInfo;
}
/**
* Set the info
* @param info the info to set
* Get the headers
* @return the headers
*/
public void setInfo(UriInfo info) {
this.info = info;
}
public HttpHeaders getHeaders() {
return theHeaders;
}
/**
* DEFAULT VALUES
*/
public EncodingEnum getDefaultResponseEncoding() {
@Override
public EncodingEnum getDefaultResponseEncoding() {
return EncodingEnum.JSON;
}
@ -119,5 +114,6 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
@Override
public boolean isUseBrowserFriendlyContentTypes() {
return true;
}
}
}

View File

@ -2,6 +2,8 @@ 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;
@ -18,7 +20,7 @@ import javax.ws.rs.core.Response;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequestDetails;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
import ca.uhn.fhir.jaxrs.server.util.MethodBindings;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.primitive.IdDt;
@ -26,9 +28,12 @@ import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.BundleInclusionRule;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IPagingProvider;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.util.UrlUtil;
/**
@ -40,22 +45,18 @@ import ca.uhn.fhir.util.UrlUtil;
@Consumes({MediaType.APPLICATION_FORM_URLENCODED,MediaType.APPLICATION_JSON, "application/json+fhir", "application/xml+fhir"})
public abstract class AbstractJaxRsResourceProvider<R extends IResource> extends AbstractJaxRsProvider implements IJaxRsResourceProvider<R> {
private static MethodBindings bindings;
private final MethodBindings bindings;
protected AbstractJaxRsResourceProvider() {
bindings = MethodBindings.getMethodBindings(this, getClass());
}
public AbstractJaxRsResourceProvider(Class<?> subclass) {
initBindings(subclass);
protected AbstractJaxRsResourceProvider(Class<?> subclass) {
bindings = MethodBindings.getMethodBindings(this, subclass);
}
private void initBindings(Class<?> subclass) {
if(bindings == null) {
MethodBindings methodBindings = new MethodBindings();
methodBindings.findMethods(this, subclass, getFhirContext());
bindings = methodBindings;
}
}
@Override
protected String getBaseUri() {
public String getBaseUri() {
try {
return new URL(getInfo().getBaseUri().toURL(), getResourceType().getSimpleName()).toExternalForm();
} catch(Exception e) {
@ -115,7 +116,7 @@ public abstract class AbstractJaxRsResourceProvider<R extends IResource> extends
protected Response customOperation(final String resource, RequestTypeEnum requestType, String id, String operationName, RestOperationTypeEnum operationType)
throws Exception {
return executeMethod(resource, requestType, operationType, id, bindings.getBinding(operationType, operationName));
return executeMethod(resource, requestType, operationType, id, getBindings().getBinding(operationType, operationName));
}
@GET
@ -124,7 +125,7 @@ public abstract class AbstractJaxRsResourceProvider<R extends IResource> extends
@Interceptors(JaxRsExceptionInterceptor.class)
public Response findHistory(@PathParam("id") final String id, @PathParam("version") final String versionString)
throws BaseServerResponseException, IOException {
BaseMethodBinding<?> method = bindings.getBinding(RestOperationTypeEnum.VREAD);
BaseMethodBinding<?> method = getBindings().getBinding(RestOperationTypeEnum.VREAD);
final RequestDetails theRequest = createRequestDetails(null, RequestTypeEnum.GET, RestOperationTypeEnum.VREAD);
if (id == null) {
throw new InvalidRequestException("Don't know how to handle request path: " + getInfo().getRequestUri().toASCIIString());
@ -138,7 +139,7 @@ public abstract class AbstractJaxRsResourceProvider<R extends IResource> extends
@Path("/{id}/{compartment}")
@Interceptors(JaxRsExceptionInterceptor.class)
public Response findCompartment(@PathParam("id") final String id, @PathParam("compartment") final String compartment) throws BaseServerResponseException, IOException {
BaseMethodBinding<?> method = bindings.getBinding(RestOperationTypeEnum.SEARCH_TYPE, compartment);
BaseMethodBinding<?> method = getBindings().getBinding(RestOperationTypeEnum.SEARCH_TYPE, compartment);
final RequestDetails theRequest = createRequestDetails(null, RequestTypeEnum.GET, RestOperationTypeEnum.VREAD);
if (id == null) {
throw new InvalidRequestException("Don't know how to handle request path: " + getInfo().getRequestUri().toASCIIString());
@ -150,7 +151,7 @@ public abstract class AbstractJaxRsResourceProvider<R extends IResource> extends
private <T extends BaseMethodBinding<?>> Response executeMethod(final String resourceString, RequestTypeEnum requestType, RestOperationTypeEnum restOperation, String id)
throws BaseServerResponseException, IOException {
BaseMethodBinding<?> method = bindings.getBinding(restOperation);
BaseMethodBinding<?> method = getBindings().getBinding(restOperation);
return executeMethod(resourceString, requestType, restOperation, id, method);
}
@ -162,8 +163,8 @@ public abstract class AbstractJaxRsResourceProvider<R extends IResource> extends
}
protected JaxRsRequestDetails createRequestDetails(final String resourceString, RequestTypeEnum requestType, RestOperationTypeEnum restOperation, String id) {
JaxRsRequestDetails theRequest = super.createRequestDetails(resourceString, requestType, restOperation);
protected JaxRsRequest createRequestDetails(final String resourceString, RequestTypeEnum requestType, RestOperationTypeEnum restOperation, String id) {
JaxRsRequest theRequest = super.createRequestDetails(resourceString, requestType, restOperation);
theRequest.setId(StringUtils.isBlank(id) ? null : new IdDt(getResourceType().getName(), UrlUtil.unescape(id)));
if(restOperation == RestOperationTypeEnum.UPDATE) {
String contentLocation = theRequest.getHeader(Constants.HEADER_CONTENT_LOCATION);
@ -173,8 +174,27 @@ public abstract class AbstractJaxRsResourceProvider<R extends IResource> extends
}
return theRequest;
}
@Override
public List<IServerInterceptor> getInterceptors() {
return Collections.emptyList();
}
@Override
public IPagingProvider getPagingProvider() {
return null;
}
@Override
public BundleInclusionRule getBundleInclusionRule() {
return BundleInclusionRule.BASED_ON_INCLUDES;
}
@Override
public abstract Class<R> getResourceType();
public MethodBindings getBindings() {
return bindings;
}
}

View File

@ -4,12 +4,12 @@ import java.io.IOException;
import javax.ws.rs.core.Response;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequestDetails;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.IRestfulServer;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
public interface IJaxRsResourceProvider<T> extends IRestfulServer<JaxRsRequestDetails>, IResourceProvider {
public interface IJaxRsResourceProvider<T> extends IRestfulServer<JaxRsRequest>, IResourceProvider {
Response search()
throws Exception;

View File

@ -9,17 +9,34 @@ import java.util.List;
import javax.ws.rs.core.HttpHeaders;
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsProvider;
import ca.uhn.fhir.jaxrs.server.JaxRsResponse;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.param.ResourceParameter;
import ca.uhn.fhir.rest.server.IRestfulResponse;
public class JaxRsRequestDetails extends RequestDetails {
public class JaxRsRequest extends RequestDetails {
private String theResourceString;
private HttpHeaders headers;
private AbstractJaxRsProvider myServer;
public AbstractJaxRsProvider getServer() {
public JaxRsRequest() {
}
public JaxRsRequest(AbstractJaxRsProvider server, String resourceString,
RequestTypeEnum requestType, RestOperationTypeEnum restOperation) {
this.headers = server.getHeaders();
this.theResourceString = resourceString;
this.setRestOperationType(restOperation);
setServer(server);
setFhirServerBase(server.getBaseUri());
setParameters(server.getQueryMap());
setRequestType(requestType);
}
@Override
public AbstractJaxRsProvider getServer() {
return myServer;
}
@ -27,16 +44,10 @@ public class JaxRsRequestDetails extends RequestDetails {
this.myServer = theServer;
}
public JaxRsRequestDetails(HttpHeaders headers, String resourceString) {
this.headers = headers;
this.theResourceString = resourceString;
setResponse(new JaxRsResponse(resourceString, this));
}
@Override
public String getHeader(String headerIfNoneExist) {
List<String> requestHeader = headers.getRequestHeader(headerIfNoneExist);
return (requestHeader == null || requestHeader.size() == 0) ? null : requestHeader.get(0);
public String getHeader(String headerKey) {
List<String> requestHeader = getHeaders(headerKey);
return requestHeader.isEmpty() ? null : requestHeader.get(0);
}
@Override
@ -55,14 +66,24 @@ public class JaxRsRequestDetails extends RequestDetails {
return theResourceString.getBytes(ResourceParameter.determineRequestCharset(this));
}
@Override
public IRestfulResponse getResponse() {
if(super.getResponse() == null) {
setResponse(new JaxRsResponse(this));
}
return super.getResponse();
}
@Override
public Reader getReader()
throws IOException {
// not yet implemented
throw new UnsupportedOperationException();
}
@Override
public InputStream getInputStream() {
// not yet implemented
throw new UnsupportedOperationException();
}
}

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.jaxrs.server;
package ca.uhn.fhir.jaxrs.server.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@ -15,7 +15,6 @@ import javax.ws.rs.core.Response.ResponseBuilder;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequestDetails;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.method.ParseAction;
@ -24,9 +23,9 @@ import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.RestfulResponse;
import ca.uhn.fhir.rest.server.RestfulServerUtils;
public class JaxRsResponse extends RestfulResponse<JaxRsRequestDetails> {
public class JaxRsResponse extends RestfulResponse<JaxRsRequest> {
public JaxRsResponse(String resourceString, JaxRsRequestDetails jaxRsRequestDetails) {
public JaxRsResponse(JaxRsRequest jaxRsRequestDetails) {
super(jaxRsRequestDetails);
}
@ -43,15 +42,13 @@ public class JaxRsResponse extends RestfulResponse<JaxRsRequestDetails> {
@Override
public Response sendWriterResponse(int status, String contentType, String charset, Writer writer) {
return Response.status(status)/*.header(HttpHeaders.CONTENT_TYPE, charset)*/.header(Constants.HEADER_CONTENT_TYPE, contentType).entity(writer.toString()).build();
Object entity = writer instanceof StringWriter ? writer.toString() : writer;
return buildResponse(status)/*.header(HttpHeaders.CONTENT_TYPE, charset)*/.header(Constants.HEADER_CONTENT_TYPE, contentType).entity(entity).build();
}
@Override
public Object sendAttachmentResponse(IBaseBinary bin, int statusCode, String contentType) throws IOException {
ResponseBuilder response = Response.status(statusCode);
for (Entry<String, String> header : getHeaders().entrySet()) {
response.header(header.getKey(), header.getValue());
}
public Response sendAttachmentResponse(IBaseBinary bin, int statusCode, String contentType) throws IOException {
ResponseBuilder response = buildResponse(statusCode);
if (bin.getContent() != null && bin.getContent().length > 0) {
response.header(Constants.HEADER_CONTENT_TYPE, contentType).entity(bin.getContent());
}
@ -59,20 +56,28 @@ public class JaxRsResponse extends RestfulResponse<JaxRsRequestDetails> {
}
@Override
public Object returnResponse(ParseAction<?> outcome, int operationStatus, boolean allowPrefer, MethodOutcome response,
public Response returnResponse(ParseAction<?> outcome, int operationStatus, boolean allowPrefer, MethodOutcome response,
String resourceName)
throws IOException {
Writer writer = new StringWriter();
IParser parser = RestfulServerUtils.getNewParser(getRequestDetails().getServer().getFhirContext(), getRequestDetails());
StringWriter writer = new StringWriter();
if(outcome != null) {
IParser parser = RestfulServerUtils.getNewParser(getRequestDetails().getServer().getFhirContext(), getRequestDetails());
outcome.execute(parser, writer);
}
return Response.status(operationStatus).header(Constants.HEADER_CONTENT_TYPE, getParserType()).entity(writer.toString()).build();
return sendWriterResponse(operationStatus, getParserType(), null, writer);
}
protected String getParserType() {
EncodingEnum encodingEnum = RestfulServerUtils.determineResponseEncodingWithDefault(getRequestDetails());
return encodingEnum == EncodingEnum.JSON ? MediaType.APPLICATION_JSON : MediaType.APPLICATION_XML;
}
private ResponseBuilder buildResponse(int statusCode) {
ResponseBuilder response = Response.status(statusCode);
for (Entry<String, String> header : getHeaders().entrySet()) {
response.header(header.getKey(), header.getValue());
}
return response;
}
}

View File

@ -5,7 +5,6 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
@ -14,55 +13,73 @@ import ca.uhn.fhir.rest.method.OperationMethodBinding;
import ca.uhn.fhir.rest.method.SearchMethodBinding;
import ca.uhn.fhir.util.ReflectionUtil;
/**
* @author Peter Van Houte
* Class that contains the method bindings defined by a ResourceProvider
*/
public class MethodBindings {
/** ALL METHOD BINDINGS */
ConcurrentHashMap<RestOperationTypeEnum, ConcurrentHashMap<String, BaseMethodBinding<?>>> allBindings = new ConcurrentHashMap<RestOperationTypeEnum, ConcurrentHashMap<String,BaseMethodBinding<?>>>();
/** Static collection of bindings mapped to a class*/
private static final ConcurrentHashMap<Class<?>, MethodBindings> classBindings = new ConcurrentHashMap<Class<?>, MethodBindings>();
/** Static collection of operationBindings mapped to a class */
private ConcurrentHashMap<RestOperationTypeEnum, ConcurrentHashMap<String, BaseMethodBinding<?>>> operationBindings = new ConcurrentHashMap<RestOperationTypeEnum, ConcurrentHashMap<String,BaseMethodBinding<?>>>();
public <T extends AbstractJaxRsResourceProvider<?>> void findMethods(T theProvider, Class<?> subclass, FhirContext fhirContext) {
for (final Method m : ReflectionUtil.getDeclaredMethods(subclass)) {
final BaseMethodBinding<?> foundMethodBinding = BaseMethodBinding.bindMethod(m, fhirContext, theProvider);
public <T extends AbstractJaxRsResourceProvider<?>> MethodBindings(T theProvider, Class<?> clazz) {
for (final Method m : ReflectionUtil.getDeclaredMethods(clazz)) {
final BaseMethodBinding<?> foundMethodBinding = BaseMethodBinding.bindMethod(m, theProvider.getFhirContext(), theProvider);
if (foundMethodBinding == null) {
continue;
}
ConcurrentHashMap<String, BaseMethodBinding<?>> map = getAllBindingsMap(foundMethodBinding.getRestOperationType());
if (foundMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding binding = (OperationMethodBinding) foundMethodBinding;
putIfAbsent(map, binding.getName(), binding);
} else if (foundMethodBinding instanceof SearchMethodBinding) {
Search search = m.getAnnotation(Search.class);
String compartmentName = StringUtils.defaultIfBlank(search.compartmentName(), "");
putIfAbsent(map, compartmentName, foundMethodBinding);
} else {
putIfAbsent(map, "", foundMethodBinding);
}
String bindingKey = getBindingKey(foundMethodBinding);
putIfAbsent(bindingKey, foundMethodBinding);
}
}
private void putIfAbsent(ConcurrentHashMap<String, BaseMethodBinding<?>> map, String key, BaseMethodBinding binding) {
private String getBindingKey(final BaseMethodBinding<?> foundMethodBinding) {
if (foundMethodBinding instanceof OperationMethodBinding) {
return ((OperationMethodBinding) foundMethodBinding).getName();
} else if (foundMethodBinding instanceof SearchMethodBinding) {
Search search = foundMethodBinding.getMethod().getAnnotation(Search.class);
return search.compartmentName();
} else {
return "";
}
}
private void putIfAbsent(String key, BaseMethodBinding<?> binding) {
operationBindings.putIfAbsent(binding.getRestOperationType(), new ConcurrentHashMap<String, BaseMethodBinding<?>>());
ConcurrentHashMap<String, BaseMethodBinding<?>> map = operationBindings.get(binding.getRestOperationType());
if (map.containsKey(key)) {
throw new IllegalArgumentException("Multiple Search Method Bindings Found : " + map.get(key) + " -- " + binding.getMethod());
}
}
map.put(key, binding);
}
private ConcurrentHashMap<String,BaseMethodBinding<?>> getAllBindingsMap(final RestOperationTypeEnum restOperationTypeEnum) {
allBindings.putIfAbsent(restOperationTypeEnum, new ConcurrentHashMap<String, BaseMethodBinding<?>>());
return allBindings.get(restOperationTypeEnum);
}
public BaseMethodBinding<?> getBinding(RestOperationTypeEnum operationType) {
return getBinding(operationType, "");
}
public BaseMethodBinding<?> getBinding(RestOperationTypeEnum operationType, String qualifier) {
String nonEmptyQualifier = StringUtils.defaultIfBlank(qualifier, "");
ConcurrentHashMap<String, BaseMethodBinding<?>> map = getAllBindingsMap(operationType);
if(!map.containsKey(nonEmptyQualifier)) {
String nonEmptyQualifier = StringUtils.defaultIfBlank(qualifier, "");
ConcurrentHashMap<String, BaseMethodBinding<?>> map = operationBindings.get(operationType);
if(map == null || !map.containsKey(nonEmptyQualifier)) {
throw new UnsupportedOperationException();
} else {
return map.get(nonEmptyQualifier);
}
}
public BaseMethodBinding<?> getBinding(RestOperationTypeEnum operationType) {
return getBinding(operationType, "");
}
public static <T extends AbstractJaxRsResourceProvider<?>> MethodBindings getMethodBindings(T theProvider, Class<?> clazz) {
if(!getClassBindings().containsKey(clazz)) {
MethodBindings foundBindings = new MethodBindings(theProvider, clazz);
getClassBindings().putIfAbsent(clazz, foundBindings);
}
return getClassBindings().get(clazz);
}
public static ConcurrentHashMap<Class<?>, MethodBindings> getClassBindings() {
return classBindings;
}
}

View File

@ -0,0 +1,318 @@
package ca.uhn.fhir.jaxrs.server;
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.List;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
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.server.example.JaxRsPatientRestProvider;
import ca.uhn.fhir.jaxrs.server.example.RandomServerPortProvider;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Conformance;
import ca.uhn.fhir.model.dstu2.resource.Parameters;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.BoundCodeDt;
import ca.uhn.fhir.model.primitive.DateDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
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 JaxRsPatientProviderTest {
private static IGenericClient client;
private static final FhirContext ourCtx = FhirContext.forDstu2();
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);
jerseyServlet.setInitParameter("jersey.config.server.provider.classnames", JaxRsPatientRestProvider.class.getCanonicalName());
jettyServer.start();
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 ca.uhn.fhir.model.api.Bundle results = client.search().forResource(Patient.class)
.where(Patient.NAME.matchesExactly().value(PATIENT_NAME)).execute();
System.out.println(results.getEntries().get(0));
assertEquals(results.getEntries().size(), 1);
}
/** Search - Multi-valued Parameters (ANY/OR) */
@Test
public void findUsingGenericClientBySearchWithMultiValues() {
final ca.uhn.fhir.model.api.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")).execute();
System.out.println(response.getEntries().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(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
assertTrue(response.getEntry().size() > 0);
}
/** Search - Subsetting (_summary and _elements) */
@Test
@Ignore
public void testSummary() {
Object response = client.search()
.forResource(Patient.class)
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
}
@Test
public void testCreatePatient() {
final Patient existing = new Patient();
existing.setId((IdDt) null);
existing.getNameFirstRep().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.getId()));
client.setEncoding(EncodingEnum.JSON);
}
/** Conditional Creates */
@Test
public void testConditionalCreate() {
final Patient existing = new Patient();
existing.setId((IdDt) null);
existing.getNameFirstRep().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.getIdentifierFirstRep()))
.execute();
}
/** Find By Id */
@Test
public void findUsingGenericClientById() {
final Patient results = client.read(Patient.class, "1");
assertEquals(results.getId().getIdPartAsLong().longValue(), 1L);
}
@Test
public void testUpdateById() {
final Patient existing = client.read(Patient.class, "1");
final List<HumanNameDt> name = existing.getName();
name.get(0).addSuffix("The Second");
existing.setName(name);
client.setEncoding(EncodingEnum.XML);
final MethodOutcome results = client.update("1", existing);
}
@Test
public void testDeletePatient() {
final Patient existing = new Patient();
existing.getNameFirstRep().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.getId());
fail();
}
catch (final Exception e) {
//assertEquals(e.getStatusCode(), Constants.STATUS_HTTP_404_NOT_FOUND);
}
}
/** 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.getNameFirstRep().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();
}
/** 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 DateDt("2001-01-01"));
inParams.addParameter().setName("end").setValue(new DateDt("2015-03-01"));
inParams.addParameter().setName("dummy").setValue(new StringDt("myAwesomeDummyValue"));
// Invoke $everything on "Patient/1"
Parameters outParams = client
.operation()
.onInstance(new IdDt("Patient", "1"))
.named("$last")
.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() {
client.registerInterceptor(new LoggingInterceptor(true));
// Create the input parameters to pass to the server
Parameters inParams = new Parameters();
inParams.addParameter().setName("start").setValue(new DateDt("2001-01-01"));
inParams.addParameter().setName("end").setValue(new DateDt("2015-03-01"));
inParams.addParameter().setName("dummy").setValue(new StringDt("myAwesomeDummyValue"));
// Invoke $everything on "Patient/1"
Parameters outParams = client
.operation()
.onInstance(new IdDt("Patient", "1"))
.named("$last")
.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 testFindUnknownPatient() {
try {
final Patient existing = client.read(Patient.class, "999955541264");
fail();
}
catch (final Exception e) {
e.printStackTrace();
//assertEquals(e.getStatusCode(), 404);
}
}
@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

@ -0,0 +1,269 @@
package ca.uhn.fhir.jaxrs.server.example;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
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 ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.resource.Condition;
import ca.uhn.fhir.model.dstu2.resource.Parameters;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.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;
/**
* Fhir Physician Rest Service
* @author axmpm
*
*/
@Path(JaxRsPatientRestProvider.PATH)
@Stateless
@Produces({MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML})
public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider<Patient> /*implements IJaxRsPatientProvider*/ {
static final String PATH = "/Patient";
private static Long counter = 1L;
private static final ConcurrentHashMap<String, List<Patient>> patients = new ConcurrentHashMap<String, List<Patient>>();
public JaxRsPatientRestProvider() throws Exception {
super(JaxRsPatientRestProvider.class);
}
static {
patients.put(""+counter, createPatient("Van Houte"));
patients.put(""+(counter), createPatient("Agnew"));
for(int i = 0 ; i<20 ; i++) {
patients.put(""+(counter), createPatient("Random Patient " + counter));
}
}
private static List<Patient> createPatient(final String name) {
final Patient patient = new Patient();
patient.getNameFirstRep().addFamily(name);
return createPatient(patient);
}
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 IdDt createId(final Long id, final Long theVersionId) {
return new IdDt("Patient", "" + id, "" + theVersionId);
}
@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.getNameFirstRep().getFamilyFirstRep().getValueNotNull().equals(name.getValueNotNull())) {
single = patient;
}
}
if (single != null) {
result.add(single);
}
}
return result;
}
@Update
public MethodOutcome update(@IdParam final IdDt theId, @ResourceParam final Patient patient)
throws Exception {
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.getId().getVersionIdPartAsLong()+1));
patientList.add(patient);
final MethodOutcome result = new MethodOutcome().setCreated(false);
result.setResource(patient);
result.setId(patient.getId());
return result;
} else {
throw new ResourceNotFoundException(theId);
}
}
@Read
public Patient find(@IdParam final IdDt theId) {
if(patients.containsKey(theId.getIdPart())) {
return getLast(patients.get(theId.getIdPart()));
} else {
throw new ResourceNotFoundException(theId);
}
}
private Patient getLast(final List<Patient> list) {
return list.get(list.size()-1);
}
@Read(version = true)
public Patient findHistory(@IdParam final IdDt theId) {
if (patients.containsKey(theId.getIdPart())) {
final List<Patient> list = patients.get(theId.getIdPart());
for (final Patient patient : list) {
if (patient.getId().getVersionIdPartAsLong().equals(theId.getVersionIdPartAsLong())) {
return patient;
}
}
}
throw new ResourceNotFoundException(theId);
}
@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(patient.getId());
return result;
}
@Delete
public MethodOutcome delete(@IdParam final IdDt theId) {
final Patient deletedPatient = find(theId);
patients.remove(deletedPatient.getId().getIdPart());
final MethodOutcome result = new MethodOutcome().setCreated(true);
result.setResource(deletedPatient);
return result;
}
@GET
@Path("/{id}/$last")
@Interceptors(JaxRsExceptionInterceptor.class)
public Response operationLastGet(@PathParam("id") String id)
throws Exception {
return customOperation(null, RequestTypeEnum.GET, id, "$last", RestOperationTypeEnum.EXTENDED_OPERATION_TYPE);
}
@Search(compartmentName="Condition")
public List<IResource> searchCompartment(@IdParam IdDt thePatientId) {
List<IResource> retVal=new ArrayList<IResource>();
Condition condition = new Condition();
condition.setId(new IdDt("665577"));
retVal.add(condition);
return retVal;
}
@POST
@Path("/{id}/$last")
@Interceptors(JaxRsExceptionInterceptor.class)
public Response operationLast(final String resource)
throws Exception {
return customOperation(resource, RequestTypeEnum.POST, null, "$last", RestOperationTypeEnum.EXTENDED_OPERATION_TYPE);
}
// @ca.uhn.fhir.rest.annotation.Validate
// public MethodOutcome validate(
// @ResourceParam T theResource,
// @ResourceParam String theRawResource,
// @ResourceParam EncodingEnum theEncoding,
// @ca.uhn.fhir.rest.annotation.Validate.Mode ValidationModeEnum theMode,
// @ca.uhn.fhir.rest.annotation.Validate.Profile String theProfile) {
// return validate(theResource, null, theRawResource, theEncoding, theMode, theProfile);
// }
@Operation(name="last", idempotent=true, returnParameters= {
@OperationParam(name="return", type=StringDt.class)
})
public Parameters last(@OperationParam(name = "dummy") StringDt dummyInput) {
System.out.println("inputparameter");
Parameters parameters = new Parameters();
Patient patient = find(new IdDt(counter.intValue()-1));
parameters
.addParameter()
.setName("return")
.setResource(patient)
.setValue(new StringDt((counter-1)+"" + "inputVariable [ " + dummyInput.getValue()+ "]"));
return parameters;
}
@Override
public Class<Patient> getResourceType() {
return Patient.class;
}
/** THE DEFAULTS */
@Override
public List<IServerInterceptor> getInterceptors() {
return Collections.emptyList();
}
@Override
public ETagSupportEnum getETagSupport() {
return ETagSupportEnum.DISABLED;
}
@Override
public boolean isDefaultPrettyPrint() {
return true;
}
@Override
public AddProfileTagEnum getAddProfileTag() {
return AddProfileTagEnum.NEVER;
}
@Override
public boolean isUseBrowserFriendlyContentTypes() {
return true;
}
@Override
public IPagingProvider getPagingProvider() {
return new FifoMemoryPagingProvider(10);
}
@Override
public BundleInclusionRule getBundleInclusionRule() {
return BundleInclusionRule.BASED_ON_INCLUDES;
}
}

View File

@ -0,0 +1,36 @@
package ca.uhn.fhir.jaxrs.server.example;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.List;
/**
* Provides server ports
*/
public class RandomServerPortProvider {
private static List<Integer> ourPorts = new ArrayList<Integer>();
public static int findFreePort() {
ServerSocket server;
try {
server = new ServerSocket(0);
int port = server.getLocalPort();
ourPorts.add(port);
server.close();
Thread.sleep(500);
return port;
} catch (IOException e) {
throw new Error(e);
} catch (InterruptedException e) {
throw new Error(e);
}
}
public static List<Integer> list() {
return ourPorts;
}
}

View File

@ -0,0 +1,12 @@
package ca.uhn.fhir.jaxrs.server.example;
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
import ca.uhn.fhir.model.dstu2.resource.Patient;
public class TestDummyPatientProvider extends AbstractJaxRsResourceProvider<Patient> {
@Override
public Class<Patient> getResourceType() {
return Patient.class;
}
}

View File

@ -0,0 +1,121 @@
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.apache.commons.lang3.Validate;
import org.glassfish.jersey.internal.MapPropertiesDelegate;
import org.glassfish.jersey.server.ContainerRequest;
import org.junit.Before;
import org.junit.Test;
import ca.uhn.fhir.jaxrs.server.example.TestDummyPatientProvider;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
public class JaxRsRequestTest {
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 TestDummyPatientProvider 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(JaxRsRequestTest.BASEURI, details.getFhirServerBase());
}
@Test
public void testGetServer() {
assertEquals(this.provider, details.getServer());
}
@Test
public void testJaxRsRequestDetails() {
Validate.notNull(new JaxRsRequest());
}
public JaxRsRequest createRequestDetails() throws URISyntaxException {
//headers
headers = new ContainerRequest(new URI(BASEURI), new URI(REQUESTURI), HttpMethod.GET, null, new MapPropertiesDelegate());
//uri info
UriInfo uriInfo = mock(UriInfo.class);
when(uriInfo.getQueryParameters()).thenReturn(queryParameters);
//mocks
provider = spy(TestDummyPatientProvider.class);
doReturn(uriInfo).when(provider).getInfo();
doReturn(BASEURI).when(provider).getBaseUri();
doReturn(headers).when(provider).getHeaders();
return new JaxRsRequest(provider, RESOURCE_STRING, RequestTypeEnum.GET, RestOperationTypeEnum.HISTORY_TYPE);
}
}

View File

@ -0,0 +1,196 @@
package ca.uhn.fhir.jaxrs.server.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Set;
import java.util.zip.GZIPInputStream;
import javax.ws.rs.core.Response;
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.model.api.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Binary;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
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 JaxRsResponseTest {
private JaxRsResponse response;
private JaxRsRequest request;
private Bundle bundle;
private Set<SummaryEnum> theSummaryMode;
@Before
public void setUp() throws URISyntaxException {
request = new JaxRsRequestTest().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();
Response result = (Response) RestfulServerUtils.streamResponseAsBundle(request.getServer(), bundle, theSummaryMode, theRequestIsBrowser, respondGzip, request);
assertEquals(200, result.getStatus());
assertEquals(Constants.CT_FHIR_JSON, result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
assertTrue(result.getEntity().toString().contains("Patient"));
assertTrue(result.getEntity().toString().contains("15"));
}
@Test
public void testGetResponseWriterBrowserNoZip() throws IOException {
boolean theRequestIsBrowser = true;
boolean respondGzip = false;
Response result = (Response) RestfulServerUtils.streamResponseAsBundle(request.getServer(), bundle, theSummaryMode, theRequestIsBrowser, respondGzip, request);
assertEquals(200, result.getStatus());
assertEquals(Constants.CT_JSON, result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
assertTrue(result.getEntity().toString().contains("Patient"));
assertTrue(result.getEntity().toString().contains("15"));
}
@Test
public void testGetResponseWriterWithZip() throws IOException {
boolean theRequestIsBrowser = true;
boolean respondGzip = true;
Response result = (Response) RestfulServerUtils.streamResponseAsBundle(request.getServer(), bundle, theSummaryMode, theRequestIsBrowser, respondGzip, request);
assertEquals(200, result.getStatus());
assertEquals(Constants.CT_JSON, result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
assertEquals(Constants.ENCODING_GZIP, result.getHeaderString(Constants.HEADER_CONTENT_ENCODING));
// assertTrue(unzip(result.getEntity()).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, theRequestIsBrowser, theSummaryMode, 200, respondGzip, 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, theRequestIsBrowser, theSummaryMode, 200, respondGzip, 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, theRequestIsBrowser, theSummaryMode, 200, respondGzip, 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 {
IdDt theId = new IdDt(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, 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 {
IdDt theId = new IdDt(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, 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, result.getHeaderString(Constants.HEADER_CONTENT_TYPE));
}
private String unzip(Object entity) throws IOException {
byte[] compressed = ((String) entity).getBytes(Constants.CHARSET_NAME_UTF8);
final int BUFFER_SIZE = 32;
ByteArrayInputStream is = new ByteArrayInputStream(compressed);
GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
StringBuilder string = new StringBuilder();
byte[] data = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = gis.read(data)) != -1) {
string.append(new String(data, 0, bytesRead));
}
gis.close();
is.close();
return string.toString();
}
private Bundle getSinglePatientResource() {
Patient theResource = createPatient();
Bundle bundle = Bundle.withSingleResource(theResource);
return bundle;
}
private Patient createPatient() {
Patient theResource = new Patient();
theResource.setId(new IdDt(15L));
return theResource;
}
}

View File

@ -0,0 +1,127 @@
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.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import ca.uhn.fhir.jaxrs.server.example.TestDummyPatientProvider;
import ca.uhn.fhir.model.dstu2.resource.Parameters;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.annotation.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;
@FixMethodOrder(MethodSorters.DEFAULT)
public class MethodBindingsTest {
@Before
public void setUp() {
MethodBindings.getClassBindings().clear();
}
@Test(expected = UnsupportedOperationException.class)
public void testFindMethodsForProviderNotDefinedMappingMethods() {
new TestDummyPatientProvider().getBindings().getBinding(RestOperationTypeEnum.UPDATE, "");
}
@Test
public void testFindMethodsForProviderWithMethods() {
class TestFindPatientProvider extends TestDummyPatientProvider {
@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 TestDummyPatientProvider {
@Search
public List<Patient> search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) {
return null;
}
}
class TestUpdatePatientProvider extends TestDummyPatientProvider {
@Update
public MethodOutcome update(@IdParam final IdDt theId, @ResourceParam final Patient patient) {
return null;
}
}
assertEquals(TestFindPatientProvider.class, new TestFindPatientProvider().getBindings().getBinding(RestOperationTypeEnum.SEARCH_TYPE).getMethod().getDeclaringClass());
assertEquals(TestUpdatePatientProvider.class, new TestUpdatePatientProvider().getBindings().getBinding(RestOperationTypeEnum.UPDATE).getMethod().getDeclaringClass());
}
@Test
public void testFindMethodsWithDoubleMethodsDeclaration() {
class TestDoubleSearchProvider extends TestDummyPatientProvider {
@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 TestDummyPatientProvider {
@Search
public List<Patient> search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) {
return null;
}
@Update
public MethodOutcome update(@IdParam final IdDt theId, @ResourceParam final Patient patient) {
return null;
}
@Operation(name = "firstMethod", idempotent = true, returnParameters = { @OperationParam(name = "return", type = StringDt.class) })
public Parameters firstMethod(@OperationParam(name = "dummy") StringDt dummyInput) {
return null;
}
@Operation(name = "secondMethod", returnParameters = { @OperationParam(name = "return", type = StringDt.class) })
public Parameters secondMethod(@OperationParam(name = "dummy") StringDt dummyInput) {
return null;
}
}
MethodBindings 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(UnsupportedOperationException e){
}
}
}