From b3317c79436a6268182a2505bf03e7d4ed4d945a Mon Sep 17 00:00:00 2001 From: andrzej Date: Sat, 9 Aug 2008 01:36:33 +0000 Subject: [PATCH] Added WeakObserverList, which allows observers to be garbage-collected. git-svn-id: https://samskivert.googlecode.com/svn/trunk@2360 6335cc39-0255-0410-8fd6-9bcaacd3b74c --- .../com/samskivert/util/WeakObserverList.java | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 src/java/com/samskivert/util/WeakObserverList.java diff --git a/src/java/com/samskivert/util/WeakObserverList.java b/src/java/com/samskivert/util/WeakObserverList.java new file mode 100644 index 00000000..2ac12495 --- /dev/null +++ b/src/java/com/samskivert/util/WeakObserverList.java @@ -0,0 +1,211 @@ +// +// $Id$ +// +// samskivert library - useful routines for java programs +// Copyright (C) 2001-2007 Michael Bayne +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.util; + +import java.lang.ref.WeakReference; + +import java.util.AbstractList; + +import com.samskivert.util.ObserverList.ObserverOp; + +/** + * An {@link ObserverList} equivalent that does not prevent added observers from being + * garbage-collected. + */ +public class WeakObserverList extends AbstractList +{ + /** + * A convenience method for creating an observer list that avoids duplicating the type + * parameter on the right hand side. + */ + public static WeakObserverList newSafeInOrder () + { + return new WeakObserverList(ObserverList.SAFE_IN_ORDER_NOTIFY); + } + + /** + * A convenience method for creating an observer list that avoids duplicating the type + * parameter on the right hand side. + */ + public static WeakObserverList newFastUnsafe () + { + return new WeakObserverList(ObserverList.FAST_UNSAFE_NOTIFY); + } + + /** + * A convenience method for creating an observer list that avoids duplicating the type + * parameter on the right hand side. + */ + public static WeakObserverList newList (int notifyPolicy, boolean allowDups) + { + return new WeakObserverList(notifyPolicy, allowDups); + } + + /** + * Creates an empty observer list with the supplied notification + * policy and that only allows observers to observe the list once. + * + * @param notifyPolicy Either {@link ObserverList#SAFE_IN_ORDER_NOTIFY} or {@link + * ObserverList#FAST_UNSAFE_NOTIFY}. + */ + public WeakObserverList (int notifyPolicy) + { + this(notifyPolicy, false); + } + + /** + * Creates an empty observer list with the supplied notification and + * duplicate observer policy. + * + * @param notifyPolicy Either {@link ObserverList#SAFE_IN_ORDER_NOTIFY} or {@link + * ObserverList#FAST_UNSAFE_NOTIFY}. + * @param allowDups whether to allow observers to be added to the list + * more than once. + */ + public WeakObserverList (int notifyPolicy, boolean allowDups) + { + // dereference the elements when searching for a value + _wrappedList = new ObserverList>(notifyPolicy, allowDups) { + public int indexOf (Object element) { + @SuppressWarnings("unchecked") WeakReference ref = + (WeakReference)element; + T value = ref.get(); + for (int ii = 0, nn = size(); ii < nn; ii++) { + if (value == get(ii).get()) { + return ii; + } + } + return -1; + } + public int lastIndexOf (Object element) { + @SuppressWarnings("unchecked") WeakReference ref = + (WeakReference)element; + T value = ref.get(); + for (int ii = size() - 1; ii >= 0; ii--) { + if (value == get(ii).get()) { + return ii; + } + } + return -1; + } + }; + } + + @Override // documentation inherited + public int size () + { + return _wrappedList.size(); + } + + @Override // documentation inherited + public boolean contains (Object element) + { + @SuppressWarnings("unchecked") T value = (T)element; + return _wrappedList.contains(new WeakReference(value)); + } + + @Override // documentation inherited + public boolean remove (Object element) + { + @SuppressWarnings("unchecked") T value = (T)element; + return _wrappedList.remove(new WeakReference(value)); + } + + @Override // documentation inherited + public int indexOf (Object element) + { + @SuppressWarnings("unchecked") T value = (T)element; + return _wrappedList.indexOf(new WeakReference(value)); + } + + @Override // documentation inherited + public int lastIndexOf (Object element) + { + @SuppressWarnings("unchecked") T value = (T)element; + return _wrappedList.lastIndexOf(new WeakReference(value)); + } + + @Override // documentation inherited + public T get (int index) + { + return _wrappedList.get(index).get(); + } + + @Override // documentation inherited + public T set (int index, T element) + { + return _wrappedList.set(index, new WeakReference(element)).get(); + } + + @Override // documentation inherited + public void add (int index, T element) + { + _wrappedList.add(index, new WeakReference(element)); + } + + @Override // documentation inherited + public T remove (int index) + { + return _wrappedList.remove(index).get(); + } + + /** + * Applies the supplied observer operation to all observers in the + * list in a manner conforming to the notification ordering policy + * specified at construct time. + */ + public void apply (ObserverOp obop) + { + _derefOp.init(obop); + _wrappedList.apply(_derefOp); + } + + /** + * An operation that resolves a reference and applies a wrapped op. + */ + protected static class DerefOp + implements ObserverOp> + { + /** + * (Re)initializes this op with a reference to the wrapped op. + */ + public void init (ObserverOp op) + { + _op = op; + } + + // documentation inherited from interface ObserverOp + public boolean apply (WeakReference ref) + { + T observer = ref.get(); + return observer != null && _op.apply(observer); + } + + /** The wrapped op. */ + protected ObserverOp _op; + } + + /** The wrapped list. */ + protected ObserverList> _wrappedList; + + /** The wrapper op. */ + protected DerefOp _derefOp = new DerefOp(); +}