Refactor method outcomes abit

This commit is contained in:
jamesagnew 2014-04-28 08:39:22 -04:00
parent e69464f34d
commit 2287011601
11 changed files with 497 additions and 289 deletions

61
bormb.txt Normal file
View File

@ -0,0 +1,61 @@
@Override
public void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse) throws BaseServerResponseException, IOException {
Object[] params = new Object[getParameters().size()];
for (int i = 0; i < getParameters().size(); i++) {
IParameter param = getParameters().get(i);
if (param != null) {
params[i] = param.translateQueryParametersIntoServerArgument(theRequest, null);
}
}
addParametersForServerRequest(theRequest, params);
MethodOutcome response = (MethodOutcome) invokeServerMethod(getProvider(), params);
if (response == null) {
if (myReturnVoid == false) {
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) {
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.addHeadersToResponse(theResponse);
Writer writer = theResponse.getWriter();
try {
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 {
writer.close();
}
// getMethod().in
}

68
bormbwrp.txt Normal file
View File

@ -0,0 +1,68 @@
@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, resource);
}
addParametersForServerRequest(theRequest, params);
MethodOutcome response;
try {
response = (MethodOutcome) invokeServerMethod(getProvider(), params);
} catch (BaseServerResponseException e) {
streamOperationOutcome(e, theServer, encoding, theResponse);
return;
}
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.addHeadersToResponse(theResponse);
if (response != null && response.getOperationOutcome() != null) {
theResponse.setContentType(encoding.getResourceContentType());
Writer writer = theResponse.getWriter();
try {
parser.encodeResourceToWriter(response.getOperationOutcome(), writer);
} finally {
writer.close();
}
} else {
theResponse.setContentType(Constants.CT_TEXT);
Writer writer = theResponse.getWriter();
writer.close();
}
// getMethod().in
}

View File

@ -26,28 +26,35 @@ import ca.uhn.fhir.model.primitive.IdDt;
public class MethodOutcome { public class MethodOutcome {
private IdDt myId; private IdDt myId;
private IdDt myVersionId;
private boolean myCreated;
private OperationOutcome myOperationOutcome; private OperationOutcome myOperationOutcome;
private IdDt myVersionId;
public MethodOutcome() { public MethodOutcome() {
} }
public MethodOutcome(IdDt theId) { public MethodOutcome(IdDt theId) {
myId=theId; myId = theId;
} }
public MethodOutcome(boolean theCreated, IdDt theId, IdDt theVersionId) { public MethodOutcome(IdDt theId, IdDt theVersionId) {
super();
myId = theId; myId = theId;
myVersionId = theVersionId; myVersionId = theVersionId;
myCreated=theCreated; }
public MethodOutcome(IdDt theId, IdDt theVersionId, OperationOutcome theOperationOutcome) {
myId = theId;
myVersionId = theVersionId;
myOperationOutcome = theOperationOutcome;
} }
public IdDt getId() { public IdDt getId() {
return myId; return myId;
} }
public OperationOutcome getOperationOutcome() {
return myOperationOutcome;
}
public IdDt getVersionId() { public IdDt getVersionId() {
return myVersionId; return myVersionId;
} }
@ -56,32 +63,12 @@ public class MethodOutcome {
myId = theId; myId = theId;
} }
public void setOperationOutcome(OperationOutcome theOperationOutcome) {
myOperationOutcome = theOperationOutcome;
}
public void setVersionId(IdDt theVersionId) { public void setVersionId(IdDt theVersionId) {
myVersionId = theVersionId; 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;
}
public void setOperationOutcome(OperationOutcome theOperationOutcome) {
myOperationOutcome=theOperationOutcome;
}
public OperationOutcome getOperationOutcome() {
return myOperationOutcome;
}
} }

View File

@ -130,7 +130,8 @@ public abstract class BaseMethodBinding {
protected Object invokeServerMethod(Object theResourceProvider, Object[] theMethodParams) { protected Object invokeServerMethod(Object theResourceProvider, Object[] theMethodParams) {
try { try {
return getMethod().invoke(theResourceProvider, theMethodParams); Method method = getMethod();
return method.invoke(theResourceProvider, theMethodParams);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
if (e.getCause() instanceof BaseServerResponseException) { if (e.getCause() instanceof BaseServerResponseException) {
throw (BaseServerResponseException) e.getCause(); throw (BaseServerResponseException) e.getCause();

View File

@ -38,6 +38,7 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu.resource.OperationOutcome; import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
@ -48,6 +49,7 @@ import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingUtil; import ca.uhn.fhir.rest.server.EncodingUtil;
import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException; import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
@ -65,13 +67,11 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding {
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;
} }
} }
} }
@Override @Override
@ -138,29 +138,155 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding {
} }
protected void streamOperationOutcome(BaseServerResponseException theE, RestfulServer theServer, EncodingUtil theEncoding, HttpServletResponse theResponse) throws IOException {
theResponse.setStatus(theE.getStatusCode());
theServer.addHeadersToResponse(theResponse);
if (theE.getOperationOutcome() != null) {
theResponse.setContentType(theEncoding.getResourceContentType());
IParser parser = theEncoding.newParser(theServer.getFhirContext());
Writer writer = theResponse.getWriter();
try {
parser.encodeResourceToWriter(theE.getOperationOutcome(), writer);
} finally {
writer.close();
}
} else {
theResponse.setContentType(Constants.CT_TEXT);
Writer writer = theResponse.getWriter();
try {
writer.append(theE.getMessage());
} finally {
writer.close();
}
}
}
/*
* @Override public void invokeServer(RestfulServer theServer, Request
* theRequest, HttpServletResponse theResponse) throws
* BaseServerResponseException, IOException { Object[] params = new
* Object[getParameters().size()]; for (int i = 0; i <
* getParameters().size(); i++) { IParameter param = getParameters().get(i);
* if (param != null) { params[i] =
* param.translateQueryParametersIntoServerArgument(theRequest, null); } }
*
* addParametersForServerRequest(theRequest, params);
*
* MethodOutcome response = (MethodOutcome)
* invokeServerMethod(getProvider(), params);
*
* if (response == null) { if (myReturnVoid == false) { 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) { 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.addHeadersToResponse(theResponse);
*
* Writer writer = theResponse.getWriter(); try { 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 {
* writer.close(); } // getMethod().in }
*/
@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 = BaseMethodBinding.determineResponseEncoding(theRequest.getServletRequest(), theRequest.getParameters());
IParser parser = encoding.newParser(getContext());
IResource resource;
if (requestContainsResource()) {
resource = parser.parseResource(theRequest.getInputReader());
} else {
resource = null;
}
Object[] params = new Object[getParameters().size()]; Object[] params = new Object[getParameters().size()];
for (int i = 0; i < getParameters().size(); i++) { for (int i = 0; i < getParameters().size(); i++) {
IParameter param = getParameters().get(i); IParameter param = getParameters().get(i);
if (param != null) { if (param == null) {
params[i] = param.translateQueryParametersIntoServerArgument(theRequest, null); continue;
} }
params[i] = param.translateQueryParametersIntoServerArgument(theRequest, resource);
} }
addParametersForServerRequest(theRequest, params); addParametersForServerRequest(theRequest, params);
MethodOutcome response = (MethodOutcome) invokeServerMethod(getProvider(), params); MethodOutcome response;
try {
if (response == null) { response = (MethodOutcome) invokeServerMethod(getProvider(), params);
if (myReturnVoid == false) { } catch (InternalErrorException e) {
throw new ConfigurationException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() + " returned null"); ourLog.error("Internal error during method invocation", e);
} else { streamOperationOutcome(e, theServer, encoding, theResponse);
theResponse.setStatus(Constants.STATUS_HTTP_204_NO_CONTENT); return;
} catch (BaseServerResponseException e) {
ourLog.info("Exception during method invocation: "+e.getMessage());
streamOperationOutcome(e, theServer, encoding, theResponse);
return;
}
if (getResourceOperationType() == RestfulOperationTypeEnum.CREATE) {
if (response == null) {
throw new InternalErrorException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() + " returned null, which is not allowed for create operation");
} }
} else if (!myReturnVoid) {
if (response.isCreated()) {
theResponse.setStatus(Constants.STATUS_HTTP_201_CREATED); theResponse.setStatus(Constants.STATUS_HTTP_201_CREATED);
addLocationHeader(theRequest, theResponse, response);
} else if (response == null) {
if (isReturnVoid() == false) {
throw new InternalErrorException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() + " returned null");
}
theResponse.setStatus(Constants.STATUS_HTTP_204_NO_CONTENT);
} else {
if (response.getOperationOutcome() == null) {
theResponse.setStatus(Constants.STATUS_HTTP_204_NO_CONTENT);
} else {
theResponse.setStatus(Constants.STATUS_HTTP_200_OK);
}
if (getResourceOperationType() == RestfulOperationTypeEnum.UPDATE) {
addLocationHeader(theRequest, theResponse, response);
}
}
theServer.addHeadersToResponse(theResponse);
if (response != null && response.getOperationOutcome() != null) {
theResponse.setContentType(encoding.getResourceContentType());
Writer writer = theResponse.getWriter();
try {
parser.encodeResourceToWriter(response.getOperationOutcome(), writer);
} finally {
writer.close();
}
} else {
theResponse.setContentType(Constants.CT_TEXT);
Writer writer = theResponse.getWriter();
writer.close();
}
// getMethod().in
}
private void addLocationHeader(Request theRequest, HttpServletResponse theResponse, MethodOutcome response) {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
b.append(theRequest.getFhirServerBase()); b.append(theRequest.getFhirServerBase());
b.append('/'); b.append('/');
@ -172,31 +298,14 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding {
b.append(response.getVersionId().getValue()); b.append(response.getVersionId().getValue());
} }
theResponse.addHeader("Location", b.toString()); theResponse.addHeader("Location", b.toString());
} else {
theResponse.setStatus(Constants.STATUS_HTTP_200_OK);
}
} else {
theResponse.setStatus(Constants.STATUS_HTTP_204_NO_CONTENT);
} }
theServer.addHeadersToResponse(theResponse); /**
* Subclasses may override if the incoming request should not contain a
Writer writer = theResponse.getWriter(); * resource
try { */
if (response != null) { protected boolean requestContainsResource() {
OperationOutcome outcome = new OperationOutcome(); return true;
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 {
writer.close();
}
// getMethod().in
} }
protected abstract void addParametersForServerRequest(Request theRequest, Object[] theParams); protected abstract void addParametersForServerRequest(Request theRequest, Object[] theParams);
@ -225,14 +334,15 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding {
} }
/** /**
* For servers, this method will match only incoming requests * For servers, this method will match only incoming requests that match the
* that match the given operation, or which have no operation in the * given operation, or which have no operation in the URL if this method
* URL if this method returns null. * returns null.
*/ */
protected abstract String getMatchingOperation(); protected abstract String getMatchingOperation();
/** /**
* Subclasses may override to allow a void method return type, which is allowable for some methods (e.g. delete) * Subclasses may override to allow a void method return type, which is
* allowable for some methods (e.g. delete)
*/ */
protected boolean allowVoidReturnType() { protected boolean allowVoidReturnType() {
return false; return false;

View File

@ -75,100 +75,9 @@ abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOu
// nothing // 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, resource);
}
addParametersForServerRequest(theRequest, params);
MethodOutcome response;
try {
response = (MethodOutcome) invokeServerMethod(getProvider(), params);
} catch (BaseServerResponseException e) {
streamOperationOutcome(e, theServer, encoding, theResponse);
return;
}
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.addHeadersToResponse(theResponse);
if (response != null && response.getOperationOutcome() != null) {
theResponse.setContentType(encoding.getResourceContentType());
Writer writer = theResponse.getWriter();
try {
parser.encodeResourceToWriter(response.getOperationOutcome(), writer);
} finally {
writer.close();
}
} else {
theResponse.setContentType(Constants.CT_TEXT);
Writer writer = theResponse.getWriter();
writer.close();
}
// getMethod().in
}
private void streamOperationOutcome(BaseServerResponseException theE, RestfulServer theServer, EncodingUtil theEncoding, HttpServletResponse theResponse) throws IOException {
theResponse.setStatus(theE.getStatusCode());
theServer.addHeadersToResponse(theResponse);
if (theE.getOperationOutcome() != null) {
theResponse.setContentType(theEncoding.getResourceContentType());
IParser parser = theEncoding.newParser(theServer.getFhirContext());
Writer writer = theResponse.getWriter();
try {
parser.encodeResourceToWriter(theE.getOperationOutcome(), writer);
} finally {
writer.close();
}
} else {
theResponse.setContentType(Constants.CT_TEXT);
Writer writer = theResponse.getWriter();
try {
writer.append(theE.getMessage());
} finally {
writer.close();
}
}
}
@Override @Override
public String getResourceName() { public String getResourceName() {

View File

@ -35,8 +35,6 @@ import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
public class CreateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceParam { public class CreateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceParam {
public CreateMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) { public CreateMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) {
super(theMethod, theContext, Create.class, theProvider); super(theMethod, theContext, Create.class, theProvider);
} }

View File

@ -79,6 +79,11 @@ public class DeleteMethodBinding extends BaseOutcomeReturningMethodBinding {
} }
@Override
protected boolean requestContainsResource() {
return false;
}
@Override @Override
protected boolean allowVoidReturnType() { protected boolean allowVoidReturnType() {
return true; return true;

View File

@ -298,7 +298,6 @@ public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
// This method returns a MethodOutcome object which contains // This method returns a MethodOutcome object which contains
// the ID and Version ID for the newly saved resource // the ID and Version ID for the newly saved resource
MethodOutcome retVal = new MethodOutcome(); MethodOutcome retVal = new MethodOutcome();
retVal.setCreated(true);
retVal.setId(new IdDt("3746")); retVal.setId(new IdDt("3746"));
retVal.setVersionId(new IdDt("1")); retVal.setVersionId(new IdDt("1"));
@ -341,7 +340,6 @@ public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient t
// This method returns a MethodOutcome object which contains // This method returns a MethodOutcome object which contains
// the ID and Version ID for the newly saved resource // the ID and Version ID for the newly saved resource
MethodOutcome retVal = new MethodOutcome(); MethodOutcome retVal = new MethodOutcome();
retVal.setCreated(true);
retVal.setId(theId); retVal.setId(theId);
retVal.setVersionId(new IdDt("2")); // Leave this blank if the server doesn't version retVal.setVersionId(new IdDt("2")); // Leave this blank if the server doesn't version

View File

@ -125,7 +125,6 @@ public class ResfulServerMethodTest {
} }
@Test @Test
public void testCreateWithUnprocessableEntity() throws Exception { public void testCreateWithUnprocessableEntity() throws Exception {
@ -244,7 +243,8 @@ public class ResfulServerMethodTest {
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Patient patient = (Patient) ourCtx.newJsonParser().parseResource(responseContent); Patient patient = (Patient) ourCtx.newJsonParser().parseResource(responseContent);
// assertEquals("PatientOne", patient.getName().get(0).getGiven().get(0).getValue()); // assertEquals("PatientOne",
// patient.getName().get(0).getGiven().get(0).getValue());
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient));
@ -371,10 +371,12 @@ public class ResfulServerMethodTest {
// @Test // @Test
// public void testSearchByComplex() throws Exception { // public void testSearchByComplex() throws Exception {
// //
// HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?Patient.identifier=urn:oid:2.16.840.1.113883.3.239.18.148%7C7000135&name=urn:oid:1.3.6.1.4.1.12201.102.5%7C522&date="); // HttpGet httpGet = new HttpGet("http://localhost:" + ourPort +
// "/Patient?Patient.identifier=urn:oid:2.16.840.1.113883.3.239.18.148%7C7000135&name=urn:oid:1.3.6.1.4.1.12201.102.5%7C522&date=");
// HttpResponse status = ourClient.execute(httpGet); // HttpResponse status = ourClient.execute(httpGet);
// //
// String responseContent = IOUtils.toString(status.getEntity().getContent()); // String responseContent =
// IOUtils.toString(status.getEntity().getContent());
// ourLog.info("Response was:\n{}", responseContent); // ourLog.info("Response was:\n{}", responseContent);
// //
// assertEquals(200, status.getStatusLine().getStatusCode()); // assertEquals(200, status.getStatusLine().getStatusCode());
@ -586,7 +588,6 @@ public class ResfulServerMethodTest {
} }
@Test @Test
public void testSearchByDobWithSearchActionAndPost() throws Exception { public void testSearchByDobWithSearchActionAndPost() throws Exception {
@ -642,7 +643,6 @@ public class ResfulServerMethodTest {
assertEquals("NONE", patient.getIdentifier().get(1).getValue().getValue()); assertEquals("NONE", patient.getIdentifier().get(1).getValue().getValue());
assertEquals("2011-01-02", patient.getIdentifier().get(2).getValue().getValue()); assertEquals("2011-01-02", patient.getIdentifier().get(2).getValue().getValue());
} }
@Test @Test
@ -851,11 +851,87 @@ public class ResfulServerMethodTest {
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent); ourLog.info("Response was:\n{}", responseContent);
assertEquals(201, status.getStatusLine().getStatusCode()); OperationOutcome oo =new FhirContext().newXmlParser().parseResource(OperationOutcome.class, responseContent);
assertEquals("OODETAILS", oo.getIssueFirstRep().getDetails().getValue());
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("Location").getValue()); assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("Location").getValue());
} }
@Test
public void testUpdateWrongResourceType() throws Exception {
// TODO: this method sends in the wrong resource type vs. the URL so it should
// give a useful error message
Patient patient = new Patient();
patient.addIdentifier().setValue("002");
HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
HttpResponse status = ourClient.execute(httpPost);
assertEquals(201, status.getStatusLine().getStatusCode());
assertEquals("http://localhost:" + ourPort + "/DiagnosticReport/001/_history/002", status.getFirstHeader("Location").getValue());
}
@Test
public void testUpdateNoResponse() throws Exception {
DiagnosticReport dr = new DiagnosticReport();
dr.addCodedDiagnosis().addCoding().setCode("AAA");
HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
HttpResponse status = ourClient.execute(httpPost);
assertEquals(204, status.getStatusLine().getStatusCode());
assertEquals("http://localhost:" + ourPort + "/DiagnosticReport/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 @Test
public void testValidate() throws Exception { public void testValidate() throws Exception {
@ -909,43 +985,6 @@ public class ResfulServerMethodTest {
} }
@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());
}
@AfterClass @AfterClass
public static void afterClass() throws Exception { public static void afterClass() throws Exception {
ourServer.stop(); ourServer.stop();
@ -985,6 +1024,14 @@ public class ResfulServerMethodTest {
throw new ResourceNotFoundException("AAAABBBB"); throw new ResourceNotFoundException("AAAABBBB");
} }
@SuppressWarnings("unused")
@Create()
public MethodOutcome createDiagnosticReport(@ResourceParam DiagnosticReport thePatient) {
OperationOutcome outcome = new OperationOutcome();
outcome.addIssue().setDetails("FOOBAR");
throw new UnprocessableEntityException(outcome);
}
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Delete() @Delete()
public void deleteDiagnosticReport(@IdParam IdDt theId) { public void deleteDiagnosticReport(@IdParam IdDt theId) {
@ -998,21 +1045,12 @@ public class ResfulServerMethodTest {
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Update() @Update()
public MethodOutcome updateDiagnosticReportWithVersion(@IdParam IdDt theId, @VersionIdParam IdDt theVersionId, @ResourceParam DiagnosticReport thePatient) { public MethodOutcome updateDiagnosticReportWithVersionAndNoResponse(@IdParam IdDt theId, @ResourceParam DiagnosticReport thePatient) {
IdDt id = theId; IdDt id = theId;
IdDt version = theVersionId; IdDt version = new IdDt("002");
return new MethodOutcome(true, id, version); return new MethodOutcome(id, version);
} }
@SuppressWarnings("unused")
@Create()
public MethodOutcome createDiagnosticReport(@ResourceParam DiagnosticReport thePatient) {
OperationOutcome outcome = new OperationOutcome();
outcome.addIssue().setDetails("FOOBAR");
throw new UnprocessableEntityException(outcome);
}
} }
/** /**
@ -1024,37 +1062,7 @@ public class ResfulServerMethodTest {
public MethodOutcome createPatient(@ResourceParam Patient thePatient) { public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
IdDt id = new IdDt(thePatient.getIdentifier().get(0).getValue().getValue()); IdDt id = new IdDt(thePatient.getIdentifier().get(0).getValue().getValue());
IdDt version = new IdDt(thePatient.getIdentifier().get(1).getValue().getValue()); IdDt version = new IdDt(thePatient.getIdentifier().get(1).getValue().getValue());
return new MethodOutcome(true, id, version); return new MethodOutcome(id, version);
}
@Validate()
public MethodOutcome validatePatient(@ResourceParam Patient thePatient) {
if (thePatient.getNameFirstRep().getFamilyFirstRep().getValueNotNull().equals("FOO")) {
MethodOutcome methodOutcome = new MethodOutcome();
OperationOutcome oo = new OperationOutcome();
oo.addIssue().setDetails("it passed");
methodOutcome.setOperationOutcome(oo);
return methodOutcome;
}
if (thePatient.getNameFirstRep().getFamilyFirstRep().getValueNotNull().equals("BAR")) {
throw new UnprocessableEntityException("it failed");
}
return new MethodOutcome();
}
private Patient createPatient1() {
Patient patient = new Patient();
patient.addIdentifier();
patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
patient.getIdentifier().get(0).setValue("00001");
patient.addName();
patient.getName().get(0).addFamily("Test");
patient.getName().get(0).addGiven("PatientOne");
patient.getGender().setText("M");
patient.getId().setValue("1");
return patient;
} }
@Delete() @Delete()
@ -1066,8 +1074,8 @@ public class ResfulServerMethodTest {
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
public List<Patient> findDiagnosticReportsByPatient(@RequiredParam(name = "Patient.identifier") IdentifierDt thePatientId, public List<Patient> findDiagnosticReportsByPatient(@RequiredParam(name = "Patient.identifier") IdentifierDt thePatientId, @RequiredParam(name = DiagnosticReport.SP_NAME) CodingListParam theNames, @OptionalParam(name = DiagnosticReport.SP_DATE) DateRangeParam theDateRange)
@RequiredParam(name = DiagnosticReport.SP_NAME) CodingListParam theNames, @OptionalParam(name = DiagnosticReport.SP_DATE) DateRangeParam theDateRange) throws Exception { throws Exception {
return Collections.emptyList(); return Collections.emptyList();
} }
@ -1201,8 +1209,7 @@ public class ResfulServerMethodTest {
} }
@Search() @Search()
public Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringDt theString, public Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringDt theString, @IncludeParam(allow = { "include1", "include2", "include3" }) List<PathSpecification> theIncludes) {
@IncludeParam(allow = { "include1", "include2", "include3" }) List<PathSpecification> theIncludes) {
Patient next = getIdToPatient().get("1"); Patient next = getIdToPatient().get("1");
next.addCommunication().setText(theString.getValue()); next.addCommunication().setText(theString.getValue());
@ -1276,19 +1283,52 @@ public class ResfulServerMethodTest {
@Update() @Update()
public MethodOutcome updateDiagnosticReportWithVersion(@IdParam IdDt theId, @VersionIdParam IdDt theVersionId, @ResourceParam DiagnosticReport thePatient) { 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 * 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 * update/create/etc method
*/ */
IdDt id = theId; IdDt id = theId;
IdDt version = theVersionId; IdDt version = theVersionId;
return new MethodOutcome(true, id, version); return new MethodOutcome(id, version);
} }
@Update() @Update()
public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient thePatient) { public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient thePatient) {
IdDt id = theId; IdDt id = theId;
IdDt version = new IdDt(thePatient.getIdentifierFirstRep().getValue().getValue()); IdDt version = new IdDt(thePatient.getIdentifierFirstRep().getValue().getValue());
return new MethodOutcome(true, id, version); OperationOutcome oo = new OperationOutcome();
oo.addIssue().setDetails("OODETAILS");
return new MethodOutcome(id, version, oo);
}
@Validate()
public MethodOutcome validatePatient(@ResourceParam Patient thePatient) {
if (thePatient.getNameFirstRep().getFamilyFirstRep().getValueNotNull().equals("FOO")) {
MethodOutcome methodOutcome = new MethodOutcome();
OperationOutcome oo = new OperationOutcome();
oo.addIssue().setDetails("it passed");
methodOutcome.setOperationOutcome(oo);
return methodOutcome;
}
if (thePatient.getNameFirstRep().getFamilyFirstRep().getValueNotNull().equals("BAR")) {
throw new UnprocessableEntityException("it failed");
}
return new MethodOutcome();
}
private Patient createPatient1() {
Patient patient = new Patient();
patient.addIdentifier();
patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
patient.getIdentifier().get(0).setValue("00001");
patient.addName();
patient.getName().get(0).addFamily("Test");
patient.getName().get(0).addGiven("PatientOne");
patient.getGender().setText("M");
patient.getId().setValue("1");
return patient;
} }
} }

View File

@ -62,7 +62,7 @@ public class RestfulPatientResourceProvider implements IResourceProvider {
* @return Returns a resource matching this identifier, or null if none exists. * @return Returns a resource matching this identifier, or null if none exists.
*/ */
@Read() @Read()
public Patient getResourceById(@IdParam IdDt theId) { public Patient getPatientById(@IdParam IdDt theId) {
Patient retVal; Patient retVal;
try { try {
retVal = myIdToPatientMap.get(theId.asLong()); retVal = myIdToPatientMap.get(theId.asLong());
@ -80,17 +80,17 @@ public class RestfulPatientResourceProvider implements IResourceProvider {
* The "@Search" annotation indicates that this method supports the search operation. You may have many different method annotated with this annotation, to support many different search criteria. * The "@Search" annotation indicates that this method supports the search operation. You may have many different method annotated with this annotation, to support many different search criteria.
* This example searches by family name. * This example searches by family name.
* *
* @param theIdentifier * @param theFamilyName
* This operation takes one parameter which is the search criteria. It is annotated with the "@Required" annotation. This annotation takes one argument, a string containing the name of * This operation takes one parameter which is the search criteria. It is annotated with the "@Required" annotation. This annotation takes one argument, a string containing the name of
* the search criteria. The datatype here is StringDt, but there are other possible parameter types depending on the specific search criteria. * the search criteria. The datatype here is StringDt, but there are other possible parameter types depending on the specific search criteria.
* @return This method returns a list of Patients. This list may contain multiple matching resources, or it may also be empty. * @return This method returns a list of Patients. This list may contain multiple matching resources, or it may also be empty.
*/ */
@Search() @Search()
public List<Patient> getPatient(@RequiredParam(name = Patient.SP_FAMILY) StringDt theFamilyName) { public List<Patient> findPatientsByName(@RequiredParam(name = Patient.SP_FAMILY) StringDt theFamilyName) {
ArrayList<Patient> retVal = new ArrayList<Patient>(); ArrayList<Patient> retVal = new ArrayList<Patient>();
/* /*
* Look for all patients matching this * Look for all patients matching the name
*/ */
for (Patient nextPatient : myIdToPatientMap.values()) { for (Patient nextPatient : myIdToPatientMap.values()) {
NAMELOOP: NAMELOOP:
@ -109,16 +109,13 @@ public class RestfulPatientResourceProvider implements IResourceProvider {
/** /**
* The "@Search" annotation indicates that this method supports the search operation. You may have many different method annotated with this annotation, to support many different search criteria. * The "@Create" annotation indicates that this method supports creating a new resource
* This example searches by family name.
* *
* @param theIdentifier * @param thePatient This is the actual resource to save
* This operation takes one parameter which is the search criteria. It is annotated with the "@Required" annotation. This annotation takes one argument, a string containing the name of * @return This method returns a "MethodOutcome"
* the search criteria. The datatype here is StringDt, but there are other possible parameter types depending on the specific search criteria.
* @return This method returns a list of Patients. This list may contain multiple matching resources, or it may also be empty.
*/ */
@Create() @Create()
public MethodOutcome getPatient(@ResourceParam Patient thePatient) { public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
/* /*
* Our server will have a rule that patients must * Our server will have a rule that patients must
* have a family name or we will reject them * have a family name or we will reject them
@ -128,6 +125,40 @@ public class RestfulPatientResourceProvider implements IResourceProvider {
outcome.addIssue().setSeverity(IssueSeverityEnum.FATAL).setDetails("No last name provided"); outcome.addIssue().setSeverity(IssueSeverityEnum.FATAL).setDetails("No last name provided");
throw new UnprocessableEntityException(outcome); throw new UnprocessableEntityException(outcome);
} }
long id = myNextId++;
myIdToPatientMap.put(id, thePatient);
// Let the caller know the ID of the newly created resource
return new MethodOutcome(new IdDt(id));
}
/**
* The "@Search" annotation indicates that this method supports the search operation. You may have many different method annotated with this annotation, to support many different search criteria.
* This example searches by family name.
*
* @param theIdentifier
* This operation takes one parameter which is the search criteria. It is annotated with the "@Required" annotation. This annotation takes one argument, a string containing the name of
* the search criteria. The datatype here is StringDt, but there are other possible parameter types depending on the specific search criteria.
* @return This method returns a list of Patients. This list may contain multiple matching resources, or it may also be empty.
*/
@Create()
public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
/*
* Our server will have a rule that patients must
* have a family name or we will reject them
*/
if (thePatient.getNameFirstRep().getFamilyFirstRep().isEmpty()) {
OperationOutcome outcome = new OperationOutcome();
outcome.addIssue().setSeverity(IssueSeverityEnum.FATAL).setDetails("No last name provided");
throw new UnprocessableEntityException(outcome);
}
long id = myNextId++;
myIdToPatientMap.put(id, thePatient);
// Let the caller know the ID of the newly created resource
return new MethodOutcome(new IdDt(id));
} }
} }