You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2010/06/24 18:57:02 UTC

svn commit: r957626 - in /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core: ./ session/

Author: jukka
Date: Thu Jun 24 16:57:01 2010
New Revision: 957626

URL: http://svn.apache.org/viewvc?rev=957626&view=rev
Log:
JCR-890: concurrent read-only access to a session

Handle Session.logout() in a way that prevents concurrent session access.

Also move the SessionContext argument from perform() to a member variable of SessionOperation.

Removed:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/ActiveSessionState.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/ClosedSessionState.java
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRefreshOperation.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemSaveOperation.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionContext.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionOperation.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionRefreshOperation.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionSaveOperation.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionState.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java?rev=957626&r1=957625&r2=957626&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java Thu Jun 24 16:57:01 2010
@@ -384,7 +384,7 @@ public abstract class ItemImpl implement
     public void save() throws RepositoryException {
         // check state of this instance
         sanityCheck();
-        perform(new ItemSaveOperation(getItemState()));
+        perform(new ItemSaveOperation(sessionContext, getItemState()));
     }
 
     /**
@@ -399,7 +399,7 @@ public abstract class ItemImpl implement
             // of all descendant non-transient instances; maybe also
             // have to reset stale ItemState instances
         } else {
-            perform(new ItemRefreshOperation(getItemState()));
+            perform(new ItemRefreshOperation(sessionContext, getItemState()));
         }
     }
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRefreshOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRefreshOperation.java?rev=957626&r1=957625&r2=957626&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRefreshOperation.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRefreshOperation.java Thu Jun 24 16:57:01 2010
@@ -22,13 +22,13 @@ public class ItemRefreshOperation extend
 
     private final ItemState state;
 
-    public ItemRefreshOperation(ItemState state) {
-        super("item refresh");
+    public ItemRefreshOperation(SessionContext context, ItemState state) {
+        super("item refresh", context);
         this.state = state;
     }
 
     @Override
-    public void perform(SessionContext context) throws RepositoryException {
+    public void perform() throws RepositoryException {
         SessionItemStateManager stateMgr = context.getItemStateManager();
 
         // Optimisation for the root node

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemSaveOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemSaveOperation.java?rev=957626&r1=957625&r2=957626&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemSaveOperation.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemSaveOperation.java Thu Jun 24 16:57:01 2010
@@ -82,13 +82,13 @@ class ItemSaveOperation extends SessionO
 
     private final ItemState state;
 
-    public ItemSaveOperation(ItemState state) {
-        super("item save");
+    public ItemSaveOperation(SessionContext context, ItemState state) {
+        super("item save", context);
         this.state = state;
     }
 
     @Override
-    public void perform(SessionContext context) throws RepositoryException {
+    public void perform() throws RepositoryException {
         SessionItemStateManager stateMgr = context.getItemStateManager();
 
         /**
@@ -97,7 +97,7 @@ class ItemSaveOperation extends SessionO
          */
         Collection<ItemState> dirty;
         try {
-            dirty = getTransientStates(stateMgr);
+            dirty = getTransientStates();
         } catch (ConcurrentModificationException e) {
             String msg = "Concurrent modification; session is closed";
             log.error(msg, e);
@@ -113,7 +113,7 @@ class ItemSaveOperation extends SessionO
          * build list of transient descendants in the attic
          * (i.e. those marked as 'removed')
          */
-        Collection<ItemState> removed = getRemovedStates(stateMgr);
+        Collection<ItemState> removed = getRemovedStates();
 
         // All affected item states. The keys are used to look up whether
         // an item is affected, and the values are iterated through below
@@ -214,7 +214,7 @@ class ItemSaveOperation extends SessionO
 
         // validate access and node type constraints
         // (this will also validate child removals)
-        validateTransientItems(context, dirty, removed);
+        validateTransientItems(dirty, removed);
 
         // start the update operation
         try {
@@ -226,20 +226,20 @@ class ItemSaveOperation extends SessionO
         boolean succeeded = false;
         try {
             // process transient items marked as 'removed'
-            removeTransientItems(stateMgr, removed);
+            removeTransientItems(removed);
 
             // process transient items that have change in mixins
-            processShareableNodes(context, dirty);
+            processShareableNodes(dirty);
 
             // initialize version histories for new nodes (might generate new transient state)
-            if (initVersionHistories(context, dirty)) {
+            if (initVersionHistories(dirty)) {
                 // re-build the list of transient states because the previous call
                 // generated new transient state
-                dirty = getTransientStates(stateMgr);
+                dirty = getTransientStates();
             }
 
             // process 'new' or 'modified' transient states
-            persistTransientItems(context.getItemManager(), dirty);
+            persistTransientItems(dirty);
 
             // dispose the transient states marked 'new' or 'modified'
             // at this point item state data is pushed down one level,
@@ -272,7 +272,7 @@ class ItemSaveOperation extends SessionO
                 // applied by persistTransientItems() and we need to
                 // restore transient state, i.e. undo the effect of
                 // persistTransientItems()
-                restoreTransientItems(context, dirty);
+                restoreTransientItems(dirty);
             }
         }
 
@@ -297,8 +297,7 @@ class ItemSaveOperation extends SessionO
      * @throws InvalidItemStateException
      * @throws RepositoryException
      */
-    private Collection<ItemState> getTransientStates(
-            SessionItemStateManager stateMgr)
+    private Collection<ItemState> getTransientStates()
             throws InvalidItemStateException, RepositoryException {
         // list of transient states that should be persisted
         ArrayList<ItemState> dirty = new ArrayList<ItemState>();
@@ -306,7 +305,7 @@ class ItemSaveOperation extends SessionO
         if (state.isNode()) {
             // build list of 'new' or 'modified' descendants
             for (ItemState transientState
-                    : stateMgr.getDescendantTransientItemStates(state.getId())) {
+                    : context.getItemStateManager().getDescendantTransientItemStates(state.getId())) {
                 // fail-fast test: check status of transient state
                 switch (transientState.getStatus()) {
                     case ItemState.STATUS_NEW:
@@ -385,13 +384,12 @@ class ItemSaveOperation extends SessionO
      * @throws InvalidItemStateException
      * @throws RepositoryException
      */
-    private Collection<ItemState> getRemovedStates(
-            SessionItemStateManager stateMgr)
+    private Collection<ItemState> getRemovedStates()
             throws InvalidItemStateException, RepositoryException {
         if (state.isNode()) {
             ArrayList<ItemState> removed = new ArrayList<ItemState>();
             for (ItemState transientState
-                    : stateMgr.getDescendantTransientItemStatesInAttic(state.getId())) {
+                    : context.getItemStateManager().getDescendantTransientItemStatesInAttic(state.getId())) {
                 // check if stale
                 switch (transientState.getStatus()) {
                 case ItemState.STATUS_STALE_MODIFIED:
@@ -435,7 +433,6 @@ class ItemSaveOperation extends SessionO
      * and in Property.setValue (for properties to be modified).
      */
     private void validateTransientItems(
-            SessionContext context,
             Iterable<ItemState> dirty, Iterable<ItemState> removed)
             throws RepositoryException {
         SessionImpl session = context.getSessionImpl();
@@ -494,7 +491,7 @@ class ItemSaveOperation extends SessionO
                 // primary type
                 NodeTypeImpl pnt = ntMgr.getNodeType(nodeState.getNodeTypeName());
                 // effective node type (primary type incl. mixins)
-                EffectiveNodeType ent = getEffectiveNodeType(context, nodeState);
+                EffectiveNodeType ent = getEffectiveNodeType(nodeState);
                 /**
                  * if the transient node was added (i.e. if it is 'new') or if
                  * its primary type has changed, check its node type against the
@@ -712,17 +709,13 @@ class ItemSaveOperation extends SessionO
      * walk through list of transient items marked 'removed' and
      * definitively remove each one
      */
-    private void removeTransientItems(
-            SessionItemStateManager stateMgr, Iterable<ItemState> states) {
+    private void removeTransientItems(Iterable<ItemState> states) {
         for (ItemState transientState : states) {
             ItemState persistentState = transientState.getOverlayedState();
-            /**
-             * remove persistent state
-             *
-             * this will indirectly (through stateDestroyed listener method)
-             * permanently invalidate all Item instances wrapping it
-             */
-            stateMgr.destroy(persistentState);
+            // remove persistent state
+            // this will indirectly (through stateDestroyed listener method)
+            // permanently invalidate all Item instances wrapping it
+            context.getItemStateManager().destroy(persistentState);
         }
     }
 
@@ -736,8 +729,7 @@ class ItemSaveOperation extends SessionO
      * has been removed, throw.</li>
      * </ul>
      */
-    private void processShareableNodes(
-            SessionContext context, Iterable<ItemState> states)
+    private void processShareableNodes(Iterable<ItemState> states)
             throws RepositoryException {
         for (ItemState is : states) {
             if (is.isNode()) {
@@ -745,10 +737,10 @@ class ItemSaveOperation extends SessionO
                 boolean wasShareable = false;
                 if (ns.hasOverlayedState()) {
                     NodeState old = (NodeState) ns.getOverlayedState();
-                    EffectiveNodeType ntOld = getEffectiveNodeType(context, old);
+                    EffectiveNodeType ntOld = getEffectiveNodeType(old);
                     wasShareable = ntOld.includesNodeType(NameConstants.MIX_SHAREABLE);
                 }
-                EffectiveNodeType ntNew = getEffectiveNodeType(context, ns);
+                EffectiveNodeType ntNew = getEffectiveNodeType(ns);
                 boolean isShareable = ntNew.includesNodeType(NameConstants.MIX_SHAREABLE);
 
                 if (!wasShareable && isShareable) {
@@ -773,8 +765,7 @@ class ItemSaveOperation extends SessionO
      * @return true if this call generated new transient state; otherwise false
      * @throws RepositoryException
      */
-    private boolean initVersionHistories(
-            SessionContext context, Iterable<ItemState> states)
+    private boolean initVersionHistories(Iterable<ItemState> states)
             throws RepositoryException {
         SessionImpl session = context.getSessionImpl();
         ItemManager itemMgr = context.getItemManager();
@@ -784,7 +775,7 @@ class ItemSaveOperation extends SessionO
         for (ItemState itemState : states) {
             if (itemState.isNode()) {
                 NodeState nodeState = (NodeState) itemState;
-                EffectiveNodeType nt = getEffectiveNodeType(context, nodeState);
+                EffectiveNodeType nt = getEffectiveNodeType(nodeState);
                 if (nt.includesNodeType(NameConstants.MIX_VERSIONABLE)) {
                     if (!nodeState.hasPropertyName(NameConstants.JCR_VERSIONHISTORY)) {
                         NodeImpl node = (NodeImpl) itemMgr.getItem(itemState.getId());
@@ -839,9 +830,9 @@ class ItemSaveOperation extends SessionO
     /**
      * walk through list of transient items and persist each one
      */
-    private void persistTransientItems(
-            ItemManager itemMgr, Iterable<ItemState> states)
+    private void persistTransientItems(Iterable<ItemState> states)
             throws RepositoryException {
+        ItemManager itemMgr = context.getItemManager();
         for (ItemState state : states) {
             // persist state of transient item
             itemMgr.getItem(state.getId()).makePersistent();
@@ -851,8 +842,7 @@ class ItemSaveOperation extends SessionO
     /**
      * walk through list of transient states and re-apply transient changes
      */
-    private void restoreTransientItems(
-            SessionContext context, Iterable<ItemState> items) {
+    private void restoreTransientItems(Iterable<ItemState> items) {
         ItemManager itemMgr = context.getItemManager();
         SessionItemStateManager stateMgr = context.getItemStateManager();
 
@@ -907,8 +897,7 @@ class ItemSaveOperation extends SessionO
      * @return the effective node type
      * @throws RepositoryException
      */
-    private EffectiveNodeType getEffectiveNodeType(
-            SessionContext context, NodeState state)
+    private EffectiveNodeType getEffectiveNodeType(NodeState state)
             throws RepositoryException {
         try {
             NodeTypeRegistry registry =

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java?rev=957626&r1=957625&r2=957626&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java Thu Jun 24 16:57:01 2010
@@ -1579,7 +1579,7 @@ public class NodeImpl extends ItemImpl i
             throws ValueFormatException, VersionException, LockException,
             ConstraintViolationException, RepositoryException {
         SetPropertyOperation operation =
-            new SetPropertyOperation(name, value, false);
+            new SetPropertyOperation(sessionContext, name, value, false);
         sessionContext.getSessionState().perform(operation);
         return operation.getProperty();
     }
@@ -2165,8 +2165,8 @@ public class NodeImpl extends ItemImpl i
         if (value != null && value.getType() != type) {
             value = ValueHelper.convert(value, type, getValueFactory());
         }
-        SetPropertyOperation operation =
-            new SetPropertyOperation(session.getQName(name), value, true);
+        SetPropertyOperation operation = new SetPropertyOperation(
+                sessionContext, session.getQName(name), value, true);
         sessionContext.getSessionState().perform(operation);
         return operation.getProperty();
     }
@@ -2174,8 +2174,8 @@ public class NodeImpl extends ItemImpl i
     /** Wrapper around {@link SetPropertyOperation} */
     public Property setProperty(String name, Value value)
             throws RepositoryException {
-        SetPropertyOperation operation =
-            new SetPropertyOperation(session.getQName(name), value, false);
+        SetPropertyOperation operation = new SetPropertyOperation(
+                sessionContext, session.getQName(name), value, false);
         sessionContext.getSessionState().perform(operation);
         return operation.getProperty();
     }
@@ -2271,8 +2271,9 @@ public class NodeImpl extends ItemImpl i
          * @param enforceType <code>true</code> to enforce the value type
          */
         public SetPropertyOperation(
+                SessionContext sessionContext,
                 Name name, Value value, boolean enforceType) {
-            super("setProperty()");
+            super("setProperty()", sessionContext);
             this.name = name;
             this.value = value;
             this.enforceType = enforceType;
@@ -2305,7 +2306,7 @@ public class NodeImpl extends ItemImpl i
          * @throws RepositoryException          if another error occurs.
          */
         @Override
-        public void perform(SessionContext context) throws RepositoryException {
+        public void perform() throws RepositoryException {
             itemSanityCheck();
             // check pre-conditions for setting property
             checkSetProperty();

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=957626&r1=957625&r2=957626&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 Jun 24 16:57:01 2010
@@ -34,8 +34,6 @@ import org.apache.jackrabbit.core.securi
 import org.apache.jackrabbit.core.security.SecurityConstants;
 import org.apache.jackrabbit.core.security.authentication.AuthContext;
 import org.apache.jackrabbit.core.security.authorization.Permission;
-import org.apache.jackrabbit.core.session.ActiveSessionState;
-import org.apache.jackrabbit.core.session.ClosedSessionState;
 import org.apache.jackrabbit.core.session.SessionContext;
 import org.apache.jackrabbit.core.session.SessionOperation;
 import org.apache.jackrabbit.core.session.SessionRefreshOperation;
@@ -243,7 +241,6 @@ public class SessionImpl extends Abstrac
             WorkspaceConfig wspConfig)
             throws AccessDeniedException, RepositoryException {
         this.context = new SessionContext(repositoryContext, this);
-        this.context.setSessionState(new ActiveSessionState(context));
         this.repositoryContext = repositoryContext;
         this.subject = subject;
 
@@ -851,14 +848,15 @@ public class SessionImpl extends Abstrac
      * {@inheritDoc}
      */
     public void save() throws RepositoryException {
-        perform(new SessionSaveOperation());
+        perform(new SessionSaveOperation(context));
     }
 
     /**
      * {@inheritDoc}
      */
     public void refresh(boolean keepChanges) throws RepositoryException {
-        perform(new SessionRefreshOperation(keepChanges, clusterSyncOnRefresh()));
+        perform(new SessionRefreshOperation(
+                context, keepChanges, clusterSyncOnRefresh()));
     }
 
     /**
@@ -892,7 +890,8 @@ public class SessionImpl extends Abstrac
      */
     public void move(String srcAbsPath, String destAbsPath)
             throws RepositoryException {
-        perform(new SessionMoveOperation(this, srcAbsPath, destAbsPath));
+        perform(new SessionMoveOperation(
+                context, this, srcAbsPath, destAbsPath));
     }
 
     /**
@@ -960,56 +959,51 @@ public class SessionImpl extends Abstrac
     }
 
     /**
-     * {@inheritDoc}
+     * Invalidates this session and releases all associated resources.
      */
     @Override
-    public synchronized void logout() {
-        if (!isLive()) {
-            // ignore
-            return;
-        }
-
-        // JCR-798: Remove all registered event listeners to avoid concurrent
-        // access to session internals by the event delivery or even listeners
-        removeRegisteredEventListeners();
-
-        // discard any pending changes first as those might
-        // interfere with subsequent operations
-        context.getItemStateManager().disposeAllTransientItemStates();
-
-        // notify listeners that session is about to be closed
-        notifyLoggingOut();
-
-        // dispose session item state manager
-        context.getItemStateManager().dispose();
-        // dispose item manager
-        context.getItemManager().dispose();
-        // dispose workspace
-        wsp.dispose();
+    public void logout() {
+        if (context.getSessionState().close()) {
+            // JCR-798: Remove all registered event listeners to avoid concurrent
+            // access to session internals by the event delivery or even listeners
+            removeRegisteredEventListeners();
+
+            // discard any pending changes first as those might
+            // interfere with subsequent operations
+            context.getItemStateManager().disposeAllTransientItemStates();
+
+            // notify listeners that session is about to be closed
+            notifyLoggingOut();
+
+            // dispose session item state manager
+            context.getItemStateManager().dispose();
+            // dispose item manager
+            context.getItemManager().dispose();
+            // dispose workspace
+            wsp.dispose();
 
-        // invalidate session
-        context.setSessionState(new ClosedSessionState());
+            // logout JAAS subject
+            if (loginContext != null) {
+                try {
+                    loginContext.logout();
+                } catch (javax.security.auth.login.LoginException le) {
+                    log.warn("failed to logout current subject: " + le.getMessage());
+                }
+                loginContext = null;
+            }
 
-        // logout JAAS subject
-        if (loginContext != null) {
             try {
-                loginContext.logout();
-            } catch (javax.security.auth.login.LoginException le) {
-                log.warn("failed to logout current subject: " + le.getMessage());
+                context.getAccessManager().close();
+            } catch (Exception e) {
+                log.warn("error while closing AccessManager", e);
             }
-            loginContext = null;
-        }
 
-        try {
-            context.getAccessManager().close();
-        } catch (Exception e) {
-            log.warn("error while closing AccessManager", e);
+            // finally notify listeners that session has been closed
+            notifyLoggedOut();
         }
-
-        // finally notify listeners that session has been closed
-        notifyLoggedOut();
     }
 
+
     /**
      * {@inheritDoc}
      */

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java?rev=957626&r1=957625&r2=957626&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java Thu Jun 24 16:57:01 2010
@@ -54,9 +54,10 @@ public class SessionMoveOperation extend
     private final Path.Element destName;
 
     public SessionMoveOperation(
+            SessionContext sessionContext,
             PathResolver resolver, String srcAbsPath, String destAbsPath)
             throws RepositoryException {
-        super("move");
+        super("move", sessionContext);
 
         this.srcAbsPath = srcAbsPath;
         this.srcPath = getAbsolutePath(resolver, srcAbsPath);
@@ -104,7 +105,8 @@ public class SessionMoveOperation extend
         }
     }
 
-    public void perform(SessionContext context) throws RepositoryException {
+    @Override
+    public void perform() throws RepositoryException {
         // Get node instances
         NodeImpl targetNode = getNode(context, srcPath, srcAbsPath);
         NodeImpl srcParentNode =

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionContext.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionContext.java?rev=957626&r1=957625&r2=957626&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionContext.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionContext.java Thu Jun 24 16:57:01 2010
@@ -32,7 +32,10 @@ public class SessionContext {
 
     private final SessionImpl session;
 
-    private volatile SessionState state;
+    /**
+     * The state of this session.
+     */
+    private final SessionState state;
 
     /**
      * The item state manager of this session
@@ -60,6 +63,7 @@ public class SessionContext {
         assert session != null;
         this.repositoryContext = repositoryContext;
         this.session = session;
+        this.state = new SessionState();
     }
 
     public RepositoryContext getRepositoryContext() {
@@ -93,10 +97,6 @@ public class SessionContext {
         return state;
     }
 
-    public void setSessionState(SessionState state) {
-        this.state = state;
-    }
-
     public SessionItemStateManager getItemStateManager() {
         assert itemStateManager != null;
         return itemStateManager;

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionOperation.java?rev=957626&r1=957625&r2=957626&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionOperation.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionOperation.java Thu Jun 24 16:57:01 2010
@@ -23,23 +23,30 @@ import javax.jcr.RepositoryException;
  * {@link SessionState} interface to implement generic controls like
  * synchronization and liveness checks on all session operation.
  */
-public class SessionOperation {
+public abstract class SessionOperation {
 
     private final String name;
 
-    public SessionOperation(String name) {
+    protected final SessionContext context;
+
+    /**
+     * Creates a new session operation.
+     *
+     * @param name operation name
+     * @param context component context of the session
+     */
+    protected SessionOperation(String name, SessionContext context) {
         this.name = name;
+        this.context = context;
     }
 
     /**
      * Performs this operation. The default implementation does nothing;
      * subclasses should override this method to implement custom operations.
      *
-     * @param context component context of the session
      * @throws RepositoryException if the operation fails
      */
-    public void perform(SessionContext context) throws RepositoryException {
-    }
+    public abstract void perform() throws RepositoryException;
 
     /**
      * Returns the name of this operation.

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionRefreshOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionRefreshOperation.java?rev=957626&r1=957625&r2=957626&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionRefreshOperation.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionRefreshOperation.java Thu Jun 24 16:57:01 2010
@@ -30,14 +30,15 @@ public class SessionRefreshOperation ext
 
     private final boolean clusterSync;
 
-    public SessionRefreshOperation(boolean keepChanges, boolean clusterSync) {
-        super("refresh");
+    public SessionRefreshOperation(
+            SessionContext context, boolean keepChanges, boolean clusterSync) {
+        super("refresh", context);
         this.keepChanges = keepChanges;
         this.clusterSync = clusterSync;
     }
 
     @Override
-    public void perform(SessionContext context) throws RepositoryException {
+    public void perform() throws RepositoryException {
         // JCR-1753: Ensure that we are up to date with cluster changes
         ClusterNode cluster = context.getRepositoryContext().getClusterNode();
         if (cluster != null && clusterSync) {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionSaveOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionSaveOperation.java?rev=957626&r1=957625&r2=957626&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionSaveOperation.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionSaveOperation.java Thu Jun 24 16:57:01 2010
@@ -23,13 +23,12 @@ import org.apache.jackrabbit.core.id.Nod
 
 public class SessionSaveOperation extends SessionOperation {
 
-    public SessionSaveOperation() {
-        super("save");
+    public SessionSaveOperation(SessionContext context) {
+        super("save", context);
     }
 
     @Override
-    public void perform(SessionContext context)
-            throws RepositoryException {
+    public void perform() throws RepositoryException {
         NodeId id;
         // JCR-2425: check whether session is allowed to read root node
         if (context.getSessionImpl().hasPermission("/", Session.ACTION_READ)) {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionState.java?rev=957626&r1=957625&r2=957626&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionState.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionState.java Thu Jun 24 16:57:01 2010
@@ -16,13 +16,35 @@
  */
 package org.apache.jackrabbit.core.session;
 
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
  * The internal state of a session.
  */
-public interface SessionState {
+public class SessionState {
+
+    /**
+     * Logger instance.
+     */
+    private static final Logger log =
+        LoggerFactory.getLogger(SessionState.class);
+
+    /**
+     * The lock used to guarantee synchronized execution of repository
+     * operations. An explicit lock is used instead of normal Java
+     * synchronization in order to be able to log attempts to concurrently
+     * use a session. TODO: Check if this is a performance issue!
+     */
+    private final Lock lock = new ReentrantLock();
+
+    private volatile Exception closed = null;
 
     /**
      * Checks whether this session is alive.
@@ -31,22 +53,63 @@ public interface SessionState {
      * @return <code>true</code> if the session is alive,
      *         <code>false</code> otherwise
      */
-    boolean isAlive();
+    public boolean isAlive() {
+        return closed == null;
+    }
 
     /**
      * Throws an exception if this session is not alive.
      *
      * @throws RepositoryException throw if this session is not alive
      */
-    void checkAlive() throws RepositoryException;
+    public void checkAlive() throws RepositoryException {
+        if (!isAlive()) {
+            throw new RepositoryException(
+                    "This session has been closed. See the chained exception"
+                    + " for a trace of where the session was closed", closed);
+        }
+    }
 
     /**
-     * Performs the given session operation.
+     * Performs the given operation within a synchronized block.
      *
-     * @param operation the session operation
-     * @throws RepositoryException if the operation fails or can not
-     *                             for some other reason be performed
+     * @throws RepositoryException if the operation fails
      */
-    void perform(SessionOperation operation) throws RepositoryException;
+    public void perform(SessionOperation operation) throws RepositoryException {
+        if (!lock.tryLock()) {
+            log.warn("Attempt to perform {} while another thread is"
+                    + " concurrently accessing the session. Blocking until"
+                    + " the other thread is finished using this session.",
+                    operation);
+            lock.lock();
+        }
+        try {
+            checkAlive();
+            log.debug("Performing {}", operation);
+            operation.perform();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public boolean close() {
+        if (!lock.tryLock()) {
+            log.warn("Attempt to close a session while another thread is"
+                    + " concurrently accessing the session. Blocking until"
+                    + " the other thread is finished using this session.");
+            lock.lock();
+        }
+        try {
+            if (isAlive()) {
+                closed = new Exception();
+                return true;
+            } else {
+                log.warn("This session has already been closed", closed);
+                return false;
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
 
 }