You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ck...@apache.org on 2009/05/18 11:19:46 UTC

svn commit: r775868 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/lock/XAEnvironment.java main/java/org/apache/jackrabbit/core/lock/XALockManager.java test/java/org/apache/jackrabbit/core/XATest.java

Author: ckoell
Date: Mon May 18 09:19:45 2009
New Revision: 775868

URL: http://svn.apache.org/viewvc?rev=775868&view=rev
Log:
JCR-1634: In XA transaction session.addLockToken() does not have effect

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XAEnvironment.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockManager.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/XATest.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XAEnvironment.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XAEnvironment.java?rev=775868&r1=775867&r2=775868&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XAEnvironment.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XAEnvironment.java Mon May 18 09:19:45 2009
@@ -24,6 +24,7 @@
 import org.slf4j.LoggerFactory;
 
 import javax.jcr.RepositoryException;
+import javax.jcr.Workspace;
 import javax.jcr.lock.LockException;
 import java.util.Map;
 import java.util.HashMap;
@@ -263,16 +264,66 @@
 
     /**
      * Add lock token to this environment.
+     * @param session 
      * @param lt lock token
+     * @throws RepositoryException 
      */
-    public void addLockToken(String lt) {
+    public void addLockToken(SessionImpl session, String lt) throws RepositoryException {
+        try {
+            LockToken lockToken = LockToken.parse(lt);
+            NodeImpl node = (NodeImpl) session.getItemManager().getItem(lockToken.getId());
+            AbstractLockInfo info = getLockInfo(node);
+            if (info != null) {
+                if (info.getLockHolder() == null) {
+                    info.setLockHolder(session);
+                } else {
+                    String msg = "Cannot add lock token: lock already held by other session.";
+                    log.warn(msg);
+                    throw new LockException(msg);
+                }
+            }
+            // inform SessionLockManager
+            getSessionLockManager(session).lockTokenAdded(lt);
+        } catch (IllegalArgumentException e) {
+            String msg = "Bad lock token: " + e.getMessage();
+            log.warn(msg);
+            throw new LockException(msg);
+        }
     }
 
     /**
      * Remove lock token from this environment.
+     * @param session 
      * @param lt lock token
+     * @throws RepositoryException 
      */
-    public void removeLockToken(String lt) {
+    public void removeLockToken(SessionImpl session, String lt) throws RepositoryException {
+        try {
+            LockToken lockToken = LockToken.parse(lt);
+
+            NodeImpl node = (NodeImpl) session.getItemManager().getItem(lockToken.getId());
+            AbstractLockInfo info = getLockInfo(node);
+            if (info != null) {
+                if (session == info.getLockHolder()) {
+                    info.setLockHolder(null);
+                } else {
+                    String msg = "Cannot remove lock token: lock held by other session.";
+                    log.warn(msg);
+                    throw new LockException(msg);
+                }
+            }
+            // inform SessionLockManager
+            getSessionLockManager(session).lockTokenRemoved(lt);
+        } catch (IllegalArgumentException e) {
+            String msg = "Bad lock token: " + e.getMessage();
+            log.warn(msg);
+            throw new LockException(msg);
+        }
+    }
+
+    static SessionLockManager getSessionLockManager(SessionImpl session) throws RepositoryException {
+        Workspace wsp = (Workspace) session.getWorkspace();
+        return (SessionLockManager) wsp.getLockManager();
     }
 
     /**
@@ -437,7 +488,12 @@
             if (isUnlock) {
                 lockMgr.internalUnlock(node);
             } else {
-                lockMgr.internalLock(node, deep, sessionScoped, getSecondsRemaining(), lockOwner);
+                AbstractLockInfo internalLock = lockMgr.internalLock(node, deep, sessionScoped, getSecondsRemaining(), lockOwner);
+                AbstractLockInfo xaEnvLock = getLockInfo(node);
+                // Check if the lockToken has been removed in the transaction ...
+                if (xaEnvLock != null && xaEnvLock.getLockHolder() == null) {
+                    internalLock.setLockHolder(null);
+                }
             }
         }
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockManager.java?rev=775868&r1=775867&r2=775868&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockManager.java Mon May 18 09:19:45 2009
@@ -205,7 +205,7 @@
      */
     public void lockTokenAdded(SessionImpl session, String lt) throws RepositoryException {
         if (isInXA()) {
-            xaEnv.addLockToken(lt);
+            xaEnv.addLockToken(session, lt);
         } else {
             lockMgr.lockTokenAdded(session, lt);
         }
@@ -216,7 +216,7 @@
      */
     public void lockTokenRemoved(SessionImpl session, String lt) throws RepositoryException {
         if (isInXA()) {
-            xaEnv.removeLockToken(lt);
+            xaEnv.removeLockToken(session, lt);
         } else {
             lockMgr.lockTokenRemoved(session, lt);
         }

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/XATest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/XATest.java?rev=775868&r1=775867&r2=775868&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/XATest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/XATest.java Mon May 18 09:19:45 2009
@@ -29,6 +29,7 @@
 import javax.jcr.version.VersionException;
 import javax.jcr.version.Version;
 import javax.jcr.lock.Lock;
+import javax.jcr.lock.LockException;
 import javax.transaction.UserTransaction;
 import javax.transaction.RollbackException;
 import java.util.StringTokenizer;
@@ -787,6 +788,48 @@
     }
 
     /**
+     * Test locking and unlocking behavior in transaction
+     * @throws Exception
+     */
+    public void testLockUnlockCommit() throws Exception {
+        Session other = helper.getSuperuserSession();
+        try {
+            // add node that is both lockable and referenceable, save
+            Node n = testRootNode.addNode(nodeName1);
+            n.addMixin(mixLockable);
+            n.addMixin(mixReferenceable);
+            testRootNode.save();
+
+            // reference node in second session
+            Node nOther = other.getNodeByUUID(n.getUUID());
+
+            // verify node is not locked in either session
+            assertFalse("Node not locked in session 1", n.isLocked());
+            assertFalse("Node not locked in session 2", nOther.isLocked());
+
+            // get user transaction object, start and lock node
+            UserTransaction utx = new UserTransactionImpl(superuser);
+            utx.begin();
+            n.lock(false, true);
+
+            // verify node is locked in first session only
+            assertTrue("Node locked in session 1", n.isLocked());
+            assertFalse("Node not locked in session 2", nOther.isLocked());
+
+            n.unlock();
+            // commit in first session
+            utx.commit();
+
+            // verify node is locked in both sessions
+            assertFalse("Node locked in session 1", n.isLocked());
+            assertFalse("Node locked in session 2", nOther.isLocked());
+        } finally {
+            // logout
+            other.logout();
+        }
+    }
+
+    /**
      * Test locking a node in one session. Verify that node is not locked
      * in session after rollback.
      * @throws Exception
@@ -920,7 +963,78 @@
         assertTrue(nOther2.isLocked());
         
         utx.commit();
+    
+    }
+
+    /**
+     * Test add and remove lock tokens in a transaction 
+     * @throws Exception
+     */
+    public void testAddRemoveLockToken() throws Exception {
+        // create new node and lock it
+        UserTransaction utx = new UserTransactionImpl(superuser);
+        utx.begin();
+
+        // add node that is both lockable and referenceable, save
+        Node rootNode = superuser.getRootNode(); 
+        Node n = rootNode.addNode(nodeName1);
+        n.addMixin(mixLockable);
+        n.addMixin(mixReferenceable);
+        rootNode.save();
+
+        String uuid = n.getUUID();
+        
+        // lock this new node
+        Lock lock = n.lock(true, false);
+        String lockToken = lock.getLockToken();
+        
+        // assert: session must get a non-null lock token
+        assertNotNull("session must get a non-null lock token", lockToken);
+
+        // assert: session must hold lock token
+        assertTrue("session must hold lock token", containsLockToken(superuser, lockToken));
+
+        superuser.removeLockToken(lockToken);
+        assertNull("session must get a null lock token", lock.getLockToken());
+        
+        // commit
+        utx.commit();
+        
+        // refresh Lock Info
+        lock = n.getLock();
+
+        assertNull("session must get a null lock token", lock.getLockToken());
 
+        Session other = helper.getSuperuserSession();
+        // start new Transaction and try to add lock token
+        utx = new UserTransactionImpl(other);
+        utx.begin();
+        
+        Node otherNode = other.getNodeByUUID(uuid); 
+        assertTrue("Node not locked", otherNode.isLocked());
+        try {
+            otherNode.setProperty(propertyName1, "foo");
+            fail("Lock exception should be thrown");
+        } catch (LockException e) {
+            // expected
+        }
+        
+        // add lock token
+        other.addLockToken(lockToken);
+        
+        // refresh Lock Info
+        lock = otherNode.getLock();
+
+        // assert: session must hold lock token
+        assertTrue("session must hold lock token", containsLockToken(other, lock.getLockToken()));        
+        
+        otherNode.unlock();
+        
+        assertFalse("Node is locked", otherNode.isLocked());
+        
+        otherNode.setProperty(propertyName1, "foo");
+        other.save();
+        utx.commit();
     }
 
     /**
@@ -1628,4 +1742,18 @@
 
         utx.commit();
     }
+    
+    /**
+     * Return a flag indicating whether the indicated session contains
+     * a specific lock token
+     */
+    private boolean containsLockToken(Session session, String lockToken) {
+        String[] lt = session.getLockTokens();
+        for (int i = 0; i < lt.length; i++) {
+            if (lt[i].equals(lockToken)) {
+                return true;
+            }
+        }
+        return false;
+    }    
 }