Create methd
This commit is contained in:
parent
ad189d66e2
commit
b38be51668
|
@ -7,6 +7,6 @@ import java.lang.annotation.Target;
|
|||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface Id {
|
||||
public @interface IdParam {
|
||||
// just a marker
|
||||
}
|
|
@ -20,7 +20,7 @@ import java.lang.annotation.Target;
|
|||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value= {ElementType.PARAMETER})
|
||||
public @interface Include {
|
||||
public @interface IncludeParam {
|
||||
|
||||
/**
|
||||
* Optional parameter, if provided the server will only allow the values
|
|
@ -5,6 +5,6 @@ import java.lang.annotation.RetentionPolicy;
|
|||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
||||
public @interface Optional {
|
||||
public @interface OptionalParam {
|
||||
String name();
|
||||
}
|
|
@ -5,6 +5,6 @@ import java.lang.annotation.RetentionPolicy;
|
|||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
||||
public @interface Required {
|
||||
public @interface RequiredParam {
|
||||
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)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface VersionId {
|
||||
public @interface VersionIdParam {
|
||||
// just a marker
|
||||
}
|
|
@ -7,10 +7,6 @@ public class MethodOutcome {
|
|||
private IdDt myId;
|
||||
private IdDt myVersionId;
|
||||
|
||||
public IdDt getId() {
|
||||
return myId;
|
||||
}
|
||||
|
||||
public MethodOutcome() {
|
||||
}
|
||||
|
||||
|
@ -20,14 +16,18 @@ public class MethodOutcome {
|
|||
myVersionId = theVersionId;
|
||||
}
|
||||
|
||||
public void setId(IdDt theId) {
|
||||
myId = theId;
|
||||
public IdDt getId() {
|
||||
return myId;
|
||||
}
|
||||
|
||||
public IdDt getVersionId() {
|
||||
return myVersionId;
|
||||
}
|
||||
|
||||
public void setId(IdDt theId) {
|
||||
myId = theId;
|
||||
}
|
||||
|
||||
public void setVersionId(IdDt theVersionId) {
|
||||
myVersionId = theVersionId;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
|
||||
public abstract class BaseClientInvocation {
|
||||
|
||||
/**
|
||||
|
@ -9,6 +13,6 @@ public abstract class BaseClientInvocation {
|
|||
*
|
||||
* @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.Method;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
|
@ -57,7 +60,7 @@ public class ClientInvocationHandler implements InvocationHandler {
|
|||
}
|
||||
|
||||
BaseMethodBinding binding = myBindings.get(theMethod);
|
||||
GetClientInvocation clientInvocation = binding.invokeClient(theArgs);
|
||||
BaseClientInvocation clientInvocation = binding.invokeClient(theArgs);
|
||||
|
||||
HttpRequestBase httpRequest = clientInvocation.asHttpRequest(myUrlBase);
|
||||
HttpResponse response = myClient.execute(httpRequest);
|
||||
|
@ -75,7 +78,20 @@ public class ClientInvocationHandler implements InvocationHandler {
|
|||
|
||||
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 {
|
||||
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.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
|
||||
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.Read;
|
||||
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.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
|
@ -29,11 +39,11 @@ public abstract class BaseMethodBinding {
|
|||
private FhirContext myContext;
|
||||
|
||||
public BaseMethodBinding(Method theMethod, FhirContext theConetxt) {
|
||||
assert theMethod!=null;
|
||||
assert theConetxt!=null;
|
||||
assert theMethod != null;
|
||||
assert theConetxt != null;
|
||||
|
||||
myMethod = theMethod;
|
||||
myContext=theConetxt;
|
||||
myContext = theConetxt;
|
||||
}
|
||||
|
||||
public FhirContext getContext() {
|
||||
|
@ -44,7 +54,7 @@ public abstract class BaseMethodBinding {
|
|||
return myMethod;
|
||||
}
|
||||
|
||||
public abstract GetClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException;
|
||||
public abstract BaseClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException;
|
||||
|
||||
public abstract RestfulOperationTypeEnum getResourceOperationType();
|
||||
|
||||
|
@ -52,11 +62,24 @@ public abstract class BaseMethodBinding {
|
|||
|
||||
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) {
|
||||
Read read = theMethod.getAnnotation(Read.class);
|
||||
Search search = theMethod.getAnnotation(Search.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;
|
||||
}
|
||||
|
||||
|
@ -77,9 +100,11 @@ public abstract class BaseMethodBinding {
|
|||
return new ReadMethodBinding(returnType, theMethod, theContext);
|
||||
} else if (search != null) {
|
||||
String queryName = search.queryName();
|
||||
return new SearchMethodBinding(returnType, theMethod, queryName,theContext);
|
||||
return new SearchMethodBinding(returnType, theMethod, queryName, theContext);
|
||||
} else if (conformance != null) {
|
||||
return new ConformanceMethodBinding(theMethod, theContext);
|
||||
} else if (create != null) {
|
||||
return new CreateMethodBinding(theMethod, theContext);
|
||||
} else {
|
||||
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) {
|
||||
obj1 = object;
|
||||
} else {
|
||||
throw new ConfigurationException("Method " + theNextMethod.getName() + " on type '" + theNextMethod.getDeclaringClass().getSimpleName() + " has annotations @" + obj1.getClass().getSimpleName() + " and @" + object.getClass().getSimpleName()
|
||||
+ ". Can not have both.");
|
||||
throw new ConfigurationException("Method " + theNextMethod.getName() + " on type '" + theNextMethod.getDeclaringClass().getSimpleName() + " has annotations @"
|
||||
+ 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 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.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -78,15 +76,8 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
|||
public abstract ReturnTypeEnum getReturnType();
|
||||
|
||||
@Override
|
||||
public Object invokeClient(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));
|
||||
}
|
||||
public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode,Map<String, List<String>> theHeaders) throws IOException {
|
||||
IParser parser = createAppropriateParser(theResponseMimeType, theResponseReader, theResponseStatusCode);
|
||||
|
||||
switch (getReturnType()) {
|
||||
case BUNDLE: {
|
||||
|
@ -125,6 +116,7 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
|||
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;
|
||||
|
||||
@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 {
|
||||
HashSet<String> set = new HashSet<String>();
|
||||
|
@ -237,6 +207,8 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
|||
|
||||
theHttpResponse.setCharacterEncoding("UTF-8");
|
||||
|
||||
theServer.addHapiHeader(theHttpResponse);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.getAuthorName().setValue(getClass().getCanonicalName());
|
||||
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 {
|
||||
|
||||
theHttpResponse.setStatus(200);
|
||||
|
|
|
@ -2,34 +2,86 @@ package ca.uhn.fhir.rest.method;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
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 org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
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.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.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.exceptions.BaseServerResponseException;
|
||||
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 {
|
||||
|
||||
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) {
|
||||
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
|
||||
public GetClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
if (resourceParameter == null) {
|
||||
throw new ConfigurationException("Method " + theMethod.getName() + " in type " + theMethod.getDeclaringClass().getCanonicalName() + " does not have a parameter annotated with @"
|
||||
+ ResourceParam.class.getSimpleName());
|
||||
}
|
||||
|
||||
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
|
||||
public RestfulOperationTypeEnum getResourceOperationType() {
|
||||
|
@ -41,12 +93,122 @@ public class CreateMethodBinding extends BaseMethodBinding {
|
|||
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
|
||||
public boolean matches(Request theRequest) {
|
||||
if (theRequest.getRequestType()!= RequestType.POST) {
|
||||
if (theRequest.getRequestType() != RequestType.POST) {
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.isBlank(theRequest.getResourceName())) {
|
||||
if (!myResourceName.equals(theRequest.getResourceName())) {
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.isNotBlank(theRequest.getOperation())) {
|
||||
|
@ -55,16 +217,4 @@ public class CreateMethodBinding extends BaseMethodBinding {
|
|||
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.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
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.rest.client.GetClientInvocation;
|
||||
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.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.QueryUtil;
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
|
@ -69,43 +68,20 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
public GetClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
|
||||
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) {
|
||||
args.put(Constants.PARAM_QUERY, Collections.singletonList(myQueryName));
|
||||
queryStringArgs.put(Constants.PARAM_QUERY, Collections.singletonList(myQueryName));
|
||||
}
|
||||
|
||||
if (theArgs != null) {
|
||||
for (int idx = 0; idx < theArgs.length; idx++) {
|
||||
Object object = theArgs[idx];
|
||||
IParameter nextParam = myParameters.get(idx);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nextParam.translateClientArgumentIntoQueryArgument(theArgs[idx], queryStringArgs);
|
||||
}
|
||||
}
|
||||
|
||||
return new GetClientInvocation(args, getResourceName());
|
||||
return new GetClientInvocation(queryStringArgs, getResourceName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -117,25 +93,7 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
Object[] params = new Object[myParameters.size()];
|
||||
for (int i = 0; i < myParameters.size(); i++) {
|
||||
IParameter param = myParameters.get(i);
|
||||
String[] value = parameterValues.get(param.getName());
|
||||
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);
|
||||
|
||||
params[i] = param.translateQueryParametersIntoServerArgument(parameterValues, null);
|
||||
}
|
||||
|
||||
Object response;
|
||||
|
@ -174,7 +132,10 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
|
||||
Set<String> methodParamsTemp = new HashSet<String>();
|
||||
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());
|
||||
if (temp.isRequired() && !theRequest.getParameters().containsKey(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 ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.PathSpecification;
|
||||
import ca.uhn.fhir.rest.annotation.Id;
|
||||
import ca.uhn.fhir.rest.annotation.Include;
|
||||
import ca.uhn.fhir.rest.annotation.Optional;
|
||||
import ca.uhn.fhir.rest.annotation.Required;
|
||||
import ca.uhn.fhir.rest.annotation.VersionId;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.IncludeParam;
|
||||
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
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.IParameter;
|
||||
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.util.ReflectionUtil;
|
||||
|
||||
|
@ -71,25 +74,30 @@ class Util {
|
|||
}
|
||||
|
||||
IParameter param;
|
||||
if (nextAnnotation instanceof Required) {
|
||||
if (nextAnnotation instanceof RequiredParam) {
|
||||
SearchParameter parameter = new SearchParameter();
|
||||
parameter.setName(((Required) nextAnnotation).name());
|
||||
parameter.setName(((RequiredParam) nextAnnotation).name());
|
||||
parameter.setRequired(true);
|
||||
parameter.setType(parameterType, innerCollectionType, outerCollectionType);
|
||||
param = parameter;
|
||||
} else if (nextAnnotation instanceof Optional) {
|
||||
} else if (nextAnnotation instanceof OptionalParam) {
|
||||
SearchParameter parameter = new SearchParameter();
|
||||
parameter.setName(((Optional) nextAnnotation).name());
|
||||
parameter.setName(((OptionalParam) nextAnnotation).name());
|
||||
parameter.setRequired(false);
|
||||
parameter.setType(parameterType, innerCollectionType, innerCollectionType);
|
||||
param = parameter;
|
||||
} else if (nextAnnotation instanceof Include) {
|
||||
} else if (nextAnnotation instanceof IncludeParam) {
|
||||
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() + "'");
|
||||
|
||||
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 {
|
||||
continue;
|
||||
}
|
||||
|
@ -108,11 +116,11 @@ class Util {
|
|||
}
|
||||
|
||||
public static Integer findReadIdParameterIndex(Method theMethod) {
|
||||
return findParamIndex(theMethod, Id.class);
|
||||
return findParamIndex(theMethod, IdParam.class);
|
||||
}
|
||||
|
||||
public static Integer findReadVersionIdParameterIndex(Method theMethod) {
|
||||
return findParamIndex(theMethod, VersionId.class);
|
||||
return findParamIndex(theMethod, VersionIdParam.class);
|
||||
}
|
||||
|
||||
private static Integer findParamIndex(Method theMethod, Class<?> toFind) {
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
package ca.uhn.fhir.rest.param;
|
||||
|
||||
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.InvalidRequestException;
|
||||
|
||||
public interface IParameter {
|
||||
|
||||
List<List<String>> encode(Object theObject) throws InternalErrorException;
|
||||
|
||||
String getName();
|
||||
|
||||
Object parse(List<List<String>> theString) throws InternalErrorException, InvalidRequestException;
|
||||
|
||||
boolean isRequired();
|
||||
void translateClientArgumentIntoQueryArgument(Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments) throws InternalErrorException;
|
||||
|
||||
/**
|
||||
* Parameter should return true if {@link #parse(List)} should be called even
|
||||
* if the query string contained no values for the given parameter
|
||||
* 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
|
||||
* 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();
|
||||
|
||||
SearchParamTypeEnum getParamType();
|
||||
Object translateQueryParametersIntoServerArgument(Map<String, String[]> theQueryParameters, Object theRequestContents) throws InternalErrorException, InvalidRequestException;
|
||||
|
||||
}
|
|
@ -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.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.InvalidRequestException;
|
||||
|
||||
public class IncludeParameter implements IParameter {
|
||||
public class IncludeParameter extends IQueryParameter {
|
||||
|
||||
private Class<? extends Collection<PathSpecification>> myInstantiableCollectionType;
|
||||
private HashSet<String> myAllow;
|
||||
|
||||
public IncludeParameter(Include theAnnotation, Class<? extends Collection<PathSpecification>> theInstantiableCollectionType) {
|
||||
public IncludeParameter(IncludeParam theAnnotation, Class<? extends Collection<PathSpecification>> theInstantiableCollectionType) {
|
||||
myInstantiableCollectionType = theInstantiableCollectionType;
|
||||
if (theAnnotation.allow().length > 0) {
|
||||
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.
|
||||
*/
|
||||
public class SearchParameter implements IParameter {
|
||||
public class SearchParameter extends IQueryParameter {
|
||||
|
||||
private String name;
|
||||
private IParamBinder parser;
|
||||
private IParamBinder myParamBinder;
|
||||
private boolean required;
|
||||
private Class<?> type;
|
||||
private SearchParamTypeEnum myParamType;
|
||||
|
@ -37,7 +37,7 @@ public class SearchParameter implements IParameter {
|
|||
*/
|
||||
@Override
|
||||
public List<List<String>> encode(Object theObject) throws InternalErrorException {
|
||||
return parser.encode(theObject);
|
||||
return myParamBinder.encode(theObject);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -62,7 +62,7 @@ public class SearchParameter implements IParameter {
|
|||
*/
|
||||
@Override
|
||||
public Object parse(List<List<String>> theString) throws InternalErrorException, InvalidRequestException {
|
||||
return parser.parse(theString);
|
||||
return myParamBinder.parse(theString);
|
||||
}
|
||||
|
||||
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) {
|
||||
this.type = 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)) {
|
||||
this.parser = new QueryParameterOrBinder((Class<? extends IQueryParameterOr>) type);
|
||||
this.myParamBinder = new QueryParameterOrBinder((Class<? extends IQueryParameterOr>) type);
|
||||
} else if (IQueryParameterAnd.class.isAssignableFrom(type)) {
|
||||
this.parser = new QueryParameterAndBinder((Class<? extends IQueryParameterAnd>) type);
|
||||
this.myParamBinder = new QueryParameterAndBinder((Class<? extends IQueryParameterAnd>) type);
|
||||
} else {
|
||||
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_PRETTY = "_pretty";
|
||||
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 {
|
||||
Map<String, EncodingUtil> valToEncoding = new HashMap<String, EncodingUtil>();
|
||||
|
|
|
@ -1,10 +1,23 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public abstract IParser newParser(FhirContext theContext);
|
||||
|
||||
public String getBundleContentType() {
|
||||
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.provider.ServerConformanceProvider;
|
||||
import ca.uhn.fhir.rest.server.provider.ServerProfileProvider;
|
||||
import ca.uhn.fhir.util.VersionUtil;
|
||||
|
||||
public abstract class RestfulServer extends HttpServlet {
|
||||
|
||||
|
@ -312,6 +313,9 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
|
||||
} catch (AuthenticationException e) {
|
||||
response.setStatus(e.getStatusCode());
|
||||
addHapiHeader(response);
|
||||
response.setContentType("text/plain");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.getWriter().write(e.getMessage());
|
||||
} catch (BaseServerResponseException e) {
|
||||
|
||||
|
@ -322,6 +326,7 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
}
|
||||
|
||||
response.setStatus(e.getStatusCode());
|
||||
addHapiHeader(response);
|
||||
response.setContentType("text/plain");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
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;
|
||||
|
||||
public abstract class BaseServerResponseException extends Exception {
|
||||
public abstract class BaseServerResponseException extends RuntimeException {
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
public ResourceNotFoundException(String theMessage) {
|
||||
super(404, theMessage);
|
||||
}
|
||||
|
||||
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.SearchMethodBinding;
|
||||
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.ResourceBinding;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
|
@ -87,7 +88,12 @@ public class ServerConformanceProvider implements IResourceProvider {
|
|||
|
||||
RestResourceSearchParam searchParam = 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("_")) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
|||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu.resource.Profile;
|
||||
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.Search;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
|
@ -29,7 +29,7 @@ public class ServerProfileProvider implements IResourceProvider {
|
|||
}
|
||||
|
||||
@Read()
|
||||
public Profile getProfileById(@Id IdDt theId) {
|
||||
public Profile getProfileById(@IdParam IdDt theId) {
|
||||
RuntimeResourceDefinition retVal = myContext.getResourceDefinitionById(theId.getValue());
|
||||
if (retVal==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.resource.Organization;
|
||||
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.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
|
||||
*/
|
||||
@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;
|
||||
|
||||
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.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 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.primitive.IdDt;
|
||||
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.Required;
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
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.
|
||||
*/
|
||||
@Read()
|
||||
public Patient getResourceById(@Id IdDt theId);
|
||||
public Patient getResourceById(@IdParam IdDt theId);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@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
|
||||
|
|
|
@ -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.StringDt;
|
||||
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.Required;
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
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.
|
||||
*/
|
||||
@Read()
|
||||
public Patient getResourceById(@Id IdDt theId) {
|
||||
public Patient getResourceById(@IdParam IdDt theId) {
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier();
|
||||
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.
|
||||
*/
|
||||
@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.addIdentifier();
|
||||
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.StringDt;
|
||||
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.Required;
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
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.
|
||||
*/
|
||||
@Read()
|
||||
public Patient getResourceById(@Id IdDt theId) {
|
||||
public Patient getResourceById(@IdParam IdDt theId) {
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier();
|
||||
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.
|
||||
*/
|
||||
@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.addIdentifier();
|
||||
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.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.rest.annotation.Id;
|
||||
import ca.uhn.fhir.rest.annotation.Include;
|
||||
import ca.uhn.fhir.rest.annotation.Optional;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
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.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.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.param.CodingListParam;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.param.QualifiedDateParam;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class RestfulPatientResourceProviderMore implements IResourceProvider {
|
||||
public abstract class RestfulPatientResourceProviderMore implements IResourceProvider {
|
||||
|
||||
//START SNIPPET: searchAll
|
||||
@Search
|
||||
|
@ -43,7 +47,7 @@ public List<Organization> getAllOrganizations() {
|
|||
|
||||
//START SNIPPET: read
|
||||
@Read()
|
||||
public Patient getResourceById(@Id IdDt theId) {
|
||||
public Patient getResourceById(@IdParam IdDt theId) {
|
||||
Patient retVal = new Patient();
|
||||
// ...populate...
|
||||
return retVal;
|
||||
|
@ -52,8 +56,8 @@ public Patient getResourceById(@Id IdDt theId) {
|
|||
|
||||
//START SNIPPET: vread
|
||||
@Read()
|
||||
public Patient getResourceById(@Id IdDt theId,
|
||||
@VersionId IdDt theVersionId) {
|
||||
public Patient getResourceById(@IdParam IdDt theId,
|
||||
@VersionIdParam IdDt theVersionId) {
|
||||
Patient retVal = new Patient();
|
||||
// ...populate...
|
||||
return retVal;
|
||||
|
@ -62,7 +66,7 @@ public Patient getResourceById(@Id IdDt theId,
|
|||
|
||||
//START SNIPPET: searchStringParam
|
||||
@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>();
|
||||
// ...populate...
|
||||
return retVal;
|
||||
|
@ -71,7 +75,7 @@ public List<Patient> searchByLastName(@Required(name=Patient.SP_FAMILY) StringDt
|
|||
|
||||
//START SNIPPET: searchNamedQuery
|
||||
@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>();
|
||||
// ...populate...
|
||||
return retVal;
|
||||
|
@ -80,7 +84,7 @@ public List<Patient> searchByNamedQuery(@Required(name="someparam") StringDt the
|
|||
|
||||
//START SNIPPET: searchIdentifierParam
|
||||
@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 identifier = theId.getValue().getValue();
|
||||
|
||||
|
@ -92,8 +96,8 @@ public List<Patient> searchByIdentifier(@Required(name=Patient.SP_IDENTIFIER) Id
|
|||
|
||||
//START SNIPPET: searchOptionalParam
|
||||
@Search()
|
||||
public List<Patient> searchByNames( @Required(name=Patient.SP_FAMILY) StringDt theFamilyName,
|
||||
@Optional(name=Patient.SP_GIVEN) StringDt theGivenName ) {
|
||||
public List<Patient> searchByNames( @RequiredParam(name=Patient.SP_FAMILY) StringDt theFamilyName,
|
||||
@OptionalParam(name=Patient.SP_GIVEN) StringDt theGivenName ) {
|
||||
String familyName = theFamilyName.getValue();
|
||||
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
|
||||
@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
|
||||
// of the codings here.
|
||||
List<CodingDt> wantedCodings = theCodings.getCodings();
|
||||
|
@ -118,7 +122,7 @@ public List<Observation> searchByObservationNames( @Required(name=Observation.SP
|
|||
|
||||
//START SNIPPET: dates
|
||||
@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. <=
|
||||
Date date = theDate.getValue(); // e.g. 2011-01-02
|
||||
TemporalPrecisionEnum precision = theDate.getPrecision(); // e.g. DAY
|
||||
|
@ -150,9 +154,9 @@ public Class<? extends IResource> getResourceType() {
|
|||
//START SNIPPET: pathSpec
|
||||
@Search()
|
||||
public List<DiagnosticReport> getDiagnosticReport(
|
||||
@Required(name=DiagnosticReport.SP_IDENTIFIER)
|
||||
@RequiredParam(name=DiagnosticReport.SP_IDENTIFIER)
|
||||
IdentifierDt theIdentifier,
|
||||
@Include(allow= {"DiagnosticReport.subject"})
|
||||
@IncludeParam(allow= {"DiagnosticReport.subject"})
|
||||
Set<PathSpecification> theIncludes ) {
|
||||
List<DiagnosticReport> retVal = new ArrayList<DiagnosticReport>();
|
||||
|
||||
|
@ -178,8 +182,8 @@ public List<DiagnosticReport> getDiagnosticReport(
|
|||
|
||||
//START SNIPPET: dateRange
|
||||
@Search()
|
||||
public List<Observation> getObservationsByDateRange(@Required(name="subject.identifier") IdentifierDt theSubjectId,
|
||||
@Required(name=Observation.SP_DATE) DateRangeParam theRange) {
|
||||
public List<Observation> getObservationsByDateRange(@RequiredParam(name="subject.identifier") IdentifierDt theSubjectId,
|
||||
@RequiredParam(name=Observation.SP_DATE) DateRangeParam theRange) {
|
||||
List<Observation> retVal = new ArrayList<Observation>();
|
||||
|
||||
// The following two will be set as the start and end
|
||||
|
@ -200,6 +204,43 @@ private Patient loadSomePatientFromDatabase(IdDt theId) {
|
|||
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>
|
||||
|
||||
<menu name="Welcome">
|
||||
<item name="Introduction" href="index.html" />
|
||||
<item name="Welcome" href="index.html" />
|
||||
</menu>
|
||||
|
||||
<menu name="Documentation">
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
operation retrieves a resource by ID. It is annotated with the
|
||||
<a href="./apidocs/ca/uhn/fhir/rest/annotation/Read.html">@Read</a>
|
||||
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.
|
||||
</p>
|
||||
|
||||
|
@ -61,7 +61,7 @@
|
|||
operation retrieves a specific version of a resource with a given ID. It looks exactly
|
||||
like a "read" operation, but with a second
|
||||
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.
|
||||
</p>
|
||||
|
||||
|
@ -109,9 +109,9 @@
|
|||
<p>
|
||||
To allow a search using given search parameters, add one or more parameters
|
||||
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
|
||||
<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>
|
||||
|
@ -158,16 +158,16 @@
|
|||
Search methods may take multiple parameters, and these parameters
|
||||
may be optional. To add a second required parameter, annotate the
|
||||
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
|
||||
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>
|
||||
You may annotate a method with any combination of as many @Required and as many @Optional
|
||||
parameters as you want. It is valid to have only @Required parameters, or
|
||||
only @Optional parameters, or any combination of the two.
|
||||
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 @RequiredParam parameters, or
|
||||
only @OptionalParam parameters, or any combination of the two.
|
||||
</p>
|
||||
|
||||
<macro name="snippet">
|
||||
|
@ -376,6 +376,48 @@
|
|||
|
||||
</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>
|
||||
|
||||
|
|
|
@ -19,9 +19,64 @@
|
|||
This library is still in experimental stage, so please tread with caution.
|
||||
</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 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>
|
||||
|
||||
</document>
|
||||
|
|
|
@ -10,12 +10,15 @@ import java.util.List;
|
|||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.io.input.ReaderInputStream;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.ProtocolVersion;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicStatusLine;
|
||||
import org.hamcrest.core.StringContains;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
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.primitive.IdDt;
|
||||
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.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.param.QualifiedDateParam;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
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
|
||||
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.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.rest.annotation.Id;
|
||||
import ca.uhn.fhir.rest.annotation.Include;
|
||||
import ca.uhn.fhir.rest.annotation.Optional;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
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.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.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.param.CodingListParam;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
|
@ -23,33 +26,36 @@ import ca.uhn.fhir.rest.param.QualifiedDateParam;
|
|||
public interface ITestClient extends IBasicClient {
|
||||
|
||||
@Read(type=Patient.class)
|
||||
Patient getPatientById(@Id IdDt theId);
|
||||
Patient getPatientById(@IdParam IdDt theId);
|
||||
|
||||
@Read(type=Patient.class)
|
||||
Patient getPatientByVersionId(@Id IdDt theId, @VersionId IdDt theVersionId);
|
||||
Patient getPatientByVersionId(@IdParam IdDt theId, @VersionIdParam IdDt theVersionId);
|
||||
|
||||
@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)
|
||||
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()
|
||||
public List<Patient> getPatientMultipleIdentifiers(@Required(name = "ids") CodingListParam theIdentifiers);
|
||||
public List<Patient> getPatientMultipleIdentifiers(@RequiredParam(name = "ids") CodingListParam theIdentifiers);
|
||||
|
||||
@Search()
|
||||
public List<Patient> getPatientByDateRange(@Required(name = "dateRange") DateRangeParam theIdentifiers);
|
||||
public List<Patient> getPatientByDateRange(@RequiredParam(name = "dateRange") DateRangeParam theIdentifiers);
|
||||
|
||||
@Search()
|
||||
public List<Patient> getPatientByDob(@Required(name=Patient.SP_BIRTHDATE) QualifiedDateParam theBirthDate);
|
||||
public List<Patient> getPatientByDob(@RequiredParam(name=Patient.SP_BIRTHDATE) QualifiedDateParam theBirthDate);
|
||||
|
||||
@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")
|
||||
public Patient getPatientNoParams();
|
||||
|
||||
@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;
|
||||
|
||||
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.Arrays;
|
||||
|
@ -15,6 +17,8 @@ import org.apache.commons.io.IOUtils;
|
|||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
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.UriDt;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.annotation.Id;
|
||||
import ca.uhn.fhir.rest.annotation.Include;
|
||||
import ca.uhn.fhir.rest.annotation.Optional;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
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.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.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.DateRangeParam;
|
||||
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
|
||||
public void testFormatParamXml() throws Exception {
|
||||
|
||||
|
@ -655,15 +683,15 @@ public class ResfulServerMethodTest {
|
|||
}
|
||||
|
||||
@Search(queryName="someQueryOneParam")
|
||||
public Patient getPatientOneParam(@Required(name="param1") StringDt theParam) {
|
||||
public Patient getPatientOneParam(@RequiredParam(name="param1") StringDt theParam) {
|
||||
Patient next = getIdToPatient().get("1");
|
||||
next.addName().addFamily(theParam.getValue());
|
||||
return next;
|
||||
}
|
||||
|
||||
@Search()
|
||||
public Patient getPatientWithIncludes(@Required(name = "withIncludes") StringDt theString,
|
||||
@Include(allow= {"include1","include2", "include3"}) List<PathSpecification> theIncludes) {
|
||||
public Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringDt theString,
|
||||
@IncludeParam(allow= {"include1","include2", "include3"}) List<PathSpecification> theIncludes) {
|
||||
Patient next = getIdToPatient().get("1");
|
||||
|
||||
next.addCommunication().setText(theString.getValue());
|
||||
|
@ -675,8 +703,16 @@ public class ResfulServerMethodTest {
|
|||
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()
|
||||
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 (IdentifierDt nextId : next.getIdentifier()) {
|
||||
if (nextId.matchesSystemAndValue(theIdentifier)) {
|
||||
|
@ -688,13 +724,13 @@ public class ResfulServerMethodTest {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public List<Patient> findDiagnosticReportsByPatient(@Required(name = "Patient.identifier") IdentifierDt thePatientId, @Required(name = DiagnosticReport.SP_NAME) CodingListParam theNames,
|
||||
@Optional(name = DiagnosticReport.SP_DATE) DateRangeParam theDateRange) throws Exception {
|
||||
public List<Patient> findDiagnosticReportsByPatient(@RequiredParam(name = "Patient.identifier") IdentifierDt thePatientId, @RequiredParam(name = DiagnosticReport.SP_NAME) CodingListParam theNames,
|
||||
@OptionalParam(name = DiagnosticReport.SP_DATE) DateRangeParam theDateRange) throws Exception {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Search()
|
||||
public Patient getPatientWithDOB(@Required(name = "dob") QualifiedDateParam theDob) {
|
||||
public Patient getPatientWithDOB(@RequiredParam(name = "dob") QualifiedDateParam theDob) {
|
||||
Patient next = getIdToPatient().get("1");
|
||||
if (theDob.getComparator() != null) {
|
||||
next.addIdentifier().setValue(theDob.getComparator().getCode());
|
||||
|
@ -706,7 +742,7 @@ public class ResfulServerMethodTest {
|
|||
}
|
||||
|
||||
@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>();
|
||||
Patient next = getIdToPatient().get("1");
|
||||
next.getName().get(0).getFamily().set(0, theName1);
|
||||
|
@ -722,7 +758,7 @@ public class ResfulServerMethodTest {
|
|||
* @param theName3
|
||||
*/
|
||||
@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>();
|
||||
Patient next = getIdToPatient().get("1");
|
||||
next.getName().get(0).getFamily().set(0, theName1);
|
||||
|
@ -735,7 +771,7 @@ public class ResfulServerMethodTest {
|
|||
}
|
||||
|
||||
@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>();
|
||||
Patient next = getIdToPatient().get("1");
|
||||
|
||||
|
@ -756,12 +792,12 @@ public class ResfulServerMethodTest {
|
|||
* @return The resource
|
||||
*/
|
||||
@Read()
|
||||
public Patient getResourceById(@Id IdDt theId) {
|
||||
public Patient getResourceById(@IdParam IdDt theId) {
|
||||
return getIdToPatient().get(theId.getValue());
|
||||
}
|
||||
|
||||
@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());
|
||||
retVal.getName().get(0).setText(theVersionId.getValue());
|
||||
return retVal;
|
||||
|
@ -778,7 +814,7 @@ public class ResfulServerMethodTest {
|
|||
}
|
||||
|
||||
@Search()
|
||||
public Patient getPatientByDateRange(@Required(name = "dateRange") DateRangeParam theIdentifiers) {
|
||||
public Patient getPatientByDateRange(@RequiredParam(name = "dateRange") DateRangeParam theIdentifiers) {
|
||||
Patient retVal = getIdToPatient().get("1");
|
||||
retVal.getName().get(0).addSuffix().setValue(theIdentifiers.getLowerBound().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.primitive.IdDt;
|
||||
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.Required;
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.server.provider.ServerProfileProvider;
|
||||
import ca.uhn.fhir.testutil.RandomServerPortProvider;
|
||||
|
@ -162,7 +162,7 @@ public class ResfulServerSelfReferenceTest {
|
|||
|
||||
|
||||
@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 (IdentifierDt nextId : next.getIdentifier()) {
|
||||
if (nextId.matchesSystemAndValue(theIdentifier)) {
|
||||
|
@ -182,7 +182,7 @@ public class ResfulServerSelfReferenceTest {
|
|||
* @return The resource
|
||||
*/
|
||||
@Read()
|
||||
public Patient getResourceById(@Id IdDt theId) {
|
||||
public Patient getResourceById(@IdParam IdDt theId) {
|
||||
return getIdToPatient().get(theId.getValue());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue