[ex] 17284 AE: ComponentManagerImpl.getStateStore + Notification Model synchronization [r=jeka]

This commit is contained in:
Alexey Pegov
2009-12-07 20:00:23 +03:00
parent 9b80dd090f
commit 9bb55e837a
2 changed files with 144 additions and 49 deletions
@@ -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<Notification, Pair<Project, Boolean>> myNotifications = new LinkedHashMap<Notification, Pair<Project, Boolean>>();
private final List<NotificationModelListener> 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<Notification> tba = myNotifications.keySet();
List<Notification> changed = null;
try {
myLock.acquire();
if (myNotifications.isEmpty()) return;
changed = new ArrayList<Notification>();
for (final Map.Entry<Notification, Pair<Project, Boolean>> entry : myNotifications.entrySet()) {
entry.setValue(new Pair<Project, Boolean>(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<Project, Boolean> 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<Notification> tbr = new ArrayList<Notification>();
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<Project, Boolean> 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<Notification, Project, Boolean> filter) {
final LinkedList<Notification> filtered = filterNotifications(filter);
if (index >= 0 && filtered.size() > index) {
return filtered.get(index);
try {
myLock.acquire();
final List<Notification> filtered = filterNotifications(filter);
if (index >= 0 && filtered.size() > index) {
return filtered.get(index);
}
}
finally {
myLock.release();
}
return null;
}
private LinkedList<Notification> filterNotifications(@NotNull PairFunction<Notification, Project, Boolean> filter) {
final LinkedList<Notification> result = new LinkedList<Notification>();
final HashSet<Map.Entry<Notification, Pair<Project, Boolean>>> entries =
new HashSet<Map.Entry<Notification, Pair<Project, Boolean>>>(myNotifications.entrySet());
for (final Map.Entry<Notification, Pair<Project, Boolean>> entry : entries) {
private List<Notification> filterNotifications(@NotNull PairFunction<Notification, Project, Boolean> filter) {
LinkedList<Notification> result;
if (myNotifications.isEmpty()) return Collections.emptyList();
result = new LinkedList<Notification>();
for (final Map.Entry<Notification, Pair<Project, Boolean>> 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<Notification, Project, Boolean> filter) {
return filterNotifications(filter).size();
try {
myLock.acquire();
return filterNotifications(filter).size();
}
finally {
myLock.release();
}
}
public boolean isEmpty(@NotNull PairFunction<Notification, Project, Boolean> filter) {
@@ -125,18 +174,25 @@ public class NotificationModel {
@Nullable
public Notification getFirst(@NotNull PairFunction<Notification, Project, Boolean> filter) {
final LinkedList<Notification> result = filterNotifications(filter);
if (result.size() > 0) {
return result.getFirst();
try {
myLock.acquire();
final List<Notification> result = filterNotifications(filter);
return result.isEmpty() ? null : result.get(0);
}
finally {
myLock.release();
}
return null;
}
public void clear(@NotNull PairFunction<Notification, Project, Boolean> filter) {
final LinkedList<Notification> result = filterNotifications(filter);
for (final Notification notification : result) {
myNotifications.remove(notification);
List<Notification> 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<Notification> getByType(@Nullable final NotificationType type, @NotNull PairFunction<Notification, Project, Boolean> filter) {
if (type == null) {
return Collections.unmodifiableList(filterNotifications(filter));
}
else {
final List<Notification> result = new ArrayList<Notification>();
final LinkedList<Notification> 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<Notification> filtered;
try {
myLock.acquire();
filtered = filterNotifications(filter);
}
finally {
myLock.release();
}
final List<Notification> result = new ArrayList<Notification>();
for (final Notification notification : filtered) {
if (type == notification.getType()) {
result.add(notification);
}
}
return result;
}
public boolean wasRead(final Notification notification) {
final Pair<Project, Boolean> pair = myNotifications.get(notification);
return pair != null && pair.second;
try {
myLock.acquire();
final Pair<Project, Boolean> pair = myNotifications.get(notification);
return pair != null && pair.second;
}
finally {
myLock.release();
}
}
public boolean hasUnread(final PairFunction<Notification, Project, Boolean> filter) {
return getUnreadCount(filter) > 0;
try {
myLock.acquire();
return getUnreadCount(filter) > 0;
}
finally {
myLock.release();
}
}
private int getUnreadCount(final PairFunction<Notification, Project, Boolean> filter) {
@@ -182,12 +263,26 @@ public class NotificationModel {
}
public boolean hasRead(PairFunction<Notification, Project, Boolean> filter) {
return getUnreadCount(filter) < myNotifications.size();
try {
myLock.acquire();
return getUnreadCount(filter) < myNotifications.size();
}
finally {
myLock.release();
}
}
@Nullable
public NotificationType getMaximumType(PairFunction<Notification, Project, Boolean> filter) {
final LinkedList<Notification> notifications = filterNotifications(filter);
final List<Notification> notifications;
try {
myLock.acquire();
notifications = filterNotifications(filter);
}
finally {
myLock.release();
}
NotificationType result = null;
for (Notification notification : notifications) {
if (NotificationType.ERROR == notification.getType()) {
@@ -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