You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by oz...@apache.org on 2004/05/17 15:26:06 UTC

cvs commit: jakarta-commons-sandbox/transaction/src/java/org/apache/commons/transaction/memory TransactionalMapWrapper.java TxLRUObjectCache.java ByteSizeLimitedObjectCache.java

ozeigermann    2004/05/17 06:26:06

  Added:       transaction/src/java/org/apache/commons/transaction/memory
                        TransactionalMapWrapper.java
  Removed:     transaction/src/java/org/apache/commons/transaction/memory
                        TxLRUObjectCache.java
                        ByteSizeLimitedObjectCache.java
  Log:
  Replaced working base with transactional map wrapper
  
  Revision  Changes    Path
  1.1                  jakarta-commons-sandbox/transaction/src/java/org/apache/commons/transaction/memory/TransactionalMapWrapper.java
  
  Index: TransactionalMapWrapper.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons-sandbox/transaction/src/java/org/apache/commons/transaction/memory/TransactionalMapWrapper.java,v 1.1 2004/05/17 13:26:06 ozeigermann Exp $
   * $Revision: 1.1 $
   * $Date: 2004/05/17 13:26:06 $
   *
   * ====================================================================
   *
   * Copyright 1999-2002 The Apache Software Foundation 
   *
   * Licensed 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.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;
  
  /**
   * Wrapper that adds transactional control to all kinds of maps that implement the {@link Map} interface.
   * 
   * @author <a href="mailto:ozeigermann@apache.org">Oliver Zeigermann</a>
   * @version $Revision: 1.1 $
   */
  public class TransactionalMapWrapper implements Map {
  
      protected Map wrapped;
  
      protected Map txBranches = new HashMap();
  
      protected ThreadLocal activeTx = new ThreadLocal();
  
      protected boolean includeBranch = true;
  
      public TransactionalMapWrapper(Map wrapped) {
          this.wrapped = wrapped;
      }
  
      public synchronized void startTransaction() {
          if (getActiveTx() != null) {
              throw new IllegalStateException(
                  "Active thread " + Thread.currentThread() + " already associated with a transaction!");
          }
          activeTx.set(new TxContext());
      }
  
      public synchronized void rollbackTransaction() {
          TxContext txContext = getActiveTx();
  
          if (txContext == null) {
              throw new IllegalStateException(
                  "Active thread " + Thread.currentThread() + " not associated with a transaction!");
          }
  
          // simply forget about tx
          activeTx.set(null);
      }
  
      public synchronized void commitTransaction() {
          TxContext txContext = getActiveTx();
  
          if (txContext == null) {
              throw new IllegalStateException(
                  "Active thread " + Thread.currentThread() + " not associated with a transaction!");
          }
  
          for (Iterator it = txContext.getChanges().entrySet().iterator(); it.hasNext();) {
              Map.Entry entry = (Map.Entry) it.next();
              wrapped.put(entry.getKey(), entry.getValue());
          }
  
          for (Iterator it = txContext.getDeletes().iterator(); it.hasNext();) {
              Object key = it.next();
              wrapped.remove(key);
          }
  
          // now forget about tx
          activeTx.set(null);
      }
  
      //
      // Map methods
      // 
  
      public synchronized void clear() {
          wrapped.clear();
          activeTx.set(null);
      }
  
      public synchronized int size() {
          int size = wrapped.size();
  
          TxContext txContext = getActiveTx();
          if (txContext != null) {
              size += txContext.getChanges().size();
              size -= txContext.deletes.size();
          }
          return size;
  
      }
  
      public synchronized boolean isEmpty() {
          TxContext txContext = getActiveTx();
          if (txContext != null) {
              return wrapped.isEmpty();
          } else {
              return (size() > 0);
          }
      }
  
      public synchronized boolean containsKey(Object key) {
          TxContext txContext = getActiveTx();
  
          if (txContext == null) {
              return wrapped.containsKey(key);
          } else {
              return (!txContext.getDeletes().contains(key) && txContext.getChanges().containsKey(key));
          }
      }
  
      public synchronized boolean containsValue(Object value) {
          TxContext txContext = getActiveTx();
  
          if (txContext == null) {
              return wrapped.containsValue(value);
          } else {
              return values().contains(value);
          }
      }
  
      public synchronized Collection values() {
  
          TxContext 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);
                  values.add(value);
              }
              return values;
          }
      }
  
      public synchronized void putAll(Map map) {
          TxContext txContext = getActiveTx();
  
          if (txContext == null) {
              wrapped.putAll(map);
          } else {
              for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
                  Map.Entry entry = (Map.Entry) it.next();
                  txContext.getChanges().put(entry.getKey(), entry.getValue());
                  txContext.getDeletes().remove(entry.getKey());
              }
  
          }
      }
  
      public synchronized Set entrySet() {
          TxContext txContext = getActiveTx();
          if (txContext == null) {
              return wrapped.entrySet();
          } else {
              Set entrySet = new HashSet();
              Set keySet = keySet();
              // XXX expensive :(
              for (Iterator it = keySet.iterator(); it.hasNext();) {
                  Object key = it.next();
                  Object value = get(key);
                  entrySet.add(new HashEntry(key, value));
              }
              return entrySet;
          }
      }
  
      public synchronized Set keySet() {
          Set keySet = wrapped.keySet();
  
          TxContext txContext = getActiveTx();
          if (txContext != null) {
              Set deleteSet = txContext.getDeletes();
              keySet.removeAll(deleteSet);
              Set changeSet = txContext.getChanges().keySet();
              keySet.addAll(changeSet);
          }
          return keySet;
      }
  
      public synchronized Object get(Object key) {
          TxContext txContext = getActiveTx();
  
          if (txContext != null) {
              if (txContext.getDeletes().contains(key)) {
                  // reflects that entry has been deleted in this tx 
                  return null;
              }
  
              Object changed = txContext.getChanges().get(key);
              if (changed != null) {
                  // if object has been changed in this tx, get the local one
                  return changed;
              }
          }
  
          // as fall back return value from global cache (if present)
          return wrapped.get(key);
      }
  
      public synchronized Object remove(Object key) {
          TxContext txContext = getActiveTx();
  
          Object old = null;
  
          if (txContext == null) {
              old = wrapped.remove(key);
          } else {
              old = txContext.getChanges().remove(key);
              txContext.getDeletes().add(key);
          }
  
          return old;
      }
  
      public synchronized Object put(Object key, Object value) {
          TxContext txContext = getActiveTx();
  
          Object old = get(key);
  
          if (txContext == null) {
              wrapped.put(key, value);
          } else {
              txContext.getDeletes().remove(key);
              txContext.getChanges().put(key, value);
          }
  
          return old;
      }
  
      protected TxContext getActiveTx() {
          return (TxContext) activeTx.get();
      }
  
      protected static class TxContext {
          protected final Set deletes;
          protected final Map changes;
  
          public TxContext() {
              deletes = new HashSet();
              changes = new HashMap();
          }
  
          public Map getChanges() {
              return changes;
          }
  
          public Set getDeletes() {
              return deletes;
          }
      }
  
      // 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();
          }
      }
  
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org