/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.jcr2spi.lock;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.lock.Lock;
import javax.jcr.lock.LockException;
import javax.jcr.lock.LockManager;
import javax.jcr.nodetype.NodeType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <code>OpenScopedLockTest</code>...
*/
public class OpenScopedLockTest extends AbstractLockTest {
private static Logger log = LoggerFactory.getLogger(OpenScopedLockTest.class);
@Override
boolean isSessionScoped() {
return false;
}
public void testLogoutHasNoEffect() throws Exception {
// create a second session session. since logout of the 'superuser'
// will cause all inherited tear-down to fail
Node testRoot2 = (Node) otherSession.getItem(testRootNode.getPath());
Node lockedNode2 = testRoot2.addNode(nodeName2, testNodeType);
lockedNode2.addMixin(mixLockable);
testRoot2.save();
Lock lock2 = lockedNode2.lock(false, isSessionScoped());
// force reloading of the testroot in order to be aware of the
// locked node added by another session
testRootNode.refresh(false);
Node n2 = (Node) superuser.getItem(lockedNode2.getPath());
try {
String lockToken = lock2.getLockToken();
otherSession.removeLockToken(lockToken);
superuser.addLockToken(lockToken);
otherSession.logout();
assertTrue("After logout a open-scoped node must still be locked.", lock2.isLive());
assertTrue("After logout a open-scoped node must still be locked.", n2.isLocked());
} finally {
n2.unlock();
}
}
/**
* Test if the lock token has been automatically added to the set of lock
* tokens present with the Session that created the new Lock.
*
* @throws RepositoryException
*/
public void testLockTokenPresentWithSession() throws RepositoryException {
String token = lock.getLockToken();
String[] allTokens = lockedNode.getSession().getLockTokens();
for (int i = 0; i < allTokens.length; i++) {
if (allTokens[i].equals(token)) {
// lock token is present with the session that applied the lock
// OK
return;
}
}
// lock token not present within tokens returned by Session.getLockTokens.
fail("Upon successful call to Node.lock, the lock token must automatically be added to the set of tokens held by the Session.");
}
public void testTokenTransfer() throws Exception {
String lockToken = lock.getLockToken();
try {
superuser.removeLockToken(lockToken);
String nlt = lock.getLockToken();
assertTrue("freshly obtained lock token must either be null or the same as the one returned earlier",
nlt == null || nlt.equals(lockToken));
} finally {
// move lock token back in order to have lock removed properly
superuser.addLockToken(lockToken);
}
}
public void testRefreshAfterTokenTransfer() throws Exception {
String lockToken = lock.getLockToken();
try {
superuser.removeLockToken(lockToken);
lock.refresh();
fail("After transfering lock token the original lock object cannot be refresh by session, that does hold lock any more.");
} catch (LockException e) {
// oK
} finally {
// move lock token back in order to have lock removed properly
superuser.addLockToken(lockToken);
}
}
public void testRefreshAfterTokenTransfer2() throws Exception {
String lockToken = lock.getLockToken();
Node n2 = (Node) otherSession.getItem(lockedNode.getPath());
try {
superuser.removeLockToken(lockToken);
otherSession.addLockToken(lockToken);
n2.getLock().refresh();
} finally {
// move lock token back in order to have lock removed properly
otherSession.removeLockToken(lockToken);
superuser.addLockToken(lockToken);
}
}
public void testLockHolderAfterTokenTransfer() throws Exception {
String lockToken = lock.getLockToken();
Node n2 = (Node) otherSession.getItem(lockedNode.getPath());
try {
superuser.removeLockToken(lockToken);
otherSession.addLockToken(lockToken);
assertTrue("After lockToken transfer, the new lockHolder must get a non-null token", n2.getLock().getLockToken() != null);
assertTrue("After lockToken transfer, the new lockHolder must get the same token.", n2.getLock().getLockToken().equals(lockToken));
} finally {
// move lock token back in order to have lock removed properly
otherSession.removeLockToken(lockToken);
superuser.addLockToken(lockToken);
}
}
public void testUnlockAfterTokenTransfer() throws Exception {
String lockToken = lock.getLockToken();
try {
superuser.removeLockToken(lockToken);
lockedNode.unlock();
fail("After transfering lock token the original lock object cannot be unlocked by session, that does hold lock any more.");
} catch (LockException e) {
// oK
} finally {
// move lock token back in order to have lock removed properly
superuser.addLockToken(lockToken);
}
}
public void testUnlockAfterTokenTransfer2() throws Exception {
String lockToken = lock.getLockToken();
try {
superuser.removeLockToken(lockToken);
otherSession.addLockToken(lockToken);
// otherSession is now lockHolder -> unlock must succeed.
Node n2 = (Node) otherSession.getItem(lockedNode.getPath());
n2.unlock();
} catch (RepositoryException e) {
// only in case of failure:
// move lock token back in order to have lock removed properly
// if test succeeds, moving back tokens is not necessary.
otherSession.removeLockToken(lockToken);
superuser.addLockToken(lockToken);
// and rethrow
throw e;
}
}
/**
* Test if a Lock created by one session gets properly invalidated
* if the lock token has been transfered to another session, which
* unlocks the Node.
*/
public void testUnlockAfterTokenTransfer3() throws Exception {
String lockToken = lock.getLockToken();
try {
superuser.removeLockToken(lockToken);
otherSession.addLockToken(lockToken);
// otherSession is now lockHolder -> unlock must succeed.
Node n2 = (Node) otherSession.getItem(lockedNode.getPath());
n2.unlock();
assertFalse("Lock has been release by another session.", lockedNode.holdsLock());
assertFalse("Lock has been release by another session.", lock.isLive());
assertFalse("Lock has been release by another session.", lock.getNode().isLocked());
try {
lockedNode.getLock();
fail("Lock has been release by another session.");
} catch (LockException e) {
// ok
}
} catch (RepositoryException e) {
// only in case of failure:
// move lock token back in order to have lock removed properly
// if test succeeds, moving back tokens is not necessary.
otherSession.removeLockToken(lockToken);
superuser.addLockToken(lockToken);
// and rethrow
throw e;
}
}
public void testIsLockedWhileAnotherLockIsPresent() throws Exception {
Session s = lockedNode.getSession();
LockManager lm = s.getWorkspace().getLockManager();
String l2token = null;
String l2path = null;
String path = lockedNode.getPath();
String lockToken = lock.getLockToken();
assertTrue(lm.isLocked(path));
assertTrue(lm.holdsLock(path));
lm.removeLockToken(lockToken);
Session anotherSession = null;
try {
// check lock is seen by new session
anotherSession = getHelper().getSuperuserSession();
LockManager anotherLockManager = anotherSession.getWorkspace().getLockManager();
assertTrue(anotherLockManager.isLocked(path));
assertTrue(anotherLockManager.holdsLock(path));
// create a second lock
Node l2node = anotherSession.getNode(path).getParent().addNode("second-lock");
l2node.addMixin(NodeType.MIX_LOCKABLE);
anotherSession.save();
l2path = l2node.getPath();
Lock l2 = anotherLockManager.lock(l2path, false, false, Long.MAX_VALUE, "foobar");
l2token = l2.getLockToken();
assertNotNull(l2token);
anotherSession.save();
anotherSession.refresh(false);
assertTrue(anotherLockManager.isLocked(path));
assertTrue(anotherLockManager.holdsLock(path));
// try to unlock the lock obtained from the other session
anotherLockManager.addLockToken(lockToken);
anotherLockManager.unlock(path);
anotherSession.save();
// unlock "my" lock
anotherLockManager.unlock(l2path);
anotherSession.save();
l2path = null;
}
finally {
if (anotherSession != null) {
anotherSession.logout();
}
if (l2path != null && l2token != null) {
superuser.refresh(false);
LockManager sulm = superuser.getWorkspace().getLockManager();
sulm.addLockToken(l2token);
sulm.unlock(l2path);
}
}
}
}