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
|
||||
first time an XML parser is created.
|
||||
</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 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 (!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;
|
||||
}
|
||||
|
@ -89,8 +88,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
|||
}
|
||||
|
||||
@Override
|
||||
public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException,
|
||||
BaseServerResponseException {
|
||||
public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
||||
switch (theResponseStatusCode) {
|
||||
case Constants.STATUS_HTTP_200_OK:
|
||||
case Constants.STATUS_HTTP_201_CREATED:
|
||||
|
@ -147,8 +145,8 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
|||
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--) {
|
||||
IServerInterceptor next = theServer.getInterceptors().get(i);
|
||||
boolean continueProcessing = next.outgoingResponse(theRequest, outcome, theRequest.getServletRequest(), theRequest.getServletResponse());
|
||||
|
@ -156,19 +154,18 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (getResourceOperationType()) {
|
||||
case CREATE:
|
||||
if (response == null) {
|
||||
throw new InternalErrorException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName()
|
||||
+ " returned null, which is not allowed for create operation");
|
||||
throw new InternalErrorException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() + " returned null, which is not allowed for create operation");
|
||||
}
|
||||
if (response.getCreated() == null || Boolean.TRUE.equals(response.getCreated())) {
|
||||
servletResponse.setStatus(Constants.STATUS_HTTP_201_CREATED);
|
||||
} else {
|
||||
servletResponse.setStatus(Constants.STATUS_HTTP_200_OK);
|
||||
}
|
||||
addLocationHeader(theRequest, servletResponse, response);
|
||||
addLocationHeader(theRequest, servletResponse, response, Constants.HEADER_LOCATION);
|
||||
break;
|
||||
|
||||
case UPDATE:
|
||||
|
@ -178,7 +175,8 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
|||
servletResponse.setStatus(Constants.STATUS_HTTP_201_CREATED);
|
||||
}
|
||||
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;
|
||||
|
||||
|
@ -226,7 +224,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
|||
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();
|
||||
b.append(theRequest.getFhirServerBase());
|
||||
b.append('/');
|
||||
|
@ -240,31 +238,38 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
|||
b.append("/" + Constants.PARAM_HISTORY + "/");
|
||||
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
|
||||
* 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); } }
|
||||
* @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 {
|
||||
* 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 }
|
||||
* 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 }
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
|
@ -352,5 +358,4 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@ public class UpdateTest {
|
|||
|
||||
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("content-location").getValue());
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue