Get delete working
This commit is contained in:
parent
3a7ea0c8ba
commit
acb5b02672
|
@ -47,15 +47,12 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
|
||||||
return myDatatypeToDefinition.get(theType);
|
return myDatatypeToDefinition.get(theType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RuntimeChildUndeclaredExtensionDefinition.class);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
|
void sealAndInitialize(Map<Class<? extends IElement>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
|
||||||
Map<String, BaseRuntimeElementDefinition<?>> datatypeAttributeNameToDefinition = new HashMap<String, BaseRuntimeElementDefinition<?>>();
|
Map<String, BaseRuntimeElementDefinition<?>> datatypeAttributeNameToDefinition = new HashMap<String, BaseRuntimeElementDefinition<?>>();
|
||||||
myDatatypeToAttributeName = new HashMap<Class<? extends IElement>, String>();
|
myDatatypeToAttributeName = new HashMap<Class<? extends IElement>, String>();
|
||||||
|
|
||||||
for (BaseRuntimeElementDefinition<?> next : theClassToElementDefinitions.values()) {
|
for (BaseRuntimeElementDefinition<?> next : theClassToElementDefinitions.values()) {
|
||||||
ourLog.info(next.getName());
|
|
||||||
if (next instanceof IRuntimeDatatypeDefinition) {
|
if (next instanceof IRuntimeDatatypeDefinition) {
|
||||||
if (!((IRuntimeDatatypeDefinition) next).isSpecialization()) {
|
if (!((IRuntimeDatatypeDefinition) next).isSpecialization()) {
|
||||||
String attrName = "value" + WordUtils.capitalize(next.getName());
|
String attrName = "value" + WordUtils.capitalize(next.getName());
|
||||||
|
|
|
@ -180,7 +180,7 @@ public abstract class BaseMethodBinding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static EncodingUtil determineResponseEncoding(HttpServletRequest theRequest, Map<String, String[]> theParams) {
|
public static EncodingUtil determineResponseEncoding(HttpServletRequest theRequest, Map<String, String[]> theParams) {
|
||||||
String[] format = theParams.remove(Constants.PARAM_FORMAT);
|
String[] format = theParams.remove(Constants.PARAM_FORMAT);
|
||||||
if (format != null) {
|
if (format != null) {
|
||||||
for (String nextFormat : format) {
|
for (String nextFormat : format) {
|
||||||
|
|
|
@ -5,8 +5,6 @@ import java.io.Reader;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -40,14 +38,7 @@ import ca.uhn.fhir.rest.server.exceptions.UnclassifiedServerFailureException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
|
|
||||||
public abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding {
|
public abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding {
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseOutcomeReturningMethodBinding.class);
|
||||||
private static Set<String> ALLOWED_PARAMS;
|
|
||||||
static {
|
|
||||||
HashSet<String> set = new HashSet<String>();
|
|
||||||
set.add(Constants.PARAM_FORMAT);
|
|
||||||
ALLOWED_PARAMS = Collections.unmodifiableSet(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<IParameter> myParameters;
|
private List<IParameter> myParameters;
|
||||||
private boolean myReturnVoid;
|
private boolean myReturnVoid;
|
||||||
|
|
||||||
|
@ -57,28 +48,15 @@ public abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBindin
|
||||||
|
|
||||||
if (!theMethod.getReturnType().equals(MethodOutcome.class)) {
|
if (!theMethod.getReturnType().equals(MethodOutcome.class)) {
|
||||||
if (!allowVoidReturnType()) {
|
if (!allowVoidReturnType()) {
|
||||||
throw new ConfigurationException("Method " + theMethod.getName() + " in type " + theMethod.getDeclaringClass().getCanonicalName() + " is a @" + theMethodAnnotation.getSimpleName()
|
throw new ConfigurationException("Method " + theMethod.getName() + " in type " + theMethod.getDeclaringClass().getCanonicalName() + " is a @" + theMethodAnnotation.getSimpleName() + " method but it does not return " + MethodOutcome.class);
|
||||||
+ " method but it does not return " + MethodOutcome.class);
|
} else if (theMethod.getReturnType() == void.class) {
|
||||||
} else if (theMethod.getReturnType() == Void.class) {
|
|
||||||
myReturnVoid = true;
|
myReturnVoid = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<IParameter> getParameters() {
|
public abstract String getResourceName();
|
||||||
return myParameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subclasses may override to allow a void method return type, which is allowable for some methods (e.g. delete)
|
|
||||||
*/
|
|
||||||
protected boolean allowVoidReturnType() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected abstract BaseClientInvocation createClientInvocation(Object[] theArgs, IResource resource, String resourceName);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
||||||
|
@ -95,6 +73,16 @@ public abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBindin
|
||||||
String locationHeader = locationHeaders.get(0);
|
String locationHeader = locationHeaders.get(0);
|
||||||
parseContentLocation(retVal, locationHeader);
|
parseContentLocation(retVal, locationHeader);
|
||||||
}
|
}
|
||||||
|
if (theResponseStatusCode != Constants.STATUS_HTTP_204_NO_CONTENT) {
|
||||||
|
EncodingUtil ct = EncodingUtil.forContentType(theResponseMimeType);
|
||||||
|
if (ct != null) {
|
||||||
|
IParser parser = ct.newParser(getContext());
|
||||||
|
OperationOutcome outcome = parser.parseResource(OperationOutcome.class, theResponseReader);
|
||||||
|
retVal.setOperationOutcome(outcome);
|
||||||
|
} else {
|
||||||
|
ourLog.debug("Ignoring response content of type: {}", theResponseMimeType);
|
||||||
|
}
|
||||||
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
case Constants.STATUS_HTTP_400_BAD_REQUEST:
|
case Constants.STATUS_HTTP_400_BAD_REQUEST:
|
||||||
throw new InvalidRequestException("Server responded with: " + IOUtils.toString(theResponseReader));
|
throw new InvalidRequestException("Server responded with: " + IOUtils.toString(theResponseReader));
|
||||||
|
@ -116,43 +104,11 @@ public abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBindin
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void parseContentLocation(MethodOutcome theOutcomeToPopulate, String theLocationHeader) {
|
|
||||||
String resourceNamePart = "/" + getResourceName() + "/";
|
|
||||||
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 abstract String getResourceName();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse) throws BaseServerResponseException, IOException {
|
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()];
|
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);
|
addParametersForServerRequest(theRequest, params);
|
||||||
|
|
||||||
MethodOutcome response;
|
MethodOutcome response;
|
||||||
try {
|
try {
|
||||||
|
@ -168,6 +124,8 @@ public abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBindin
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
if (myReturnVoid == false) {
|
if (myReturnVoid == false) {
|
||||||
throw new ConfigurationException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() + " returned null");
|
throw new ConfigurationException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() + " returned null");
|
||||||
|
} else {
|
||||||
|
theResponse.setStatus(Constants.STATUS_HTTP_204_NO_CONTENT);
|
||||||
}
|
}
|
||||||
} else if (!myReturnVoid) {
|
} else if (!myReturnVoid) {
|
||||||
if (response.isCreated()) {
|
if (response.isCreated()) {
|
||||||
|
@ -192,26 +150,29 @@ public abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBindin
|
||||||
|
|
||||||
theServer.addHapiHeader(theResponse);
|
theServer.addHapiHeader(theResponse);
|
||||||
|
|
||||||
theResponse.setContentType(Constants.CT_TEXT);
|
|
||||||
|
|
||||||
Writer writer = theResponse.getWriter();
|
Writer writer = theResponse.getWriter();
|
||||||
try {
|
try {
|
||||||
writer.append("Resource has been created");
|
if (response != null) {
|
||||||
|
OperationOutcome outcome = new OperationOutcome();
|
||||||
|
if (response.getOperationOutcome() != null && response.getOperationOutcome().getIssue() != null) {
|
||||||
|
outcome.getIssue().addAll(response.getOperationOutcome().getIssue());
|
||||||
|
}
|
||||||
|
EncodingUtil encoding = BaseMethodBinding.determineResponseEncoding(theRequest.getServletRequest(), theRequest.getParameters());
|
||||||
|
theResponse.setContentType(encoding.getResourceContentType());
|
||||||
|
IParser parser = encoding.newParser(getContext());
|
||||||
|
parser.encodeResourceToWriter(outcome, writer);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
writer.close();
|
writer.close();
|
||||||
}
|
}
|
||||||
// getMethod().in
|
// getMethod().in
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected abstract void addParametersForServerRequest(Request theRequest, Object[] theParams);
|
||||||
* For subclasses to override
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
protected void addAdditionalParams(Request theRequest, Object[] theParams) {
|
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract Set<RequestType> provideAllowableRequestTypes();
|
public boolean isReturnVoid() {
|
||||||
|
return myReturnVoid;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(Request theRequest) {
|
public boolean matches(Request theRequest) {
|
||||||
|
@ -229,4 +190,39 @@ public abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBindin
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclasses may override to allow a void method return type, which is
|
||||||
|
* allowable for some methods (e.g. delete)
|
||||||
|
*/
|
||||||
|
protected boolean allowVoidReturnType() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract BaseClientInvocation createClientInvocation(Object[] theArgs, IResource resource, String resourceName);
|
||||||
|
|
||||||
|
protected List<IParameter> getParameters() {
|
||||||
|
return myParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void parseContentLocation(MethodOutcome theOutcomeToPopulate, String theLocationHeader) {
|
||||||
|
String resourceNamePart = "/" + getResourceName() + "/";
|
||||||
|
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())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Set<RequestType> provideAllowableRequestTypes();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,26 @@
|
||||||
package ca.uhn.fhir.rest.method;
|
package ca.uhn.fhir.rest.method;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
|
import ca.uhn.fhir.parser.IParser;
|
||||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
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.BaseClientInvocation;
|
||||||
import ca.uhn.fhir.rest.param.IParameter;
|
import ca.uhn.fhir.rest.param.IParameter;
|
||||||
import ca.uhn.fhir.rest.param.ResourceParameter;
|
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.InternalErrorException;
|
||||||
|
|
||||||
public abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOutcomeReturningMethodBinding {
|
public abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOutcomeReturningMethodBinding {
|
||||||
|
@ -38,6 +49,79 @@ public abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For subclasses to override
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void addParametersForServerRequest(Request theRequest, Object[] theParams) {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse) throws BaseServerResponseException, IOException {
|
||||||
|
EncodingUtil encoding = BaseMethodBinding.determineResponseEncoding(theRequest.getServletRequest(), theRequest.getParameters());
|
||||||
|
IParser parser = encoding.newParser(getContext());
|
||||||
|
IResource resource = parser.parseResource(theRequest.getInputReader());
|
||||||
|
|
||||||
|
Object[] params = new Object[getParameters().size()];
|
||||||
|
for (int i = 0; i < getParameters().size(); i++) {
|
||||||
|
IParameter param = getParameters().get(i);
|
||||||
|
if (param == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
params[i] = param.translateQueryParametersIntoServerArgument(theRequest.getParameters(), resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
addParametersForServerRequest(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) {
|
||||||
|
if (isReturnVoid() == false) {
|
||||||
|
throw new ConfigurationException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() + " returned null");
|
||||||
|
}
|
||||||
|
} else if (!isReturnVoid()) {
|
||||||
|
if (response.isCreated()) {
|
||||||
|
theResponse.setStatus(Constants.STATUS_HTTP_201_CREATED);
|
||||||
|
StringBuilder b = new StringBuilder();
|
||||||
|
b.append(theRequest.getFhirServerBase());
|
||||||
|
b.append('/');
|
||||||
|
b.append(getResourceName());
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
theResponse.setStatus(Constants.STATUS_HTTP_204_NO_CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
theServer.addHapiHeader(theResponse);
|
||||||
|
|
||||||
|
theResponse.setContentType(Constants.CT_TEXT);
|
||||||
|
|
||||||
|
Writer writer = theResponse.getWriter();
|
||||||
|
try {
|
||||||
|
writer.append("Resource has been created");
|
||||||
|
} finally {
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
// getMethod().in
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getResourceName() {
|
public String getResourceName() {
|
||||||
|
|
|
@ -20,39 +20,40 @@ import ca.uhn.fhir.rest.client.PostClientInvocation;
|
||||||
import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
|
import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
|
||||||
public class DeleteMethodBinding extends BaseOutcomeReturningMethodBinding {
|
public class DeleteMethodBinding extends BaseOutcomeReturningMethodBinding {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private String myResourceName;
|
private String myResourceName;
|
||||||
private Integer myIdParameterIndex;
|
private Integer myIdParameterIndex;
|
||||||
|
|
||||||
public DeleteMethodBinding(Method theMethod, FhirContext theContext, IResourceProvider theProvider) {
|
public DeleteMethodBinding(Method theMethod, FhirContext theContext, IResourceProvider theProvider) {
|
||||||
super(theMethod, theContext, Delete.class);
|
super(theMethod, theContext, Delete.class);
|
||||||
|
|
||||||
Delete deleteAnnotation = theMethod.getAnnotation(Delete.class);
|
Delete deleteAnnotation = theMethod.getAnnotation(Delete.class);
|
||||||
Class<? extends IResource> resourceType = deleteAnnotation.resourceType();
|
Class<? extends IResource> resourceType = deleteAnnotation.resourceType();
|
||||||
if (resourceType != Delete.NotSpecified.class) {
|
if (resourceType != Delete.NotSpecified.class) {
|
||||||
RuntimeResourceDefinition def = theContext.getResourceDefinition(resourceType);
|
RuntimeResourceDefinition def = theContext.getResourceDefinition(resourceType);
|
||||||
myResourceName = def.getName();
|
myResourceName = def.getName();
|
||||||
} else {
|
} else {
|
||||||
if (theProvider!=null) {
|
if (theProvider != null) {
|
||||||
RuntimeResourceDefinition def = theContext.getResourceDefinition(theProvider.getResourceType());
|
RuntimeResourceDefinition def = theContext.getResourceDefinition(theProvider.getResourceType());
|
||||||
myResourceName = def.getName();
|
myResourceName = def.getName();
|
||||||
}else {
|
} else {
|
||||||
throw new ConfigurationException("Can not determine resource type for method '"+theMethod.getName() + "' on type " + theMethod.getDeclaringClass().getCanonicalName() + " - Did you forget to include the resourceType() value on the @" + Delete.class.getSimpleName() + " method annotation?");
|
throw new ConfigurationException("Can not determine resource type for method '" + theMethod.getName() + "' on type " + theMethod.getDeclaringClass().getCanonicalName() + " - Did you forget to include the resourceType() value on the @"
|
||||||
|
+ Delete.class.getSimpleName() + " method annotation?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
myIdParameterIndex = Util.findIdParameterIndex(theMethod);
|
myIdParameterIndex = Util.findIdParameterIndex(theMethod);
|
||||||
if (myIdParameterIndex == null) {
|
if (myIdParameterIndex == null) {
|
||||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' on type '" + theMethod.getDeclaringClass().getCanonicalName() + "' has no parameter annotated with the @" + IdParam.class.getSimpleName() + " annotation");
|
throw new ConfigurationException("Method '" + theMethod.getName() + "' on type '" + theMethod.getDeclaringClass().getCanonicalName() + "' has no parameter annotated with the @" + IdParam.class.getSimpleName() + " annotation");
|
||||||
}
|
}
|
||||||
|
|
||||||
Integer versionIdParameterIndex = Util.findVersionIdParameterIndex(theMethod);
|
Integer versionIdParameterIndex = Util.findVersionIdParameterIndex(theMethod);
|
||||||
if (versionIdParameterIndex!=null) {
|
if (versionIdParameterIndex != null) {
|
||||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' on type '" + theMethod.getDeclaringClass().getCanonicalName() + "' has a parameter annotated with the @" + VersionIdParam.class.getSimpleName() + " annotation but delete methods may not have this annotation");
|
throw new ConfigurationException("Method '" + theMethod.getName() + "' on type '" + theMethod.getDeclaringClass().getCanonicalName() + "' has a parameter annotated with the @" + VersionIdParam.class.getSimpleName()
|
||||||
|
+ " annotation but delete methods may not have this annotation");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -90,11 +91,11 @@ public class DeleteMethodBinding extends BaseOutcomeReturningMethodBinding {
|
||||||
return myResourceName;
|
return myResourceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
// public boolean matches(Request theRequest) {
|
// public boolean matches(Request theRequest) {
|
||||||
// // TODO Auto-generated method stub
|
// // TODO Auto-generated method stub
|
||||||
// return super.matches(theRequest);
|
// return super.matches(theRequest);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
|
public BaseClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
|
||||||
|
@ -109,4 +110,16 @@ public class DeleteMethodBinding extends BaseOutcomeReturningMethodBinding {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addParametersForServerRequest(Request theRequest, Object[] theParams) {
|
||||||
|
String url = theRequest.getCompleteUrl();
|
||||||
|
int resNameIdx = url.indexOf(getResourceName());
|
||||||
|
String id = url.substring(resNameIdx+getResourceName().length() + 1);
|
||||||
|
if (id.contains("/")) {
|
||||||
|
throw new InvalidRequestException("Invalid request path for a DELETE operation: "+theRequest.getCompleteUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
theParams[myIdParameterIndex] = new IdDt(id);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ public class UpdateMethodBinding extends BaseOutcomeReturningMethodBindingWithRe
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addAdditionalParams(Request theRequest, Object[] theParams) {
|
protected void addParametersForServerRequest(Request theRequest, Object[] theParams) {
|
||||||
/*
|
/*
|
||||||
* We are being a bit lenient here, since technically the client is
|
* We are being a bit lenient here, since technically the client is
|
||||||
* supposed to include the version in the Content-Location header, but
|
* supposed to include the version in the Content-Location header, but
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package ca.uhn.fhir.rest.server;
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
|
||||||
|
@ -21,6 +23,17 @@ public enum EncodingUtil {
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
private static HashMap<String, EncodingUtil> ourContentTypeToEncoding;
|
||||||
|
|
||||||
|
static {
|
||||||
|
ourContentTypeToEncoding = new HashMap<String, EncodingUtil>();
|
||||||
|
for (EncodingUtil next: values()) {
|
||||||
|
ourContentTypeToEncoding.put(next.getBundleContentType(), next);
|
||||||
|
ourContentTypeToEncoding.put(next.getResourceContentType(), next);
|
||||||
|
ourContentTypeToEncoding.put(next.getBrowserFriendlyBundleContentType(), next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String myResourceContentType;
|
private String myResourceContentType;
|
||||||
private String myBundleContentType;
|
private String myBundleContentType;
|
||||||
private String myBrowserFriendlyContentType;
|
private String myBrowserFriendlyContentType;
|
||||||
|
@ -45,4 +58,9 @@ public enum EncodingUtil {
|
||||||
return myBrowserFriendlyContentType;
|
return myBrowserFriendlyContentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static EncodingUtil forContentType(String theContentType) {
|
||||||
|
return ourContentTypeToEncoding.get(theContentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ public class CompleteExampleClient {
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This translated into a URL similar to the following:
|
* This is translated into a URL similar to the following:
|
||||||
* http://fhir.healthintersections.com.au/open/Patient?identifier=urn:oid:1.2.36.146.595.217.0.1%7C12345
|
* http://fhir.healthintersections.com.au/open/Patient?identifier=urn:oid:1.2.36.146.595.217.0.1%7C12345
|
||||||
*/
|
*/
|
||||||
@Search
|
@Search
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
</macro>
|
</macro>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
You will probable wish to add more methods
|
You will probably want to add more methods
|
||||||
to your client interface. See
|
to your client interface. See
|
||||||
<a href="./doc_rest_operations.html">RESTful Operations</a> for
|
<a href="./doc_rest_operations.html">RESTful Operations</a> for
|
||||||
lots more examples of how to add methods for various operations.
|
lots more examples of how to add methods for various operations.
|
||||||
|
|
|
@ -14,6 +14,7 @@ import org.apache.http.Header;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.ProtocolVersion;
|
import org.apache.http.ProtocolVersion;
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.methods.HttpDelete;
|
||||||
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.client.methods.HttpPost;
|
||||||
import org.apache.http.client.methods.HttpPut;
|
import org.apache.http.client.methods.HttpPut;
|
||||||
import org.apache.http.client.methods.HttpUriRequest;
|
import org.apache.http.client.methods.HttpUriRequest;
|
||||||
|
@ -32,6 +33,7 @@ import ca.uhn.fhir.model.api.PathSpecification;
|
||||||
import ca.uhn.fhir.model.dstu.composite.CodingDt;
|
import ca.uhn.fhir.model.dstu.composite.CodingDt;
|
||||||
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Conformance;
|
import ca.uhn.fhir.model.dstu.resource.Conformance;
|
||||||
|
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
@ -115,7 +117,45 @@ public class ClientTest {
|
||||||
assertEquals("100", response.getId().getValue());
|
assertEquals("100", response.getId().getValue());
|
||||||
assertEquals("200", response.getVersionId().getValue());
|
assertEquals("200", response.getVersionId().getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelete() throws Exception {
|
||||||
|
|
||||||
|
OperationOutcome oo = new OperationOutcome();
|
||||||
|
oo.addIssue().setDetails("Hello");
|
||||||
|
String resp = new FhirContext().newXmlParser().encodeResourceToString(oo);
|
||||||
|
|
||||||
|
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(resp), Charset.forName("UTF-8")));
|
||||||
|
|
||||||
|
ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo");
|
||||||
|
MethodOutcome response = client.deletePatient(new IdDt("1234"));
|
||||||
|
|
||||||
|
assertEquals(HttpDelete.class, capt.getValue().getClass());
|
||||||
|
assertEquals("http://foo/Patient/1234", capt.getValue().getURI().toString());
|
||||||
|
assertEquals("Hello", response.getOperationOutcome().getIssueFirstRep().getDetails().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteNoResponse() throws Exception {
|
||||||
|
|
||||||
|
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), 204, "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(""), Charset.forName("UTF-8")));
|
||||||
|
|
||||||
|
ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo");
|
||||||
|
client.deleteDiagnosticReport(new IdDt("1234"));
|
||||||
|
|
||||||
|
assertEquals(HttpDelete.class, capt.getValue().getClass());
|
||||||
|
assertEquals("http://foo/DiagnosticReport/1234", capt.getValue().getURI().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdate() throws Exception {
|
public void testUpdate() throws Exception {
|
||||||
|
|
|
@ -5,10 +5,12 @@ import java.util.List;
|
||||||
import ca.uhn.fhir.model.api.Bundle;
|
import ca.uhn.fhir.model.api.Bundle;
|
||||||
import ca.uhn.fhir.model.api.PathSpecification;
|
import ca.uhn.fhir.model.api.PathSpecification;
|
||||||
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||||
|
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
import ca.uhn.fhir.rest.annotation.Create;
|
import ca.uhn.fhir.rest.annotation.Create;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Delete;
|
||||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
import ca.uhn.fhir.rest.annotation.IncludeParam;
|
import ca.uhn.fhir.rest.annotation.IncludeParam;
|
||||||
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||||
|
@ -29,6 +31,12 @@ public interface ITestClient extends IBasicClient {
|
||||||
@Read(type=Patient.class)
|
@Read(type=Patient.class)
|
||||||
Patient getPatientById(@IdParam IdDt theId);
|
Patient getPatientById(@IdParam IdDt theId);
|
||||||
|
|
||||||
|
@Delete(resourceType=Patient.class)
|
||||||
|
MethodOutcome deletePatient(@IdParam IdDt theId);
|
||||||
|
|
||||||
|
@Delete(resourceType=DiagnosticReport.class)
|
||||||
|
void deleteDiagnosticReport(@IdParam IdDt theId);
|
||||||
|
|
||||||
@Read(type=Patient.class)
|
@Read(type=Patient.class)
|
||||||
Patient getPatientByVersionId(@IdParam IdDt theId, @VersionIdParam IdDt theVersionId);
|
Patient getPatientByVersionId(@IdParam IdDt theId, @VersionIdParam IdDt theVersionId);
|
||||||
|
|
||||||
|
|
|
@ -566,11 +566,26 @@ public class ResfulServerMethodTest {
|
||||||
|
|
||||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
|
||||||
OperationOutcome patient = (OperationOutcome) ourCtx.newXmlParser().parseBundle(responseContent).getEntries().get(0).getResource();
|
OperationOutcome patient = ourCtx.newXmlParser().parseResource(OperationOutcome.class, responseContent);
|
||||||
assertEquals("1234", patient.getIssueFirstRep().getDetails().getValue());
|
assertEquals("1234", patient.getIssueFirstRep().getDetails().getValue());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteNoResponse() throws Exception {
|
||||||
|
|
||||||
|
// HttpPost httpPost = new HttpPost("http://localhost:" + ourPort +
|
||||||
|
// "/Patient/1");
|
||||||
|
// httpPost.setEntity(new StringEntity("test",
|
||||||
|
// ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||||
|
|
||||||
|
HttpDelete httpGet = new HttpDelete("http://localhost:" + ourPort + "/DiagnosticReport/1234");
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
|
||||||
|
assertEquals(204, status.getStatusLine().getStatusCode());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPrettyPrint() throws Exception {
|
public void testPrettyPrint() throws Exception {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue