You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by oz...@apache.org on 2007/08/17 01:13:13 UTC

svn commit: r566884 - in /commons/proper/transaction/branches/TRANSACTION_2: src/java/org/apache/commons/transaction/ src/java/org/apache/commons/transaction/file/ src/java/org/apache/commons/transaction/locking/ src/java/org/apache/commons/transaction...

Author: ozeigermann
Date: Thu Aug 16 16:13:11 2007
New Revision: 566884

URL: http://svn.apache.org/viewvc?view=rev&rev=566884
Log:
Readded RWLockManager based on custom ReadWriteLock implementation. 

All tests pass.

Added:
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/AbstractLockManager.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/RWLockManager.java
Modified:
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/AbstractTransactionalResourceManager.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceManager.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceUndoManager.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileSequence.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/TxFileResourceManager.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/DefaultHierarchicalLockManager.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/DefaultLockManager.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockManager.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/locks/ResourceRWLock.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/package.html
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/BasicTxMap.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/OptimisticTxMap.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/PessimisticTxMap.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/resource/ResourceException.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/resource/ResourceManager.java
    commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/resource/StreamableResource.java
    commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/TxFileResourceManagerTest.java
    commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/memory/PessimisticTxMapTest.java
    commons/proper/transaction/branches/TRANSACTION_2/xdocs/index.xml

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/AbstractTransactionalResourceManager.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/AbstractTransactionalResourceManager.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/AbstractTransactionalResourceManager.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/AbstractTransactionalResourceManager.java Thu Aug 16 16:13:11 2007
@@ -31,7 +31,8 @@
  * implement {@link #createContext()} to create an object of that type, and
  * {@link #commitCanFail()}.
  * 
- * @param <T>
+ * <p>
+ * This implementation is <em>thread-safe</em>.
  */
 public abstract class AbstractTransactionalResourceManager<T extends AbstractTransactionalResourceManager.AbstractTxContext>
         implements ManageableResourceManager {
@@ -42,9 +43,6 @@
     private String name;
 
     protected abstract T createContext();
-
-    public AbstractTransactionalResourceManager() {
-    }
 
     public AbstractTransactionalResourceManager(String name) {
         this.name = name;

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceManager.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceManager.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceManager.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceManager.java Thu Aug 16 16:13:11 2007
@@ -33,6 +33,14 @@
 import org.apache.commons.transaction.resource.StreamableResource;
 import org.apache.commons.transaction.util.FileHelper;
 
+/**
+ * Default file system implementation of a {@link ResourceManager resource manager}.
+ * 
+ * <p>
+ * This implementation is <b>NOT</b> <em>thread-safe</em>. Use
+ * {@link TxFileResourceManager} if you require a <em>thread-safe</em>
+ * implementation.
+ */
 public class FileResourceManager implements ResourceManager<FileResourceManager.FileResource> {
 
     private Log logger = LogFactory.getLog(getClass());
@@ -62,7 +70,7 @@
         private final File file;
 
         private final String canonicalPath;
-        
+
         private final String name;
 
         protected static File getFileForResource(StreamableResource resource)
@@ -124,7 +132,7 @@
             return file.exists();
         }
 
-        public List<? extends FileResource>  getChildren() throws ResourceException {
+        public List<? extends FileResource> getChildren() throws ResourceException {
             List<FileResource> result = new ArrayList<FileResource>();
             File[] files = file.listFiles();
             for (File file : files) {
@@ -140,7 +148,8 @@
              * if (getPath().equals(getRootPath())) return null;
              */
             File parent = file.getParentFile();
-            if (parent == null) return null;
+            if (parent == null)
+                return null;
             return create(parent);
         }
 
@@ -268,7 +277,7 @@
         protected FileResource create(File file) throws ResourceException {
             return new FileResource(file);
         }
-        
+
         public FileResource getChild(String name) throws ResourceException {
             File child = new File(file, name);
             return create(child);

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceUndoManager.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceUndoManager.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceUndoManager.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileResourceUndoManager.java Thu Aug 16 16:13:11 2007
@@ -4,20 +4,20 @@
 
 public interface FileResourceUndoManager {
 
-    public enum Code {
+    enum Code {
         DELETED_DIRECTORY, UPDATED_CONTENT, CREATED
     }
     
-    public void startRecord();
+    void startRecord();
 
-    public void undoRecord();
+    void undoRecord();
 
-    public void forgetRecord();
+    void forgetRecord();
 
-    public void recordCreate(File file);
+    void recordCreate(File file);
 
-    public void recordDelete(File file);
+    void recordDelete(File file);
 
-    public void recordUpdate(File file);
+    void recordUpdate(File file);
 
 }

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileSequence.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileSequence.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileSequence.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/FileSequence.java Thu Aug 16 16:13:11 2007
@@ -38,7 +38,6 @@
  * versioning values of sequences and throwing away all versions, but the
  * current and the previous one.
  * 
- * @version $Id: FileSequence.java 493628 2007-01-07 01:42:48Z joerg $
  */
 public class FileSequence {
 
@@ -47,7 +46,7 @@
     protected final String storeDir;
 
     /**
-     * Creates a new resouce manager operation on the specified directories.
+     * Creates a new resource manager operation on the specified directories.
      * 
      * @param storeDir
      *            directory where sequence information is stored

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/MemoryUndoManager.java Thu Aug 16 16:13:11 2007
@@ -10,7 +10,16 @@
 import org.apache.commons.logging.LogFactory;
 import org.apache.commons.transaction.util.FileHelper;
 
-// TODO: memory version to be serialized to XML using JAXB
+/**
+ * Default implementation of {@link FileResourceUndoManager}.
+ * 
+ * <p>Undo information is held in memory only. Changed content streams are stored as temporary files.
+ * 
+ * <p><em>Caution:</em>This implementation does not guarantee ACID properties after a JVM crash.
+ *
+ * <p>
+ * This implementation is <em>thread-safe</em>.
+ */
 public class MemoryUndoManager implements FileResourceUndoManager {
 
     private Log logger = LogFactory.getLog(getClass());

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/TxFileResourceManager.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/TxFileResourceManager.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/TxFileResourceManager.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/file/TxFileResourceManager.java Thu Aug 16 16:13:11 2007
@@ -36,11 +36,38 @@
 import org.apache.commons.transaction.locking.HierarchicalLockManager;
 import org.apache.commons.transaction.locking.DefaultHierarchicalLockManager;
 import org.apache.commons.transaction.locking.LockManager;
+import org.apache.commons.transaction.locking.RWLockManager;
 import org.apache.commons.transaction.resource.ResourceException;
 import org.apache.commons.transaction.resource.ResourceManager;
 import org.apache.commons.transaction.resource.StreamableResource;
 import org.apache.commons.transaction.util.FileHelper;
 
+/**
+ * Transactional file system implementation of a
+ * {@link ResourceManager resource manager}.
+ * 
+ * <p>
+ * All meaningful actions that ensure ACID transactions are delegated to special
+ * components. This allows for customization of all kinds:
+ * <ul>
+ * <li>{@link #setLm(LockManager)}: Sets the {@link LockManager lock manager}
+ * that decides how to protect resources from concurrent modifications. Defaults
+ * to {@link DefaultLockManager}.
+ * <li>{@link #setUndoManager(FileResourceUndoManager)}: Sets the
+ * {@link FileResourceUndoManager undo manager} that keeps track of all changes
+ * and allows to undo them upon request.Defaults
+ * to {@link MemoryUndoManager}.
+ * </ul>
+ * 
+ * 
+ * <p>
+ * This implementation is <em>thread-safe</em>.
+ * 
+ * @see FileResourceUndoManager
+ * @see ResourceManager
+ * @see HierarchicalLockManager
+ * @see LockManager
+ */
 public class TxFileResourceManager extends
         AbstractTransactionalResourceManager<TxFileResourceManager.FileTxContext> implements
         ManageableResourceManager, ResourceManager<StreamableResource> {
@@ -56,7 +83,37 @@
     public TxFileResourceManager(String name, String rootPath) {
         super(name);
         wrapped = new FileResourceManager(rootPath);
-        setLm(new DefaultLockManager<Object, Object>());
+        setLm(new RWLockManager<Object, Object>());
+    }
+
+    @Override
+    public void setLm(LockManager<Object, Object> lm) {
+        super.setLm(lm);
+        hlm = new DefaultHierarchicalLockManager(getRootPath(), lm);
+    }
+
+    @Override
+    public boolean commitCanFail() {
+        return false;
+    }
+
+    @Override
+    public FileResource getResource(String path) throws ResourceException {
+        FileTxContext context = getActiveTx();
+        if (context != null) {
+            return context.getResource(path);
+        } else {
+            return wrapped.getResource(path);
+        }
+
+    }
+
+    public String getRootPath() {
+        return wrapped.getRootPath();
+    }
+
+    public void setUndoManager(FileResourceUndoManager undoManager) {
+        this.undoManager = undoManager;
     }
 
     @Override
@@ -68,10 +125,8 @@
         return hlm;
     }
 
-    @Override
-    public void setLm(LockManager<Object, Object> lm) {
-        super.setLm(lm);
-        hlm = new DefaultHierarchicalLockManager(getRootPath(), lm);
+    protected FileResourceUndoManager getUndoManager() {
+        return undoManager;
     }
 
     public class FileTxContext extends AbstractTxContext implements
@@ -104,7 +159,7 @@
             getUndoManager().startRecord();
             super.start(timeout, unit);
         }
-        
+
         @Override
         public String getRootPath() {
             return TxFileResourceManager.this.getRootPath();
@@ -344,33 +399,6 @@
                 super.writeLock();
             }
         }
-    }
-
-    @Override
-    public boolean commitCanFail() {
-        return false;
-    }
-
-    public FileResource getResource(String path) throws ResourceException {
-        FileTxContext context = getActiveTx();
-        if (context != null) {
-            return context.getResource(path);
-        } else {
-            return wrapped.getResource(path);
-        }
-
-    }
-
-    public String getRootPath() {
-        return wrapped.getRootPath();
-    }
-
-    protected FileResourceUndoManager getUndoManager() {
-        return undoManager;
-    }
-
-    public void setUndoManager(FileResourceUndoManager undoManager) {
-        this.undoManager = undoManager;
     }
 
 }

Added: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/AbstractLockManager.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/AbstractLockManager.java?view=auto&rev=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/AbstractLockManager.java (added)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/AbstractLockManager.java Thu Aug 16 16:13:11 2007
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.transaction.locking;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.transaction.locking.LockException.Code;
+
+/**
+ * Abstract implementation of {@link LockManager}.
+ * 
+ * <p>
+ * This implementation is <em>thread-safe</em>.
+ */
+public abstract class AbstractLockManager<K, M> implements LockManager<K, M> {
+    private Log logger = LogFactory.getLog(getClass());
+
+    protected Map<Thread, Set<Lock>> locksForThreads = new ConcurrentHashMap<Thread, Set<Lock>>();
+
+    protected Map<Thread, Long> effectiveGlobalTimeouts = new ConcurrentHashMap<Thread, Long>();
+
+    @Override
+    public void endWork() {
+        release();
+    }
+
+    @Override
+    public void startWork(long timeout, TimeUnit unit) {
+        if (isWorking()) {
+            throw new IllegalStateException("work has already been started");
+        }
+        locksForThreads.put(Thread.currentThread(), new HashSet<Lock>());
+
+        long timeoutMSecs = unit.toMillis(timeout);
+        long now = System.currentTimeMillis();
+        long effectiveTimeout = now + timeoutMSecs;
+        effectiveGlobalTimeouts.put(Thread.currentThread(), effectiveTimeout);
+    }
+
+    protected long computeRemainingTime(Thread thread) {
+        long timeout = effectiveGlobalTimeouts.get(thread);
+        long now = System.currentTimeMillis();
+        long remaining = timeout - now;
+        return remaining;
+    }
+
+    public boolean isWorking() {
+        return locksForThreads.get(Thread.currentThread()) != null;
+    }
+
+    @Override
+    public void lock(M managedResource, K key, boolean exclusive) throws LockException {
+        long remainingTime = computeRemainingTime(Thread.currentThread());
+
+        boolean locked = tryLockInternal(managedResource, key, exclusive, remainingTime,
+                TimeUnit.MILLISECONDS);
+        if (!locked) {
+            throw new LockException(Code.TIMED_OUT, key);
+        }
+    }
+
+    @Override
+    public boolean tryLock(M managedResource, K key, boolean exclusive) {
+        return tryLockInternal(managedResource, key, exclusive, 0, TimeUnit.MILLISECONDS);
+    }
+
+    abstract protected boolean tryLockInternal(M managedResource, K key, boolean exclusive,
+            long time, TimeUnit unit) throws LockException;
+
+    protected void reportTimeout(Thread thread) throws LockException {
+        if (hasTimedOut(thread)) {
+            throw new LockException(LockException.Code.TIMED_OUT);
+        }
+    }
+
+    protected boolean hasTimedOut(Thread thread) {
+        long remainingTime = computeRemainingTime(thread);
+        return (remainingTime < 0);
+
+    }
+
+    protected void release() {
+        Set<Lock> locks = locksForThreads.get(Thread.currentThread());
+        // graceful reaction...
+        if (locks == null) {
+            return;
+        }
+        for (Lock lock : locks) {
+            lock.unlock();
+        }
+
+        locksForThreads.remove(Thread.currentThread());
+    }
+
+    protected static class KeyEntry<K, M> {
+
+        private K k;
+
+        private M m;
+
+        public KeyEntry(K k, M m) {
+            this.k = k;
+            this.m = m;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj instanceof KeyEntry) {
+                KeyEntry otherEntry = (KeyEntry) obj;
+                return (otherEntry.k.equals(k) && otherEntry.m.equals(m));
+            }
+            return false;
+        }
+
+        public int hashCode() {
+            return k.hashCode() + m.hashCode();
+        }
+        
+        public String toString() {
+            return m.toString() + ":" + k.toString();
+        }
+    }
+
+}

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/DefaultHierarchicalLockManager.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/DefaultHierarchicalLockManager.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/DefaultHierarchicalLockManager.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/DefaultHierarchicalLockManager.java Thu Aug 16 16:13:11 2007
@@ -18,6 +18,23 @@
 
 import java.util.concurrent.TimeUnit;
 
+/**
+ * Default implementation of the {@link HierarchicalLockManager}.
+ * 
+ * <p>
+ * It splits the path into segments and non-exclusively locks each segment
+ * beginning from the root. The final segment - which is supposed to be the
+ * resource to be locked itself - can either be locked exclusively or
+ * non-exclusively. Too choose between the two, provide the flag in
+ * {@link #lockInHierarchy(Object, String, boolean)}.
+ * 
+ * <p>
+ * This implementation needs an ordinary {@link LockManager lock manager} that
+ * it delegates all locking calls to.
+ * 
+ * <p>
+ * This implementation is <em>thread-safe</em>.
+ */
 public class DefaultHierarchicalLockManager<M> implements HierarchicalLockManager<Object, M> {
 
     private final String rootPath;

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/DefaultLockManager.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/DefaultLockManager.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/DefaultLockManager.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/DefaultLockManager.java Thu Aug 16 16:13:11 2007
@@ -16,11 +16,11 @@
  */
 package org.apache.commons.transaction.locking;
 
-import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantLock;
 
 import org.apache.commons.logging.Log;
@@ -28,103 +28,27 @@
 import org.apache.commons.transaction.locking.LockException.Code;
 
 /**
+ * Default implementation of {@link LockManager}.
  * 
- * @author olli
+ * <p>
+ * This is a minimal implementation that only knows a single type of lock.
+ * Read-/Write-locks are not supported. Deadlock detection is not performed.
+ * Transferring locks between threads is not possible. These limitations are due
+ * to the standard {@link Lock} and {@link ReadWriteLock} implementations.
  * 
- * @param <K>
- * @param <M>
+ * <p>
+ * This implementation is <em>thread-safe</em>.
  */
-public class DefaultLockManager<K, M> implements LockManager<K, M> {
+public class DefaultLockManager<K, M> extends AbstractLockManager<K, M> implements
+        LockManager<K, M> {
     private Log logger = LogFactory.getLog(getClass());
 
     protected ConcurrentHashMap<KeyEntry<K, M>, ReentrantLock> locks = new ConcurrentHashMap<KeyEntry<K, M>, ReentrantLock>();
 
-    protected Map<Thread, CopyOnWriteArraySet<ReentrantLock>> locksForThreads = new ConcurrentHashMap<Thread, CopyOnWriteArraySet<ReentrantLock>>();
-
-    protected Map<Thread, Long> effectiveGlobalTimeouts = new ConcurrentHashMap<Thread, Long>();
-
-    @Override
-    public void endWork() {
-        release();
-    }
-
-    @Override
-    public void startWork(long timeout, TimeUnit unit) {
-        if (isWorking()) {
-            throw new IllegalStateException("work has already been started");
-        }
-        locksForThreads.put(Thread.currentThread(), new CopyOnWriteArraySet<ReentrantLock>());
-
-        long timeoutMSecs = unit.toMillis(timeout);
-        long now = System.currentTimeMillis();
-        long effectiveTimeout = now + timeoutMSecs;
-        effectiveGlobalTimeouts.put(Thread.currentThread(), effectiveTimeout);
-    }
-
-    // TODO
-    protected boolean checkForDeadlock() {
-        return false;
-
-    }
-
-    protected long computeRemainingTime(Thread thread) {
-        long timeout = effectiveGlobalTimeouts.get(thread);
-        long now = System.currentTimeMillis();
-        long remaining = timeout - now;
-        return remaining;
-    }
-
     protected ReentrantLock create() {
         return new ReentrantLock();
     }
 
-    protected static class KeyEntry<K, M> {
-
-        private K k;
-
-        private M m;
-
-        public KeyEntry(K k, M m) {
-            this.k = k;
-            this.m = m;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj)
-                return true;
-            if (obj instanceof KeyEntry) {
-                KeyEntry otherEntry = (KeyEntry) obj;
-                return (otherEntry.k.equals(k) && otherEntry.m.equals(m));
-            }
-            return false;
-        }
-
-        public int hashCode() {
-            return k.hashCode() + m.hashCode();
-        }
-    }
-
-    public boolean isWorking() {
-        return locksForThreads.get(Thread.currentThread()) != null;
-    }
-
-    @Override
-    public void lock(M managedResource, K key, boolean exclusive) throws LockException {
-        long remainingTime = computeRemainingTime(Thread.currentThread());
-
-        boolean locked = tryLockInternal(managedResource, key, exclusive, remainingTime,
-                TimeUnit.MILLISECONDS);
-        if (!locked) {
-            throw new LockException(Code.TIMED_OUT, key);
-        }
-    }
-
-    @Override
-    public boolean tryLock(M managedResource, K key, boolean exclusive) {
-        return tryLockInternal(managedResource, key, exclusive, 0, TimeUnit.MILLISECONDS);
-    }
-
     protected boolean tryLockInternal(M managedResource, K key, boolean exclusive, long time,
             TimeUnit unit) throws LockException {
         reportTimeout(Thread.currentThread());
@@ -135,7 +59,7 @@
         ReentrantLock existingLock = locks.putIfAbsent(entry, lock);
         if (existingLock != null)
             lock = existingLock;
-        Set<ReentrantLock> locks = locksForThreads.get(Thread.currentThread());
+        Set<Lock> locks = locksForThreads.get(Thread.currentThread());
         if (locks == null) {
             throw new IllegalStateException("lock() can only be called after startWork()");
         }
@@ -170,23 +94,16 @@
     }
 
     protected void release() {
-        Set<ReentrantLock> locks = locksForThreads.get(Thread.currentThread());
+        Set<Lock> locks = locksForThreads.get(Thread.currentThread());
         // graceful reaction...
         if (locks == null) {
             return;
         }
-        for (ReentrantLock lock : locks) {
-            int holdCount = lock.getHoldCount();
+        for (Lock lock : locks) {
+            int holdCount = ((ReentrantLock) lock).getHoldCount();
             logger.debug("Locks held by this thread: " + holdCount);
-            while (true) {
-                try {
-                    lock.unlock();
-                } catch (IllegalMonitorStateException imse) {
-                    // We are lacking information on whether we have a read
-                    // lock and if so how many.
-                    // XXX Just free as many as possible.
-                    break;
-                }
+            for (int i = 0; i < holdCount; i++) {
+                lock.unlock();
             }
         }
 

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockManager.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockManager.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockManager.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockManager.java Thu Aug 16 16:13:11 2007
@@ -17,6 +17,7 @@
 package org.apache.commons.transaction.locking;
 
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
 
 /**
  * 
@@ -26,6 +27,9 @@
  * {@link #lock(Object, Object, boolean)} and
  * {@link #tryLock(Object, Object, boolean)}.
  * 
+ * <p>
+ * You can plug in your own lock manager version most easily. However, for
+ * advanced features this will most likely require a custom implementation of {@link Lock} as well.
  * 
  * 
  * @param <K>
@@ -40,7 +44,7 @@
      * @param unit
      *            the time unit of the {@code timeout} argument
      */
-    public void startWork(long timeout, TimeUnit unit);
+    void startWork(long timeout, TimeUnit unit);
 
     /**
      * Ends a block of work that has been started in
@@ -48,14 +52,14 @@
      * All registered locks will be unregistered from this lock manager.
      * 
      */
-    public void endWork();
+    void endWork();
 
     /**
      * @param managedResource
      *            resource for on which this block of work shall be done
      */
-    public void lock(M managedResource, K key, boolean exclusive) throws LockException;
+    void lock(M managedResource, K key, boolean exclusive) throws LockException;
 
-    public boolean tryLock(M managedResource, K key, boolean exclusive);
+    boolean tryLock(M managedResource, K key, boolean exclusive);
 
 }

Added: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/RWLockManager.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/RWLockManager.java?view=auto&rev=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/RWLockManager.java (added)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/RWLockManager.java Thu Aug 16 16:13:11 2007
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.transaction.locking;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+
+import org.apache.commons.transaction.locking.LockException.Code;
+import org.apache.commons.transaction.locking.locks.ResourceRWLock;
+
+public class RWLockManager<K, M> extends AbstractLockManager<K, M> implements LockManager<K, M> {
+
+    protected ConcurrentHashMap<KeyEntry<K, M>, ResourceRWLock> locks = new ConcurrentHashMap<KeyEntry<K, M>, ResourceRWLock>();
+
+    protected ResourceRWLock create(String name) {
+        return new ResourceRWLock(name);
+    }
+
+    protected boolean tryLockInternal(M managedResource, K key, boolean exclusive, long time,
+            TimeUnit unit) throws LockException {
+        reportTimeout(Thread.currentThread());
+
+        KeyEntry<K, M> entry = new KeyEntry<K, M>(key, managedResource);
+
+        String resourceName = entry.toString();
+
+        ResourceRWLock rwlock = create(resourceName);
+        ResourceRWLock existingLock = locks.putIfAbsent(entry, rwlock);
+        if (existingLock != null)
+            rwlock = existingLock;
+        Set<Lock> locksForThisThread = locksForThreads.get(Thread.currentThread());
+        if (locksForThisThread == null) {
+            throw new IllegalStateException("lock() can only be called after startWork()");
+        }
+
+        Lock lock = exclusive ? rwlock.writeLock() : rwlock.readLock();
+
+        boolean locked;
+        if (time == 0) {
+            locked = lock.tryLock();
+        } else {
+            rwlock.registerWaiter();
+            try {
+                locked = doTrickyYetEfficientLockOnlyIfThisCanNotCauseADeadlock(lock, unit
+                        .toMillis(time));
+            } finally {
+                rwlock.unregisterWaiter();
+            }
+        }
+        if (locked)
+            locksForThisThread.add(lock);
+
+        return locked;
+    }
+
+    protected boolean doTrickyYetEfficientLockOnlyIfThisCanNotCauseADeadlock(Lock lock,
+            long timeMsecs) throws LockException {
+
+        // This algorithm is devided into three parts:
+        // Note: We can be interrupted most of the time
+        //
+        // (I) prewait:
+        // Wait a fraktion of the time to see if we can acquire
+        // the lock in short time. If we can all is good and we exit
+        // signalling success. If not we need to get into a more resource
+        // consuming phase.
+        //
+        // (II) clearing of timed out threads / deadlock detection:
+        // As we have not been able to acquire the lock, yet, maybe there is
+        // deadlock. Clear all threads already timed out and afterwards
+        // check for a deadlock state. If there is one report it with an
+        // exception. If not we enter the final phase.
+        // 
+        // (III) real wait:
+        // Everything is under control, we were just a little bit too
+        // impatient. So wait for the remaining time and see if the can get
+        // the lock
+        // 
+
+        try {
+            boolean locked;
+
+            // (I) prewait
+
+            long startTime = System.currentTimeMillis();
+
+            // TODO this heuristic divisor really should be configurable
+            long preWaitTime = timeMsecs / 10;
+            locked = lock.tryLock(preWaitTime, TimeUnit.MILLISECONDS);
+            if (locked)
+                return true;
+
+            // (II) deadlock detect
+            cancelAllTimedOut();
+            if (wouldDeadlock(Thread.currentThread(), new HashSet<Thread>())) {
+                throw new LockException(LockException.Code.WOULD_DEADLOCK);
+            }
+
+            // (III) real wait
+            long now = System.currentTimeMillis();
+            long remainingWaitTime = timeMsecs - (now - startTime);
+            if (remainingWaitTime < 0)
+                return false;
+
+            locked = lock.tryLock(remainingWaitTime, TimeUnit.MILLISECONDS);
+            return locked;
+        } catch (InterruptedException e) {
+            throw new LockException(Code.INTERRUPTED);
+        }
+
+    }
+
+    protected boolean wouldDeadlock(Thread thread, Set<Thread> path) {
+        path.add(thread);
+        // these are our locks
+        // Note: No need to make a copy as we can be sure to iterate on our
+        // private
+        // version, as this is a CopyOnWriteArraySet!
+        Set<Lock> locks = locksForThreads.get(thread);
+        // check is necessary as the possibly offending thread might have ended
+        // before this check completes
+        if (locks != null) {
+            for (Lock lock : locks) {
+                // these are the ones waiting for one of our locks
+                // and if they wait, they wait because of me!
+                Collection<Thread> conflicts = ((ResourceRWLock.InnerLock) lock)
+                        .getResourceRWLock().getQueuedThreads();
+                for (Thread conflictThread : conflicts) {
+                    // this means, we have found a cycle in the wait graph
+                    if (path.contains(conflictThread)) {
+                        return true;
+                    } else if (wouldDeadlock(conflictThread, path)) {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        path.remove(thread);
+        return false;
+    }
+
+    protected void cancelAllTimedOut() {
+        Set<Thread> threads = effectiveGlobalTimeouts.keySet();
+        for (Thread thread : threads) {
+            if (hasTimedOut(thread)) {
+                // TODO #1: We need to record this thread has timed out to
+                // produce
+                // a meaningful exception when it tries to continue its work
+                // TODO #2: If would be even better if we could actively release
+                // its locks, but only the thread that acquired a lock can
+                // release it. An extended implementation of ReentrantLock would
+                // help.
+                thread.interrupt();
+            }
+
+        }
+    }
+
+}

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/locks/ResourceRWLock.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/locks/ResourceRWLock.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/locks/ResourceRWLock.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/locks/ResourceRWLock.java Thu Aug 16 16:13:11 2007
@@ -16,7 +16,9 @@
  */
 package org.apache.commons.transaction.locking.locks;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.concurrent.ConcurrentSkipListSet;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.AbstractQueuedSynchronizer;
@@ -31,7 +33,8 @@
  * <ul>
  * <li>each thread can hold at most one lock level, i.e. either none, read, or
  * write.
- * <li>ownership is (also partially) transferable from one thread to another (not in this initial implementation)
+ * <li>ownership is (also partially) transferable from one thread to another
+ * (not in this initial implementation)
  * <li>upgrade from read-lock to write-lock is supported
  * <li>information which thread holds which locks is available
  * </ul>
@@ -40,26 +43,64 @@
 
     private static final long serialVersionUID = -5452408535686743324L;
 
-    private final ResourceRWLock.ReadLock readerLock;
+    private final ResourceRWLock.ReadLock readLock;
 
-    private final ResourceRWLock.WriteLock writerLock;
+    private final ResourceRWLock.WriteLock writeLock;
 
     private final Sync sync = new Sync();
 
+    private final String resourceName;
+
+    private final Collection<Thread> waiterThreads = new ConcurrentSkipListSet<Thread>(
+            threadComparator);
+
     public ResourceRWLock() {
-        readerLock = new ReadLock();
-        writerLock = new WriteLock();
+        this(null);
+    }
+
+    public ResourceRWLock(String resourceName) {
+        this.resourceName = resourceName;
+        this.readLock = new ReadLock();
+        this.writeLock = new WriteLock();
     }
 
     public ResourceRWLock.WriteLock writeLock() {
-        return writerLock;
+        return writeLock;
     }
 
     public ResourceRWLock.ReadLock readLock() {
-        return readerLock;
+        return readLock;
     }
 
-    class ReadLock implements Lock {
+    public Collection<Thread> getQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<Thread>(sync.getQueuedThreads());
+        list.addAll(waiterThreads);
+        return list;
+    }
+
+    public void registerWaiter() {
+        Thread current = Thread.currentThread();
+        waiterThreads.add(current);
+    }
+
+    public void unregisterWaiter() {
+        Thread current = Thread.currentThread();
+        waiterThreads.remove(current);
+    }
+
+    public class InnerLock {
+        public ResourceRWLock getResourceRWLock() {
+            return ResourceRWLock.this;
+        }
+
+    }
+
+    public String toString() {
+        return readLock().toString();
+    }
+
+    class ReadLock extends InnerLock implements Lock {
+
         public void lock() {
             sync.acquireShared(1);
         }
@@ -84,20 +125,27 @@
             throw new UnsupportedOperationException();
         }
 
-        public String toString() {
+        String simpleString() {
             StringBuffer buf = new StringBuffer();
-            buf.append(super.toString()).append("[Read locks = ");
-            buf.append("]");
+            buf.append("Read lock on ");
+            buf.append(resourceName == null ? super.toString() : resourceName);
+            buf.append("[");
             Collection<Thread> readerThreads = sync.readerThreads;
             for (Thread thread : readerThreads) {
                 buf.append(thread.getName());
                 buf.append(" ");
             }
+            buf.append("]");
             return buf.toString();
         }
+
+        public String toString() {
+            return simpleString() + "\n" + getResourceRWLock().writeLock.simpleString();
+        }
     }
 
-    class WriteLock implements Lock {
+    class WriteLock extends InnerLock implements Lock {
+
         public void lock() {
             sync.acquire(1);
         }
@@ -122,19 +170,24 @@
             return sync.newCondition();
         }
 
-        public String toString() {
+        String simpleString() {
             Thread o = sync.getOwner();
-            return super.toString()
+            return "Write lock on " + (resourceName == null ? super.toString() : resourceName)
                     + ((o == null) ? "[Unlocked]" : "[Locked by thread " + o.getName() + "]");
         }
 
+        public String toString() {
+            return simpleString() + "\n" + getResourceRWLock().readLock.simpleString();
+        }
+
     }
 
     static class Sync extends AbstractQueuedSynchronizer {
 
         private static final long serialVersionUID = 8791542812047042797L;
 
-        private final Collection<Thread> readerThreads = new ConcurrentSkipListSet<Thread>();
+        private final Collection<Thread> readerThreads = new ConcurrentSkipListSet<Thread>(
+                threadComparator);
 
         private final int NO_LOCK = 0;
 
@@ -257,5 +310,19 @@
         }
 
     }
+
+    private static final Comparator<Thread> threadComparator = new Comparator<Thread>() {
+
+        @Override
+        public int compare(Thread o1, Thread o2) {
+            int h1 = o1.getName().hashCode();
+            int h2 = o2.getName().hashCode();
+
+            if (h1 == h2)
+                return 0;
+            return (h1 < h2 ? -1 : 1);
+        }
+
+    };
 
 }

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/package.html
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/package.html?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/package.html (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/package.html Thu Aug 16 16:13:11 2007
@@ -1,118 +1,6 @@
 <html>
 <body>
 <h1>Locking</h1>
-
-<p>Beginning with version 1.1 the Commons Transaction package features
-extended transaction support mechanisms. They are grouped around the
-new <a
-href="../apidocs/org/apache/commons/transaction/locking/LockManager2.html">lock
-manager</a> and its <a
-href="../apidocs/org/apache/commons/transaction/locking/GenericLockManager.html">implementation</a>
-that should be used as the only interface to access locks
-associated to some sort of transaction. To do so it offers you locking
-methods like <a
-href="../apidocs/org/apache/commons/transaction/locking/LockManager2.html#lock(java.lang.Object,%20java.lang.Object,%20int,%20int,%20boolean,%20long)">lock</a>
-and <a
-href="../apidocs/org/apache/commons/transaction/locking/LockManager2.html#tryLock(java.lang.Object,%20java.lang.Object,%20int,%20boolean)">tryLock</a>.</p>  
-
-<p>It is important for this manager to be central and have
-knowledge of all locking operations to perform tasks like <a href="deadlock.html">deadlock
-detection</a>, incorporate <a
-href="../apidocs/org/apache/commons/transaction/locking/LockManager2.html#startGlobalTimeout(java.lang.Object,%20long)">global
-transaction timeouts</a> and add convenience methods to <a
-href="../apidocs/org/apache/commons/transaction/locking/LockManager2.html#releaseAll(java.lang.Object)">release
-all locks</a> of a transaction.</p>  
-
-<p>Additional to the <a href="preference.html">preference feature</a>
-in the new <a href="../apidocs/org/apache/commons/transaction/locking/MultiLevelLock2.html">lock</a>, its <a
-href="../apidocs/org/apache/commons/transaction/locking/GenericLock.html">implementation</a>
-has some internal means to record all requests that wait for
-(partially) acquiring a lock in the sequence they occur. This is
-used by the deadlock detection in the lock manager. Another possible
-use is in custom implementations of fair scheduling lock
-mechanisms. Even though the specific protected methods 
-<a
-href="../apidocs/org/apache/commons/transaction/locking/GenericLock.html#registerWaiter(org.apache.commons.transaction.locking.GenericLock.LockOwner)">registerWaiter</a>
-and
-<a
-href="../apidocs/org/apache/commons/transaction/locking/GenericLock.html#unregisterWaiter(org.apache.commons.transaction.locking.GenericLock.LockOwner)">unregisterWaiter</a>
-and field 
-<a
-href="../apidocs/org/apache/commons/transaction/locking/GenericLock.html#waitingOwners">waitingOwners</a> are not made available
-through interfaces subclasses can still use them and even make their means public.</p> 
-
-<h2>Deadlocks</h2>
- <p>A deadlock describes the scenario where two or more threads are
- mutually blocking each other. Each waits for the other to release its
- lock which will never happen as no thread can perform any
- action. Consider the following figure for illustration this. Thread #1 holds locks
-a, b and c and waits for lock d. Thread #2 holds locks d and e and
-waits for lock b. As lock d is owner by Thread #2, Thread #1 can not
- continue before Thread #2 releases it. Now Thread #2 waits for lock b
- which is turn is owner by Thread #1.</p>
-
-<center>
-<img src="deadlock1.png"/>
-</center>
-
-<p> Neither thread will ever be able
- to release any locks as both executions are blocked: the whole scene is dead!
-</p>
-
-<h3>How does deadlock detection work?</h3>
-
-<p>Theoretically, deadlock detection is pretty simple. First you have threads
-that own locks, then you have threads that wait for locks to
-acquire. Now you can think of a directed graph where you have
-threads and locks being nodes and each lock ownership and lock wait is
-a vertex that connects those nodes. When you have a cycle in that
-graph, i.e. when you can traverse the (directed!) graph starting from a certain
-node and you can reach that node again, you have a deadlock. This
-means a thread waits for itself to release a lock to 
-finally acquire a desired lock. Obviously, this will never happen
-without taking additional actions from the outside. Such an action
-could be to release the block for one thread telling it that there was
-a deadlock and the thread shall resolve it now it is able to perform actions.</p>
-<p>This can be illustrated with the above figure. Traversing the graph starting from Thread #1 going
-over lock b, Thread #2, lock d and finally Thread #1 (again) reveals
-the cycle and thus the deadlock. Note that of course you could just as
-well have started with Thread #2 and would have revealed the same cycle.
-</p>
-
-<h3>How does deadlock detection work for Commons Transaction?</h3>
-
-<p>In case of commons transaction things are a bit more complicated
-as a lock can have multiple (compatible) threads or better to say
-owners - lock ownership is not directly tied to the thread accessing
-the lock, but to an Object called owner. It can well be possible
-that an owner can both (partially) own a lock and wait for it as
-well. This may sound confusing, but actually becomes pretty obvious
-when you look at this example. There is a read/write lock and both owner #1
-and #2 hold a read lock which of course is compatible. Now when owner
-#1 ties to acquire a write lock it will have to wait for owner #2 to
-release its read lock. In such a case owner #1 both (partially) holds
-the lock and waits for it as illustrated by the following figure.</p>
-
-<center>
-<img src="deadlock2.png"/>
-</center>
-
-<p>The above algorithm would detect a deadlock. This of course is not there
-as owner #1 is blocked, but owner #2 is not and may finally release the read
-lock. This means the scenario is not dead.</p>
-<p>Obviously, the wait set of the lock is the problem. The graph does not
-tell us why owner #1 is waiting. In fact it does not wait for owner #1, but
-only for owner #2. Lookig at the next figure we see this. Both owners
-only own part of the lock and owner #1 is waiting for that part of
-the lock that owner #2 owns. 
-</p>
-
-<center>
-<img src="deadlock3.png"/>
-</center>
-
-<p>Thus the algorithm has to be modified in such a way that only the
-  real conflicting parts of the locks are taken into consideration. </p>
-
+<p>
 </body>
 </html>

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/BasicTxMap.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/BasicTxMap.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/BasicTxMap.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/BasicTxMap.java Thu Aug 16 16:13:11 2007
@@ -27,8 +27,8 @@
 
 import org.apache.commons.transaction.AbstractTransactionalResourceManager;
 import org.apache.commons.transaction.AbstractTransactionalResourceManager.AbstractTxContext;
-import org.apache.commons.transaction.locking.DefaultLockManager;
 import org.apache.commons.transaction.locking.LockManager;
+import org.apache.commons.transaction.locking.RWLockManager;
 
 /**
  * Map featuring transactional control.
@@ -47,6 +47,9 @@
  * This implementation wraps a map of type {@link ConcurrentHashMap}. All
  * internal synchronization is delegated to this class.
  * 
+ * <p>
+ * This implementation is <em>thread-safe</em>.
+ * 
  * @see OptimisticTxMap
  * @see PessimisticTxMap
  * @see ConcurrentHashMap
@@ -61,7 +64,7 @@
     }
 
     public BasicTxMap(String name) {
-        this(name, new DefaultLockManager<Object, Object>());
+        this(name, new RWLockManager<Object, Object>());
     }
 
     public Map<K, V> getWrappedMap() {

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/OptimisticTxMap.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/OptimisticTxMap.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/OptimisticTxMap.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/OptimisticTxMap.java Thu Aug 16 16:13:11 2007
@@ -27,9 +27,9 @@
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
-import org.apache.commons.transaction.locking.DefaultLockManager;
 import org.apache.commons.transaction.locking.LockException;
 import org.apache.commons.transaction.locking.LockManager;
+import org.apache.commons.transaction.locking.RWLockManager;
 
 /**
  * Map featuring transactional control.
@@ -44,6 +44,9 @@
  * 
  * <p>This implementation wraps a map of type {@link ConcurrentHashMap}. 
  * 
+ * <p>
+ * This implementation is <em>thread-safe</em>.
+ * 
  * @see BasicTxMap
  * @see PessimisticTxMap
  * @see ConcurrentHashMap
@@ -60,7 +63,7 @@
     private long accessTimeout = 1000 * 30; // 30 seconds
 
     public OptimisticTxMap(String name) {
-        this(name, new DefaultLockManager<Object, Object>());
+        this(name, new RWLockManager<Object, Object>());
     }
 
     public OptimisticTxMap(String name, LockManager<Object, Object> lm) {

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/PessimisticTxMap.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/PessimisticTxMap.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/PessimisticTxMap.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/PessimisticTxMap.java Thu Aug 16 16:13:11 2007
@@ -23,8 +23,8 @@
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
-import org.apache.commons.transaction.locking.DefaultLockManager;
 import org.apache.commons.transaction.locking.LockManager;
+import org.apache.commons.transaction.locking.RWLockManager;
 
 /**
  * Map featuring transactional control.
@@ -42,6 +42,9 @@
  * <p>
  * This implementation wraps a map of type {@link ConcurrentHashMap}.
  * 
+ * <p>
+ * This implementation is <em>thread-safe</em>.
+ * 
  * @see BasicTxMap
  * @see OptimisticTxMap
  * @see ConcurrentHashMap
@@ -51,7 +54,7 @@
     private ReadWriteLock globalLock = new ReentrantReadWriteLock();
 
     public PessimisticTxMap(String name) {
-        this(name, new DefaultLockManager<Object, Object>());
+        this(name, new RWLockManager<Object, Object>());
     }
 
     public PessimisticTxMap(String name, LockManager<Object, Object> lm) {
@@ -90,7 +93,6 @@
         LockingTxContext txContext = (LockingTxContext) getActiveTx();
         if (txContext != null) {
             txContext.writeLock(key);
-            // XXX fake intention lock (prohibits global WRITE)
         }
     }
 

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/resource/ResourceException.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/resource/ResourceException.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/resource/ResourceException.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/resource/ResourceException.java Thu Aug 16 16:13:11 2007
@@ -16,7 +16,6 @@
  */
 package org.apache.commons.transaction.resource;
 
-import java.io.IOException;
 
 public class ResourceException extends Exception {
 

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/resource/ResourceManager.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/resource/ResourceManager.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/resource/ResourceManager.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/resource/ResourceManager.java Thu Aug 16 16:13:11 2007
@@ -16,9 +16,24 @@
  */
 package org.apache.commons.transaction.resource;
 
-
+/**
+ * Interface for a manager on resources. All meaningful work is done using the
+ * interface for the resource.
+ */
 public interface ResourceManager<R> {
+    /**
+     * Gets the resource denoted by the path
+     * 
+     * @param path the path of the resource
+     * @return the resource denoted by the path
+     * @throws ResourceException in case anything goes fatally wrong
+     */
     R getResource(String path) throws ResourceException;
 
+    /**
+     * Gets the root path of this manager.
+     * 
+     * @return the root path or <code>null</code> if no applicable
+     */
     String getRootPath();
 }

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/resource/StreamableResource.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/resource/StreamableResource.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/resource/StreamableResource.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/resource/StreamableResource.java Thu Aug 16 16:13:11 2007
@@ -16,21 +16,61 @@
  */
 package org.apache.commons.transaction.resource;
 
+import java.io.File;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.List;
 
+/**
+ * Interface for a resource that has a stream and properties. The resource is
+ * organized in a hierarchy.
+ * 
+ * <p>
+ * This can be a direct match for {@link File}.
+ * 
+ */
 public interface StreamableResource {
+
+    /**
+     * Gets the full path of this resource
+     * 
+     * @return the full path
+     */
     String getPath();
+
+    /**
+     * Gets the name, i.e. the last segment of the {@link #getPath() path}.
+     * 
+     * @return the name
+     */
     String getName();
 
+    /**
+     * Checks whether this resource is a directory, i.e. whether it can have
+     * children. Note that a resource can be both a directory and a file.
+     * 
+     * @return <code>true</code> if this resource can have children
+     */
     boolean isDirectory();
 
+    /**
+     * Checks whether this resource is a file, i.e. whether it contains a
+     * content stream. Note that a resource can be both a directory and a file.
+     * 
+     * @return <code>true</code> if this resource contains a content stream
+     */
     boolean isFile();
 
+    /**
+     * Gets the children of the resource.
+     * 
+     * @return a list of children (empty if this is a file), never <code>null</code>
+     * @throws ResourceException in case anything goes fatally wrong
+     */
     List<? extends StreamableResource> getChildren() throws ResourceException;
 
     StreamableResource getParent() throws ResourceException;
+
     StreamableResource getChild(String name) throws ResourceException;
 
     InputStream readStream() throws ResourceException;
@@ -52,8 +92,9 @@
     Object getProperty(String name);
 
     void setProperty(String name, Object newValue);
+
     void removeProperty(String name);
-    
+
     void readLock();
 
     void writeLock();

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/TxFileResourceManagerTest.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/TxFileResourceManagerTest.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/TxFileResourceManagerTest.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/file/TxFileResourceManagerTest.java Thu Aug 16 16:13:11 2007
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.transaction.file;
 
+import static junit.framework.Assert.fail;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -25,12 +27,9 @@
 import java.util.concurrent.TimeUnit;
 
 import junit.framework.JUnit4TestAdapter;
-import static junit.framework.Assert.*;
-import org.junit.Test;
 
 import org.apache.commons.transaction.file.FileResourceManager.FileResource;
-import org.apache.commons.transaction.locking.DefaultLockManager;
-import org.apache.commons.transaction.locking.LockManager;
+import org.junit.Test;
 
 public class TxFileResourceManagerTest {
     
@@ -40,6 +39,10 @@
         return new JUnit4TestAdapter(TxFileResourceManagerTest.class);
     }
 
+    public static void main(java.lang.String[] args) {
+        junit.textui.TestRunner.run(suite());
+    }
+
     private static final void createFiles(String[] filePaths) {
         createFiles(filePaths, null, null);
     }
@@ -190,8 +193,5 @@
         }
 
     }
-
-    public static void main(java.lang.String[] args) {
-        junit.textui.TestRunner.run(suite());
-    }
+    
 }

Modified: commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/memory/PessimisticTxMapTest.java
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/memory/PessimisticTxMapTest.java?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/memory/PessimisticTxMapTest.java (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/memory/PessimisticTxMapTest.java Thu Aug 16 16:13:11 2007
@@ -94,4 +94,103 @@
         }
     }
 
+    @Test
+    public void testConflict() {
+        log.info("Checking concurrent conflict resolvation features");
+
+        final PessimisticTxMap<String, String> txMap1 = new PessimisticTxMap<String, String>(
+                "txMap1");
+        final Map map1 = txMap1.getWrappedMap();
+
+        final RendezvousBarrier restart = new RendezvousBarrier("restart", TIMEOUT);
+
+        int conflictingRuns = 0;
+        int runs = 25;
+
+        for (int i = 0; i < runs; i++) {
+            System.out.print(".");
+
+            final RendezvousBarrier deadlockBarrier1 = new RendezvousBarrier("deadlock" + i,
+                    TIMEOUT);
+
+            Thread thread1 = new Thread(new Runnable() {
+                public void run() {
+                    txMap1.startTransaction(5, TimeUnit.SECONDS);
+                    try {
+                        // first both threads get a lock, this one on key2
+                        txMap1.put("key2", "value2");
+                        synchronized (deadlockBarrier1) {
+                            deadlockBarrier1.meet();
+                            deadlockBarrier1.reset();
+                        }
+                        // if I am first, the other thread will be dead, i.e.
+                        // exactly one
+                        txMap1.put("key1", "value2");
+                        txMap1.commitTransaction();
+                    } catch (LockException le) {
+                        assertEquals(le.getCode(), LockException.Code.WOULD_DEADLOCK);
+                        deadlockCnt++;
+                        txMap1.rollbackTransaction();
+                    } catch (InterruptedException ie) {
+                    } finally {
+                        try {
+                            synchronized (restart) {
+                                restart.meet();
+                                restart.reset();
+                            }
+                        } catch (InterruptedException ie) {
+                        }
+
+                    }
+                }
+            }, "Thread1");
+
+            thread1.start();
+
+            txMap1.startTransaction(5, TimeUnit.SECONDS);
+            try {
+                // first both threads get a lock, this one on key1
+                txMap1.get("key1");
+                synchronized (deadlockBarrier1) {
+                    try {
+                        deadlockBarrier1.meet();
+                    } catch (InterruptedException e) {
+                        // TODO Auto-generated catch block
+                        e.printStackTrace();
+                    }
+                    deadlockBarrier1.reset();
+                }
+                // if I am first, the other thread will be dead, i.e. exactly
+                // one
+                txMap1.get("key2");
+                txMap1.commitTransaction();
+            } catch (LockException le) {
+                assertEquals(le.getCode(), LockException.Code.WOULD_DEADLOCK);
+                deadlockCnt++;
+                txMap1.rollbackTransaction();
+            } finally {
+                try {
+                    synchronized (restart) {
+                        restart.meet();
+                        restart.reset();
+                    }
+                } catch (InterruptedException ie) {
+                }
+
+            }
+
+            // XXX in special scenarios the current implementation might cause
+            // both owners to be deadlock victims
+            if (deadlockCnt != 1) {
+                // log.warn("More than one thread was deadlock victim!");
+                conflictingRuns++;
+            }
+            assertTrue(deadlockCnt >= 1);
+            deadlockCnt = 0;
+        }
+        System.out.println();
+        System.out.println("Of the " + runs + " there were " + conflictingRuns
+                + " runs that rolled back both transactions!");
+    }
+
 }

Modified: commons/proper/transaction/branches/TRANSACTION_2/xdocs/index.xml
URL: http://svn.apache.org/viewvc/commons/proper/transaction/branches/TRANSACTION_2/xdocs/index.xml?view=diff&rev=566884&r1=566883&r2=566884
==============================================================================
--- commons/proper/transaction/branches/TRANSACTION_2/xdocs/index.xml (original)
+++ commons/proper/transaction/branches/TRANSACTION_2/xdocs/index.xml Thu Aug 16 16:13:11 2007
@@ -75,9 +75,6 @@
 						can do that for you:
 						<ul>
 							<li>
-								benefit from automatic deadlock recovery
-							</li>
-							<li>
 								be sure you never forget to release a
 								lock again
 							</li>
@@ -89,6 +86,9 @@
 								have an out-of-the-box solution for
 								hierarchical locks
 							</li>
+							<li>
+								plug in your own custom or advanced solutions
+							</li>
 						</ul>
 					</li>
 					<li>need transactional access to maps</li>
@@ -122,8 +122,7 @@
 						</b>
 						Interfaces and implementations for lock
 						managers. Lock managers help you to keep control
-						over your locks. All current implementations
-						also perform deadlock detection.
+						over your locks.
 					</li>
 
 					<li>