Added WeakObserverList, which allows observers to be
garbage-collected. git-svn-id: https://samskivert.googlecode.com/svn/trunk@2360 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -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<T> extends AbstractList<T>
|
||||
{
|
||||
/**
|
||||
* A convenience method for creating an observer list that avoids duplicating the type
|
||||
* parameter on the right hand side.
|
||||
*/
|
||||
public static <T> WeakObserverList<T> newSafeInOrder ()
|
||||
{
|
||||
return new WeakObserverList<T>(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 <T> WeakObserverList<T> newFastUnsafe ()
|
||||
{
|
||||
return new WeakObserverList<T>(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 <T> WeakObserverList<T> newList (int notifyPolicy, boolean allowDups)
|
||||
{
|
||||
return new WeakObserverList<T>(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<WeakReference<T>>(notifyPolicy, allowDups) {
|
||||
public int indexOf (Object element) {
|
||||
@SuppressWarnings("unchecked") WeakReference<T> ref =
|
||||
(WeakReference<T>)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<T> ref =
|
||||
(WeakReference<T>)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<T>(value));
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public boolean remove (Object element)
|
||||
{
|
||||
@SuppressWarnings("unchecked") T value = (T)element;
|
||||
return _wrappedList.remove(new WeakReference<T>(value));
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public int indexOf (Object element)
|
||||
{
|
||||
@SuppressWarnings("unchecked") T value = (T)element;
|
||||
return _wrappedList.indexOf(new WeakReference<T>(value));
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public int lastIndexOf (Object element)
|
||||
{
|
||||
@SuppressWarnings("unchecked") T value = (T)element;
|
||||
return _wrappedList.lastIndexOf(new WeakReference<T>(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<T>(element)).get();
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public void add (int index, T element)
|
||||
{
|
||||
_wrappedList.add(index, new WeakReference<T>(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<T> obop)
|
||||
{
|
||||
_derefOp.init(obop);
|
||||
_wrappedList.apply(_derefOp);
|
||||
}
|
||||
|
||||
/**
|
||||
* An operation that resolves a reference and applies a wrapped op.
|
||||
*/
|
||||
protected static class DerefOp<T>
|
||||
implements ObserverOp<WeakReference<T>>
|
||||
{
|
||||
/**
|
||||
* (Re)initializes this op with a reference to the wrapped op.
|
||||
*/
|
||||
public void init (ObserverOp<T> op)
|
||||
{
|
||||
_op = op;
|
||||
}
|
||||
|
||||
// documentation inherited from interface ObserverOp
|
||||
public boolean apply (WeakReference<T> ref)
|
||||
{
|
||||
T observer = ref.get();
|
||||
return observer != null && _op.apply(observer);
|
||||
}
|
||||
|
||||
/** The wrapped op. */
|
||||
protected ObserverOp<T> _op;
|
||||
}
|
||||
|
||||
/** The wrapped list. */
|
||||
protected ObserverList<WeakReference<T>> _wrappedList;
|
||||
|
||||
/** The wrapper op. */
|
||||
protected DerefOp<T> _derefOp = new DerefOp<T>();
|
||||
}
|
||||
Reference in New Issue
Block a user