Author: ozeigermann Date: Sun Jul 22 08:16:04 2007 New Revision: 558494 URL: http://svn.apache.org/viewvc?view=rev&rev=558494 Log: Major refeactoring to - allow for new type of lock manager - allow operations on multiple transaction resource managers inside a single transaction
Added: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/ManageableResourceManager.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionException.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionImpl.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/HierarchicalRWLockManager.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/RWLockManager.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/BasicTxMap.java - copied, changed from r558031, jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/TxMap.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/TransactionImplTest.java Removed: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/GenericLockManager.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/IntrinsicLockManager.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/ReadWriteLockManager.java Modified: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/AbstractTransactionalResourceManager.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/Transaction.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionalResourceManager.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/HierarchicalLockManager.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockException.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockManager.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/OptimisticTxMap.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/PessimisticTxMap.java jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/TxMap.java Modified: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/AbstractTransactionalResourceManager.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/AbstractTransactionalResourceManager.java?view=diff&rev=558494&r1=558493&r2=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/AbstractTransactionalResourceManager.java (original) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/AbstractTransactionalResourceManager.java Sun Jul 22 08:16:04 2007 @@ -16,37 +16,44 @@ */ package org.apache.commons.transaction; +import java.util.Map; import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReadWriteLock; import org.apache.commons.transaction.locking.LockException; -import org.apache.commons.transaction.locking.ReadWriteLockManager; -import org.apache.commons.transaction.locking.LockException.Code; +import org.apache.commons.transaction.locking.LockManager; /** * Not thread-safe. FIXME: Should it be? - * + * * @author olli - * + * * @param <T> */ -public abstract class AbstractTransactionalResourceManager<T extends AbstractTransactionalResourceManager.AbstractTxContext> implements TransactionalResourceManager { +public abstract class AbstractTransactionalResourceManager<T extends AbstractTransactionalResourceManager.AbstractTxContext> + implements ManageableResourceManager { protected ThreadLocal<T> activeTx = new ThreadLocal<T>(); + private LockManager<Object, String> lm; + + private String name; + protected abstract T createContext(); - /** - * Checks whether this transaction has been marked to allow a rollback as - * the only valid outcome. This can be set my method - * [EMAIL PROTECTED] #markTransactionForRollback()} or might be set internally be any - * fatal error. Once a transaction is marked for rollback there is no way to - * undo this. A transaction that is marked for rollback can not be - * committed, also rolled back. - * - * @return <code>true</code> if this transaction has been marked for a - * roll back - * @see #markTransactionForRollback() - */ + public AbstractTransactionalResourceManager() { + } + + public AbstractTransactionalResourceManager(String name) { + this.name = name; + } + + // can be used to share a lock manager with other transactinal resource + // managers + public AbstractTransactionalResourceManager(String name, LockManager<Object, String> lm) { + this.name = name; + this.lm = lm; + } + + @Override public boolean isTransactionMarkedForRollback() { T txContext = getActiveTx(); @@ -59,13 +66,14 @@ } @Override - public void startTransaction() { + public void startTransaction(long timeout, TimeUnit unit) { if (getActiveTx() != null) { throw new IllegalStateException("Active thread " + Thread.currentThread() + " already associated with a transaction!"); } - T txContent = createContext(); - setActiveTx(txContent); + T txContext = createContext(); + txContext.start(timeout, unit); + setActiveTx(txContext); } @@ -83,7 +91,7 @@ } @Override - public void commitTransaction() { + public boolean commitTransaction() { T txContext = getActiveTx(); if (txContext == null) { @@ -99,32 +107,7 @@ txContext.commit(); txContext.dispose(); setActiveTx(null); - } - - /** - * Prepares the changes done inside this transaction reasource. - * - */ - public boolean prepareTransaction() { - T txContext = getActiveTx(); - - if (txContext == null) { - throw new IllegalStateException("Active thread " + Thread.currentThread() - + " not associated with a transaction!"); - } - return txContext.prepare(); - } - - @Override - public void setTransactionTimeout(long mSecs) { - T txContext = getActiveTx(); - - if (txContext == null) { - throw new IllegalStateException("Active thread " + Thread.currentThread() - + " not associated with a transaction!"); - } - - txContext.setTimeout(mSecs); + return true; } protected T getActiveTx() { @@ -135,130 +118,114 @@ activeTx.set(txContext); } - public boolean isTransactionPrepared() { - // TODO Auto-generated method stub - return false; - } - public boolean isReadOnlyTransaction() { - // TODO Auto-generated method stub - return false; - } + T txContext = getActiveTx(); - /** - * Marks the current transaction to allow only a rollback as valid outcome. - * - * @see #isTransactionMarkedForRollback() - */ - public void markTransactionForRollback() { - // TODO Auto-generated method stub - + if (txContext == null) { + throw new IllegalStateException("Active thread " + Thread.currentThread() + + " not associated with a transaction!"); + } + + return (txContext.isReadOnly()); } public abstract class AbstractTxContext { - private long timeout = -1L; + private boolean readOnly = true; - private long startTime = -1L; + private boolean markedForRollback = false; - private boolean readOnly = true; + private LockManager<Object, String> lm; - private boolean prepared = false; - private boolean markedForRollback = false; + public AbstractTxContext() { + } - private ReadWriteLockManager lm = new ReadWriteLockManager(); + public LockManager<Object, String> getLm() { + if (this.lm != null) return this.lm; + else return AbstractTransactionalResourceManager.this.lm; + } - public AbstractTxContext() { - startTime = System.currentTimeMillis(); + + public void join(LockManager lm) { + this.lm = lm; } - protected long getRemainingTimeout() { - long now = System.currentTimeMillis(); - return (getStartTime()- now + timeout); + public void start(long timeout, TimeUnit unit) { + getLm().startWork(timeout, unit); } public void dispose() { - Iterable<ReadWriteLock> locks = getLm().getAllForCurrentThread(); - - for (ReadWriteLock lock : locks) { - lock.readLock().unlock(); - lock.writeLock().unlock(); - } + getLm().endWork(); } public boolean isReadOnly() { return readOnly; } - public boolean prepare() { - prepared = true; - return true; + public void setReadOnly(boolean readOnly) { + this.readOnly = readOnly; } - public long getStartTime() { - return startTime; + public void readLock(Object id) throws LockException { + getLm().lock(getName(), id, false); } - public void setStartTime(long startTimeMSecs) { - this.startTime = startTimeMSecs; + public void writeLock(Object id) throws LockException { + getLm().lock(getName(), id, true); } - public long getTimeout() { - return timeout; + public boolean isMarkedForRollback() { + return markedForRollback; } - public void setTimeout(long timeoutMSecs) { - this.timeout = timeoutMSecs; - } - - public void setReadOnly(boolean readOnly) { - this.readOnly = readOnly; + public void markForRollback() { + markedForRollback = true; } - public ReadWriteLockManager getLm() { - return lm; - } + public void commit() { - protected ReadWriteLock initLock(Object id) { - return getLm().putIfAbsent(id, getLm().create()); } + } - public void readLock(Object id) throws LockException { - try { - boolean locked = initLock(id).readLock().tryLock(getRemainingTimeout(), TimeUnit.MILLISECONDS); - if (!locked) { - throw new LockException(Code.TIMED_OUT, id); - } - } catch (InterruptedException e) { - throw new LockException(Code.INTERRUPTED, id); - } - } - - public void writeLock(Object id)throws LockException { - try { - boolean locked = initLock(id).writeLock().tryLock(getRemainingTimeout(), TimeUnit.MILLISECONDS); - if (!locked) { - throw new LockException(Code.TIMED_OUT, id); - } - } catch (InterruptedException e) { - throw new LockException(Code.INTERRUPTED, id); - } - } + public LockManager<Object, String> getLm() { + return lm; + } - public boolean isMarkedForRollback() { - return markedForRollback; - } + public void setLm(LockManager<Object, String> lm) { + this.lm = lm; + } - public boolean isPrepared() { - return prepared; - } + public String getName() { + return name; + } - public void markForRollback() { - markedForRollback = true; + public void setName(String name) { + this.name = name; + } + + public abstract boolean commitCanFail(); + + @Override + public void joinTransaction(LockManager lm) { + if (getActiveTx() != null) { + throw new IllegalStateException("Active thread " + Thread.currentThread() + + " already associated with a transaction!"); } + T txContext = createContext(); + txContext.join(lm); + setActiveTx(txContext); - public void commit() { - + } + + public void setRollbackOnly() { + T txContext = getActiveTx(); + + if (txContext == null) { + throw new IllegalStateException("Active thread " + Thread.currentThread() + + " not associated with a transaction!"); } + txContext.markForRollback(); + } + } Added: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/ManageableResourceManager.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/ManageableResourceManager.java?view=auto&rev=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/ManageableResourceManager.java (added) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/ManageableResourceManager.java Sun Jul 22 08:16:04 2007 @@ -0,0 +1,46 @@ +/* + * 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; + +import org.apache.commons.transaction.locking.LockManager; + + +public interface ManageableResourceManager extends TransactionalResourceManager { + void setRollbackOnly(); + boolean commitCanFail(); + /** + * Checks whether this transaction has been marked to allow a rollback as + * the only valid outcome. This can be set my method + * [EMAIL PROTECTED] #markTransactionForRollback()} or might be set internally be any + * fatal error. Once a transaction is marked for rollback there is no way to + * undo this. A transaction that is marked for rollback can not be + * committed, also rolled back. + * + * @return <code>true</code> if this transaction has been marked for a + * roll back + * @see #markTransactionForRollback() + */ + public boolean isTransactionMarkedForRollback(); + + + public boolean isReadOnlyTransaction(); + + public void joinTransaction(LockManager lm); + + + +} Modified: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/Transaction.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/Transaction.java?view=diff&rev=558494&r1=558493&r2=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/Transaction.java (original) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/Transaction.java Sun Jul 22 08:16:04 2007 @@ -16,12 +16,19 @@ */ package org.apache.commons.transaction; -public interface Transaction { - public void setTransactionTimeout(long mSecs); - - public void start(); +import java.util.concurrent.TimeUnit; - void setRollbackOnly(); +/** + * A managed transaction meant as interface to the user. Meant to operate on more than one resource manager. + * This is a light weight replacement for a complex 2PC xa transaction. + * + * @author olli + * + * + */ +// TODO: We need a manager for such a transaction (or at least an implementation) +public interface Transaction { + public void start(long timeout, TimeUnit unit); boolean isRollbackOnly(); @@ -29,6 +36,6 @@ public void commit(); - boolean enlistResourceManager(TransactionalResourceManager resourceManager); + void enlistResourceManager(ManageableResourceManager resourceManager); } Added: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionException.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionException.java?view=auto&rev=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionException.java (added) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionException.java Sun Jul 22 08:16:04 2007 @@ -0,0 +1,38 @@ +package org.apache.commons.transaction; + + + +public class TransactionException extends RuntimeException { + + /** + * + */ + private static final long serialVersionUID = 7650329971392401844L; + + public enum Code { + COMMIT_FAILED, + ROLLBACK_ONLY + } + + protected Code code; + + public TransactionException(Throwable cause, Code code) { + super(cause); + this.code = code; + } + + public TransactionException(Code code) { + this.code = code; + } + + /** + * Returns the formal reason for the exception. + * + * @return the reason code + */ + public Code getCode() { + return code; + } + + +} Added: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionImpl.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionImpl.java?view=auto&rev=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionImpl.java (added) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionImpl.java Sun Jul 22 08:16:04 2007 @@ -0,0 +1,100 @@ +/* + * 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; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.transaction.locking.LockManager; + +/** + * A managed transaction meant as interface to the user. Meant to operate on + * more than one resource manager. This is a light weight replacement for a + * complex 2PC xa transaction. + * + * @author olli + * + * + */ +public class TransactionImpl implements Transaction { + + protected LockManager lm; + + protected List<ManageableResourceManager> rms; + + public TransactionImpl(LockManager lm) { + this.lm = lm; + this.rms = new LinkedList<ManageableResourceManager>(); + } + + public void commit() throws TransactionException { + lm.endWork(); + if (isRollbackOnly()) { + throw new TransactionException(TransactionException.Code.ROLLBACK_ONLY); + } + for (ManageableResourceManager manager : rms) { + if (!manager.isReadOnlyTransaction()) { + try { + if (!manager.commitTransaction()) { + throw new TransactionException(TransactionException.Code.COMMIT_FAILED); + } + } catch (Exception e) { + throw new TransactionException(e, TransactionException.Code.COMMIT_FAILED); + } catch (Error e) { + // is this really a good idea? + rollback(); + throw e; + } + } + } + } + + public void enlistResourceManager(ManageableResourceManager resourceManager) { + // if the manager might fail upon commit, tried it as early as possible + if (resourceManager.commitCanFail()) { + rms.add(0, resourceManager); + } else { + rms.add(resourceManager); + } + } + + public boolean isRollbackOnly() { + for (ManageableResourceManager manager : rms) { + if (manager.isTransactionMarkedForRollback()) + return true; + } + return false; + } + + public void rollback() { + lm.endWork(); + for (ManageableResourceManager manager : rms) { + if (!manager.isReadOnlyTransaction()) { + manager.rollbackTransaction(); + } + } + } + + public void start(long timeout, TimeUnit unit) { + for (ManageableResourceManager manager : rms) { + manager.joinTransaction(lm); + } + lm.startWork(timeout, unit); + } + +} Modified: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionalResourceManager.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionalResourceManager.java?view=diff&rev=558494&r1=558493&r2=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionalResourceManager.java (original) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/TransactionalResourceManager.java Sun Jul 22 08:16:04 2007 @@ -16,20 +16,16 @@ */ package org.apache.commons.transaction; +import java.util.concurrent.TimeUnit; + /** * Interface for something that makes up a transactional resource manager. + * Comparable to an XA resource. * */ public interface TransactionalResourceManager { /** - * TODO - * - * @param mSecs - */ - public void setTransactionTimeout(long mSecs); - - /** * Starts a new transaction and associates it with the current thread. All * subsequent changes in the same thread made to the map are invisible from * other threads until [EMAIL PROTECTED] #commitTransaction()} is called. Use @@ -43,14 +39,13 @@ * @see #commitTransaction() * @see #rollbackTransaction() */ - public void startTransaction(); - + public void startTransaction(long timeout, TimeUnit unit); /** * Discards all changes made in the current transaction and deletes the * association between the current thread and the transaction. * - * @see #startTransaction() + * @see #startTransaction(long, TimeUnit) * @see #commitTransaction() */ public void rollbackTransaction(); @@ -59,9 +54,8 @@ * Commits all changes made in the current transaction and deletes the * association between the current thread and the transaction. * - * @see #startTransaction() + * @see #startTransaction(long, TimeUnit) * @see #rollbackTransaction() */ - public void commitTransaction(); - + public boolean commitTransaction(); } Modified: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/HierarchicalLockManager.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/HierarchicalLockManager.java?view=diff&rev=558494&r1=558493&r2=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/HierarchicalLockManager.java (original) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/HierarchicalLockManager.java Sun Jul 22 08:16:04 2007 @@ -2,6 +2,7 @@ // Takes care of hierarchical locking with folders and resources -public class HierarchicalLockManager extends ReadWriteLockManager { - +public interface HierarchicalLockManager<M> extends LockManager<String, M> { + public void lockAsFolder(String path, boolean exclusive) throws LockException; + public void lockAsResource(String path, boolean exclusive) throws LockException; } Added: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/HierarchicalRWLockManager.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/HierarchicalRWLockManager.java?view=auto&rev=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/HierarchicalRWLockManager.java (added) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/HierarchicalRWLockManager.java Sun Jul 22 08:16:04 2007 @@ -0,0 +1,15 @@ +package org.apache.commons.transaction.locking; + +public class HierarchicalRWLockManager<M> extends RWLockManager<String, M> implements + HierarchicalLockManager<M> { + + public void lockAsFolder(String path, boolean exclusive) throws LockException { + // TODO Auto-generated method stub + + } + + public void lockAsResource(String path, boolean exclusive) throws LockException { + // TODO Auto-generated method stub + + } +} Modified: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockException.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockException.java?view=diff&rev=558494&r1=558493&r2=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockException.java (original) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockException.java Sun Jul 22 08:16:04 2007 @@ -87,6 +87,10 @@ super(cause); } + public LockException(Code code) { + this.code = code; + } + public LockException(Throwable cause, Code code) { super(cause); this.code = code; Modified: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockManager.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockManager.java?view=diff&rev=558494&r1=558493&r2=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockManager.java (original) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/LockManager.java Sun Jul 22 08:16:04 2007 @@ -1,18 +1,41 @@ package org.apache.commons.transaction.locking; +import java.util.concurrent.TimeUnit; +/** + * + * @author olli + * + * + * + * @param <K> + */ +public interface LockManager<K, M> { + /** + * Starts a block of work for which a certain set of locks is required. + * + * @param timeout + * the maximum time for the whole work to take before it times + * out + * @param unit + * the time unit of the [EMAIL PROTECTED] timeout} argument + */ + public void startWork(long timeout, TimeUnit unit); -public interface LockManager<K, L> { - public L get(K key); + /** + * Ends a block of work that has been started in + * [EMAIL PROTECTED] #startWork(long, TimeUnit)}. All locks acquired will be released. + * All registered locks will be unregistered from this lock manager. + * + */ + public void endWork(); - public L putIfAbsent(K key, L lock); + public boolean isWorking(); - public L remove(K key); - - public L create(); - - public Iterable<L> getAll(); - - public Iterable<L> getAllForCurrentThread(); + /** + * @param managedResource + * resource for on which this block of work shall be done + */ + public void lock(M managedResource, K key, boolean exclusive) throws LockException; } Added: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/RWLockManager.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/RWLockManager.java?view=auto&rev=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/RWLockManager.java (added) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/locking/RWLockManager.java Sun Jul 22 08:16:04 2007 @@ -0,0 +1,169 @@ +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 java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.apache.commons.transaction.locking.LockException.Code; + +public class RWLockManager<K, M> implements LockManager<K, M> { + + protected ConcurrentHashMap<KeyEntry<K, M>, ReadWriteLock> locks = new ConcurrentHashMap<KeyEntry<K, M>, ReadWriteLock>(); + + protected Map<Thread, Set<ReadWriteLock>> locksForThreads = new ConcurrentHashMap<Thread, Set<ReadWriteLock>>(); + + protected Map<ReadWriteLock, Set<Thread>> threadsForLocks = new ConcurrentHashMap<ReadWriteLock, Set<Thread>>(); + + protected Map<Thread, Long> effectiveGlobalTimeouts = new ConcurrentHashMap<Thread, Long>(); + + // TODO + public static Iterable<ReadWriteLock> orderLocks() { + return null; + + } + + // TODO + public void lockAll(Iterable<ReadWriteLock> locks) { + } + + @Override + public void endWork() { + Set<ReadWriteLock> locks = locksForThreads.get(Thread.currentThread()); + // graceful reaction... + if (locks == null) { + return; + } + for (ReadWriteLock lock : locks) { + try { + lock.readLock().unlock(); + } catch (IllegalMonitorStateException imse) { + // we do not care + } + try { + lock.writeLock().unlock(); + } catch (IllegalMonitorStateException imse) { + // we do not care + } + + // FIXME: We need to do this atomically + Set<Thread> threadsForThisLock = threadsForLocks.get(lock); + if (threadsForThisLock != null) { + threadsForThisLock.remove(Thread.currentThread()); + if (threadsForThisLock.isEmpty()) { + threadsForLocks.remove(lock); + locks.remove(lock); + } + } + } + + locksForThreads.remove(Thread.currentThread()); + } + + @Override + public void startWork(long timeout, TimeUnit unit) { + if (isWorking()) { + throw new IllegalStateException("work has already been started"); + } + locksForThreads.put(Thread.currentThread(), new HashSet<ReadWriteLock>()); + + 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() { + long timeout = effectiveGlobalTimeouts.get(Thread.currentThread()); + long now = System.currentTimeMillis(); + long remaining = timeout - now; + return remaining; + } + + protected final ReadWriteLock putIfAbsent(KeyEntry<K, M> entry, ReadWriteLock lock) { + ReadWriteLock existingLock = locks.get(entry); + if (existingLock == null) { + ReadWriteLock concurrentlyInsertedLock = locks.putIfAbsent(entry, lock); + if (concurrentlyInsertedLock != null) + lock = concurrentlyInsertedLock; + } + return lock; + + } + + protected ReadWriteLock create() { + return new ReentrantReadWriteLock(); + } + + 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(); + } + } + + @Override + public void lock(M managedResource, K key, boolean exclusive) throws LockException { + long remainingTime = computeRemainingTime(); + if (remainingTime < 0) { + throw new LockException(LockException.Code.TIMED_OUT); + } + + KeyEntry<K, M> entry = new KeyEntry<K, M>(key, managedResource); + + ReadWriteLock rwlock = putIfAbsent(entry, create()); + Set<ReadWriteLock> locks = locksForThreads.get(Thread.currentThread()); + if (locks == null) { + throw new IllegalStateException("lock() can only be called after startWork()"); + } + locks.add(rwlock); + + Lock lock = exclusive ? rwlock.writeLock() : rwlock.readLock(); + + try { + boolean locked = lock.tryLock(remainingTime, TimeUnit.MILLISECONDS); + if (!locked) { + throw new LockException(Code.TIMED_OUT, key); + } + } catch (InterruptedException e) { + throw new LockException(Code.INTERRUPTED, key); + } + + } + + @Override + public boolean isWorking() { + return locksForThreads.get(Thread.currentThread()) != null; + } + +} Copied: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/BasicTxMap.java (from r558031, jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/TxMap.java) URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/BasicTxMap.java?view=diff&rev=558494&p1=jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/TxMap.java&r1=558031&p2=jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/BasicTxMap.java&r2=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/TxMap.java (original) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/BasicTxMap.java Sun Jul 22 08:16:04 2007 @@ -28,6 +28,7 @@ import org.apache.commons.transaction.AbstractTransactionalResourceManager; import org.apache.commons.transaction.TransactionalResourceManager; import org.apache.commons.transaction.AbstractTransactionalResourceManager.AbstractTxContext; +import org.apache.commons.transaction.locking.LockManager; /** * Wrapper that adds transactional control to all kinds of maps that implement @@ -49,12 +50,15 @@ * @see OptimisticTxMap * @see PessimisticTxMap */ -public class TxMap<K, V> extends - AbstractTransactionalResourceManager<TxMap.MapTxContext> implements Map<K, V>, - TransactionalResourceManager { +public class BasicTxMap<K, V> extends AbstractTransactionalResourceManager<BasicTxMap.MapTxContext> implements + TxMap<K, V> { protected Map<K, V> wrapped = new ConcurrentHashMap<K, V>(); + public BasicTxMap(String name) { + super(name); + } + // // Map methods // @@ -419,6 +423,11 @@ } } + } + + @Override + public boolean commitCanFail() { + return false; } } Modified: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/OptimisticTxMap.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/OptimisticTxMap.java?view=diff&rev=558494&r1=558493&r2=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/OptimisticTxMap.java (original) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/OptimisticTxMap.java Sun Jul 22 08:16:04 2007 @@ -27,11 +27,12 @@ import org.apache.commons.transaction.TransactionalResourceManager; import org.apache.commons.transaction.locking.LockException; +import org.apache.commons.transaction.locking.LockManager; /** * Wrapper that adds transactional control to all kinds of maps that implement * the [EMAIL PROTECTED] Map} interface. By using a naive optimistic transaction control - * this wrapper has better isolation than [EMAIL PROTECTED] TxMap}, but + * this wrapper has better isolation than [EMAIL PROTECTED] BasicTxMap}, but * may also fail to commit. * * <br> @@ -50,11 +51,10 @@ * around. * * @version $Id: OptimisticMapWrapper.java 493628 2007-01-07 01:42:48Z joerg $ - * @see TxMap + * @see BasicTxMap * @see PessimisticTxMap */ -public class OptimisticTxMap<K, V> extends TxMap<K, V> implements Map<K, V>, -TransactionalResourceManager { +public class OptimisticTxMap<K, V> extends BasicTxMap<K, V> implements TxMap<K, V> { private Set<CopyingTxContext> activeTransactions = new HashSet<CopyingTxContext>(); private ReadWriteLock commitLock = new ReentrantReadWriteLock(); @@ -68,11 +68,16 @@ activeTransactions.remove(txContext); } - public void commitTransaction() throws LockException { - commitTransaction(false); + public OptimisticTxMap(String name) { + super(name); } - public void commitTransaction(boolean force) throws LockException { + + public boolean commitTransaction() throws LockException { + return commitTransaction(false); + } + + public boolean commitTransaction(boolean force) throws LockException { MapTxContext txContext = getActiveTx(); if (txContext == null) { @@ -99,8 +104,7 @@ activeTransactions.remove(txContext); copyChangesToConcurrentTransactions(); - super.commitTransaction(); - + return super.commitTransaction(); } catch (InterruptedException e) { throw new LockException(e); } finally { @@ -337,4 +341,10 @@ public void setCommitTimeout(long commitTimeout) { this.commitTimeout = commitTimeout; } + + @Override + public boolean commitCanFail() { + return true; + } + } Modified: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/PessimisticTxMap.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/PessimisticTxMap.java?view=diff&rev=558494&r1=558493&r2=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/PessimisticTxMap.java (original) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/PessimisticTxMap.java Sun Jul 22 08:16:04 2007 @@ -22,11 +22,12 @@ import java.util.Set; import org.apache.commons.transaction.TransactionalResourceManager; +import org.apache.commons.transaction.locking.LockManager; /** * Wrapper that adds transactional control to all kinds of maps that implement * the [EMAIL PROTECTED] Map} interface. By using pessimistic transaction control (blocking - * locks) this wrapper has better isolation than [EMAIL PROTECTED] TxMap}, + * locks) this wrapper has better isolation than [EMAIL PROTECTED] BasicTxMap}, * but also has less possible concurrency and may even deadlock. A commit, * however, will never fail. <br> * Start a transaction by calling [EMAIL PROTECTED] #startTransaction()}. Then perform the @@ -41,14 +42,17 @@ * <code>SERIALIZABLE</code>. * * @version $Id: PessimisticMapWrapper.java 493628 2007-01-07 01:42:48Z joerg $ - * @see TxMap + * @see BasicTxMap * @see OptimisticTxMap */ -public class PessimisticTxMap<K, V> extends TxMap<K, V> implements Map<K, V>, -TransactionalResourceManager { +public class PessimisticTxMap<K, V> extends BasicTxMap<K, V> implements TxMap<K, V> { protected static final Object GLOBAL_LOCK = "GLOBAL"; + public PessimisticTxMap(String name) { + super(name); + } + public Collection values() { assureGlobalReadLock(); return super.values(); @@ -142,6 +146,10 @@ super.clear(); } + } + @Override + public boolean commitCanFail() { + return false; } } Modified: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/TxMap.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/TxMap.java?view=diff&rev=558494&r1=558493&r2=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/TxMap.java (original) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/java/org/apache/commons/transaction/memory/TxMap.java Sun Jul 22 08:16:04 2007 @@ -16,409 +16,9 @@ */ package org.apache.commons.transaction.memory; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import org.apache.commons.transaction.AbstractTransactionalResourceManager; -import org.apache.commons.transaction.TransactionalResourceManager; -import org.apache.commons.transaction.AbstractTransactionalResourceManager.AbstractTxContext; - -/** - * Wrapper that adds transactional control to all kinds of maps that implement - * the [EMAIL PROTECTED] Map} interface. This wrapper has rather weak isolation, but is - * simply, neven blocks and commits will never fail for logical reasons. <br> - * Start a transaction by calling [EMAIL PROTECTED] #startTransaction()}. Then perform the - * normal actions on the map and finally either call - * [EMAIL PROTECTED] #commitTransaction()} to make your changes permanent or - * [EMAIL PROTECTED] #rollbackTransaction()} to undo them. <br> - * <em>Caution:</em> Do not modify values retrieved by [EMAIL PROTECTED] #get(Object)} as - * this will circumvent the transactional mechanism. Rather clone the value or - * copy it in a way you see fit and store it back using - * [EMAIL PROTECTED] #put(Object, Object)}. <br> - * <em>Note:</em> This wrapper guarantees isolation level - * <code>READ COMMITTED</code> only. I.e. as soon a value is committed in one - * transaction it will be immediately visible in all other concurrent - * transactions. - * - * @see OptimisticTxMap - * @see PessimisticTxMap - */ -public class TxMap<K, V> extends - AbstractTransactionalResourceManager<TxMap.MapTxContext> implements Map<K, V>, - TransactionalResourceManager { - - protected Map<K, V> wrapped = new ConcurrentHashMap<K, V>(); - - // - // Map methods - // - - /** - * @see Map#clear() - */ - public void clear() { - MapTxContext txContext = getActiveTx(); - if (txContext != null) { - txContext.clear(); - } else { - wrapped.clear(); - } - } - - /** - * @see Map#size() - */ - public int size() { - MapTxContext txContext = getActiveTx(); - if (txContext != null) { - return txContext.size(); - } else { - return wrapped.size(); - } - } - - /** - * @see Map#isEmpty() - */ - public boolean isEmpty() { - MapTxContext txContext = getActiveTx(); - if (txContext == null) { - return wrapped.isEmpty(); - } else { - return txContext.isEmpty(); - } - } - - /** - * @see Map#containsKey(java.lang.Object) - */ - public boolean containsKey(Object key) { - return keySet().contains(key); - } - - /** - * @see Map#containsValue(java.lang.Object) - */ - public boolean containsValue(Object value) { - MapTxContext txContext = getActiveTx(); - - if (txContext == null) { - return wrapped.containsValue(value); - } else { - return values().contains(value); - } - } - - /** - * @see Map#values() - */ - public Collection values() { - - MapTxContext txContext = getActiveTx(); - - if (txContext == null) { - return wrapped.values(); - } else { - // XXX expensive :( - Collection values = new ArrayList(); - for (Iterator it = keySet().iterator(); it.hasNext();) { - Object key = it.next(); - Object value = get(key); - // XXX we have no isolation, so get entry might have been - // deleted in the meantime - if (value != null) { - values.add(value); - } - } - return values; - } - } - - /** - * @see Map#putAll(java.util.Map) - */ - public void putAll(Map map) { - MapTxContext txContext = getActiveTx(); - - if (txContext == null) { - wrapped.putAll(map); - } else { - for (Iterator it = map.entrySet().iterator(); it.hasNext();) { - Map.Entry<K, V> entry = (Map.Entry) it.next(); - txContext.put(entry.getKey(), entry.getValue()); - } - } - } - - /** - * @see Map#entrySet() - */ - public Set entrySet() { - MapTxContext txContext = getActiveTx(); - if (txContext == null) { - return wrapped.entrySet(); - } else { - Set entrySet = new HashSet(); - // XXX expensive :( - for (Iterator it = keySet().iterator(); it.hasNext();) { - Object key = it.next(); - Object value = get(key); - // XXX we have no isolation, so get entry might have been - // deleted in the meantime - if (value != null) { - entrySet.add(new HashEntry(key, value)); - } - } - return entrySet; - } - } - - /** - * @see Map#keySet() - */ - public Set keySet() { - MapTxContext txContext = getActiveTx(); - - if (txContext == null) { - return wrapped.keySet(); - } else { - return txContext.keys(); - } - } - - /** - * @see Map#get(java.lang.Object) - */ - public V get(Object key) { - MapTxContext txContext = getActiveTx(); - - if (txContext != null) { - return txContext.get(key); - } else { - return wrapped.get(key); - } - } - - /** - * @see Map#remove(java.lang.Object) - */ - public V remove(Object key) { - MapTxContext txContext = getActiveTx(); - - if (txContext == null) { - return wrapped.remove(key); - } else { - V oldValue = get(key); - txContext.remove(key); - return oldValue; - } - } - - /** - * @see Map#put(java.lang.Object, java.lang.Object) - */ - public V put(K key, V value) { - MapTxContext txContext = getActiveTx(); - - if (txContext == null) { - return wrapped.put(key, value); - } else { - V oldValue = get(key); - txContext.put(key, value); - return oldValue; - } - - } - - @Override - protected MapTxContext createContext() { - return new MapTxContext(); - } - - @Override - protected MapTxContext getActiveTx() { - return activeTx.get(); - } - - // mostly copied from org.apache.commons.collections.map.AbstractHashedMap - protected static class HashEntry implements Map.Entry { - /** The key */ - protected Object key; - - /** The value */ - protected Object value; - - protected HashEntry(Object key, Object value) { - this.key = key; - this.value = value; - } - - public Object getKey() { - return key; - } - - public Object getValue() { - return value; - } - - public Object setValue(Object value) { - Object old = this.value; - this.value = value; - return old; - } - - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof Map.Entry)) { - return false; - } - Map.Entry other = (Map.Entry) obj; - return (getKey() == null ? other.getKey() == null : getKey().equals(other.getKey())) - && (getValue() == null ? other.getValue() == null : getValue().equals( - other.getValue())); - } - - public int hashCode() { - return (getKey() == null ? 0 : getKey().hashCode()) - ^ (getValue() == null ? 0 : getValue().hashCode()); - } - - public String toString() { - return new StringBuffer().append(getKey()).append('=').append(getValue()).toString(); - } - } - - public class MapTxContext extends AbstractTxContext { - protected Set deletes; - - protected Map<K, V> changes; - - protected Map<K, V> adds; - - protected boolean cleared; - - protected MapTxContext() { - deletes = new HashSet(); - changes = new HashMap<K, V>(); - adds = new HashMap<K, V>(); - cleared = false; - } - - protected Set keys() { - Set keySet = new HashSet(); - if (!cleared) { - keySet.addAll(wrapped.keySet()); - keySet.removeAll(deletes); - } - keySet.addAll(adds.keySet()); - return keySet; - } - - protected V get(Object key) { - - if (deletes.contains(key)) { - // reflects that entry has been deleted in this tx - return null; - } - - if (changes.containsKey(key)) { - return changes.get(key); - } - - if (adds.containsKey(key)) { - return adds.get(key); - } - - if (cleared) { - return null; - } else { - // not modified in this tx - return wrapped.get(key); - } - } - - protected void put(K key, V value) { - try { - setReadOnly(false); - deletes.remove(key); - if (wrapped.containsKey(key)) { - changes.put(key, value); - } else { - adds.put(key, value); - } - } catch (RuntimeException e) { - markForRollback(); - throw e; - } catch (Error e) { - markForRollback(); - throw e; - } - } - - protected void remove(Object key) { - - try { - setReadOnly(false); - changes.remove(key); - adds.remove(key); - if (wrapped.containsKey(key) && !cleared) { - deletes.add(key); - } - } catch (RuntimeException e) { - markForRollback(); - throw e; - } catch (Error e) { - markForRollback(); - throw e; - } - } - - protected int size() { - int size = (cleared ? 0 : wrapped.size()); - - size -= deletes.size(); - size += adds.size(); - - return size; - } - - protected void clear() { - setReadOnly(false); - cleared = true; - deletes.clear(); - changes.clear(); - adds.clear(); - } - - protected boolean isEmpty() { - return (size() == 0); - } - - public void commit() { - if (!isReadOnly()) { - - if (cleared) { - wrapped.clear(); - } - - wrapped.putAll(changes); - wrapped.putAll(adds); - - for (Iterator it = deletes.iterator(); it.hasNext();) { - Object key = it.next(); - wrapped.remove(key); - } - } - } - - } +import org.apache.commons.transaction.ManageableResourceManager; +public interface TxMap<K, V> extends Map<K, V>, ManageableResourceManager { } Added: jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/TransactionImplTest.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/TransactionImplTest.java?view=auto&rev=558494 ============================================================================== --- jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/TransactionImplTest.java (added) +++ jakarta/commons/proper/transaction/branches/TRANSACTION_2/src/test/org/apache/commons/transaction/TransactionImplTest.java Sun Jul 22 08:16:04 2007 @@ -0,0 +1,41 @@ +package org.apache.commons.transaction; + +import java.util.concurrent.TimeUnit; + +import junit.framework.JUnit4TestAdapter; + +import org.apache.commons.transaction.locking.LockManager; +import org.apache.commons.transaction.locking.RWLockManager; +import org.apache.commons.transaction.memory.PessimisticTxMap; +import org.apache.commons.transaction.memory.TxMap; +import org.junit.Test; + +public class TransactionImplTest { + public static junit.framework.Test suite() { + return new JUnit4TestAdapter(TransactionImplTest.class); + } + + @Test + public void basic() { + LockManager lm = new RWLockManager<String, String>(); + Transaction t = new TransactionImpl(lm); + TxMap<String, Object> txMap1 = new PessimisticTxMap<String, Object>("TxMap1"); + t.enlistResourceManager(txMap1); + TxMap<String, Object> txMap2 = new PessimisticTxMap<String, Object>("TxMap2"); + t.enlistResourceManager(txMap2); + + try { + t.start(60, TimeUnit.SECONDS); + txMap1.put("Olli", "Huhu"); + txMap2.put("Olli", "Haha"); + t.commit(); + } catch (Throwable throwable) { + t.rollback(); + } + + } + + public static void main(String[] args) { + new TransactionImplTest().basic(); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]