Search in sources :

Example 6 with Change

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

the class Mailbox method isItemModified.

/** Returns whether the given item has been marked dirty for a particular
     *  reason during the current transaction.  Outside of a transaction, this
     *  method will return {@code false}.
     * @param item  The {@code MailItem} we're interested in.
     * @param how   A bitmask of {@link Change} "why" flags (e.g. {@code
     *              Change#MODIFIED_FLAGS}).
     * @see Change */
public boolean isItemModified(MailItem item, int how) {
    PendingModifications dirty = currentChange().dirty;
    if (!dirty.hasNotifications()) {
        return false;
    }
    PendingModifications.ModificationKey mkey = new PendingModifications.ModificationKey(item);
    if (dirty.created != null && dirty.created.containsKey(mkey)) {
        return true;
    }
    Change chg = dirty.modified == null ? null : dirty.modified.get(mkey);
    return chg != null && (chg.why & how) != 0;
}
Also used : PendingModifications(com.zimbra.cs.session.PendingModifications) Change(com.zimbra.cs.session.PendingModifications.Change)

Example 7 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)

Example 8 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 9 with Change

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

the class ImapSession method notifyPendingChanges.

@Override
public void notifyPendingChanges(PendingModifications pns, int changeId, Session source) {
    if (!pns.hasNotifications()) {
        return;
    }
    ImapHandler i4handler = handler;
    try {
        synchronized (this) {
            AddedItems added = new AddedItems();
            if (pns.deleted != null) {
                for (Map.Entry<ModificationKey, Change> entry : pns.deleted.entrySet()) {
                    handleDelete(changeId, entry.getKey().getItemId(), entry.getValue());
                }
            }
            if (pns.created != null) {
                for (MailItem item : pns.created.values()) {
                    handleCreate(changeId, item, added);
                }
            }
            if (pns.modified != null) {
                for (Change chg : pns.modified.values()) {
                    handleModify(changeId, chg, added);
                }
            }
            // add new messages to the currently selected mailbox
            if (!added.isEmpty()) {
                mFolder.handleAddedMessages(changeId, added);
            }
            mFolder.finishNotification(changeId);
        }
        if (i4handler != null && i4handler.isIdle()) {
            i4handler.sendNotifications(true, true);
        }
    } catch (IOException e) {
        //   which calls Session.doCleanup, which calls Mailbox.removeListener
        if (ZimbraLog.imap.isDebugEnabled()) {
            // with stack trace
            ZimbraLog.imap.debug("Failed to notify, closing %s", this, e);
        } else {
            // without stack trace
            ZimbraLog.imap.info("Failed to notify (%s), closing %s", e.toString(), this);
        }
        if (i4handler != null) {
            i4handler.close();
        }
    }
}
Also used : MailItem(com.zimbra.cs.mailbox.MailItem) ModificationKey(com.zimbra.cs.session.PendingModifications.ModificationKey) Change(com.zimbra.cs.session.PendingModifications.Change) IOException(java.io.IOException) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) TreeMap(java.util.TreeMap)

Example 10 with Change

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

the class CalListCache method notifyCommittedChanges.

void notifyCommittedChanges(PendingModifications mods, int changeId) {
    ChangeMap changeMap = new ChangeMap(1);
    if (mods.created != null) {
        for (Map.Entry<ModificationKey, MailItem> entry : mods.created.entrySet()) {
            MailItem item = entry.getValue();
            if (item instanceof Folder) {
                Folder folder = (Folder) item;
                MailItem.Type viewType = folder.getDefaultView();
                if (viewType == MailItem.Type.APPOINTMENT || viewType == MailItem.Type.TASK) {
                    ChangedFolders changedFolders = changeMap.getAccount(entry.getKey().getAccountId());
                    changedFolders.created.add(folder.getId());
                }
            }
        }
    }
    if (mods.modified != null) {
        for (Map.Entry<ModificationKey, Change> entry : mods.modified.entrySet()) {
            Change change = entry.getValue();
            Object whatChanged = change.what;
            if (whatChanged instanceof Folder) {
                Folder folder = (Folder) whatChanged;
                MailItem.Type viewType = folder.getDefaultView();
                if (viewType == MailItem.Type.APPOINTMENT || viewType == MailItem.Type.TASK) {
                    ChangedFolders changedFolders = changeMap.getAccount(entry.getKey().getAccountId());
                    int folderId = folder.getId();
                    if ((change.why & Change.FOLDER) != 0) {
                        // moving the calendar folder to another parent folder
                        int parentFolder = folder.getFolderId();
                        changedFolders.created.add(folderId);
                        if (parentFolder == Mailbox.ID_FOLDER_TRASH) {
                            changedFolders.deleted.add(folderId);
                        } else {
                            changedFolders.created.add(folderId);
                        }
                    } else {
                        // not a folder move, but something else changed, either calendar's metadata
                        // or a child item (appointment/task)
                        changedFolders.modified.add(folderId);
                    }
                }
            } else if (whatChanged instanceof Message) {
                Message msg = (Message) whatChanged;
                if (msg.hasCalendarItemInfos()) {
                    if (msg.getFolderId() == Mailbox.ID_FOLDER_INBOX || (change.why & Change.FOLDER) != 0) {
                        // If message was moved, we don't know which folder it was moved from.
                        // Just invalidate the Inbox because that's the only message folder we care
                        // about in calendaring.
                        ChangedFolders changedFolders = changeMap.getAccount(entry.getKey().getAccountId());
                        changedFolders.modified.add(Mailbox.ID_FOLDER_INBOX);
                    }
                }
            }
        }
    }
    if (mods.deleted != null) {
        for (Map.Entry<ModificationKey, Change> entry : mods.deleted.entrySet()) {
            MailItem.Type type = (MailItem.Type) entry.getValue().what;
            if (type == MailItem.Type.FOLDER) {
                // We only have item id.  Let's just assume it's a calendar folder id and check
                // against the cached list.
                ChangedFolders changedFolders = changeMap.getAccount(entry.getKey().getAccountId());
                changedFolders.deleted.add(entry.getKey().getItemId());
            }
        // Let's not worry about hard deletes of invite/reply emails.  It has no practical benefit.
        }
    }
    try {
        for (Map.Entry<String, ChangedFolders> entry : changeMap.entrySet()) {
            ChangedFolders changedFolders = entry.getValue();
            if (changedFolders.isEmpty())
                continue;
            String accountId = entry.getKey();
            AccountKey key = new AccountKey(accountId);
            CalList list = mMemcachedLookup.get(key);
            if (list != null) {
                boolean updated = false;
                CalList newList = new CalList(list);
                for (Integer folderId : changedFolders.created) {
                    if (!list.contains(folderId)) {
                        updated = true;
                        newList.add(folderId);
                    }
                }
                for (Integer folderId : changedFolders.modified) {
                    if (list.contains(folderId))
                        updated = true;
                }
                for (Integer folderId : changedFolders.deleted) {
                    if (list.contains(folderId)) {
                        updated = true;
                        newList.remove(folderId);
                    }
                }
                // There was a change.  Increment the version and put back to cache.
                if (updated) {
                    newList.incrementSeq();
                    mMemcachedLookup.put(key, newList);
                }
            }
        }
    } catch (ServiceException e) {
        ZimbraLog.calendar.warn("Unable to notify calendar list cache.  Some cached data may become stale.", e);
    }
}
Also used : Message(com.zimbra.cs.mailbox.Message) ModificationKey(com.zimbra.cs.session.PendingModifications.ModificationKey) Change(com.zimbra.cs.session.PendingModifications.Change) Folder(com.zimbra.cs.mailbox.Folder) MailItem(com.zimbra.cs.mailbox.MailItem) ServiceException(com.zimbra.common.service.ServiceException) HashMap(java.util.HashMap) Map(java.util.Map) MemcachedMap(com.zimbra.common.util.memcached.MemcachedMap)

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