Index: jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java =================================================================== --- jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java (revision 697717) +++ jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java (working copy) @@ -93,6 +93,9 @@ import javax.security.auth.Subject; import java.io.File; import java.io.PrintStream; +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; import java.security.AccessControlException; import java.util.ArrayList; import java.util.Collection; @@ -231,6 +234,12 @@ * Retention and Hold Manager */ private RetentionManager retentionManager; + + /** + * A weak reference to this object. It should be used for components that + * don't need a hard link to this object. + */ + private WeakReference reference = new WeakReference(this); /** * Protected constructor. @@ -1641,5 +1650,20 @@ ps.println(); itemStateMgr.dump(ps); } + + /** + * Get the weak reference for this object. + * + * @return the weak reference + */ + public Reference getReference() { + return reference; + } + + public void finalize() { + int test; + System.out.println("Unclosed session detected: " + this); + logout(); + } } Index: jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TransientRepository.java =================================================================== --- jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TransientRepository.java (revision 697717) +++ jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TransientRepository.java (working copy) @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.ref.Reference; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; @@ -331,9 +332,9 @@ try { logger.debug("Opening a new session"); - Session session = repository.login(credentials, workspaceName); - sessions.add(session); - ((SessionImpl) session).addListener(this); + SessionImpl session = (SessionImpl) repository.login(credentials, workspaceName); + sessions.add(session.getReference()); + session.addListener(this); logger.info("Session opened"); return session; @@ -395,8 +396,11 @@ public synchronized void shutdown() { Iterator iterator = new HashSet(sessions).iterator(); while (iterator.hasNext()) { - Session session = (Session) iterator.next(); - session.logout(); + Reference reference = (Reference) iterator.next(); + Session session = (Session) reference.get(); + if (session != null) { + session.logout(); + } } } @@ -410,8 +414,8 @@ * @see SessionListener#loggedOut(SessionImpl) */ public synchronized void loggedOut(SessionImpl session) { - assert sessions.contains(session); - sessions.remove(session); + assert sessions.contains(session.getReference()); + sessions.remove(session.getReference()); logger.info("Session closed"); if (sessions.isEmpty()) { // FIXME: This is an ugly hack to avoid an infinite loop when Index: jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/StateChangeDispatcher.java =================================================================== --- jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/StateChangeDispatcher.java (revision 697717) +++ jackrabbit/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/StateChangeDispatcher.java (working copy) @@ -20,6 +20,8 @@ import org.apache.jackrabbit.core.NodeId; import org.apache.jackrabbit.spi.Name; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; import java.util.Collection; import java.util.Iterator; @@ -44,14 +46,25 @@ * @param listener the new listener to be informed on modifications */ public void addListener(ItemStateListener listener) { - assert (!listeners.contains(listener)); - listeners.add(listener); + assert getReference(listeners, listener) == null; + listeners.add(new WeakReference(listener)); if (listener instanceof NodeStateListener) { - assert (!nsListeners.contains(listener)); - nsListeners.add(listener); + assert getReference(nsListeners, listener) == null; + nsListeners.add(new WeakReference(listener)); } } + + private Reference getReference(Collection coll, ItemStateListener listener) { + Iterator iter = listeners.iterator(); + while (iter.hasNext()) { + Reference ref = (Reference) iter.next(); + if (ref.get() == listener) { + return ref; + } + } + return null; + } /** * Remove an ItemStateListener @@ -59,9 +72,9 @@ */ public void removeListener(ItemStateListener listener) { if (listener instanceof NodeStateListener) { - nsListeners.remove(listener); + nsListeners.remove(getReference(nsListeners, listener)); } - listeners.remove(listener); + listeners.remove(getReference(listeners, listener)); } /** @@ -71,7 +84,11 @@ public void notifyStateCreated(ItemState created) { Iterator iter = listeners.iterator(); while (iter.hasNext()) { - ((ItemStateListener) iter.next()).stateCreated(created); + Reference ref = (Reference) iter.next(); + ItemStateListener l = (ItemStateListener) ref.get(); + if (l != null) { + l.stateCreated(created); + } } } @@ -82,7 +99,11 @@ public void notifyStateModified(ItemState modified) { Iterator iter = listeners.iterator(); while (iter.hasNext()) { - ((ItemStateListener) iter.next()).stateModified(modified); + Reference ref = (Reference) iter.next(); + ItemStateListener l = (ItemStateListener) ref.get(); + if (l != null) { + l.stateModified(modified); + } } } @@ -93,7 +114,11 @@ public void notifyStateDestroyed(ItemState destroyed) { Iterator iter = listeners.iterator(); while (iter.hasNext()) { - ((ItemStateListener) iter.next()).stateDestroyed(destroyed); + Reference ref = (Reference) iter.next(); + ItemStateListener l = (ItemStateListener) ref.get(); + if (l != null) { + l.stateDestroyed(destroyed); + } } } @@ -104,7 +129,11 @@ public void notifyStateDiscarded(ItemState discarded) { Iterator iter = listeners.iterator(); while (iter.hasNext()) { - ((ItemStateListener) iter.next()).stateDiscarded(discarded); + Reference ref = (Reference) iter.next(); + ItemStateListener l = (ItemStateListener) ref.get(); + if (l != null) { + l.stateDiscarded(discarded); + } } } @@ -118,7 +147,11 @@ public void notifyNodeAdded(NodeState state, Name name, int index, NodeId id) { Iterator iter = nsListeners.iterator(); while (iter.hasNext()) { - ((NodeStateListener) iter.next()).nodeAdded(state, name, index, id); + Reference ref = (Reference) iter.next(); + NodeStateListener n = (NodeStateListener) ref.get(); + if (n != null) { + n.nodeAdded(state, name, index, id); + } } } @@ -129,7 +162,11 @@ public void notifyNodesReplaced(NodeState state) { Iterator iter = nsListeners.iterator(); while (iter.hasNext()) { - ((NodeStateListener) iter.next()).nodesReplaced(state); + Reference ref = (Reference) iter.next(); + NodeStateListener n = (NodeStateListener) ref.get(); + if (n != null) { + n.nodesReplaced(state); + } } } @@ -140,7 +177,11 @@ public void notifyNodeModified(NodeState state) { Iterator iter = nsListeners.iterator(); while (iter.hasNext()) { - ((NodeStateListener) iter.next()).nodeModified(state); + Reference ref = (Reference) iter.next(); + NodeStateListener n = (NodeStateListener) ref.get(); + if (n != null) { + n.nodeModified(state); + } } } @@ -154,7 +195,11 @@ public void notifyNodeRemoved(NodeState state, Name name, int index, NodeId id) { Iterator iter = nsListeners.iterator(); while (iter.hasNext()) { - ((NodeStateListener) iter.next()).nodeRemoved(state, name, index, id); + Reference ref = (Reference) iter.next(); + NodeStateListener n = (NodeStateListener) ref.get(); + if (n != null) { + n.nodeRemoved(state, name, index, id); + } } }