More perf work
This commit is contained in:
parent
62ece72e6f
commit
217d9f8176
|
@ -696,7 +696,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
search.setResourceType(resourceName);
|
search.setResourceType(resourceName);
|
||||||
search.setResourceId(theId);
|
search.setResourceId(theId);
|
||||||
search.setSearchType(SearchTypeEnum.HISTORY);
|
search.setSearchType(SearchTypeEnum.HISTORY);
|
||||||
|
search.setStatus(SearchStatusEnum.FINISHED);
|
||||||
|
|
||||||
if (theSince != null) {
|
if (theSince != null) {
|
||||||
if (resourceName == null) {
|
if (resourceName == null) {
|
||||||
search.setTotalCount(myResourceHistoryTableDao.countForAllResourceTypes(theSince));
|
search.setTotalCount(myResourceHistoryTableDao.countForAllResourceTypes(theSince));
|
||||||
|
|
|
@ -593,87 +593,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public IBundleProvider everything(IIdType theId) {
|
|
||||||
// Search search = new Search();
|
|
||||||
// search.setUuid(UUID.randomUUID().toString());
|
|
||||||
// search.setCreated(new Date());
|
|
||||||
// myEntityManager.persist(search);
|
|
||||||
//
|
|
||||||
// List<SearchResult> results = new ArrayList<SearchResult>();
|
|
||||||
// if (theId != null) {
|
|
||||||
// Long pid = translateForcedIdToPid(theId);
|
|
||||||
// ResourceTable entity = myEntityManager.find(ResourceTable.class, pid);
|
|
||||||
// validateGivenIdIsAppropriateToRetrieveResource(theId, entity);
|
|
||||||
// SearchResult res = new SearchResult(search);
|
|
||||||
// res.setResourcePid(pid);
|
|
||||||
// results.add(res);
|
|
||||||
// } else {
|
|
||||||
// TypedQuery<Tuple> query = createSearchAllByTypeQuery();
|
|
||||||
// for (Tuple next : query.getResultList()) {
|
|
||||||
// SearchResult res = new SearchResult(search);
|
|
||||||
// res.setResourcePid(next.get(0, Long.class));
|
|
||||||
// results.add(res);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// int totalCount = results.size();
|
|
||||||
// mySearchResultDao.save(results);
|
|
||||||
// mySearchResultDao.flush();
|
|
||||||
//
|
|
||||||
// CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
|
||||||
//
|
|
||||||
// // Load _revincludes
|
|
||||||
// CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
|
||||||
// Root<ResourceLink> from = cq.from(ResourceLink.class);
|
|
||||||
// cq.select(from.get("mySourceResourcePid").as(Long.class));
|
|
||||||
//
|
|
||||||
// Subquery<Long> pidsSubquery = cq.subquery(Long.class);
|
|
||||||
// Root<SearchResult> pidsSubqueryFrom = pidsSubquery.from(SearchResult.class);
|
|
||||||
// pidsSubquery.select(pidsSubqueryFrom.get("myResourcePid").as(Long.class));
|
|
||||||
// pidsSubquery.where(pidsSubqueryFrom.get("mySearch").in(search));
|
|
||||||
//
|
|
||||||
// cq.where(from.get("myTargetResourceId").in(pidsSubquery));
|
|
||||||
// TypedQuery<Long> query = myEntityManager.createQuery(cq);
|
|
||||||
//
|
|
||||||
// results = new ArrayList<SearchResult>();
|
|
||||||
// for (Long next : query.getResultList()) {
|
|
||||||
// SearchResult res = new SearchResult(search);
|
|
||||||
// res.setResourcePid(next);
|
|
||||||
// results.add(res);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Save _revincludes
|
|
||||||
// totalCount += results.size();
|
|
||||||
// mySearchResultDao.save(results);
|
|
||||||
// mySearchResultDao.flush();
|
|
||||||
//
|
|
||||||
// final int finalTotalCount = totalCount;
|
|
||||||
// return new IBundleProvider() {
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public int size() {
|
|
||||||
// return finalTotalCount;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public Integer preferredPageSize() {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
|
|
||||||
// // TODO Auto-generated method stub
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public InstantDt getPublished() {
|
|
||||||
// // TODO Auto-generated method stub
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <MT extends IBaseMetaType> MT metaGetOperation(Class<MT> theType, IIdType theId, RequestDetails theRequestDetails) {
|
public <MT extends IBaseMetaType> MT metaGetOperation(Class<MT> theType, IIdType theId, RequestDetails theRequestDetails) {
|
||||||
|
|
|
@ -1315,8 +1315,10 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
@Override
|
@Override
|
||||||
public Long next() {
|
public Long next() {
|
||||||
fetchNext();
|
fetchNext();
|
||||||
Validate.isTrue(myNext != NO_MORE, "No more elements");
|
Long retVal = myNext;
|
||||||
return myNext;
|
myNext = null;
|
||||||
|
Validate.isTrue(retVal != NO_MORE, "No more elements");
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -268,6 +268,8 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void call() throws Exception {
|
public Void call() throws Exception {
|
||||||
|
StopWatch sw = new StopWatch();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
||||||
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);
|
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);
|
||||||
|
@ -277,14 +279,18 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
doSearch();
|
doSearch();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ourLog.info("Completed search for {} resources in {}ms", mySyncedPids.size(), sw.getMillis());
|
||||||
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
ourLog.error("Failed during search loading", t);
|
ourLog.error("Failed during search loading after {}ms", t, sw.getMillis());
|
||||||
myUnsyncedPids.clear();
|
myUnsyncedPids.clear();
|
||||||
|
|
||||||
mySearch.setStatus(SearchStatusEnum.FAILED);
|
mySearch.setStatus(SearchStatusEnum.FAILED);
|
||||||
String failureMessage = ExceptionUtils.getRootCauseMessage(t);
|
String failureMessage = ExceptionUtils.getRootCauseMessage(t);
|
||||||
mySearch.setFailureMessage(failureMessage);
|
mySearch.setFailureMessage(failureMessage);
|
||||||
saveSearch();
|
saveSearch();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
myIdToSearchTask.remove(mySearch.getUuid());
|
myIdToSearchTask.remove(mySearch.getUuid());
|
||||||
|
|
|
@ -308,9 +308,6 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCountParam() throws Exception {
|
public void testCountParam() throws Exception {
|
||||||
// NB this does not get used- The paging provider has its own limits built in
|
|
||||||
myDaoConfig.setHardSearchLimit(100);
|
|
||||||
|
|
||||||
List<IBaseResource> resources = new ArrayList<IBaseResource>();
|
List<IBaseResource> resources = new ArrayList<IBaseResource>();
|
||||||
for (int i = 0; i < 100; i++) {
|
for (int i = 0; i < 100; i++) {
|
||||||
Organization org = new Organization();
|
Organization org = new Organization();
|
||||||
|
@ -1611,6 +1608,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
assertEquals(77, ids.size());
|
assertEquals(77, ids.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@Test
|
@Test
|
||||||
public void testFullTextSearch() throws RuntimeException, Exception {
|
public void testFullTextSearch() throws RuntimeException, Exception {
|
||||||
Observation obs1 = new Observation();
|
Observation obs1 = new Observation();
|
||||||
|
@ -1920,6 +1918,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@Test
|
@Test
|
||||||
public void testMetadataSuperParamsAreIncluded() throws IOException {
|
public void testMetadataSuperParamsAreIncluded() throws IOException {
|
||||||
StructureDefinition p = new StructureDefinition();
|
StructureDefinition p = new StructureDefinition();
|
||||||
|
@ -2622,6 +2621,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@Test
|
@Test
|
||||||
public void testSearchPagingKeepsOldSearches() throws Exception {
|
public void testSearchPagingKeepsOldSearches() throws Exception {
|
||||||
String methodName = "testSearchPagingKeepsOldSearches";
|
String methodName = "testSearchPagingKeepsOldSearches";
|
||||||
|
|
|
@ -60,6 +60,23 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
myContext = theContext;
|
myContext = theContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addProfileIfNeeded(IRestfulServer<?> theServer, String theServerBase, IBaseResource nextRes) {
|
||||||
|
RuntimeResourceDefinition def = theServer.getFhirContext().getResourceDefinition(nextRes);
|
||||||
|
if (theServer.getAddProfileTag() == AddProfileTagEnum.ALWAYS || !def.isStandardType()) {
|
||||||
|
TagList tl = ResourceMetadataKeyEnum.TAG_LIST.get((IResource) nextRes);
|
||||||
|
if (tl == null) {
|
||||||
|
tl = new TagList();
|
||||||
|
ResourceMetadataKeyEnum.TAG_LIST.put((IResource) nextRes, tl);
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeResourceDefinition nextDef = myContext.getResourceDefinition(nextRes);
|
||||||
|
String profile = nextDef.getResourceProfile(theServerBase);
|
||||||
|
if (isNotBlank(profile)) {
|
||||||
|
tl.add(new Tag(Tag.HL7_ORG_PROFILE_TAG, profile, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||||
if (myBundle == null) {
|
if (myBundle == null) {
|
||||||
|
@ -149,7 +166,7 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
myBundle.getAuthorName().setValue(theAuthor);
|
myBundle.getAuthorName().setValue(theAuthor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (myBundle.getUpdated().isEmpty() && isNotBlank(theLastUpdated.getValueAsString())) {
|
if (theLastUpdated != null && myBundle.getUpdated().isEmpty() && isNotBlank(theLastUpdated.getValueAsString())) {
|
||||||
myBundle.getUpdated().setValueAsString(theLastUpdated.getValueAsString());
|
myBundle.getUpdated().setValueAsString(theLastUpdated.getValueAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,27 +207,31 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
int numToReturn;
|
int numToReturn;
|
||||||
String searchId = null;
|
String searchId = null;
|
||||||
List<IBaseResource> resourceList;
|
List<IBaseResource> resourceList;
|
||||||
|
Integer numTotalResults = theResult.size();
|
||||||
if (theServer.getPagingProvider() == null) {
|
if (theServer.getPagingProvider() == null) {
|
||||||
numToReturn = theResult.size();
|
numToReturn = numTotalResults;
|
||||||
resourceList = theResult.getResources(0, numToReturn);
|
resourceList = theResult.getResources(0, numToReturn);
|
||||||
RestfulServerUtils.validateResourceListNotNull(resourceList);
|
RestfulServerUtils.validateResourceListNotNull(resourceList);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
IPagingProvider pagingProvider = theServer.getPagingProvider();
|
IPagingProvider pagingProvider = theServer.getPagingProvider();
|
||||||
if (theLimit == null) {
|
if (theLimit == null || theLimit.equals(Integer.valueOf(0))) {
|
||||||
numToReturn = pagingProvider.getDefaultPageSize();
|
numToReturn = pagingProvider.getDefaultPageSize();
|
||||||
} else {
|
} else {
|
||||||
numToReturn = Math.min(pagingProvider.getMaximumPageSize(), theLimit);
|
numToReturn = Math.min(pagingProvider.getMaximumPageSize(), theLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
numToReturn = Math.min(numToReturn, theResult.size() - theOffset);
|
if (numTotalResults != null) {
|
||||||
|
numToReturn = Math.min(numToReturn, numTotalResults - theOffset);
|
||||||
|
}
|
||||||
|
|
||||||
resourceList = theResult.getResources(theOffset, numToReturn + theOffset);
|
resourceList = theResult.getResources(theOffset, numToReturn + theOffset);
|
||||||
RestfulServerUtils.validateResourceListNotNull(resourceList);
|
RestfulServerUtils.validateResourceListNotNull(resourceList);
|
||||||
|
|
||||||
if (theSearchId != null) {
|
if (theSearchId != null) {
|
||||||
searchId = theSearchId;
|
searchId = theSearchId;
|
||||||
} else {
|
} else {
|
||||||
if (theResult.size() > numToReturn) {
|
if (numTotalResults == null || numTotalResults > numToReturn) {
|
||||||
searchId = pagingProvider.storeResultList(theResult);
|
searchId = pagingProvider.storeResultList(theResult);
|
||||||
Validate.notNull(searchId, "Paging provider returned null searchId");
|
Validate.notNull(searchId, "Paging provider returned null searchId");
|
||||||
}
|
}
|
||||||
|
@ -230,7 +251,7 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
|
|
||||||
|
|
||||||
addResourcesToBundle(new ArrayList<IBaseResource>(resourceList), theBundleType, theServerBase, theServer.getBundleInclusionRule(), theIncludes);
|
addResourcesToBundle(new ArrayList<IBaseResource>(resourceList), theBundleType, theServerBase, theServer.getBundleInclusionRule(), theIncludes);
|
||||||
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType, theResult.getPublished());
|
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, numTotalResults, theBundleType, theResult.getPublished());
|
||||||
|
|
||||||
if (theServer.getPagingProvider() != null) {
|
if (theServer.getPagingProvider() != null) {
|
||||||
int limit;
|
int limit;
|
||||||
|
@ -238,7 +259,7 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
limit = Math.min(limit, theServer.getPagingProvider().getMaximumPageSize());
|
limit = Math.min(limit, theServer.getPagingProvider().getMaximumPageSize());
|
||||||
|
|
||||||
if (searchId != null) {
|
if (searchId != null) {
|
||||||
if (theOffset + numToReturn < theResult.size()) {
|
if (numTotalResults == null || theOffset + numToReturn < numTotalResults) {
|
||||||
myBundle.getLinkNext()
|
myBundle.getLinkNext()
|
||||||
.setValue(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, theOffset + numToReturn, numToReturn, theResponseEncoding, thePrettyPrint, theBundleType));
|
.setValue(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, theOffset + numToReturn, numToReturn, theResponseEncoding, thePrettyPrint, theBundleType));
|
||||||
}
|
}
|
||||||
|
@ -250,23 +271,6 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addProfileIfNeeded(IRestfulServer<?> theServer, String theServerBase, IBaseResource nextRes) {
|
|
||||||
RuntimeResourceDefinition def = theServer.getFhirContext().getResourceDefinition(nextRes);
|
|
||||||
if (theServer.getAddProfileTag() == AddProfileTagEnum.ALWAYS || !def.isStandardType()) {
|
|
||||||
TagList tl = ResourceMetadataKeyEnum.TAG_LIST.get((IResource) nextRes);
|
|
||||||
if (tl == null) {
|
|
||||||
tl = new TagList();
|
|
||||||
ResourceMetadataKeyEnum.TAG_LIST.put((IResource) nextRes, tl);
|
|
||||||
}
|
|
||||||
|
|
||||||
RuntimeResourceDefinition nextDef = myContext.getResourceDefinition(nextRes);
|
|
||||||
String profile = nextDef.getResourceProfile(theServerBase);
|
|
||||||
if (isNotBlank(profile)) {
|
|
||||||
tl.add(new Tag(Tag.HL7_ORG_PROFILE_TAG, profile, null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResult, String theServerBase, String theCompleteUrl, int theTotalResults,
|
public void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResult, String theServerBase, String theCompleteUrl, int theTotalResults,
|
||||||
BundleTypeEnum theBundleType) {
|
BundleTypeEnum theBundleType) {
|
||||||
|
|
|
@ -0,0 +1,186 @@
|
||||||
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
|
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHandler;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.model.api.Bundle;
|
||||||
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
|
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||||
|
import ca.uhn.fhir.util.PortUtil;
|
||||||
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
|
||||||
|
public class SearchBundleProviderWithNoSizeDstu1Test {
|
||||||
|
|
||||||
|
private static CloseableHttpClient ourClient;
|
||||||
|
private static FhirContext ourCtx = FhirContext.forDstu1();
|
||||||
|
private static TokenAndListParam ourIdentifiers;
|
||||||
|
private static IBundleProvider ourLastBundleProvider;
|
||||||
|
private static String ourLastMethod;
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchBundleProviderWithNoSizeDstu1Test.class);
|
||||||
|
private static int ourPort;
|
||||||
|
|
||||||
|
private static Server ourServer;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
ourLastMethod = null;
|
||||||
|
ourIdentifiers = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBundleProviderReturnsNoSize() throws Exception {
|
||||||
|
Bundle respBundle;
|
||||||
|
|
||||||
|
ourLastBundleProvider = mock(IBundleProvider.class);
|
||||||
|
when(ourLastBundleProvider.size()).thenReturn(null);
|
||||||
|
when(ourLastBundleProvider.getResources(any(int.class), any(int.class))).then(new Answer<List<IBaseResource>>() {
|
||||||
|
@Override
|
||||||
|
public List<IBaseResource> answer(InvocationOnMock theInvocation) throws Throwable {
|
||||||
|
int from =(Integer)theInvocation.getArguments()[0];
|
||||||
|
int to =(Integer)theInvocation.getArguments()[1];
|
||||||
|
ArrayList<IBaseResource> retVal = Lists.newArrayList();
|
||||||
|
for (int i = from; i < to; i++) {
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setId(Integer.toString(i));
|
||||||
|
retVal.add(p);
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}});
|
||||||
|
|
||||||
|
HttpGet httpGet;
|
||||||
|
CloseableHttpResponse status = null;
|
||||||
|
StringDt linkNext;
|
||||||
|
|
||||||
|
try {
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=json");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals("searchAll", ourLastMethod);
|
||||||
|
respBundle = ourCtx.newJsonParser().parseBundle(responseContent);
|
||||||
|
|
||||||
|
assertEquals(10, respBundle.getEntries().size());
|
||||||
|
assertEquals("Patient/0", respBundle.getEntries().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||||
|
linkNext = respBundle.getLinkNext();
|
||||||
|
assertNotNull(linkNext.getValue());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
when(ourLastBundleProvider.size()).thenReturn(25);
|
||||||
|
|
||||||
|
try {
|
||||||
|
httpGet = new HttpGet(linkNext.getValue());
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals("searchAll", ourLastMethod);
|
||||||
|
respBundle = ourCtx.newJsonParser().parseBundle(responseContent);
|
||||||
|
|
||||||
|
assertEquals(10, respBundle.getEntries().size());
|
||||||
|
assertEquals("Patient/10", respBundle.getEntries().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||||
|
linkNext = respBundle.getLinkNext();
|
||||||
|
assertNotNull(linkNext.getValue());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
httpGet = new HttpGet(linkNext.getValue());
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals("searchAll", ourLastMethod);
|
||||||
|
respBundle = ourCtx.newJsonParser().parseBundle(responseContent);
|
||||||
|
|
||||||
|
assertEquals(5, respBundle.getEntries().size());
|
||||||
|
assertEquals("Patient/20", respBundle.getEntries().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||||
|
linkNext = respBundle.getLinkNext();
|
||||||
|
assertNull(linkNext.getValue());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() throws Exception {
|
||||||
|
ourServer.stop();
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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(ourCtx);
|
||||||
|
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
|
||||||
|
|
||||||
|
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 {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
|
return Patient.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Search()
|
||||||
|
public IBundleProvider searchAll() {
|
||||||
|
ourLastMethod = "searchAll";
|
||||||
|
return ourLastBundleProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -306,8 +306,9 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
int numToReturn;
|
int numToReturn;
|
||||||
String searchId = null;
|
String searchId = null;
|
||||||
List<IBaseResource> resourceList;
|
List<IBaseResource> resourceList;
|
||||||
|
Integer numTotalResults = theResult.size();
|
||||||
if (theServer.getPagingProvider() == null) {
|
if (theServer.getPagingProvider() == null) {
|
||||||
numToReturn = theResult.size();
|
numToReturn = numTotalResults;
|
||||||
if (numToReturn > 0) {
|
if (numToReturn > 0) {
|
||||||
resourceList = theResult.getResources(0, numToReturn);
|
resourceList = theResult.getResources(0, numToReturn);
|
||||||
} else {
|
} else {
|
||||||
|
@ -317,13 +318,16 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
IPagingProvider pagingProvider = theServer.getPagingProvider();
|
IPagingProvider pagingProvider = theServer.getPagingProvider();
|
||||||
if (theLimit == null) {
|
if (theLimit == null || theLimit.equals(Integer.valueOf(0))) {
|
||||||
numToReturn = pagingProvider.getDefaultPageSize();
|
numToReturn = pagingProvider.getDefaultPageSize();
|
||||||
} else {
|
} else {
|
||||||
numToReturn = Math.min(pagingProvider.getMaximumPageSize(), theLimit);
|
numToReturn = Math.min(pagingProvider.getMaximumPageSize(), theLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
numToReturn = Math.min(numToReturn, theResult.size() - theOffset);
|
if (numTotalResults != null) {
|
||||||
|
numToReturn = Math.min(numToReturn, numTotalResults - theOffset);
|
||||||
|
}
|
||||||
|
|
||||||
if (numToReturn > 0) {
|
if (numToReturn > 0) {
|
||||||
resourceList = theResult.getResources(theOffset, numToReturn + theOffset);
|
resourceList = theResult.getResources(theOffset, numToReturn + theOffset);
|
||||||
} else {
|
} else {
|
||||||
|
@ -334,7 +338,7 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
if (theSearchId != null) {
|
if (theSearchId != null) {
|
||||||
searchId = theSearchId;
|
searchId = theSearchId;
|
||||||
} else {
|
} else {
|
||||||
if (theResult.size() > numToReturn) {
|
if (numTotalResults == null || numTotalResults > numToReturn) {
|
||||||
searchId = pagingProvider.storeResultList(theResult);
|
searchId = pagingProvider.storeResultList(theResult);
|
||||||
Validate.notNull(searchId, "Paging provider returned null searchId");
|
Validate.notNull(searchId, "Paging provider returned null searchId");
|
||||||
}
|
}
|
||||||
|
@ -350,7 +354,7 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
addResourcesToBundle(new ArrayList<IBaseResource>(resourceList), theBundleType, theServerBase, theServer.getBundleInclusionRule(), theIncludes);
|
addResourcesToBundle(new ArrayList<IBaseResource>(resourceList), theBundleType, theServerBase, theServer.getBundleInclusionRule(), theIncludes);
|
||||||
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType, theResult.getPublished());
|
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, numTotalResults, theBundleType, theResult.getPublished());
|
||||||
|
|
||||||
if (theServer.getPagingProvider() != null) {
|
if (theServer.getPagingProvider() != null) {
|
||||||
int limit;
|
int limit;
|
||||||
|
@ -358,7 +362,7 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
limit = Math.min(limit, theServer.getPagingProvider().getMaximumPageSize());
|
limit = Math.min(limit, theServer.getPagingProvider().getMaximumPageSize());
|
||||||
|
|
||||||
if (searchId != null) {
|
if (searchId != null) {
|
||||||
if (theOffset + numToReturn < theResult.size()) {
|
if (numTotalResults == null || theOffset + numToReturn < numTotalResults) {
|
||||||
myBundle.addLink().setRelation(Constants.LINK_NEXT)
|
myBundle.addLink().setRelation(Constants.LINK_NEXT)
|
||||||
.setUrl(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, theOffset + numToReturn, numToReturn, theResponseEncoding, thePrettyPrint, theBundleType));
|
.setUrl(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, theOffset + numToReturn, numToReturn, theResponseEncoding, thePrettyPrint, theBundleType));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,186 @@
|
||||||
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
|
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHandler;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
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.rest.annotation.RequiredParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||||
|
import ca.uhn.fhir.util.PortUtil;
|
||||||
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
|
||||||
|
public class SearchBundleProviderWithNoSizeDstu2Test {
|
||||||
|
|
||||||
|
private static CloseableHttpClient ourClient;
|
||||||
|
private static FhirContext ourCtx = FhirContext.forDstu2();
|
||||||
|
private static TokenAndListParam ourIdentifiers;
|
||||||
|
private static IBundleProvider ourLastBundleProvider;
|
||||||
|
private static String ourLastMethod;
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchBundleProviderWithNoSizeDstu2Test.class);
|
||||||
|
private static int ourPort;
|
||||||
|
|
||||||
|
private static Server ourServer;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
ourLastMethod = null;
|
||||||
|
ourIdentifiers = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBundleProviderReturnsNoSize() throws Exception {
|
||||||
|
Bundle respBundle;
|
||||||
|
|
||||||
|
ourLastBundleProvider = mock(IBundleProvider.class);
|
||||||
|
when(ourLastBundleProvider.size()).thenReturn(null);
|
||||||
|
when(ourLastBundleProvider.getResources(any(int.class), any(int.class))).then(new Answer<List<IBaseResource>>() {
|
||||||
|
@Override
|
||||||
|
public List<IBaseResource> answer(InvocationOnMock theInvocation) throws Throwable {
|
||||||
|
int from =(Integer)theInvocation.getArguments()[0];
|
||||||
|
int to =(Integer)theInvocation.getArguments()[1];
|
||||||
|
ArrayList<IBaseResource> retVal = Lists.newArrayList();
|
||||||
|
for (int i = from; i < to; i++) {
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setId(Integer.toString(i));
|
||||||
|
retVal.add(p);
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}});
|
||||||
|
|
||||||
|
HttpGet httpGet;
|
||||||
|
CloseableHttpResponse status = null;
|
||||||
|
Link linkNext;
|
||||||
|
|
||||||
|
try {
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=json");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals("searchAll", ourLastMethod);
|
||||||
|
respBundle = ourCtx.newJsonParser().parseResource(Bundle.class, responseContent);
|
||||||
|
|
||||||
|
assertEquals(10, respBundle.getEntry().size());
|
||||||
|
assertEquals("Patient/0", respBundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||||
|
linkNext = respBundle.getLink("next");
|
||||||
|
assertNotNull(linkNext);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
when(ourLastBundleProvider.size()).thenReturn(25);
|
||||||
|
|
||||||
|
try {
|
||||||
|
httpGet = new HttpGet(linkNext.getUrl());
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals("searchAll", ourLastMethod);
|
||||||
|
respBundle = ourCtx.newJsonParser().parseResource(Bundle.class, responseContent);
|
||||||
|
|
||||||
|
assertEquals(10, respBundle.getEntry().size());
|
||||||
|
assertEquals("Patient/10", respBundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||||
|
linkNext = respBundle.getLink("next");
|
||||||
|
assertNotNull(linkNext);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
httpGet = new HttpGet(linkNext.getUrl());
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals("searchAll", ourLastMethod);
|
||||||
|
respBundle = ourCtx.newJsonParser().parseResource(Bundle.class, responseContent);
|
||||||
|
|
||||||
|
assertEquals(5, respBundle.getEntry().size());
|
||||||
|
assertEquals("Patient/20", respBundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||||
|
linkNext = respBundle.getLink("next");
|
||||||
|
assertNull(linkNext);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() throws Exception {
|
||||||
|
ourServer.stop();
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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(ourCtx);
|
||||||
|
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
|
||||||
|
|
||||||
|
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 {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
|
return Patient.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Search()
|
||||||
|
public IBundleProvider searchAll() {
|
||||||
|
ourLastMethod = "searchAll";
|
||||||
|
return ourLastBundleProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ package org.hl7.fhir.dstu3.hapi.rest.server;
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@ -45,388 +45,392 @@ import ca.uhn.fhir.util.ResourceReferenceInfo;
|
||||||
|
|
||||||
public class Dstu3BundleFactory implements IVersionSpecificBundleFactory {
|
public class Dstu3BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
|
|
||||||
private Bundle myBundle;
|
private Bundle myBundle;
|
||||||
private FhirContext myContext;
|
private FhirContext myContext;
|
||||||
private String myBase;
|
private String myBase;
|
||||||
|
|
||||||
public Dstu3BundleFactory(FhirContext theContext) {
|
public Dstu3BundleFactory(FhirContext theContext) {
|
||||||
myContext = theContext;
|
myContext = theContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addResourcesForSearch(List<? extends IBaseResource> theResult) {
|
private void addResourcesForSearch(List<? extends IBaseResource> theResult) {
|
||||||
List<IBaseResource> includedResources = new ArrayList<IBaseResource>();
|
List<IBaseResource> includedResources = new ArrayList<IBaseResource>();
|
||||||
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
||||||
|
|
||||||
for (IBaseResource next : theResult) {
|
for (IBaseResource next : theResult) {
|
||||||
if (next.getIdElement().isEmpty() == false) {
|
if (next.getIdElement().isEmpty() == false) {
|
||||||
addedResourceIds.add(next.getIdElement());
|
addedResourceIds.add(next.getIdElement());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (IBaseResource nextBaseRes : theResult) {
|
for (IBaseResource nextBaseRes : theResult) {
|
||||||
Resource next = (Resource) nextBaseRes;
|
Resource next = (Resource) nextBaseRes;
|
||||||
Set<String> containedIds = new HashSet<String>();
|
Set<String> containedIds = new HashSet<String>();
|
||||||
if (next instanceof DomainResource) {
|
if (next instanceof DomainResource) {
|
||||||
for (Resource nextContained : ((DomainResource)next).getContained()) {
|
for (Resource nextContained : ((DomainResource) next).getContained()) {
|
||||||
if (nextContained.getIdElement().isEmpty() == false) {
|
if (nextContained.getIdElement().isEmpty() == false) {
|
||||||
containedIds.add(nextContained.getIdElement().getValue());
|
containedIds.add(nextContained.getIdElement().getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<IBaseReference> references = myContext.newTerser().getAllPopulatedChildElementsOfType(next, IBaseReference.class);
|
|
||||||
do {
|
|
||||||
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
|
||||||
|
|
||||||
for (IBaseReference nextRef : references) {
|
List<IBaseReference> references = myContext.newTerser().getAllPopulatedChildElementsOfType(next, IBaseReference.class);
|
||||||
IAnyResource nextRes = (IAnyResource) nextRef.getResource();
|
do {
|
||||||
if (nextRes != null) {
|
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
||||||
if (nextRes.getIdElement().hasIdPart()) {
|
|
||||||
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
|
||||||
// Don't add contained IDs as top level resources
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
IIdType id = nextRes.getIdElement();
|
for (IBaseReference nextRef : references) {
|
||||||
if (id.hasResourceType() == false) {
|
IAnyResource nextRes = (IAnyResource) nextRef.getResource();
|
||||||
String resName = myContext.getResourceDefinition(nextRes).getName();
|
if (nextRes != null) {
|
||||||
id = id.withResourceType(resName);
|
if (nextRes.getIdElement().hasIdPart()) {
|
||||||
}
|
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
||||||
|
// Don't add contained IDs as top level resources
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!addedResourceIds.contains(id)) {
|
IIdType id = nextRes.getIdElement();
|
||||||
addedResourceIds.add(id);
|
if (id.hasResourceType() == false) {
|
||||||
addedResourcesThisPass.add(nextRes);
|
String resName = myContext.getResourceDefinition(nextRes).getName();
|
||||||
}
|
id = id.withResourceType(resName);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
if (!addedResourceIds.contains(id)) {
|
||||||
}
|
addedResourceIds.add(id);
|
||||||
}
|
addedResourcesThisPass.add(nextRes);
|
||||||
|
}
|
||||||
|
|
||||||
// Linked resources may themselves have linked resources
|
}
|
||||||
references = new ArrayList<IBaseReference>();
|
}
|
||||||
for (IAnyResource iResource : addedResourcesThisPass) {
|
}
|
||||||
List<IBaseReference> newReferences = myContext.newTerser().getAllPopulatedChildElementsOfType(iResource, IBaseReference.class);
|
|
||||||
references.addAll(newReferences);
|
|
||||||
}
|
|
||||||
|
|
||||||
includedResources.addAll(addedResourcesThisPass);
|
// Linked resources may themselves have linked resources
|
||||||
|
references = new ArrayList<IBaseReference>();
|
||||||
|
for (IAnyResource iResource : addedResourcesThisPass) {
|
||||||
|
List<IBaseReference> newReferences = myContext.newTerser().getAllPopulatedChildElementsOfType(iResource, IBaseReference.class);
|
||||||
|
references.addAll(newReferences);
|
||||||
|
}
|
||||||
|
|
||||||
} while (references.isEmpty() == false);
|
includedResources.addAll(addedResourcesThisPass);
|
||||||
|
|
||||||
BundleEntryComponent entry = myBundle.addEntry().setResource(next);
|
} while (references.isEmpty() == false);
|
||||||
if (next.getIdElement().hasBaseUrl()) {
|
|
||||||
entry.setFullUrl(next.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
String httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(next);
|
BundleEntryComponent entry = myBundle.addEntry().setResource(next);
|
||||||
if (httpVerb != null) {
|
if (next.getIdElement().hasBaseUrl()) {
|
||||||
entry.getRequest().getMethodElement().setValueAsString(httpVerb);
|
entry.setFullUrl(next.getId());
|
||||||
entry.getRequest().getUrlElement().setValue(next.getId());
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
String httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(next);
|
||||||
* Actually add the resources to the bundle
|
if (httpVerb != null) {
|
||||||
*/
|
entry.getRequest().getMethodElement().setValueAsString(httpVerb);
|
||||||
for (IBaseResource next : includedResources) {
|
entry.getRequest().getUrlElement().setValue(next.getId());
|
||||||
BundleEntryComponent entry = myBundle.addEntry();
|
}
|
||||||
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
}
|
||||||
if (next.getIdElement().hasBaseUrl()) {
|
|
||||||
entry.setFullUrl(next.getIdElement().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
/*
|
||||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
* Actually add the resources to the bundle
|
||||||
if (myBundle == null) {
|
*/
|
||||||
myBundle = new Bundle();
|
for (IBaseResource next : includedResources) {
|
||||||
}
|
BundleEntryComponent entry = myBundle.addEntry();
|
||||||
|
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
||||||
|
if (next.getIdElement().hasBaseUrl()) {
|
||||||
|
entry.setFullUrl(next.getIdElement().getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<IAnyResource> includedResources = new ArrayList<IAnyResource>();
|
@Override
|
||||||
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||||
|
if (myBundle == null) {
|
||||||
|
myBundle = new Bundle();
|
||||||
|
}
|
||||||
|
|
||||||
for (IBaseResource next : theResult) {
|
List<IAnyResource> includedResources = new ArrayList<IAnyResource>();
|
||||||
if (next.getIdElement().isEmpty() == false) {
|
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
||||||
addedResourceIds.add(next.getIdElement());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (IBaseResource next : theResult) {
|
for (IBaseResource next : theResult) {
|
||||||
|
if (next.getIdElement().isEmpty() == false) {
|
||||||
|
addedResourceIds.add(next.getIdElement());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Set<String> containedIds = new HashSet<String>();
|
for (IBaseResource next : theResult) {
|
||||||
|
|
||||||
if (next instanceof DomainResource) {
|
|
||||||
for (Resource nextContained : ((DomainResource)next).getContained()) {
|
|
||||||
if (isNotBlank(nextContained.getId())) {
|
|
||||||
containedIds.add(nextContained.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ResourceReferenceInfo> references = myContext.newTerser().getAllResourceReferences(next);
|
Set<String> containedIds = new HashSet<String>();
|
||||||
do {
|
|
||||||
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
|
||||||
|
|
||||||
for (ResourceReferenceInfo nextRefInfo : references) {
|
if (next instanceof DomainResource) {
|
||||||
if (!theBundleInclusionRule.shouldIncludeReferencedResource(nextRefInfo, theIncludes)) {
|
for (Resource nextContained : ((DomainResource) next).getContained()) {
|
||||||
continue;
|
if (isNotBlank(nextContained.getId())) {
|
||||||
}
|
containedIds.add(nextContained.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IAnyResource nextRes = (IAnyResource) nextRefInfo.getResourceReference().getResource();
|
List<ResourceReferenceInfo> references = myContext.newTerser().getAllResourceReferences(next);
|
||||||
if (nextRes != null) {
|
do {
|
||||||
if (nextRes.getIdElement().hasIdPart()) {
|
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
||||||
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
|
||||||
// Don't add contained IDs as top level resources
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
IIdType id = nextRes.getIdElement();
|
for (ResourceReferenceInfo nextRefInfo : references) {
|
||||||
if (id.hasResourceType() == false) {
|
if (!theBundleInclusionRule.shouldIncludeReferencedResource(nextRefInfo, theIncludes)) {
|
||||||
String resName = myContext.getResourceDefinition(nextRes).getName();
|
continue;
|
||||||
id = id.withResourceType(resName);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!addedResourceIds.contains(id)) {
|
IAnyResource nextRes = (IAnyResource) nextRefInfo.getResourceReference().getResource();
|
||||||
addedResourceIds.add(id);
|
if (nextRes != null) {
|
||||||
addedResourcesThisPass.add(nextRes);
|
if (nextRes.getIdElement().hasIdPart()) {
|
||||||
}
|
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
||||||
|
// Don't add contained IDs as top level resources
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
IIdType id = nextRes.getIdElement();
|
||||||
}
|
if (id.hasResourceType() == false) {
|
||||||
}
|
String resName = myContext.getResourceDefinition(nextRes).getName();
|
||||||
|
id = id.withResourceType(resName);
|
||||||
|
}
|
||||||
|
|
||||||
includedResources.addAll(addedResourcesThisPass);
|
if (!addedResourceIds.contains(id)) {
|
||||||
|
addedResourceIds.add(id);
|
||||||
|
addedResourcesThisPass.add(nextRes);
|
||||||
|
}
|
||||||
|
|
||||||
// Linked resources may themselves have linked resources
|
}
|
||||||
references = new ArrayList<ResourceReferenceInfo>();
|
}
|
||||||
for (IAnyResource iResource : addedResourcesThisPass) {
|
}
|
||||||
List<ResourceReferenceInfo> newReferences = myContext.newTerser().getAllResourceReferences(iResource);
|
|
||||||
references.addAll(newReferences);
|
|
||||||
}
|
|
||||||
} while (references.isEmpty() == false);
|
|
||||||
|
|
||||||
BundleEntryComponent entry = myBundle.addEntry().setResource((Resource) next);
|
includedResources.addAll(addedResourcesThisPass);
|
||||||
Resource nextAsResource = (Resource)next;
|
|
||||||
IIdType id = populateBundleEntryFullUrl(next, entry);
|
|
||||||
String httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(nextAsResource);
|
|
||||||
if (httpVerb != null) {
|
|
||||||
entry.getRequest().getMethodElement().setValueAsString(httpVerb);
|
|
||||||
if (id != null) {
|
|
||||||
entry.getRequest().setUrl(id.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String searchMode = ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(nextAsResource);
|
|
||||||
if (searchMode != null) {
|
|
||||||
entry.getSearch().getModeElement().setValueAsString(searchMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
// Linked resources may themselves have linked resources
|
||||||
* Actually add the resources to the bundle
|
references = new ArrayList<ResourceReferenceInfo>();
|
||||||
*/
|
for (IAnyResource iResource : addedResourcesThisPass) {
|
||||||
for (IAnyResource next : includedResources) {
|
List<ResourceReferenceInfo> newReferences = myContext.newTerser().getAllResourceReferences(iResource);
|
||||||
BundleEntryComponent entry = myBundle.addEntry();
|
references.addAll(newReferences);
|
||||||
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
}
|
||||||
populateBundleEntryFullUrl(next, entry);
|
} while (references.isEmpty() == false);
|
||||||
}
|
|
||||||
|
|
||||||
}
|
BundleEntryComponent entry = myBundle.addEntry().setResource((Resource) next);
|
||||||
|
Resource nextAsResource = (Resource) next;
|
||||||
|
IIdType id = populateBundleEntryFullUrl(next, entry);
|
||||||
|
String httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(nextAsResource);
|
||||||
|
if (httpVerb != null) {
|
||||||
|
entry.getRequest().getMethodElement().setValueAsString(httpVerb);
|
||||||
|
if (id != null) {
|
||||||
|
entry.getRequest().setUrl(id.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private IIdType populateBundleEntryFullUrl(IBaseResource next, BundleEntryComponent entry) {
|
String searchMode = ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(nextAsResource);
|
||||||
IIdType idElement = null;
|
if (searchMode != null) {
|
||||||
if (next.getIdElement().hasBaseUrl()) {
|
entry.getSearch().getModeElement().setValueAsString(searchMode);
|
||||||
idElement = next.getIdElement();
|
}
|
||||||
entry.setFullUrl(idElement.toVersionless().getValue());
|
}
|
||||||
} else {
|
|
||||||
if (isNotBlank(myBase) && next.getIdElement().hasIdPart()) {
|
|
||||||
idElement = next.getIdElement();
|
|
||||||
idElement = idElement.withServerBase(myBase, myContext.getResourceDefinition(next).getName());
|
|
||||||
entry.setFullUrl(idElement.toVersionless().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return idElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
/*
|
||||||
public void addRootPropertiesToBundle(String theAuthor, String theServerBase, String theCompleteUrl, Integer theTotalResults, BundleTypeEnum theBundleType, IPrimitiveType<Date> theLastUpdated) {
|
* Actually add the resources to the bundle
|
||||||
|
*/
|
||||||
|
for (IAnyResource next : includedResources) {
|
||||||
|
BundleEntryComponent entry = myBundle.addEntry();
|
||||||
|
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
||||||
|
populateBundleEntryFullUrl(next, entry);
|
||||||
|
}
|
||||||
|
|
||||||
myBase = theServerBase;
|
}
|
||||||
|
|
||||||
if (myBundle.getIdElement().isEmpty()) {
|
|
||||||
myBundle.setId(UUID.randomUUID().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myBundle.getMeta().getLastUpdated() == null && theLastUpdated != null) {
|
private IIdType populateBundleEntryFullUrl(IBaseResource next, BundleEntryComponent entry) {
|
||||||
myBundle.getMeta().getLastUpdatedElement().setValueAsString(theLastUpdated.getValueAsString());
|
IIdType idElement = null;
|
||||||
}
|
if (next.getIdElement().hasBaseUrl()) {
|
||||||
|
idElement = next.getIdElement();
|
||||||
|
entry.setFullUrl(idElement.toVersionless().getValue());
|
||||||
|
} else {
|
||||||
|
if (isNotBlank(myBase) && next.getIdElement().hasIdPart()) {
|
||||||
|
idElement = next.getIdElement();
|
||||||
|
idElement = idElement.withServerBase(myBase, myContext.getResourceDefinition(next).getName());
|
||||||
|
entry.setFullUrl(idElement.toVersionless().getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return idElement;
|
||||||
|
}
|
||||||
|
|
||||||
if (!hasLink(Constants.LINK_SELF, myBundle) && isNotBlank(theCompleteUrl)) {
|
@Override
|
||||||
myBundle.addLink().setRelation("self").setUrl(theCompleteUrl);
|
public void addRootPropertiesToBundle(String theAuthor, String theServerBase, String theCompleteUrl, Integer theTotalResults, BundleTypeEnum theBundleType, IPrimitiveType<Date> theLastUpdated) {
|
||||||
}
|
|
||||||
|
|
||||||
if (myBundle.getTypeElement().isEmpty() && theBundleType != null) {
|
myBase = theServerBase;
|
||||||
myBundle.getTypeElement().setValueAsString(theBundleType.getCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myBundle.getTotalElement().isEmpty() && theTotalResults != null) {
|
if (myBundle.getIdElement().isEmpty()) {
|
||||||
myBundle.getTotalElement().setValue(theTotalResults);
|
myBundle.setId(UUID.randomUUID().toString());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (myBundle.getMeta().getLastUpdated() == null && theLastUpdated != null) {
|
||||||
public ca.uhn.fhir.model.api.Bundle getDstu1Bundle() {
|
myBundle.getMeta().getLastUpdatedElement().setValueAsString(theLastUpdated.getValueAsString());
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (!hasLink(Constants.LINK_SELF, myBundle) && isNotBlank(theCompleteUrl)) {
|
||||||
public IBaseResource getResourceBundle() {
|
myBundle.addLink().setRelation("self").setUrl(theCompleteUrl);
|
||||||
return myBundle;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasLink(String theLinkType, Bundle theBundle) {
|
if (myBundle.getTypeElement().isEmpty() && theBundleType != null) {
|
||||||
for (BundleLinkComponent next : theBundle.getLink()) {
|
myBundle.getTypeElement().setValueAsString(theBundleType.getCode());
|
||||||
if (theLinkType.equals(next.getRelation())) {
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (myBundle.getTotalElement().isEmpty() && theTotalResults != null) {
|
||||||
public void initializeBundleFromBundleProvider(IRestfulServer<?> theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl,
|
myBundle.getTotalElement().setValue(theTotalResults);
|
||||||
boolean thePrettyPrint, int theOffset, Integer theLimit, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes) {
|
}
|
||||||
myBase = theServerBase;
|
}
|
||||||
|
|
||||||
int numToReturn;
|
|
||||||
String searchId = null;
|
|
||||||
List<IBaseResource> resourceList;
|
|
||||||
if (theServer.getPagingProvider() == null) {
|
|
||||||
numToReturn = theResult.size();
|
|
||||||
if (numToReturn > 0) {
|
|
||||||
resourceList = theResult.getResources(0, numToReturn);
|
|
||||||
} else {
|
|
||||||
resourceList = Collections.emptyList();
|
|
||||||
}
|
|
||||||
RestfulServerUtils.validateResourceListNotNull(resourceList);
|
|
||||||
|
|
||||||
} else {
|
@Override
|
||||||
IPagingProvider pagingProvider = theServer.getPagingProvider();
|
public ca.uhn.fhir.model.api.Bundle getDstu1Bundle() {
|
||||||
if (theLimit == null) {
|
return null;
|
||||||
numToReturn = pagingProvider.getDefaultPageSize();
|
}
|
||||||
} else {
|
|
||||||
numToReturn = Math.min(pagingProvider.getMaximumPageSize(), theLimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
numToReturn = Math.min(numToReturn, theResult.size() - theOffset);
|
@Override
|
||||||
if (numToReturn > 0) {
|
public IBaseResource getResourceBundle() {
|
||||||
resourceList = theResult.getResources(theOffset, numToReturn + theOffset);
|
return myBundle;
|
||||||
} else {
|
}
|
||||||
resourceList = Collections.emptyList();
|
|
||||||
}
|
|
||||||
RestfulServerUtils.validateResourceListNotNull(resourceList);
|
|
||||||
|
|
||||||
if (theSearchId != null) {
|
private boolean hasLink(String theLinkType, Bundle theBundle) {
|
||||||
searchId = theSearchId;
|
for (BundleLinkComponent next : theBundle.getLink()) {
|
||||||
} else {
|
if (theLinkType.equals(next.getRelation())) {
|
||||||
if (theResult.size() > numToReturn) {
|
return true;
|
||||||
searchId = pagingProvider.storeResultList(theResult);
|
}
|
||||||
Validate.notNull(searchId, "Paging provider returned null searchId");
|
}
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (IBaseResource next : resourceList) {
|
@Override
|
||||||
if (next.getIdElement() == null || next.getIdElement().isEmpty()) {
|
public void initializeBundleFromBundleProvider(IRestfulServer<?> theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl,
|
||||||
if (!(next instanceof BaseOperationOutcome)) {
|
boolean thePrettyPrint, int theOffset, Integer theLimit, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes) {
|
||||||
throw new InternalErrorException("Server method returned resource of type[" + next.getClass().getSimpleName() + "] with no ID specified (IResource#setId(IdDt) must be called)");
|
myBase = theServerBase;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addResourcesToBundle(new ArrayList<IBaseResource>(resourceList), theBundleType, theServerBase, theServer.getBundleInclusionRule(), theIncludes);
|
int numToReturn;
|
||||||
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType, theResult.getPublished());
|
String searchId = null;
|
||||||
|
List<IBaseResource> resourceList;
|
||||||
|
Integer numTotalResults = theResult.size();
|
||||||
|
if (theServer.getPagingProvider() == null) {
|
||||||
|
numToReturn = numTotalResults;
|
||||||
|
if (numToReturn > 0) {
|
||||||
|
resourceList = theResult.getResources(0, numToReturn);
|
||||||
|
} else {
|
||||||
|
resourceList = Collections.emptyList();
|
||||||
|
}
|
||||||
|
RestfulServerUtils.validateResourceListNotNull(resourceList);
|
||||||
|
|
||||||
if (theServer.getPagingProvider() != null) {
|
} else {
|
||||||
int limit;
|
IPagingProvider pagingProvider = theServer.getPagingProvider();
|
||||||
limit = theLimit != null ? theLimit : theServer.getPagingProvider().getDefaultPageSize();
|
if (theLimit == null || theLimit.equals(Integer.valueOf(0))) {
|
||||||
limit = Math.min(limit, theServer.getPagingProvider().getMaximumPageSize());
|
numToReturn = pagingProvider.getDefaultPageSize();
|
||||||
|
} else {
|
||||||
|
numToReturn = Math.min(pagingProvider.getMaximumPageSize(), theLimit);
|
||||||
|
}
|
||||||
|
|
||||||
if (searchId != null) {
|
if (numTotalResults != null) {
|
||||||
if (theOffset + numToReturn < theResult.size()) {
|
numToReturn = Math.min(numToReturn, numTotalResults - theOffset);
|
||||||
myBundle.addLink().setRelation(Constants.LINK_NEXT)
|
}
|
||||||
.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, theBundleType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (numToReturn > 0) {
|
||||||
public void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResources, String theServerBase, String theCompleteUrl, int theTotalResults,
|
resourceList = theResult.getResources(theOffset, numToReturn + theOffset);
|
||||||
BundleTypeEnum theBundleType) {
|
} else {
|
||||||
myBundle = new Bundle();
|
resourceList = Collections.emptyList();
|
||||||
|
}
|
||||||
|
RestfulServerUtils.validateResourceListNotNull(resourceList);
|
||||||
|
|
||||||
myBundle.setId(UUID.randomUUID().toString());
|
if (theSearchId != null) {
|
||||||
|
searchId = theSearchId;
|
||||||
|
} else {
|
||||||
|
if (numTotalResults == null || numTotalResults > numToReturn) {
|
||||||
|
searchId = pagingProvider.storeResultList(theResult);
|
||||||
|
Validate.notNull(searchId, "Paging provider returned null searchId");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
myBundle.getMeta().setLastUpdated(new Date());
|
for (IBaseResource next : resourceList) {
|
||||||
|
if (next.getIdElement() == null || next.getIdElement().isEmpty()) {
|
||||||
|
if (!(next instanceof BaseOperationOutcome)) {
|
||||||
|
throw new InternalErrorException("Server method returned resource of type[" + next.getClass().getSimpleName() + "] with no ID specified (IResource#setId(IdDt) must be called)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_FHIR_BASE).setUrl(theServerBase);
|
addResourcesToBundle(new ArrayList<IBaseResource>(resourceList), theBundleType, theServerBase, theServer.getBundleInclusionRule(), theIncludes);
|
||||||
myBundle.addLink().setRelation(Constants.LINK_SELF).setUrl(theCompleteUrl);
|
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType, theResult.getPublished());
|
||||||
myBundle.getTypeElement().setValueAsString(theBundleType.getCode());
|
|
||||||
|
|
||||||
if (theBundleType.equals(BundleTypeEnum.TRANSACTION)) {
|
if (theServer.getPagingProvider() != null) {
|
||||||
for (IBaseResource nextBaseRes : theResources) {
|
int limit;
|
||||||
Resource next = (Resource) nextBaseRes;
|
limit = theLimit != null ? theLimit : theServer.getPagingProvider().getDefaultPageSize();
|
||||||
BundleEntryComponent nextEntry = myBundle.addEntry();
|
limit = Math.min(limit, theServer.getPagingProvider().getMaximumPageSize());
|
||||||
|
|
||||||
nextEntry.setResource(next);
|
if (searchId != null) {
|
||||||
if (next.getIdElement().isEmpty()) {
|
if (numTotalResults == null || theOffset + numToReturn < numTotalResults) {
|
||||||
nextEntry.getRequest().setMethod(HTTPVerb.POST);
|
myBundle.addLink().setRelation(Constants.LINK_NEXT)
|
||||||
} else {
|
.setUrl(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, theOffset + numToReturn, numToReturn, theResponseEncoding, thePrettyPrint, theBundleType));
|
||||||
nextEntry.getRequest().setMethod(HTTPVerb.PUT);
|
}
|
||||||
if (next.getIdElement().isAbsolute()) {
|
if (theOffset > 0) {
|
||||||
nextEntry.getRequest().setUrl(next.getId());
|
int start = Math.max(0, theOffset - limit);
|
||||||
} else {
|
myBundle.addLink().setRelation(Constants.LINK_PREVIOUS)
|
||||||
String resourceType = myContext.getResourceDefinition(next).getName();
|
.setUrl(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, start, limit, theResponseEncoding, thePrettyPrint, theBundleType));
|
||||||
nextEntry.getRequest().setUrl(new IdType(theServerBase, resourceType, next.getIdElement().getIdPart(), next.getIdElement().getVersionIdPart()).getValue());
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
addResourcesForSearch(theResources);
|
|
||||||
}
|
|
||||||
|
|
||||||
myBundle.getTotalElement().setValue(theTotalResults);
|
@Override
|
||||||
}
|
public void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResources, String theServerBase, String theCompleteUrl, int theTotalResults,
|
||||||
|
BundleTypeEnum theBundleType) {
|
||||||
|
myBundle = new Bundle();
|
||||||
|
|
||||||
@Override
|
myBundle.setId(UUID.randomUUID().toString());
|
||||||
public void initializeWithBundleResource(IBaseResource theBundle) {
|
|
||||||
myBundle = (Bundle) theBundle;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
myBundle.getMeta().setLastUpdated(new Date());
|
||||||
public List<IBaseResource> toListOfResources() {
|
|
||||||
ArrayList<IBaseResource> retVal = new ArrayList<IBaseResource>();
|
myBundle.addLink().setRelation(Constants.LINK_FHIR_BASE).setUrl(theServerBase);
|
||||||
for (BundleEntryComponent next : myBundle.getEntry()) {
|
myBundle.addLink().setRelation(Constants.LINK_SELF).setUrl(theCompleteUrl);
|
||||||
if (next.getResource() != null) {
|
myBundle.getTypeElement().setValueAsString(theBundleType.getCode());
|
||||||
retVal.add(next.getResource());
|
|
||||||
} else if (next.getResponse().getLocationElement().isEmpty() == false) {
|
if (theBundleType.equals(BundleTypeEnum.TRANSACTION)) {
|
||||||
IdType id = new IdType(next.getResponse().getLocation());
|
for (IBaseResource nextBaseRes : theResources) {
|
||||||
String resourceType = id.getResourceType();
|
Resource next = (Resource) nextBaseRes;
|
||||||
if (isNotBlank(resourceType)) {
|
BundleEntryComponent nextEntry = myBundle.addEntry();
|
||||||
IAnyResource res = (IAnyResource) myContext.getResourceDefinition(resourceType).newInstance();
|
|
||||||
res.setId(id);
|
nextEntry.setResource(next);
|
||||||
retVal.add(res);
|
if (next.getIdElement().isEmpty()) {
|
||||||
}
|
nextEntry.getRequest().setMethod(HTTPVerb.POST);
|
||||||
}
|
} else {
|
||||||
}
|
nextEntry.getRequest().setMethod(HTTPVerb.PUT);
|
||||||
return retVal;
|
if (next.getIdElement().isAbsolute()) {
|
||||||
}
|
nextEntry.getRequest().setUrl(next.getId());
|
||||||
|
} else {
|
||||||
|
String resourceType = myContext.getResourceDefinition(next).getName();
|
||||||
|
nextEntry.getRequest().setUrl(new IdType(theServerBase, resourceType, next.getIdElement().getIdPart(), next.getIdElement().getVersionIdPart()).getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addResourcesForSearch(theResources);
|
||||||
|
}
|
||||||
|
|
||||||
|
myBundle.getTotalElement().setValue(theTotalResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initializeWithBundleResource(IBaseResource theBundle) {
|
||||||
|
myBundle = (Bundle) theBundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<IBaseResource> toListOfResources() {
|
||||||
|
ArrayList<IBaseResource> retVal = new ArrayList<IBaseResource>();
|
||||||
|
for (BundleEntryComponent next : myBundle.getEntry()) {
|
||||||
|
if (next.getResource() != null) {
|
||||||
|
retVal.add(next.getResource());
|
||||||
|
} else if (next.getResponse().getLocationElement().isEmpty() == false) {
|
||||||
|
IdType id = new IdType(next.getResponse().getLocation());
|
||||||
|
String resourceType = id.getResourceType();
|
||||||
|
if (isNotBlank(resourceType)) {
|
||||||
|
IAnyResource res = (IAnyResource) myContext.getResourceDefinition(resourceType).newInstance();
|
||||||
|
res.setId(id);
|
||||||
|
retVal.add(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package ca.uhn.fhir.rest.server;
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.*;
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -19,6 +18,8 @@ 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.hl7.fhir.dstu3.model.Bundle;
|
import org.hl7.fhir.dstu3.model.Bundle;
|
||||||
|
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||||
|
import org.hl7.fhir.dstu3.model.Bundle.BundleLinkComponent;
|
||||||
import org.hl7.fhir.dstu3.model.HumanName;
|
import org.hl7.fhir.dstu3.model.HumanName;
|
||||||
import org.hl7.fhir.dstu3.model.OperationOutcome;
|
import org.hl7.fhir.dstu3.model.OperationOutcome;
|
||||||
import org.hl7.fhir.dstu3.model.Patient;
|
import org.hl7.fhir.dstu3.model.Patient;
|
||||||
|
@ -27,6 +28,10 @@ import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||||
|
@ -58,16 +63,78 @@ public class SearchBundleProviderWithNoSizeDstu3Test {
|
||||||
Bundle respBundle;
|
Bundle respBundle;
|
||||||
|
|
||||||
ourLastBundleProvider = mock(IBundleProvider.class);
|
ourLastBundleProvider = mock(IBundleProvider.class);
|
||||||
when(ourLastBundleProvider.size()).thenReturn(-1);
|
when(ourLastBundleProvider.size()).thenReturn(null);
|
||||||
|
when(ourLastBundleProvider.getResources(any(int.class), any(int.class))).then(new Answer<List<IBaseResource>>() {
|
||||||
|
@Override
|
||||||
|
public List<IBaseResource> answer(InvocationOnMock theInvocation) throws Throwable {
|
||||||
|
int from =(Integer)theInvocation.getArguments()[0];
|
||||||
|
int to =(Integer)theInvocation.getArguments()[1];
|
||||||
|
ArrayList<IBaseResource> retVal = Lists.newArrayList();
|
||||||
|
for (int i = from; i < to; i++) {
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setId(Integer.toString(i));
|
||||||
|
retVal.add(p);
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}});
|
||||||
|
|
||||||
|
HttpGet httpGet;
|
||||||
|
CloseableHttpResponse status = null;
|
||||||
|
BundleLinkComponent linkNext;
|
||||||
|
|
||||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=json");
|
|
||||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
|
||||||
try {
|
try {
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=json");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(responseContent);
|
ourLog.info(responseContent);
|
||||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
assertEquals("searchAll", ourLastMethod);
|
assertEquals("searchAll", ourLastMethod);
|
||||||
respBundle = ourCtx.newJsonParser().parseResource(Bundle.class, responseContent);
|
respBundle = ourCtx.newJsonParser().parseResource(Bundle.class, responseContent);
|
||||||
|
|
||||||
|
assertEquals(10, respBundle.getEntry().size());
|
||||||
|
assertEquals("Patient/0", respBundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||||
|
linkNext = respBundle.getLink("next");
|
||||||
|
assertNotNull(linkNext);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
when(ourLastBundleProvider.size()).thenReturn(25);
|
||||||
|
|
||||||
|
try {
|
||||||
|
httpGet = new HttpGet(linkNext.getUrl());
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals("searchAll", ourLastMethod);
|
||||||
|
respBundle = ourCtx.newJsonParser().parseResource(Bundle.class, responseContent);
|
||||||
|
|
||||||
|
assertEquals(10, respBundle.getEntry().size());
|
||||||
|
assertEquals("Patient/10", respBundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||||
|
linkNext = respBundle.getLink("next");
|
||||||
|
assertNotNull(linkNext);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
httpGet = new HttpGet(linkNext.getUrl());
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals("searchAll", ourLastMethod);
|
||||||
|
respBundle = ourCtx.newJsonParser().parseResource(Bundle.class, responseContent);
|
||||||
|
|
||||||
|
assertEquals(5, respBundle.getEntry().size());
|
||||||
|
assertEquals("Patient/20", respBundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||||
|
linkNext = respBundle.getLink("next");
|
||||||
|
assertNull(linkNext);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue