Create method almost working
This commit is contained in:
parent
b38be51668
commit
b325a5bfb1
|
@ -1,10 +0,0 @@
|
|||
package ca.uhn.fhir.rest.annotation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
||||
public @interface PUT {
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
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;
|
||||
|
||||
/**
|
||||
* RESTful method annotation to be used for the FHIR
|
||||
* <a href="http://hl7.org/implement/standards/fhir/http.html#update">update</a> method.
|
||||
*
|
||||
* <p>
|
||||
* Update is used to save an update to an existing resource (using its ID and optionally
|
||||
* a version ID). It also may allow a client to save a new resource using an ID of its choosing.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value=ElementType.METHOD)
|
||||
public @interface Update {
|
||||
|
||||
}
|
|
@ -6,14 +6,16 @@ public class MethodOutcome {
|
|||
|
||||
private IdDt myId;
|
||||
private IdDt myVersionId;
|
||||
private boolean myCreated;
|
||||
|
||||
public MethodOutcome() {
|
||||
}
|
||||
|
||||
public MethodOutcome(IdDt theId, IdDt theVersionId) {
|
||||
public MethodOutcome(boolean theCreated, IdDt theId, IdDt theVersionId) {
|
||||
super();
|
||||
myId = theId;
|
||||
myVersionId = theVersionId;
|
||||
myCreated=theCreated;
|
||||
}
|
||||
|
||||
public IdDt getId() {
|
||||
|
@ -32,4 +34,20 @@ public class MethodOutcome {
|
|||
myVersionId = theVersionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to <code>true</code> if the method resulted in the creation of a new resource. Set to
|
||||
* <code>false</code> if the method resulted in an update/modification/removal to an existing resource.
|
||||
*/
|
||||
public boolean isCreated() {
|
||||
return myCreated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to <code>true</code> if the method resulted in the creation of a new resource. Set to
|
||||
* <code>false</code> if the method resulted in an update/modification/removal to an existing resource.
|
||||
*/
|
||||
public void setCreated(boolean theCreated) {
|
||||
myCreated=theCreated;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
|
||||
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 abstract class BaseClientInvocationWithContents extends BaseClientInvocation {
|
||||
|
||||
private final Bundle myBundle;
|
||||
private final FhirContext myContext;
|
||||
private List<Header> myHeaders;
|
||||
private final IResource myResource;
|
||||
private String myUrlExtension;
|
||||
|
||||
public BaseClientInvocationWithContents(FhirContext theContext, Bundle theBundle) {
|
||||
super();
|
||||
myContext = theContext;
|
||||
myResource = null;
|
||||
myBundle = theBundle;
|
||||
}
|
||||
|
||||
public BaseClientInvocationWithContents(FhirContext theContext, IResource theResource, String theUrlExtension) {
|
||||
super();
|
||||
myContext = theContext;
|
||||
myResource = theResource;
|
||||
myBundle = null;
|
||||
myUrlExtension = theUrlExtension;
|
||||
}
|
||||
|
||||
public void addHeader(String theName, String theValue) {
|
||||
if (myHeaders == null) {
|
||||
myHeaders = new ArrayList<Header>();
|
||||
}
|
||||
myHeaders.add(new BasicHeader(theName, theValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpRequestBase asHttpRequest(String theUrlBase) throws DataFormatException, IOException {
|
||||
String url = theUrlBase + StringUtils.defaultString(myUrlExtension);
|
||||
String contents = myContext.newXmlParser().encodeResourceToString(myResource);
|
||||
StringEntity entity = new StringEntity(contents, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"));
|
||||
|
||||
HttpRequestBase http = createRequest(url, entity);
|
||||
if (myHeaders != null) {
|
||||
for (Header next : myHeaders) {
|
||||
http.addHeader(next);
|
||||
}
|
||||
}
|
||||
return http;
|
||||
}
|
||||
|
||||
protected abstract HttpRequestBase createRequest(String url, StringEntity theEntity);
|
||||
|
||||
}
|
|
@ -1,47 +1,27 @@
|
|||
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 class PostClientInvocation extends BaseClientInvocationWithContents {
|
||||
|
||||
public PostClientInvocation(FhirContext theContext, Bundle theBundle) {
|
||||
super();
|
||||
myContext = theContext;
|
||||
myResource = null;
|
||||
myBundle = theBundle;
|
||||
super(theContext, theBundle);
|
||||
}
|
||||
|
||||
public PostClientInvocation(FhirContext theContext, IResource theResource, String theUrlExtension) {
|
||||
super();
|
||||
myContext = theContext;
|
||||
myResource = theResource;
|
||||
myBundle = null;
|
||||
myUrlExtension = theUrlExtension;
|
||||
super(theContext, theResource, 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;
|
||||
protected HttpPost createRequest(String url, StringEntity theEntity) {
|
||||
HttpPost retVal = new HttpPost(url);
|
||||
retVal.setEntity(theEntity);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
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;
|
||||
|
||||
public class PutClientInvocation extends BaseClientInvocationWithContents {
|
||||
|
||||
public PutClientInvocation(FhirContext theContext, Bundle theBundle) {
|
||||
super(theContext, theBundle);
|
||||
}
|
||||
|
||||
public PutClientInvocation(FhirContext theContext, IResource theResource, String theUrlExtension) {
|
||||
super(theContext, theResource, theUrlExtension);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpRequestBase createRequest(String url, StringEntity theEntity) {
|
||||
HttpPut retVal = new HttpPut(url);
|
||||
retVal.setEntity(theEntity);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -25,6 +25,7 @@ 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.annotation.Update;
|
||||
import ca.uhn.fhir.rest.client.BaseClientInvocation;
|
||||
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
|
@ -79,7 +80,8 @@ public abstract class BaseMethodBinding {
|
|||
Search search = theMethod.getAnnotation(Search.class);
|
||||
Metadata conformance = theMethod.getAnnotation(Metadata.class);
|
||||
Create create = theMethod.getAnnotation(Create.class);
|
||||
if (!verifyMethodHasZeroOrOneOperationAnnotation(theMethod, read, search, conformance,create)) {
|
||||
Update update = theMethod.getAnnotation(Update.class);
|
||||
if (!verifyMethodHasZeroOrOneOperationAnnotation(theMethod, read, search, conformance,create,update)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -105,6 +107,8 @@ public abstract class BaseMethodBinding {
|
|||
return new ConformanceMethodBinding(theMethod, theContext);
|
||||
} else if (create != null) {
|
||||
return new CreateMethodBinding(theMethod, theContext);
|
||||
} else if (update != null) {
|
||||
return new UpdateMethodBinding(theMethod, theContext);
|
||||
} else {
|
||||
throw new ConfigurationException("Did not detect any FHIR annotations on method '" + theMethod.getName() + "' on type: " + theMethod.getDeclaringClass().getCanonicalName());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,241 @@
|
|||
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.primitive.IdDt;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
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.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.MethodNotAllowedException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionNotSpecifiedException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnclassifiedServerFailureException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
|
||||
public abstract class BaseOutcomeReturningMethodBinding 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 BaseOutcomeReturningMethodBinding(Method theMethod, FhirContext theContext, Class<?> theMethodAnnotation) {
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
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 @" + theMethodAnnotation.getSimpleName() + " method but it does not return " + MethodOutcome.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@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);
|
||||
String resourceName = def.getName();
|
||||
|
||||
return createClientInvocation(theArgs, resource, resourceName);
|
||||
}
|
||||
|
||||
protected abstract BaseClientInvocation createClientInvocation(Object[] theArgs, IResource resource, String resourceName);
|
||||
|
||||
@Override
|
||||
public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
||||
switch (theResponseStatusCode) {
|
||||
case Constants.STATUS_HTTP_200_OK:
|
||||
case Constants.STATUS_HTTP_201_CREATED:
|
||||
List<String> locationHeaders = theHeaders.get("location");
|
||||
MethodOutcome retVal = new MethodOutcome();
|
||||
if (locationHeaders != null && locationHeaders.size() > 0) {
|
||||
String locationHeader = locationHeaders.get(0);
|
||||
parseContentLocation(retVal, locationHeader);
|
||||
}
|
||||
return retVal;
|
||||
case Constants.STATUS_HTTP_400_BAD_REQUEST:
|
||||
throw new InvalidRequestException("Server responded with: " + IOUtils.toString(theResponseReader));
|
||||
case Constants.STATUS_HTTP_404_NOT_FOUND:
|
||||
throw new ResourceNotFoundException("Server responded with: " + IOUtils.toString(theResponseReader));
|
||||
case Constants.STATUS_HTTP_405_METHOD_NOT_ALLOWED:
|
||||
throw new MethodNotAllowedException("Server responded with: " + IOUtils.toString(theResponseReader));
|
||||
case Constants.STATUS_HTTP_409_CONFLICT:
|
||||
throw new ResourceVersionConflictException("Server responded with: " + IOUtils.toString(theResponseReader));
|
||||
case Constants.STATUS_HTTP_412_PRECONDITION_FAILED:
|
||||
throw new ResourceVersionNotSpecifiedException("Server responded with: " + IOUtils.toString(theResponseReader));
|
||||
case Constants.STATUS_HTTP_422_UNPROCESSABLE_ENTITY:
|
||||
IParser parser = createAppropriateParser(theResponseMimeType, theResponseReader, theResponseStatusCode);
|
||||
OperationOutcome operationOutcome = parser.parseResource(OperationOutcome.class, theResponseReader);
|
||||
throw new UnprocessableEntityException(operationOutcome);
|
||||
default:
|
||||
throw new UnclassifiedServerFailureException(theResponseStatusCode, IOUtils.toString(theResponseReader));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void parseContentLocation(MethodOutcome theOutcomeToPopulate, String theLocationHeader) {
|
||||
String resourceNamePart = "/" + myResourceName + "/";
|
||||
int resourceIndex = theLocationHeader.lastIndexOf(resourceNamePart);
|
||||
if (resourceIndex > -1) {
|
||||
int idIndexStart = resourceIndex + resourceNamePart.length();
|
||||
int idIndexEnd = theLocationHeader.indexOf('/', idIndexStart);
|
||||
if (idIndexEnd == -1) {
|
||||
theOutcomeToPopulate.setId(new IdDt(theLocationHeader.substring(idIndexStart)));
|
||||
} else {
|
||||
theOutcomeToPopulate.setId(new IdDt(theLocationHeader.substring(idIndexStart, idIndexEnd)));
|
||||
String versionIdPart = "/_history/";
|
||||
int historyIdStart = theLocationHeader.indexOf(versionIdPart, idIndexEnd);
|
||||
if (historyIdStart != -1) {
|
||||
theOutcomeToPopulate.setVersionId(new IdDt(theLocationHeader.substring(historyIdStart + versionIdPart.length())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getResourceName() {
|
||||
return myResourceName;
|
||||
}
|
||||
|
||||
@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);
|
||||
if (param == null) {
|
||||
continue;
|
||||
}
|
||||
params[i] = param.translateQueryParametersIntoServerArgument(theRequest.getParameters(), resource);
|
||||
}
|
||||
|
||||
addAdditionalParams(theRequest, params);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
if (response.isCreated()) {
|
||||
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() != null && response.getVersionId().isEmpty() == false) {
|
||||
b.append("/_history/");
|
||||
b.append(response.getVersionId().getValue());
|
||||
}
|
||||
theResponse.addHeader("Location", b.toString());
|
||||
} else {
|
||||
theResponse.setStatus(Constants.STATUS_HTTP_200_OK);
|
||||
}
|
||||
|
||||
theServer.addHapiHeader(theResponse);
|
||||
|
||||
theResponse.setContentType(Constants.CT_TEXT);
|
||||
|
||||
Writer writer = theResponse.getWriter();
|
||||
try {
|
||||
writer.append("Resource has been created");
|
||||
} finally {
|
||||
writer.close();
|
||||
}
|
||||
// getMethod().in
|
||||
}
|
||||
|
||||
/**
|
||||
* For subclasses to override
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
protected void addAdditionalParams(Request theRequest, Object[] theParams) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
protected abstract Set<RequestType> provideAllowableRequestTypes();
|
||||
|
||||
@Override
|
||||
public boolean matches(Request theRequest) {
|
||||
Set<RequestType> allowableRequestTypes = provideAllowableRequestTypes();
|
||||
RequestType requestType = theRequest.getRequestType();
|
||||
if (!allowableRequestTypes.contains(requestType)) {
|
||||
return false;
|
||||
}
|
||||
if (!myResourceName.equals(theRequest.getResourceName())) {
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.isNotBlank(theRequest.getOperation())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,86 +1,24 @@
|
|||
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.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 {
|
||||
public class CreateMethodBinding extends BaseOutcomeReturningMethodBinding {
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
super(theMethod, theContext, Create.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -94,127 +32,16 @@ public class CreateMethodBinding extends BaseMethodBinding {
|
|||
}
|
||||
|
||||
@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);
|
||||
protected Set<RequestType> provideAllowableRequestTypes() {
|
||||
return Collections.singleton(RequestType.POST);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseClientInvocation createClientInvocation(Object[] theArgs, IResource resource, String resourceName) {
|
||||
StringBuilder urlExtension = new StringBuilder();
|
||||
urlExtension.append(def.getName());
|
||||
urlExtension.append(resourceName);
|
||||
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
if (!myResourceName.equals(theRequest.getResourceName())) {
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.isNotBlank(theRequest.getOperation())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
|
||||
Validate.notNull(theMethod, "Method must not be null");
|
||||
|
||||
Integer idIndex = Util.findReadIdParameterIndex(theMethod);
|
||||
Integer versionIdIndex = Util.findReadVersionIdParameterIndex(theMethod);
|
||||
Integer idIndex = Util.findIdParameterIndex(theMethod);
|
||||
Integer versionIdIndex = Util.findVersionIdParameterIndex(theMethod);
|
||||
|
||||
myIdIndex = idIndex;
|
||||
myVersionIdIndex = versionIdIndex;
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
package ca.uhn.fhir.rest.method;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
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.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Update;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.BaseClientInvocation;
|
||||
import ca.uhn.fhir.rest.client.PutClientInvocation;
|
||||
import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
public class UpdateMethodBinding extends BaseOutcomeReturningMethodBinding {
|
||||
|
||||
private Integer myIdParameterIndex;
|
||||
|
||||
private Integer myVersionIdParameterIndex;
|
||||
|
||||
public UpdateMethodBinding(Method theMethod, FhirContext theContext) {
|
||||
super(theMethod, theContext, Update.class);
|
||||
|
||||
myIdParameterIndex = Util.findIdParameterIndex(theMethod);
|
||||
if (myIdParameterIndex == null) {
|
||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' on type '" + theMethod.getDeclaringClass().getCanonicalName() + "' has no parameter annotated with the @" + IdParam.class.getSimpleName() + " annotation");
|
||||
}
|
||||
myVersionIdParameterIndex = Util.findVersionIdParameterIndex(theMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestfulOperationTypeEnum getResourceOperationType() {
|
||||
return RestfulOperationTypeEnum.UPDATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestfulOperationSystemEnum getSystemOperationType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addAdditionalParams(Request theRequest, Object[] theParams) {
|
||||
/*
|
||||
* We are being a bit lenient here, since technically the client is
|
||||
* supposed to include the version in the Content-Location header, but
|
||||
* we allow it in the PUT URL as well..
|
||||
*/
|
||||
String locationHeader = theRequest.getServletRequest().getHeader(Constants.HEADER_CONTENT_LOCATION);
|
||||
if (isNotBlank(locationHeader)) {
|
||||
MethodOutcome mo = new MethodOutcome();
|
||||
parseContentLocation(mo, locationHeader);
|
||||
if (mo.getId() == null || mo.getId().isEmpty()) {
|
||||
throw new InvalidRequestException("Invalid Content-Location header for resource " + getResourceName()+ ": " + locationHeader);
|
||||
}
|
||||
if (mo.getVersionId() != null && mo.getVersionId().isEmpty() == false) {
|
||||
theRequest.setVersion(mo.getVersionId());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: we should send an HTTP 412 automatically if the server
|
||||
// only has a method which requires a version ID, and no
|
||||
// Content-Location header is present
|
||||
|
||||
theParams[myIdParameterIndex] = theRequest.getId();
|
||||
if (myVersionIdParameterIndex != null) {
|
||||
theParams[myVersionIdParameterIndex] = theRequest.getVersion();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseClientInvocation createClientInvocation(Object[] theArgs, IResource resource, String resourceName) {
|
||||
IdDt idDt = (IdDt) theArgs[myIdParameterIndex];
|
||||
if (idDt == null) {
|
||||
throw new NullPointerException("ID can not be null");
|
||||
}
|
||||
String id = idDt.getValue();
|
||||
|
||||
StringBuilder urlExtension = new StringBuilder();
|
||||
urlExtension.append(resourceName);
|
||||
urlExtension.append('/');
|
||||
urlExtension.append(id);
|
||||
PutClientInvocation retVal = new PutClientInvocation(getContext(), resource, urlExtension.toString());
|
||||
|
||||
if (myVersionIdParameterIndex != null) {
|
||||
IdDt versionIdDt = (IdDt) theArgs[myIdParameterIndex];
|
||||
if (versionIdDt != null) {
|
||||
String versionId = versionIdDt.getValue();
|
||||
if (StringUtils.isNotBlank(versionId)) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append('/');
|
||||
b.append(urlExtension);
|
||||
b.append('/');
|
||||
b.append(versionId);
|
||||
retVal.addHeader(Constants.HEADER_CONTENT_LOCATION, b.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<RequestType> provideAllowableRequestTypes() {
|
||||
return Collections.singleton(RequestType.PUT);
|
||||
}
|
||||
|
||||
}
|
|
@ -98,16 +98,19 @@ class Util {
|
|||
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 if (nextAnnotation instanceof IdParam || nextAnnotation instanceof VersionIdParam) {
|
||||
param = null;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
haveHandledMethod= true;
|
||||
parameters.add(param);
|
||||
|
||||
}
|
||||
|
||||
if (!haveHandledMethod) {
|
||||
throw new ConfigurationException("Parameter # " + paramIndex + " of method '" + method.getName() + "' has no recognized FHIR interface parameter annotations. Don't know how to handle this parameter!");
|
||||
throw new ConfigurationException("Parameter #" + paramIndex + " of method '" + method.getName() + "' on type '"+method.getDeclaringClass().getCanonicalName()+"' has no recognized FHIR interface parameter annotations. Don't know how to handle this parameter");
|
||||
}
|
||||
|
||||
paramIndex++;
|
||||
|
@ -115,11 +118,11 @@ class Util {
|
|||
return parameters;
|
||||
}
|
||||
|
||||
public static Integer findReadIdParameterIndex(Method theMethod) {
|
||||
public static Integer findIdParameterIndex(Method theMethod) {
|
||||
return findParamIndex(theMethod, IdParam.class);
|
||||
}
|
||||
|
||||
public static Integer findReadVersionIdParameterIndex(Method theMethod) {
|
||||
public static Integer findVersionIdParameterIndex(Method theMethod) {
|
||||
return findParamIndex(theMethod, VersionIdParam.class);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,14 @@ public class Constants {
|
|||
public static final String PARAM_QUERY = "_query";
|
||||
public static final int STATUS_HTTP_201_CREATED = 201;
|
||||
public static final String CT_TEXT = "text/plain";
|
||||
public static final int STATUS_HTTP_200_OK = 200;
|
||||
public static final int STATUS_HTTP_422_UNPROCESSABLE_ENTITY = 422;
|
||||
public static final int STATUS_HTTP_404_NOT_FOUND = 404;
|
||||
public static final int STATUS_HTTP_400_BAD_REQUEST = 400;
|
||||
public static final int STATUS_HTTP_405_METHOD_NOT_ALLOWED = 405;
|
||||
public static final int STATUS_HTTP_409_CONFLICT = 409;
|
||||
public static final int STATUS_HTTP_412_PRECONDITION_FAILED = 412;
|
||||
public static final String HEADER_CONTENT_LOCATION = "Content-Location";
|
||||
|
||||
static {
|
||||
Map<String, EncodingUtil> valToEncoding = new HashMap<String, EncodingUtil>();
|
||||
|
|
|
@ -95,10 +95,14 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
|
||||
Collection<IResourceProvider> resourceProvider = getResourceProviders();
|
||||
for (IResourceProvider nextProvider : resourceProvider) {
|
||||
if (myTypeToProvider.containsKey(nextProvider.getResourceType())) {
|
||||
throw new ServletException("Multiple providers for type: " + nextProvider.getResourceType().getCanonicalName());
|
||||
Class<? extends IResource> resourceType = nextProvider.getResourceType();
|
||||
if (resourceType==null) {
|
||||
throw new NullPointerException("getResourceType() on class '" + nextProvider.getClass().getCanonicalName() + "' returned null");
|
||||
}
|
||||
myTypeToProvider.put(nextProvider.getResourceType(), nextProvider);
|
||||
if (myTypeToProvider.containsKey(resourceType)) {
|
||||
throw new ServletException("Multiple providers for type: " + resourceType.getCanonicalName());
|
||||
}
|
||||
myTypeToProvider.put(resourceType, nextProvider);
|
||||
}
|
||||
|
||||
ourLog.info("Got {} resource providers", myTypeToProvider.size());
|
||||
|
@ -266,7 +270,7 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
}
|
||||
|
||||
if (resourceBinding == null) {
|
||||
throw new MethodNotFoundException("Unknown resource type: " + resourceName);
|
||||
throw new MethodNotFoundException("Unknown resource type '" + resourceName+"' - Server knows how to handle: "+resources.keySet());
|
||||
}
|
||||
|
||||
if (tok.hasMoreTokens()) {
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package ca.uhn.fhir.rest.server.exceptions;
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/27/2014.
|
||||
*/
|
||||
public class MethodNotAllowedException extends BaseServerResponseException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public MethodNotAllowedException(String error) {
|
||||
super(405, error);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package ca.uhn.fhir.rest.server.exceptions;
|
||||
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/27/2014.
|
||||
*/
|
||||
public class ResourceVersionConflictException extends BaseServerResponseException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ResourceVersionConflictException(String error) {
|
||||
super(Constants.STATUS_HTTP_409_CONFLICT, error);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package ca.uhn.fhir.rest.server.exceptions;
|
||||
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
|
||||
/**
|
||||
* Thrown for an Update operation if that operation requires a version to
|
||||
* be specified in an HTTP header, and none was.
|
||||
*/
|
||||
public class ResourceVersionNotSpecifiedException extends BaseServerResponseException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ResourceVersionNotSpecifiedException(String error) {
|
||||
super(Constants.STATUS_HTTP_412_PRECONDITION_FAILED, error);
|
||||
}
|
||||
}
|
|
@ -223,6 +223,7 @@ public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
|
|||
// This method returns a MethodOutcome object which contains
|
||||
// the ID and Version ID for the newly saved resource
|
||||
MethodOutcome retVal = new MethodOutcome();
|
||||
retVal.setCreated(true);
|
||||
retVal.setId(new IdDt("3746"));
|
||||
retVal.setVersionId(new IdDt("1"));
|
||||
return retVal;
|
||||
|
|
|
@ -16,6 +16,7 @@ import ca.uhn.fhir.rest.annotation.Read;
|
|||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.annotation.Update;
|
||||
import ca.uhn.fhir.rest.annotation.VersionIdParam;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.api.IBasicClient;
|
||||
|
@ -58,4 +59,7 @@ public interface ITestClient extends IBasicClient {
|
|||
@Create
|
||||
public MethodOutcome createPatient(@ResourceParam Patient thePatient);
|
||||
|
||||
@Update
|
||||
public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient thePatient);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -15,8 +13,10 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
@ -34,6 +34,7 @@ import org.junit.Test;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.BundleEntry;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.PathSpecification;
|
||||
import ca.uhn.fhir.model.dstu.composite.CodingDt;
|
||||
import ca.uhn.fhir.model.dstu.composite.HumanNameDt;
|
||||
|
@ -54,6 +55,7 @@ import ca.uhn.fhir.rest.annotation.Read;
|
|||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.annotation.Update;
|
||||
import ca.uhn.fhir.rest.annotation.VersionIdParam;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.param.CodingListParam;
|
||||
|
@ -82,9 +84,10 @@ public class ResfulServerMethodTest {
|
|||
|
||||
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
|
||||
ServerProfileProvider profProvider = new ServerProfileProvider(ourCtx);
|
||||
DummyDiagnosticReportResourceProvider reportProvider = new DummyDiagnosticReportResourceProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
ServletHolder servletHolder = new ServletHolder(new DummyRestfulServer(patientProvider, profProvider));
|
||||
ServletHolder servletHolder = new ServletHolder(new DummyRestfulServer(patientProvider, profProvider,reportProvider));
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
@ -419,6 +422,66 @@ public class ResfulServerMethodTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient/001");
|
||||
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 testUpdateWithVersion() throws Exception {
|
||||
|
||||
DiagnosticReport patient = new DiagnosticReport();
|
||||
patient.getIdentifier().setValue("001");
|
||||
|
||||
HttpPut httpPut = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
|
||||
httpPut.addHeader("Content-Location","/DiagnosticReport/001/_history/002");
|
||||
httpPut.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPut);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
assertEquals("http://localhost:" + ourPort + "/DiagnosticReport/001/_history/002", status.getFirstHeader("Location").getValue());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test()
|
||||
public void testUpdateWithVersionBadContentLocationHeader() throws Exception {
|
||||
|
||||
DiagnosticReport patient = new DiagnosticReport();
|
||||
patient.getIdentifier().setValue("001");
|
||||
|
||||
HttpPut httpPut = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
|
||||
httpPut.addHeader("Content-Location","/Patient/001/_history/002");
|
||||
httpPut.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
CloseableHttpResponse results = ourClient.execute(httpPut);
|
||||
String responseContent = IOUtils.toString(results.getEntity().getContent());
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(400, results.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatParamXml() throws Exception {
|
||||
|
||||
|
@ -639,6 +702,24 @@ public class ResfulServerMethodTest {
|
|||
|
||||
}
|
||||
|
||||
|
||||
public static class DummyDiagnosticReportResourceProvider implements IResourceProvider{
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
return DiagnosticReport.class;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Update()
|
||||
public MethodOutcome updateDiagnosticReportWithVersion(@IdParam IdDt theId, @VersionIdParam IdDt theVersionId, @ResourceParam DiagnosticReport thePatient) {
|
||||
IdDt id = theId;
|
||||
IdDt version = theVersionId;
|
||||
return new MethodOutcome(true, id, version);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
|
@ -675,6 +756,18 @@ public class ResfulServerMethodTest {
|
|||
return idToPatient;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Update()
|
||||
public MethodOutcome updateDiagnosticReportWithVersion(@IdParam IdDt theId, @VersionIdParam IdDt theVersionId, @ResourceParam DiagnosticReport thePatient) {
|
||||
/* TODO: THIS METHOD IS NOT USED. It's the wrong type (DiagnosticReport), so
|
||||
* it should cause an exception on startup. Also we should detect if there
|
||||
* are multiple resource params on an update/create/etc method
|
||||
*/
|
||||
IdDt id = theId;
|
||||
IdDt version = theVersionId;
|
||||
return new MethodOutcome(true, id, version);
|
||||
}
|
||||
|
||||
@Search(queryName="someQueryNoParams")
|
||||
public Patient getPatientNoParams() {
|
||||
Patient next = getIdToPatient().get("1");
|
||||
|
@ -707,10 +800,17 @@ public class ResfulServerMethodTest {
|
|||
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);
|
||||
return new MethodOutcome(true, id, version);
|
||||
}
|
||||
|
||||
@Update()
|
||||
public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient thePatient) {
|
||||
IdDt id = theId;
|
||||
IdDt version = new IdDt(thePatient.getIdentifierFirstRep().getValue().getValue());
|
||||
return new MethodOutcome(true, id, version);
|
||||
}
|
||||
|
||||
|
||||
@Search()
|
||||
public Patient getPatient(@RequiredParam(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier) {
|
||||
for (Patient next : getIdToPatient().values()) {
|
||||
|
|
Loading…
Reference in New Issue