Return-Path: Delivered-To: apmail-jakarta-commons-dev-archive@www.apache.org Received: (qmail 54681 invoked from network); 5 Jun 2004 16:33:45 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur-2.apache.org with SMTP; 5 Jun 2004 16:33:45 -0000 Received: (qmail 36930 invoked by uid 500); 5 Jun 2004 16:33:39 -0000 Delivered-To: apmail-jakarta-commons-dev-archive@jakarta.apache.org Received: (qmail 36902 invoked by uid 500); 5 Jun 2004 16:33:39 -0000 Mailing-List: contact commons-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Jakarta Commons Developers List" Reply-To: "Jakarta Commons Developers List" Delivered-To: mailing list commons-dev@jakarta.apache.org Received: (qmail 36884 invoked by uid 500); 5 Jun 2004 16:33:39 -0000 Received: (qmail 36878 invoked by uid 99); 5 Jun 2004 16:33:38 -0000 Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.27.1) with SMTP; Sat, 05 Jun 2004 09:33:38 -0700 Received: (qmail 54563 invoked by uid 1773); 5 Jun 2004 16:33:37 -0000 Date: 5 Jun 2004 16:33:37 -0000 Message-ID: <20040605163337.54562.qmail@minotaur.apache.org> From: ozeigermann@apache.org To: jakarta-commons-sandbox-cvs@apache.org Subject: cvs commit: jakarta-commons-sandbox/transaction/src/java/org/apache/commons/transaction/memory TransactionalMapWrapper.java X-Virus-Checked: Checked X-Spam-Rating: minotaur-2.apache.org 1.6.2 0/1000/N ozeigermann 2004/06/05 09:33:37 Modified: transaction/src/java/org/apache/commons/transaction/memory TransactionalMapWrapper.java Log: - Added Javadocs - Removed obsolete rollbackonly flag - Added suspended flag Revision Changes Path 1.16 +144 -27 jakarta-commons-sandbox/transaction/src/java/org/apache/commons/transaction/memory/TransactionalMapWrapper.java Index: TransactionalMapWrapper.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/transaction/src/java/org/apache/commons/transaction/memory/TransactionalMapWrapper.java,v retrieving revision 1.15 retrieving revision 1.16 diff -u -r1.15 -r1.16 --- TransactionalMapWrapper.java 5 Jun 2004 14:52:09 -0000 1.15 +++ TransactionalMapWrapper.java 5 Jun 2004 16:33:37 -0000 1.16 @@ -54,16 +54,19 @@ */ public class TransactionalMapWrapper implements Map, Status { + /** The map wrapped. */ protected Map wrapped; - protected ThreadLocal activeTx = new ThreadLocal(); - + /** Factory to be used to create temporary maps for transactions. */ protected MapFactory mapFactory; + /** Factory to be used to create temporary sets for transactions. */ protected SetFactory setFactory; + private ThreadLocal activeTx = new ThreadLocal(); + /** * Creates a new transactional map wrapper. Temporary maps and sets to store transactional - * data will be instances of {@link HashMap} and {@link HashSet}. + * data will be instances of {@link java.util.HashMap} and {@link java.util.HashSet}. * * @param wrapped map to be wrapped */ @@ -85,6 +88,12 @@ this.setFactory = setFactory; } + /** + * Checks if any write operations have been performed inside this transaction. + * + * @return true if no write opertation has been performed inside the current transaction, + * false otherwise + */ public synchronized boolean isReadOnly() { TxContext txContext = getActiveTx(); @@ -96,6 +105,16 @@ return txContext.readOnly; } + /** + * Checks whether this transaction has been marked to allow a rollback as the only + * valid outcome. This can be set my method {@link #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 true if this transaction has been marked for a roll back + * @see #markTransactionForRollback() + */ public synchronized boolean isTransactionMarkedForRollback() { TxContext txContext = getActiveTx(); @@ -104,9 +123,14 @@ "Active thread " + Thread.currentThread() + " not associated with a transaction!"); } - return txContext.rollbackOnly; + return (txContext.status == Status.STATUS_MARKED_ROLLBACK); } + /** + * Marks the current transaction to allow only a rollback as valid outcome. + * + * @see #isTransactionMarkedForRollback() + */ public synchronized void markTransactionForRollback() { TxContext txContext = getActiveTx(); @@ -115,10 +139,24 @@ "Active thread " + Thread.currentThread() + " not associated with a transaction!"); } - txContext.rollbackOnly = true; - + txContext.status = Status.STATUS_MARKED_ROLLBACK; } + /** + * Suspends the transaction associated to the current thread. I.e. the associated between the + * current thread and the transaction is deleted. This is useful when you want to continue the transaction + * in another thread later. Call {@link #resumeTransaction(TxContext)} - possibly in another thread than the current - + * to resume work on the transaction. + *

+ * Caution: When calling this method the returned identifier + * for the transaction is the only remaining reference to the transaction, so be sure to remember it or + * the transaction will be eventually deleted (and thereby rolled back) as garbage. + * + * @return an identifier for the suspended transaction, will be needed to later resume the transaction by + * {@link #resumeTransaction(TxContext)} + * + * @see #resumeTransaction(TxContext) + */ public synchronized TxContext suspendTransaction() { TxContext txContext = getActiveTx(); @@ -127,10 +165,18 @@ "Active thread " + Thread.currentThread() + " not associated with a transaction!"); } - setActiveTx(null); + txContext.suspended = true; + setActiveTx(null); return txContext; } + /** + * Resumes a transaction in the current thread that has previously been suspened by {@link #suspendTransaction()}. + * + * @param suspendedTx the identifier for the transaction to be resumed, delivered by {@link #suspendTransaction()} + * + * @see #suspendTransaction() + */ public synchronized void resumeTransaction(TxContext suspendedTx) { if (getActiveTx() != null) { throw new IllegalStateException( @@ -140,10 +186,20 @@ if (suspendedTx == null) { throw new IllegalStateException("No transaction to resume!"); } + + if (!suspendedTx.suspended) { + throw new IllegalStateException("Transaction to resume needs to be suspended!"); + } + suspendedTx.suspended = false; setActiveTx(suspendedTx); } + /** + * Returns the state of the current transaction. + * + * @return state of the current transaction as decribed in the {@link Status} interface. + */ public synchronized int getTransactionState() { TxContext txContext = getActiveTx(); @@ -153,6 +209,18 @@ return txContext.status; } + /** + * 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 {@link #commitTransaction()} is called. + * Use {@link #rollbackTransaction()} to discard your changes. After calling either method there will be + * no transaction associated to the current thread any longer. + *

+ * Caution: Be careful to finally call one of those methods, + * as otherwise the transaction will lurk around for ever. + * + * @see #commitTransaction() + * @see #rollbackTransaction() + */ public synchronized void startTransaction() { if (getActiveTx() != null) { throw new IllegalStateException( @@ -161,6 +229,13 @@ setActiveTx(new TxContext()); } + /** + * Discards all changes made in the current transaction and deletes the association between the current thread + * and the transaction. + * + * @see #startTransaction() + * @see #commitTransaction() + */ public synchronized void rollbackTransaction() { TxContext txContext = getActiveTx(); @@ -174,6 +249,13 @@ setActiveTx(null); } + /** + * Commits all changes made in the current transaction and deletes the association between the current thread + * and the transaction. + * + * @see #startTransaction() + * @see #rollbackTransaction() + */ public synchronized void commitTransaction() { TxContext txContext = getActiveTx(); @@ -182,7 +264,7 @@ "Active thread " + Thread.currentThread() + " not associated with a transaction!"); } - if (txContext.rollbackOnly) { + if (txContext.status == Status.STATUS_MARKED_ROLLBACK) { throw new IllegalStateException("Active thread " + Thread.currentThread() + " is marked for rollback!"); } @@ -195,6 +277,9 @@ // Map methods // + /** + * @see Map#clear() + */ public synchronized void clear() { TxContext txContext = getActiveTx(); if (txContext != null) { @@ -204,6 +289,9 @@ } } + /** + * @see Map#size() + */ public synchronized int size() { TxContext txContext = getActiveTx(); if (txContext != null) { @@ -213,6 +301,9 @@ } } + /** + * @see Map#isEmpty() + */ public synchronized boolean isEmpty() { TxContext txContext = getActiveTx(); if (txContext == null) { @@ -222,10 +313,16 @@ } } + /** + * @see Map#containsKey(java.lang.Object) + */ public synchronized boolean containsKey(Object key) { return (get(key) != null); } + /** + * @see Map#containsValue(java.lang.Object) + */ public synchronized boolean containsValue(Object value) { TxContext txContext = getActiveTx(); @@ -236,6 +333,9 @@ } } + /** + * @see Map#values() + */ public synchronized Collection values() { TxContext txContext = getActiveTx(); @@ -254,6 +354,9 @@ } } + /** + * @see Map#putAll(java.util.Map) + */ public synchronized void putAll(Map map) { TxContext txContext = getActiveTx(); @@ -267,6 +370,9 @@ } } + /** + * @see Map#entrySet() + */ public synchronized Set entrySet() { TxContext txContext = getActiveTx(); if (txContext == null) { @@ -283,6 +389,9 @@ } } + /** + * @see Map#keySet() + */ public synchronized Set keySet() { TxContext txContext = getActiveTx(); @@ -293,6 +402,9 @@ } } + /** + * @see Map#get(java.lang.Object) + */ public synchronized Object get(Object key) { TxContext txContext = getActiveTx(); @@ -303,6 +415,9 @@ } } + /** + * @see Map#remove(java.lang.Object) + */ public synchronized Object remove(Object key) { TxContext txContext = getActiveTx(); @@ -315,6 +430,9 @@ } } + /** + * @see Map#put(java.lang.Object, java.lang.Object) + */ public synchronized Object put(Object key, Object value) { TxContext txContext = getActiveTx(); @@ -387,26 +505,25 @@ protected Set deletes; protected Map changes; protected Map adds; - protected boolean rollbackOnly; protected int status; protected boolean cleared; protected boolean readOnly; + protected boolean suspended = false; protected TxContext() { deletes = setFactory.createSet(); changes = mapFactory.createMap(); adds = mapFactory.createMap(); - rollbackOnly = false; status = Status.STATUS_ACTIVE; cleared = false; readOnly = true; } protected Set keys() { - Set keySet = new HashSet(); - if (!cleared) { - keySet.addAll(wrapped.keySet()); - } + Set keySet = new HashSet(); + if (!cleared) { + keySet.addAll(wrapped.keySet()); + } keySet.addAll(adds.keySet()); return keySet; } @@ -446,10 +563,10 @@ adds.put(key, value); } } catch (RuntimeException e) { - rollbackOnly = true; + status = Status.STATUS_MARKED_ROLLBACK; throw e; } catch (Error e) { - rollbackOnly = true; + status = Status.STATUS_MARKED_ROLLBACK; throw e; } } @@ -458,16 +575,16 @@ try { readOnly = false; - changes.remove(key); + changes.remove(key); adds.remove(key); if (wrapped.containsKey(key) && !cleared) { - deletes.add(key); + deletes.add(key); } } catch (RuntimeException e) { - rollbackOnly = true; + status = Status.STATUS_MARKED_ROLLBACK; throw e; } catch (Error e) { - rollbackOnly = true; + status = Status.STATUS_MARKED_ROLLBACK; throw e; } } @@ -496,8 +613,8 @@ wrapped.clear(); } - wrapped.putAll(changes); - wrapped.putAll(adds); + wrapped.putAll(changes); + wrapped.putAll(adds); for (Iterator it = deletes.iterator(); it.hasNext();) { Object key = it.next(); @@ -513,7 +630,7 @@ changes = null; mapFactory.disposeMap(adds); adds = null; + status = Status.STATUS_NO_TRANSACTION; } } - } --------------------------------------------------------------------- To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org For additional commands, e-mail: commons-dev-help@jakarta.apache.org