Create methd
This commit is contained in:
parent
ad189d66e2
commit
b38be51668
|
@ -7,6 +7,6 @@ import java.lang.annotation.Target;
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.PARAMETER)
|
@Target(ElementType.PARAMETER)
|
||||||
public @interface Id {
|
public @interface IdParam {
|
||||||
// just a marker
|
// just a marker
|
||||||
}
|
}
|
|
@ -20,7 +20,7 @@ import java.lang.annotation.Target;
|
||||||
*/
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(value= {ElementType.PARAMETER})
|
@Target(value= {ElementType.PARAMETER})
|
||||||
public @interface Include {
|
public @interface IncludeParam {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional parameter, if provided the server will only allow the values
|
* Optional parameter, if provided the server will only allow the values
|
|
@ -5,6 +5,6 @@ import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
|
||||||
public @interface Optional {
|
public @interface OptionalParam {
|
||||||
String name();
|
String name();
|
||||||
}
|
}
|
|
@ -5,6 +5,6 @@ import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
|
||||||
public @interface Required {
|
public @interface RequiredParam {
|
||||||
String name();
|
String name();
|
||||||
}
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package ca.uhn.fhir.rest.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target(value=ElementType.PARAMETER)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface ResourceParam {
|
||||||
|
|
||||||
|
}
|
|
@ -7,6 +7,6 @@ import java.lang.annotation.Target;
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.PARAMETER)
|
@Target(ElementType.PARAMETER)
|
||||||
public @interface VersionId {
|
public @interface VersionIdParam {
|
||||||
// just a marker
|
// just a marker
|
||||||
}
|
}
|
|
@ -7,10 +7,6 @@ public class MethodOutcome {
|
||||||
private IdDt myId;
|
private IdDt myId;
|
||||||
private IdDt myVersionId;
|
private IdDt myVersionId;
|
||||||
|
|
||||||
public IdDt getId() {
|
|
||||||
return myId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MethodOutcome() {
|
public MethodOutcome() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,14 +16,18 @@ public class MethodOutcome {
|
||||||
myVersionId = theVersionId;
|
myVersionId = theVersionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(IdDt theId) {
|
public IdDt getId() {
|
||||||
myId = theId;
|
return myId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IdDt getVersionId() {
|
public IdDt getVersionId() {
|
||||||
return myVersionId;
|
return myVersionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setId(IdDt theId) {
|
||||||
|
myId = theId;
|
||||||
|
}
|
||||||
|
|
||||||
public void setVersionId(IdDt theVersionId) {
|
public void setVersionId(IdDt theVersionId) {
|
||||||
myVersionId = theVersionId;
|
myVersionId = theVersionId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
package ca.uhn.fhir.rest.client;
|
package ca.uhn.fhir.rest.client;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.apache.http.client.methods.HttpRequestBase;
|
import org.apache.http.client.methods.HttpRequestBase;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
|
|
||||||
public abstract class BaseClientInvocation {
|
public abstract class BaseClientInvocation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,6 +13,6 @@ public abstract class BaseClientInvocation {
|
||||||
*
|
*
|
||||||
* @param theUrlBase The FHIR server base url (with a trailing "/")
|
* @param theUrlBase The FHIR server base url (with a trailing "/")
|
||||||
*/
|
*/
|
||||||
public abstract HttpRequestBase asHttpRequest(String theUrlBase);
|
public abstract HttpRequestBase asHttpRequest(String theUrlBase) throws DataFormatException, IOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,13 @@ import java.io.StringReader;
|
||||||
import java.lang.reflect.InvocationHandler;
|
import java.lang.reflect.InvocationHandler;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.http.Header;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
@ -57,7 +60,7 @@ public class ClientInvocationHandler implements InvocationHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseMethodBinding binding = myBindings.get(theMethod);
|
BaseMethodBinding binding = myBindings.get(theMethod);
|
||||||
GetClientInvocation clientInvocation = binding.invokeClient(theArgs);
|
BaseClientInvocation clientInvocation = binding.invokeClient(theArgs);
|
||||||
|
|
||||||
HttpRequestBase httpRequest = clientInvocation.asHttpRequest(myUrlBase);
|
HttpRequestBase httpRequest = clientInvocation.asHttpRequest(myUrlBase);
|
||||||
HttpResponse response = myClient.execute(httpRequest);
|
HttpResponse response = myClient.execute(httpRequest);
|
||||||
|
@ -75,7 +78,20 @@ public class ClientInvocationHandler implements InvocationHandler {
|
||||||
|
|
||||||
String mimeType = ct.getMimeType();
|
String mimeType = ct.getMimeType();
|
||||||
|
|
||||||
return binding.invokeClient(mimeType, reader, response.getStatusLine().getStatusCode());
|
Map<String, List<String>> headers = new HashMap<String, List<String>>();
|
||||||
|
if (response.getAllHeaders() != null) {
|
||||||
|
for (Header next : response.getAllHeaders()) {
|
||||||
|
String name = next.getName().toLowerCase();
|
||||||
|
List<String> list = headers.get(name);
|
||||||
|
if (list == null) {
|
||||||
|
list = new ArrayList<String>();
|
||||||
|
headers.put(name, list);
|
||||||
|
}
|
||||||
|
list.add(next.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return binding.invokeClient(mimeType, reader, response.getStatusLine().getStatusCode(), headers);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
if (response instanceof CloseableHttpResponse) {
|
if (response instanceof CloseableHttpResponse) {
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package ca.uhn.fhir.rest.client;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.client.methods.HttpRequestBase;
|
||||||
|
import org.apache.http.entity.ContentType;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.model.api.Bundle;
|
||||||
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
|
||||||
|
public class PostClientInvocation extends BaseClientInvocation {
|
||||||
|
|
||||||
|
private final IResource myResource;
|
||||||
|
private final Bundle myBundle;
|
||||||
|
private final FhirContext myContext;
|
||||||
|
private String myUrlExtension;
|
||||||
|
|
||||||
|
public PostClientInvocation(FhirContext theContext, Bundle theBundle) {
|
||||||
|
super();
|
||||||
|
myContext = theContext;
|
||||||
|
myResource = null;
|
||||||
|
myBundle = theBundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PostClientInvocation(FhirContext theContext, IResource theResource, String theUrlExtension) {
|
||||||
|
super();
|
||||||
|
myContext = theContext;
|
||||||
|
myResource = theResource;
|
||||||
|
myBundle = null;
|
||||||
|
myUrlExtension = theUrlExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpRequestBase asHttpRequest(String theUrlBase) throws DataFormatException, IOException {
|
||||||
|
HttpPost httpPost = new HttpPost(theUrlBase + StringUtils.defaultString(myUrlExtension));
|
||||||
|
String contents = myContext.newXmlParser().encodeResourceToString(myResource);
|
||||||
|
httpPost.setEntity(new StringEntity(contents, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||||
|
return httpPost;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -6,19 +6,29 @@ import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Enumeration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
|
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
|
||||||
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
|
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
|
||||||
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Create;
|
||||||
import ca.uhn.fhir.rest.annotation.Metadata;
|
import ca.uhn.fhir.rest.annotation.Metadata;
|
||||||
import ca.uhn.fhir.rest.annotation.Read;
|
import ca.uhn.fhir.rest.annotation.Read;
|
||||||
import ca.uhn.fhir.rest.annotation.Search;
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
import ca.uhn.fhir.rest.client.GetClientInvocation;
|
import ca.uhn.fhir.rest.client.BaseClientInvocation;
|
||||||
|
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
|
||||||
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
import ca.uhn.fhir.rest.server.EncodingUtil;
|
||||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
@ -29,11 +39,11 @@ public abstract class BaseMethodBinding {
|
||||||
private FhirContext myContext;
|
private FhirContext myContext;
|
||||||
|
|
||||||
public BaseMethodBinding(Method theMethod, FhirContext theConetxt) {
|
public BaseMethodBinding(Method theMethod, FhirContext theConetxt) {
|
||||||
assert theMethod!=null;
|
assert theMethod != null;
|
||||||
assert theConetxt!=null;
|
assert theConetxt != null;
|
||||||
|
|
||||||
myMethod = theMethod;
|
myMethod = theMethod;
|
||||||
myContext=theConetxt;
|
myContext = theConetxt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FhirContext getContext() {
|
public FhirContext getContext() {
|
||||||
|
@ -44,7 +54,7 @@ public abstract class BaseMethodBinding {
|
||||||
return myMethod;
|
return myMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract GetClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException;
|
public abstract BaseClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException;
|
||||||
|
|
||||||
public abstract RestfulOperationTypeEnum getResourceOperationType();
|
public abstract RestfulOperationTypeEnum getResourceOperationType();
|
||||||
|
|
||||||
|
@ -52,11 +62,24 @@ public abstract class BaseMethodBinding {
|
||||||
|
|
||||||
public abstract boolean matches(Request theRequest);
|
public abstract boolean matches(Request theRequest);
|
||||||
|
|
||||||
|
protected IParser createAppropriateParser(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode) throws IOException {
|
||||||
|
IParser parser;
|
||||||
|
if (Constants.CT_ATOM_XML.equals(theResponseMimeType)) {
|
||||||
|
parser = getContext().newXmlParser();
|
||||||
|
} else if (Constants.CT_FHIR_XML.equals(theResponseMimeType)) {
|
||||||
|
parser = getContext().newXmlParser();
|
||||||
|
} else {
|
||||||
|
throw new NonFhirResponseException("Response contains non-FHIR content-type: " + theResponseMimeType, theResponseMimeType, theResponseStatusCode, IOUtils.toString(theResponseReader));
|
||||||
|
}
|
||||||
|
return parser;
|
||||||
|
}
|
||||||
|
|
||||||
public static BaseMethodBinding bindMethod(Class<? extends IResource> theReturnType, Method theMethod, FhirContext theContext) {
|
public static BaseMethodBinding bindMethod(Class<? extends IResource> theReturnType, Method theMethod, FhirContext theContext) {
|
||||||
Read read = theMethod.getAnnotation(Read.class);
|
Read read = theMethod.getAnnotation(Read.class);
|
||||||
Search search = theMethod.getAnnotation(Search.class);
|
Search search = theMethod.getAnnotation(Search.class);
|
||||||
Metadata conformance = theMethod.getAnnotation(Metadata.class);
|
Metadata conformance = theMethod.getAnnotation(Metadata.class);
|
||||||
if (!verifyMethodHasZeroOrOneOperationAnnotation(theMethod, read, search, conformance)) {
|
Create create = theMethod.getAnnotation(Create.class);
|
||||||
|
if (!verifyMethodHasZeroOrOneOperationAnnotation(theMethod, read, search, conformance,create)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,9 +100,11 @@ public abstract class BaseMethodBinding {
|
||||||
return new ReadMethodBinding(returnType, theMethod, theContext);
|
return new ReadMethodBinding(returnType, theMethod, theContext);
|
||||||
} else if (search != null) {
|
} else if (search != null) {
|
||||||
String queryName = search.queryName();
|
String queryName = search.queryName();
|
||||||
return new SearchMethodBinding(returnType, theMethod, queryName,theContext);
|
return new SearchMethodBinding(returnType, theMethod, queryName, theContext);
|
||||||
} else if (conformance != null) {
|
} else if (conformance != null) {
|
||||||
return new ConformanceMethodBinding(theMethod, theContext);
|
return new ConformanceMethodBinding(theMethod, theContext);
|
||||||
|
} else if (create != null) {
|
||||||
|
return new CreateMethodBinding(theMethod, theContext);
|
||||||
} else {
|
} else {
|
||||||
throw new ConfigurationException("Did not detect any FHIR annotations on method '" + theMethod.getName() + "' on type: " + theMethod.getDeclaringClass().getCanonicalName());
|
throw new ConfigurationException("Did not detect any FHIR annotations on method '" + theMethod.getName() + "' on type: " + theMethod.getDeclaringClass().getCanonicalName());
|
||||||
}
|
}
|
||||||
|
@ -113,8 +138,8 @@ public abstract class BaseMethodBinding {
|
||||||
if (obj1 == null) {
|
if (obj1 == null) {
|
||||||
obj1 = object;
|
obj1 = object;
|
||||||
} else {
|
} else {
|
||||||
throw new ConfigurationException("Method " + theNextMethod.getName() + " on type '" + theNextMethod.getDeclaringClass().getSimpleName() + " has annotations @" + obj1.getClass().getSimpleName() + " and @" + object.getClass().getSimpleName()
|
throw new ConfigurationException("Method " + theNextMethod.getName() + " on type '" + theNextMethod.getDeclaringClass().getSimpleName() + " has annotations @"
|
||||||
+ ". Can not have both.");
|
+ obj1.getClass().getSimpleName() + " and @" + object.getClass().getSimpleName() + ". Can not have both.");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -145,10 +170,31 @@ public abstract class BaseMethodBinding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static EncodingUtil determineResponseEncoding(HttpServletRequest theRequest, Map<String, String[]> theParams) {
|
||||||
|
String[] format = theParams.remove(Constants.PARAM_FORMAT);
|
||||||
|
if (format != null) {
|
||||||
|
for (String nextFormat : format) {
|
||||||
|
EncodingUtil retVal = Constants.FORMAT_VAL_TO_ENCODING.get(nextFormat);
|
||||||
|
if (retVal != null) {
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Enumeration<String> acceptValues = theRequest.getHeaders("Accept");
|
||||||
|
if (acceptValues != null) {
|
||||||
|
while (acceptValues.hasMoreElements()) {
|
||||||
|
EncodingUtil retVal = Constants.FORMAT_VAL_TO_ENCODING.get(acceptValues.nextElement());
|
||||||
|
if (retVal != null) {
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EncodingUtil.XML;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse) throws BaseServerResponseException, IOException;
|
public abstract void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse) throws BaseServerResponseException, IOException;
|
||||||
|
|
||||||
public abstract Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode) throws IOException;
|
public abstract Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,12 @@ import java.io.Reader;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
@ -78,15 +76,8 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
||||||
public abstract ReturnTypeEnum getReturnType();
|
public abstract ReturnTypeEnum getReturnType();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode) throws IOException {
|
public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode,Map<String, List<String>> theHeaders) throws IOException {
|
||||||
IParser parser;
|
IParser parser = createAppropriateParser(theResponseMimeType, theResponseReader, theResponseStatusCode);
|
||||||
if (Constants.CT_ATOM_XML.equals(theResponseMimeType)) {
|
|
||||||
parser = getContext().newXmlParser();
|
|
||||||
} else if (Constants.CT_FHIR_XML.equals(theResponseMimeType)) {
|
|
||||||
parser = getContext().newXmlParser();
|
|
||||||
} else {
|
|
||||||
throw new NonFhirResponseException("Response contains non-FHIR content-type: " + theResponseMimeType, theResponseMimeType, theResponseStatusCode, IOUtils.toString(theResponseReader));
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (getReturnType()) {
|
switch (getReturnType()) {
|
||||||
case BUNDLE: {
|
case BUNDLE: {
|
||||||
|
@ -125,6 +116,7 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
||||||
throw new IllegalStateException("Should not get here!");
|
throw new IllegalStateException("Should not get here!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public abstract List<IResource> invokeServer(IResourceProvider theResourceProvider, IdDt theId, IdDt theVersionId, Map<String, String[]> theParameterValues) throws InvalidRequestException, InternalErrorException;
|
public abstract List<IResource> invokeServer(IResourceProvider theResourceProvider, IdDt theId, IdDt theVersionId, Map<String, String[]> theParameterValues) throws InvalidRequestException, InternalErrorException;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -176,28 +168,6 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private EncodingUtil determineResponseEncoding(HttpServletRequest theRequest, Map<String, String[]> theParams) {
|
|
||||||
String[] format = theParams.remove(Constants.PARAM_FORMAT);
|
|
||||||
if (format != null) {
|
|
||||||
for (String nextFormat : format) {
|
|
||||||
EncodingUtil retVal = Constants.FORMAT_VAL_TO_ENCODING.get(nextFormat);
|
|
||||||
if (retVal != null) {
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Enumeration<String> acceptValues = theRequest.getHeaders("Accept");
|
|
||||||
if (acceptValues != null) {
|
|
||||||
while (acceptValues.hasMoreElements()) {
|
|
||||||
EncodingUtil retVal = Constants.FORMAT_VAL_TO_ENCODING.get(acceptValues.nextElement());
|
|
||||||
if (retVal != null) {
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return EncodingUtil.XML;
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
HashSet<String> set = new HashSet<String>();
|
HashSet<String> set = new HashSet<String>();
|
||||||
|
@ -237,6 +207,8 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
||||||
|
|
||||||
theHttpResponse.setCharacterEncoding("UTF-8");
|
theHttpResponse.setCharacterEncoding("UTF-8");
|
||||||
|
|
||||||
|
theServer.addHapiHeader(theHttpResponse);
|
||||||
|
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.getAuthorName().setValue(getClass().getCanonicalName());
|
bundle.getAuthorName().setValue(getClass().getCanonicalName());
|
||||||
bundle.getBundleId().setValue(UUID.randomUUID().toString());
|
bundle.getBundleId().setValue(UUID.randomUUID().toString());
|
||||||
|
@ -300,6 +272,7 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IResource theResource, EncodingUtil theResponseEncoding, boolean thePrettyPrint, boolean theRequestIsBrowser, NarrativeModeEnum theNarrativeMode) throws IOException {
|
private void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IResource theResource, EncodingUtil theResponseEncoding, boolean thePrettyPrint, boolean theRequestIsBrowser, NarrativeModeEnum theNarrativeMode) throws IOException {
|
||||||
|
|
||||||
theHttpResponse.setStatus(200);
|
theHttpResponse.setStatus(200);
|
||||||
|
|
|
@ -2,34 +2,86 @@ package ca.uhn.fhir.rest.method;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
|
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
||||||
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
|
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
|
||||||
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
|
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.client.GetClientInvocation;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Create;
|
||||||
|
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||||
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
|
import ca.uhn.fhir.rest.client.BaseClientInvocation;
|
||||||
|
import ca.uhn.fhir.rest.client.PostClientInvocation;
|
||||||
import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
|
import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
|
||||||
|
import ca.uhn.fhir.rest.param.IParameter;
|
||||||
|
import ca.uhn.fhir.rest.param.ResourceParameter;
|
||||||
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
import ca.uhn.fhir.rest.server.EncodingUtil;
|
||||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.UnclassifiedServerFailureException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
|
|
||||||
public class CreateMethodBinding extends BaseMethodBinding {
|
public class CreateMethodBinding extends BaseMethodBinding {
|
||||||
|
|
||||||
|
private static Set<String> ALLOWED_PARAMS;
|
||||||
|
static {
|
||||||
|
HashSet<String> set = new HashSet<String>();
|
||||||
|
set.add(Constants.PARAM_FORMAT);
|
||||||
|
ALLOWED_PARAMS = Collections.unmodifiableSet(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int myResourceParameterIndex;
|
||||||
|
private List<IParameter> myParameters;
|
||||||
|
private String myResourceName;
|
||||||
|
|
||||||
public CreateMethodBinding(Method theMethod, FhirContext theContext) {
|
public CreateMethodBinding(Method theMethod, FhirContext theContext) {
|
||||||
super(theMethod, theContext);
|
super(theMethod, theContext);
|
||||||
|
myParameters = Util.getResourceParameters(theMethod);
|
||||||
|
ResourceParameter resourceParameter = null;
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
for (IParameter next : myParameters) {
|
||||||
|
if (next instanceof ResourceParameter) {
|
||||||
|
resourceParameter = (ResourceParameter) next;
|
||||||
|
myResourceName = theContext.getResourceDefinition(resourceParameter.getResourceType()).getName();
|
||||||
|
myResourceParameterIndex = index;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
if (resourceParameter == null) {
|
||||||
public GetClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
|
throw new ConfigurationException("Method " + theMethod.getName() + " in type " + theMethod.getDeclaringClass().getCanonicalName() + " does not have a parameter annotated with @"
|
||||||
// TODO Auto-generated method stub
|
+ ResourceParam.class.getSimpleName());
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!theMethod.getReturnType().equals(MethodOutcome.class)) {
|
||||||
|
throw new ConfigurationException("Method " + theMethod.getName() + " in type " + theMethod.getDeclaringClass().getCanonicalName() + " is a @" + Create.class.getSimpleName()
|
||||||
|
+ " method but it does not return " + MethodOutcome.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RestfulOperationTypeEnum getResourceOperationType() {
|
public RestfulOperationTypeEnum getResourceOperationType() {
|
||||||
|
@ -41,12 +93,122 @@ public class CreateMethodBinding extends BaseMethodBinding {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
|
||||||
|
IResource resource = (IResource) theArgs[myResourceParameterIndex];
|
||||||
|
if (resource == null) {
|
||||||
|
throw new NullPointerException("Resource can not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeResourceDefinition def = getContext().getResourceDefinition(resource);
|
||||||
|
|
||||||
|
StringBuilder urlExtension = new StringBuilder();
|
||||||
|
urlExtension.append(def.getName());
|
||||||
|
|
||||||
|
return new PostClientInvocation(getContext(), resource, urlExtension.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode,Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
||||||
|
switch (theResponseStatusCode) {
|
||||||
|
case 400:
|
||||||
|
throw new InvalidRequestException("Server responded with: " + IOUtils.toString(theResponseReader));
|
||||||
|
case 404:
|
||||||
|
throw new ResourceNotFoundException("Server responded with: " + IOUtils.toString(theResponseReader));
|
||||||
|
case 422:
|
||||||
|
IParser parser = createAppropriateParser(theResponseMimeType, theResponseReader, theResponseStatusCode);
|
||||||
|
OperationOutcome operationOutcome = parser.parseResource(OperationOutcome.class, theResponseReader);
|
||||||
|
throw new UnprocessableEntityException(operationOutcome);
|
||||||
|
case 200: // Support 200 just to be lenient
|
||||||
|
case 201: // but it should be 201
|
||||||
|
MethodOutcome retVal = new MethodOutcome();
|
||||||
|
List<String> locationHeaders = theHeaders.get("location");
|
||||||
|
if (locationHeaders != null && locationHeaders.size() > 0) {
|
||||||
|
String h = locationHeaders.get(0);
|
||||||
|
String resourceNamePart = "/" + myResourceName + "/";
|
||||||
|
int resourceIndex = h.lastIndexOf(resourceNamePart);
|
||||||
|
if (resourceIndex > -1) {
|
||||||
|
int idIndexStart = resourceIndex + resourceNamePart.length();
|
||||||
|
int idIndexEnd = h.indexOf('/', idIndexStart);
|
||||||
|
if (idIndexEnd == -1) {
|
||||||
|
retVal.setId(new IdDt(h.substring(idIndexStart)));
|
||||||
|
}else {
|
||||||
|
retVal.setId(new IdDt(h.substring(idIndexStart, idIndexEnd)));
|
||||||
|
String versionIdPart = "/_history/";
|
||||||
|
int historyIdStart = h.indexOf(versionIdPart, idIndexEnd);
|
||||||
|
if (historyIdStart != -1) {
|
||||||
|
retVal.setVersionId(new IdDt(h.substring(historyIdStart + versionIdPart.length())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
default:
|
||||||
|
throw new UnclassifiedServerFailureException(theResponseStatusCode, IOUtils.toString(theResponseReader));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse) throws BaseServerResponseException, IOException {
|
||||||
|
EncodingUtil encoding = determineResponseEncoding(theRequest.getServletRequest(), theRequest.getParameters());
|
||||||
|
IParser parser = encoding.newParser(getContext());
|
||||||
|
IResource resource = parser.parseResource(theRequest.getInputReader());
|
||||||
|
|
||||||
|
Object[] params = new Object[myParameters.size()];
|
||||||
|
for (int i = 0; i < myParameters.size(); i++) {
|
||||||
|
IParameter param = myParameters.get(i);
|
||||||
|
params[i] = param.translateQueryParametersIntoServerArgument(theRequest.getParameters(), resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodOutcome response;
|
||||||
|
try {
|
||||||
|
response = (MethodOutcome) this.getMethod().invoke(theRequest.getResourceProvider(), params);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new InternalErrorException(e);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new InternalErrorException(e);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw new InternalErrorException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response == null) {
|
||||||
|
throw new ConfigurationException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() + " returned null");
|
||||||
|
}
|
||||||
|
|
||||||
|
theResponse.setStatus(Constants.STATUS_HTTP_201_CREATED);
|
||||||
|
|
||||||
|
StringBuilder b = new StringBuilder();
|
||||||
|
b.append(theRequest.getFhirServerBase());
|
||||||
|
b.append('/');
|
||||||
|
b.append(myResourceName);
|
||||||
|
b.append('/');
|
||||||
|
b.append(response.getId().getValue());
|
||||||
|
if (response.getVersionId().isEmpty() == false) {
|
||||||
|
b.append("/_history/");
|
||||||
|
b.append(response.getVersionId().getValue());
|
||||||
|
}
|
||||||
|
theResponse.addHeader("Location", b.toString());
|
||||||
|
|
||||||
|
theServer.addHapiHeader(theResponse);
|
||||||
|
|
||||||
|
theResponse.setContentType(Constants.CT_TEXT);
|
||||||
|
|
||||||
|
Writer writer = theResponse.getWriter();
|
||||||
|
try {
|
||||||
|
writer.append("Resource has been created");
|
||||||
|
} finally {
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
// getMethod().in
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(Request theRequest) {
|
public boolean matches(Request theRequest) {
|
||||||
if (theRequest.getRequestType()!= RequestType.POST) {
|
if (theRequest.getRequestType() != RequestType.POST) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (StringUtils.isBlank(theRequest.getResourceName())) {
|
if (!myResourceName.equals(theRequest.getResourceName())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotBlank(theRequest.getOperation())) {
|
if (StringUtils.isNotBlank(theRequest.getOperation())) {
|
||||||
|
@ -55,16 +217,4 @@ public class CreateMethodBinding extends BaseMethodBinding {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse) throws BaseServerResponseException, IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode) throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package ca.uhn.fhir.rest.method;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
@ -19,11 +18,11 @@ import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.rest.client.GetClientInvocation;
|
import ca.uhn.fhir.rest.client.GetClientInvocation;
|
||||||
import ca.uhn.fhir.rest.param.IParameter;
|
import ca.uhn.fhir.rest.param.IParameter;
|
||||||
|
import ca.uhn.fhir.rest.param.IQueryParameter;
|
||||||
import ca.uhn.fhir.rest.server.Constants;
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.util.QueryUtil;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by dsotnikov on 2/25/2014.
|
* Created by dsotnikov on 2/25/2014.
|
||||||
|
@ -69,43 +68,20 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
||||||
public GetClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
|
public GetClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
|
||||||
assert (myQueryName == null || ((theArgs != null ? theArgs.length : 0) == myParameters.size())) : "Wrong number of arguments: " + theArgs;
|
assert (myQueryName == null || ((theArgs != null ? theArgs.length : 0) == myParameters.size())) : "Wrong number of arguments: " + theArgs;
|
||||||
|
|
||||||
Map<String, List<String>> args = new LinkedHashMap<String, List<String>>();
|
Map<String, List<String>> queryStringArgs = new LinkedHashMap<String, List<String>>();
|
||||||
|
|
||||||
if (myQueryName != null) {
|
if (myQueryName != null) {
|
||||||
args.put(Constants.PARAM_QUERY, Collections.singletonList(myQueryName));
|
queryStringArgs.put(Constants.PARAM_QUERY, Collections.singletonList(myQueryName));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theArgs != null) {
|
if (theArgs != null) {
|
||||||
for (int idx = 0; idx < theArgs.length; idx++) {
|
for (int idx = 0; idx < theArgs.length; idx++) {
|
||||||
Object object = theArgs[idx];
|
|
||||||
IParameter nextParam = myParameters.get(idx);
|
IParameter nextParam = myParameters.get(idx);
|
||||||
|
nextParam.translateClientArgumentIntoQueryArgument(theArgs[idx], queryStringArgs);
|
||||||
if (object == null) {
|
|
||||||
if (nextParam.isRequired()) {
|
|
||||||
throw new NullPointerException("SearchParameter '" + nextParam.getName() + "' is required and may not be null");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
List<List<String>> value = nextParam.encode(object);
|
|
||||||
ArrayList<String> paramValues = new ArrayList<String>(value.size());
|
|
||||||
args.put(nextParam.getName(), paramValues);
|
|
||||||
|
|
||||||
for (List<String> nextParamEntry : value) {
|
|
||||||
StringBuilder b = new StringBuilder();
|
|
||||||
for (String str : nextParamEntry) {
|
|
||||||
if (b.length() > 0) {
|
|
||||||
b.append(",");
|
|
||||||
}
|
|
||||||
b.append(str.replace(",", "\\,"));
|
|
||||||
}
|
|
||||||
paramValues.add(b.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GetClientInvocation(args, getResourceName());
|
return new GetClientInvocation(queryStringArgs, getResourceName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -117,25 +93,7 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
||||||
Object[] params = new Object[myParameters.size()];
|
Object[] params = new Object[myParameters.size()];
|
||||||
for (int i = 0; i < myParameters.size(); i++) {
|
for (int i = 0; i < myParameters.size(); i++) {
|
||||||
IParameter param = myParameters.get(i);
|
IParameter param = myParameters.get(i);
|
||||||
String[] value = parameterValues.get(param.getName());
|
params[i] = param.translateQueryParametersIntoServerArgument(parameterValues, null);
|
||||||
if (value == null || value.length == 0) {
|
|
||||||
if (param.handlesMissing()) {
|
|
||||||
params[i] = param.parse(new ArrayList<List<String>>(0));
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<List<String>> paramList = new ArrayList<List<String>>(value.length);
|
|
||||||
for (String nextParam : value) {
|
|
||||||
if (nextParam.contains(",") == false) {
|
|
||||||
paramList.add(Collections.singletonList(nextParam));
|
|
||||||
} else {
|
|
||||||
paramList.add(QueryUtil.splitQueryStringByCommasIgnoreEscape(nextParam));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
params[i] = param.parse(paramList);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Object response;
|
Object response;
|
||||||
|
@ -174,7 +132,10 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
||||||
|
|
||||||
Set<String> methodParamsTemp = new HashSet<String>();
|
Set<String> methodParamsTemp = new HashSet<String>();
|
||||||
for (int i = 0; i < this.myParameters.size(); i++) {
|
for (int i = 0; i < this.myParameters.size(); i++) {
|
||||||
IParameter temp = this.myParameters.get(i);
|
if (!(myParameters.get(i) instanceof IQueryParameter)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
IQueryParameter temp = (IQueryParameter) myParameters.get(i);
|
||||||
methodParamsTemp.add(temp.getName());
|
methodParamsTemp.add(temp.getName());
|
||||||
if (temp.isRequired() && !theRequest.getParameters().containsKey(temp.getName())) {
|
if (temp.isRequired() && !theRequest.getParameters().containsKey(temp.getName())) {
|
||||||
ourLog.trace("Method {} doesn't match param '{}' is not present", getMethod().getName(), temp.getName());
|
ourLog.trace("Method {} doesn't match param '{}' is not present", getMethod().getName(), temp.getName());
|
||||||
|
|
|
@ -11,15 +11,18 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.api.PathSpecification;
|
import ca.uhn.fhir.model.api.PathSpecification;
|
||||||
import ca.uhn.fhir.rest.annotation.Id;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Include;
|
import ca.uhn.fhir.rest.annotation.IncludeParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Optional;
|
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Required;
|
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||||
import ca.uhn.fhir.rest.annotation.VersionId;
|
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.VersionIdParam;
|
||||||
import ca.uhn.fhir.rest.param.CollectionBinder;
|
import ca.uhn.fhir.rest.param.CollectionBinder;
|
||||||
import ca.uhn.fhir.rest.param.IParameter;
|
import ca.uhn.fhir.rest.param.IParameter;
|
||||||
import ca.uhn.fhir.rest.param.IncludeParameter;
|
import ca.uhn.fhir.rest.param.IncludeParameter;
|
||||||
|
import ca.uhn.fhir.rest.param.ResourceParameter;
|
||||||
import ca.uhn.fhir.rest.param.SearchParameter;
|
import ca.uhn.fhir.rest.param.SearchParameter;
|
||||||
import ca.uhn.fhir.util.ReflectionUtil;
|
import ca.uhn.fhir.util.ReflectionUtil;
|
||||||
|
|
||||||
|
@ -71,25 +74,30 @@ class Util {
|
||||||
}
|
}
|
||||||
|
|
||||||
IParameter param;
|
IParameter param;
|
||||||
if (nextAnnotation instanceof Required) {
|
if (nextAnnotation instanceof RequiredParam) {
|
||||||
SearchParameter parameter = new SearchParameter();
|
SearchParameter parameter = new SearchParameter();
|
||||||
parameter.setName(((Required) nextAnnotation).name());
|
parameter.setName(((RequiredParam) nextAnnotation).name());
|
||||||
parameter.setRequired(true);
|
parameter.setRequired(true);
|
||||||
parameter.setType(parameterType, innerCollectionType, outerCollectionType);
|
parameter.setType(parameterType, innerCollectionType, outerCollectionType);
|
||||||
param = parameter;
|
param = parameter;
|
||||||
} else if (nextAnnotation instanceof Optional) {
|
} else if (nextAnnotation instanceof OptionalParam) {
|
||||||
SearchParameter parameter = new SearchParameter();
|
SearchParameter parameter = new SearchParameter();
|
||||||
parameter.setName(((Optional) nextAnnotation).name());
|
parameter.setName(((OptionalParam) nextAnnotation).name());
|
||||||
parameter.setRequired(false);
|
parameter.setRequired(false);
|
||||||
parameter.setType(parameterType, innerCollectionType, innerCollectionType);
|
parameter.setType(parameterType, innerCollectionType, innerCollectionType);
|
||||||
param = parameter;
|
param = parameter;
|
||||||
} else if (nextAnnotation instanceof Include) {
|
} else if (nextAnnotation instanceof IncludeParam) {
|
||||||
if (parameterType != PathSpecification.class || innerCollectionType == null || outerCollectionType != null) {
|
if (parameterType != PathSpecification.class || innerCollectionType == null || outerCollectionType != null) {
|
||||||
throw new ConfigurationException("Method '" + method.getName() + "' is annotated with @" + Include.class.getSimpleName() + " but has a type other than Collection<"+PathSpecification.class.getSimpleName() + ">");
|
throw new ConfigurationException("Method '" + method.getName() + "' is annotated with @" + IncludeParam.class.getSimpleName() + " but has a type other than Collection<"+PathSpecification.class.getSimpleName() + ">");
|
||||||
}
|
}
|
||||||
Class<? extends Collection<PathSpecification>> instantiableCollectionType = (Class<? extends Collection<PathSpecification>>) CollectionBinder.getInstantiableCollectionType(innerCollectionType, "Method '" + method.getName() + "'");
|
Class<? extends Collection<PathSpecification>> instantiableCollectionType = (Class<? extends Collection<PathSpecification>>) CollectionBinder.getInstantiableCollectionType(innerCollectionType, "Method '" + method.getName() + "'");
|
||||||
|
|
||||||
param = new IncludeParameter((Include) nextAnnotation, instantiableCollectionType);
|
param = new IncludeParameter((IncludeParam) nextAnnotation, instantiableCollectionType);
|
||||||
|
} else if (nextAnnotation instanceof ResourceParam) {
|
||||||
|
if (!IResource.class.isAssignableFrom(parameterType)) {
|
||||||
|
throw new ConfigurationException("Method '" + method.getName() + "' is annotated with @" + ResourceParam.class.getSimpleName() + " but has a type that is not an implemtation of " + IResource.class.getCanonicalName());
|
||||||
|
}
|
||||||
|
param = new ResourceParameter((Class<? extends IResource>) parameterType);
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -108,11 +116,11 @@ class Util {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Integer findReadIdParameterIndex(Method theMethod) {
|
public static Integer findReadIdParameterIndex(Method theMethod) {
|
||||||
return findParamIndex(theMethod, Id.class);
|
return findParamIndex(theMethod, IdParam.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Integer findReadVersionIdParameterIndex(Method theMethod) {
|
public static Integer findReadVersionIdParameterIndex(Method theMethod) {
|
||||||
return findParamIndex(theMethod, VersionId.class);
|
return findParamIndex(theMethod, VersionIdParam.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Integer findParamIndex(Method theMethod, Class<?> toFind) {
|
private static Integer findParamIndex(Method theMethod, Class<?> toFind) {
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
package ca.uhn.fhir.rest.param;
|
package ca.uhn.fhir.rest.param;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
|
||||||
public interface IParameter {
|
public interface IParameter {
|
||||||
|
|
||||||
List<List<String>> encode(Object theObject) throws InternalErrorException;
|
void translateClientArgumentIntoQueryArgument(Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments) throws InternalErrorException;
|
||||||
|
|
||||||
String getName();
|
|
||||||
|
|
||||||
Object parse(List<List<String>> theString) throws InternalErrorException, InvalidRequestException;
|
|
||||||
|
|
||||||
boolean isRequired();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameter should return true if {@link #parse(List)} should be called even
|
* This <b>server method</b> method takes the data received by the server in an incoming request, and translates that data into a single argument for a server method invocation. Note that all
|
||||||
* if the query string contained no values for the given parameter
|
* received data is passed to this method, but the expectation is that not necessarily that all data is used by every parameter.
|
||||||
|
*
|
||||||
|
* @param theQueryParameters
|
||||||
|
* The query params, e.g. ?family=smith&given=john
|
||||||
|
* @param theRequestContents
|
||||||
|
* The parsed contents of the incoming request. E.g. if the request was an HTTP POST with a resource in the body, this argument would contain the parsed {@link IResource} instance.
|
||||||
|
* @return Returns the argument object as it will be passed to the {@link IResourceProvider} method.
|
||||||
*/
|
*/
|
||||||
boolean handlesMissing();
|
Object translateQueryParametersIntoServerArgument(Map<String, String[]> theQueryParameters, Object theRequestContents) throws InternalErrorException, InvalidRequestException;
|
||||||
|
|
||||||
SearchParamTypeEnum getParamType();
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
package ca.uhn.fhir.rest.param;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
import ca.uhn.fhir.util.QueryUtil;
|
||||||
|
|
||||||
|
public abstract class IQueryParameter implements IParameter {
|
||||||
|
|
||||||
|
public abstract List<List<String>> encode(Object theObject) throws InternalErrorException;
|
||||||
|
|
||||||
|
public abstract String getName();
|
||||||
|
|
||||||
|
public abstract Object parse(List<List<String>> theString) throws InternalErrorException, InvalidRequestException;
|
||||||
|
|
||||||
|
public abstract boolean isRequired();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameter should return true if {@link #parse(List)} should be called even
|
||||||
|
* if the query string contained no values for the given parameter
|
||||||
|
*/
|
||||||
|
public abstract boolean handlesMissing();
|
||||||
|
|
||||||
|
public abstract SearchParamTypeEnum getParamType();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void translateClientArgumentIntoQueryArgument(Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments) throws InternalErrorException {
|
||||||
|
if (theSourceClientArgument == null) {
|
||||||
|
if (isRequired()) {
|
||||||
|
throw new NullPointerException("SearchParameter '" + getName() + "' is required and may not be null");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
List<List<String>> value = encode(theSourceClientArgument);
|
||||||
|
ArrayList<String> paramValues = new ArrayList<String>(value.size());
|
||||||
|
theTargetQueryArguments.put(getName(), paramValues);
|
||||||
|
|
||||||
|
for (List<String> nextParamEntry : value) {
|
||||||
|
StringBuilder b = new StringBuilder();
|
||||||
|
for (String str : nextParamEntry) {
|
||||||
|
if (b.length() > 0) {
|
||||||
|
b.append(",");
|
||||||
|
}
|
||||||
|
b.append(str.replace(",", "\\,"));
|
||||||
|
}
|
||||||
|
paramValues.add(b.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object translateQueryParametersIntoServerArgument(Map<String, String[]> theQueryParameters, Object theRequestContents) throws InternalErrorException, InvalidRequestException {
|
||||||
|
String[] value = theQueryParameters.get(getName());
|
||||||
|
if (value == null || value.length == 0) {
|
||||||
|
if (handlesMissing()) {
|
||||||
|
return parse(new ArrayList<List<String>>(0));
|
||||||
|
}else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<List<String>> paramList = new ArrayList<List<String>>(value.length);
|
||||||
|
for (String nextParam : value) {
|
||||||
|
if (nextParam.contains(",") == false) {
|
||||||
|
paramList.add(Collections.singletonList(nextParam));
|
||||||
|
} else {
|
||||||
|
paramList.add(QueryUtil.splitQueryStringByCommasIgnoreEscape(nextParam));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse(paramList);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -9,16 +9,16 @@ import java.util.TreeSet;
|
||||||
|
|
||||||
import ca.uhn.fhir.model.api.PathSpecification;
|
import ca.uhn.fhir.model.api.PathSpecification;
|
||||||
import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum;
|
import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum;
|
||||||
import ca.uhn.fhir.rest.annotation.Include;
|
import ca.uhn.fhir.rest.annotation.IncludeParam;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
|
||||||
public class IncludeParameter implements IParameter {
|
public class IncludeParameter extends IQueryParameter {
|
||||||
|
|
||||||
private Class<? extends Collection<PathSpecification>> myInstantiableCollectionType;
|
private Class<? extends Collection<PathSpecification>> myInstantiableCollectionType;
|
||||||
private HashSet<String> myAllow;
|
private HashSet<String> myAllow;
|
||||||
|
|
||||||
public IncludeParameter(Include theAnnotation, Class<? extends Collection<PathSpecification>> theInstantiableCollectionType) {
|
public IncludeParameter(IncludeParam theAnnotation, Class<? extends Collection<PathSpecification>> theInstantiableCollectionType) {
|
||||||
myInstantiableCollectionType = theInstantiableCollectionType;
|
myInstantiableCollectionType = theInstantiableCollectionType;
|
||||||
if (theAnnotation.allow().length > 0) {
|
if (theAnnotation.allow().length > 0) {
|
||||||
myAllow = new HashSet<String>();
|
myAllow = new HashSet<String>();
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package ca.uhn.fhir.rest.param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
|
||||||
|
public class ResourceParameter implements IParameter {
|
||||||
|
|
||||||
|
private Class<? extends IResource> myResourceName ;
|
||||||
|
|
||||||
|
public ResourceParameter(Class<? extends IResource> theParameterType) {
|
||||||
|
myResourceName =theParameterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void translateClientArgumentIntoQueryArgument(Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments) throws InternalErrorException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object translateQueryParametersIntoServerArgument(Map<String, String[]> theQueryParameters, Object theRequestContents) throws InternalErrorException, InvalidRequestException {
|
||||||
|
IResource resource = (IResource) theRequestContents;
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<? extends IResource> getResourceType() {
|
||||||
|
return myResourceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public IResource
|
||||||
|
|
||||||
|
}
|
|
@ -16,10 +16,10 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
/**
|
/**
|
||||||
* Created by dsotnikov on 2/25/2014.
|
* Created by dsotnikov on 2/25/2014.
|
||||||
*/
|
*/
|
||||||
public class SearchParameter implements IParameter {
|
public class SearchParameter extends IQueryParameter {
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private IParamBinder parser;
|
private IParamBinder myParamBinder;
|
||||||
private boolean required;
|
private boolean required;
|
||||||
private Class<?> type;
|
private Class<?> type;
|
||||||
private SearchParamTypeEnum myParamType;
|
private SearchParamTypeEnum myParamType;
|
||||||
|
@ -37,7 +37,7 @@ public class SearchParameter implements IParameter {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<List<String>> encode(Object theObject) throws InternalErrorException {
|
public List<List<String>> encode(Object theObject) throws InternalErrorException {
|
||||||
return parser.encode(theObject);
|
return myParamBinder.encode(theObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
@ -62,7 +62,7 @@ public class SearchParameter implements IParameter {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object parse(List<List<String>> theString) throws InternalErrorException, InvalidRequestException {
|
public Object parse(List<List<String>> theString) throws InternalErrorException, InvalidRequestException {
|
||||||
return parser.parse(theString);
|
return myParamBinder.parse(theString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
|
@ -77,11 +77,11 @@ public class SearchParameter implements IParameter {
|
||||||
public void setType(final Class<?> type, Class<? extends Collection<?>> theInnerCollectionType, Class<? extends Collection<?>> theOuterCollectionType) {
|
public void setType(final Class<?> type, Class<? extends Collection<?>> theInnerCollectionType, Class<? extends Collection<?>> theOuterCollectionType) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
if (IQueryParameterType.class.isAssignableFrom(type)) {
|
if (IQueryParameterType.class.isAssignableFrom(type)) {
|
||||||
this.parser = new QueryParameterTypeBinder((Class<? extends IQueryParameterType>) type);
|
this.myParamBinder = new QueryParameterTypeBinder((Class<? extends IQueryParameterType>) type);
|
||||||
} else if (IQueryParameterOr.class.isAssignableFrom(type)) {
|
} else if (IQueryParameterOr.class.isAssignableFrom(type)) {
|
||||||
this.parser = new QueryParameterOrBinder((Class<? extends IQueryParameterOr>) type);
|
this.myParamBinder = new QueryParameterOrBinder((Class<? extends IQueryParameterOr>) type);
|
||||||
} else if (IQueryParameterAnd.class.isAssignableFrom(type)) {
|
} else if (IQueryParameterAnd.class.isAssignableFrom(type)) {
|
||||||
this.parser = new QueryParameterAndBinder((Class<? extends IQueryParameterAnd>) type);
|
this.myParamBinder = new QueryParameterAndBinder((Class<? extends IQueryParameterAnd>) type);
|
||||||
} else {
|
} else {
|
||||||
throw new ConfigurationException("Unsupported data type for parameter: " + type.getCanonicalName());
|
throw new ConfigurationException("Unsupported data type for parameter: " + type.getCanonicalName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@ public class Constants {
|
||||||
public static final String PARAM_HISTORY = "_history";
|
public static final String PARAM_HISTORY = "_history";
|
||||||
public static final String PARAM_PRETTY = "_pretty";
|
public static final String PARAM_PRETTY = "_pretty";
|
||||||
public static final String PARAM_QUERY = "_query";
|
public static final String PARAM_QUERY = "_query";
|
||||||
|
public static final int STATUS_HTTP_201_CREATED = 201;
|
||||||
|
public static final String CT_TEXT = "text/plain";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Map<String, EncodingUtil> valToEncoding = new HashMap<String, EncodingUtil>();
|
Map<String, EncodingUtil> valToEncoding = new HashMap<String, EncodingUtil>();
|
||||||
|
|
|
@ -1,10 +1,23 @@
|
||||||
package ca.uhn.fhir.rest.server;
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
|
||||||
public enum EncodingUtil {
|
public enum EncodingUtil {
|
||||||
|
|
||||||
XML(Constants.CT_FHIR_XML, Constants.CT_ATOM_XML, Constants.CT_XML),
|
XML(Constants.CT_FHIR_XML, Constants.CT_ATOM_XML, Constants.CT_XML) {
|
||||||
|
@Override
|
||||||
|
public IParser newParser(FhirContext theContext) {
|
||||||
|
return theContext.newXmlParser();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
JSON(Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON, Constants.CT_JSON)
|
JSON(Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON, Constants.CT_JSON) {
|
||||||
|
@Override
|
||||||
|
public IParser newParser(FhirContext theContext) {
|
||||||
|
return theContext.newJsonParser();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -18,6 +31,8 @@ public enum EncodingUtil {
|
||||||
myBrowserFriendlyContentType = theBrowserFriendlyContentType;
|
myBrowserFriendlyContentType = theBrowserFriendlyContentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract IParser newParser(FhirContext theContext);
|
||||||
|
|
||||||
public String getBundleContentType() {
|
public String getBundleContentType() {
|
||||||
return myBundleContentType;
|
return myBundleContentType;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.MethodNotFoundException;
|
||||||
import ca.uhn.fhir.rest.server.provider.ServerConformanceProvider;
|
import ca.uhn.fhir.rest.server.provider.ServerConformanceProvider;
|
||||||
import ca.uhn.fhir.rest.server.provider.ServerProfileProvider;
|
import ca.uhn.fhir.rest.server.provider.ServerProfileProvider;
|
||||||
|
import ca.uhn.fhir.util.VersionUtil;
|
||||||
|
|
||||||
public abstract class RestfulServer extends HttpServlet {
|
public abstract class RestfulServer extends HttpServlet {
|
||||||
|
|
||||||
|
@ -312,6 +313,9 @@ public abstract class RestfulServer extends HttpServlet {
|
||||||
|
|
||||||
} catch (AuthenticationException e) {
|
} catch (AuthenticationException e) {
|
||||||
response.setStatus(e.getStatusCode());
|
response.setStatus(e.getStatusCode());
|
||||||
|
addHapiHeader(response);
|
||||||
|
response.setContentType("text/plain");
|
||||||
|
response.setCharacterEncoding("UTF-8");
|
||||||
response.getWriter().write(e.getMessage());
|
response.getWriter().write(e.getMessage());
|
||||||
} catch (BaseServerResponseException e) {
|
} catch (BaseServerResponseException e) {
|
||||||
|
|
||||||
|
@ -322,6 +326,7 @@ public abstract class RestfulServer extends HttpServlet {
|
||||||
}
|
}
|
||||||
|
|
||||||
response.setStatus(e.getStatusCode());
|
response.setStatus(e.getStatusCode());
|
||||||
|
addHapiHeader(response);
|
||||||
response.setContentType("text/plain");
|
response.setContentType("text/plain");
|
||||||
response.setCharacterEncoding("UTF-8");
|
response.setCharacterEncoding("UTF-8");
|
||||||
response.getWriter().append(e.getMessage());
|
response.getWriter().append(e.getMessage());
|
||||||
|
@ -352,5 +357,8 @@ public abstract class RestfulServer extends HttpServlet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addHapiHeader(HttpServletResponse theHttpResponse) {
|
||||||
|
theHttpResponse.addHeader("X-CatchingFhir", "HAPI FHIR " + VersionUtil.getVersion());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package ca.uhn.fhir.rest.server.exceptions;
|
package ca.uhn.fhir.rest.server.exceptions;
|
||||||
|
|
||||||
public abstract class BaseServerResponseException extends Exception {
|
public abstract class BaseServerResponseException extends RuntimeException {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,10 @@ public class ResourceNotFoundException extends BaseServerResponseException {
|
||||||
super(404, "Resource of type " + theClass.getSimpleName() + " with ID " + thePatientId + " is not known");
|
super(404, "Resource of type " + theClass.getSimpleName() + " with ID " + thePatientId + " is not known");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ResourceNotFoundException(String theMessage) {
|
||||||
|
super(404, theMessage);
|
||||||
|
}
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package ca.uhn.fhir.rest.server.exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for use when a response is received or being sent that
|
||||||
|
* does not correspond to any other exception type
|
||||||
|
*/
|
||||||
|
public class UnclassifiedServerFailureException extends BaseServerResponseException {
|
||||||
|
|
||||||
|
public UnclassifiedServerFailureException(int theStatusCode, String theMessage) {
|
||||||
|
super(theStatusCode, theMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package ca.uhn.fhir.rest.server.exceptions;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an <b>HTTP 422 Unprocessable Entity</b> response, which means that a resource was rejected by the server because it "violated applicable FHIR profiles or server business rules".
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This exception will generally contain an {@link OperationOutcome} instance which details the failure.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class UnprocessableEntityException extends BaseServerResponseException {
|
||||||
|
|
||||||
|
private OperationOutcome myOperationOutcome;
|
||||||
|
|
||||||
|
public UnprocessableEntityException(OperationOutcome theOperationOutcome) {
|
||||||
|
super(422, "Unprocessable Entity");
|
||||||
|
|
||||||
|
myOperationOutcome = theOperationOutcome;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnprocessableEntityException(String theMessage) {
|
||||||
|
super(422, theMessage);
|
||||||
|
|
||||||
|
myOperationOutcome = new OperationOutcome();
|
||||||
|
myOperationOutcome.addIssue().setDetails(theMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnprocessableEntityException(String... theMessage) {
|
||||||
|
super(422, theMessage != null && theMessage.length > 0 ? theMessage[0] : "");
|
||||||
|
|
||||||
|
myOperationOutcome = new OperationOutcome();
|
||||||
|
if (theMessage != null) {
|
||||||
|
for (String next : theMessage) {
|
||||||
|
myOperationOutcome.addIssue().setDetails(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationOutcome getOperationOutcome() {
|
||||||
|
return myOperationOutcome;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ import ca.uhn.fhir.rest.annotation.Metadata;
|
||||||
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
||||||
import ca.uhn.fhir.rest.method.SearchMethodBinding;
|
import ca.uhn.fhir.rest.method.SearchMethodBinding;
|
||||||
import ca.uhn.fhir.rest.param.IParameter;
|
import ca.uhn.fhir.rest.param.IParameter;
|
||||||
|
import ca.uhn.fhir.rest.param.IQueryParameter;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
import ca.uhn.fhir.rest.server.ResourceBinding;
|
import ca.uhn.fhir.rest.server.ResourceBinding;
|
||||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
|
@ -87,7 +88,12 @@ public class ServerConformanceProvider implements IResourceProvider {
|
||||||
|
|
||||||
RestResourceSearchParam searchParam = null;
|
RestResourceSearchParam searchParam = null;
|
||||||
StringDt searchParamChain = null;
|
StringDt searchParamChain = null;
|
||||||
for (IParameter nextParameter : params) {
|
for (IParameter nextParameterObj : params) {
|
||||||
|
if (!(nextParameterObj instanceof IQueryParameter)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IQueryParameter nextParameter = (IQueryParameter)nextParameterObj;
|
||||||
if (nextParameter.getName().startsWith("_")) {
|
if (nextParameter.getName().startsWith("_")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Profile;
|
import ca.uhn.fhir.model.dstu.resource.Profile;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.rest.annotation.Id;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Read;
|
import ca.uhn.fhir.rest.annotation.Read;
|
||||||
import ca.uhn.fhir.rest.annotation.Search;
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
@ -29,7 +29,7 @@ public class ServerProfileProvider implements IResourceProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Read()
|
@Read()
|
||||||
public Profile getProfileById(@Id IdDt theId) {
|
public Profile getProfileById(@IdParam IdDt theId) {
|
||||||
RuntimeResourceDefinition retVal = myContext.getResourceDefinitionById(theId.getValue());
|
RuntimeResourceDefinition retVal = myContext.getResourceDefinitionById(theId.getValue());
|
||||||
if (retVal==null) {
|
if (retVal==null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -9,7 +9,7 @@ import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||||
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
|
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Organization;
|
import ca.uhn.fhir.model.dstu.resource.Organization;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
import ca.uhn.fhir.rest.annotation.Required;
|
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Search;
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ public class CompleteExampleClient {
|
||||||
* http://fhir.healthintersections.com.au/open/Patient?identifier=urn:oid:1.2.36.146.595.217.0.1%7C12345
|
* http://fhir.healthintersections.com.au/open/Patient?identifier=urn:oid:1.2.36.146.595.217.0.1%7C12345
|
||||||
*/
|
*/
|
||||||
@Search
|
@Search
|
||||||
List<Patient> findPatientsForMrn(@Required(name=Patient.SP_IDENTIFIER) IdentifierDt theIdentifier);
|
List<Patient> findPatientsForMrn(@RequiredParam(name=Patient.SP_IDENTIFIER) IdentifierDt theIdentifier);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,53 @@
|
||||||
package example;
|
package example;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
|
import ca.uhn.fhir.model.dstu.valueset.AdministrativeGenderCodesEnum;
|
||||||
|
import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum;
|
||||||
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Create;
|
||||||
|
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.api.MethodOutcome;
|
||||||
|
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||||
|
import static ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum.*;
|
||||||
|
|
||||||
public class QuickUsage {
|
public class QuickUsage {
|
||||||
|
|
||||||
public void format() {
|
public static void main(String[] args) throws DataFormatException, IOException {
|
||||||
|
|
||||||
Patient obs = new Patient();
|
Patient patient = new Patient();
|
||||||
|
patient.addIdentifier().setUse(OFFICIAL).setSystem("urn:fake:mrns").setValue("7000135");
|
||||||
|
patient.addIdentifier().setUse(SECONDARY).setSystem("urn:fake:otherids").setValue("3287486");
|
||||||
|
|
||||||
|
patient.addName().addFamily("Smith").addGiven("John").addGiven("Q").addSuffix("Junior");
|
||||||
|
|
||||||
|
patient.setGender(AdministrativeGenderCodesEnum.M);
|
||||||
|
|
||||||
|
|
||||||
|
FhirContext ctx = new FhirContext();
|
||||||
|
String xmlEncoded = ctx.newXmlParser().encodeResourceToString(patient);
|
||||||
|
String jsonEncoded = ctx.newJsonParser().encodeResourceToString(patient);
|
||||||
|
|
||||||
|
MyClientInterface client = ctx.newRestfulClient(MyClientInterface.class, "http://foo/fhir");
|
||||||
|
IdentifierDt searchParam = new IdentifierDt("urn:someidentifiers", "7000135");
|
||||||
|
List<Patient> clients = client.findPatientsByIdentifier(searchParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface MyClientInterface extends IRestfulClient
|
||||||
|
{
|
||||||
|
/** A FHIR search */
|
||||||
|
@Search
|
||||||
|
public List<Patient> findPatientsByIdentifier(@RequiredParam(name="identifier") IdentifierDt theIdentifier);
|
||||||
|
|
||||||
|
/** A FHIR create */
|
||||||
|
@Create
|
||||||
|
public MethodOutcome createPatient(@ResourceParam Patient thePatient);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,9 @@ import java.util.List;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
import ca.uhn.fhir.rest.annotation.Id;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Read;
|
import ca.uhn.fhir.rest.annotation.Read;
|
||||||
import ca.uhn.fhir.rest.annotation.Required;
|
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Search;
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
import ca.uhn.fhir.rest.client.api.IBasicClient;
|
import ca.uhn.fhir.rest.client.api.IBasicClient;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ public interface RestfulClientImpl extends IBasicClient {
|
||||||
* Returns a resource matching this identifier, or null if none exists.
|
* Returns a resource matching this identifier, or null if none exists.
|
||||||
*/
|
*/
|
||||||
@Read()
|
@Read()
|
||||||
public Patient getResourceById(@Id IdDt theId);
|
public Patient getResourceById(@IdParam IdDt theId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The "@Search" annotation indicates that this method supports the
|
* The "@Search" annotation indicates that this method supports the
|
||||||
|
@ -48,7 +48,7 @@ public interface RestfulClientImpl extends IBasicClient {
|
||||||
* matching resources, or it may also be empty.
|
* matching resources, or it may also be empty.
|
||||||
*/
|
*/
|
||||||
@Search()
|
@Search()
|
||||||
public List<Patient> getPatient(@Required(name = Patient.SP_FAMILY) StringDt theFamilyName);
|
public List<Patient> getPatient(@RequiredParam(name = Patient.SP_FAMILY) StringDt theFamilyName);
|
||||||
|
|
||||||
}
|
}
|
||||||
//END SNIPPET: provider
|
//END SNIPPET: provider
|
||||||
|
|
|
@ -9,9 +9,9 @@ import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
import ca.uhn.fhir.model.primitive.UriDt;
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
import ca.uhn.fhir.rest.annotation.Id;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Read;
|
import ca.uhn.fhir.rest.annotation.Read;
|
||||||
import ca.uhn.fhir.rest.annotation.Required;
|
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Search;
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ public class RestfulObservationResourceProvider implements IResourceProvider {
|
||||||
* Returns a resource matching this identifier, or null if none exists.
|
* Returns a resource matching this identifier, or null if none exists.
|
||||||
*/
|
*/
|
||||||
@Read()
|
@Read()
|
||||||
public Patient getResourceById(@Id IdDt theId) {
|
public Patient getResourceById(@IdParam IdDt theId) {
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
patient.addIdentifier();
|
patient.addIdentifier();
|
||||||
patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
|
patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
|
||||||
|
@ -70,7 +70,7 @@ public class RestfulObservationResourceProvider implements IResourceProvider {
|
||||||
* matching resources, or it may also be empty.
|
* matching resources, or it may also be empty.
|
||||||
*/
|
*/
|
||||||
@Search()
|
@Search()
|
||||||
public List<Patient> getPatient(@Required(name = Patient.SP_FAMILY) StringDt theFamilyName) {
|
public List<Patient> getPatient(@RequiredParam(name = Patient.SP_FAMILY) StringDt theFamilyName) {
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
patient.addIdentifier();
|
patient.addIdentifier();
|
||||||
patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
|
patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
|
||||||
|
|
|
@ -9,9 +9,9 @@ import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
import ca.uhn.fhir.model.primitive.UriDt;
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
import ca.uhn.fhir.rest.annotation.Id;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Read;
|
import ca.uhn.fhir.rest.annotation.Read;
|
||||||
import ca.uhn.fhir.rest.annotation.Required;
|
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Search;
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ public class RestfulPatientResourceProvider implements IResourceProvider {
|
||||||
* Returns a resource matching this identifier, or null if none exists.
|
* Returns a resource matching this identifier, or null if none exists.
|
||||||
*/
|
*/
|
||||||
@Read()
|
@Read()
|
||||||
public Patient getResourceById(@Id IdDt theId) {
|
public Patient getResourceById(@IdParam IdDt theId) {
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
patient.addIdentifier();
|
patient.addIdentifier();
|
||||||
patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
|
patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
|
||||||
|
@ -71,7 +71,7 @@ public class RestfulPatientResourceProvider implements IResourceProvider {
|
||||||
* matching resources, or it may also be empty.
|
* matching resources, or it may also be empty.
|
||||||
*/
|
*/
|
||||||
@Search()
|
@Search()
|
||||||
public List<Patient> getPatient(@Required(name = Patient.SP_FAMILY) StringDt theFamilyName) {
|
public List<Patient> getPatient(@RequiredParam(name = Patient.SP_FAMILY) StringDt theFamilyName) {
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
patient.addIdentifier();
|
patient.addIdentifier();
|
||||||
patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
|
patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
|
||||||
|
|
|
@ -17,21 +17,25 @@ import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
import ca.uhn.fhir.rest.annotation.Id;
|
import ca.uhn.fhir.rest.annotation.Create;
|
||||||
import ca.uhn.fhir.rest.annotation.Include;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Optional;
|
import ca.uhn.fhir.rest.annotation.IncludeParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Read;
|
import ca.uhn.fhir.rest.annotation.Read;
|
||||||
import ca.uhn.fhir.rest.annotation.Required;
|
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.Search;
|
||||||
import ca.uhn.fhir.rest.annotation.VersionId;
|
import ca.uhn.fhir.rest.annotation.VersionIdParam;
|
||||||
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
import ca.uhn.fhir.rest.client.ITestClient;
|
import ca.uhn.fhir.rest.client.ITestClient;
|
||||||
import ca.uhn.fhir.rest.param.CodingListParam;
|
import ca.uhn.fhir.rest.param.CodingListParam;
|
||||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||||
import ca.uhn.fhir.rest.param.QualifiedDateParam;
|
import ca.uhn.fhir.rest.param.QualifiedDateParam;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class RestfulPatientResourceProviderMore implements IResourceProvider {
|
public abstract class RestfulPatientResourceProviderMore implements IResourceProvider {
|
||||||
|
|
||||||
//START SNIPPET: searchAll
|
//START SNIPPET: searchAll
|
||||||
@Search
|
@Search
|
||||||
|
@ -43,7 +47,7 @@ public List<Organization> getAllOrganizations() {
|
||||||
|
|
||||||
//START SNIPPET: read
|
//START SNIPPET: read
|
||||||
@Read()
|
@Read()
|
||||||
public Patient getResourceById(@Id IdDt theId) {
|
public Patient getResourceById(@IdParam IdDt theId) {
|
||||||
Patient retVal = new Patient();
|
Patient retVal = new Patient();
|
||||||
// ...populate...
|
// ...populate...
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -52,8 +56,8 @@ public Patient getResourceById(@Id IdDt theId) {
|
||||||
|
|
||||||
//START SNIPPET: vread
|
//START SNIPPET: vread
|
||||||
@Read()
|
@Read()
|
||||||
public Patient getResourceById(@Id IdDt theId,
|
public Patient getResourceById(@IdParam IdDt theId,
|
||||||
@VersionId IdDt theVersionId) {
|
@VersionIdParam IdDt theVersionId) {
|
||||||
Patient retVal = new Patient();
|
Patient retVal = new Patient();
|
||||||
// ...populate...
|
// ...populate...
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -62,7 +66,7 @@ public Patient getResourceById(@Id IdDt theId,
|
||||||
|
|
||||||
//START SNIPPET: searchStringParam
|
//START SNIPPET: searchStringParam
|
||||||
@Search()
|
@Search()
|
||||||
public List<Patient> searchByLastName(@Required(name=Patient.SP_FAMILY) StringDt theId) {
|
public List<Patient> searchByLastName(@RequiredParam(name=Patient.SP_FAMILY) StringDt theId) {
|
||||||
List<Patient> retVal = new ArrayList<Patient>();
|
List<Patient> retVal = new ArrayList<Patient>();
|
||||||
// ...populate...
|
// ...populate...
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -71,7 +75,7 @@ public List<Patient> searchByLastName(@Required(name=Patient.SP_FAMILY) StringDt
|
||||||
|
|
||||||
//START SNIPPET: searchNamedQuery
|
//START SNIPPET: searchNamedQuery
|
||||||
@Search(queryName="namedQuery1")
|
@Search(queryName="namedQuery1")
|
||||||
public List<Patient> searchByNamedQuery(@Required(name="someparam") StringDt theSomeParam) {
|
public List<Patient> searchByNamedQuery(@RequiredParam(name="someparam") StringDt theSomeParam) {
|
||||||
List<Patient> retVal = new ArrayList<Patient>();
|
List<Patient> retVal = new ArrayList<Patient>();
|
||||||
// ...populate...
|
// ...populate...
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -80,7 +84,7 @@ public List<Patient> searchByNamedQuery(@Required(name="someparam") StringDt the
|
||||||
|
|
||||||
//START SNIPPET: searchIdentifierParam
|
//START SNIPPET: searchIdentifierParam
|
||||||
@Search()
|
@Search()
|
||||||
public List<Patient> searchByIdentifier(@Required(name=Patient.SP_IDENTIFIER) IdentifierDt theId) {
|
public List<Patient> searchByIdentifier(@RequiredParam(name=Patient.SP_IDENTIFIER) IdentifierDt theId) {
|
||||||
String identifierSystem = theId.getSystem().getValueAsString();
|
String identifierSystem = theId.getSystem().getValueAsString();
|
||||||
String identifier = theId.getValue().getValue();
|
String identifier = theId.getValue().getValue();
|
||||||
|
|
||||||
|
@ -92,8 +96,8 @@ public List<Patient> searchByIdentifier(@Required(name=Patient.SP_IDENTIFIER) Id
|
||||||
|
|
||||||
//START SNIPPET: searchOptionalParam
|
//START SNIPPET: searchOptionalParam
|
||||||
@Search()
|
@Search()
|
||||||
public List<Patient> searchByNames( @Required(name=Patient.SP_FAMILY) StringDt theFamilyName,
|
public List<Patient> searchByNames( @RequiredParam(name=Patient.SP_FAMILY) StringDt theFamilyName,
|
||||||
@Optional(name=Patient.SP_GIVEN) StringDt theGivenName ) {
|
@OptionalParam(name=Patient.SP_GIVEN) StringDt theGivenName ) {
|
||||||
String familyName = theFamilyName.getValue();
|
String familyName = theFamilyName.getValue();
|
||||||
String givenName = theGivenName != null ? theGivenName.getValue() : null;
|
String givenName = theGivenName != null ? theGivenName.getValue() : null;
|
||||||
|
|
||||||
|
@ -105,7 +109,7 @@ public List<Patient> searchByNames( @Required(name=Patient.SP_FAMILY) StringDt t
|
||||||
|
|
||||||
//START SNIPPET: searchMultiple
|
//START SNIPPET: searchMultiple
|
||||||
@Search()
|
@Search()
|
||||||
public List<Observation> searchByObservationNames( @Required(name=Observation.SP_NAME) CodingListParam theCodings ) {
|
public List<Observation> searchByObservationNames( @RequiredParam(name=Observation.SP_NAME) CodingListParam theCodings ) {
|
||||||
// This search should return any observations matching one or more
|
// This search should return any observations matching one or more
|
||||||
// of the codings here.
|
// of the codings here.
|
||||||
List<CodingDt> wantedCodings = theCodings.getCodings();
|
List<CodingDt> wantedCodings = theCodings.getCodings();
|
||||||
|
@ -118,7 +122,7 @@ public List<Observation> searchByObservationNames( @Required(name=Observation.SP
|
||||||
|
|
||||||
//START SNIPPET: dates
|
//START SNIPPET: dates
|
||||||
@Search()
|
@Search()
|
||||||
public List<Patient> searchByObservationNames( @Required(name=Patient.SP_BIRTHDATE) QualifiedDateParam theDate ) {
|
public List<Patient> searchByObservationNames( @RequiredParam(name=Patient.SP_BIRTHDATE) QualifiedDateParam theDate ) {
|
||||||
QuantityCompararatorEnum comparator = theDate.getComparator(); // e.g. <=
|
QuantityCompararatorEnum comparator = theDate.getComparator(); // e.g. <=
|
||||||
Date date = theDate.getValue(); // e.g. 2011-01-02
|
Date date = theDate.getValue(); // e.g. 2011-01-02
|
||||||
TemporalPrecisionEnum precision = theDate.getPrecision(); // e.g. DAY
|
TemporalPrecisionEnum precision = theDate.getPrecision(); // e.g. DAY
|
||||||
|
@ -150,9 +154,9 @@ public Class<? extends IResource> getResourceType() {
|
||||||
//START SNIPPET: pathSpec
|
//START SNIPPET: pathSpec
|
||||||
@Search()
|
@Search()
|
||||||
public List<DiagnosticReport> getDiagnosticReport(
|
public List<DiagnosticReport> getDiagnosticReport(
|
||||||
@Required(name=DiagnosticReport.SP_IDENTIFIER)
|
@RequiredParam(name=DiagnosticReport.SP_IDENTIFIER)
|
||||||
IdentifierDt theIdentifier,
|
IdentifierDt theIdentifier,
|
||||||
@Include(allow= {"DiagnosticReport.subject"})
|
@IncludeParam(allow= {"DiagnosticReport.subject"})
|
||||||
Set<PathSpecification> theIncludes ) {
|
Set<PathSpecification> theIncludes ) {
|
||||||
List<DiagnosticReport> retVal = new ArrayList<DiagnosticReport>();
|
List<DiagnosticReport> retVal = new ArrayList<DiagnosticReport>();
|
||||||
|
|
||||||
|
@ -178,8 +182,8 @@ public List<DiagnosticReport> getDiagnosticReport(
|
||||||
|
|
||||||
//START SNIPPET: dateRange
|
//START SNIPPET: dateRange
|
||||||
@Search()
|
@Search()
|
||||||
public List<Observation> getObservationsByDateRange(@Required(name="subject.identifier") IdentifierDt theSubjectId,
|
public List<Observation> getObservationsByDateRange(@RequiredParam(name="subject.identifier") IdentifierDt theSubjectId,
|
||||||
@Required(name=Observation.SP_DATE) DateRangeParam theRange) {
|
@RequiredParam(name=Observation.SP_DATE) DateRangeParam theRange) {
|
||||||
List<Observation> retVal = new ArrayList<Observation>();
|
List<Observation> retVal = new ArrayList<Observation>();
|
||||||
|
|
||||||
// The following two will be set as the start and end
|
// The following two will be set as the start and end
|
||||||
|
@ -200,6 +204,43 @@ private Patient loadSomePatientFromDatabase(IdDt theId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//START SNIPPET: create
|
||||||
|
@Create
|
||||||
|
public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First we might want to do business validation. The UnprocessableEntityException
|
||||||
|
* results in an HTTP 422, which is appropriate for business rule failure
|
||||||
|
*/
|
||||||
|
if (thePatient.getIdentifierFirstRep().isEmpty()) {
|
||||||
|
throw new UnprocessableEntityException("No identifier supplied");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save this patient to the database...
|
||||||
|
savePatientToDatabase(thePatient);
|
||||||
|
|
||||||
|
// This method returns a MethodOutcome object which contains
|
||||||
|
// the ID and Version ID for the newly saved resource
|
||||||
|
MethodOutcome retVal = new MethodOutcome();
|
||||||
|
retVal.setId(new IdDt("3746"));
|
||||||
|
retVal.setVersionId(new IdDt("1"));
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
//END SNIPPET: create
|
||||||
|
|
||||||
|
//START SNIPPET: createClient
|
||||||
|
@Create
|
||||||
|
public abstract MethodOutcome createNewPatient(@ResourceParam Patient thePatient);
|
||||||
|
//END SNIPPET: createClient
|
||||||
|
|
||||||
|
|
||||||
|
private void savePatientToDatabase(Patient thePatient) {
|
||||||
|
// nothing
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
</links>
|
</links>
|
||||||
|
|
||||||
<menu name="Welcome">
|
<menu name="Welcome">
|
||||||
<item name="Introduction" href="index.html" />
|
<item name="Welcome" href="index.html" />
|
||||||
</menu>
|
</menu>
|
||||||
|
|
||||||
<menu name="Documentation">
|
<menu name="Documentation">
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
operation retrieves a resource by ID. It is annotated with the
|
operation retrieves a resource by ID. It is annotated with the
|
||||||
<a href="./apidocs/ca/uhn/fhir/rest/annotation/Read.html">@Read</a>
|
<a href="./apidocs/ca/uhn/fhir/rest/annotation/Read.html">@Read</a>
|
||||||
annotation, and has a single parameter annotated with the
|
annotation, and has a single parameter annotated with the
|
||||||
<a href="./apidocs/ca/uhn/fhir/rest/annotation/Read.IdParam.html">@Read.IdParam</a>
|
<a href="./apidocs/ca/uhn/fhir/rest/annotation/IdParam.html">@IdParam</a>
|
||||||
annotation.
|
annotation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
operation retrieves a specific version of a resource with a given ID. It looks exactly
|
operation retrieves a specific version of a resource with a given ID. It looks exactly
|
||||||
like a "read" operation, but with a second
|
like a "read" operation, but with a second
|
||||||
parameter annotated with the
|
parameter annotated with the
|
||||||
<a href="./apidocs/ca/uhn/fhir/rest/annotation/Read.VersionIdParam.html">@VersionIdParam</a>
|
<a href="./apidocs/ca/uhn/fhir/rest/annotation/VersionIdParam.html">@VersionIdParam</a>
|
||||||
annotation.
|
annotation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -109,9 +109,9 @@
|
||||||
<p>
|
<p>
|
||||||
To allow a search using given search parameters, add one or more parameters
|
To allow a search using given search parameters, add one or more parameters
|
||||||
to your search method and tag these parameters as either
|
to your search method and tag these parameters as either
|
||||||
<a href="./apidocs/ca/uhn/fhir/rest/server/parameters/Required.html">@Required</a>
|
<a href="./apidocs/ca/uhn/fhir/rest/server/parameters/RequiredParam.html">@RequiredParam</a>
|
||||||
or
|
or
|
||||||
<a href="./apidocs/ca/uhn/fhir/rest/server/parameters/Optional.html">@Optional</a>.
|
<a href="./apidocs/ca/uhn/fhir/rest/server/parameters/OptionalParam.html">@OptionalParam</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -158,16 +158,16 @@
|
||||||
Search methods may take multiple parameters, and these parameters
|
Search methods may take multiple parameters, and these parameters
|
||||||
may be optional. To add a second required parameter, annotate the
|
may be optional. To add a second required parameter, annotate the
|
||||||
parameter with
|
parameter with
|
||||||
<a href="./apidocs/ca/uhn/fhir/rest/server/parameters/Required.html">@Required</a>.
|
<a href="./apidocs/ca/uhn/fhir/rest/server/parameters/RequiredParam.html">@RequiredParam</a>.
|
||||||
To add an optional parameter (which will be passed in as <code>null</code> if no value
|
To add an optional parameter (which will be passed in as <code>null</code> if no value
|
||||||
is supplied), annotate the method with
|
is supplied), annotate the method with
|
||||||
<a href="./apidocs/ca/uhn/fhir/rest/server/parameters/Required.html">@Optional</a>.
|
<a href="./apidocs/ca/uhn/fhir/rest/server/parameters/OptionalParam.html">@OptionalParam</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
You may annotate a method with any combination of as many @Required and as many @Optional
|
You may annotate a method with any combination of as many @RequiredParam and as many @OptionalParam
|
||||||
parameters as you want. It is valid to have only @Required parameters, or
|
parameters as you want. It is valid to have only @RequiredParam parameters, or
|
||||||
only @Optional parameters, or any combination of the two.
|
only @OptionalParam parameters, or any combination of the two.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<macro name="snippet">
|
<macro name="snippet">
|
||||||
|
@ -376,6 +376,48 @@
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section name="Type Level - create">
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The
|
||||||
|
<a href="http://hl7.org/implement/standards/fhir/http.html#create"><b>create</b></a>
|
||||||
|
operation saves a new resource to the server, allowing the server to
|
||||||
|
give that resource an ID and version ID.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Create methods must be annotated with the
|
||||||
|
<a href="./apidocs/ca/uhn/fhir/rest/annotation/Create.html">@Create</a>
|
||||||
|
annotation, and have a single parameter annotated with the
|
||||||
|
<a href="./apidocs/ca/uhn/fhir/rest/annotation/ResourceParam.html">@Resource</a>
|
||||||
|
annotation. This parameter contains the resource instance to be created.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The following snippet shows how to define a server create method:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<macro name="snippet">
|
||||||
|
<param name="id" value="create" />
|
||||||
|
<param name="file" value="src/site/example/java/example/RestfulPatientResourceProviderMore.java" />
|
||||||
|
</macro>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Example URL to invoke this method (this would be invoked using an HTTP POST,
|
||||||
|
with the resource in the POST body):<br/>
|
||||||
|
<code>http://fhir.example.com/Patient</code>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The following snippet shows how the corresponding client interface
|
||||||
|
would look:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<macro name="snippet">
|
||||||
|
<param name="id" value="createClient" />
|
||||||
|
<param name="file" value="src/site/example/java/example/RestfulPatientResourceProviderMore.java" />
|
||||||
|
</macro>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,64 @@
|
||||||
This library is still in experimental stage, so please tread with caution.
|
This library is still in experimental stage, so please tread with caution.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Note that this is the home for the FHIR version of HAPI. If you are
|
||||||
|
looking for HL7 v2 support, <a href="../">click here</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section name="Why HAPI FHIR?">
|
||||||
|
<p>
|
||||||
|
HAPI FHIR is a simple-but-powerful library for adding FHIR messaging to your application. It
|
||||||
|
is pure Java (1.6+ compatible), and licensed under the business-friendly Apache Software
|
||||||
|
License, version 2.0.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The HAPI API makes it very easy to create FHIR resources:
|
||||||
|
</p>
|
||||||
|
<source><![CDATA[Patient patient = new Patient();
|
||||||
|
patient.addIdentifier().setUse(OFFICIAL).setSystem("urn:fake:mrns").setValue("7000135");
|
||||||
|
patient.addIdentifier().setUse(SECONDARY).setSystem("urn:fake:otherids").setValue("3287486");
|
||||||
|
|
||||||
|
patient.addName().addFamily("Smith").addGiven("John").addGiven("Q").addSuffix("Junior");
|
||||||
|
|
||||||
|
patient.setGender(AdministrativeGenderCodesEnum.M);]]></source>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This library supports both XML and JSON encoding natively:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<source><![CDATA[FhirContext ctx = new FhirContext();
|
||||||
|
String xmlEncoded = ctx.newXmlParser().encodeResourceToString(patient);
|
||||||
|
String jsonEncoded = ctx.newJsonParser().encodeResourceToString(patient);
|
||||||
|
]]></source>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Creating clients is simple and uses an annotation based format
|
||||||
|
that will be familiar to users of JAX-WS.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<source><![CDATA[public interface MyClientInterface
|
||||||
|
{
|
||||||
|
/** A FHIR search */
|
||||||
|
@Search
|
||||||
|
public List<Patient> findPatientsByIdentifier(@RequiredParam(name="identifier") IdentifierDt theIdentifier);
|
||||||
|
|
||||||
|
/** A FHIR create */
|
||||||
|
@Create
|
||||||
|
public MethodOutcome createPatient(@ResourceParam Patient thePatient);
|
||||||
|
}]]></source>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Using this client is as simple as:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<source><![CDATA[MyClientInterface client = ctx.newRestfulClient(MyClientInterface.class, "http://foo/fhir");
|
||||||
|
IdentifierDt searchParam = new IdentifierDt("urn:someidentifiers", "7000135");
|
||||||
|
List<Patient> clients = client.findPatientsByIdentifier(searchParam);]]></source>
|
||||||
|
</section>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</document>
|
</document>
|
||||||
|
|
|
@ -10,12 +10,15 @@ import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.io.input.ReaderInputStream;
|
import org.apache.commons.io.input.ReaderInputStream;
|
||||||
|
import org.apache.http.Header;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.ProtocolVersion;
|
import org.apache.http.ProtocolVersion;
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
import org.apache.http.client.methods.HttpUriRequest;
|
import org.apache.http.client.methods.HttpUriRequest;
|
||||||
import org.apache.http.message.BasicHeader;
|
import org.apache.http.message.BasicHeader;
|
||||||
import org.apache.http.message.BasicStatusLine;
|
import org.apache.http.message.BasicStatusLine;
|
||||||
|
import org.hamcrest.core.StringContains;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
@ -31,10 +34,12 @@ import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
import ca.uhn.fhir.rest.param.CodingListParam;
|
import ca.uhn.fhir.rest.param.CodingListParam;
|
||||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||||
import ca.uhn.fhir.rest.param.QualifiedDateParam;
|
import ca.uhn.fhir.rest.param.QualifiedDateParam;
|
||||||
import ca.uhn.fhir.rest.server.Constants;
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
|
||||||
public class ClientTest {
|
public class ClientTest {
|
||||||
|
|
||||||
|
@ -84,6 +89,54 @@ public class ClientTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreate() throws Exception {
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.addIdentifier("urn:foo", "123");
|
||||||
|
|
||||||
|
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||||
|
when(httpClient.execute(capt.capture())).thenReturn(httpResponse);
|
||||||
|
when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
|
||||||
|
when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||||
|
when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
|
||||||
|
when(httpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location" , "http://example.com/fhir/Patient/100/_history/200"));
|
||||||
|
|
||||||
|
ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo");
|
||||||
|
MethodOutcome response = client.createPatient(patient);
|
||||||
|
|
||||||
|
assertEquals(HttpPost.class, capt.getValue().getClass());
|
||||||
|
HttpPost post = (HttpPost) capt.getValue();
|
||||||
|
assertThat(IOUtils.toString(post.getEntity().getContent()), StringContains.containsString("<Patient"));
|
||||||
|
assertEquals("100", response.getId().getValue());
|
||||||
|
assertEquals("200", response.getVersionId().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateBad() throws Exception {
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.addIdentifier("urn:foo", "123");
|
||||||
|
|
||||||
|
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||||
|
when(httpClient.execute(capt.capture())).thenReturn(httpResponse);
|
||||||
|
when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 400, "OK"));
|
||||||
|
when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8"));
|
||||||
|
when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("foobar"), Charset.forName("UTF-8")));
|
||||||
|
|
||||||
|
try {
|
||||||
|
ctx.newRestfulClient(ITestClient.class, "http://foo").createPatient(patient);
|
||||||
|
fail();
|
||||||
|
}catch (InvalidRequestException e) {
|
||||||
|
assertThat(e.getMessage(), StringContains.containsString("foobar"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Header[] toHeaderArray(String theName, String theValue) {
|
||||||
|
return new Header[] {new BasicHeader(theName, theValue)};
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testVRead() throws Exception {
|
public void testVRead() throws Exception {
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,16 @@ import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
import ca.uhn.fhir.rest.annotation.Id;
|
import ca.uhn.fhir.rest.annotation.Create;
|
||||||
import ca.uhn.fhir.rest.annotation.Include;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Optional;
|
import ca.uhn.fhir.rest.annotation.IncludeParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Read;
|
import ca.uhn.fhir.rest.annotation.Read;
|
||||||
import ca.uhn.fhir.rest.annotation.Required;
|
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.Search;
|
||||||
import ca.uhn.fhir.rest.annotation.VersionId;
|
import ca.uhn.fhir.rest.annotation.VersionIdParam;
|
||||||
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
import ca.uhn.fhir.rest.client.api.IBasicClient;
|
import ca.uhn.fhir.rest.client.api.IBasicClient;
|
||||||
import ca.uhn.fhir.rest.param.CodingListParam;
|
import ca.uhn.fhir.rest.param.CodingListParam;
|
||||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||||
|
@ -23,33 +26,36 @@ import ca.uhn.fhir.rest.param.QualifiedDateParam;
|
||||||
public interface ITestClient extends IBasicClient {
|
public interface ITestClient extends IBasicClient {
|
||||||
|
|
||||||
@Read(type=Patient.class)
|
@Read(type=Patient.class)
|
||||||
Patient getPatientById(@Id IdDt theId);
|
Patient getPatientById(@IdParam IdDt theId);
|
||||||
|
|
||||||
@Read(type=Patient.class)
|
@Read(type=Patient.class)
|
||||||
Patient getPatientByVersionId(@Id IdDt theId, @VersionId IdDt theVersionId);
|
Patient getPatientByVersionId(@IdParam IdDt theId, @VersionIdParam IdDt theVersionId);
|
||||||
|
|
||||||
@Search(type=Patient.class)
|
@Search(type=Patient.class)
|
||||||
Patient findPatientByMrn(@Required(name = Patient.SP_IDENTIFIER) IdentifierDt theId);
|
Patient findPatientByMrn(@RequiredParam(name = Patient.SP_IDENTIFIER) IdentifierDt theId);
|
||||||
|
|
||||||
@Search(type=Patient.class)
|
@Search(type=Patient.class)
|
||||||
Bundle findPatientByName(@Required(name = Patient.SP_FAMILY) StringDt theId, @Optional(name=Patient.SP_GIVEN) StringDt theGiven);
|
Bundle findPatientByName(@RequiredParam(name = Patient.SP_FAMILY) StringDt theId, @OptionalParam(name=Patient.SP_GIVEN) StringDt theGiven);
|
||||||
|
|
||||||
@Search()
|
@Search()
|
||||||
public List<Patient> getPatientMultipleIdentifiers(@Required(name = "ids") CodingListParam theIdentifiers);
|
public List<Patient> getPatientMultipleIdentifiers(@RequiredParam(name = "ids") CodingListParam theIdentifiers);
|
||||||
|
|
||||||
@Search()
|
@Search()
|
||||||
public List<Patient> getPatientByDateRange(@Required(name = "dateRange") DateRangeParam theIdentifiers);
|
public List<Patient> getPatientByDateRange(@RequiredParam(name = "dateRange") DateRangeParam theIdentifiers);
|
||||||
|
|
||||||
@Search()
|
@Search()
|
||||||
public List<Patient> getPatientByDob(@Required(name=Patient.SP_BIRTHDATE) QualifiedDateParam theBirthDate);
|
public List<Patient> getPatientByDob(@RequiredParam(name=Patient.SP_BIRTHDATE) QualifiedDateParam theBirthDate);
|
||||||
|
|
||||||
@Search()
|
@Search()
|
||||||
public Patient getPatientWithIncludes(@Required(name = "withIncludes") StringDt theString, @Include List<PathSpecification> theIncludes);
|
public Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringDt theString, @IncludeParam List<PathSpecification> theIncludes);
|
||||||
|
|
||||||
@Search(queryName="someQueryNoParams")
|
@Search(queryName="someQueryNoParams")
|
||||||
public Patient getPatientNoParams();
|
public Patient getPatientNoParams();
|
||||||
|
|
||||||
@Search(queryName="someQueryOneParam")
|
@Search(queryName="someQueryOneParam")
|
||||||
public Patient getPatientOneParam(@Required(name="param1") StringDt theParam);
|
public Patient getPatientOneParam(@RequiredParam(name="param1") StringDt theParam);
|
||||||
|
|
||||||
|
@Create
|
||||||
|
public MethodOutcome createPatient(@ResourceParam Patient thePatient);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package ca.uhn.fhir.rest.server;
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -15,6 +17,8 @@ import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.entity.ContentType;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||||
|
@ -42,13 +46,16 @@ import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
import ca.uhn.fhir.model.primitive.UriDt;
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
import ca.uhn.fhir.rest.annotation.Id;
|
import ca.uhn.fhir.rest.annotation.Create;
|
||||||
import ca.uhn.fhir.rest.annotation.Include;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Optional;
|
import ca.uhn.fhir.rest.annotation.IncludeParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Read;
|
import ca.uhn.fhir.rest.annotation.Read;
|
||||||
import ca.uhn.fhir.rest.annotation.Required;
|
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.Search;
|
||||||
import ca.uhn.fhir.rest.annotation.VersionId;
|
import ca.uhn.fhir.rest.annotation.VersionIdParam;
|
||||||
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
import ca.uhn.fhir.rest.param.CodingListParam;
|
import ca.uhn.fhir.rest.param.CodingListParam;
|
||||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||||
import ca.uhn.fhir.rest.param.QualifiedDateParam;
|
import ca.uhn.fhir.rest.param.QualifiedDateParam;
|
||||||
|
@ -391,6 +398,27 @@ public class ResfulServerMethodTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreate() throws Exception {
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.addIdentifier().setValue("001");
|
||||||
|
patient.addIdentifier().setValue("002");
|
||||||
|
|
||||||
|
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||||
|
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||||
|
|
||||||
|
HttpResponse status = ourClient.execute(httpPost);
|
||||||
|
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
ourLog.info("Response was:\n{}", responseContent);
|
||||||
|
|
||||||
|
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("Location").getValue());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFormatParamXml() throws Exception {
|
public void testFormatParamXml() throws Exception {
|
||||||
|
|
||||||
|
@ -655,15 +683,15 @@ public class ResfulServerMethodTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Search(queryName="someQueryOneParam")
|
@Search(queryName="someQueryOneParam")
|
||||||
public Patient getPatientOneParam(@Required(name="param1") StringDt theParam) {
|
public Patient getPatientOneParam(@RequiredParam(name="param1") StringDt theParam) {
|
||||||
Patient next = getIdToPatient().get("1");
|
Patient next = getIdToPatient().get("1");
|
||||||
next.addName().addFamily(theParam.getValue());
|
next.addName().addFamily(theParam.getValue());
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Search()
|
@Search()
|
||||||
public Patient getPatientWithIncludes(@Required(name = "withIncludes") StringDt theString,
|
public Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringDt theString,
|
||||||
@Include(allow= {"include1","include2", "include3"}) List<PathSpecification> theIncludes) {
|
@IncludeParam(allow= {"include1","include2", "include3"}) List<PathSpecification> theIncludes) {
|
||||||
Patient next = getIdToPatient().get("1");
|
Patient next = getIdToPatient().get("1");
|
||||||
|
|
||||||
next.addCommunication().setText(theString.getValue());
|
next.addCommunication().setText(theString.getValue());
|
||||||
|
@ -675,8 +703,16 @@ public class ResfulServerMethodTest {
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Create()
|
||||||
|
public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
|
||||||
|
IdDt id = new IdDt(thePatient.getIdentifier().get(0).getValue().getValue());
|
||||||
|
IdDt version = new IdDt(thePatient.getIdentifier().get(1).getValue().getValue());
|
||||||
|
return new MethodOutcome(id, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Search()
|
@Search()
|
||||||
public Patient getPatient(@Required(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier) {
|
public Patient getPatient(@RequiredParam(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier) {
|
||||||
for (Patient next : getIdToPatient().values()) {
|
for (Patient next : getIdToPatient().values()) {
|
||||||
for (IdentifierDt nextId : next.getIdentifier()) {
|
for (IdentifierDt nextId : next.getIdentifier()) {
|
||||||
if (nextId.matchesSystemAndValue(theIdentifier)) {
|
if (nextId.matchesSystemAndValue(theIdentifier)) {
|
||||||
|
@ -688,13 +724,13 @@ public class ResfulServerMethodTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public List<Patient> findDiagnosticReportsByPatient(@Required(name = "Patient.identifier") IdentifierDt thePatientId, @Required(name = DiagnosticReport.SP_NAME) CodingListParam theNames,
|
public List<Patient> findDiagnosticReportsByPatient(@RequiredParam(name = "Patient.identifier") IdentifierDt thePatientId, @RequiredParam(name = DiagnosticReport.SP_NAME) CodingListParam theNames,
|
||||||
@Optional(name = DiagnosticReport.SP_DATE) DateRangeParam theDateRange) throws Exception {
|
@OptionalParam(name = DiagnosticReport.SP_DATE) DateRangeParam theDateRange) throws Exception {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Search()
|
@Search()
|
||||||
public Patient getPatientWithDOB(@Required(name = "dob") QualifiedDateParam theDob) {
|
public Patient getPatientWithDOB(@RequiredParam(name = "dob") QualifiedDateParam theDob) {
|
||||||
Patient next = getIdToPatient().get("1");
|
Patient next = getIdToPatient().get("1");
|
||||||
if (theDob.getComparator() != null) {
|
if (theDob.getComparator() != null) {
|
||||||
next.addIdentifier().setValue(theDob.getComparator().getCode());
|
next.addIdentifier().setValue(theDob.getComparator().getCode());
|
||||||
|
@ -706,7 +742,7 @@ public class ResfulServerMethodTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Search()
|
@Search()
|
||||||
public List<Patient> getPatientWithOptionalName(@Required(name = "name1") StringDt theName1, @Optional(name = "name2") StringDt theName2) {
|
public List<Patient> getPatientWithOptionalName(@RequiredParam(name = "name1") StringDt theName1, @OptionalParam(name = "name2") StringDt theName2) {
|
||||||
List<Patient> retVal = new ArrayList<Patient>();
|
List<Patient> retVal = new ArrayList<Patient>();
|
||||||
Patient next = getIdToPatient().get("1");
|
Patient next = getIdToPatient().get("1");
|
||||||
next.getName().get(0).getFamily().set(0, theName1);
|
next.getName().get(0).getFamily().set(0, theName1);
|
||||||
|
@ -722,7 +758,7 @@ public class ResfulServerMethodTest {
|
||||||
* @param theName3
|
* @param theName3
|
||||||
*/
|
*/
|
||||||
@Search()
|
@Search()
|
||||||
public List<Patient> getPatientWithOptionalName(@Required(name = "aaa") StringDt theName1, @Optional(name = "bbb") StringDt theName2, @Optional(name = "ccc") StringDt theName3) {
|
public List<Patient> getPatientWithOptionalName(@RequiredParam(name = "aaa") StringDt theName1, @OptionalParam(name = "bbb") StringDt theName2, @OptionalParam(name = "ccc") StringDt theName3) {
|
||||||
List<Patient> retVal = new ArrayList<Patient>();
|
List<Patient> retVal = new ArrayList<Patient>();
|
||||||
Patient next = getIdToPatient().get("1");
|
Patient next = getIdToPatient().get("1");
|
||||||
next.getName().get(0).getFamily().set(0, theName1);
|
next.getName().get(0).getFamily().set(0, theName1);
|
||||||
|
@ -735,7 +771,7 @@ public class ResfulServerMethodTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Search()
|
@Search()
|
||||||
public List<Patient> getPatientMultipleIdentifiers(@Required(name = "ids") CodingListParam theIdentifiers) {
|
public List<Patient> getPatientMultipleIdentifiers(@RequiredParam(name = "ids") CodingListParam theIdentifiers) {
|
||||||
List<Patient> retVal = new ArrayList<Patient>();
|
List<Patient> retVal = new ArrayList<Patient>();
|
||||||
Patient next = getIdToPatient().get("1");
|
Patient next = getIdToPatient().get("1");
|
||||||
|
|
||||||
|
@ -756,12 +792,12 @@ public class ResfulServerMethodTest {
|
||||||
* @return The resource
|
* @return The resource
|
||||||
*/
|
*/
|
||||||
@Read()
|
@Read()
|
||||||
public Patient getResourceById(@Id IdDt theId) {
|
public Patient getResourceById(@IdParam IdDt theId) {
|
||||||
return getIdToPatient().get(theId.getValue());
|
return getIdToPatient().get(theId.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Read()
|
@Read()
|
||||||
public Patient getResourceById(@Id IdDt theId, @VersionId IdDt theVersionId) {
|
public Patient getResourceById(@IdParam IdDt theId, @VersionIdParam IdDt theVersionId) {
|
||||||
Patient retVal = getIdToPatient().get(theId.getValue());
|
Patient retVal = getIdToPatient().get(theId.getValue());
|
||||||
retVal.getName().get(0).setText(theVersionId.getValue());
|
retVal.getName().get(0).setText(theVersionId.getValue());
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -778,7 +814,7 @@ public class ResfulServerMethodTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Search()
|
@Search()
|
||||||
public Patient getPatientByDateRange(@Required(name = "dateRange") DateRangeParam theIdentifiers) {
|
public Patient getPatientByDateRange(@RequiredParam(name = "dateRange") DateRangeParam theIdentifiers) {
|
||||||
Patient retVal = getIdToPatient().get("1");
|
Patient retVal = getIdToPatient().get("1");
|
||||||
retVal.getName().get(0).addSuffix().setValue(theIdentifiers.getLowerBound().getValueAsQueryToken());
|
retVal.getName().get(0).addSuffix().setValue(theIdentifiers.getLowerBound().getValueAsQueryToken());
|
||||||
retVal.getName().get(0).addSuffix().setValue(theIdentifiers.getUpperBound().getValueAsQueryToken());
|
retVal.getName().get(0).addSuffix().setValue(theIdentifiers.getUpperBound().getValueAsQueryToken());
|
||||||
|
|
|
@ -29,9 +29,9 @@ import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum;
|
import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.UriDt;
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
import ca.uhn.fhir.rest.annotation.Id;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Read;
|
import ca.uhn.fhir.rest.annotation.Read;
|
||||||
import ca.uhn.fhir.rest.annotation.Required;
|
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Search;
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
import ca.uhn.fhir.rest.server.provider.ServerProfileProvider;
|
import ca.uhn.fhir.rest.server.provider.ServerProfileProvider;
|
||||||
import ca.uhn.fhir.testutil.RandomServerPortProvider;
|
import ca.uhn.fhir.testutil.RandomServerPortProvider;
|
||||||
|
@ -162,7 +162,7 @@ public class ResfulServerSelfReferenceTest {
|
||||||
|
|
||||||
|
|
||||||
@Search()
|
@Search()
|
||||||
public Patient getPatient(@Required(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier) {
|
public Patient getPatient(@RequiredParam(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier) {
|
||||||
for (Patient next : getIdToPatient().values()) {
|
for (Patient next : getIdToPatient().values()) {
|
||||||
for (IdentifierDt nextId : next.getIdentifier()) {
|
for (IdentifierDt nextId : next.getIdentifier()) {
|
||||||
if (nextId.matchesSystemAndValue(theIdentifier)) {
|
if (nextId.matchesSystemAndValue(theIdentifier)) {
|
||||||
|
@ -182,7 +182,7 @@ public class ResfulServerSelfReferenceTest {
|
||||||
* @return The resource
|
* @return The resource
|
||||||
*/
|
*/
|
||||||
@Read()
|
@Read()
|
||||||
public Patient getResourceById(@Id IdDt theId) {
|
public Patient getResourceById(@IdParam IdDt theId) {
|
||||||
return getIdToPatient().get(theId.getValue());
|
return getIdToPatient().get(theId.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue