Index: deploy/jbossas/modeshape-jbossas-service/src/main/java/org/modeshape/jboss/managed/ManagedLock.java
===================================================================
--- deploy/jbossas/modeshape-jbossas-service/src/main/java/org/modeshape/jboss/managed/ManagedLock.java (revision 2107)
+++ deploy/jbossas/modeshape-jbossas-service/src/main/java/org/modeshape/jboss/managed/ManagedLock.java (working copy)
@@ -33,6 +33,7 @@ import org.jboss.managed.api.annotation.ManagementProperty;
import org.jboss.managed.api.annotation.ViewUse;
import org.joda.time.DateTime;
import org.modeshape.common.util.CheckArg;
+import org.modeshape.jcr.JcrLockSnapshot;
/**
* The ManagedSession
class is a JBoss managed object of a ModeShape lock.
@@ -107,7 +108,7 @@ public final class ManagedLock implements ModeShapeManagedObject {
String id,
String owner,
boolean deep ) {
- CheckArg.isNotEmpty(workspaceName, "workspaceName");
+ CheckArg.isNotNull(workspaceName, "workspaceName");
CheckArg.isNotEmpty(sessionId, "sessionId");
CheckArg.isNotNull(expiration, "expiration");
CheckArg.isNotEmpty(id, "id");
@@ -122,6 +123,12 @@ public final class ManagedLock implements ModeShapeManagedObject {
this.workspaceName = workspaceName;
}
+ public ManagedLock(JcrLockSnapshot snapshot) {
+ this(snapshot.getWorkspaceName(), snapshot.isSessionBased(), snapshot.getSessionId(),
+ new DateTime(snapshot.getExpiration().getMillisecondsInUtc()),
+ snapshot.getLockId(), snapshot.getOwner(), snapshot.isDeep());
+ }
+
/**
* Obtains the lock's expiration time. This is a JBoss managed readonly property.
*
Index: deploy/jbossas/modeshape-jbossas-service/src/main/java/org/modeshape/jboss/managed/ManagedRepository.java
===================================================================
--- deploy/jbossas/modeshape-jbossas-service/src/main/java/org/modeshape/jboss/managed/ManagedRepository.java (revision 2107)
+++ deploy/jbossas/modeshape-jbossas-service/src/main/java/org/modeshape/jboss/managed/ManagedRepository.java (working copy)
@@ -30,9 +30,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-
import javax.jcr.Repository;
-
import org.jboss.managed.api.ManagedOperation.Impact;
import org.jboss.managed.api.annotation.ManagementOperation;
import org.jboss.managed.api.annotation.ManagementParameter;
@@ -41,6 +39,7 @@ import org.jboss.managed.api.annotation.ViewUse;
import org.jboss.metatype.api.annotations.MetaMapping;
import org.joda.time.DateTime;
import org.modeshape.common.util.CheckArg;
+import org.modeshape.jcr.JcrLockSnapshot;
import org.modeshape.jcr.JcrRepository;
import org.modeshape.jcr.JcrRepository.Option;
@@ -194,12 +193,11 @@ public class ManagedRepository implements ModeShapeManagedObject {
public List listLocks( Comparator lockSorter ) {
CheckArg.isNotNull(lockSorter, "lockSorter");
- // TODO implement listLocks(Comparator)
- List locks = new ArrayList();
+ List snapshots = repository.getAllLocks();
+ List locks = new ArrayList(snapshots.size());
- // create temporary date
- for (int i = 0; i < 5; ++i) {
- locks.add(new ManagedLock("workspace-" + i, true, "sessionId-1", new DateTime(), "id-" + i, "owner-" + i, true));
+ for (JcrLockSnapshot snapshot : snapshots) {
+ locks.add(new ManagedLock(snapshot));
}
// sort
@@ -249,8 +247,7 @@ public class ManagedRepository implements ModeShapeManagedObject {
*/
@ManagementOperation( description = "Removes the lock with the specified ID", impact = Impact.WriteOnly, params = {@ManagementParameter( name = "lockId", description = "The lock identifier" )} )
public boolean removeLock( String lockId ) {
- // TODO implement removeLockWithLockToken()
- return false;
+ return repository.removeLock(lockId);
}
/**
Index: deploy/jbossas/modeshape-jbossas-service/src/test/java/org/modeshape/jboss/managed/ManagedEngineTest.java
===================================================================
--- deploy/jbossas/modeshape-jbossas-service/src/test/java/org/modeshape/jboss/managed/ManagedEngineTest.java (revision 2107)
+++ deploy/jbossas/modeshape-jbossas-service/src/test/java/org/modeshape/jboss/managed/ManagedEngineTest.java (working copy)
@@ -29,6 +29,10 @@ import static org.junit.Assert.assertThat;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
+import javax.jcr.Node;
+import javax.jcr.Session;
+import javax.jcr.lock.Lock;
+import javax.jcr.lock.LockManager;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -36,6 +40,7 @@ import org.junit.Test;
import org.modeshape.graph.connector.inmemory.InMemoryRepositorySource;
import org.modeshape.jcr.JcrConfiguration;
import org.modeshape.jcr.JcrEngine;
+import org.modeshape.jcr.JcrRepository;
import org.modeshape.jcr.JcrRepository.Option;
/**
@@ -44,6 +49,7 @@ import org.modeshape.jcr.JcrRepository.Option;
public class ManagedEngineTest {
private static Set REPO_NAMES = null;
+ private static String REPO_NAME = "JCR Repository";
private ManagedEngine me;
@@ -53,7 +59,7 @@ public class ManagedEngineTest {
@BeforeClass
public static void beforeAll() throws Exception {
REPO_NAMES = new HashSet();
- REPO_NAMES.add("JCR Repository");
+ REPO_NAMES.add(REPO_NAME);
}
@@ -66,7 +72,7 @@ public class ManagedEngineTest {
.loadedFromClasspath()
.setDescription("description")
.and()
- .repository("JCR Repository")
+.repository(REPO_NAME)
.setSource("Source2")
.setOption(Option.JAAS_LOGIN_CONFIG_NAME, "test")
.and()
@@ -111,4 +117,78 @@ public class ManagedEngineTest {
assertThat(me.getRepositories().size(), is(REPO_NAMES.size()));
}
+
+ @Test
+ public void shouldGetLocks() throws Exception {
+ JcrRepository repo = engine.getRepository(REPO_NAME);
+ ManagedRepository managedRepo = me.getRepository(REPO_NAME);
+
+ assertThat(managedRepo, is(notNullValue()));
+ assertThat(repo, is(notNullValue()));
+
+ assertThat(managedRepo.listLocks().size(), is(0));
+
+ Session session = repo.login();
+ Node rootNode = session.getRootNode();
+
+ final String NODE_NAME = "lockableNode";
+ Node lockableNode = rootNode.addNode(NODE_NAME);
+ lockableNode.addMixin("mix:lockable");
+ session.save();
+
+ LockManager lockManager = session.getWorkspace().getLockManager();
+ lockManager.lock(lockableNode.getPath(), true, false, -1, null);
+
+ assertThat(managedRepo.listLocks().size(), is(1));
+ ManagedLock managedLock = managedRepo.listLocks().get(0);
+ Lock lock = lockManager.getLock(lockableNode.getPath());
+
+ assertThat(session.getWorkspace().getName(), is(managedLock.getWorkspaceName()));
+ assertThat(lock.getLockOwner(), is(managedLock.getOwner()));
+ assertThat(lock.isDeep(), is(managedLock.isDeep()));
+ assertThat(lock.isSessionScoped(), is(managedLock.isSessionBased()));
+ assertThat(session.getUserID(), is(managedLock.getOwner()));
+
+ lockManager.unlock(lockableNode.getPath());
+ assertThat(managedRepo.listLocks().size(), is(0));
+ }
+
+ @Test
+ public void shouldRemoveValidLock() throws Exception {
+ JcrRepository repo = engine.getRepository(REPO_NAME);
+ ManagedRepository managedRepo = me.getRepository(REPO_NAME);
+
+ assertThat(managedRepo, is(notNullValue()));
+ assertThat(repo, is(notNullValue()));
+
+ assertThat(managedRepo.listLocks().size(), is(0));
+
+ Session session = repo.login();
+ Node rootNode = session.getRootNode();
+
+ final String NODE_NAME = "lockableNode";
+ Node lockableNode = rootNode.addNode(NODE_NAME);
+ lockableNode.addMixin("mix:lockable");
+ session.save();
+
+ LockManager lockManager = session.getWorkspace().getLockManager();
+ lockManager.lock(lockableNode.getPath(), true, false, -1, null);
+
+ assertThat(managedRepo.listLocks().size(), is(1));
+ ManagedLock managedLock = managedRepo.listLocks().get(0);
+
+ boolean result = managedRepo.removeLock(managedLock.getId());
+ assertThat(result, is(true));
+
+ assertThat(managedRepo.listLocks().size(), is(0));
+ assertThat(lockManager.isLocked(lockableNode.getPath()), is(false));
+
+ }
+
+ @Test
+ public void shouldNotRemoveInvalidLock() throws Exception {
+ ManagedRepository managedRepo = me.getRepository(REPO_NAME);
+
+ assertThat(managedRepo.removeLock("notAValidLockId"), is(false));
+ }
}
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrLockSnapshot.java
new file mode 100644
===================================================================
--- /dev/null (revision 2107)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrLockSnapshot.java (working copy)
@@ -0,0 +1,91 @@
+package org.modeshape.jcr;
+
+import net.jcip.annotations.Immutable;
+import org.modeshape.graph.property.DateTime;
+
+@Immutable
+public class JcrLockSnapshot {
+
+ /**
+ * The JBoss managed readonly property indicating if this lock is a deep lock.
+ */
+ private final boolean deep;
+
+ /**
+ * The JBoss managed readonly property for the lock's expiration time. The expiration time is never null
.
+ */
+ private final DateTime expiration;
+
+ /**
+ * The JBoss managed readonly property for the lock's identifier. The ID is never null
and never empty.
+ */
+ private final String lockId;
+
+ /**
+ * The JBoss managed readonly property for the lock's session identifier. The session ID is never null
and never
+ * empty.
+ */
+ private final String sessionId;
+
+ /**
+ * The JBoss managed readonly property for the lock's owner. The owner is never null
and never empty.
+ */
+ private final String owner;
+
+ /**
+ * The JBoss managed readonly property indicating if this lock is a session-based lock.
+ */
+ private final boolean sessionBased;
+
+ /**
+ * The JBoss managed readonly property for the lock's workspace name. The workspace name is never null
and never
+ * empty.
+ */
+ private final String workspaceName;
+
+ public JcrLockSnapshot( boolean deep,
+ DateTime expiration,
+ String id,
+ String sessionId,
+ String owner,
+ boolean sessionBased,
+ String workspaceName ) {
+ super();
+ this.deep = deep;
+ this.expiration = expiration;
+ this.lockId = id;
+ this.sessionId = sessionId;
+ this.owner = owner;
+ this.sessionBased = sessionBased;
+ this.workspaceName = workspaceName;
+ }
+
+ public boolean isDeep() {
+ return deep;
+ }
+
+ public DateTime getExpiration() {
+ return expiration;
+ }
+
+ public String getLockId() {
+ return lockId;
+ }
+
+ public String getSessionId() {
+ return sessionId;
+ }
+
+ public String getOwner() {
+ return owner;
+ }
+
+ public boolean isSessionBased() {
+ return sessionBased;
+ }
+
+ public String getWorkspaceName() {
+ return workspaceName;
+ }
+
+}
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrRepository.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrRepository.java (revision 2107)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrRepository.java (working copy)
@@ -907,6 +907,17 @@ public class JcrRepository implements Repository {
}
/**
+ * @return snapshots of each of the currently active locks
+ */
+ public List getAllLocks() {
+ return repositoryLockManager.allLocks();
+ }
+
+ public boolean removeLock( String lockId ) {
+ return repositoryLockManager.removeLock(lockId);
+ }
+
+ /**
* Get the options as configured for this repository.
*
* @return the unmodifiable options; never null
Index: modeshape-jcr/src/main/java/org/modeshape/jcr/RepositoryLockManager.java
===================================================================
--- modeshape-jcr/src/main/java/org/modeshape/jcr/RepositoryLockManager.java (revision 2107)
+++ modeshape-jcr/src/main/java/org/modeshape/jcr/RepositoryLockManager.java (working copy)
@@ -1,6 +1,8 @@
package org.modeshape.jcr;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@@ -15,6 +17,7 @@ import org.modeshape.graph.Subgraph;
import org.modeshape.graph.observe.Changes;
import org.modeshape.graph.property.DateTime;
import org.modeshape.graph.property.DateTimeFactory;
+import org.modeshape.graph.property.NameFactory;
import org.modeshape.graph.property.Path;
import org.modeshape.graph.property.PathFactory;
import org.modeshape.graph.property.PathNotFoundException;
@@ -23,6 +26,7 @@ import org.modeshape.graph.property.ValueFactory;
import org.modeshape.graph.property.Path.Segment;
import org.modeshape.graph.request.ChangeRequest;
import org.modeshape.graph.request.CreateNodeRequest;
+import org.modeshape.jcr.WorkspaceLockManager.ModeShapeLock;
@ThreadSafe
class RepositoryLockManager implements JcrSystemObserver {
@@ -142,6 +146,72 @@ class RepositoryLockManager implements JcrSystemObserver {
}
}
+ List allLocks() {
+ Graph systemGraph = repository.createSystemGraph(repository.getExecutionContext());
+ Subgraph locksGraph = systemGraph.getSubgraphOfDepth(2).at(locksPath);
+
+ Node parentNode = locksGraph.getRoot();
+ List snapshots = new ArrayList(parentNode.getChildrenSegments().size());
+
+ for (Location lockLocation : parentNode.getChildren()) {
+ Node lockNode = locksGraph.getNode(lockLocation);
+
+ boolean deep = firstBoolean(lockNode.getProperty(JcrLexicon.LOCK_IS_DEEP));
+ boolean sessionScoped = firstBoolean(lockNode.getProperty(ModeShapeLexicon.IS_SESSION_SCOPED));
+ String owner = firstString(lockNode.getProperty(JcrLexicon.LOCK_OWNER));
+ String workspaceName = firstString(lockNode.getProperty(ModeShapeLexicon.WORKSPACE));
+ String lockId = lockLocation.getPath().getLastSegment().getName().getLocalName();
+ String sessionId = firstString(lockNode.getProperty(ModeShapeLexicon.LOCKING_SESSION));
+ DateTime expiration = firstDate(lockNode.getProperty(ModeShapeLexicon.EXPIRATION_DATE));
+
+ JcrLockSnapshot snapshot = new JcrLockSnapshot(deep, expiration, lockId, sessionId, owner, sessionScoped,
+ workspaceName);
+ snapshots.add(snapshot);
+ }
+
+ return snapshots;
+ }
+
+ boolean removeLock( String lockId ) {
+ UUID lockUuid = null;
+ try {
+ lockUuid = UUID.fromString(lockId);
+ } catch (IllegalArgumentException iae) {
+ return false;
+ }
+
+ ExecutionContext context = repository.getExecutionContext();
+ Graph systemGraph = repository.createSystemGraph(context);
+
+ PathFactory pathFactory = context.getValueFactories().getPathFactory();
+ NameFactory nameFactory = context.getValueFactories().getNameFactory();
+
+ Path lockPath = pathFactory.create(locksPath, nameFactory.create(lockUuid.toString()));
+
+ try {
+ Node lockNode = systemGraph.getNodeAt(lockPath);
+
+ String workspaceName = firstString(lockNode.getProperty(ModeShapeLexicon.WORKSPACE));
+ String rawLockedNodeUuid = firstString(lockNode.getProperty(ModeShapeLexicon.LOCKED_UUID));
+
+ UUID nodeUuid = UUID.fromString(rawLockedNodeUuid);
+
+ WorkspaceLockManager lockManager = lockManagers.get(workspaceName);
+ assert lockManager != null;
+
+ ModeShapeLock lock = lockManager.lockFor(nodeUuid);
+
+ // It's possible that the lock was unlocked between when the graph node was read and now
+ if (lock == null) return false;
+
+ lockManager.unlock(context, lock);
+
+ return true;
+ } catch (PathNotFoundException pnfe) {
+ return false;
+ }
+ }
+
/**
* {@inheritDoc}
*
@@ -238,6 +308,14 @@ class RepositoryLockManager implements JcrSystemObserver {
return context.getValueFactories().getStringFactory().create(firstValue);
}
+ private final DateTime firstDate( Property property ) {
+ if (property == null) return null;
+ Object firstValue = property.getFirstValue();
+
+ ExecutionContext context = repository.getExecutionContext();
+ return context.getValueFactories().getDateFactory().create(firstValue);
+ }
+
private final UUID firstUuid( Property property ) {
if (property == null) return null;
Object firstValue = property.getFirstValue();