Lots of tweaks for DSTU2 support

This commit is contained in:
James Agnew 2015-01-29 11:34:57 -05:00
parent 9d7796f0be
commit 6c6685137f
21 changed files with 360 additions and 108 deletions

View File

@ -41,6 +41,7 @@ import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu.resource.Binary; import ca.uhn.fhir.model.dstu.resource.Binary;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
@ -64,6 +65,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
private final String myContents; private final String myContents;
private boolean myContentsIsBundle; private boolean myContentsIsBundle;
private Map<String, List<String>> myParams; private Map<String, List<String>> myParams;
private final BundleTypeEnum myBundleType;
public BaseHttpClientInvocationWithContents(FhirContext theContext, IResource theResource, String theUrlPath) { public BaseHttpClientInvocationWithContents(FhirContext theContext, IResource theResource, String theUrlPath) {
super(); super();
@ -74,6 +76,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
myResources = null; myResources = null;
myBundle = null; myBundle = null;
myContents = null; myContents = null;
myBundleType = null;
} }
public BaseHttpClientInvocationWithContents(FhirContext theContext, TagList theTagList, String... theUrlPath) { public BaseHttpClientInvocationWithContents(FhirContext theContext, TagList theTagList, String... theUrlPath) {
@ -88,11 +91,12 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
myResources = null; myResources = null;
myBundle = null; myBundle = null;
myContents = null; myContents = null;
myBundleType = null;
myUrlPath = StringUtils.join(theUrlPath, '/'); myUrlPath = StringUtils.join(theUrlPath, '/');
} }
public BaseHttpClientInvocationWithContents(FhirContext theContext, List<IResource> theResources) { public BaseHttpClientInvocationWithContents(FhirContext theContext, List<IResource> theResources, BundleTypeEnum theBundleType) {
myContext = theContext; myContext = theContext;
myResource = null; myResource = null;
myTagList = null; myTagList = null;
@ -100,6 +104,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
myResources = theResources; myResources = theResources;
myBundle = null; myBundle = null;
myContents = null; myContents = null;
myBundleType = theBundleType;
} }
public BaseHttpClientInvocationWithContents(FhirContext theContext, Bundle theBundle) { public BaseHttpClientInvocationWithContents(FhirContext theContext, Bundle theBundle) {
@ -110,6 +115,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
myResources = null; myResources = null;
myBundle = theBundle; myBundle = theBundle;
myContents = null; myContents = null;
myBundleType = null;
} }
public BaseHttpClientInvocationWithContents(FhirContext theContext, String theContents, boolean theIsBundle, String theUrlPath) { public BaseHttpClientInvocationWithContents(FhirContext theContext, String theContents, boolean theIsBundle, String theUrlPath) {
@ -121,6 +127,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
myBundle = null; myBundle = null;
myContents = theContents; myContents = theContents;
myContentsIsBundle = theIsBundle; myContentsIsBundle = theIsBundle;
myBundleType = null;
} }
public BaseHttpClientInvocationWithContents(FhirContext theContext, Map<String, List<String>> theParams, String... theUrlPath) { public BaseHttpClientInvocationWithContents(FhirContext theContext, Map<String, List<String>> theParams, String... theUrlPath) {
@ -133,6 +140,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
myContents = null; myContents = null;
myContentsIsBundle = false; myContentsIsBundle = false;
myParams = theParams; myParams = theParams;
myBundleType = null;
} }
@Override @Override
@ -201,7 +209,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
contents = parser.encodeBundleToString(myBundle); contents = parser.encodeBundleToString(myBundle);
contentType = encoding.getBundleContentType(); contentType = encoding.getBundleContentType();
} else if (myResources != null) { } else if (myResources != null) {
Bundle bundle = RestfulServer.createBundleFromResourceList(myContext, "", myResources, "", "", myResources.size()); Bundle bundle = RestfulServer.createBundleFromResourceList(myContext, "", myResources, "", "", myResources.size(), myBundleType);
contents = parser.encodeBundleToString(bundle); contents = parser.encodeBundleToString(bundle);
contentType = encoding.getBundleContentType(); contentType = encoding.getBundleContentType();
} else if (myContents != null) { } else if (myContents != null) {

View File

@ -98,37 +98,6 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
protected abstract BaseHttpClientInvocation createClientInvocation(Object[] theArgs, IResource resource); protected abstract BaseHttpClientInvocation createClientInvocation(Object[] theArgs, IResource resource);
/*
* @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 }
*/
/** /**
* For servers, this method will match only incoming requests that match the given operation, or which have no * 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. * operation in the URL if this method returns null.
@ -232,7 +201,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
} else { } else {
servletResponse.setStatus(Constants.STATUS_HTTP_200_OK); servletResponse.setStatus(Constants.STATUS_HTTP_200_OK);
} }
addLocationHeader(theRequest, servletResponse, response, Constants.HEADER_LOCATION); addContentLocationHeaders(theRequest, servletResponse, response);
break; break;
case UPDATE: case UPDATE:
@ -241,10 +210,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
} else { } else {
servletResponse.setStatus(Constants.STATUS_HTTP_201_CREATED); servletResponse.setStatus(Constants.STATUS_HTTP_201_CREATED);
} }
if (response != null && response.getId() != null) { addContentLocationHeaders(theRequest, servletResponse, response);
addLocationHeader(theRequest, servletResponse, response, Constants.HEADER_LOCATION);
addLocationHeader(theRequest, servletResponse, response, Constants.HEADER_CONTENT_LOCATION);
}
break; break;
case VALIDATE: case VALIDATE:
@ -279,7 +245,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
writer.close(); writer.close();
} }
} else { } else {
servletResponse.setContentType(Constants.CT_TEXT); servletResponse.setContentType(Constants.CT_TEXT_WITH_UTF8);
Writer writer = servletResponse.getWriter(); Writer writer = servletResponse.getWriter();
writer.close(); writer.close();
} }
@ -287,6 +253,13 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
// getMethod().in // getMethod().in
} }
private void addContentLocationHeaders(Request theRequest, HttpServletResponse servletResponse, MethodOutcome response) {
if (response != null && response.getId() != null) {
addLocationHeader(theRequest, servletResponse, response, Constants.HEADER_LOCATION);
addLocationHeader(theRequest, servletResponse, response, Constants.HEADER_CONTENT_LOCATION);
}
}
public boolean isReturnVoid() { public boolean isReturnVoid() {
return myReturnVoid; return myReturnVoid;
} }

View File

@ -103,18 +103,6 @@ abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOu
} }
} }
@Override
public RestfulOperationTypeEnum getResourceOperationType() {
// TODO Auto-generated method stub
return null;
}
@Override
public RestfulOperationSystemEnum getSystemOperationType() {
// TODO Auto-generated method stub
return null;
}
/** /**
* For subclasses to override * For subclasses to override
*/ */

View File

@ -41,6 +41,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.annotation.ResourceDef; import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.client.exceptions.InvalidResponseException; import ca.uhn.fhir.rest.client.exceptions.InvalidResponseException;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
@ -242,7 +243,7 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
switch (getReturnType()) { switch (getReturnType()) {
case BUNDLE: case BUNDLE:
Bundle bundle = RestfulServer.createBundleFromBundleProvider(theServer, response, result, responseEncoding, theRequest.getFhirServerBase(), theRequest.getCompleteUrl(), prettyPrint, requestIsBrowser, narrativeMode, 0, count, null); Bundle bundle = RestfulServer.createBundleFromBundleProvider(theServer, response, result, responseEncoding, theRequest.getFhirServerBase(), theRequest.getCompleteUrl(), prettyPrint, requestIsBrowser, narrativeMode, 0, count, null, getResponseBundleType());
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);
@ -276,6 +277,11 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
} }
} }
/**
* If the response is a bundle, this type will be placed in the root of the bundle (can be null)
*/
protected abstract BundleTypeEnum getResponseBundleType();
/** /**
* Subclasses may override * Subclasses may override
* *

View File

@ -28,6 +28,7 @@ import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.base.resource.BaseConformance; import ca.uhn.fhir.model.base.resource.BaseConformance;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum; import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum; import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType; import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
import ca.uhn.fhir.rest.server.IBundleProvider; import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.SimpleBundleProvider; import ca.uhn.fhir.rest.server.SimpleBundleProvider;
@ -101,4 +102,9 @@ public class ConformanceMethodBinding extends BaseResourceReturningMethodBinding
return OtherOperationTypeEnum.METADATA; return OtherOperationTypeEnum.METADATA;
} }
@Override
protected BundleTypeEnum getResponseBundleType() {
return null;
}
} }

View File

@ -31,6 +31,7 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum; import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum; import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType; import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
@ -61,6 +62,12 @@ public class DynamicSearchMethodBinding extends BaseResourceReturningMethodBindi
} }
@Override
protected BundleTypeEnum getResponseBundleType() {
return BundleTypeEnum.SEARCHSET;
}
@Override @Override
public List<IParameter> getParameters() { public List<IParameter> getParameters() {
List<IParameter> retVal = new ArrayList<IParameter>(super.getParameters()); List<IParameter> retVal = new ArrayList<IParameter>(super.getParameters());

View File

@ -35,6 +35,7 @@ import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
import ca.uhn.fhir.model.primitive.DateTimeDt; import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.History; import ca.uhn.fhir.rest.annotation.History;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
@ -125,6 +126,11 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
return retVal; return retVal;
} }
@Override
protected BundleTypeEnum getResponseBundleType() {
return BundleTypeEnum.HISTORY;
}
public static HttpGetClientInvocation createHistoryInvocation(String theResourceName, IdDt theId, DateTimeDt theSince, Integer theLimit) { public static HttpGetClientInvocation createHistoryInvocation(String theResourceName, IdDt theId, DateTimeDt theSince, Integer theLimit) {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
if (theResourceName != null) { if (theResourceName != null) {

View File

@ -30,6 +30,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
public class HttpPostClientInvocation extends BaseHttpClientInvocationWithContents { public class HttpPostClientInvocation extends BaseHttpClientInvocationWithContents {
@ -43,8 +44,8 @@ public class HttpPostClientInvocation extends BaseHttpClientInvocationWithConten
} }
public HttpPostClientInvocation(FhirContext theContext, List<IResource> theResources) { public HttpPostClientInvocation(FhirContext theContext, List<IResource> theResources, BundleTypeEnum theBundleType) {
super(theContext, theResources); super(theContext, theResources, theBundleType);
} }

View File

@ -40,6 +40,7 @@ import ca.uhn.fhir.model.dstu.resource.Binary;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum; import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum; 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.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read; import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType; import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
@ -237,4 +238,9 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding implem
return new HttpGetClientInvocation(new IdDt(theResourceName, theId.getIdPart(), theId.getVersionIdPart()).getValue()); return new HttpGetClientInvocation(new IdDt(theResourceName, theId.getIdPart(), theId.getVersionIdPart()).getValue());
} }
@Override
protected BundleTypeEnum getResponseBundleType() {
return null;
}
} }

View File

@ -42,6 +42,7 @@ import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum; import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum; 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.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.Search; import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.param.BaseQueryParameter; import ca.uhn.fhir.rest.param.BaseQueryParameter;
@ -475,4 +476,9 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
DELETE, GET, OPTIONS, POST, PUT DELETE, GET, OPTIONS, POST, PUT
} }
@Override
protected BundleTypeEnum getResponseBundleType() {
return BundleTypeEnum.SEARCHSET;
}
} }

View File

@ -36,6 +36,7 @@ import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum; import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum; 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.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.TransactionParam; import ca.uhn.fhir.rest.annotation.TransactionParam;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
@ -172,11 +173,16 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
} }
public static BaseHttpClientInvocation createTransactionInvocation(List<IResource> theResources, FhirContext theContext) { public static BaseHttpClientInvocation createTransactionInvocation(List<IResource> theResources, FhirContext theContext) {
return new HttpPostClientInvocation(theContext, theResources); return new HttpPostClientInvocation(theContext, theResources, BundleTypeEnum.TRANSACTION);
} }
public static BaseHttpClientInvocation createTransactionInvocation(Bundle theBundle, FhirContext theContext) { public static BaseHttpClientInvocation createTransactionInvocation(Bundle theBundle, FhirContext theContext) {
return new HttpPostClientInvocation(theContext, theBundle); return new HttpPostClientInvocation(theContext, theBundle);
} }
@Override
protected BundleTypeEnum getResponseBundleType() {
return BundleTypeEnum.TRANSACTION_RESPONSE;
}
} }

View File

@ -37,6 +37,7 @@ public class Constants {
public static final String CT_JSON = "application/json"; public static final String CT_JSON = "application/json";
public static final String CT_OCTET_STREAM = "application/octet-stream"; public static final String CT_OCTET_STREAM = "application/octet-stream";
public static final String CT_TEXT = "text/plain"; public static final String CT_TEXT = "text/plain";
public static final String CT_TEXT_WITH_UTF8 = CT_TEXT + "; charset=UTF-8";
public static final String CT_XML = "application/xml"; public static final String CT_XML = "application/xml";
public static final String ENCODING_GZIP = "gzip"; public static final String ENCODING_GZIP = "gzip";
public static final String FORMAT_JSON = "json"; public static final String FORMAT_JSON = "json";

View File

@ -32,6 +32,7 @@ import ca.uhn.fhir.model.dstu.resource.Binary;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleEntryStatusEnum; import ca.uhn.fhir.model.valueset.BundleEntryStatusEnum;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.Destroy; import ca.uhn.fhir.rest.annotation.Destroy;
import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.IdParam;
@ -426,7 +427,7 @@ public class RestfulServer extends HttpServlet {
NarrativeModeEnum narrativeMode = determineNarrativeMode(theRequest); NarrativeModeEnum narrativeMode = determineNarrativeMode(theRequest);
boolean respondGzip = theRequest.isRespondGzip(); boolean respondGzip = theRequest.isRespondGzip();
Bundle bundle = createBundleFromBundleProvider(this, theResponse, resultList, responseEncoding, theRequest.getFhirServerBase(), theRequest.getCompleteUrl(), prettyPrint, requestIsBrowser, narrativeMode, start, count, thePagingAction); Bundle bundle = createBundleFromBundleProvider(this, theResponse, resultList, responseEncoding, theRequest.getFhirServerBase(), theRequest.getCompleteUrl(), prettyPrint, requestIsBrowser, narrativeMode, start, count, thePagingAction, null);
for (int i = getInterceptors().size() - 1; i >= 0; i--) { for (int i = getInterceptors().size() - 1; i >= 0; i--) {
IServerInterceptor next = getInterceptors().get(i); IServerInterceptor next = getInterceptors().get(i);
@ -1031,7 +1032,7 @@ public class RestfulServer extends HttpServlet {
} }
public static Bundle createBundleFromBundleProvider(RestfulServer theServer, HttpServletResponse theHttpResponse, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint, boolean theRequestIsBrowser, public static Bundle createBundleFromBundleProvider(RestfulServer theServer, HttpServletResponse theHttpResponse, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint, boolean theRequestIsBrowser,
NarrativeModeEnum theNarrativeMode, int theOffset, Integer theLimit, String theSearchId) { NarrativeModeEnum theNarrativeMode, int theOffset, Integer theLimit, String theSearchId, BundleTypeEnum theBundleType) {
theHttpResponse.setStatus(200); theHttpResponse.setStatus(200);
if (theRequestIsBrowser && theServer.isUseBrowserFriendlyContentTypes()) { if (theRequestIsBrowser && theServer.isUseBrowserFriendlyContentTypes()) {
@ -1093,7 +1094,7 @@ public class RestfulServer extends HttpServlet {
} }
} }
Bundle bundle = createBundleFromResourceList(theServer.getFhirContext(), theServer.getServerName(), resourceList, theServerBase, theCompleteUrl, theResult.size()); Bundle bundle = createBundleFromResourceList(theServer.getFhirContext(), theServer.getServerName(), resourceList, theServerBase, theCompleteUrl, theResult.size(), theBundleType);
bundle.setPublished(theResult.getPublished()); bundle.setPublished(theResult.getPublished());
@ -1115,16 +1116,24 @@ public class RestfulServer extends HttpServlet {
return bundle; return bundle;
} }
public static Bundle createBundleFromResourceList(FhirContext theContext, String theAuthor, List<IResource> theResult, String theServerBase, String theCompleteUrl, int theTotalResults) { public static Bundle createBundleFromResourceList(FhirContext theContext, String theAuthor, List<IResource> theResult, String theServerBase, String theCompleteUrl, int theTotalResults, BundleTypeEnum theBundleType) {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.getAuthorName().setValue(theAuthor); bundle.getAuthorName().setValue(theAuthor);
bundle.getBundleId().setValue(UUID.randomUUID().toString()); bundle.getBundleId().setValue(UUID.randomUUID().toString());
bundle.getPublished().setToCurrentTimeInLocalTimeZone(); bundle.getPublished().setToCurrentTimeInLocalTimeZone();
bundle.getLinkBase().setValue(theServerBase); bundle.getLinkBase().setValue(theServerBase);
bundle.getLinkSelf().setValue(theCompleteUrl); bundle.getLinkSelf().setValue(theCompleteUrl);
bundle.getType().setValueAsEnum(theBundleType);
List<IResource> includedResources = new ArrayList<IResource>(); List<IResource> includedResources = new ArrayList<IResource>();
Set<IdDt> addedResourceIds = new HashSet<IdDt>(); Set<IdDt> addedResourceIds = new HashSet<IdDt>();
for (IResource next : theResult) {
if (next.getId().isEmpty() == false) {
addedResourceIds.add(next.getId());
}
}
for (IResource next : theResult) { for (IResource next : theResult) {
Set<String> containedIds = new HashSet<String>(); Set<String> containedIds = new HashSet<String>();

View File

@ -40,6 +40,7 @@ import ca.uhn.fhir.model.dev.valueset.EncounterStateEnum;
import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum; import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.valueset.BundleEntryStatusEnum; import ca.uhn.fhir.model.valueset.BundleEntryStatusEnum;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.IGenericClient; import ca.uhn.fhir.rest.client.IGenericClient;
@ -111,6 +112,7 @@ public class CompleteResourceProviderTest {
{ {
Bundle returned = ourClient.search().forResource(Patient.class).encodedXml().execute(); Bundle returned = ourClient.search().forResource(Patient.class).encodedXml().execute();
assertThat(returned.size(), greaterThan(1)); assertThat(returned.size(), greaterThan(1));
assertEquals(BundleTypeEnum.SEARCHSET, returned.getType().getValueAsEnum());
} }
{ {
Bundle returned = ourClient.search().forResource(Patient.class).encodedJson().execute(); Bundle returned = ourClient.search().forResource(Patient.class).encodedJson().execute();
@ -141,8 +143,8 @@ public class CompleteResourceProviderTest {
assertEquals(2, found.size()); assertEquals(2, found.size());
assertEquals(Patient.class, found.getEntries().get(0).getResource().getClass()); assertEquals(Patient.class, found.getEntries().get(0).getResource().getClass());
assertEquals(null, found.getEntries().get(0).getStatus().getValueAsEnum()); assertEquals(BundleEntryStatusEnum.MATCH, found.getEntries().get(0).getStatus().getValueAsEnum());
assertEquals(null, found.getEntries().get(0).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_STATUS)); assertEquals(BundleEntryStatusEnum.MATCH, found.getEntries().get(0).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_STATUS));
assertEquals(Organization.class, found.getEntries().get(1).getResource().getClass()); assertEquals(Organization.class, found.getEntries().get(1).getResource().getClass());
assertEquals(BundleEntryStatusEnum.INCLUDE, found.getEntries().get(1).getStatus().getValueAsEnum()); assertEquals(BundleEntryStatusEnum.INCLUDE, found.getEntries().get(1).getStatus().getValueAsEnum());
assertEquals(BundleEntryStatusEnum.INCLUDE, found.getEntries().get(1).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_STATUS)); assertEquals(BundleEntryStatusEnum.INCLUDE, found.getEntries().get(1).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_STATUS));

View File

@ -0,0 +1,78 @@
package ca.uhn.fhir.rest.client;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.Arrays;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.ReaderInputStream;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicStatusLine;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dev.resource.Patient;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.server.Constants;
public class BundleTypeTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BundleTypeTest.class);
private FhirContext ourCtx;
private HttpClient ourHttpClient;
private HttpResponse ourHttpResponse;
@Before
public void before() {
ourCtx = FhirContext.forDstu2();
ourHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ourCtx.getRestfulClientFactory().setHttpClient(ourHttpClient);
ourCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
ourHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}
@Test
public void testTransaction() throws Exception {
String retVal = ourCtx.newXmlParser().encodeBundleToString(new Bundle());
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(ourHttpClient.execute(capt.capture())).thenReturn(ourHttpResponse);
when(ourHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(ourHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8"));
when(ourHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(retVal), Charset.forName("UTF-8")));
Patient p1 = new Patient();
p1.addIdentifier().setSystem("urn:system").setValue("value");
IGenericClient client = ourCtx.newRestfulGenericClient("http://foo");
client.transaction().withResources(Arrays.asList((IResource) p1)).execute();
HttpUriRequest value = capt.getValue();
assertTrue("Expected request of type POST on long params list", value instanceof HttpPost);
HttpPost post = (HttpPost) value;
String body = IOUtils.toString(post.getEntity().getContent());
ourLog.info(body);
assertThat(body, Matchers.containsString("<type value=\"" + BundleTypeEnum.TRANSACTION.getCode()));
}
}

View File

@ -0,0 +1,128 @@
package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.dev.composite.CodingDt;
import ca.uhn.fhir.model.dev.resource.Observation;
import ca.uhn.fhir.model.dev.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenOrListParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.util.PortUtil;
import com.google.common.net.UrlEscapers;
/**
* Created by dsotnikov on 2/25/2014.
*/
public class BundleTypeInResponseTest {
private static CloseableHttpClient ourClient;
private static FhirContext ourCtx = new FhirContext();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BundleTypeInResponseTest.class);
private static int ourPort;
private static Server ourServer;
@Test
public void testSearch() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
assertEquals(1, bundle.getEntries().size());
assertEquals(BundleTypeEnum.SEARCHSET, bundle.getType().getValueAsEnum());
}
@AfterClass
public static void afterClass() throws Exception {
ourServer.stop();
}
@BeforeClass
public static void beforeClass() throws Exception {
ourPort = PortUtil.findFreePort();
ourServer = new Server(ourPort);
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer();
servlet.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
servlet.setResourceProviders(patientProvider);
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
ourServer.start();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourClient = builder.build();
}
public static class DummyPatientResourceProvider implements IResourceProvider {
@Search
public List<Patient> findPatient() {
ArrayList<Patient> retVal = new ArrayList<Patient>();
Patient patient = new Patient();
patient.setId("1");
patient.addIdentifier().setSystem("system").setValue("identifier123");
retVal.add(patient);
return retVal;
}
@Override
public Class<? extends IResource> getResourceType() {
return Patient.class;
}
}
}

View File

@ -196,7 +196,7 @@ public class ContainedResourceEncodingTest {
List<IResource> list = new ArrayList<IResource>(); List<IResource> list = new ArrayList<IResource>();
list.add(dr); list.add(dr);
Bundle bundle = RestfulServer.createBundleFromResourceList(new FhirContext(), null, list, null, null, 0); Bundle bundle = RestfulServer.createBundleFromResourceList(new FhirContext(), null, list, null, null, 0, null);
IParser parser = this.ctx.newXmlParser().setPrettyPrint(true); IParser parser = this.ctx.newXmlParser().setPrettyPrint(true);
String xml = parser.encodeBundleToString(bundle); String xml = parser.encodeBundleToString(bundle);
@ -235,7 +235,7 @@ public class ContainedResourceEncodingTest {
List<IResource> list = new ArrayList<IResource>(); List<IResource> list = new ArrayList<IResource>();
list.add(dr); list.add(dr);
Bundle bundle = RestfulServer.createBundleFromResourceList(new FhirContext(), null, list, null, null, 0); Bundle bundle = RestfulServer.createBundleFromResourceList(new FhirContext(), null, list, null, null, 0, null);
IParser parser = this.ctx.newXmlParser().setPrettyPrint(true); IParser parser = this.ctx.newXmlParser().setPrettyPrint(true);
String xml = parser.encodeBundleToString(bundle); String xml = parser.encodeBundleToString(bundle);

View File

@ -1,6 +1,8 @@
package ca.uhn.fhir.parser; package ca.uhn.fhir.parser;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotEquals;
@ -30,7 +32,6 @@ import org.hamcrest.core.StringContains;
import org.hamcrest.text.StringContainsInOrder; import org.hamcrest.text.StringContainsInOrder;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.mockito.Matchers;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
@ -277,6 +278,7 @@ public class XmlParserTest {
} }
@Test @Test
public void testEncodeContained() { public void testEncodeContained() {
IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true); IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true);

File diff suppressed because one or more lines are too long

View File

@ -18,6 +18,7 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.hamcrest.core.StringContains;
import org.hl7.fhir.instance.model.annotations.ResourceDef; import org.hl7.fhir.instance.model.annotations.ResourceDef;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
@ -70,6 +71,7 @@ public class CreateTest {
assertEquals(201, status.getStatusLine().getStatusCode()); assertEquals(201, 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());
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), StringContains.containsString("UTF-8"));
} }

View File

@ -89,6 +89,25 @@ public class RestfulServerMethodTest {
private static Server ourServer; private static Server ourServer;
private static RestfulServer ourRestfulServer; private static RestfulServer ourRestfulServer;
@Test
public void testCreateBundleDoesntCreateDoubleEntries() {
List<IResource> resources = new ArrayList<IResource>();
Patient p = new Patient();
p.setId("Patient/1");
resources.add(p);
Organization o = new Organization();
o.setId("Organization/2");
resources.add(o);
p.getManagingOrganization().setResource(o);
Bundle bundle = RestfulServer.createBundleFromResourceList(ourCtx, "", resources, "http://foo", "http://foo", 2, null);
assertEquals(2, bundle.getEntries().size());
}
@Test @Test
public void test404IsPropagatedCorrectly() throws Exception { public void test404IsPropagatedCorrectly() throws Exception {