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 {
private IdDt myId;
private IdDt myVersionId;
private boolean myCreated;
private OperationOutcome myOperationOutcome;
private IdDt myVersionId;
public MethodOutcome() {
}
public MethodOutcome(IdDt theId) {
myId=theId;
myId = theId;
}
public MethodOutcome(boolean theCreated, IdDt theId, IdDt theVersionId) {
super();
public MethodOutcome(IdDt theId, IdDt theVersionId) {
myId = theId;
myVersionId = theVersionId;
myCreated=theCreated;
}
public MethodOutcome(IdDt theId, IdDt theVersionId, OperationOutcome theOperationOutcome) {
myId = theId;
myVersionId = theVersionId;
myOperationOutcome = theOperationOutcome;
}
public IdDt getId() {
return myId;
}
public OperationOutcome getOperationOutcome() {
return myOperationOutcome;
}
public IdDt getVersionId() {
return myVersionId;
}
@ -56,32 +63,12 @@ public class MethodOutcome {
myId = theId;
}
public void setOperationOutcome(OperationOutcome theOperationOutcome) {
myOperationOutcome = theOperationOutcome;
}
public void setVersionId(IdDt 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) {
try {
return getMethod().invoke(theResourceProvider, theMethodParams);
Method method = getMethod();
return method.invoke(theResourceProvider, theMethodParams);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof BaseServerResponseException) {
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.model.api.IResource;
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.parser.IParser;
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.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;
@ -65,13 +67,11 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding {
if (!theMethod.getReturnType().equals(MethodOutcome.class)) {
if (!allowVoidReturnType()) {
throw new ConfigurationException("Method " + theMethod.getName() + " in type " + theMethod.getDeclaringClass().getCanonicalName() + " is a @" + theMethodAnnotation.getSimpleName()
+ " method but it does not return " + 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);
} else if (theMethod.getReturnType() == void.class) {
myReturnVoid = true;
}
}
}
@Override
@ -138,67 +138,176 @@ 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
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()];
for (int i = 0; i < getParameters().size(); i++) {
IParameter param = getParameters().get(i);
if (param != null) {
params[i] = param.translateQueryParametersIntoServerArgument(theRequest, null);
if (param == null) {
continue;
}
params[i] = param.translateQueryParametersIntoServerArgument(theRequest, resource);
}
addParametersForServerRequest(theRequest, params);
MethodOutcome response = (MethodOutcome) invokeServerMethod(getProvider(), params);
MethodOutcome response;
try {
response = (MethodOutcome) invokeServerMethod(getProvider(), params);
} catch (InternalErrorException e) {
ourLog.error("Internal error during method invocation", e);
streamOperationOutcome(e, theServer, encoding, theResponse);
return;
} catch (BaseServerResponseException e) {
ourLog.info("Exception during method invocation: "+e.getMessage());
streamOperationOutcome(e, theServer, encoding, theResponse);
return;
}
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);
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);
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());
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);
}
} else {
theResponse.setStatus(Constants.STATUS_HTTP_204_NO_CONTENT);
if (getResourceOperationType() == RestfulOperationTypeEnum.UPDATE) {
addLocationHeader(theRequest, theResponse, response);
}
}
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);
if (response != null && response.getOperationOutcome() != null) {
theResponse.setContentType(encoding.getResourceContentType());
Writer writer = theResponse.getWriter();
try {
parser.encodeResourceToWriter(response.getOperationOutcome(), writer);
} finally {
writer.close();
}
} finally {
} 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();
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());
}
/**
* Subclasses may override if the incoming request should not contain a
* resource
*/
protected boolean requestContainsResource() {
return true;
}
protected abstract void addParametersForServerRequest(Request theRequest, Object[] theParams);
public boolean isReturnVoid() {
@ -225,14 +334,15 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding {
}
/**
* For servers, this method will match only incoming requests
* that match the given operation, or which have no operation in the
* URL if this method returns null.
* For servers, this method will match only incoming requests that match the
* given operation, or which have no operation in the URL if this method
* returns null.
*/
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() {
return false;

View File

@ -75,100 +75,9 @@ abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOu
// 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
public String getResourceName() {

View File

@ -35,8 +35,6 @@ import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
public class CreateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceParam {
public CreateMethodBinding(Method theMethod, FhirContext theContext, Object 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
protected boolean allowVoidReturnType() {
return true;

View File

@ -298,7 +298,6 @@ 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"));
@ -341,7 +340,6 @@ public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient t
// 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(theId);
retVal.setVersionId(new IdDt("2")); // Leave this blank if the server doesn't version

View File

@ -124,8 +124,7 @@ public class ResfulServerMethodTest {
assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("Location").getValue());
}
@Test
public void testCreateWithUnprocessableEntity() throws Exception {
@ -141,7 +140,7 @@ public class ResfulServerMethodTest {
ourLog.info("Response was:\n{}", responseContent);
assertEquals(422, status.getStatusLine().getStatusCode());
OperationOutcome outcome = new FhirContext().newXmlParser().parseResource(OperationOutcome.class, new StringReader(responseContent));
assertEquals("FOOBAR", outcome.getIssueFirstRep().getDetails().getValue());
@ -244,7 +243,8 @@ public class ResfulServerMethodTest {
assertEquals(200, status.getStatusLine().getStatusCode());
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));
@ -371,10 +371,12 @@ public class ResfulServerMethodTest {
// @Test
// 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);
//
// String responseContent = IOUtils.toString(status.getEntity().getContent());
// String responseContent =
// IOUtils.toString(status.getEntity().getContent());
// ourLog.info("Response was:\n{}", responseContent);
//
// assertEquals(200, status.getStatusLine().getStatusCode());
@ -586,7 +588,6 @@ public class ResfulServerMethodTest {
}
@Test
public void testSearchByDobWithSearchActionAndPost() throws Exception {
@ -605,8 +606,8 @@ public class ResfulServerMethodTest {
assertEquals("NONE", patient.getIdentifier().get(1).getValue().getValue());
assertEquals("2011-01-02", patient.getIdentifier().get(2).getValue().getValue());
// POST
// POST
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_search?dob=2011-01-02");
status = ourClient.execute(httpPost);
@ -622,8 +623,8 @@ public class ResfulServerMethodTest {
assertEquals("NONE", patient.getIdentifier().get(1).getValue().getValue());
assertEquals("2011-01-02", patient.getIdentifier().get(2).getValue().getValue());
// POST with form encoded
// POST with form encoded
httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_search");
List<BasicNameValuePair> urlParameters = new ArrayList<BasicNameValuePair>();
urlParameters.add(new BasicNameValuePair("dob", "2011-01-02"));
@ -642,9 +643,8 @@ public class ResfulServerMethodTest {
assertEquals("NONE", patient.getIdentifier().get(1).getValue().getValue());
assertEquals("2011-01-02", patient.getIdentifier().get(2).getValue().getValue());
}
@Test
public void testSearchByMultipleIdentifiers() throws Exception {
@ -851,64 +851,50 @@ public class ResfulServerMethodTest {
String responseContent = IOUtils.toString(status.getEntity().getContent());
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());
}
@Test
public void testValidate() throws Exception {
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.addName().addFamily("FOO");
patient.addIdentifier().setValue("002");
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_validate");
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);
String responseContent = IOUtils.toString(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
OperationOutcome oo = new FhirContext().newXmlParser().parseResource(OperationOutcome.class, responseContent);
assertEquals("it passed", oo.getIssueFirstRep().getDetails().getValue());
// Now should fail
patient = new Patient();
patient.addName().addFamily("BAR");
httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_validate");
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
status = ourClient.execute(httpPost);
responseContent = IOUtils.toString(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(422, status.getStatusLine().getStatusCode());
oo = new FhirContext().newXmlParser().parseResource(OperationOutcome.class, responseContent);
assertEquals("it failed", oo.getIssueFirstRep().getDetails().getValue());
// Should fail with outcome
patient = new Patient();
patient.addName().addFamily("BAZ");
httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_validate");
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
status = ourClient.execute(httpPost);
responseContent = IOUtils.toString(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("", responseContent);
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 {
@ -946,6 +932,59 @@ public class ResfulServerMethodTest {
assertEquals(400, results.getStatusLine().getStatusCode());
}
@Test
public void testValidate() throws Exception {
Patient patient = new Patient();
patient.addName().addFamily("FOO");
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_validate");
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(200, status.getStatusLine().getStatusCode());
OperationOutcome oo = new FhirContext().newXmlParser().parseResource(OperationOutcome.class, responseContent);
assertEquals("it passed", oo.getIssueFirstRep().getDetails().getValue());
// Now should fail
patient = new Patient();
patient.addName().addFamily("BAR");
httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_validate");
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
status = ourClient.execute(httpPost);
responseContent = IOUtils.toString(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(422, status.getStatusLine().getStatusCode());
oo = new FhirContext().newXmlParser().parseResource(OperationOutcome.class, responseContent);
assertEquals("it failed", oo.getIssueFirstRep().getDetails().getValue());
// Should fail with outcome
patient = new Patient();
patient.addName().addFamily("BAZ");
httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_validate");
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
status = ourClient.execute(httpPost);
responseContent = IOUtils.toString(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("", responseContent);
}
@AfterClass
public static void afterClass() throws Exception {
ourServer.stop();
@ -985,6 +1024,14 @@ public class ResfulServerMethodTest {
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")
@Delete()
public void deleteDiagnosticReport(@IdParam IdDt theId) {
@ -998,21 +1045,12 @@ public class ResfulServerMethodTest {
@SuppressWarnings("unused")
@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 version = theVersionId;
return new MethodOutcome(true, id, version);
IdDt version = new IdDt("002");
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) {
IdDt id = new IdDt(thePatient.getIdentifier().get(0).getValue().getValue());
IdDt version = new IdDt(thePatient.getIdentifier().get(1).getValue().getValue());
return new MethodOutcome(true, 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;
return new MethodOutcome(id, version);
}
@Delete()
@ -1066,8 +1074,8 @@ public class ResfulServerMethodTest {
}
@SuppressWarnings("unused")
public List<Patient> findDiagnosticReportsByPatient(@RequiredParam(name = "Patient.identifier") IdentifierDt thePatientId,
@RequiredParam(name = DiagnosticReport.SP_NAME) CodingListParam theNames, @OptionalParam(name = DiagnosticReport.SP_DATE) DateRangeParam theDateRange) throws Exception {
public List<Patient> findDiagnosticReportsByPatient(@RequiredParam(name = "Patient.identifier") IdentifierDt thePatientId, @RequiredParam(name = DiagnosticReport.SP_NAME) CodingListParam theNames, @OptionalParam(name = DiagnosticReport.SP_DATE) DateRangeParam theDateRange)
throws Exception {
return Collections.emptyList();
}
@ -1201,8 +1209,7 @@ public class ResfulServerMethodTest {
}
@Search()
public Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringDt theString,
@IncludeParam(allow = { "include1", "include2", "include3" }) List<PathSpecification> theIncludes) {
public Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringDt theString, @IncludeParam(allow = { "include1", "include2", "include3" }) List<PathSpecification> theIncludes) {
Patient next = getIdToPatient().get("1");
next.addCommunication().setText(theString.getValue());
@ -1276,19 +1283,52 @@ public class ResfulServerMethodTest {
@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
* 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);
return new MethodOutcome(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);
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.
*/
@Read()
public Patient getResourceById(@IdParam IdDt theId) {
public Patient getPatientById(@IdParam IdDt theId) {
Patient retVal;
try {
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.
* 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
* 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.
*/
@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>();
/*
* Look for all patients matching this
* Look for all patients matching the name
*/
for (Patient nextPatient : myIdToPatientMap.values()) {
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.
* This example searches by family name.
* The "@Create" annotation indicates that this method supports creating a new resource
*
* @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.
* @param thePatient This is the actual resource to save
* @return This method returns a "MethodOutcome"
*/
@Create()
public MethodOutcome getPatient(@ResourceParam Patient thePatient) {
public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
/*
* Our server will have a rule that patients must
* 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");
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));
}
}