Clover coverage report - ActiveSpace - 1.0-SNAPSHOT
Coverage timestamp: Sat Oct 23 2004 15:04:04 BST
file stats: LOC: 341   Methods: 38
NCLOC: 239   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
ThreadCache.java 52% 64.4% 73.7% 63%
coverage coverage
 1   
 /**
 2   
  * 
 3   
  * Copyright 2004 Protique Ltd
 4   
  * 
 5   
  * Licensed under the Apache License, Version 2.0 (the "License"); 
 6   
  * you may not use this file except in compliance with the License. 
 7   
  * You may obtain a copy of the License at 
 8   
  * 
 9   
  * http://www.apache.org/licenses/LICENSE-2.0
 10   
  * 
 11   
  * Unless required by applicable law or agreed to in writing, software
 12   
  * distributed under the License is distributed on an "AS IS" BASIS, 
 13   
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 14   
  * See the License for the specific language governing permissions and 
 15   
  * limitations under the License. 
 16   
  * 
 17   
  **/
 18   
 package org.codehaus.activespace.cache.impl;
 19   
 
 20   
 import org.apache.commons.logging.Log;
 21   
 import org.apache.commons.logging.LogFactory;
 22   
 import org.codehaus.activespace.cache.TransactionException;
 23   
 
 24   
 import javax.cache.Cache;
 25   
 import javax.cache.CacheEntry;
 26   
 import javax.cache.CacheException;
 27   
 import java.util.Collection;
 28   
 import java.util.IdentityHashMap;
 29   
 import java.util.Iterator;
 30   
 import java.util.Map;
 31   
 import java.util.Set;
 32   
 
 33   
 /**
 34   
  * This class is only used by one thread at any point in time and
 35   
  * provides a thread local view of a transactional cache which implements
 36   
  * the <i>READ_COMMITTED</i> isolation level in that there are no dirty reads
 37   
  * and only committed data is read but that the data can change, during a transaction
 38   
  * as concurrent transactions in other processes and threads commit.
 39   
  *
 40   
  * @version $Revision: 1.9 $
 41   
  */
 42   
 public class ThreadCache extends CacheFacade {
 43   
     private static final Log log = LogFactory.getLog(ThreadCache.class);
 44   
 
 45   
     private Cache backingCache;
 46   
     private Map localChanges;
 47   
     private Map localRemoves;
 48   
     private boolean clear;
 49   
     private String name;
 50   
     private String ID;
 51   
     private TransactionException commitException;
 52   
 
 53  7
     public ThreadCache(Cache behindCache) {
 54  7
         init(behindCache, createMap(), createMap());
 55   
     }
 56   
 
 57  0
     public ThreadCache(Cache behindCache, Map localChanges, Map localRemoves) {
 58  0
         init(behindCache, localChanges, localRemoves);
 59   
     }
 60   
 
 61  7
     private void init(Cache behindCache, Map localChanges, Map localRemoves) {
 62  7
         if (behindCache == null) {
 63  0
             throw new IllegalArgumentException("A NULL cache is not allowed");
 64   
         }
 65  7
         this.backingCache = behindCache;
 66  7
         this.localChanges = localChanges;
 67  7
         this.localRemoves = localRemoves;
 68   
     }
 69   
 
 70  7
     public String toString() {
 71  7
         Map map = (clear) ? new IdentityHashMap() : new IdentityHashMap(backingCache);
 72  7
         for (Iterator iter = localRemoves.keySet().iterator(); iter.hasNext();) {
 73  0
             map.remove(iter.next());
 74   
         }
 75  7
         for (Iterator iter = localChanges.entrySet().iterator(); iter.hasNext();) {
 76  0
             Entry entry = (Entry) iter.next();
 77  0
             Object key = entry.getKey();
 78  0
             VersionedValue change = (VersionedValue) entry.getValue();
 79  0
             map.put(key, change.getValue());
 80   
         }
 81  7
         return map.toString();
 82   
     }
 83   
 
 84   
     /**
 85   
      * Returns the unique ID of this cache
 86   
      */
 87  0
     public String getID() {
 88  0
         return ID;
 89   
     }
 90   
 
 91  7
     public void setID(String ID) {
 92  7
         this.ID = ID;
 93   
     }
 94   
 
 95   
     /**
 96   
      * Returns whether or not this cache has been modified in the transaction
 97   
      */
 98  56
     public boolean isModifiedInTransaction() {
 99  56
         return clear || !localChanges.isEmpty() || !localRemoves.isEmpty();
 100   
     }
 101   
 
 102  18
     public TransactionalCacheCommand createTransactionCommand() {
 103  18
         if (!clear && localChanges.isEmpty() && localRemoves.isEmpty()) {
 104  0
             return null;
 105   
         }
 106  18
         return new TransactionalCacheCommand(getName(), localChanges, localRemoves, clear, ID);
 107   
     }
 108   
 
 109  18
     public String getName() {
 110  18
         return name;
 111   
     }
 112   
 
 113  7
     public void setName(String name) {
 114  7
         this.name = name;
 115   
     }
 116   
 
 117   
 
 118   
     /**
 119   
      * Throws any runtime exceptions which occurred on a background
 120   
      * thread due to the current transaction commit.
 121   
      */
 122  18
     public void handleCommitException() {
 123  18
         RuntimeException e = commitException;
 124  18
         commitException = null;
 125  18
         if (e != null) {
 126   
             // create nested exception to preserve all stack traces
 127  6
             throw new TransactionException(e);
 128   
         }
 129   
     }
 130   
 
 131   
     /**
 132   
      * Passes in a runtime exception from the cache updating thread
 133   
      * if an exception should be passed to the caller thread
 134   
      */
 135  18
     public void onCommitException(TransactionException e) {
 136  18
         this.commitException = e;
 137   
     }
 138   
 
 139   
     /**
 140   
      * Called by the transaction manager after a commit or rollback
 141   
      */
 142  20
     public void resetLocalChanges() {
 143   
         // lets always instantiate new objects to avoid
 144   
         // updating existing transaction logs
 145  20
         localChanges = createMap();
 146  20
         localRemoves = createMap();
 147  20
         clear = false;
 148   
     }
 149   
 
 150  0
     public void clear() {
 151  0
         resetLocalChanges();
 152  0
         clear = true;
 153   
     }
 154   
 
 155  8
     public boolean containsKey(Object key) {
 156  8
         if (clear) {
 157  0
             return localChangesContainsKey(key);
 158   
         }
 159  8
         return localChangesContainsKey(key) || (super.containsKey(key) && !localRemoves.containsKey(key));
 160   
     }
 161   
 
 162  4
     public boolean containsValue(Object value) {
 163  4
         if (clear) {
 164  0
             return localChangesContainsValue(value);
 165   
         }
 166   
         else {
 167  4
             if (localChangesContainsValue(value)) {
 168  2
                 return true;
 169   
             }
 170   
             else {
 171  4
                 for (Iterator iter = getDelegate().entrySet().iterator(); iter.hasNext();) {
 172  4
                     Entry entry = (Entry) iter.next();
 173  4
                     if (entry.getValue().equals(value) && !localRemoves.containsKey(entry.getKey())) {
 174  2
                         return true;
 175   
                     }
 176   
                 }
 177  0
                 return false;
 178   
             }
 179   
         }
 180   
     }
 181   
 
 182  22
     public Object get(Object key) {
 183  22
         if (clear) {
 184  0
             return getLocalChangeValue(key);
 185   
         }
 186   
         else {
 187  22
             Object answer = getLocalChangeValue(key);
 188  22
             if (answer == null && !localRemoves.containsKey(key)) {
 189  22
                 answer = super.get(key);
 190   
             }
 191  22
             return answer;
 192   
         }
 193   
     }
 194   
 
 195  0
     public Map getAll(Collection keys) throws CacheException {
 196  0
         Map answer = createMap();
 197  0
         for (Iterator iter = keys.iterator(); iter.hasNext();) {
 198  0
             Object key = iter.next();
 199  0
             answer.put(key, get(key));
 200   
         }
 201  0
         return answer;
 202   
     }
 203   
 
 204   
 
 205  22
     public CacheEntry getCacheEntry(Object key) {
 206  22
         if (clear || localRemoves.containsKey(key)) {
 207  0
             return null;
 208   
         }
 209   
         // lets return the old entry if we've done updates to the data
 210  22
         return super.getCacheEntry(key);
 211   
     }
 212   
 
 213  11
     public boolean isEmpty() {
 214  11
         if (clear) {
 215  0
             return localChanges.isEmpty();
 216   
         }
 217   
         else {
 218  11
             return localChanges.isEmpty() && (super.isEmpty() || super.size() == localRemoves.size());
 219   
         }
 220   
     }
 221   
 
 222  0
     public Object peek(Object key) {
 223  0
         if (clear) {
 224  0
             return getLocalChangeValue(key);
 225   
         }
 226   
         else {
 227  0
             Object answer = getLocalChangeValue(key);
 228  0
             if (answer == null && !localRemoves.containsKey(key)) {
 229  0
                 answer = super.peek(key);
 230   
             }
 231  0
             return answer;
 232   
         }
 233   
     }
 234   
 
 235  17
     public int size() {
 236  17
         if (clear) {
 237  0
             return localChanges.size();
 238   
         }
 239   
         else {
 240   
             // TODO lets guess though this could be wrong
 241   
             // as it does not take into account updates
 242  17
             return localChanges.size() + super.size() - localRemoves.size();
 243   
         }
 244   
     }
 245   
 
 246  0
     public void putAll(Map map) {
 247  0
         for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
 248  0
             Entry entry = (Entry) iter.next();
 249  0
             localChangesPut(entry.getKey(), entry.getValue());
 250   
         }
 251   
     }
 252   
 
 253  20
     public Object put(Object key, Object value) {
 254  20
         Object answer = getLocalChangeValue(key);
 255  20
         if (answer == null) {
 256  20
             answer = getDelegate().get(key);
 257   
         }
 258  20
         localChangesPut(key, value);
 259  20
         return answer;
 260   
     }
 261   
 
 262   
 
 263  2
     public Object remove(Object key) {
 264  2
         if (localRemoves.containsKey(key)) {
 265  0
             return null;
 266   
         }
 267   
         else {
 268  2
             Object version = getVersion(key);
 269  2
             localRemove(key, version);
 270  2
             return getDelegate().get(key);
 271   
         }
 272   
     }
 273   
 
 274  0
     public Set entrySet() {
 275   
         // TODO
 276  0
         throw createUnsupportedException();
 277   
     }
 278   
 
 279  0
     public Set keySet() {
 280   
         // TODO
 281  0
         throw createUnsupportedException();
 282   
     }
 283   
 
 284  0
     public Collection values() {
 285   
         // TODO
 286  0
         throw createUnsupportedException();
 287   
     }
 288   
 
 289   
     // Implementation methods
 290   
     //-------------------------------------------------------------------------
 291  118
     protected Cache getDelegate() {
 292  118
         return backingCache;
 293   
     }
 294   
 
 295  20
     protected void localChangesPut(Object key, Object value) {
 296  20
         localChanges.put(key, createVersionedValue(key, value));
 297   
     }
 298   
 
 299  8
     protected boolean localChangesContainsKey(Object key) {
 300  8
         return localChanges.containsKey(key);
 301   
     }
 302   
 
 303  4
     protected boolean localChangesContainsValue(Object value) {
 304  4
         for (Iterator iter = localChanges.values().iterator(); iter.hasNext();) {
 305  4
             VersionedValue change = (VersionedValue) iter.next();
 306  4
             if (value.equals(change.getValue())) {
 307  2
                 return true;
 308   
             }
 309   
         }
 310  2
         return false;
 311   
     }
 312   
 
 313  2
     protected void localRemove(Object key, Object version) {
 314  2
         localRemoves.put(key, version);
 315   
     }
 316   
 
 317  42
     protected Object getLocalChangeValue(Object key) {
 318  42
         VersionedValue change = (VersionedValue) localChanges.get(key);
 319  42
         return (change != null) ? change.getValue() : null;
 320   
     }
 321   
 
 322  20
     protected VersionedValue createVersionedValue(Object key, Object value) {
 323  20
         Object version = getVersion(key);
 324  20
         return new VersionedValue(value, version);
 325   
     }
 326   
 
 327  22
     protected Object getVersion(Object key) {
 328  22
         return JCacheHelper.getEntryVersion(this, key);
 329   
     }
 330   
 
 331  54
     protected Map createMap() {
 332   
         // lets maintain order so changes are made in the correct order
 333  54
         return new IdentityHashMap();
 334   
     }
 335   
 
 336  0
     protected UnsupportedOperationException createUnsupportedException() {
 337  0
         return new UnsupportedOperationException("This operation is not yet supported for the TransactionalCache");
 338   
     }
 339   
 }
 340   
 
 341