/** * Find an observer list for the specified name or creates a new one if not found. */ private synchronized ApptentiveNotificationObserverList resolveObserverList(String name) { ApptentiveNotificationObserverList list = observerListLookup.get(name); if (list == null) { list = new ApptentiveNotificationObserverList(); observerListLookup.put(name, list); } return list; }
/** * Adds an entry to the receiver’s dispatch table with an observer. * * @param useWeakReference - weak reference is used if <code>true</code> */ public synchronized void addObserver(String notification, ApptentiveNotificationObserver observer, boolean useWeakReference) { final ApptentiveNotificationObserverList list = resolveObserverList(notification); list.addObserver(observer, useWeakReference); }
/** * Removes all the entries specifying a given observer from the receiver’s dispatch table. */ public synchronized void removeObserver(final ApptentiveNotificationObserver observer) { for (ApptentiveNotificationObserverList observers : observerListLookup.values()) { observers.removeObserver(observer); } }
@Test public void testAddObservers() { ApptentiveNotificationObserverList list = new ApptentiveNotificationObserverList(); Observer o1 = new Observer("observer1"); Observer o2 = new Observer("observer2"); list.addObserver(o1, WEAK_REFERENCE); list.addObserver(o2, STRONG_REFERENCE); assertEquals(2, list.size()); // trying to add duplicates list.addObserver(o1, WEAK_REFERENCE); list.addObserver(o1, STRONG_REFERENCE); assertEquals(2, list.size()); list.addObserver(o2, WEAK_REFERENCE); list.addObserver(o2, STRONG_REFERENCE); assertEquals(2, list.size()); list.notifyObservers(new ApptentiveNotification("notification", new HashMap<String, Object>())); assertResult("observer1", "observer2"); }
@Test public void testThrowingException() { final ApptentiveNotificationObserverList list = new ApptentiveNotificationObserverList(); final Observer o1 = new Observer("observer1"); final Observer o2 = new Observer("observer2"); list.addObserver(o1, STRONG_REFERENCE); list.addObserver(new ApptentiveNotificationObserver() { @Override public void onReceiveNotification(ApptentiveNotification notification) { addResult("error"); throw new RuntimeException("Error"); } }, STRONG_REFERENCE); list.addObserver(o2, STRONG_REFERENCE); list.notifyObservers(new ApptentiveNotification("notification", new HashMap<String, Object>())); assertResult("observer1", "error", "observer2"); }
/** * Creates a notification with a given name and user info and posts it to the receiver. */ public synchronized void postNotification(final String name, final Map<String, Object> userInfo) { ApptentiveLog.v(NOTIFICATIONS, "Post notification: name=%s userInfo={%s}", name, StringUtils.toString(userInfo)); final ApptentiveNotificationObserverList list = findObserverList(name); if (list != null) { list.notifyObservers(new ApptentiveNotification(name, userInfo)); } }
/** * Checks if observer or its weak references are in the list. */ private boolean contains(ApptentiveNotificationObserver observer) { return indexOf(observer) != -1; }
/** * Adds an observer to the list without duplicates. * * @param useWeakReference - use weak reference if <code>true</code> * @return <code>true</code> - if observer was added */ boolean addObserver(ApptentiveNotificationObserver observer, boolean useWeakReference) { if (observer == null) { throw new IllegalArgumentException("Observer is null"); } if (!contains(observer)) { observers.add(useWeakReference ? new ObserverWeakReference(observer) : observer); return true; } return false; }
@Test public void testRemoveObservers() { ApptentiveNotificationObserverList list = new ApptentiveNotificationObserverList(); Observer o1 = new Observer("observer1"); Observer o2 = new Observer("observer2"); list.addObserver(o1, WEAK_REFERENCE); list.addObserver(o2, STRONG_REFERENCE); list.notifyObservers(new ApptentiveNotification("notification", new HashMap<String, Object>())); assertResult("observer1", "observer2"); assertEquals(2, list.size()); list.removeObserver(o1); assertEquals(1, list.size()); list.notifyObservers(new ApptentiveNotification("notification", new HashMap<String, Object>())); assertResult("observer2"); list.removeObserver(o2); list.notifyObservers(new ApptentiveNotification("notification", new HashMap<String, Object>())); assertResult(); assertEquals(0, list.size()); }
/** * Removes observer os its weak reference from the list * * @return <code>true</code> if observer was returned */ boolean removeObserver(ApptentiveNotificationObserver observer) { int index = indexOf(observer); if (index != -1) { observers.remove(index); return true; } return false; }
@Test public void testConcurrentModification() { final ApptentiveNotificationObserverList list = new ApptentiveNotificationObserverList(); final Observer o1 = new Observer("observer1"); final Observer o2 = new Observer("observer2"); list.addObserver(new ApptentiveNotificationObserver() { @Override public void onReceiveNotification(ApptentiveNotification notification) { list.removeObserver(o1); addResult("anonymous-observer1"); } }, STRONG_REFERENCE); list.addObserver(o1, WEAK_REFERENCE); list.addObserver(new ApptentiveNotificationObserver() { @Override public void onReceiveNotification(ApptentiveNotification notification) { list.removeObserver(o2); addResult("anonymous-observer2"); } }, STRONG_REFERENCE); list.addObserver(o2, STRONG_REFERENCE); list.notifyObservers(new ApptentiveNotification("notification", new HashMap<String, Object>())); assertResult("anonymous-observer1", "observer1", "anonymous-observer2", "observer2"); assertEquals(2, list.size()); list.notifyObservers(new ApptentiveNotification("notification", new HashMap<String, Object>())); assertResult("anonymous-observer1", "anonymous-observer2"); assertEquals(2, list.size()); }
/** * Removes matching entries from the receiver’s dispatch table. */ public synchronized void removeObserver(final String notification, final ApptentiveNotificationObserver observer) { final ApptentiveNotificationObserverList list = findObserverList(notification); if (list != null) { list.removeObserver(observer); } }
@Test public void testWeakReferences() { ApptentiveNotificationObserverList list = new ApptentiveNotificationObserverList(); // begin of the scope { Observer o1 = new Observer("observer1"); Observer o4 = new Observer("observer4"); list.addObserver(o1, WEAK_REFERENCE); // this reference won't be lost until the end of the current scope list.addObserver(new Observer("observer2"), WEAK_REFERENCE); // this reference would be lost right away list.addObserver(new Observer("observer3"), STRONG_REFERENCE); // this reference won't be lost list.addObserver(o4, STRONG_REFERENCE); // force GC so the weak reference becomes null System.gc(); list.notifyObservers(new ApptentiveNotification("notification", new HashMap<String, Object>())); assertResult("observer1", "observer3", "observer4"); assertEquals(3, list.size()); o1 = o4 = null; // this step is necessary for a proper GC } // end of the scope // force GC so the weak reference becomes null System.gc(); list.notifyObservers(new ApptentiveNotification("notification", new HashMap<String, Object>())); assertResult("observer3", "observer4"); assertEquals(2, list.size()); }
@Override public void onReceiveNotification(ApptentiveNotification notification) { list.removeObserver(o1); addResult("anonymous-observer1"); } }, STRONG_REFERENCE);
@Override public void onReceiveNotification(ApptentiveNotification notification) { list.removeObserver(o2); addResult("anonymous-observer2"); } }, STRONG_REFERENCE);