Index: docs/examples/gettingstarted/sequencers/src/test/java/org/modeshape/example/sequencer/SequencingClientTest.java
===================================================================
--- docs/examples/gettingstarted/sequencers/src/test/java/org/modeshape/example/sequencer/SequencingClientTest.java (revision 1855)
+++ docs/examples/gettingstarted/sequencers/src/test/java/org/modeshape/example/sequencer/SequencingClientTest.java (working copy)
@@ -31,6 +31,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
import org.modeshape.common.util.FileUtil;
import org.modeshape.graph.connector.inmemory.InMemoryRepositorySource;
import org.modeshape.jcr.JcrConfiguration;
@@ -40,9 +43,6 @@ import org.modeshape.sequencer.classfile.ClassFileSequencerLexicon;
import org.modeshape.sequencer.java.JavaMetadataSequencer;
import org.modeshape.sequencer.mp3.Mp3MetadataSequencer;
import org.modeshape.sequencer.zip.ZipSequencer;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
/**
* @author Randall Hauch
Index: extensions/modeshape-connector-infinispan/src/test/java/org/modeshape/connector/infinispan/InfinispanClusterTest.java
===================================================================
--- extensions/modeshape-connector-infinispan/src/test/java/org/modeshape/connector/infinispan/InfinispanClusterTest.java (revision 1855)
+++ extensions/modeshape-connector-infinispan/src/test/java/org/modeshape/connector/infinispan/InfinispanClusterTest.java (working copy)
@@ -5,7 +5,6 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.util.UUID;
import org.infinispan.Cache;
-import org.junit.Ignore;
import org.junit.Test;
import org.modeshape.graph.ExecutionContext;
import org.modeshape.graph.Graph;
@@ -21,10 +20,7 @@ import org.modeshape.graph.property.PathNotFoundException;
/*
* Quick test that two clustered InfinispanSources can share data.
- *
- * This test is currently ignored. See MODE-764 for details.
*/
-@Ignore
public class InfinispanClusterTest {
private static final String CONFIG_FILE = "./src/test/resources/infinispan_clustered_config.xml";
Index: extensions/modeshape-sequencer-images/src/main/java/org/modeshape/sequencer/image/ImageMetadataSequencer.java
===================================================================
--- extensions/modeshape-sequencer-images/src/main/java/org/modeshape/sequencer/image/ImageMetadataSequencer.java (revision 1855)
+++ extensions/modeshape-sequencer-images/src/main/java/org/modeshape/sequencer/image/ImageMetadataSequencer.java (working copy)
@@ -65,23 +65,6 @@ import org.modeshape.graph.sequencer.StreamSequencerContext;
*
*/
public class ImageMetadataSequencer implements StreamSequencer {
- //
- // public static final String IMAGE_PRIMARY_TYPE = "jcr:primaryType";
- // public static final String IMAGE_MIXINS = "jcr:mixinTypes";
- // public static final String IMAGE_MIME_TYPE = "jcr:mimeType";
- // public static final String IMAGE_ENCODING = "jcr:encoding";
- //
- // public static final String METADATA_NODE = "image:metadata";
- // public static final String IMAGE_FORMAT_NAME = "image:formatName";
- // public static final String IMAGE_WIDTH = "image:width";
- // public static final String IMAGE_HEIGHT = "image:height";
- // public static final String IMAGE_BITS_PER_PIXEL = "image:bitsPerPixel";
- // public static final String IMAGE_PROGRESSIVE = "image:progressive";
- // public static final String IMAGE_NUMBER_OF_IMAGES = "image:numberOfImages";
- // public static final String IMAGE_PHYSICAL_WIDTH_DPI = "image:physicalWidthDpi";
- // public static final String IMAGE_PHYSICAL_HEIGHT_DPI = "image:physicalHeightDpi";
- // public static final String IMAGE_PHYSICAL_WIDTH_INCHES = "image:physicalWidthInches";
- // public static final String IMAGE_PHYSICAL_HEIGHT_INCHES = "image:physicalHeightInches";
/**
* {@inheritDoc}
@@ -105,7 +88,7 @@ public class ImageMetadataSequencer implements StreamSequencer {
// Generate the output graph if we found useful metadata ...
if (metadata != null) {
PathFactory pathFactory = context.getValueFactories().getPathFactory();
- Path metadataNode = pathFactory.create(ImageMetadataLexicon.METADATA_NODE);
+ Path metadataNode = pathFactory.createRelativePath(ImageMetadataLexicon.METADATA_NODE);
// Place the image metadata into the output map ...
output.setProperty(metadataNode, JcrLexicon.PRIMARY_TYPE, "image:metadata");
Index: modeshape-jcr-api/src/main/java/org/modeshape/jcr/api/Lock.java
deleted file mode 100644
===================================================================
--- modeshape-jcr-api/src/main/java/org/modeshape/jcr/api/Lock.java (revision 1855)
+++ /dev/null (working copy)
@@ -1,54 +0,0 @@
-/*
- * ModeShape (http://www.modeshape.org)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership. Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of
- * individual contributors.
- *
- * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * ModeShape is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.modeshape.jcr.api;
-
-import javax.jcr.RepositoryException;
-
-/**
- * Placeholder for JCR 2.0 Lock interface
- *
- */
-public interface Lock extends javax.jcr.lock.Lock {
-
- /**
- * Returns the number of seconds remaining until this locks times out. If the lock has already timed out, a negative value is
- * returned. If the number of seconds remaining is infinite or unknown, Long.MAX_VALUE
is returned.
- *
- * @return the number of seconds remaining until this lock times out.
- * @throws RepositoryException if an error occurs.
- * @since JCR 2.0
- */
- public long getSecondsRemaining() throws RepositoryException;
-
- /**
- * Returns true
if the current session is the owner of this lock, either because it is session-scoped and bound
- * to this session or open-scoped and this session currently holds the token for this lock. Returns false
- * otherwise.
- *
- * @return a boolean
.
- * @since JCR 2.0
- */
- public boolean isLockOwningSession();
-
-}
Index: modeshape-jcr-api/src/main/java/org/modeshape/jcr/api/LockManager.java
deleted file mode 100644
===================================================================
--- modeshape-jcr-api/src/main/java/org/modeshape/jcr/api/LockManager.java (revision 1855)
+++ /dev/null (working copy)
@@ -1,184 +0,0 @@
-/*
- * ModeShape (http://www.modeshape.org)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership. Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of
- * individual contributors.
- *
- * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * ModeShape is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.modeshape.jcr.api;
-
-import javax.jcr.AccessDeniedException;
-import javax.jcr.InvalidItemStateException;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.RepositoryException;
-import javax.jcr.lock.Lock;
-import javax.jcr.lock.LockException;
-
-/**
- * Placeholder for the JCR 2.0 LockManager interface
- */
-public interface LockManager {
-
- /**
- * Adds the specified lock token to the current Session
. Holding a lock token makes the current
- * Session
the owner of the lock specified by that particular lock token.
- *
- * @param lockToken a lock token (a string).
- * @throws LockException if the specified lock token is already held by another Session
and the implementation
- * does not support simultaneous ownership of open-scoped locks.
- * @throws RepositoryException if another error occurs.
- */
- public void addLockToken( String lockToken ) throws LockException, RepositoryException;
-
- /**
- * Returns the Lock
object that applies to the node at the specified absPath
. This may be either a
- * lock on that node itself or a deep lock on a node above that node.
- *
- *
- * @param absPath absolute path of node for which to obtain the lock
- * @return The applicable Lock
object.
- * @throws LockException if no lock applies to this node.
- * @throws AccessDeniedException if the current session does not have sufficent access to get the lock.
- * @throws PathNotFoundException if no node is found at absPath
- * @throws RepositoryException if another error occurs.
- */
- public Lock getLock( String absPath ) throws PathNotFoundException, LockException, AccessDeniedException, RepositoryException;
-
- /**
- * Returns an array containing all lock tokens currently held by the current Session
. Note that any such tokens
- * will represent open-scoped locks, since session-scoped locks do not have tokens.
- *
- * @return an array of lock tokens (strings)
- * @throws RepositoryException if an error occurs.
- */
- public String[] getLockTokens() throws RepositoryException;
-
- /**
- * Returns true
if the node at absPath
holds a lock; otherwise returns false
. To
- * hold a lock means that this node has actually had a lock placed on it specifically, as opposed to just having a lock
- * apply to it due to a deep lock held by a node above.
- *
- * @param absPath absolute path of node
- * @return a boolean
.
- * @throws PathNotFoundException if no node is found at absPath
- * @throws RepositoryException if an error occurs.
- */
- public boolean holdsLock( String absPath ) throws PathNotFoundException, RepositoryException;
-
- /**
- *
- * Places a lock on the node at absPath
. If successful, the node is said to hold the lock.
- *
- * If isDeep
is true
then the lock applies to the specified node and all its descendant nodes; if
- * false
, the lock applies only to the specified node. On a successful lock, the jcr:lockIsDeep
- * property of the locked node is set to this value.
- *
- * If isSessionScoped
is true
then this lock will expire upon the expiration of the current session
- * (either through an automatic or explicit Session.logout
); if false, this lock does not expire until it is
- * explicitly unlocked, it times out, or it is automatically unlocked due to a implementation-specific limitation.
- *
- * The timeout parameter specifies the number of seconds until the lock times out (if it is not refreshed with
- * Lock.refresh
in the meantime). An implementation may use this information as a hint or ignore it altogether.
- * Clients can discover the actual timeout by inspecting the returned Lock
object.
- *
- * The ownerInfo
parameter can be used to pass a string holding owner information relevant to the client. An
- * implementation may either use or ignore this parameter. If it uses the parameter it must set the jcr:lockOwner
- * property of the locked node to this value and return this value on Lock.getLockOwner
. If it ignores this
- * parameter the jcr:lockOwner
property (and the value returned by Lock.getLockOwner
) is set to
- * either the value returned by Session.getUserID
of the owning session or an implementation-specific string
- * identifying the owner.
- *
- * The method returns a Lock
object representing the new lock. If the lock is open-scoped the returned lock will
- * include a lock token. The lock token is also automatically added to the set of lock tokens held by the current session.
- *
- * The addition or change of the properties jcr:lockIsDeep
and jcr:lockOwner
are persisted
- * immediately; there is no need to call save
.
- *
- * It is possible to lock a node even if it is checked-in.
- *
- * @param absPath absolute path of node to be locked
- * @param isDeep if true
this lock will apply to this node and all its descendants; if false
, it
- * applies only to this node.
- * @param isSessionScoped if true
, this lock expires with the current session; if false
it expires
- * when explicitly or automatically unlocked for some other reason.
- * @param timeoutHint desired lock timeout in seconds (servers are free to ignore this value); specify {@link Long#MAX_VALUE}
- * for no timeout.
- * @param ownerInfo a string containing owner information supplied by the client; servers are free to ignore this value.
- * @return A Lock
object containing a lock token.
- * @throws LockException if this node is not mix:lockable
or this node is already locked or isDeep
- * is true
and a descendant node of this node already holds a lock.
- * @throws AccessDeniedException if this session does not have sufficent access to lock this node.
- * @throws InvalidItemStateException if this node has pending unsaved changes.
- * @throws PathNotFoundException if no node is found at absPath
- * @throws RepositoryException if another error occurs.
- */
- public Lock lock( String absPath,
- boolean isDeep,
- boolean isSessionScoped,
- long timeoutHint,
- String ownerInfo )
- throws LockException, PathNotFoundException, AccessDeniedException, InvalidItemStateException, RepositoryException;
-
- /**
- * Returns true
if the node at absPath
is locked either as a result of a lock held by that node or
- * by a deep lock on a node above that node; otherwise returns false
.
- *
- * @param absPath absolute path of node
- * @return a boolean
.
- * @throws PathNotFoundException if no node is found at absPath
- * @throws RepositoryException if an error occurs.
- */
- public boolean isLocked( String absPath ) throws PathNotFoundException, RepositoryException;
-
- /**
- * Removes the specified lock token from this Session
.
- *
- * @param lockToken a lock token (a string)
- * @throws LockException if the current Session
does not hold the specified lock token.
- * @throws RepositoryException if another error occurs.
- */
- public void removeLockToken( String lockToken ) throws LockException, RepositoryException;
-
- /**
- * Removes the lock on the node at absPath
. Also removes the properties jcr:lockOwner
and
- * jcr:lockIsDeep
from that node. As well, the corresponding lock token is removed from the set of lock tokens
- * held by the current Session
.
- *
- * If the node does not currently hold a lock or holds a lock for which this Session
is not the owner and is not
- * a "lock-superuser", then a LockException
is thrown. Note that the system may give permission to a non-owning
- * session to unlock a lock. Typically, such "lock-superuser" capability is intended to facilitate administrational clean-up
- * of orphaned open-scoped locks.
- *
- * Note that it is possible to unlock a node even if it is checked-in (the lock-related properties will be changed despite the
- * checked-in status).
- *
- * If the current session does not have sufficient privileges to remove the lock, an AccessDeniedException
is
- * thrown.
- *
- * @param absPath absolute path of node to be unlocked
- * @throws LockException if this node does not currently hold a lock or holds a lock for which this Session does not have the
- * correct lock token.
- * @throws AccessDeniedException if the current session does not have permission to unlock this node.
- * @throws InvalidItemStateException if this node has pending unsaved changes.
- * @throws PathNotFoundException if no node is found at absPath
- * @throws RepositoryException if another error occurs.
- */
- public void unlock( String absPath )
- throws PathNotFoundException, LockException, AccessDeniedException, InvalidItemStateException, RepositoryException;
-}
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/AbstractJcrNode.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/AbstractJcrNode.java (revision 1855)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/AbstractJcrNode.java (working copy)
@@ -24,6 +24,7 @@
package org.modeshape.jcr;
import java.io.InputStream;
+import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
@@ -51,6 +52,7 @@ import javax.jcr.RepositoryException;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
+import javax.jcr.lock.Lock;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.nodetype.NoSuchNodeTypeException;
@@ -82,7 +84,6 @@ import org.modeshape.graph.session.GraphSession.PropertyInfo;
import org.modeshape.jcr.SessionCache.JcrNodePayload;
import org.modeshape.jcr.SessionCache.JcrPropertyPayload;
import org.modeshape.jcr.SessionCache.NodeEditor;
-import org.modeshape.jcr.api.Lock;
/**
* An abstract implementation of the JCR {@link javax.jcr.Node} interface. Instances of this class are created and managed by the
@@ -121,10 +122,6 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
return nodeInfo().getSegment();
}
- JcrLockManager lockManager() {
- return session().lockManager();
- }
-
final Node nodeInfo()
throws InvalidItemStateException, AccessDeniedException, RepositoryException {
try {
@@ -527,7 +524,14 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
// Execute a query that will report all nodes referencing this node ...
String uuid = getUUID();
QueryBuilder builder = new QueryBuilder(context().getValueFactories().getTypeSystem());
- QueryCommand query = builder.select("jcr:primaryType").fromAllNodesAs("allNodes").where().referenceValue("allNodes").isEqualTo(uuid).end().limit(maxNumberOfNodes).query();
+ QueryCommand query = builder.select("jcr:primaryType")
+ .fromAllNodesAs("allNodes")
+ .where()
+ .referenceValue("allNodes")
+ .isEqualTo(uuid)
+ .end()
+ .limit(maxNumberOfNodes)
+ .query();
Query jcrQuery = session().workspace().queryManager().createQuery(query);
QueryResult result = jcrQuery.execute();
return result.getNodes();
@@ -989,7 +993,7 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
JcrNodeType mixinCandidateType = cache.nodeTypes().getNodeType(mixinName);
// Check this separately since it throws a different type of exception
- if (this.isLocked() && !getLock().isLockOwningSession()) {
+ if (this.isLocked() && !holdsLock()) {
throw new LockException(JcrI18n.lockTokenNotHeld.text(this.location));
}
@@ -1025,7 +1029,7 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
public final void removeMixin( String mixinName ) throws RepositoryException {
checkSession();
- if (this.isLocked() && !getLock().isLockOwningSession()) {
+ if (this.isLocked() && !holdsLock()) {
throw new LockException(JcrI18n.lockTokenNotHeld.text(this.location));
}
@@ -1154,7 +1158,7 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException {
checkSession();
- if (this.isLocked() && !getLock().isLockOwningSession()) {
+ if (this.isLocked() && !holdsLock()) {
throw new LockException(JcrI18n.lockTokenNotHeld.text(this.location));
}
@@ -1220,7 +1224,7 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
RepositoryException {
checkSession();
- if (isLocked() && !getLock().isLockOwningSession()) {
+ if (isLocked() && !holdsLock()) {
throw new LockException(JcrI18n.lockTokenNotHeld.text(this.location));
}
@@ -1316,7 +1320,7 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
CheckArg.isNotEmpty(relPath, relPath);
checkSession();
- if (isLocked() && !getLock().isLockOwningSession()) {
+ if (isLocked() && !holdsLock()) {
return false;
}
@@ -1781,7 +1785,9 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
*/
public final boolean holdsLock() throws RepositoryException {
checkSession();
- return lockManager().holdsLock(this);
+ WorkspaceLockManager.ModeShapeLock lock = session().workspace().lockManager().lockFor(session(), this.location);
+
+ return lock != null && cache.session().lockTokens().contains(lock.getLockToken());
}
/**
@@ -1791,7 +1797,7 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
* @see javax.jcr.Node#isLocked()
*/
public final boolean isLocked() throws LockException, RepositoryException {
- return lockManager().isLocked(this);
+ return lock() != null;
}
/**
@@ -1802,7 +1808,37 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
public final Lock lock( boolean isDeep,
boolean isSessionScoped ) throws LockException, RepositoryException {
checkSession();
- return lockManager().lock(this, isDeep, isSessionScoped, -1L, null);
+ if (!isLockable()) {
+ throw new LockException(JcrI18n.nodeNotLockable.text(getPath()));
+ }
+
+ if (isLocked()) {
+ throw new LockException(JcrI18n.alreadyLocked.text(this.location));
+ }
+
+ if (isDeep) {
+ LinkedList> nodesToVisit = new LinkedList>();
+ nodesToVisit.add(nodeInfo());
+
+ while (!nodesToVisit.isEmpty()) {
+ Node node = nodesToVisit.remove(nodesToVisit.size() - 1);
+ if (session().workspace().lockManager().lockFor(session(), node.getLocation()) != null) throw new LockException(
+ JcrI18n.parentAlreadyLocked.text(this.location,
+ node.getLocation()));
+
+ for (Node child : node.getChildren()) {
+ nodesToVisit.add(child);
+ }
+ }
+ }
+
+ WorkspaceLockManager.ModeShapeLock lock = session().workspace().lockManager().lock(session(),
+ this.location,
+ isDeep,
+ isSessionScoped);
+
+ cache.session().addLockToken(lock.getLockToken());
+ return lock.lockFor(cache);
}
/**
@@ -1812,7 +1848,43 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
*/
public final void unlock() throws LockException, RepositoryException {
checkSession();
- lockManager().unlock(this);
+ WorkspaceLockManager.ModeShapeLock lock = session().workspace().lockManager().lockFor(session(), this.location);
+
+ if (lock == null) {
+ throw new LockException(JcrI18n.notLocked.text(this.location));
+ }
+
+ if (!session().lockTokens().contains(lock.getLockToken())) {
+ try {
+ // See if the user has the permission to break someone else's lock
+ session().checkPermission(cache.workspaceName(), null, ModeShapePermissions.UNLOCK_ANY);
+ } catch (AccessControlException iae) {
+ throw new LockException(JcrI18n.lockTokenNotHeld.text(this.location));
+ }
+ }
+
+ session().workspace().lockManager().unlock(session().getExecutionContext(), lock);
+ session().removeLockToken(lock.getLockToken());
+ }
+
+ private final WorkspaceLockManager.ModeShapeLock lock() throws RepositoryException {
+ // This can only happen in mocked testing.
+ if (session() == null || session().workspace() == null) return null;
+
+ WorkspaceLockManager lockManager = session().workspace().lockManager();
+ WorkspaceLockManager.ModeShapeLock lock = lockManager.lockFor(session(), this.location);
+ if (lock != null) return lock;
+
+ AbstractJcrNode parent = this;
+ while (!parent.isRoot()) {
+ parent = parent.getParent();
+
+ WorkspaceLockManager.ModeShapeLock parentLock = lockManager.lockFor(session(), parent.location);
+ if (parentLock != null && parentLock.isLive()) {
+ return parentLock.isDeep() ? parentLock : null;
+ }
+ }
+ return null;
}
/**
@@ -1822,7 +1894,10 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
*/
public final Lock getLock() throws LockException, RepositoryException {
checkSession();
- return lockManager().getLock(this);
+ WorkspaceLockManager.ModeShapeLock lock = lock();
+
+ if (lock == null) throw new LockException(JcrI18n.notLocked.text(this.location));
+ return lock.lockFor(cache);
}
/**
@@ -1948,8 +2023,8 @@ abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node
if (destChildRelPath != null) {
Path destPath = pathFactory.create(destChildRelPath);
if (destPath.isAbsolute() || destPath.size() != 1) {
- throw new ItemNotFoundException(
- JcrI18n.pathNotFound.text(destPath.getString(cache.context().getNamespaceRegistry()),
+ throw new ItemNotFoundException(JcrI18n.pathNotFound.text(destPath.getString(cache.context()
+ .getNamespaceRegistry()),
cache.session().workspace().getName()));
}
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/AbstractJcrProperty.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/AbstractJcrProperty.java (revision 1855)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/AbstractJcrProperty.java (working copy)
@@ -32,6 +32,7 @@ import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
+import javax.jcr.lock.Lock;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.nodetype.PropertyDefinition;
@@ -44,7 +45,6 @@ import org.modeshape.graph.property.ValueFactory;
import org.modeshape.graph.session.GraphSession.PropertyInfo;
import org.modeshape.jcr.SessionCache.JcrPropertyPayload;
import org.modeshape.jcr.SessionCache.NodeEditor;
-import org.modeshape.jcr.api.Lock;
/**
* An abstract {@link Property JCR Property} implementation.
@@ -84,7 +84,7 @@ abstract class AbstractJcrProperty extends AbstractJcrItem implements Property,
*/
protected final void checkForLock() throws LockException, RepositoryException {
- if (this.getParent().isLocked() && !getParent().getLock().isLockOwningSession()) {
+ if (this.getParent().isLocked()) {
Lock parentLock = this.getParent().getLock();
if (parentLock != null && parentLock.getLockToken() == null) {
throw new LockException(JcrI18n.lockTokenNotHeld.text(this.getParent().location));
@@ -258,10 +258,10 @@ abstract class AbstractJcrProperty extends AbstractJcrItem implements Property,
*/
public void remove() throws VersionException, LockException, ConstraintViolationException, RepositoryException {
checkSession();
- AbstractJcrNode parentNode = getParent();
+ Node parentNode = getParent();
if (parentNode.isLocked()) {
- Lock parentLock = parentNode.lockManager().getLock(parentNode);
- if (parentLock != null && !parentLock.isLockOwningSession()) {
+ Lock parentLock = parentNode.getLock();
+ if (parentLock != null && parentLock.getLockToken() == null) {
throw new LockException(JcrI18n.lockTokenNotHeld.text(getPath()));
}
}
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrI18n.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrI18n.java (revision 1855)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrI18n.java (working copy)
@@ -205,7 +205,6 @@ public final class JcrI18n {
public static I18n notLocked;
public static I18n lockTokenNotHeld;
public static I18n lockTokenAlreadyHeld;
- public static I18n invalidLockToken;
public static I18n uuidRequiredForLock;
// JcrObservationManager messages
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrLockManager.java
deleted file mode 100644
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrLockManager.java (revision 1855)
+++ /dev/null (working copy)
@@ -1,278 +0,0 @@
-/*
- * ModeShape (http://www.modeshape.org)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership. Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of
- * individual contributors.
- *
- * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * ModeShape is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.modeshape.jcr;
-
-import java.security.AccessControlException;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Set;
-import java.util.UUID;
-import javax.jcr.AccessDeniedException;
-import javax.jcr.InvalidItemStateException;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.RepositoryException;
-import javax.jcr.lock.Lock;
-import javax.jcr.lock.LockException;
-import org.modeshape.common.util.CheckArg;
-import org.modeshape.graph.session.GraphSession.Node;
-import org.modeshape.jcr.SessionCache.JcrNodePayload;
-import org.modeshape.jcr.SessionCache.JcrPropertyPayload;
-import org.modeshape.jcr.WorkspaceLockManager.ModeShapeLock;
-import org.modeshape.jcr.api.LockManager;
-
-/**
- * A per-session lock manager for a given workspace. This class encapsulates the session-specific locking logic and checks that do
- * not occur in @{link WorkspaceLockManager}.
- */
-public class JcrLockManager implements LockManager {
-
- private final JcrSession session;
- private final WorkspaceLockManager lockManager;
- private final Set lockTokens;
-
- JcrLockManager( JcrSession session,
- WorkspaceLockManager lockManager ) {
- this.session = session;
- this.lockManager = lockManager;
- lockTokens = new HashSet();
- }
-
- @Override
- public void addLockToken( String lockToken ) throws LockException {
- CheckArg.isNotNull(lockToken, "lock token");
-
- // Trivial case of giving a token back to ourself
- if (lockTokens.contains(lockToken)) {
- return;
- }
-
- if (lockManager.isHeldBySession(session, lockToken)) {
- throw new LockException(JcrI18n.lockTokenAlreadyHeld.text(lockToken));
- }
-
- lockManager.setHeldBySession(session, lockToken, true);
- lockTokens.add(lockToken);
- }
-
- @Override
- public Lock getLock( String absPath ) throws PathNotFoundException, LockException, AccessDeniedException, RepositoryException {
- AbstractJcrNode node = session.getNode(absPath);
- return getLock(node);
- }
-
- org.modeshape.jcr.api.Lock getLock( AbstractJcrNode node )
- throws PathNotFoundException, LockException, AccessDeniedException, RepositoryException {
- WorkspaceLockManager.ModeShapeLock lock = lockFor(node);
- if (lock != null) return lock.lockFor(node.cache);
- throw new LockException(JcrI18n.notLocked.text(node.location));
- }
-
- @Override
- public String[] getLockTokens() {
- Set publicTokens = new HashSet(lockTokens);
-
- for (Iterator iter = publicTokens.iterator(); iter.hasNext();) {
- String token = iter.next();
- WorkspaceLockManager.ModeShapeLock lock = lockManager.lockFor(token);
- if (lock.isSessionScoped()) iter.remove();
- }
-
- return publicTokens.toArray(new String[publicTokens.size()]);
- }
-
- Set lockTokens() {
- return this.lockTokens;
- }
-
- @Override
- public boolean holdsLock( String absPath ) throws PathNotFoundException, RepositoryException {
- AbstractJcrNode node = session.getNode(absPath);
- return holdsLock(node);
- }
-
- boolean holdsLock( AbstractJcrNode node ) {
- WorkspaceLockManager.ModeShapeLock lock = lockManager.lockFor(session, node.location);
-
- return lock != null;
-
- }
-
- @Override
- public boolean isLocked( String absPath ) throws PathNotFoundException, RepositoryException {
- AbstractJcrNode node = session.getNode(absPath);
- return isLocked(node);
- }
-
- boolean isLocked( AbstractJcrNode node ) throws PathNotFoundException, RepositoryException {
- return lockFor(node) != null;
- }
-
- @Override
- public Lock lock( String absPath,
- boolean isDeep,
- boolean isSessionScoped,
- long timeoutHint,
- String ownerInfo )
- throws LockException, PathNotFoundException, AccessDeniedException, InvalidItemStateException, RepositoryException {
- AbstractJcrNode node = session.getNode(absPath);
- return lock(node, isDeep, isSessionScoped, timeoutHint, ownerInfo);
- }
-
- org.modeshape.jcr.api.Lock lock( AbstractJcrNode node,
- boolean isDeep,
- boolean isSessionScoped,
- long timeoutHint,
- String ownerInfo )
- throws LockException, PathNotFoundException, AccessDeniedException, InvalidItemStateException, RepositoryException {
- if (!node.isLockable()) {
- throw new LockException(JcrI18n.nodeNotLockable.text(node.getPath()));
- }
-
- if (node.isLocked()) {
- throw new LockException(JcrI18n.alreadyLocked.text(node.location));
- }
-
- if (node.isModified()) {
- throw new InvalidItemStateException();
- }
-
- if (isDeep) {
- LinkedList> nodesToVisit = new LinkedList>();
- nodesToVisit.add(node.nodeInfo());
-
- while (!nodesToVisit.isEmpty()) {
- Node graphNode = nodesToVisit.remove(nodesToVisit.size() - 1);
- if (lockManager.lockFor(session, graphNode.getLocation()) != null) throw new LockException(
- JcrI18n.parentAlreadyLocked.text(node.location,
- graphNode.getLocation()));
-
- for (Node child : graphNode.getChildren()) {
- nodesToVisit.add(child);
- }
- }
- }
-
- WorkspaceLockManager.ModeShapeLock lock = lockManager.lock(session, node.location, isDeep, isSessionScoped);
-
- addLockToken(lock.getLockToken());
- return lock.lockFor(session.cache());
-
- }
-
- @Override
- public void removeLockToken( String lockToken ) throws LockException {
- CheckArg.isNotNull(lockToken, "lockToken");
- // A LockException is thrown if the lock associated with the specified lock token is session-scoped.
-
- if (!lockTokens.contains(lockToken)) {
- throw new LockException(JcrI18n.invalidLockToken.text(lockToken));
- }
-
- /*
- * The JCR API library that we're using diverges from the spec in that it doesn't declare
- * this method to throw a LockException. We'll throw a runtime exception for now.
- */
-
- ModeShapeLock lock = lockManager.lockFor(lockToken);
- if (lock == null) {
- // The lock is no longer valid
- lockTokens.remove(lockToken);
- return;
- }
-
- if (lock.isSessionScoped()) {
- throw new IllegalStateException(JcrI18n.cannotRemoveLockToken.text(lockToken));
- }
-
- lockManager.setHeldBySession(session, lockToken, false);
- lockTokens.remove(lockToken);
- }
-
- @Override
- public void unlock( String absPath )
- throws PathNotFoundException, LockException, AccessDeniedException, InvalidItemStateException, RepositoryException {
- AbstractJcrNode node = session.getNode(absPath);
- unlock(node);
- }
-
- void unlock( AbstractJcrNode node )
- throws PathNotFoundException, LockException, AccessDeniedException, InvalidItemStateException, RepositoryException {
- WorkspaceLockManager.ModeShapeLock lock = lockManager.lockFor(session, node.location);
-
- if (lock == null) {
- throw new LockException(JcrI18n.notLocked.text(node.location));
- }
-
- if (lockTokens.contains(lock.getLockToken())) {
- lockManager.unlock(session.getExecutionContext(), lock);
- removeLockToken(lock.getLockToken());
- } else {
- try {
- // See if the user has the permission to break someone else's lock
- session.checkPermission(session.cache().workspaceName(), null, ModeShapePermissions.UNLOCK_ANY);
-
- // This user doesn't have the lock token, so don't try to remove it
- lockManager.unlock(session.getExecutionContext(), lock);
- } catch (AccessControlException iae) {
- throw new LockException(JcrI18n.lockTokenNotHeld.text(node.location));
- }
- }
-
- }
-
- /**
- *
- */
- final void cleanLocks() {
- lockManager.cleanLocks(session);
- }
-
- final WorkspaceLockManager.ModeShapeLock lockFor( AbstractJcrNode node ) throws RepositoryException {
- // This can only happen in mocked testing.
- if (session == null || session.workspace() == null) return null;
-
- WorkspaceLockManager.ModeShapeLock lock = lockManager.lockFor(session, node.location);
- if (lock != null) return lock;
-
- AbstractJcrNode parent = node;
- while (!parent.isRoot()) {
- parent = parent.getParent();
-
- WorkspaceLockManager.ModeShapeLock parentLock = lockManager.lockFor(session, parent.location);
- if (parentLock != null && parentLock.isLive()) {
- return parentLock.isDeep() ? parentLock : null;
- }
- }
- return null;
- }
-
- final WorkspaceLockManager.ModeShapeLock lockFor( UUID nodeUuid ) throws RepositoryException {
- // This can only happen in mocked testing.
- if (session == null || session.workspace() == null) return null;
-
- return lockManager.lockFor(nodeUuid);
- }
-
-}
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNode.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNode.java (revision 1855)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrNode.java (working copy)
@@ -26,13 +26,13 @@ package org.modeshape.jcr;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
+import javax.jcr.lock.Lock;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.version.VersionException;
import net.jcip.annotations.NotThreadSafe;
import org.modeshape.graph.Location;
import org.modeshape.graph.session.GraphSession.NodeId;
-import org.modeshape.jcr.api.Lock;
/**
* A concrete {@link Node JCR Node} implementation.
@@ -105,8 +105,8 @@ class JcrNode extends AbstractJcrNode {
public void remove() throws RepositoryException, LockException {
Node parentNode = getParent();
if (parentNode.isLocked()) {
- Lock parentLock = lockManager().getLock(this);
- if (parentLock != null && !parentLock.isLockOwningSession()) {
+ Lock parentLock = parentNode.getLock();
+ if (parentLock != null && parentLock.getLockToken() == null) {
throw new LockException(JcrI18n.lockTokenNotHeld.text(this.location));
}
}
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrSession.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrSession.java (revision 1855)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrSession.java (working copy)
@@ -29,6 +29,7 @@ import java.io.OutputStream;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.Calendar;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -87,6 +88,7 @@ import org.modeshape.jcr.JcrContentHandler.SaveMode;
import org.modeshape.jcr.JcrNamespaceRegistry.Behavior;
import org.modeshape.jcr.JcrRepository.Option;
import org.modeshape.jcr.SessionCache.JcrPropertyPayload;
+import org.modeshape.jcr.WorkspaceLockManager.ModeShapeLock;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@@ -135,6 +137,8 @@ class JcrSession implements Session {
private final SessionCache cache;
+ private final Set lockTokens;
+
/**
* A cached instance of the root path.
*/
@@ -176,8 +180,11 @@ class JcrSession implements Session {
this.cache = new SessionCache(this);
this.isLive = true;
+ this.lockTokens = new HashSet();
- this.performReferentialIntegrityChecks = Boolean.valueOf(repository.getOptions().get(Option.PERFORM_REFERENTIAL_INTEGRITY_CHECKS)).booleanValue();
+ this.performReferentialIntegrityChecks = Boolean.valueOf(repository.getOptions()
+ .get(Option.PERFORM_REFERENTIAL_INTEGRITY_CHECKS))
+ .booleanValue();
assert this.sessionAttributes != null;
assert this.workspace != null;
@@ -221,10 +228,6 @@ class JcrSession implements Session {
return this.executionContext.getId();
}
- JcrLockManager lockManager() {
- return workspace.lockManager();
- }
-
JcrNodeTypeManager nodeTypeManager() {
return this.workspace.nodeTypeManager();
}
@@ -246,6 +249,10 @@ class JcrSession implements Session {
return this.repository;
}
+ final Collection lockTokens() {
+ return lockTokens;
+ }
+
Graph.Batch createBatch() {
return graph.batch();
}
@@ -350,11 +357,17 @@ class JcrSession implements Session {
public void addLockToken( String lt ) throws LockException {
CheckArg.isNotNull(lt, "lock token");
- try {
- lockManager().addLockToken(lt);
- } catch (LockException le) {
- // For backwards compatibility (and API compatibility), the LockExceptions from the LockManager need to get swallowed
+ // Trivial case of giving a token back to ourself
+ if (lockTokens.contains(lt)) {
+ return;
+ }
+
+ if (workspace().lockManager().isHeldBySession(this, lt)) {
+ throw new LockException(JcrI18n.lockTokenAlreadyHeld.text(lt));
}
+
+ workspace().lockManager().setHeldBySession(this, lt, true);
+ lockTokens.add(lt);
}
/**
@@ -738,7 +751,7 @@ class JcrSession implements Session {
* @see javax.jcr.Session#getLockTokens()
*/
public String[] getLockTokens() {
- return lockManager().getLockTokens();
+ return lockTokens.toArray(new String[lockTokens.size()]);
}
/**
@@ -1001,7 +1014,7 @@ class JcrSession implements Session {
isLive = false;
this.workspace().observationManager().removeAllEventListeners();
- this.lockManager().cleanLocks();
+ this.workspace().lockManager().cleanLocks(this);
this.repository.sessionLoggedOut(this);
this.executionContext.getSecurityContext().logout();
}
@@ -1028,14 +1041,14 @@ class JcrSession implements Session {
AbstractJcrNode sourceNode = getNode(pathFactory.create(srcAbsPath));
AbstractJcrNode newParentNode = getNode(destPath.getParent());
- if (sourceNode.isLocked() && !sourceNode.getLock().isLockOwningSession()) {
+ if (sourceNode.isLocked()) {
javax.jcr.lock.Lock sourceLock = sourceNode.getLock();
if (sourceLock != null && sourceLock.getLockToken() == null) {
throw new LockException(JcrI18n.lockTokenNotHeld.text(srcAbsPath));
}
}
- if (newParentNode.isLocked() && !newParentNode.getLock().isLockOwningSession()) {
+ if (newParentNode.isLocked()) {
javax.jcr.lock.Lock newParentLock = newParentNode.getLock();
if (newParentLock != null && newParentLock.getLockToken() == null) {
throw new LockException(JcrI18n.lockTokenNotHeld.text(destAbsPath));
@@ -1067,14 +1080,27 @@ class JcrSession implements Session {
*
* @see javax.jcr.Session#removeLockToken(java.lang.String)
*/
- public void removeLockToken( String lockToken ) {
- CheckArg.isNotNull(lockToken, "lock token");
+ public void removeLockToken( String lt ) {
+ CheckArg.isNotNull(lt, "lock token");
// A LockException is thrown if the lock associated with the specified lock token is session-scoped.
- try {
- lockManager().removeLockToken(lockToken);
- } catch (LockException le) {
- // For backwards compatibility (and API compatibility), the LockExceptions from the LockManager need to get swallowed
+ /*
+ * The JCR API library that we're using diverges from the spec in that it doesn't declare
+ * this method to throw a LockException. We'll throw a runtime exception for now.
+ */
+
+ ModeShapeLock lock = workspace().lockManager().lockFor(lt);
+ if (lock == null) {
+ // The lock is no longer valid
+ lockTokens.remove(lt);
+ return;
+ }
+
+ if (lock.isSessionScoped()) {
+ throw new IllegalStateException(JcrI18n.cannotRemoveLockToken.text(lt));
}
+
+ workspace().lockManager().setHeldBySession(this, lt, false);
+ lockTokens.remove(lt);
}
void recordRemoval( Location location ) throws RepositoryException {
@@ -1095,8 +1121,13 @@ class JcrSession implements Session {
TypeSystem typeSystem = executionContext.getValueFactories().getTypeSystem();
QueryBuilder builder = new QueryBuilder(typeSystem);
- QueryCommand query = builder.select("jcr:uuid").from("mix:referenceable AS referenceable").where().path("referenceable").isLike(pathStr
- + "%").end().query();
+ QueryCommand query = builder.select("jcr:uuid")
+ .from("mix:referenceable AS referenceable")
+ .where()
+ .path("referenceable")
+ .isLike(pathStr + "%")
+ .end()
+ .query();
JcrQueryManager queryManager = workspace().queryManager();
Query jcrQuery = queryManager.createQuery(query);
QueryResult result = jcrQuery.execute();
@@ -1189,10 +1220,24 @@ class JcrSession implements Session {
QueryBuilder builder = new QueryBuilder(typeSystem);
QueryCommand query = null;
if (subgraphPath != null) {
- query = builder.select("jcr:primaryType").fromAllNodesAs("allNodes").where().referenceValue("allNodes").isIn(someUuidsInBranch).and().path("allNodes").isLike(subgraphPath
- + "%").end().query();
+ query = builder.select("jcr:primaryType")
+ .fromAllNodesAs("allNodes")
+ .where()
+ .referenceValue("allNodes")
+ .isIn(someUuidsInBranch)
+ .and()
+ .path("allNodes")
+ .isLike(subgraphPath + "%")
+ .end()
+ .query();
} else {
- query = builder.select("jcr:primaryType").fromAllNodesAs("allNodes").where().referenceValue("allNodes").isIn(someUuidsInBranch).end().query();
+ query = builder.select("jcr:primaryType")
+ .fromAllNodesAs("allNodes")
+ .where()
+ .referenceValue("allNodes")
+ .isIn(someUuidsInBranch)
+ .end()
+ .query();
}
Query jcrQuery = workspace().queryManager().createQuery(query);
// The nodes that have been (transiently) deleted will not appear in these results ...
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrWorkspace.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrWorkspace.java (revision 1855)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrWorkspace.java (working copy)
@@ -78,7 +78,6 @@ import org.modeshape.jcr.JcrContentHandler.SaveMode;
import org.modeshape.jcr.SessionCache.JcrNodePayload;
import org.modeshape.jcr.SessionCache.JcrPropertyPayload;
import org.modeshape.jcr.WorkspaceLockManager.ModeShapeLock;
-import org.modeshape.jcr.api.LockManager;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@@ -146,7 +145,7 @@ class JcrWorkspace implements Workspace {
*/
private final JcrObservationManager observationManager;
- private final JcrLockManager lockManager;
+ private final WorkspaceLockManager lockManager;
/**
* The {@link Session} instance that this corresponds with this workspace.
@@ -164,6 +163,7 @@ class JcrWorkspace implements Workspace {
assert repository != null;
this.name = workspaceName;
this.repository = repository;
+ this.lockManager = repository.getLockManager(workspaceName);
// Create an execution context for this session, which should use the local namespace registry ...
NamespaceRegistry globalRegistry = context.getNamespaceRegistry();
@@ -189,7 +189,6 @@ class JcrWorkspace implements Workspace {
//
// Set up and initialize the persistent JCR namespace registry ...
this.workspaceRegistry = new JcrNamespaceRegistry(this.repository.getPersistentRegistry(), this.session);
- this.lockManager = new JcrLockManager(session, repository.getLockManager(workspaceName));
}
@@ -209,7 +208,7 @@ class JcrWorkspace implements Workspace {
return this.context;
}
- final JcrLockManager lockManager() {
+ final WorkspaceLockManager lockManager() {
return this.lockManager;
}
@@ -285,13 +284,6 @@ class JcrWorkspace implements Workspace {
}
/**
- * @return the lock manager for this workspace and session
- */
- public LockManager getLockManager() {
- return lockManager;
- }
-
- /**
* {@inheritDoc}
*/
public final QueryManager getQueryManager() {
@@ -357,7 +349,7 @@ class JcrWorkspace implements Workspace {
if (uuidProp != null) {
UUID sourceUuid = this.context.getValueFactories().getUuidFactory().create(uuidProp.getFirstValue());
- ModeShapeLock sourceLock = lockManager().lockFor(sourceUuid);
+ ModeShapeLock sourceLock = lockManager().lockFor(session, Location.create(sourceUuid));
if (sourceLock != null && sourceLock.getLockToken() == null) {
throw new LockException(JcrI18n.lockTokenNotHeld.text(srcAbsPath));
}
@@ -517,7 +509,7 @@ class JcrWorkspace implements Workspace {
if (uuidProp != null) {
UUID sourceUuid = this.context.getValueFactories().getUuidFactory().create(uuidProp.getFirstValue());
- ModeShapeLock sourceLock = lockManager().lockFor(sourceUuid);
+ ModeShapeLock sourceLock = lockManager().lockFor(session, Location.create(sourceUuid));
if (sourceLock != null && sourceLock.getLockToken() == null) {
throw new LockException(srcAbsPath);
}
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/WorkspaceLockManager.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/WorkspaceLockManager.java (revision 1855)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/WorkspaceLockManager.java (working copy)
@@ -1,26 +1,3 @@
-/*
- * ModeShape (http://www.modeshape.org)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership. Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of
- * individual contributors.
- *
- * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * ModeShape is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
package org.modeshape.jcr;
import java.util.Collection;
@@ -29,11 +6,12 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.jcr.Item;
import javax.jcr.Node;
+import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
+import javax.jcr.lock.Lock;
import javax.jcr.lock.LockException;
import net.jcip.annotations.ThreadSafe;
-import org.modeshape.common.i18n.I18n;
import org.modeshape.graph.ExecutionContext;
import org.modeshape.graph.Graph;
import org.modeshape.graph.Location;
@@ -46,6 +24,7 @@ import org.modeshape.graph.property.PathNotFoundException;
import org.modeshape.graph.property.Property;
import org.modeshape.graph.property.PropertyFactory;
import org.modeshape.graph.property.ValueFactory;
+import org.modeshape.jcr.SessionCache.NodeEditor;
/**
* Manages the locks for a particular workspace in a repository. Locks are stored in a {@code Map} while they exist
@@ -72,10 +51,7 @@ class WorkspaceLockManager {
this.workspaceLocksByNodeUuid = new ConcurrentHashMap();
Property locksPrimaryType = context.getPropertyFactory().create(JcrLexicon.PRIMARY_TYPE, ModeShapeLexicon.LOCKS);
-
- if (locksPath != null) {
- repository.createSystemGraph(context).create(locksPath, locksPrimaryType).ifAbsent().and();
- }
+ repository.createSystemGraph(context).create(locksPath, locksPrimaryType).ifAbsent().and();
}
/**
@@ -94,9 +70,9 @@ class WorkspaceLockManager {
* @throws RepositoryException if an error occurs updating the graph state
*/
ModeShapeLock lock( JcrSession session,
- Location nodeLocation,
- boolean isDeep,
- boolean isSessionScoped ) throws RepositoryException {
+ Location nodeLocation,
+ boolean isDeep,
+ boolean isSessionScoped ) throws RepositoryException {
assert nodeLocation != null;
UUID lockUuid = UUID.randomUUID();
@@ -134,8 +110,17 @@ class WorkspaceLockManager {
lockIsDeepProp).ifAbsent().and();
batch.execute();
+ SessionCache cache = session.cache();
+ AbstractJcrNode lockedNode = cache.findJcrNode(Location.create(nodeUuid));
+ NodeEditor editor = cache.getEditorFor(lockedNode.nodeInfo());
+
+ // Set the properties in the cache...
+ editor.setProperty(JcrLexicon.LOCK_OWNER,
+ (JcrValue)cache.session().getValueFactory().createValue(lockOwner, PropertyType.STRING),
+ false);
+ editor.setProperty(JcrLexicon.LOCK_IS_DEEP, (JcrValue)cache.session().getValueFactory().createValue(isDeep), false);
+
lockNodeInRepository(session, nodeUuid, lockOwnerProp, lockIsDeepProp, lock, isDeep);
- session.cache().refreshProperties(Location.create(nodeUuid));
workspaceLocksByNodeUuid.put(nodeUuid, lock);
return lock;
@@ -147,10 +132,10 @@ class WorkspaceLockManager {
/* Factory method added to facilitate mocked testing */
ModeShapeLock createLock( String lockOwner,
- UUID lockUuid,
- UUID nodeUuid,
- boolean isDeep,
- boolean isSessionScoped ) {
+ UUID lockUuid,
+ UUID nodeUuid,
+ boolean isDeep,
+ boolean isSessionScoped ) {
return new ModeShapeLock(lockOwner, lockUuid, nodeUuid, isDeep, isSessionScoped);
}
@@ -268,25 +253,20 @@ class WorkspaceLockManager {
* @param session the session on behalf of which the lock query is being performed
* @param lockToken the lock token to check; may not be null
* @return true if a session currently holds the lock token, false otherwise
- * @throws LockException if the lock token doesn't exist
*/
boolean isHeldBySession( JcrSession session,
- String lockToken ) throws LockException {
+ String lockToken ) {
assert lockToken != null;
ExecutionContext context = session.getExecutionContext();
ValueFactory booleanFactory = context.getValueFactories().getBooleanFactory();
PathFactory pathFactory = context.getValueFactories().getPathFactory();
- try {
- org.modeshape.graph.Node lockNode = repository.createSystemGraph(context).getNodeAt(pathFactory.create(locksPath,
- pathFactory.createSegment(lockToken)));
+ org.modeshape.graph.Node lockNode = repository.createSystemGraph(context)
+ .getNodeAt(pathFactory.create(locksPath,
+ pathFactory.createSegment(lockToken)));
- return booleanFactory.create(lockNode.getProperty(ModeShapeLexicon.IS_HELD_BY_SESSION).getFirstValue());
- } catch (PathNotFoundException pnfe) {
- I18n msg = JcrI18n.invalidLockToken;
- throw new LockException(msg.text(lockToken));
- }
+ return booleanFactory.create(lockNode.getProperty(ModeShapeLexicon.IS_HELD_BY_SESSION).getFirstValue());
}
@@ -308,8 +288,9 @@ class WorkspaceLockManager {
PropertyFactory propFactory = context.getPropertyFactory();
PathFactory pathFactory = context.getValueFactories().getPathFactory();
- repository.createSystemGraph(context).set(propFactory.create(ModeShapeLexicon.IS_HELD_BY_SESSION, value)).on(pathFactory.create(locksPath,
- pathFactory.createSegment(lockToken)));
+ repository.createSystemGraph(context)
+ .set(propFactory.create(ModeShapeLexicon.IS_HELD_BY_SESSION, value))
+ .on(pathFactory.create(locksPath, pathFactory.createSegment(lockToken)));
}
/**
@@ -338,18 +319,8 @@ class WorkspaceLockManager {
* @return the corresponding lock, possibly null if there is no such lock
*/
ModeShapeLock lockFor( JcrSession session,
- Location nodeLocation ) {
+ Location nodeLocation ) {
UUID nodeUuid = uuidFor(session, nodeLocation);
- return lockFor(nodeUuid);
- }
-
- /**
- * Returns the lock that corresponds to the given UUID
- *
- * @param nodeUuid the node UUID
- * @return the corresponding lock, possibly null if there is no such lock
- */
- ModeShapeLock lockFor( UUID nodeUuid ) {
if (nodeUuid == null) return null;
return workspaceLocksByNodeUuid.get(nodeUuid);
}
@@ -383,7 +354,7 @@ class WorkspaceLockManager {
*/
void cleanLocks( JcrSession session ) {
ExecutionContext context = session.getExecutionContext();
- Collection lockTokens = session.lockManager().lockTokens();
+ Collection lockTokens = session.lockTokens();
for (String lockToken : lockTokens) {
ModeShapeLock lock = lockFor(lockToken);
if (lock != null && lock.isSessionScoped()) {
@@ -432,10 +403,10 @@ class WorkspaceLockManager {
}
ModeShapeLock( String lockOwner,
- UUID lockUuid,
- UUID nodeUuid,
- boolean deep,
- boolean sessionScoped ) {
+ UUID lockUuid,
+ UUID nodeUuid,
+ boolean deep,
+ boolean sessionScoped ) {
super();
this.lockOwner = lockOwner;
this.lockUuid = lockUuid;
@@ -470,18 +441,17 @@ class WorkspaceLockManager {
}
@SuppressWarnings( "synthetic-access" )
- public org.modeshape.jcr.api.Lock lockFor( SessionCache cache ) throws RepositoryException {
+ public Lock lockFor( SessionCache cache ) throws RepositoryException {
final AbstractJcrNode node = cache.findJcrNode(Location.create(nodeUuid));
final JcrSession session = cache.session();
- return new org.modeshape.jcr.api.Lock() {
+ return new Lock() {
public String getLockOwner() {
return lockOwner;
}
public String getLockToken() {
- if (sessionScoped) return null;
String uuidString = lockUuid.toString();
- return session.lockManager().lockTokens().contains(uuidString) ? uuidString : null;
+ return session.lockTokens().contains(uuidString) ? uuidString : null;
}
public Node getNode() {
@@ -501,24 +471,12 @@ class WorkspaceLockManager {
}
public void refresh() throws LockException {
- String uuidString = lockUuid.toString();
- if (!session.lockManager().lockTokens().contains(uuidString)) {
+ if (getLockToken() == null) {
throw new LockException(JcrI18n.notLocked.text(node.location));
}
}
-
- @Override
- public long getSecondsRemaining() throws RepositoryException {
- return isLockOwningSession() ? Integer.MAX_VALUE : Integer.MIN_VALUE;
- }
-
- @Override
- public boolean isLockOwningSession() {
- String uuidString = lockUuid.toString();
- return session.lockManager().lockTokens().contains(uuidString);
- }
-
};
}
+
}
}
Index: modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties
===================================================================
--- modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties (revision 1855)
+++ modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties (working copy)
@@ -190,7 +190,6 @@ alreadyLocked = The node at location '{0}' is already locked
parentAlreadyLocked = The node at location '{0}' cannot be locked because the parent node at location '{1}' is already locked
notLocked = The node at location '{0}' is not locked
lockTokenNotHeld = The node at location '{0}' is locked and this session does not hold its lock token
-invalidLockToken = The lock token '{0}' is not valid
lockTokenAlreadyHeld = The lock token '{0}' is already held by another session. It must be removed from that session before it can be added to another session.
uuidRequiredForLock = Only referenceable nodes can be locked. The node at location '(0}' is not referenceable.
Index: modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrNodeTest.java
===================================================================
--- modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrNodeTest.java (revision 1855)
+++ modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrNodeTest.java (working copy)
@@ -656,15 +656,11 @@ public class AbstractJcrNodeTest extends AbstractJcrTest {
SessionCache cache2 = new SessionCache(jcrSession2, store2.getCurrentWorkspaceName(), context, nodeTypes, store2);
Workspace workspace2 = mock(Workspace.class);
- JcrRepository repository2 = mock(JcrRepository.class);
+ Repository repository2 = mock(Repository.class);
when(jcrSession2.getWorkspace()).thenReturn(workspace2);
when(jcrSession2.getRepository()).thenReturn(repository2);
when(workspace2.getName()).thenReturn("workspace2");
- WorkspaceLockManager lockManager = new WorkspaceLockManager(context, repository2, "workspace2", null);
- JcrLockManager jcrLockManager = new JcrLockManager(jcrSession2, lockManager);
- when(jcrSession2.lockManager()).thenReturn(jcrLockManager);
-
// Use the same id and location; use 'Toyota Prius'
// since the UUID is defined in 'cars.xml' and therefore will be the same
javax.jcr.Node prius2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Toyota Prius"));
@@ -689,15 +685,11 @@ public class AbstractJcrNodeTest extends AbstractJcrTest {
SessionCache cache2 = new SessionCache(jcrSession2, store2.getCurrentWorkspaceName(), context, nodeTypes, store2);
Workspace workspace2 = mock(Workspace.class);
- JcrRepository repository2 = mock(JcrRepository.class);
+ Repository repository2 = mock(Repository.class);
when(jcrSession2.getWorkspace()).thenReturn(workspace2);
when(jcrSession2.getRepository()).thenReturn(repository2);
when(workspace2.getName()).thenReturn("workspace1");
- WorkspaceLockManager lockManager = new WorkspaceLockManager(context, repository2, "workspace2", null);
- JcrLockManager jcrLockManager = new JcrLockManager(jcrSession2, lockManager);
- when(jcrSession2.lockManager()).thenReturn(jcrLockManager);
-
// Use the same id and location; use 'Nissan Altima'
// since the UUIDs will be different (cars.xml doesn't define on this node) ...
javax.jcr.Node altima2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
@@ -726,10 +718,6 @@ public class AbstractJcrNodeTest extends AbstractJcrTest {
when(jcrSession2.getRepository()).thenReturn(repository);
when(workspace2.getName()).thenReturn("workspace1");
- WorkspaceLockManager lockManager = new WorkspaceLockManager(context, repository, "workspace1", null);
- JcrLockManager jcrLockManager = new JcrLockManager(jcrSession2, lockManager);
- when(jcrSession2.lockManager()).thenReturn(jcrLockManager);
-
// Use the same id and location ...
javax.jcr.Node prius2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Toyota Prius"));
prius2.addMixin("mix:referenceable");
Index: modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrPropertyTest.java
===================================================================
--- modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrPropertyTest.java (revision 1855)
+++ modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrPropertyTest.java (working copy)
@@ -172,15 +172,11 @@ public class AbstractJcrPropertyTest extends AbstractJcrTest {
SessionCache cache2 = new SessionCache(jcrSession2, store2.getCurrentWorkspaceName(), context, nodeTypes, store2);
Workspace workspace2 = mock(Workspace.class);
- JcrRepository repository2 = mock(JcrRepository.class);
+ Repository repository2 = mock(Repository.class);
when(jcrSession2.getWorkspace()).thenReturn(workspace2);
when(jcrSession2.getRepository()).thenReturn(repository2);
when(workspace2.getName()).thenReturn("workspace2");
- WorkspaceLockManager lockManager = new WorkspaceLockManager(context, repository2, "workspace2", null);
- JcrLockManager jcrLockManager = new JcrLockManager(jcrSession2, lockManager);
- when(jcrSession2.lockManager()).thenReturn(jcrLockManager);
-
// Use the same id and location; use 'Toyota Prius'
// since the UUID is defined in 'cars.xml' and therefore will be the same
javax.jcr.Node prius2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Toyota Prius"));
@@ -210,15 +206,11 @@ public class AbstractJcrPropertyTest extends AbstractJcrTest {
SessionCache cache2 = new SessionCache(jcrSession2, store2.getCurrentWorkspaceName(), context, nodeTypes, store2);
Workspace workspace2 = mock(Workspace.class);
- JcrRepository repository2 = mock(JcrRepository.class);
+ Repository repository2 = mock(Repository.class);
when(jcrSession2.getWorkspace()).thenReturn(workspace2);
when(jcrSession2.getRepository()).thenReturn(repository2);
when(workspace2.getName()).thenReturn("workspace1");
- WorkspaceLockManager lockManager = new WorkspaceLockManager(context, repository2, "workspace2", null);
- JcrLockManager jcrLockManager = new JcrLockManager(jcrSession2, lockManager);
- when(jcrSession2.lockManager()).thenReturn(jcrLockManager);
-
// Use the same id and location; use 'Nissan Altima'
// since the UUIDs will be different (cars.xml doesn't define on this node) ...
javax.jcr.Node altima2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
@@ -252,10 +244,6 @@ public class AbstractJcrPropertyTest extends AbstractJcrTest {
when(jcrSession2.getRepository()).thenReturn(repository);
when(workspace2.getName()).thenReturn("workspace1");
- WorkspaceLockManager lockManager = new WorkspaceLockManager(context, repository, "workspace2", null);
- JcrLockManager jcrLockManager = new JcrLockManager(jcrSession2, lockManager);
- when(jcrSession2.lockManager()).thenReturn(jcrLockManager);
-
// Use the same id and location ...
javax.jcr.Node prius2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Toyota Prius"));
prius2.addMixin("mix:referenceable");
Index: modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrTest.java
===================================================================
--- modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrTest.java (revision 1855)
+++ modeshape-jcr/src/test/java/org/modeshape/jcr/AbstractJcrTest.java (working copy)
@@ -56,8 +56,6 @@ public abstract class AbstractJcrTest {
protected SessionCache cache;
protected JcrSession jcrSession;
protected JcrNodeTypeManager nodeTypes;
- protected WorkspaceLockManager lockManager;
- protected JcrLockManager jcrLockManager;
protected Workspace workspace;
/**
@@ -119,18 +117,12 @@ public abstract class AbstractJcrTest {
// Stub the session, workspace, and repository; then stub some critical methods ...
jcrSession = mock(JcrSession.class);
workspace = mock(Workspace.class);
- String workspaceName = "workspace1";
when(jcrSession.getExecutionContext()).thenReturn(context);
when(jcrSession.getWorkspace()).thenReturn(workspace);
when(jcrSession.getRepository()).thenReturn(repository);
- when(workspace.getName()).thenReturn(workspaceName);
+ when(workspace.getName()).thenReturn("workspace1");
when(jcrSession.isLive()).thenReturn(true);
- lockManager = new WorkspaceLockManager(context, repository, workspaceName, null);
- jcrLockManager = new JcrLockManager(jcrSession, lockManager);
-
- when(jcrSession.lockManager()).thenReturn(jcrLockManager);
-
// Create the node type manager for the session ...
// no need to stub the 'JcrSession.checkPermission' methods, since we're never calling 'register' on the
// JcrNodeTypeManager
Index: modeshape-jcr/src/test/java/org/modeshape/jcr/JcrTckTest.java
===================================================================
--- modeshape-jcr/src/test/java/org/modeshape/jcr/JcrTckTest.java (revision 1855)
+++ modeshape-jcr/src/test/java/org/modeshape/jcr/JcrTckTest.java (working copy)
@@ -309,12 +309,12 @@ public class JcrTckTest {
// We currently don't pass the tests in those suites that are commented out
// See https://jira.jboss.org/jira/browse/ModeShape-285
- // addTest(new QueryTests());
- // addTest(new ObservationTests()); // remove this and the ObservationTests inner class when all tests pass and
+ addTest(new QueryTests());
+ addTest(new ObservationTests()); // remove this and the ObservationTests inner class when all tests pass and
// uncomment observation.TestAll
// addTest(org.apache.jackrabbit.test.api.observation.TestAll.suite());
- // addTest(org.apache.jackrabbit.test.api.version.TestAll.suite());
+ addTest(org.apache.jackrabbit.test.api.version.TestAll.suite());
addTest(org.apache.jackrabbit.test.api.lock.TestAll.suite());
addTest(org.apache.jackrabbit.test.api.util.TestAll.suite());
// addTest(org.apache.jackrabbit.test.api.query.TestAll.suite());