use of com.zimbra.cs.service.util.SyncToken in project zm-mailbox by Zimbra.
the class WaitSetRequest method parseAddUpdateAccounts.
/**
* @param allowedAccountIds NULL means "all allowed" (admin)
*/
static List<WaitSetAccount> parseAddUpdateAccounts(ZimbraSoapContext zsc, Element elt, Set<MailItem.Type> defaultInterest) throws ServiceException {
List<WaitSetAccount> toRet = new ArrayList<WaitSetAccount>();
if (elt != null) {
for (Iterator<Element> iter = elt.elementIterator(MailConstants.E_A); iter.hasNext(); ) {
Element a = iter.next();
String id;
String name = a.getAttribute(MailConstants.A_NAME, null);
if (name != null) {
Account acct = Provisioning.getInstance().get(AccountBy.name, name);
if (acct != null) {
id = acct.getId();
} else {
WaitSetError err = new WaitSetError(name, WaitSetError.Type.NO_SUCH_ACCOUNT);
continue;
}
} else {
id = a.getAttribute(MailConstants.A_ID);
}
WaitSetMgr.checkRightForAdditionalAccount(id, zsc);
String tokenStr = a.getAttribute(MailConstants.A_TOKEN, null);
SyncToken token = tokenStr != null ? new SyncToken(tokenStr) : null;
Set<MailItem.Type> interests = parseInterestStr(a.getAttribute(MailConstants.A_TYPES, null), defaultInterest);
toRet.add(new WaitSetAccount(id, token, interests));
}
}
return toRet;
}
use of com.zimbra.cs.service.util.SyncToken in project zm-mailbox by Zimbra.
the class SyncTest method testPaginatedSync.
/**
* Test Paginations.
* 1. Modified paged , delete paged (del cutoff modseq < modified cutoff mod Seq)
* 2. All modified , delete paged.
* 3. Modified paged , delete paged (del cutoff modseq > modified cutoff mod Seq)
* 4. Modified paged , all deletes.
* 5. Modified and delete unpaged.
* @throws Exception
*/
@Test
public void testPaginatedSync() throws Exception {
Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com");
Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(acct);
mbox.beginTrackingSync();
SyncRequest request = new SyncRequest();
request.setFolderId("2");
Map<String, Object> context = new HashMap<String, Object>();
context.put(SoapEngine.ZIMBRA_CONTEXT, new ZimbraSoapContext(AuthProvider.getAuthToken(acct), acct.getId(), SoapProtocol.Soap12, SoapProtocol.Soap12));
Element response = new Sync().handle(JaxbUtil.jaxbToElement(request), context);
SyncResponse syncRes = JaxbUtil.elementToJaxb(response);
Set<Integer> itemsDeleted = new HashSet<Integer>();
Set<Integer> itemsAddedOrModified = new HashSet<Integer>();
String token = syncRes.getToken();
int msgId1 = mbox.addMessage(null, MailboxTestUtil.generateMessage("test subject"), MailboxTest.STANDARD_DELIVERY_OPTIONS, null).getId();
int msgId2 = mbox.addMessage(null, MailboxTestUtil.generateMessage("test subject"), MailboxTest.STANDARD_DELIVERY_OPTIONS, null).getId();
int msgId3 = mbox.addMessage(null, MailboxTestUtil.generateMessage("test subject"), MailboxTest.STANDARD_DELIVERY_OPTIONS, null).getId();
int msgId4 = mbox.addMessage(null, MailboxTestUtil.generateMessage("test subject"), MailboxTest.STANDARD_DELIVERY_OPTIONS, null).getId();
int msgId5 = mbox.addMessage(null, MailboxTestUtil.generateMessage("test subject"), MailboxTest.STANDARD_DELIVERY_OPTIONS, null).getId();
int msgId6 = mbox.addMessage(null, MailboxTestUtil.generateMessage("test subject"), MailboxTest.STANDARD_DELIVERY_OPTIONS, null).getId();
itemsAddedOrModified.add(msgId1);
itemsAddedOrModified.add(msgId2);
itemsAddedOrModified.add(msgId3);
itemsAddedOrModified.add(msgId4);
itemsAddedOrModified.add(msgId5);
itemsAddedOrModified.add(msgId6);
request = new SyncRequest();
request.setChangeLimit(100);
request.setFolderId("2");
request.setToken(token);
response = new Sync().handle(JaxbUtil.jaxbToElement(request), context);
syncRes = JaxbUtil.elementToJaxb(response);
List<Object> listObj = syncRes.getItems();
removeItemsFromList(itemsAddedOrModified, listObj);
Assert.assertTrue(itemsAddedOrModified.isEmpty());
token = syncRes.getToken();
// Modified paged , delete paged (del cutoff modseq < modified cutoff mod Seq);
mbox.move(null, msgId1, Type.MESSAGE, 5);
mbox.move(null, msgId2, Type.MESSAGE, 5);
mbox.delete(null, msgId3, Type.MESSAGE);
mbox.alterTag(null, new int[] { msgId5, msgId6, msgId4 }, MailItem.Type.MESSAGE, Flag.FlagInfo.UNREAD, true, null);
itemsDeleted.add(msgId1);
itemsDeleted.add(msgId2);
itemsDeleted.add(msgId3);
itemsAddedOrModified.add(msgId4);
itemsAddedOrModified.add(msgId5);
itemsAddedOrModified.add(msgId6);
request = new SyncRequest();
request.setToken(token);
request.setFolderId("2");
request.setChangeLimit(2);
request.setDeleteLimit(2);
response = new Sync().handle(JaxbUtil.jaxbToElement(request), context);
syncRes = JaxbUtil.elementToJaxb(response);
token = syncRes.getToken();
//Expected 2 deletes and 2 added message. and hasMore=true
SyncDeletedInfo sdi1 = syncRes.getDeleted();
String[] deletes = sdi1.getIds().split(",");
Assert.assertEquals(2, deletes.length);
removeDeleteFromList(itemsDeleted, deletes);
//pending to sync.
Assert.assertEquals(1, itemsDeleted.size());
listObj = syncRes.getItems();
Assert.assertEquals(2, listObj.size());
removeItemsFromList(itemsAddedOrModified, listObj);
//pending to sync.
Assert.assertEquals(1, itemsAddedOrModified.size());
Assert.assertTrue(syncRes.getMore());
SyncToken syncToken = new SyncToken(token);
int lastChange = syncToken.getChangeId();
int lastDel = syncToken.getDeleteModSeq();
Assert.assertTrue(lastDel < lastChange);
// Test3: previous interrupted sync. All modified and delete paged.
mbox.move(null, msgId5, Type.MESSAGE, 5);
mbox.delete(null, msgId4, Type.MESSAGE);
itemsDeleted.add(msgId4);
itemsDeleted.add(msgId5);
request = new SyncRequest();
request.setToken(token);
request.setFolderId("2");
request.setDeleteLimit(2);
request.setChangeLimit(2);
response = new Sync().handle(JaxbUtil.jaxbToElement(request), context);
syncRes = JaxbUtil.elementToJaxb(response);
token = syncRes.getToken();
//Expected all modified and 2 deleted message. and hasMore=true
SyncDeletedInfo sdi2 = syncRes.getDeleted();
deletes = sdi2.getIds().split(",");
Assert.assertEquals(2, deletes.length);
removeDeleteFromList(itemsDeleted, deletes);
//pending to sync.
Assert.assertEquals(1, itemsDeleted.size());
listObj = syncRes.getItems();
Assert.assertEquals(1, listObj.size());
removeItemsFromList(itemsAddedOrModified, listObj);
//All synced.
Assert.assertEquals(0, itemsAddedOrModified.size());
Assert.assertTrue(syncRes.getMore());
syncToken = new SyncToken(token);
lastChange = syncToken.getChangeId();
lastDel = syncToken.getDeleteModSeq();
Assert.assertTrue(lastDel < lastChange);
Assert.assertTrue(syncRes.getMore());
// Test3: previous interrupted sync. modified and delete paged.(del cutoff modseq > modified cutoff mod Seq)
int msgId7 = mbox.addMessage(null, MailboxTestUtil.generateMessage("test subject"), MailboxTest.STANDARD_DELIVERY_OPTIONS, null).getId();
int msgId8 = mbox.addMessage(null, MailboxTestUtil.generateMessage("test subject"), MailboxTest.STANDARD_DELIVERY_OPTIONS, null).getId();
int msgId9 = mbox.addMessage(null, MailboxTestUtil.generateMessage("test subject"), MailboxTest.STANDARD_DELIVERY_OPTIONS, null).getId();
mbox.alterTag(null, new int[] { msgId9 }, MailItem.Type.MESSAGE, Flag.FlagInfo.UNREAD, true, null);
mbox.delete(null, msgId6, Type.MESSAGE);
itemsAddedOrModified.add(msgId7);
itemsAddedOrModified.add(msgId8);
itemsAddedOrModified.add(msgId9);
itemsDeleted.add(msgId6);
request = new SyncRequest();
request.setToken(token);
request.setFolderId("2");
request.setChangeLimit(2);
request.setDeleteLimit(1);
response = new Sync().handle(JaxbUtil.jaxbToElement(request), context);
syncRes = JaxbUtil.elementToJaxb(response);
token = syncRes.getToken();
//Expected 1 deletes and 2 added message. and hasMore=true
SyncDeletedInfo sdi3 = syncRes.getDeleted();
deletes = sdi3.getIds().split(",");
Assert.assertEquals(1, deletes.length);
removeDeleteFromList(itemsDeleted, deletes);
//pending to sync.
Assert.assertEquals(1, itemsDeleted.size());
listObj = syncRes.getItems();
Assert.assertEquals(2, listObj.size());
removeItemsFromList(itemsAddedOrModified, listObj);
//pending to sync.
Assert.assertEquals(1, itemsAddedOrModified.size());
Assert.assertTrue(syncRes.getMore());
syncToken = new SyncToken(token);
lastChange = syncToken.getChangeId();
lastDel = syncToken.getDeleteModSeq();
Assert.assertTrue(lastDel > lastChange);
Assert.assertTrue(syncRes.getMore());
// Test4: previous interrupted sync. Modified paged and All Deletes.
int msgId10 = mbox.addMessage(null, MailboxTestUtil.generateMessage("test subject"), MailboxTest.STANDARD_DELIVERY_OPTIONS, null).getId();
int msgId11 = mbox.addMessage(null, MailboxTestUtil.generateMessage("test subject"), MailboxTest.STANDARD_DELIVERY_OPTIONS, null).getId();
int msgId12 = mbox.addMessage(null, MailboxTestUtil.generateMessage("test subject"), MailboxTest.STANDARD_DELIVERY_OPTIONS, null).getId();
mbox.alterTag(null, new int[] { msgId9 }, MailItem.Type.MESSAGE, Flag.FlagInfo.UNREAD, true, null);
mbox.delete(null, msgId9, Type.MESSAGE);
itemsAddedOrModified.add(msgId10);
itemsAddedOrModified.add(msgId11);
itemsAddedOrModified.add(msgId12);
itemsAddedOrModified.remove(msgId9);
itemsDeleted.add(msgId9);
request = new SyncRequest();
request.setToken(token);
request.setFolderId("2");
request.setDeleteLimit(2);
request.setChangeLimit(2);
response = new Sync().handle(JaxbUtil.jaxbToElement(request), context);
syncRes = JaxbUtil.elementToJaxb(response);
token = syncRes.getToken();
//Expected 2 deletes and 2 added message. and hasMore=true.
//trick: deleted the remaining to sync modified message from last sync.
SyncDeletedInfo sdi4 = syncRes.getDeleted();
deletes = sdi4.getIds().split(",");
Assert.assertEquals(2, deletes.length);
removeDeleteFromList(itemsDeleted, deletes);
//All synced.
Assert.assertEquals(0, itemsDeleted.size());
listObj = syncRes.getItems();
Assert.assertEquals(2, listObj.size());
removeItemsFromList(itemsAddedOrModified, listObj);
//pending to sync.
Assert.assertEquals(1, itemsAddedOrModified.size());
Assert.assertTrue(syncRes.getMore());
syncToken = new SyncToken(token);
lastChange = syncToken.getChangeId();
lastDel = syncToken.getDeleteModSeq();
Assert.assertTrue(lastDel == mbox.getLastChangeID());
Assert.assertTrue(syncRes.getMore());
//Test5: All deletes and all Modified.
int msgId13 = mbox.addMessage(null, MailboxTestUtil.generateMessage("test subject"), MailboxTest.STANDARD_DELIVERY_OPTIONS, null).getId();
mbox.alterTag(null, new int[] { msgId11 }, MailItem.Type.MESSAGE, Flag.FlagInfo.UNREAD, true, null);
mbox.delete(null, msgId10, Type.MESSAGE);
itemsAddedOrModified.add(msgId13);
itemsAddedOrModified.add(msgId11);
itemsDeleted.add(msgId10);
request = new SyncRequest();
request.setToken(token);
request.setFolderId("2");
request.setDeleteLimit(0);
request.setChangeLimit(10);
response = new Sync().handle(JaxbUtil.jaxbToElement(request), context);
syncRes = JaxbUtil.elementToJaxb(response);
token = syncRes.getToken();
//Expected 2 deletes and 2 added message. and hasMore=true.
//trick: deleted the remaining to sync modified message from last sync.
SyncDeletedInfo sdi5 = syncRes.getDeleted();
deletes = sdi5.getIds().split(",");
Assert.assertEquals(1, deletes.length);
removeDeleteFromList(itemsDeleted, deletes);
// All synced.
Assert.assertEquals(0, itemsDeleted.size());
listObj = syncRes.getItems();
Assert.assertEquals(3, listObj.size());
removeItemsFromList(itemsAddedOrModified, listObj);
//All synced.
Assert.assertEquals(0, itemsAddedOrModified.size());
syncToken = new SyncToken(token);
lastChange = syncToken.getChangeId();
lastDel = syncToken.getDeleteModSeq();
Assert.assertEquals(lastChange, mbox.getLastChangeID());
Assert.assertTrue(lastDel == -1);
Assert.assertNull(syncRes.getMore());
}
use of com.zimbra.cs.service.util.SyncToken in project zm-mailbox by Zimbra.
the class MailboxUpgrade method migrateHighestIndexed.
private static void migrateHighestIndexed(Mailbox mbox) throws ServiceException {
DbConnection conn = DbPool.getConnection(mbox);
PreparedStatement stmt;
ResultSet rs;
try {
// fetch highest_indexed
String highestIndexed = null;
stmt = conn.prepareStatement("SELECT highest_indexed FROM " + DbMailbox.qualifyZimbraTableName(mbox, "mailbox") + " WHERE id = ?");
stmt.setInt(1, mbox.getId());
rs = stmt.executeQuery();
if (rs.next()) {
highestIndexed = rs.getString(1);
}
rs.close();
stmt.close();
if (Strings.isNullOrEmpty(highestIndexed)) {
return;
}
SyncToken token;
try {
token = new SyncToken(highestIndexed);
} catch (ServiceException e) {
return;
}
// update index_id where mod_content/mod_metadata > highest_indexed
stmt = conn.prepareStatement("UPDATE " + DbMailItem.getMailItemTableName(mbox) + " SET index_id = 0 WHERE " + DbMailItem.IN_THIS_MAILBOX_AND + "mod_content > ? AND mod_metadata > ? AND index_id IS NOT NULL");
int pos = DbMailItem.setMailboxId(stmt, mbox, 1);
stmt.setInt(pos++, token.getChangeId());
stmt.setInt(pos++, token.getChangeId());
stmt.executeUpdate();
stmt.close();
// clear highest_indexed
stmt = conn.prepareStatement("UPDATE " + DbMailbox.qualifyZimbraTableName(mbox, "mailbox") + " SET highest_indexed = NULL WHERE id = ?");
stmt.setInt(1, mbox.getId());
stmt.executeUpdate();
stmt.close();
conn.commit();
} catch (SQLException e) {
conn.rollback();
throw ServiceException.FAILURE("Failed to migrate highest_indexed", e);
} finally {
conn.closeQuietly();
}
}
use of com.zimbra.cs.service.util.SyncToken in project zm-mailbox by Zimbra.
the class Sync method handle.
@Override
public Element handle(Element request, Map<String, Object> context) throws ServiceException {
ZimbraSoapContext zsc = getZimbraSoapContext(context);
Mailbox mbox = getRequestedMailbox(zsc);
OperationContext octxt = getOperationContext(zsc, context);
ItemIdFormatter ifmt = new ItemIdFormatter(zsc);
SyncRequest syncRequest = JaxbUtil.elementToJaxb(request);
String token = syncRequest.getToken();
Element response = zsc.createElement(MailConstants.SYNC_RESPONSE);
response.addAttribute(MailConstants.A_CHANGE_DATE, System.currentTimeMillis() / 1000);
// the sync token is of the form "last fully synced change id" (e.g. "32425") or
// last fully synced change id-last item synced in next change id" (e.g. "32425-99213") or
// last fully synced change id-last item synced in next change id and last fully synced delete change id" (e.g. "32425-99213:d1231232") or
// last fully synced change id-last item synced in next change id and
// last fully synced delete id-last item synced in next delete id (e.g. "32425-99213:d12312-82134")
SyncToken syncToken = null;
int tokenInt = 0;
if (!StringUtil.isNullOrEmpty(token)) {
syncToken = new SyncToken(token);
tokenInt = syncToken.getChangeId();
}
if (syncToken == null) {
syncToken = new SyncToken(0);
}
int deleleLimit = syncRequest.getDeleteLimit();
int changeLimit = syncRequest.getChangeLimit();
// server can apply delete pagination through debugconfig/localconfig.
if (deleleLimit <= 0) {
deleleLimit = DebugConfig.syncMaximumDeleteCount;
}
// client specify more than DebugConfig.syncMaximumChangeCount It will use DebugConfig.syncMaximumChangeCount
if (changeLimit <= 0 || changeLimit > DebugConfig.syncMaximumChangeCount) {
changeLimit = DebugConfig.syncMaximumChangeCount;
}
boolean initialSync = tokenInt <= 0;
// permit the caller to restrict initial sync only to calendar items with a recurrence after a given date
long calendarStart = (syncRequest.getCalendarCutoff() != null) ? syncRequest.getCalendarCutoff() : -1;
int messageSyncStart = (syncRequest.getMsgCutoff() != null) ? syncRequest.getMsgCutoff() : -1;
// if the sync is constrained to a folder subset, we need to first figure out what can be seen
Folder root = null;
ItemId iidFolder = null;
try {
iidFolder = new ItemId(request.getAttribute(MailConstants.A_FOLDER, DEFAULT_FOLDER_ID + ""), zsc);
OperationContext octxtOwner = new OperationContext(mbox);
root = mbox.getFolderById(octxtOwner, iidFolder.getId());
} catch (MailServiceException.NoSuchItemException nsie) {
}
Set<Folder> visible = octxt.isDelegatedRequest(mbox) ? mbox.getVisibleFolders(octxt) : null;
FolderNode rootNode = null;
if (root == null || iidFolder == null) {
// resolve grantee names of all ACLs on the mailbox
rootNode = mbox.getFolderTree(octxt, null, true);
} else {
// resolve grantee names of all ACLs on all sub-folders of the requested folder
rootNode = mbox.getFolderTree(octxt, iidFolder, true);
}
OperationContextData.addGranteeNames(octxt, rootNode);
// actually perform the sync
mbox.lock.lock();
try {
mbox.beginTrackingSync();
if (initialSync) {
response.addAttribute(MailConstants.A_TOKEN, mbox.getLastChangeID());
response.addAttribute(MailConstants.A_SIZE, mbox.getSize());
boolean anyFolders = folderSync(response, octxt, ifmt, mbox, root, visible, calendarStart, messageSyncStart, SyncPhase.INITIAL);
// if no folders are visible, add an empty "<folder/>" as a hint
if (!anyFolders) {
response.addElement(MailConstants.E_FOLDER);
}
} else {
boolean typedDeletes = request.getAttributeBool(MailConstants.A_TYPED_DELETES, false);
String newToken = deltaSync(response, octxt, ifmt, mbox, syncToken, deleleLimit, changeLimit, typedDeletes, root, visible, messageSyncStart);
response.addAttribute(MailConstants.A_TOKEN, newToken);
}
} finally {
mbox.lock.release();
}
return response;
}
use of com.zimbra.cs.service.util.SyncToken in project zm-mailbox by Zimbra.
the class Sync method deltaSync.
private static String deltaSync(Element response, OperationContext octxt, ItemIdFormatter ifmt, Mailbox mbox, SyncToken syncToken, int deleteLimit, int changeLimit, boolean typedDeletes, Folder root, Set<Folder> visible, int messageSyncStart) throws ServiceException {
int begin = syncToken.getChangeId();
int deleteModSeqCutoff = syncToken.getDeleteModSeq();
deleteModSeqCutoff = deleteModSeqCutoff <= 0 ? begin : deleteModSeqCutoff;
int mboxLastChangeId = mbox.getLastChangeID();
SyncToken newSyncToken = new SyncToken(mboxLastChangeId);
if (begin >= mboxLastChangeId && deleteModSeqCutoff >= mboxLastChangeId) {
return newSyncToken.toString();
}
int changeItemIdCutoff = syncToken.getOffsetInNext();
int deleteItemIdCutoff = syncToken.getDeleteOffsetInNext();
// first, fetch deleted items
TypedIdList tombstones = mbox.getTombstones(deleteModSeqCutoff);
Element eDeleted = response.addElement(MailConstants.E_DELETED);
// then, put together the requested folder hierarchy in 2 different flavors
List<Folder> hierarchy = (root == null || root.getId() == Mailbox.ID_FOLDER_USER_ROOT ? null : root.getSubfolderHierarchy());
Set<Integer> targetIds = (root != null && root.getId() == Mailbox.ID_FOLDER_USER_ROOT ? null : new HashSet<Integer>(hierarchy == null ? 0 : hierarchy.size()));
if (hierarchy != null) {
for (Folder folder : hierarchy) {
targetIds.add(folder.getId());
}
}
// then, handle created/modified folders
if (octxt.isDelegatedRequest(mbox)) {
// first, make sure that something changed...
if (!mbox.getModifiedFolders(begin).isEmpty() || !Collections.disjoint(tombstones.types(), FOLDER_TYPES)) {
// special-case the folder hierarchy for delegated delta sync
boolean anyFolders = folderSync(response, octxt, ifmt, mbox, root, visible, -1, messageSyncStart, SyncPhase.DELTA);
// if no folders are visible, add an empty "<folder/>" as a hint
if (!anyFolders) {
response.addElement(MailConstants.E_FOLDER);
}
}
} else {
for (Folder folder : mbox.getModifiedFolders(begin)) {
// no case of "synthetic tombstone" (item falling out of the tree being synced)
if (targetIds == null || targetIds.contains(folder.getId())) {
ToXML.encodeFolder(response, ifmt, octxt, folder, Change.ALL_FIELDS);
} else {
tombstones.add(folder.getType(), folder.getId(), folder.getUuid(), folder.getModifiedSequence());
}
}
}
// next, handle created/modified tags
for (Tag tag : mbox.getModifiedTags(octxt, begin)) {
ToXML.encodeTag(response, ifmt, octxt, tag, Change.ALL_FIELDS);
}
// finally, handle created/modified "other items"
int itemCount = 0;
Pair<List<Integer>, TypedIdList> changed = mbox.getModifiedItems(octxt, Math.min(begin, deleteModSeqCutoff), messageSyncStart, MailItem.Type.UNKNOWN, targetIds, deleteModSeqCutoff);
List<Integer> modified = changed.getFirst();
// items that have been altered in non-visible folders will be returned as "deleted" in order to handle moves
if (changed.getSecond() != null) {
tombstones.addAll(changed.getSecond());
}
delta: while (!modified.isEmpty()) {
List<Integer> batch = modified.subList(0, Math.min(modified.size(), FETCH_BATCH_SIZE));
for (MailItem item : mbox.getItemById(octxt, batch, MailItem.Type.UNKNOWN)) {
// detect interrupted sync and resume from the appropriate place
if ((item.getModifiedSequence() == begin + 1 && item.getId() < changeItemIdCutoff) || item.getModifiedSequence() <= begin) {
//if interrupted delete and un-interrupted modifications.
continue;
}
// if we've overflowed this sync response, set things up so that a subsequent sync starts from where we're cutting off
if (itemCount >= changeLimit) {
response.addAttribute(MailConstants.A_QUERY_MORE, true);
newSyncToken.setChangeModSeq((item.getModifiedSequence() - 1));
newSyncToken.setChangeItemId(item.getId());
newSyncToken.setDeleteModSeq(mboxLastChangeId);
break delta;
}
// For items in the system, if the content has changed since the user last sync'ed
// (because it was edited or created), just send back the folder ID and saved date --
// the client will request the whole object out of band -- potentially using the
// content servlet's "include metadata in headers" hack.
// If it's just the metadata that changed, send back the set of mutable attributes.
boolean created = item.getSavedSequence() > begin;
ToXML.encodeItem(response, ifmt, octxt, item, created ? Change.FOLDER | Change.CONFLICT | Change.DATE | Change.PARENT : MUTABLE_FIELDS);
itemCount++;
}
batch.clear();
}
// cleanup: only return a <deleted> element if we're sending back deleted item ids
if ((deleteLimit > 0 && tombstones.size() > deleteLimit) || deleteItemIdCutoff > 0) {
PagedDelete pgDel = new PagedDelete(tombstones, typedDeletes);
pgDel.removeBeforeCutoff(deleteItemIdCutoff, deleteModSeqCutoff);
if (deleteLimit > 0) {
pgDel.trimDeletesTillPageLimit(deleteLimit);
}
encodePagedDelete(eDeleted, pgDel, newSyncToken, tombstones, typedDeletes);
if (pgDel.isDeleteOverFlow()) {
response.addAttribute(MailConstants.A_QUERY_MORE, true);
response.addAttribute(MailConstants.A_QUERY_MORE, true);
}
} else {
encodeUnpagedDelete(eDeleted, tombstones, typedDeletes);
}
return newSyncToken.toString();
}
Aggregations