You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2006/04/28 10:34:07 UTC
svn commit: r397802 - in /jackrabbit/trunk/jackrabbit/src:
main/java/org/apache/jackrabbit/util/Locked.java
test/java/org/apache/jackrabbit/core/LockTest.java
Author: mreutegg
Date: Fri Apr 28 01:34:05 2006
New Revision: 397802
URL: http://svn.apache.org/viewcvs?rev=397802&view=rev
Log:
Improve Locked utility
- run method now provides the lockable Node
- removed instance variables
- changed test cases accodingly
Modified:
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/Locked.java
jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/LockTest.java
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/Locked.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/Locked.java?rev=397802&r1=397801&r2=397802&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/Locked.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/Locked.java Fri Apr 28 01:34:05 2006
@@ -15,16 +15,21 @@
*/
package org.apache.jackrabbit.util;
-import javax.jcr.RepositoryException;
import javax.jcr.Node;
-import javax.jcr.Session;
import javax.jcr.Repository;
-import javax.jcr.observation.ObservationManager;
-import javax.jcr.observation.EventListener;
-import javax.jcr.observation.EventIterator;
-import javax.jcr.observation.Event;
-import javax.jcr.lock.LockException;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.lock.Lock;
+import javax.jcr.lock.LockException;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+import javax.jcr.observation.ObservationManager;
+
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.name.SessionNamespaceResolver;
+import org.apache.jackrabbit.name.NoPrefixDeclaredException;
/**
* <code>Locked</code> is a utility to synchronize modifications on a lockable
@@ -36,12 +41,13 @@
* The following example shows how this utility can be used to implement
* a persistent counter:
* <pre>
- * final Node counter = ...;
+ * Node counter = ...;
* long nextValue = ((Long) new Locked() {
- * protected Object run() throws RepositoryException {
- * long value = counter.getProperty("value").getLong();
- * counter.setProperty("value", ++value);
- * counter.save();
+ * protected Object run(Node counter) throws RepositoryException {
+ * Property seqProp = counter.getProperty("value");
+ * long value = seqProp.getLong();
+ * seqProp.setValue(++value);
+ * seqProp.save();
* return new Long(value);
* }
* }.with(counter, false)).longValue();
@@ -50,12 +56,13 @@
* whether the <code>run</code> method could be executed within the timeout
* period:
* <pre>
- * final Node counter = ...;
+ * Node counter = ...;
* Object ret = new Locked() {
- * protected Object run() throws RepositoryException {
- * long value = counter.getProperty("value").getLong();
- * counter.setProperty("value", ++value);
- * counter.save();
+ * protected Object run(Node counter) throws RepositoryException {
+ * Property seqProp = counter.getProperty("value");
+ * long value = seqProp.getLong();
+ * seqProp.setValue(++value);
+ * seqProp.save();
* return new Long(value);
* }
* }.with(counter, false);
@@ -76,16 +83,6 @@
public static final Object TIMED_OUT = new Object();
/**
- * The lock we hold while executing {@link #run}.
- */
- private Lock lock;
-
- /**
- * An event listener if one was registered
- */
- private EventListener listener;
-
- /**
* Executes {@link #run} while the lock on <code>lockable</code> is held.
* This method will block until {@link #run} is executed while holding the
* lock on node <code>lockable</code>.
@@ -94,6 +91,8 @@
* @param isDeep <code>true</code> if <code>lockable</code> will be locked
* deep.
* @return the object returned by {@link #run}.
+ * @throws IllegalArgumentException if <code>lockable</code> is not
+ * <i>mix:lockable</i>.
* @throws RepositoryException if {@link #run} throws an exception.
* @throws InterruptedException if this thread is interrupted while waiting
* for the lock on node <code>lockable</code>.
@@ -114,19 +113,37 @@
* @return the object returned by {@link #run} or {@link #TIMED_OUT} if the
* lock on <code>lockable</code> could not be aquired within the
* specified timeout.
- * @throws RepositoryException if {@link #run} throws an exception.
- * @throws InterruptedException if this thread is interrupted while waiting
- * for the lock on node <code>lockable</code>.
+ * @throws IllegalArgumentException if <code>timeout</code> is negative or
+ * <code>lockable</code> is not
+ * <i>mix:lockable</i>.
+ * @throws RepositoryException if {@link #run} throws an exception.
+ * @throws UnsupportedRepositoryOperationException
+ * if this repository does not support
+ * locking.
+ * @throws InterruptedException if this thread is interrupted while
+ * waiting for the lock on node
+ * <code>lockable</code>.
*/
public Object with(Node lockable, boolean isDeep, long timeout)
- throws RepositoryException, InterruptedException {
+ throws UnsupportedRepositoryOperationException, RepositoryException, InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout must be >= 0");
}
+
Session session = lockable.getSession();
+ SessionNamespaceResolver resolver = new SessionNamespaceResolver(session);
+
+ Lock lock;
+ EventListener listener = null;
try {
- if (tryLock(lockable, isDeep)) {
- return runAndUnlock();
+ // check whether the lockable can be locked at all
+ if (!lockable.isNodeType(resolver.getJCRName(QName.MIX_LOCKABLE))) {
+ throw new IllegalArgumentException("Node is not lockable");
+ }
+
+ lock = tryLock(lockable, isDeep);
+ if (lock != null) {
+ return runAndUnlock(lock);
}
if (timeout == 0) {
@@ -157,10 +174,11 @@
// now keep trying to aquire the lock
// using 'this' as a monitor allows the event listener to notify
// the current thread when the lockable node is possibly unlocked
- for (;;) {
+ for (; ;) {
synchronized (this) {
- if (tryLock(lockable, isDeep)) {
- return runAndUnlock();
+ lock = tryLock(lockable, isDeep);
+ if (lock != null) {
+ return runAndUnlock(lock);
} else {
// check timeout
if (System.currentTimeMillis() > timelimit) {
@@ -181,6 +199,8 @@
}
}
}
+ } catch (NoPrefixDeclaredException e) {
+ throw new RepositoryException(e);
} finally {
if (listener != null) {
session.getWorkspace().getObservationManager().removeEventListener(listener);
@@ -190,21 +210,24 @@
/**
* This method is executed while holding the lock.
+ * @param node The <code>Node</code> on which the lock is placed.
* @return an object which is then returned by {@link #with with()}.
* @throws RepositoryException if an error occurs.
*/
- protected abstract Object run() throws RepositoryException;
+ protected abstract Object run(Node node) throws RepositoryException;
/**
* Executes {@link #run} and unlocks the lockable node in any case, even
* when an exception is thrown.
*
- * @return the object returned by {@link #run()}.
+ * @param lock The <code>Lock</code> to unlock in any case before returning.
+ *
+ * @return the object returned by {@link #run}.
* @throws RepositoryException if an error occurs.
*/
- private Object runAndUnlock() throws RepositoryException {
+ private Object runAndUnlock(Lock lock) throws RepositoryException {
try {
- return run();
+ return run(lock.getNode());
} finally {
lock.getNode().unlock();
}
@@ -215,18 +238,20 @@
*
* @param lockable the lockable node
* @param isDeep <code>true</code> if the lock should be deep
- * @return <code>true</code> if the lock could be aquired.
+ * @return The <code>Lock</code> or <code>null</code> if the
+ * <code>lockable</code> cannot be locked.
+ * @throws UnsupportedRepositoryOperationException
+ * if this repository does not support locking.
* @throws RepositoryException if an error occurs
*/
- private boolean tryLock(Node lockable, boolean isDeep) throws RepositoryException {
+ private static Lock tryLock(Node lockable, boolean isDeep)
+ throws UnsupportedRepositoryOperationException, RepositoryException {
try {
- lock = lockable.lock(isDeep, true);
- // if we get here we have a lock
- return true;
+ return lockable.lock(isDeep, true);
} catch (LockException e) {
// locked by some other session
}
- return false;
+ return null;
}
/**
@@ -235,7 +260,8 @@
* @param s a session of the repository.
* @return <code>true</code> if the repository supports observation.
*/
- private boolean isObservationSupported(Session s) {
+ private static boolean isObservationSupported(Session s) {
return "true".equalsIgnoreCase(s.getRepository().getDescriptor(Repository.OPTION_OBSERVATION_SUPPORTED));
}
+
}
Modified: jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/LockTest.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/LockTest.java?rev=397802&r1=397801&r2=397802&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/LockTest.java (original)
+++ jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/LockTest.java Fri Apr 28 01:34:05 2006
@@ -21,6 +21,7 @@
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Node;
+import javax.jcr.Property;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
@@ -62,9 +63,9 @@
}
try {
for (int i = 0; i < NUM_CHANGES; i++) {
- final Node n = (Node) s.getItem(lockable.getPath());
+ Node n = (Node) s.getItem(lockable.getPath());
new Locked() {
- protected Object run() throws RepositoryException {
+ protected Object run(Node n) throws RepositoryException {
String nodeName = "node" + threadNumber;
if (n.hasNode(nodeName)) {
n.getNode(nodeName).remove();
@@ -129,12 +130,13 @@
}
try {
for (int i = 0; i < NUM_VALUE_GETS; i++) {
- final Node n = (Node) s.getItem(counter.getPath());
+ Node n = (Node) s.getItem(counter.getPath());
long currentValue = ((Long) new Locked() {
- protected Object run() throws RepositoryException {
- long value = n.getProperty("value").getLong();
- n.setProperty("value", ++value);
- n.save();
+ protected Object run(Node n) throws RepositoryException {
+ Property seqProp = n.getProperty("value");
+ long value = seqProp.getLong();
+ seqProp.setValue(++value);
+ seqProp.save();
return new Long(value);
}
}.with(n, false)).longValue();
@@ -194,12 +196,13 @@
}
try {
for (int i = 0; i < NUM_VALUE_GETS; i++) {
- final Node n = (Node) s.getItem(counter.getPath());
+ Node n = (Node) s.getItem(counter.getPath());
Object ret = new Locked() {
- protected Object run() throws RepositoryException {
- long value = n.getProperty("value").getLong();
- n.setProperty("value", ++value);
- n.save();
+ protected Object run(Node n) throws RepositoryException {
+ Property seqProp = n.getProperty("value");
+ long value = seqProp.getLong();
+ seqProp.setValue(++value);
+ seqProp.save();
return new Long(value);
}
}.with(n, false, 10 * 1000); // expect a value after ten seconds