ozeigermann 2004/06/03 06:34:35
Modified: transaction/src/java/org/apache/commons/transaction/memory
TransactionalMapWrapper.java
Log:
- Fixed wrong calculation of size
- Made it more reuseable
Revision Changes Path
1.11 +224 -153
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.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- TransactionalMapWrapper.java 2 Jun 2004 21:54:04 -0000 1.10
+++ TransactionalMapWrapper.java 3 Jun 2004 13:34:35 -0000 1.11
@@ -25,6 +25,7 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
@@ -57,39 +58,44 @@
protected ThreadLocal activeTx = new ThreadLocal();
- protected MapFactory mapFactory;
- protected SetFactory setFactory;
+ protected MapFactory mapFactory;
+ protected SetFactory setFactory;
- /**
- * Creates a new transactional map wrapper. Temporary maps and sets to store
transactional
- * data will be instances of [EMAIL PROTECTED] HashMap} and [EMAIL PROTECTED]
HashSet}.
- *
- * @param wrapped map to be wrapped
- */
+ /**
+ * Creates a new transactional map wrapper. Temporary maps and sets to store
transactional
+ * data will be instances of [EMAIL PROTECTED] HashMap} and [EMAIL PROTECTED]
HashSet}.
+ *
+ * @param wrapped map to be wrapped
+ */
public TransactionalMapWrapper(Map wrapped) {
- this(wrapped, new HashMapFactory(), new HashSetFactory());
+ this(wrapped, new HashMapFactory(), new HashSetFactory());
}
- /**
- * Creates a new transactional map wrapper. Temporary maps and sets to store
transactional
- * data will be created and disposed using [EMAIL PROTECTED] MapFactory} and
[EMAIL PROTECTED] SetFactory}.
- *
- * @param wrapped map to be wrapped
- * @param mapFactory factory for temporary maps
- * @param setFactory factory for temporary sets
- */
- public TransactionalMapWrapper(Map wrapped, MapFactory mapFactory, SetFactory
setFactory) {
- this.wrapped = wrapped;
- this.mapFactory = mapFactory;
- this.setFactory = setFactory;
- }
+ /**
+ * Creates a new transactional map wrapper. Temporary maps and sets to store
transactional
+ * data will be created and disposed using [EMAIL PROTECTED] MapFactory} and
[EMAIL PROTECTED] SetFactory}.
+ *
+ * @param wrapped map to be wrapped
+ * @param mapFactory factory for temporary maps
+ * @param setFactory factory for temporary sets
+ */
+ public TransactionalMapWrapper(
+ Map wrapped,
+ MapFactory mapFactory,
+ SetFactory setFactory) {
+ this.wrapped = wrapped;
+ this.mapFactory = mapFactory;
+ this.setFactory = setFactory;
+ }
public synchronized boolean isReadOnly() {
TxContext txContext = getActiveTx();
if (txContext == null) {
throw new IllegalStateException(
- "Active thread " + Thread.currentThread() + " not associated with a
transaction!");
+ "Active thread "
+ + Thread.currentThread()
+ + " not associated with a transaction!");
}
return txContext.readOnly;
@@ -100,7 +106,9 @@
if (txContext == null) {
throw new IllegalStateException(
- "Active thread " + Thread.currentThread() + " not associated with a
transaction!");
+ "Active thread "
+ + Thread.currentThread()
+ + " not associated with a transaction!");
}
return txContext.rollbackOnly;
@@ -111,7 +119,9 @@
if (txContext == null) {
throw new IllegalStateException(
- "Active thread " + Thread.currentThread() + " not associated with a
transaction!");
+ "Active thread "
+ + Thread.currentThread()
+ + " not associated with a transaction!");
}
txContext.rollbackOnly = true;
@@ -123,7 +133,9 @@
if (txContext == null) {
throw new IllegalStateException(
- "Active thread " + Thread.currentThread() + " not associated with a
transaction!");
+ "Active thread "
+ + Thread.currentThread()
+ + " not associated with a transaction!");
}
setActiveTx(null);
@@ -133,7 +145,9 @@
public synchronized void resumeTransaction(TxContext suspendedTx) {
if (getActiveTx() != null) {
throw new IllegalStateException(
- "Active thread " + Thread.currentThread() + " already associated
with a transaction!");
+ "Active thread "
+ + Thread.currentThread()
+ + " already associated with a transaction!");
}
if (suspendedTx == null) {
@@ -155,7 +169,9 @@
public synchronized void startTransaction() {
if (getActiveTx() != null) {
throw new IllegalStateException(
- "Active thread " + Thread.currentThread() + " already associated
with a transaction!");
+ "Active thread "
+ + Thread.currentThread()
+ + " already associated with a transaction!");
}
setActiveTx(new TxContext());
}
@@ -165,12 +181,13 @@
if (txContext == null) {
throw new IllegalStateException(
- "Active thread " + Thread.currentThread() + " not associated with a
transaction!");
+ "Active thread "
+ + Thread.currentThread()
+ + " not associated with a transaction!");
}
// simply forget about tx
- mapFactory.disposeMap(txContext.changes);
- setFactory.disposeSet(txContext.deletes);
+ txContext.dispose();
setActiveTx(null);
}
@@ -179,30 +196,20 @@
if (txContext == null) {
throw new IllegalStateException(
- "Active thread " + Thread.currentThread() + " not associated with a
transaction!");
+ "Active thread "
+ + Thread.currentThread()
+ + " not associated with a transaction!");
}
if (txContext.rollbackOnly) {
- throw new IllegalStateException("Active thread " +
Thread.currentThread() + " is marked for rollback!");
- }
-
- if (txContext.cleared) {
- wrapped.clear();
- }
-
- for (Iterator it = txContext.changes.entrySet().iterator(); it.hasNext();) {
- Map.Entry entry = (Map.Entry) it.next();
- wrapped.put(entry.getKey(), entry.getValue());
- }
-
- for (Iterator it = txContext.deletes.iterator(); it.hasNext();) {
- Object key = it.next();
- wrapped.remove(key);
+ throw new IllegalStateException(
+ "Active thread "
+ + Thread.currentThread()
+ + " is marked for rollback!");
}
- // now forget about tx
- mapFactory.disposeMap(txContext.changes);
- setFactory.disposeSet(txContext.deletes);
+ txContext.merge();
+ txContext.dispose();
setActiveTx(null);
}
@@ -212,29 +219,20 @@
public synchronized void clear() {
TxContext txContext = getActiveTx();
- if (txContext == null) {
- wrapped.clear();
+ if (txContext != null) {
+ txContext.clear();
} else {
- txContext.readOnly = false;
- txContext.cleared = true;
- txContext.deletes.clear();
- txContext.changes.clear();
+ wrapped.clear();
}
}
public synchronized int size() {
- int size = wrapped.size();
-
TxContext txContext = getActiveTx();
if (txContext != null) {
- size -= txContext.deletes.size();
- if (txContext.cleared) {
- size = 0;
- }
- size += txContext.changes.size();
+ return txContext.size();
+ } else {
+ return wrapped.size();
}
- return size;
-
}
public synchronized boolean isEmpty() {
@@ -247,15 +245,7 @@
}
public synchronized boolean containsKey(Object key) {
- TxContext txContext = getActiveTx();
-
- if (txContext == null) {
- return wrapped.containsKey(key);
- } else {
- return (
- (!txContext.cleared && wrapped.containsKey(key) &&
!txContext.deletes.contains(key))
- || txContext.changes.containsKey(key));
- }
+ return (get(key) != null);
}
public synchronized boolean containsValue(Object value) {
@@ -292,21 +282,13 @@
if (txContext == null) {
wrapped.putAll(map);
} else {
- try {
- txContext.readOnly = false;
- for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
- Map.Entry entry = (Map.Entry) it.next();
- txContext.changes.put(entry.getKey(), entry.getValue());
- txContext.deletes.remove(entry.getKey());
- }
- } catch (RuntimeException e) {
- txContext.rollbackOnly = true;
- throw e;
- } catch (Error e) {
- txContext.rollbackOnly = true;
- throw e;
+ for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
+ Map.Entry entry = (Map.Entry) it.next();
+ txContext.put(
+ entry.getKey(),
+ entry.getValue(),
+ wrapped.get(entry.getKey()));
}
-
}
}
@@ -315,10 +297,9 @@
if (txContext == null) {
return wrapped.entrySet();
} else {
- Set entrySet = setFactory.createSet();
- Set keySet = keySet();
+ Set entrySet = new HashSet();
// XXX expensive :(
- for (Iterator it = keySet.iterator(); it.hasNext();) {
+ for (Iterator it = keySet().iterator(); it.hasNext();) {
Object key = it.next();
Object value = get(key);
entrySet.add(new HashEntry(key, value));
@@ -328,16 +309,12 @@
}
public synchronized Set keySet() {
-
TxContext txContext = getActiveTx();
if (txContext == null) {
return wrapped.keySet();
} else {
- Set keySet = (txContext.cleared ? setFactory.createSet() :
wrapped.keySet());
- keySet.removeAll(txContext.deletes);
- keySet.addAll(txContext.changes.keySet());
- return keySet;
+ return txContext.keys();
}
}
@@ -345,72 +322,35 @@
TxContext txContext = getActiveTx();
if (txContext != null) {
- if (txContext.deletes.contains(key)) {
- // reflects that entry has been deleted in this tx
- return null;
- }
-
- Object changed = txContext.changes.get(key);
- if (changed != null) {
- // if object has been changed in this tx, get the local one
- return changed;
- }
- }
-
- if (txContext == null || !txContext.cleared) {
- // as fall back return value from global cache (if present)
+ return txContext.get(key);
+ } else {
return wrapped.get(key);
}
- return null;
}
public synchronized Object remove(Object key) {
TxContext txContext = getActiveTx();
- Object old = null;
-
if (txContext == null) {
- old = wrapped.remove(key);
+ return wrapped.remove(key);
} else {
- old = get(key);
- try {
- txContext.readOnly = false;
- txContext.changes.remove(key);
- txContext.deletes.add(key);
- } catch (RuntimeException e) {
- txContext.rollbackOnly = true;
- throw e;
- } catch (Error e) {
- txContext.rollbackOnly = true;
- throw e;
- }
+ Object oldValue = get(key);
+ txContext.remove(key);
+ return oldValue;
}
-
- return old;
}
public synchronized Object put(Object key, Object value) {
TxContext txContext = getActiveTx();
- Object old = get(key);
-
if (txContext == null) {
- wrapped.put(key, value);
+ return wrapped.put(key, value);
} else {
- try {
- txContext.readOnly = false;
- txContext.deletes.remove(key);
- txContext.changes.put(key, value);
- } catch (RuntimeException e) {
- txContext.rollbackOnly = true;
- throw e;
- } catch (Error e) {
- txContext.rollbackOnly = true;
- throw e;
- }
+ Object oldValue = get(key);
+ txContext.put(key, value, oldValue);
+ return oldValue;
}
- return old;
}
protected TxContext getActiveTx() {
@@ -455,22 +395,33 @@
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()));
+ 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());
+ return (getKey() == null ? 0 : getKey().hashCode())
+ ^ (getValue() == null ? 0 : getValue().hashCode());
}
public String toString() {
- return new
StringBuffer().append(getKey()).append('=').append(getValue()).toString();
+ return new StringBuffer()
+ .append(getKey())
+ .append('=')
+ .append(getValue())
+ .toString();
}
}
public class TxContext {
- protected final Set deletes;
- protected final Map changes;
+ protected Set deletes;
+ protected Map changes;
+ protected Map adds;
protected boolean rollbackOnly;
protected int status;
protected boolean cleared;
@@ -479,10 +430,130 @@
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 = (cleared ? new HashSet() : wrapped.keySet());
+ keySet.removeAll(deletes);
+ keySet.addAll(adds.keySet());
+ return keySet;
+
+ }
+
+ protected Object get(Object key) {
+
+ if (deletes.contains(key)) {
+ // reflects that entry has been deleted in this tx
+ return null;
+ }
+
+ Object changed = changes.get(key);
+ if (changed != null) {
+ return changed;
+ }
+
+ Object added = adds.get(key);
+ if (added != null) {
+ return added;
+ }
+
+ if (cleared) {
+ return null;
+ } else {
+ // not modified in this tx
+ return wrapped.get(key);
+ }
+ }
+
+ protected void put(Object key, Object value, Object oldValue) {
+ try {
+ readOnly = false;
+ deletes.remove(key);
+ if (oldValue != null) {
+ changes.put(key, value);
+ } else {
+ adds.put(key, value);
+ }
+ } catch (RuntimeException e) {
+ rollbackOnly = true;
+ throw e;
+ } catch (Error e) {
+ rollbackOnly = true;
+ throw e;
+ }
+ }
+
+ protected void remove(Object key) {
+
+ try {
+ readOnly = false;
+ adds.remove(key);
+ changes.remove(key);
+ deletes.add(key);
+ } catch (RuntimeException e) {
+ rollbackOnly = true;
+ throw e;
+ } catch (Error e) {
+ rollbackOnly = true;
+ throw e;
+ }
+ }
+
+ protected int size() {
+ int size = (cleared ? 0 : wrapped.size());
+
+ size -= deletes.size();
+ size += adds.size();
+
+ return size;
+ }
+
+ protected void clear() {
+ readOnly = false;
+ cleared = true;
+ deletes.clear();
+ changes.clear();
+ adds.clear();
+ }
+
+ protected void merge() {
+ if (!readOnly) {
+
+ if (cleared) {
+ wrapped.clear();
+ }
+
+ for (Iterator it = changes.entrySet().iterator();
+ it.hasNext();
+ ) {
+ Map.Entry entry = (Map.Entry) it.next();
+ wrapped.put(entry.getKey(), entry.getValue());
+ }
+
+ for (Iterator it = adds.entrySet().iterator(); it.hasNext();) {
+ Map.Entry entry = (Map.Entry) it.next();
+ wrapped.put(entry.getKey(), entry.getValue());
+ }
+
+ for (Iterator it = deletes.iterator(); it.hasNext();) {
+ Object key = it.next();
+ wrapped.remove(key);
+ }
+ }
+ }
+
+ protected void dispose() {
+ setFactory.disposeSet(deletes);
+ deletes = null;
+ mapFactory.disposeMap(changes);
+ changes = null;
+ mapFactory.disposeMap(adds);
+ adds = null;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]