Fix #241 and fix #247 - Don't encode UUID IDs on resources, and preserve

bundle type when retrieving pages
This commit is contained in:
James Agnew 2015-10-29 15:38:19 -04:00
parent 01320ac1b1
commit d3685e72ba
18 changed files with 1007 additions and 842 deletions

View File

@ -40,6 +40,11 @@
<artifactId>thymeleaf</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<optional>true</optional>
</dependency>
<!-- Only required for CORS support -->
<dependency>

View File

@ -186,7 +186,7 @@ public class OperationMethodBinding extends BaseResourceReturningMethodBinding {
@Override
protected BundleTypeEnum getResponseBundleType() {
return null;
return BundleTypeEnum.COLLECTION;
}
public List<ReturnType> getReturnParams() {

View File

@ -149,6 +149,11 @@ public class Constants {
public static final String URL_TOKEN_METADATA = "metadata";
public static final String PARAM_CONTENT = "_content";
public static final String PARAM_TEXT = "_text";
/**
* Used in paging links
*/
public static final Object PARAM_BUNDLETYPE = "_bundletype";
static {
Map<String, EncodingEnum> valToEncoding = new HashMap<String, EncodingEnum>();

View File

@ -58,6 +58,7 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.Destroy;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Initialize;
@ -511,7 +512,13 @@ public class RestfulServer extends HttpServlet {
String linkSelfBase = getServerAddressStrategy().determineServerBase(getServletContext(), theRequest.getServletRequest());
String linkSelf = linkSelfBase + theRequest.getCompleteUrl().substring(theRequest.getCompleteUrl().indexOf('?'));
bundleFactory.initializeBundleFromBundleProvider(this, resultList, responseEncoding, theRequest.getFhirServerBase(), linkSelf, prettyPrint, start, count, thePagingAction, null, includes);
BundleTypeEnum bundleType = null;
String[] bundleTypeValues = theRequest.getParameters().get(Constants.PARAM_BUNDLETYPE);
if (bundleTypeValues != null) {
bundleType = BundleTypeEnum.VALUESET_BINDER.fromCodeString(bundleTypeValues[0]);
}
bundleFactory.initializeBundleFromBundleProvider(this, resultList, responseEncoding, theRequest.getFhirServerBase(), linkSelf, prettyPrint, start, count, thePagingAction, bundleType, includes);
Bundle bundle = bundleFactory.getDstu1Bundle();
if (bundle != null) {

View File

@ -60,6 +60,7 @@ import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
@ -132,7 +133,7 @@ public class RestfulServerUtils {
}
}
public static String createPagingLink(Set<Include> theIncludes, String theServerBase, String theSearchId, int theOffset, int theCount, EncodingEnum theResponseEncoding, boolean thePrettyPrint) {
public static String createPagingLink(Set<Include> theIncludes, String theServerBase, String theSearchId, int theOffset, int theCount, EncodingEnum theResponseEncoding, boolean thePrettyPrint, BundleTypeEnum theBundleType) {
try {
StringBuilder b = new StringBuilder();
b.append(theServerBase);
@ -172,6 +173,13 @@ public class RestfulServerUtils {
}
}
}
if (theBundleType != null) {
b.append('&');
b.append(Constants.PARAM_BUNDLETYPE);
b.append('=');
b.append(theBundleType.getCode());
}
return b.toString();
} catch (UnsupportedEncodingException e) {

View File

@ -75,6 +75,12 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.20.0-GA</version>
</dependency>
<dependency>
<groupId>com.phloc</groupId>
<artifactId>phloc-schematron</artifactId>
@ -234,7 +240,7 @@
<artifactId>hibernate-search-orm</artifactId>
<version>5.5.0.Final</version>
</dependency>
<!-- Misc -->
<dependency>
<groupId>com.google.guava</groupId>
@ -345,10 +351,7 @@
<targetResourceSpringBeansFile>hapi-fhir-server-resourceproviders-dstu2.xml</targetResourceSpringBeansFile>
<baseResourceNames></baseResourceNames>
<excludeResourceNames>
<!--
<excludeResourceName>OperationDefinition</excludeResourceName>
<excludeResourceName>OperationOutcome</excludeResourceName>
-->
<!-- <excludeResourceName>OperationDefinition</excludeResourceName> <excludeResourceName>OperationOutcome</excludeResourceName> -->
</excludeResourceNames>
</configuration>
</execution>

View File

@ -101,20 +101,20 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
protected EntityManager myEntityManager;
@Autowired
private PlatformTransactionManager myPlatformTransactionManager;
protected PlatformTransactionManager myPlatformTransactionManager;
@Autowired
private DaoConfig myDaoConfig;
@Autowired(required = false)
private ISearchDao mySearchDao;
protected ISearchDao mySearchDao;
private String myResourceName;
private Class<T> myResourceType;
private String mySecondaryPrimaryKeyParamName;
@Autowired()
private ISearchResultDao mySearchResultDao;
protected ISearchResultDao mySearchResultDao;
@Override
public void addTag(IIdType theId, TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) {

View File

@ -30,21 +30,21 @@ import ca.uhn.fhir.jpa.dao.SearchParameterMap.EverythingModeEnum;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.UnsignedIntDt;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
public class FhirResourceDaoPatientDstu2 extends FhirResourceDaoDstu2<Patient>implements IFhirResourceDaoPatient<Patient> {
@Override
public IBundleProvider patientInstanceEverything(HttpServletRequest theServletRequest, IIdType theId, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort) {
private IBundleProvider doEverythingOperation(IIdType theId, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort) {
SearchParameterMap paramMap = new SearchParameterMap();
if (theCount != null) {
paramMap.setCount(theCount.getValue());
}
// paramMap.setRevIncludes(Collections.singleton(IResource.INCLUDE_ALL.asRecursive()));
paramMap.setIncludes(Collections.singleton(IResource.INCLUDE_ALL.asRecursive()));
paramMap.setEverythingMode(theId != null ? EverythingModeEnum.PATIENT_INSTANCE : EverythingModeEnum.PATIENT_TYPE);
paramMap.setSort(theSort);
@ -52,13 +52,28 @@ public class FhirResourceDaoPatientDstu2 extends FhirResourceDaoDstu2<Patient>im
if (theId != null) {
paramMap.add("_id", new StringParam(theId.getIdPart()));
}
ca.uhn.fhir.rest.server.IBundleProvider retVal = search(paramMap);
return retVal;
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this);
builder.setType(getResourceType(), getResourceName());
return builder.search(paramMap);
}
@Override
public IBundleProvider patientInstanceEverything(HttpServletRequest theServletRequest, IIdType theId, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName());
notifyInterceptors(RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE, requestDetails);
return doEverythingOperation(theId, theCount, theLastUpdated, theSort);
}
@Override
public IBundleProvider patientTypeEverything(HttpServletRequest theServletRequest, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort) {
return patientInstanceEverything(theServletRequest, null, theCount, theLastUpdated, theSort);
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName());
notifyInterceptors(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE, requestDetails);
return doEverythingOperation(null, theCount, theLastUpdated, theSort);
}
}

View File

@ -134,6 +134,38 @@ public class SystemProviderDstu2Test extends BaseJpaDstu2Test {
myRestServer.unregisterInterceptor(interceptor);
}
@Test
public void testEverythingReturnsCorrectBundleType() throws Exception {
myRestServer.setDefaultResponseEncoding(EncodingEnum.JSON);
myRestServer.setPagingProvider(new FifoMemoryPagingProvider(1).setDefaultPageSize(10));
ResponseHighlighterInterceptor interceptor = new ResponseHighlighterInterceptor();
myRestServer.registerInterceptor(interceptor);
for (int i = 0; i < 11; i++) {
Patient p = new Patient();
p.addName().addFamily("Name" + i);
ourClient.create().resource(p).execute();
}
HttpGet get = new HttpGet(ourServerBase + "/Patient/$everything");
get.addHeader("Accept", "application/xml+fhir");
CloseableHttpResponse http = ourHttpClient.execute(get);
try {
String response = IOUtils.toString(http.getEntity().getContent());
ourLog.info(response);
assertThat(response, not(containsString("_format")));
assertEquals(200, http.getStatusLine().getStatusCode());
Bundle responseBundle = ourCtx.newXmlParser().parseResource(Bundle.class, response);
assertEquals(BundleTypeEnum.COLLECTION, responseBundle.getTypeElement().getValueAsEnum());
} finally {
http.close();
}
myRestServer.unregisterInterceptor(interceptor);
}
@Test
public void testEverythingType() throws Exception {
HttpGet get = new HttpGet(ourServerBase + "/Patient/$everything");

View File

@ -255,11 +255,11 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
if (searchId != null) {
if (theOffset + numToReturn < theResult.size()) {
myBundle.getLinkNext().setValue(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, theOffset + numToReturn, numToReturn, theResponseEncoding, thePrettyPrint));
myBundle.getLinkNext().setValue(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, theOffset + numToReturn, numToReturn, theResponseEncoding, thePrettyPrint, theBundleType));
}
if (theOffset > 0) {
int start = Math.max(0, theOffset - limit);
myBundle.getLinkPrevious().setValue(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, start, limit, theResponseEncoding, thePrettyPrint));
myBundle.getLinkPrevious().setValue(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, start, limit, theResponseEncoding, thePrettyPrint, theBundleType));
}
}
}

View File

@ -73,7 +73,7 @@ public class PagingTest {
assertEquals(5, bundle.getEntries().size());
assertEquals("0", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("4", bundle.getEntries().get(4).getResource().getId().getIdPart());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=5&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true", bundle.getLinkNext()
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=5&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true&_bundletype=searchset", bundle.getLinkNext()
.getValue());
assertNull(bundle.getLinkPrevious().getValue());
link = bundle.getLinkNext().getValue();
@ -90,7 +90,7 @@ public class PagingTest {
assertEquals("5", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("9", bundle.getEntries().get(4).getResource().getId().getIdPart());
assertNull(bundle.getLinkNext().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=5&_format=json&_pretty=true", bundle.getLinkPrevious()
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=5&_format=json&_pretty=true&_bundletype=searchset", bundle.getLinkPrevious()
.getValue());
}
}
@ -141,7 +141,7 @@ public class PagingTest {
assertEquals(2, bundle.getEntries().size());
assertEquals("0", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("1", bundle.getEntries().get(1).getResource().getId().getIdPart());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkNext().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml&_bundletype=searchset", bundle.getLinkNext().getValue());
assertNull(bundle.getLinkPrevious().getValue());
link = bundle.getLinkNext().getValue();
}
@ -156,9 +156,9 @@ public class PagingTest {
assertEquals(2, bundle.getEntries().size());
assertEquals("2", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("3", bundle.getEntries().get(1).getResource().getId().getIdPart());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=4&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkNext().getValue());
assertEquals(base + '/' + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkSelf().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkPrevious().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=4&" + Constants.PARAM_COUNT + "=2&_format=xml&_bundletype=searchset", bundle.getLinkNext().getValue());
assertEquals(base + '/' + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml&_bundletype=searchset", bundle.getLinkSelf().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=2&_format=xml&_bundletype=searchset", bundle.getLinkPrevious().getValue());
}
}
@ -236,7 +236,7 @@ public class PagingTest {
assertEquals(2, bundle.getEntries().size());
assertEquals("0", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("1", bundle.getEntries().get(1).getResource().getId().getIdPart());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2", bundle.getLinkNext().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_bundletype=searchset", bundle.getLinkNext().getValue());
assertNull(bundle.getLinkPrevious().getValue());
link = bundle.getLinkNext().getValue();
}
@ -251,9 +251,9 @@ public class PagingTest {
assertEquals(2, bundle.getEntries().size());
assertEquals("2", bundle.getEntries().get(0).getResource().getId().getIdPart());
assertEquals("3", bundle.getEntries().get(1).getResource().getId().getIdPart());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=4&" + Constants.PARAM_COUNT + "=2", bundle.getLinkNext().getValue());
assertEquals(base + '/' + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2", bundle.getLinkSelf().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=2", bundle.getLinkPrevious().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=4&" + Constants.PARAM_COUNT + "=2&_bundletype=searchset", bundle.getLinkNext().getValue());
assertEquals(base + '/' + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_bundletype=searchset", bundle.getLinkSelf().getValue());
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=2&_bundletype=searchset", bundle.getLinkPrevious().getValue());
}
}

View File

@ -349,7 +349,11 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
}
numToReturn = Math.min(numToReturn, theResult.size() - theOffset);
resourceList = theResult.getResources(theOffset, numToReturn + theOffset);
if (numToReturn > 0) {
resourceList = theResult.getResources(theOffset, numToReturn + theOffset);
} else {
resourceList = Collections.emptyList();
}
RestfulServerUtils.validateResourceListNotNull(resourceList);
if (theSearchId != null) {
@ -390,12 +394,12 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
if (searchId != null) {
if (theOffset + numToReturn < theResult.size()) {
myBundle.addLink().setRelation(Constants.LINK_NEXT)
.setUrl(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, theOffset + numToReturn, numToReturn, theResponseEncoding, thePrettyPrint));
.setUrl(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, theOffset + numToReturn, numToReturn, theResponseEncoding, thePrettyPrint, theBundleType));
}
if (theOffset > 0) {
int start = Math.max(0, theOffset - limit);
myBundle.addLink().setRelation(Constants.LINK_PREVIOUS)
.setUrl(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, start, limit, theResponseEncoding, thePrettyPrint));
.setUrl(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, start, limit, theResponseEncoding, thePrettyPrint, theBundleType));
}
}
}

View File

@ -1,19 +1,24 @@
package ca.uhn.fhir.parser;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import ca.uhn.fhir.model.dstu2.resource.*;
import ca.uhn.fhir.model.dstu2.valueset.*;
import org.apache.commons.io.IOUtils;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import ca.uhn.fhir.context.ConfigurationException;
@ -29,7 +34,22 @@ import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.Binary;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu2.resource.Condition;
import ca.uhn.fhir.model.dstu2.resource.Conformance;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu2.resource.Medication;
import ca.uhn.fhir.model.dstu2.resource.MedicationOrder;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.resource.QuestionnaireResponse;
import ca.uhn.fhir.model.dstu2.valueset.AdministrativeGenderEnum;
import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
import ca.uhn.fhir.model.dstu2.valueset.ConditionVerificationStatusEnum;
import ca.uhn.fhir.model.dstu2.valueset.IdentifierUseEnum;
import ca.uhn.fhir.model.dstu2.valueset.MaritalStatusCodesEnum;
import ca.uhn.fhir.model.dstu2.valueset.ObservationStatusEnum;
import ca.uhn.fhir.model.primitive.DateDt;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.IdDt;
@ -1019,7 +1039,6 @@ public class JsonParserDstu2Test {
}
// see #241
@Ignore
@Test
public void testEncodeThenParseShouldNotAddSpuriousId() throws Exception {
Condition condition = new Condition().setVerificationStatus(ConditionVerificationStatusEnum.CONFIRMED);
@ -1030,7 +1049,8 @@ public class JsonParserDstu2Test {
bundle.getEntry().add(entry);
IParser parser = ourCtx.newJsonParser();
String json = parser.encodeResourceToString(bundle);
ourLog.info(json);
bundle = (ca.uhn.fhir.model.dstu2.resource.Bundle) parser.parseResource(json);
assertTrue(bundle.getEntry().get(0).getResource().getIdElement().isEmpty());
assertThat(json, not(containsString("\"id\"")));
}
}

View File

@ -2,6 +2,7 @@ package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.startsWith;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@ -36,12 +37,14 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Link;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.DateAndListParam;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.util.PatternMatcher;
import ca.uhn.fhir.util.PortUtil;
@ -63,7 +66,7 @@ public class SearchDstu2Test {
ourLastDateAndList = null;
ourLastRef = null;
}
@Test
public void testSearchWhitelist01Failing() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchWhitelist01&ref=value");
@ -73,7 +76,6 @@ public class SearchDstu2Test {
ourLog.info(responseContent);
assertEquals(400, status.getStatusLine().getStatusCode());
}
@Test
public void testSearchReferenceParams01() throws Exception {
@ -83,11 +85,11 @@ public class SearchDstu2Test {
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("123", ourLastRef.getIdPart());
assertEquals(null, ourLastRef.getResourceType());
}
@Test
public void testSearchReferenceParams02() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchNoList&ref=Patient/123");
@ -96,7 +98,7 @@ public class SearchDstu2Test {
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("123", ourLastRef.getIdPart());
assertEquals("Patient", ourLastRef.getResourceType());
}
@ -109,7 +111,7 @@ public class SearchDstu2Test {
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("123", ourLastRef.getIdPart());
assertEquals("Patient", ourLastRef.getResourceType());
}
@ -122,7 +124,7 @@ public class SearchDstu2Test {
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("123", ourLastRef.getIdPart());
assertEquals("Patient", ourLastRef.getResourceType());
}
@ -139,16 +141,62 @@ public class SearchDstu2Test {
assertEquals(2, ourLastDateAndList.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().size());
assertEquals(2, ourLastDateAndList.getValuesAsQueryTokens().get(1).getValuesAsQueryTokens().size());
assertEquals("2001", ourLastDateAndList.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValueAsString());
assertEquals("2002", ourLastDateAndList.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(1).getValueAsString());
assertEquals("2002", ourLastDateAndList.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(1).getValueAsString());
}
/**
* See #247
*/
@Test
public void testSearchPagesAllHaveCorrectBundleType() throws Exception {
Bundle resp;
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?searchHugeResults=yes&_count=10&_pretty=true");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
resp = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent);
assertEquals("searchset", resp.getType());
assertEquals(100, resp.getTotal().intValue());
}
Link nextLink = resp.getLink("next");
assertThat(nextLink.getUrl(), startsWith("http://"));
// Now try the next page
{
HttpGet httpGet = new HttpGet(nextLink.getUrl());
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
resp = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent);
assertEquals("searchset", resp.getType());
assertEquals(100, resp.getTotal().intValue());
}
nextLink = resp.getLink("next");
assertThat(nextLink.getUrl(), startsWith("http://"));
// Now try a third page
{
HttpGet httpGet = new HttpGet(nextLink.getUrl());
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
resp = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent);
assertEquals("searchset", resp.getType());
assertEquals(100, resp.getTotal().intValue());
}
}
@Test
public void testSearchByPost() throws Exception {
HttpPost httpGet = new HttpPost("http://localhost:" + ourPort + "/Patient/_search");
StringEntity entity = new StringEntity("searchDateAndList=2001,2002&searchDateAndList=2003,2004", ContentType.APPLICATION_FORM_URLENCODED);
httpGet.setEntity(entity);
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
@ -167,7 +215,7 @@ public class SearchDstu2Test {
HttpPut httpGet = new HttpPut("http://localhost:" + ourPort + "/Patient/_search");
StringEntity entity = new StringEntity("searchDateAndList=2001,2002&searchDateAndList=2003,2004", ContentType.APPLICATION_FORM_URLENCODED);
httpGet.setEntity(entity);
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
@ -175,13 +223,13 @@ public class SearchDstu2Test {
assertEquals(400, status.getStatusLine().getStatusCode());
}
@Test
public void testSearchByPostWithBodyAndUrlParams() throws Exception {
@Test
public void testSearchByPostWithBodyAndUrlParams() throws Exception {
HttpPost httpGet = new HttpPost("http://localhost:" + ourPort + "/Patient/_search?_format=json");
StringEntity entity = new StringEntity("searchDateAndList=2001,2002&searchDateAndList=2003,2004", ContentType.APPLICATION_FORM_URLENCODED);
httpGet.setEntity(entity);
CloseableHttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
@ -196,7 +244,6 @@ public class SearchDstu2Test {
}
@Test
public void testSearchBlacklist01Failing() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchBlacklist01&ref.black1=value");
@ -206,6 +253,7 @@ public class SearchDstu2Test {
ourLog.info(responseContent);
assertEquals(400, status.getStatusLine().getStatusCode());
}
@Test
public void testSearchBlacklist01Passing() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchBlacklist01&ref.white1=value");
@ -235,7 +283,7 @@ public class SearchDstu2Test {
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertThat(responseContent, not(containsString("text")));
assertEquals(200, status.getStatusLine().getStatusCode());
@ -252,7 +300,7 @@ public class SearchDstu2Test {
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertThat(responseContent, not(containsString("text")));
assertEquals(200, status.getStatusLine().getStatusCode());
@ -269,7 +317,7 @@ public class SearchDstu2Test {
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, PatternMatcher.pattern("id value..[0-9a-f-]+\\\""));
}
@ -277,7 +325,7 @@ public class SearchDstu2Test {
@Test
public void testResultBundleHasUpdateTime() throws Exception {
ourReturnPublished = new InstantDt("2011-02-03T11:22:33Z");
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchWithBundleProvider&_pretty=true");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
@ -301,6 +349,7 @@ public class SearchDstu2Test {
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer(ourCtx);
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
servlet.setResourceProviders(patientProvider);
ServletHolder servletHolder = new ServletHolder(servlet);
@ -319,7 +368,6 @@ public class SearchDstu2Test {
* Created by dsotnikov on 2/25/2014.
*/
public static class DummyPatientResourceProvider implements IResourceProvider {
@Override
public Class<? extends IResource> getResourceType() {
@ -359,6 +407,21 @@ public class SearchDstu2Test {
}
//@formatter:on
//@formatter:off
@Search()
public List<Patient> searchHugeResults(
@RequiredParam(name = "searchHugeResults") StringParam theParam) {
ourLastMethod = "searchHugeResults";
ArrayList<Patient> retVal = new ArrayList<Patient>();
for (int i = 0; i < 100; i++) {
Patient patient = new Patient();
patient.setId("" + i);
retVal.add(patient.addIdentifier(new IdentifierDt("SYSTEM", "CODE"+ i)));
}
return retVal;
}
//@formatter:on
//@formatter:off
@Search(queryName="searchBlacklist01")
public List<Patient> searchBlacklist01(
@ -368,33 +431,33 @@ public class SearchDstu2Test {
}
//@formatter:on
@Search(queryName="searchWithBundleProvider")
@Search(queryName = "searchWithBundleProvider")
public IBundleProvider searchWithBundleProvider() {
return new IBundleProvider() {
@Override
public InstantDt getPublished() {
return ourReturnPublished;
}
@Override
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
throw new IllegalStateException();
}
@Override
public Integer preferredPageSize() {
return null;
}
@Override
public int size() {
return 0;
}
};
}
@Search(queryName="searchWithRef")
@Search(queryName = "searchWithRef")
public Patient searchWithRef() {
Patient patient = new Patient();
patient.setId("Patient/1/_history/1");

View File

@ -364,12 +364,12 @@ public class Dstu2Hl7OrgBundleFactory implements IVersionSpecificBundleFactory {
if (searchId != null) {
if (theOffset + numToReturn < theResult.size()) {
myBundle.addLink().setRelation(Constants.LINK_NEXT).setUrl(RestfulServerUtils.createPagingLink(theIncludes,
theServerBase, searchId, theOffset + numToReturn, numToReturn, theResponseEncoding, thePrettyPrint));
theServerBase, searchId, theOffset + numToReturn, numToReturn, theResponseEncoding, thePrettyPrint, theBundleType));
}
if (theOffset > 0) {
int start = Math.max(0, theOffset - limit);
myBundle.addLink().setRelation(Constants.LINK_PREVIOUS).setUrl(RestfulServerUtils.createPagingLink(
theIncludes, theServerBase, searchId, start, limit, theResponseEncoding, thePrettyPrint));
theIncludes, theServerBase, searchId, start, limit, theResponseEncoding, thePrettyPrint, theBundleType));
}
}
}

68
pom.xml
View File

@ -224,9 +224,8 @@
<apache_httpclient_version>4.4</apache_httpclient_version>
<apache_httpcore_version>4.4</apache_httpcore_version>
<derby_version>10.12.1.1</derby_version>
<!-- Note on Hibernate versions: Hibernate 4.3+ uses JPA 2.1, which is too new for a number of platforms including JBoss EAP 6.x and Glassfish 3.0. Upgrade this
version with caution! Also note that if you change this, you may get a failure in hibernate4-maven-plugin. See the note in hapi-fhir-jpaserver-base/pom.xml's configuration
for that plugin... -->
<!-- Note on Hibernate versions: Hibernate 4.3+ uses JPA 2.1, which is too new for a number of platforms including JBoss EAP 6.x and Glassfish 3.0. Upgrade this version with caution! Also note that if
you change this, you may get a failure in hibernate4-maven-plugin. See the note in hapi-fhir-jpaserver-base/pom.xml's configuration for that plugin... -->
<hibernate_version>5.0.2.Final</hibernate_version>
<hibernate_validator_version>5.2.1.Final</hibernate_validator_version>
<jetty_version>9.3.4.v20151007</jetty_version>
@ -244,14 +243,10 @@
<thymeleaf-version>2.1.4.RELEASE</thymeleaf-version>
<ebay_cors_filter_version>1.0.1</ebay_cors_filter_version>
<xmlunit_version>1.6</xmlunit_version>
<!--
We are aiming to still work on a very old version of SLF4j even though
we depend on the newest, just to be nice to users of the API. This version
is tested in the hapi-fhir-cobertura.
-->
<!-- We are aiming to still work on a very old version of SLF4j even though we depend on the newest, just to be nice to users of the API. This version is tested in the hapi-fhir-cobertura. -->
<slf4j_target_version>1.6.0</slf4j_target_version>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
@ -502,6 +497,11 @@
<artifactId>hibernate-validator</artifactId>
<version>${hibernate_validator_version}</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.20.0-GA</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-android</artifactId>
@ -923,43 +923,43 @@
<configuration>
<target>
<copy todir="target/site/apidocs">
<fileset dir="hapi-fhir-base/target/site/apidocs" />
<fileset dir="hapi-fhir-base/target/site/apidocs"/>
</copy>
<copy todir="target/site/apidocs-dstu">
<fileset dir="hapi-fhir-structures-dstu/target/site/apidocs" />
<fileset dir="hapi-fhir-structures-dstu/target/site/apidocs"/>
</copy>
<copy todir="target/site/apidocs-hl7org-dstu2">
<fileset dir="hapi-fhir-structures-hl7org-dstu2/target/site/apidocs" />
<fileset dir="hapi-fhir-structures-hl7org-dstu2/target/site/apidocs"/>
</copy>
<copy todir="target/site/apidocs-dstu2">
<fileset dir="hapi-fhir-structures-dstu2/target/site/apidocs" />
<fileset dir="hapi-fhir-structures-dstu2/target/site/apidocs"/>
</copy>
<copy todir="target/site/apidocs-jpaserver">
<fileset dir="hapi-fhir-jpaserver-base/target/site/apidocs" />
<fileset dir="hapi-fhir-jpaserver-base/target/site/apidocs"/>
</copy>
<copy todir="target/site/xref-jpaserver">
<fileset dir="hapi-fhir-jpaserver-base/target/site/xref" />
<fileset dir="hapi-fhir-jpaserver-base/target/site/xref"/>
</copy>
<copy todir="target/site/xref-base">
<fileset dir="hapi-fhir-base/target/site/xref" />
<fileset dir="hapi-fhir-base/target/site/xref"/>
</copy>
<!-- <copy todir="target/site/cobertura"> <fileset dir="hapi-fhir-cobertura/target/site/cobertura" /> </copy> -->
<copy todir="target/site">
<fileset dir="hapi-fhir-base/target/site" includes="checkstyle.*" />
<fileset dir="hapi-fhir-base/target/site" includes="checkstyle.*"/>
</copy>
<echo>Fixing Checkstyle Report</echo>
<replace dir="target/site" summary="true">
<include name="checkstyle.html" />
<include name="checkstyle.html"/>
<replacetoken>"../../</replacetoken>
<replacevalue>"./</replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="*.html" />
<include name="*.html"/>
<replacetoken>http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-responsive.min.css</replacetoken>
<replacevalue>./css/bootstrap-responsive.min.css</replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="index.html" />
<include name="index.html"/>
<replacetoken><![CDATA[<h2 id="Welcome">Welcome</h2>]]></replacetoken>
<replacevalue><![CDATA[<div class="jumbotron subhead">
<div class="row" id="banner">
@ -988,33 +988,33 @@
<target>
<echo>Adding Fontawesome</echo>
<replace dir="target/site" summary="true">
<include name="*.html" />
<include name="*.html"/>
<replacetoken><![CDATA[<a href="download.html" title="Download">Download</a>]]></replacetoken>
<replacevalue><![CDATA[<a href="download.html" title="Download"><i class="fa fa-download"></i> Download</a>]]></replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="*.html" />
<include name="*.html"/>
<replacetoken><![CDATA[<a href="https://github.com/jamesagnew/hapi-fhir/" title="GitHub Project" class="externalLink">GitHub Project</a>]]></replacetoken>
<replacevalue><![CDATA[<a href="https://github.com/jamesagnew/hapi-fhir/" title="GitHub Project" class="externalLink"><i class="fa fa-github"></i> GitHub Project</a>]]></replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="*.html" />
<include name="*.html"/>
<replacetoken><![CDATA[data-toggle="dropdown">Test Servers <]]></replacetoken>
<replacevalue><![CDATA[data-toggle="dropdown"><i class="fa fa-fire"></i>&nbsp;Test Servers&nbsp;<]]></replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="*.html" />
<include name="*.html"/>
<replacetoken><![CDATA[data-toggle="dropdown">Documentation <]]></replacetoken>
<replacevalue><![CDATA[data-toggle="dropdown"><i class="fa fa-book"></i>&nbsp;Documentation&nbsp;<]]></replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="*.html" />
<include name="*.html"/>
<replacetoken><![CDATA[data-toggle="dropdown">Get Help <]]></replacetoken>
<replacevalue><![CDATA[data-toggle="dropdown"><i class="fa fa-support"></i>&nbsp;Get Help&nbsp;<]]></replacevalue>
</replace>
<echo>Changing Breadcrumbs</echo>
<replace dir="target/site" summary="true">
<include name="doc_*.html" />
<include name="doc_*.html"/>
<replacetoken><![CDATA[<li class="divider">/</li>]]></replacetoken>
<replacevalue><![CDATA[<li class="divider">/</li>
<li><a href="docindex.html" title="Documentation">Documentation</a></li>
@ -1065,8 +1065,8 @@
<echo>Adding Google analytics in target/site for &lt;body&gt;</echo>
<replace dir="target/site" summary="true">
<include name="**/*.html"></include>
<replacefilter token="#build#" value="${label}" />
<replacefilter token="#version#" value="${project.version}" />
<replacefilter token="#build#" value="${label}"/>
<replacefilter token="#version#" value="${project.version}"/>
<replacetoken><![CDATA[</body>]]></replacetoken>
<replacevalue><![CDATA[
<script>
@ -1204,9 +1204,8 @@
<reporting>
<plugins>
<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-checkstyle-plugin</artifactId> <reportSets> <reportSet> <reports><report>checkstyle-aggregate</report></reports>
</reportSet> </reportSets> <configuration> <configLocation>config/sun_checks.xml</configLocation> <includes> hapi-fhir-base/src/main/java/**/*.java </includes> </configuration>
</plugin> -->
<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-checkstyle-plugin</artifactId> <reportSets> <reportSet> <reports><report>checkstyle-aggregate</report></reports> </reportSet>
</reportSets> <configuration> <configLocation>config/sun_checks.xml</configLocation> <includes> hapi-fhir-base/src/main/java/**/*.java </includes> </configuration> </plugin> -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-changes-plugin</artifactId>
@ -1281,9 +1280,8 @@
</modules>
<build>
<plugins>
<!-- <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>${maven_assembly_plugin_version}</version> <executions> <execution> <phase>package</phase>
<goals> <goal>single</goal> </goals> <configuration> <attach>false</attach> <descriptors> <descriptor>${project.basedir}/src/assembly/hapi-fhir-sample-projects.xml</descriptor>
</descriptors> </configuration> </execution> </executions> </plugin> -->
<!-- <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>${maven_assembly_plugin_version}</version> <executions> <execution> <phase>package</phase> <goals> <goal>single</goal> </goals>
<configuration> <attach>false</attach> <descriptors> <descriptor>${project.basedir}/src/assembly/hapi-fhir-sample-projects.xml</descriptor> </descriptors> </configuration> </execution> </executions> </plugin> -->
</plugins>
</build>

View File

@ -212,7 +212,7 @@
<![CDATA[<a href="./apidocs-jpaserver/ca/uhn/fhir/jpa/dao/IJpaServerInterceptor.html">IJpaServerInterceptor</a>]]>
interceptors for JPA server which can be used for more fine grained operations.
</action>
<action type="fix">
<action type="fix" issue="241">
Parser (XML and JSON) shouldn't encode an ID tag in resources
which are part of a bundle when the resource has a UUID/OID
ID.
@ -222,6 +222,11 @@
to declare that it should allow even parameters it doesn't
understand.
</action>
<action type="fix" issue="247">
Correctly set the Bundle.type value on all pages of a search result in
the server, and correcltly set the same value in JPA server $everything
results.
</action>
</release>
<release version="1.2" date="2015-09-18">
<action type="add">