Search in sources :

Example 11 with Change

use of com.zimbra.cs.session.PendingModifications.Change in project zm-mailbox by Zimbra.

the class Mailbox method snapshotModifications.

/** Makes a deep copy of the {@code PendingModifications} object with
     *  {@link Flag#BITMASK_UNCACHED} set on each {@code MailItem} present in
     *  the {@code created} and {@code modified} hashes.  These copied {@code
     *  MailItem}s are not linked to their {@code Mailbox} and thus will not
     *  change when modifications are subsequently made to the contents of the
     *  {@code Mailbox}.  The original {@code PendingModifications} object and
     *  the {@code MailItem}s it references are unchanged.
     *  <p>
     *  This method should only be called <i>immediately</i> before notifying
     *  listeners of the changes from the currently-ending transaction. */
private PendingModifications snapshotModifications(PendingModifications pms) throws ServiceException {
    if (pms == null) {
        return null;
    }
    assert (currentChange().depth == 0);
    ItemCache cache = mItemCache.get();
    FolderCache folders = mFolderCache == null || Collections.disjoint(pms.changedTypes, FOLDER_TYPES) ? mFolderCache : snapshotFolders();
    PendingModifications snapshot = new PendingModifications();
    if (pms.deleted != null && !pms.deleted.isEmpty()) {
        snapshot.recordDeleted(pms.deleted);
    }
    if (pms.created != null && !pms.created.isEmpty()) {
        for (MailItem item : pms.created.values()) {
            if (item instanceof Folder && folders != null) {
                Folder folder = folders.get(item.getId());
                if (folder == null) {
                    ZimbraLog.mailbox.warn("folder missing from snapshotted folder set: %d", item.getId());
                    folder = (Folder) item;
                }
                snapshot.recordCreated(folder);
            } else if (item instanceof Tag) {
                if (((Tag) item).isListed()) {
                    snapshot.recordCreated(snapshotItem(item));
                }
            } else {
                // NOTE: if the folder cache is null, folders fall down here and should always get copy == false
                if (cache != null && cache.contains(item)) {
                    item = snapshotItem(item);
                }
                snapshot.recordCreated(item);
            }
        }
    }
    if (pms.modified != null && !pms.modified.isEmpty()) {
        for (Map.Entry<PendingModifications.ModificationKey, Change> entry : pms.modified.entrySet()) {
            Change chg = entry.getValue();
            if (!(chg.what instanceof MailItem)) {
                snapshot.recordModified(entry.getKey(), chg);
                continue;
            }
            MailItem item = (MailItem) chg.what;
            if (item instanceof Folder && folders != null) {
                Folder folder = folders.get(item.getId());
                if (folder == null) {
                    ZimbraLog.mailbox.warn("folder missing from snapshotted folder set: %d", item.getId());
                    folder = (Folder) item;
                }
                snapshot.recordModified(folder, chg.why, (MailItem) chg.preModifyObj);
            } else if (item instanceof Tag) {
                if (((Tag) item).isListed()) {
                    snapshot.recordModified(snapshotItem(item), chg.why, (MailItem) chg.preModifyObj);
                }
            } else {
                // NOTE: if the folder cache is null, folders fall down here and should always get copy == false
                if (cache != null && cache.contains(item)) {
                    item = snapshotItem(item);
                }
                snapshot.recordModified(item, chg.why, (MailItem) chg.preModifyObj);
            }
        }
    }
    return snapshot;
}
Also used : DbMailItem(com.zimbra.cs.db.DbMailItem) PendingModifications(com.zimbra.cs.session.PendingModifications) AlterItemTag(com.zimbra.cs.redolog.op.AlterItemTag) CreateTag(com.zimbra.cs.redolog.op.CreateTag) DbTag(com.zimbra.cs.db.DbTag) Change(com.zimbra.cs.session.PendingModifications.Change) CreateFolder(com.zimbra.cs.redolog.op.CreateFolder) ZFolder(com.zimbra.client.ZFolder) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ConcurrentLinkedHashMap(com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap) IcalXmlStrMap(com.zimbra.cs.mailbox.calendar.IcalXmlStrMap) HashMap(java.util.HashMap) TimeZoneMap(com.zimbra.common.calendar.TimeZoneMap)

Example 12 with Change

use of com.zimbra.cs.session.PendingModifications.Change in project zm-mailbox by Zimbra.

the class DataSourceFolderListener method notify.

@Override
public void notify(ChangeNotification notification) {
    if (notification.mods.deleted != null) {
        for (Map.Entry<ModificationKey, Change> entry : notification.mods.deleted.entrySet()) {
            MailItem.Type type = (MailItem.Type) entry.getValue().what;
            if (type == MailItem.Type.FOLDER) {
                Folder oldFolder = (Folder) entry.getValue().preModifyObj;
                if (oldFolder == null) {
                    ZimbraLog.datasource.warn("Cannot determine the old folder name for %s.", entry.getKey());
                    continue;
                }
                try {
                    ZimbraLog.datasource.info("Deleting datasources that reference %s.", oldFolder.getPath());
                    Account account = oldFolder.getAccount();
                    List<DataSource> datasources = account.getAllDataSources();
                    for (DataSource datasource : datasources) {
                        if (datasource.getFolderId() == oldFolder.getId()) {
                            ZimbraLog.datasource.debug("Deleting datasource %s.", datasource.getName());
                            account.deleteDataSource(datasource.getId());
                        }
                    }
                } catch (ServiceException e) {
                    ZimbraLog.datasource.warn("Could not delete datasources for folder.", oldFolder.getPath());
                }
            }
        }
    }
}
Also used : Account(com.zimbra.cs.account.Account) MailItem(com.zimbra.cs.mailbox.MailItem) ServiceException(com.zimbra.common.service.ServiceException) ModificationKey(com.zimbra.cs.session.PendingModifications.ModificationKey) Change(com.zimbra.cs.session.PendingModifications.Change) Folder(com.zimbra.cs.mailbox.Folder) Map(java.util.Map) DataSource(com.zimbra.cs.account.DataSource)

Example 13 with Change

use of com.zimbra.cs.session.PendingModifications.Change in project zm-mailbox by Zimbra.

the class CalItemReminderService method notify.

@Override
public void notify(ChangeNotification notification) {
    Account account = notification.mailboxAccount;
    if (notification.mods.created != null) {
        for (Map.Entry<ModificationKey, MailItem> entry : notification.mods.created.entrySet()) {
            MailItem item = entry.getValue();
            if (item instanceof CalendarItem) {
                ZimbraLog.scheduler.debug("Handling creation of calendar item (id=%s,mailboxId=%s)", item.getId(), item.getMailboxId());
                scheduleNextReminders((CalendarItem) item, true, true);
            }
        }
    }
    if (notification.mods.modified != null) {
        for (Map.Entry<ModificationKey, Change> entry : notification.mods.modified.entrySet()) {
            Change change = entry.getValue();
            if (change.what instanceof CalendarItem) {
                CalendarItem calItem = (CalendarItem) change.what;
                ZimbraLog.scheduler.debug("Handling modification of calendar item (id=%s,mailboxId=%s)", calItem.getId(), calItem.getMailboxId());
                boolean calItemCanceled = false;
                try {
                    if ((change.why & Change.FOLDER) != 0 && calItem.inTrash()) {
                        calItemCanceled = true;
                    }
                } catch (ServiceException e) {
                    ZimbraLog.scheduler.error("Error in fetching calendar item's folder", e);
                }
                // cancel any existing reminders and schedule new ones if cal item not canceled
                if (cancelExistingReminders(calItem) && !calItemCanceled)
                    scheduleNextReminders(calItem, true, true);
            }
        }
    }
    if (notification.mods.deleted != null) {
        for (Map.Entry<ModificationKey, Change> entry : notification.mods.deleted.entrySet()) {
            MailItem.Type type = (MailItem.Type) entry.getValue().what;
            if (type == MailItem.Type.APPOINTMENT || type == MailItem.Type.TASK) {
                Mailbox mbox = null;
                try {
                    mbox = MailboxManager.getInstance().getMailboxByAccount(account, MailboxManager.FetchMode.DO_NOT_AUTOCREATE);
                } catch (ServiceException e) {
                    ZimbraLog.scheduler.error("Error looking up the mailbox of account %s", account.getId(), e);
                }
                if (mbox != null) {
                    cancelExistingReminders(entry.getKey().getItemId(), mbox.getId());
                }
            }
        }
    }
}
Also used : Account(com.zimbra.cs.account.Account) ModificationKey(com.zimbra.cs.session.PendingModifications.ModificationKey) Change(com.zimbra.cs.session.PendingModifications.Change) CalendarItem(com.zimbra.cs.mailbox.CalendarItem) MailItem(com.zimbra.cs.mailbox.MailItem) ServiceException(com.zimbra.common.service.ServiceException) Mailbox(com.zimbra.cs.mailbox.Mailbox) Map(java.util.Map)

Example 14 with Change

use of com.zimbra.cs.session.PendingModifications.Change in project zm-mailbox by Zimbra.

the class ShareStartStopListener method notify.

@Override
public void notify(ChangeNotification notification) {
    if (notification.mods.created != null) {
        // A new folder with non-empty ACL means start of sharing.
        for (MailItem created : notification.mods.created.values()) {
            if (created instanceof Folder) {
                Folder folder = (Folder) created;
                if (folder.getACL() != null) {
                    startShare(folder);
                }
            }
        }
    }
    if (notification.mods.modified != null) {
        // ACL change on folder can mean start or stop of sharing.
        for (Change change : notification.mods.modified.values()) {
            if ((change.why & Change.ACL) != 0 && change.preModifyObj instanceof Folder && change.what instanceof Folder) {
                Folder before = (Folder) change.preModifyObj;
                Folder after = (Folder) change.what;
                boolean beforeHasACL = before.getACL() != null;
                boolean afterHasACL = after.getACL() != null;
                if (!beforeHasACL && afterHasACL) {
                    startShare(after);
                } else if (beforeHasACL && !afterHasACL) {
                    stopShare(after);
                }
            // Note: No attempt is made to start/stop share based on the folder moving into
            // or out of trash/spam folder.  This is because no notification is generated
            // when the folder crosses the boundary by virtue of one of its parent folders moving.
            }
        }
    }
    if (notification.mods.deleted != null) {
        // Deletion of a folder with non-empty ACL stops sharing.
        for (Change change : notification.mods.deleted.values()) {
            Folder folder = null;
            if (change.what instanceof Folder) {
                folder = (Folder) change.what;
            } else if (change.preModifyObj instanceof Folder) {
                folder = (Folder) change.preModifyObj;
            }
            if (folder != null && folder.getACL() != null) {
                stopShare(folder);
            }
        }
    }
}
Also used : Change(com.zimbra.cs.session.PendingModifications.Change)

Example 15 with Change

use of com.zimbra.cs.session.PendingModifications.Change in project zm-mailbox by Zimbra.

the class TagTest method notifications.

@Test
public void notifications() throws Exception {
    Mailbox mbox = MailboxManager.getInstance().getMailboxByAccountId(MockProvisioning.DEFAULT_ACCOUNT_ID);
    MockListener ml = new MockListener();
    MailboxListener.register(ml);
    try {
        // new implicit tags should not be included in notifications
        DeliveryOptions dopt = new DeliveryOptions().setFolderId(Mailbox.ID_FOLDER_INBOX).setFlags(Flag.BITMASK_UNREAD).setTags(new String[] { tag2 });
        mbox.addMessage(null, ThreaderTest.getRootMessage(), dopt, null);
        for (MailItem item : ml.pms.created.values()) {
            Assert.assertFalse("implicit tags should not be notified", item instanceof Tag);
        }
        ml.clear();
        // new real tags *should* be included in notifications
        mbox.createTag(null, tag1, (byte) 0);
        Assert.assertFalse("explicit tag create must produce notifications", ml.pms.created.isEmpty());
        Assert.assertTrue("explicit tags must be notified", ml.pms.created.values().iterator().next() instanceof Tag);
        ml.clear();
        // changes to implicit tags should not be included in notifications
        int msgId = mbox.addMessage(null, ThreaderTest.getRootMessage(), dopt, null).getId();
        for (Change chg : ml.pms.modified.values()) {
            Assert.assertFalse("implicit tag changes should not be notified", chg.what instanceof Tag);
        }
        ml.clear();
        // changes to real tags *should* be included in notifications
        mbox.alterTag(null, msgId, MailItem.Type.MESSAGE, tag1, true, null);
        Assert.assertFalse("explicit tag apply must produce notifications", ml.pms.modified == null || ml.pms.modified.isEmpty());
        boolean found = false;
        for (Change chg : ml.pms.modified.values()) {
            found |= chg.what instanceof Tag;
        }
        Assert.assertTrue("explicit tag apply must be notified", found);
    } finally {
        MailboxListener.unregister(ml);
    }
}
Also used : DbTag(com.zimbra.cs.db.DbTag) Change(com.zimbra.cs.session.PendingModifications.Change) MockListener(com.zimbra.cs.mailbox.MailboxTest.MockListener) Test(org.junit.Test)

Aggregations

Change (com.zimbra.cs.session.PendingModifications.Change)15 MailItem (com.zimbra.cs.mailbox.MailItem)10 ModificationKey (com.zimbra.cs.session.PendingModifications.ModificationKey)10 Map (java.util.Map)10 ServiceException (com.zimbra.common.service.ServiceException)8 Folder (com.zimbra.cs.mailbox.Folder)6 HashMap (java.util.HashMap)5 ZFolder (com.zimbra.client.ZFolder)3 MemcachedMap (com.zimbra.common.util.memcached.MemcachedMap)3 DbTag (com.zimbra.cs.db.DbTag)3 Mailbox (com.zimbra.cs.mailbox.Mailbox)3 PendingModifications (com.zimbra.cs.session.PendingModifications)3 HashSet (java.util.HashSet)3 Account (com.zimbra.cs.account.Account)2 DbMailItem (com.zimbra.cs.db.DbMailItem)2 CalendarItem (com.zimbra.cs.mailbox.CalendarItem)2 Message (com.zimbra.cs.mailbox.Message)2 AlterItemTag (com.zimbra.cs.redolog.op.AlterItemTag)2 CreateFolder (com.zimbra.cs.redolog.op.CreateFolder)2 CreateTag (com.zimbra.cs.redolog.op.CreateTag)2