EWS: new paging implementation based on imap uid sort to avoid issues on concurrent changes on searched folder

git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@2218 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
mguessan 2014-01-29 23:01:59 +00:00
parent b0f53a82eb
commit 882946775f
1 changed files with 32 additions and 7 deletions

View File

@ -717,30 +717,55 @@ public class EwsExchangeSession extends ExchangeSession {
} }
protected List<EWSMethod.Item> searchItems(String folderPath, Set<String> attributes, Condition condition, FolderQueryTraversal folderQueryTraversal, int maxCount) throws IOException { protected List<EWSMethod.Item> searchItems(String folderPath, Set<String> attributes, Condition condition, FolderQueryTraversal folderQueryTraversal, int maxCount) throws IOException {
int offset = 0; int resultCount = 0;
List<EWSMethod.Item> results = new ArrayList<EWSMethod.Item>(); List<EWSMethod.Item> results = new ArrayList<EWSMethod.Item>();
FindItemMethod findItemMethod; FindItemMethod findItemMethod;
do { do {
int fetchCount = PAGE_SIZE; int fetchCount = PAGE_SIZE;
// adjust fetch count on last page request
if (maxCount > 0) { if (maxCount > 0) {
fetchCount = Math.min(PAGE_SIZE, maxCount - offset); fetchCount = Math.min(PAGE_SIZE, maxCount - resultCount);
} }
findItemMethod = new FindItemMethod(folderQueryTraversal, BaseShape.ID_ONLY, getFolderId(folderPath), offset, fetchCount); // search items in folder, do not retrieve all properties
findItemMethod = new FindItemMethod(folderQueryTraversal, BaseShape.ID_ONLY, getFolderId(folderPath), 0, fetchCount);
for (String attribute : attributes) { for (String attribute : attributes) {
findItemMethod.addAdditionalProperty(Field.get(attribute)); findItemMethod.addAdditionalProperty(Field.get(attribute));
} }
if (condition != null && !condition.isEmpty()) { // make sure imapUid is available
findItemMethod.setSearchExpression((SearchExpression) condition); if (!attributes.contains("imapUid")) {
findItemMethod.addAdditionalProperty(Field.get("imapUid"));
} }
// always sort items by imapUid descending to retrieve recent messages first
findItemMethod.setFieldOrder(new FieldOrder(Field.get("imapUid"), FieldOrder.Order.Descending)); findItemMethod.setFieldOrder(new FieldOrder(Field.get("imapUid"), FieldOrder.Order.Descending));
// use requested filter for first page
Condition localCondition = condition;
if (resultCount > 0) {
// adjust condition for next pages: retrieve only items with imapUid lower than current lowest
String lowestImapUid = results.get(results.size()-1).get(Field.get("imapUid").getResponseName());
if (localCondition == null || localCondition.isEmpty()) {
localCondition = lt("imapUid", lowestImapUid);
} else {
localCondition = and(lt("imapUid", lowestImapUid), condition);
}
}
if (localCondition != null && !localCondition.isEmpty()) {
findItemMethod.setSearchExpression((SearchExpression) localCondition);
}
executeMethod(findItemMethod); executeMethod(findItemMethod);
results.addAll(findItemMethod.getResponseItems()); results.addAll(findItemMethod.getResponseItems());
offset = results.size(); resultCount = results.size();
if (resultCount > 0 && LOGGER.isDebugEnabled()) {
LOGGER.debug("Search items current count: "+resultCount+" fetchCount: "+fetchCount
+" highest uid: "+results.get(0).get(Field.get("imapUid").getResponseName())
+" lowest uid: "+results.get(resultCount-1).get(Field.get("imapUid").getResponseName()));
}
if (Thread.interrupted()) { if (Thread.interrupted()) {
LOGGER.debug("Search items failed: Interrupted by client"); LOGGER.debug("Search items failed: Interrupted by client");
throw new IOException("Search items failed: Interrupted by client"); throw new IOException("Search items failed: Interrupted by client");
} }
} while (!(findItemMethod.includesLastItemInRange || (maxCount > 0 && offset == maxCount))); } while (!(findItemMethod.includesLastItemInRange || (maxCount > 0 && resultCount == maxCount)));
return results; return results;
} }