Return a content-location header on update
This commit is contained in:
parent
4622af7a82
commit
dcccf5553e
|
@ -63,6 +63,11 @@
|
||||||
HAPI now logs a single line indicating the StAX implementation being used upon the
|
HAPI now logs a single line indicating the StAX implementation being used upon the
|
||||||
first time an XML parser is created.
|
first time an XML parser is created.
|
||||||
</action>
|
</action>
|
||||||
|
<action type="fix">
|
||||||
|
Update methods on the server did not return a "content-location" header, but
|
||||||
|
only a "location" header. Both are required according to the FHIR specification.
|
||||||
|
Thanks to Bill de Beaubien of Systems Made Simple for reporting this!
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="0.6" date="2014-Sep-08" description="This release brings a number of new features and bug fixes!">
|
<release version="0.6" date="2014-Sep-08" description="This release brings a number of new features and bug fixes!">
|
||||||
<!--
|
<!--
|
||||||
|
|
|
@ -61,8 +61,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
@ -89,8 +88,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException,
|
public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
||||||
BaseServerResponseException {
|
|
||||||
switch (theResponseStatusCode) {
|
switch (theResponseStatusCode) {
|
||||||
case Constants.STATUS_HTTP_200_OK:
|
case Constants.STATUS_HTTP_200_OK:
|
||||||
case Constants.STATUS_HTTP_201_CREATED:
|
case Constants.STATUS_HTTP_201_CREATED:
|
||||||
|
@ -147,8 +145,8 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
||||||
throw new InternalErrorException("Server method returned invalid resource ID: " + response.getId().getValue());
|
throw new InternalErrorException("Server method returned invalid resource ID: " + response.getId().getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OperationOutcome outcome = response != null ? response.getOperationOutcome():null;
|
OperationOutcome outcome = response != null ? response.getOperationOutcome() : null;
|
||||||
for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
|
for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
|
||||||
IServerInterceptor next = theServer.getInterceptors().get(i);
|
IServerInterceptor next = theServer.getInterceptors().get(i);
|
||||||
boolean continueProcessing = next.outgoingResponse(theRequest, outcome, theRequest.getServletRequest(), theRequest.getServletResponse());
|
boolean continueProcessing = next.outgoingResponse(theRequest, outcome, theRequest.getServletRequest(), theRequest.getServletResponse());
|
||||||
|
@ -156,19 +154,18 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (getResourceOperationType()) {
|
switch (getResourceOperationType()) {
|
||||||
case CREATE:
|
case CREATE:
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
throw new InternalErrorException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName()
|
throw new InternalErrorException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() + " returned null, which is not allowed for create operation");
|
||||||
+ " returned null, which is not allowed for create operation");
|
|
||||||
}
|
}
|
||||||
if (response.getCreated() == null || Boolean.TRUE.equals(response.getCreated())) {
|
if (response.getCreated() == null || Boolean.TRUE.equals(response.getCreated())) {
|
||||||
servletResponse.setStatus(Constants.STATUS_HTTP_201_CREATED);
|
servletResponse.setStatus(Constants.STATUS_HTTP_201_CREATED);
|
||||||
} else {
|
} else {
|
||||||
servletResponse.setStatus(Constants.STATUS_HTTP_200_OK);
|
servletResponse.setStatus(Constants.STATUS_HTTP_200_OK);
|
||||||
}
|
}
|
||||||
addLocationHeader(theRequest, servletResponse, response);
|
addLocationHeader(theRequest, servletResponse, response, Constants.HEADER_LOCATION);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UPDATE:
|
case UPDATE:
|
||||||
|
@ -178,7 +175,8 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
||||||
servletResponse.setStatus(Constants.STATUS_HTTP_201_CREATED);
|
servletResponse.setStatus(Constants.STATUS_HTTP_201_CREATED);
|
||||||
}
|
}
|
||||||
if (response != null && response.getId() != null) {
|
if (response != null && response.getId() != null) {
|
||||||
addLocationHeader(theRequest, servletResponse, response);
|
addLocationHeader(theRequest, servletResponse, response, Constants.HEADER_LOCATION);
|
||||||
|
addLocationHeader(theRequest, servletResponse, response, Constants.HEADER_CONTENT_LOCATION);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -226,7 +224,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
||||||
return myReturnVoid;
|
return myReturnVoid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addLocationHeader(Request theRequest, HttpServletResponse theResponse, MethodOutcome response) {
|
private void addLocationHeader(Request theRequest, HttpServletResponse theResponse, MethodOutcome response, String headerLocation) {
|
||||||
StringBuilder b = new StringBuilder();
|
StringBuilder b = new StringBuilder();
|
||||||
b.append(theRequest.getFhirServerBase());
|
b.append(theRequest.getFhirServerBase());
|
||||||
b.append('/');
|
b.append('/');
|
||||||
|
@ -240,31 +238,38 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
||||||
b.append("/" + Constants.PARAM_HISTORY + "/");
|
b.append("/" + Constants.PARAM_HISTORY + "/");
|
||||||
b.append(response.getVersionId().getValue());
|
b.append(response.getVersionId().getValue());
|
||||||
}
|
}
|
||||||
theResponse.addHeader(Constants.HEADER_LOCATION, b.toString());
|
theResponse.addHeader(headerLocation, b.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @Override public void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse) throws BaseServerResponseException, IOException { Object[] params = new
|
* @Override public void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse)
|
||||||
* Object[getParameters().size()]; for (int i = 0; i < getParameters().size(); i++) { IParameter param = getParameters().get(i); if (param != null) { params[i] =
|
* throws BaseServerResponseException, IOException { Object[] params = new Object[getParameters().size()]; for (int
|
||||||
* param.translateQueryParametersIntoServerArgument(theRequest, null); } }
|
* i = 0; i < getParameters().size(); i++) { IParameter param = getParameters().get(i); if (param != null) {
|
||||||
|
* params[i] = param.translateQueryParametersIntoServerArgument(theRequest, null); } }
|
||||||
*
|
*
|
||||||
* addParametersForServerRequest(theRequest, params);
|
* addParametersForServerRequest(theRequest, params);
|
||||||
*
|
*
|
||||||
* MethodOutcome response = (MethodOutcome) invokeServerMethod(getProvider(), params);
|
* MethodOutcome response = (MethodOutcome) invokeServerMethod(getProvider(), params);
|
||||||
*
|
*
|
||||||
* if (response == null) { if (myReturnVoid == false) { throw new ConfigurationException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() +
|
* if (response == null) { if (myReturnVoid == false) { throw new ConfigurationException("Method " +
|
||||||
* " returned null"); } else { theResponse.setStatus(Constants.STATUS_HTTP_204_NO_CONTENT); } } else if (!myReturnVoid) { if (response.isCreated()) {
|
* getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() + " returned null"); }
|
||||||
* theResponse.setStatus(Constants.STATUS_HTTP_201_CREATED); StringBuilder b = new StringBuilder(); b.append(theRequest.getFhirServerBase()); b.append('/'); b.append(getResourceName());
|
* else { theResponse.setStatus(Constants.STATUS_HTTP_204_NO_CONTENT); } } else if (!myReturnVoid) { if
|
||||||
* b.append('/'); b.append(response.getId().getValue()); if (response.getVersionId() != null && response.getVersionId().isEmpty() == false) { b.append("/_history/");
|
* (response.isCreated()) { theResponse.setStatus(Constants.STATUS_HTTP_201_CREATED); StringBuilder b = new
|
||||||
* b.append(response.getVersionId().getValue()); } theResponse.addHeader("Location", b.toString()); } else { theResponse.setStatus(Constants.STATUS_HTTP_200_OK); } } else {
|
* 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); }
|
* theResponse.setStatus(Constants.STATUS_HTTP_204_NO_CONTENT); }
|
||||||
*
|
*
|
||||||
* theServer.addHeadersToResponse(theResponse);
|
* theServer.addHeadersToResponse(theResponse);
|
||||||
*
|
*
|
||||||
* Writer writer = theResponse.getWriter(); try { if (response != null) { OperationOutcome outcome = new OperationOutcome(); if (response.getOperationOutcome() != null &&
|
* Writer writer = theResponse.getWriter(); try { if (response != null) { OperationOutcome outcome = new
|
||||||
* response.getOperationOutcome().getIssue() != null) { outcome.getIssue().addAll(response.getOperationOutcome().getIssue()); } EncodingUtil encoding =
|
* OperationOutcome(); if (response.getOperationOutcome() != null && response.getOperationOutcome().getIssue() !=
|
||||||
* BaseMethodBinding.determineResponseEncoding(theRequest .getServletRequest(), theRequest.getParameters()); theResponse.setContentType(encoding.getResourceContentType()); IParser parser =
|
* null) { outcome.getIssue().addAll(response.getOperationOutcome().getIssue()); } EncodingUtil encoding =
|
||||||
* encoding.newParser(getContext()); parser.encodeResourceToWriter(outcome, writer); } } finally { writer.close(); } // getMethod().in }
|
* 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);
|
||||||
|
@ -279,7 +284,8 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
||||||
protected abstract BaseHttpClientInvocation createClientInvocation(Object[] theArgs, IResource resource);
|
protected abstract BaseHttpClientInvocation createClientInvocation(Object[] theArgs, IResource resource);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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();
|
protected abstract String getMatchingOperation();
|
||||||
|
|
||||||
|
@ -352,5 +358,4 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ public class UpdateTest {
|
||||||
|
|
||||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
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());
|
||||||
|
assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("content-location").getValue());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue