You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2009/03/12 11:49:31 UTC
svn commit: r752831 - in
/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core:
SessionImpl.java TransientRepository.java state/StateChangeDispatcher.java
Author: thomasm
Date: Thu Mar 12 10:49:25 2009
New Revision: 752831
URL: http://svn.apache.org/viewvc?rev=752831&view=rev
Log:
JCR-1216 Unreferenced sessions should get garbage collected
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TransientRepository.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/StateChangeDispatcher.java
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java?rev=752831&r1=752830&r2=752831&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java Thu Mar 12 10:49:25 2009
@@ -226,6 +226,12 @@
* Retention and Hold Manager
*/
private RetentionManager retentionManager;
+
+ /**
+ * The stack trace knows who opened this session. It is logged
+ * if the session is finalized, but Session.logout() was never called.
+ */
+ private Exception openStackTrace = new Exception("Stack Trace");
/**
* Internal helper class for common validation checks (lock status, checkout
@@ -1542,5 +1548,17 @@
ps.println();
itemStateMgr.dump(ps);
}
+
+ /**
+ * Finalize the session. If the application doesn't close Session.logout(),
+ * the session is closed automatically; however a warning is written to the log file,
+ * together with the stack trace of where the session was opened.
+ */
+ public void finalize() {
+ if (alive) {
+ log.warn("Unclosed session detected. The session was opened here: ", openStackTrace);
+ logout();
+ }
+ }
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TransientRepository.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TransientRepository.java?rev=752831&r1=752830&r2=752831&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TransientRepository.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TransientRepository.java Thu Mar 12 10:49:25 2009
@@ -25,14 +25,14 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Properties;
-import java.util.Set;
import javax.jcr.Credentials;
-import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
+import org.apache.commons.collections.map.ReferenceMap;
import org.apache.commons.io.IOUtils;
import org.apache.jackrabbit.api.JackrabbitRepository;
import org.apache.jackrabbit.core.config.ConfigurationException;
@@ -57,11 +57,6 @@
LoggerFactory.getLogger(TransientRepository.class);
/**
- * Buffer size for copying the default repository configuration file.
- */
- private static final int BUFFER_SIZE = 4096;
-
- /**
* Resource path of the default repository configuration file.
*/
private static final String DEFAULT_REPOSITORY_XML = "repository.xml";
@@ -123,7 +118,7 @@
* repository instance is automatically shut down until a new session
* is opened.
*/
- private final Set sessions;
+ private final Map sessions = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
/**
* The static repository descriptors. The default {@link RepositoryImpl}
@@ -142,7 +137,6 @@
public TransientRepository(RepositoryFactory factory) throws IOException {
this.factory = factory;
this.repository = null;
- this.sessions = new HashSet();
this.descriptors = new Properties();
// FIXME: The current RepositoryImpl class does not allow static
@@ -331,9 +325,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.put(session, session);
+ session.addListener(this);
logger.info("Session opened");
return session;
@@ -393,7 +387,7 @@
* @see Session#logout()
*/
public synchronized void shutdown() {
- Iterator iterator = new HashSet(sessions).iterator();
+ Iterator iterator = new HashSet(sessions.keySet()).iterator();
while (iterator.hasNext()) {
Session session = (Session) iterator.next();
session.logout();
@@ -410,7 +404,7 @@
* @see SessionListener#loggedOut(SessionImpl)
*/
public synchronized void loggedOut(SessionImpl session) {
- assert sessions.contains(session);
+ assert sessions.containsKey(session);
sessions.remove(session);
logger.info("Session closed");
if (sessions.isEmpty()) {
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/StateChangeDispatcher.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/StateChangeDispatcher.java?rev=752831&r1=752830&r2=752831&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/StateChangeDispatcher.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/StateChangeDispatcher.java Thu Mar 12 10:49:25 2009
@@ -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;
@@ -30,12 +32,14 @@
public class StateChangeDispatcher {
/**
- * Simple item state listeners
+ * Simple item state listeners.
+ * A copy on write array list is used so that no synchronization is required.
*/
private final Collection listeners = new CopyOnWriteArrayList();
/**
* Node state listeners
+ * A copy on write array list is used so that no synchronization is required.
*/
private final transient Collection nsListeners = new CopyOnWriteArrayList();
@@ -44,14 +48,29 @@
* @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 = coll.iterator();
+ while (iter.hasNext()) {
+ Reference ref = (Reference) iter.next();
+ Object o = ref.get();
+ if (o == listener) {
+ return ref;
+ } else if (o == null) {
+ // clean up unreferenced objects
+ coll.remove(ref);
+ }
+ }
+ return null;
+ }
/**
* Remove an <code>ItemStateListener</code>
@@ -59,9 +78,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 +90,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 +105,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 +120,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 +135,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 +153,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 +168,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 +183,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 +201,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);
+ }
}
}