From 9bb55e837ab940335ecfdcb776fe45def974ef30 Mon Sep 17 00:00:00 2001 From: Alexey Pegov Date: Mon, 7 Dec 2009 20:00:23 +0300 Subject: [PATCH] [ex] 17284 AE: ComponentManagerImpl.getStateStore + Notification Model synchronization [r=jeka] --- .../notification/impl/NotificationModel.java | 191 +++++++++++++----- .../openapi/project/impl/ProjectImpl.java | 2 +- 2 files changed, 144 insertions(+), 49 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/notification/impl/NotificationModel.java b/platform/platform-impl/src/com/intellij/notification/impl/NotificationModel.java index a4c3c69429b4..5a02efb97bc0 100644 --- a/platform/platform-impl/src/com/intellij/notification/impl/NotificationModel.java +++ b/platform/platform-impl/src/com/intellij/notification/impl/NotificationModel.java @@ -20,6 +20,7 @@ import com.intellij.notification.NotificationType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.util.PairFunction; +import com.intellij.util.concurrency.ReentrantLock2; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -35,6 +36,8 @@ public class NotificationModel { private final Map> myNotifications = new LinkedHashMap>(); private final List myListeners = ContainerUtil.createEmptyCOWList(); + private final ReentrantLock2 myLock = new ReentrantLock2(); + public void addListener(@NotNull final NotificationModelListener listener) { myListeners.add(listener); } @@ -44,33 +47,59 @@ public class NotificationModel { } public void add(@NotNull final Notification notification, final @Nullable Project project) { - myNotifications.put(notification, Pair.create(project, false)); + try { + myLock.acquire(); + myNotifications.put(notification, Pair.create(project, false)); + } + finally { + myLock.release(); + } + for (NotificationModelListener listener : myListeners) { listener.notificationsAdded(notification); } + } public void markRead() { - if (myNotifications.size() > 0) { - final Collection tba = myNotifications.keySet(); + List changed = null; + + try { + myLock.acquire(); + if (myNotifications.isEmpty()) return; + + changed = new ArrayList(); + for (final Map.Entry> entry : myNotifications.entrySet()) { entry.setValue(new Pair(entry.getValue().first, true)); + changed.add(entry.getKey()); } + } + finally { + myLock.release(); + } + if (!changed.isEmpty()) { + final Notification[] read = changed.toArray(new Notification[changed.size()]); for (final NotificationModelListener listener : myListeners) { - listener.notificationsRead(tba.toArray(new Notification[tba.size()])); + listener.notificationsRead(read); } } } @Nullable public Notification remove(@NotNull final Notification notification) { - if (myNotifications.containsKey(notification)) { - myNotifications.remove(notification); + try { + myLock.acquire(); + final Pair pair = myNotifications.remove(notification); + if (pair == null) return notification; + } + finally { + myLock.release(); + } - for (NotificationModelListener listener : myListeners) { - listener.notificationsRemoved(notification); - } + for (NotificationModelListener listener : myListeners) { + listener.notificationsRemoved(notification); } return notification; @@ -78,35 +107,49 @@ public class NotificationModel { public void remove(@NotNull final Notification... notifications) { final List tbr = new ArrayList(); - for (final Notification notification : notifications) { - if (myNotifications.containsKey(notification)) { - tbr.add(notification); - myNotifications.remove(notification); + try { + myLock.acquire(); + for (final Notification notification : notifications) { + final Pair pair = myNotifications.remove(notification); + if (pair != null) { + tbr.add(notification); + } } } + finally { + myLock.release(); + } - if (tbr.size() > 0) { + if (!tbr.isEmpty()) { + final Notification[] removed = tbr.toArray((Notification[])Array.newInstance(tbr.get(0).getClass(), tbr.size())); for (NotificationModelListener listener : myListeners) { - listener.notificationsRemoved(tbr.toArray((Notification[])Array.newInstance(tbr.get(0).getClass(), tbr.size()))); + listener.notificationsRemoved(removed); } } } @Nullable public Notification get(final int index, @NotNull PairFunction filter) { - final LinkedList filtered = filterNotifications(filter); - if (index >= 0 && filtered.size() > index) { - return filtered.get(index); + try { + myLock.acquire(); + final List filtered = filterNotifications(filter); + if (index >= 0 && filtered.size() > index) { + return filtered.get(index); + } + } + finally { + myLock.release(); } return null; } - private LinkedList filterNotifications(@NotNull PairFunction filter) { - final LinkedList result = new LinkedList(); - final HashSet>> entries = - new HashSet>>(myNotifications.entrySet()); - for (final Map.Entry> entry : entries) { + private List filterNotifications(@NotNull PairFunction filter) { + LinkedList result; + if (myNotifications.isEmpty()) return Collections.emptyList(); + + result = new LinkedList(); + for (final Map.Entry> entry : myNotifications.entrySet()) { if (filter.fun(entry.getKey(), entry.getValue().first)) { result.addFirst(entry.getKey()); } @@ -116,7 +159,13 @@ public class NotificationModel { } public int getCount(@NotNull PairFunction filter) { - return filterNotifications(filter).size(); + try { + myLock.acquire(); + return filterNotifications(filter).size(); + } + finally { + myLock.release(); + } } public boolean isEmpty(@NotNull PairFunction filter) { @@ -125,18 +174,25 @@ public class NotificationModel { @Nullable public Notification getFirst(@NotNull PairFunction filter) { - final LinkedList result = filterNotifications(filter); - if (result.size() > 0) { - return result.getFirst(); + try { + myLock.acquire(); + final List result = filterNotifications(filter); + return result.isEmpty() ? null : result.get(0); + } + finally { + myLock.release(); } - - return null; } public void clear(@NotNull PairFunction filter) { - final LinkedList result = filterNotifications(filter); - for (final Notification notification : result) { - myNotifications.remove(notification); + List result; + try { + myLock.acquire(); + result = filterNotifications(filter); + myNotifications.keySet().removeAll(result); + } + finally { + myLock.release(); } if (!result.isEmpty()) { @@ -149,28 +205,53 @@ public class NotificationModel { public List getByType(@Nullable final NotificationType type, @NotNull PairFunction filter) { if (type == null) { - return Collections.unmodifiableList(filterNotifications(filter)); - } - else { - final List result = new ArrayList(); - final LinkedList filtered = filterNotifications(filter); - for (final Notification notification : filtered) { - if (type == notification.getType()) { - result.add(notification); - } + try { + myLock.acquire(); + return Collections.unmodifiableList(filterNotifications(filter)); + } + finally { + myLock.release(); } - - return result; } + + final List filtered; + try { + myLock.acquire(); + filtered = filterNotifications(filter); + } + finally { + myLock.release(); + } + + final List result = new ArrayList(); + for (final Notification notification : filtered) { + if (type == notification.getType()) { + result.add(notification); + } + } + + return result; } public boolean wasRead(final Notification notification) { - final Pair pair = myNotifications.get(notification); - return pair != null && pair.second; + try { + myLock.acquire(); + final Pair pair = myNotifications.get(notification); + return pair != null && pair.second; + } + finally { + myLock.release(); + } } public boolean hasUnread(final PairFunction filter) { - return getUnreadCount(filter) > 0; + try { + myLock.acquire(); + return getUnreadCount(filter) > 0; + } + finally { + myLock.release(); + } } private int getUnreadCount(final PairFunction filter) { @@ -182,12 +263,26 @@ public class NotificationModel { } public boolean hasRead(PairFunction filter) { - return getUnreadCount(filter) < myNotifications.size(); + try { + myLock.acquire(); + return getUnreadCount(filter) < myNotifications.size(); + } + finally { + myLock.release(); + } } @Nullable public NotificationType getMaximumType(PairFunction filter) { - final LinkedList notifications = filterNotifications(filter); + final List notifications; + try { + myLock.acquire(); + notifications = filterNotifications(filter); + } + finally { + myLock.release(); + } + NotificationType result = null; for (Notification notification : notifications) { if (NotificationType.ERROR == notification.getType()) { diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java index 23cea6f0382b..3a9b498ea3b6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java @@ -225,7 +225,7 @@ public class ProjectImpl extends ComponentManagerImpl implements ProjectEx { @Nullable @NonNls public String getLocation() { - return getStateStore().getLocation(); + return isDisposed() ? null : getStateStore().getLocation(); } @Deprecated