Clover coverage report -
Coverage timestamp: Thu Jul 5 2007 20:02:32 EDT
file stats: LOC: 451   Methods: 28
NCLOC: 283   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
ChainingCacheLoader.java 75% 87.3% 85.7% 84.5%
coverage coverage
 1    /*
 2    * JBoss, Home of Professional Open Source
 3    *
 4    * Distributable under LGPL license.
 5    * See terms of license at gnu.org.
 6    */
 7    package org.jboss.cache.loader;
 8   
 9    import org.jboss.cache.Fqn;
 10    import org.jboss.cache.Modification;
 11    import org.jboss.cache.RegionManager;
 12    import org.jboss.cache.config.CacheLoaderConfig;
 13    import org.jboss.cache.config.CacheLoaderConfig.IndividualCacheLoaderConfig;
 14   
 15    import java.io.ObjectInputStream;
 16    import java.io.ObjectOutputStream;
 17    import java.util.ArrayList;
 18    import java.util.Collections;
 19    import java.util.Iterator;
 20    import java.util.List;
 21    import java.util.Map;
 22    import java.util.Set;
 23   
 24    /**
 25    * This decorator is used whenever more than one cache loader is configured. READ operations are directed to
 26    * each of the cache loaders (in the order which they were configured) until a non-null (or non-empty in the case
 27    * of retrieving collection objects) result is achieved.
 28    * <p/>
 29    * WRITE operations are propagated to ALL registered cacheloaders that specified set ignoreModifications to false.
 30    *
 31    * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
 32    */
 33    public class ChainingCacheLoader extends AbstractCacheLoader
 34    {
 35    private final List<CacheLoader> cacheLoaders = new ArrayList<CacheLoader>(2);
 36    private final List<CacheLoader> writeCacheLoaders = new ArrayList<CacheLoader>(2);
 37    private final List<CacheLoaderConfig.IndividualCacheLoaderConfig> cacheLoaderConfigs = new ArrayList<CacheLoaderConfig.IndividualCacheLoaderConfig>(2);
 38   
 39    /**
 40    * Sets the configuration. Will be called before {@link #create()} and {@link #start()}
 41    *
 42    * @param config ignored
 43    */
 44  0 public void setConfig(IndividualCacheLoaderConfig config)
 45    {
 46    // don't do much here?
 47    }
 48   
 49  0 public IndividualCacheLoaderConfig getConfig()
 50    {
 51  0 return null;
 52    }
 53   
 54    /**
 55    * Returns a list of children names, all names are <em>relative</em>. Returns null if the parent node is not found.
 56    * The returned set must not be modified, e.g. use Collections.unmodifiableSet(s) to return the result
 57    *
 58    * @param fqn The FQN of the parent
 59    * @return Set<?>. A list of children. Returns null if no children nodes are present, or the parent is
 60    * not present
 61    */
 62  2044 public Set<?> getChildrenNames(Fqn fqn) throws Exception
 63    {
 64  2044 Set<?> answer = null;
 65  2044 for (CacheLoader l : cacheLoaders)
 66    {
 67  4056 answer = l.getChildrenNames(fqn);
 68  32 if (answer != null && answer.size() > 0) break;
 69    }
 70  2044 return answer;
 71    }
 72   
 73    /**
 74    * Returns all keys and values from the persistent store, given a fully qualified name
 75    *
 76    * @param name
 77    * @return Map<Object,Object> of keys and values for the given node. Returns null if the node was not found, or
 78    * if the node has no attributes
 79    * @throws Exception
 80    */
 81  2342 public Map get(Fqn name) throws Exception
 82    {
 83  2342 Map answer = null;
 84  2342 for (CacheLoader l : cacheLoaders)
 85    {
 86  2413 answer = l.get(name);
 87  2279 if (answer != null) break;
 88    }
 89  2342 return answer;
 90    }
 91   
 92    /**
 93    * Checks whether the CacheLoader has a node with Fqn
 94    *
 95    * @param name
 96    * @return True if node exists, false otherwise
 97    */
 98  68 public boolean exists(Fqn name) throws Exception
 99    {
 100  68 boolean answer = false;
 101  68 for (CacheLoader l : cacheLoaders)
 102    {
 103  100 answer = l.exists(name);
 104  36 if (answer) break;
 105    }
 106  68 return answer;
 107    }
 108   
 109    /**
 110    * Inserts key and value into the attributes hashmap of the given node. If the node does not exist, all
 111    * parent nodes from the root down are created automatically. Returns the old value
 112    */
 113  2146 public Object put(Fqn name, Object key, Object value) throws Exception
 114    {
 115  2146 Object answer = null;
 116  2146 Iterator<CacheLoader> i = writeCacheLoaders.iterator();
 117  2146 boolean isFirst = true;
 118  2146 while (i.hasNext())
 119    {
 120  4291 CacheLoader l = i.next();
 121  4291 Object tAnswer = l.put(name, key, value);
 122  4291 if (isFirst)
 123    {
 124  2146 answer = tAnswer;
 125  2146 isFirst = false;
 126    }
 127   
 128    }
 129  2146 return answer;
 130    }
 131   
 132    /**
 133    * Inserts all elements of attributes into the attributes hashmap of the given node, overwriting existing
 134    * attributes, but not clearing the existing hashmap before insertion (making it a union of existing and
 135    * new attributes)
 136    * If the node does not exist, all parent nodes from the root down are created automatically
 137    *
 138    * @param name The fully qualified name of the node
 139    * @param attributes A Map of attributes. Can be null
 140    */
 141  2030 public void put(Fqn name, Map attributes) throws Exception
 142    {
 143  2030 for (CacheLoader l : writeCacheLoaders)
 144    {
 145  4060 l.put(name, attributes);
 146    }
 147    }
 148   
 149    /**
 150    * Inserts all modifications to the backend store. Overwrite whatever is already in
 151    * the datastore.
 152    *
 153    * @param modifications A List<Modification> of modifications
 154    * @throws Exception
 155    */
 156  57 public void put(List<Modification> modifications) throws Exception
 157    {
 158  57 for (CacheLoader l : writeCacheLoaders)
 159    {
 160  114 l.put(modifications);
 161    }
 162    }
 163   
 164    /**
 165    * Removes the given key and value from the attributes of the given node. No-op if node doesn't exist.
 166    * Returns the first response from the loader chain.
 167    */
 168  2024 public Object remove(Fqn name, Object key) throws Exception
 169    {
 170  2024 Object answer = null;
 171  2024 Iterator<CacheLoader> i = writeCacheLoaders.iterator();
 172  2024 boolean isFirst = true;
 173  2024 while (i.hasNext())
 174    {
 175  4048 CacheLoader l = i.next();
 176  4048 Object tAnswer = l.remove(name, key);
 177  4048 if (isFirst)
 178    {
 179  2024 answer = tAnswer;
 180  2024 isFirst = false;
 181    }
 182    }
 183  2024 return answer;
 184    }
 185   
 186    /**
 187    * Removes the given node. If the node is the root of a subtree, this will recursively remove all subnodes,
 188    * depth-first
 189    */
 190  2163 public void remove(Fqn name) throws Exception
 191    {
 192  4322 for (CacheLoader l : writeCacheLoaders) l.remove(name);
 193    }
 194   
 195    /**
 196    * Removes all attributes from a given node, but doesn't delete the node itself
 197    *
 198    * @param name
 199    * @throws Exception
 200    */
 201  3 public void removeData(Fqn name) throws Exception
 202    {
 203  3 for (CacheLoader l : writeCacheLoaders)
 204    {
 205  6 l.removeData(name);
 206    }
 207    }
 208   
 209    /**
 210    * Prepare the modifications. For example, for a DB-based CacheLoader:
 211    * <ol>
 212    * <li>Create a local (JDBC) transaction
 213    * <li>Associate the local transaction with <code>tx</code> (tx is the key)
 214    * <li>Execute the coresponding SQL statements against the DB (statements derived from modifications)
 215    * </ol>
 216    * For non-transactional CacheLoader (e.g. file-based), this could be a null operation
 217    *
 218    * @param tx The transaction, just used as a hashmap key
 219    * @param modifications List<Modification>, a list of all modifications within the given transaction
 220    * @param one_phase Persist immediately and (for example) commit the local JDBC transaction as well. When true,
 221    * we won't get a {@link #commit(Object)} or {@link #rollback(Object)} method call later
 222    * @throws Exception
 223    */
 224  8 public void prepare(Object tx, List modifications, boolean one_phase) throws Exception
 225    {
 226  8 for (CacheLoader l : writeCacheLoaders)
 227    {
 228  15 l.prepare(tx, modifications, one_phase);
 229    }
 230    }
 231   
 232    /**
 233    * Commit the transaction. A DB-based CacheLoader would look up the local JDBC transaction asociated
 234    * with <code>tx</code> and commit that transaction<br/>
 235    * Non-transactional CacheLoaders could simply write the data that was previously saved transiently under the
 236    * given <code>tx</code> key, to (for example) a file system (note this only holds if the previous prepare() did
 237    * not define one_phase=true
 238    *
 239    * @param tx
 240    */
 241  5 public void commit(Object tx) throws Exception
 242    {
 243  5 for (CacheLoader l : writeCacheLoaders)
 244    {
 245  9 l.commit(tx);
 246    }
 247    }
 248   
 249    /**
 250    * Roll the transaction back. A DB-based CacheLoader would look up the local JDBC transaction asociated
 251    * with <code>tx</code> and roll back that transaction
 252    *
 253    * @param tx
 254    */
 255  2 public void rollback(Object tx)
 256    {
 257  2 for (CacheLoader l : writeCacheLoaders)
 258    {
 259  4 l.rollback(tx);
 260    }
 261    }
 262   
 263   
 264    /**
 265    * Creates individual cache loaders.
 266    *
 267    * @throws Exception
 268    */
 269  68 public void create() throws Exception
 270    {
 271  68 Iterator<CacheLoader> it = cacheLoaders.iterator();
 272  68 Iterator<CacheLoaderConfig.IndividualCacheLoaderConfig> cfgIt = cacheLoaderConfigs.iterator();
 273  68 while (it.hasNext() && cfgIt.hasNext())
 274    {
 275  136 CacheLoader cl = it.next();
 276  136 CacheLoaderConfig.IndividualCacheLoaderConfig cfg = cfgIt.next();
 277  136 cl.create();
 278    }
 279    }
 280   
 281  68 public void start() throws Exception
 282    {
 283  68 for (CacheLoader cacheLoader : cacheLoaders)
 284    {
 285  136 cacheLoader.start();
 286    }
 287    }
 288   
 289  68 public void stop()
 290    {
 291  68 for (CacheLoader cacheLoader : cacheLoaders)
 292    {
 293  136 cacheLoader.stop();
 294    }
 295    }
 296   
 297  68 public void destroy()
 298    {
 299  68 for (CacheLoader cacheLoader : cacheLoaders)
 300    {
 301  136 cacheLoader.destroy();
 302    }
 303    }
 304   
 305    /**
 306    * No-op, as this class doesn't directly use the ERegionManager.
 307    */
 308  0 public void setRegionManager(RegionManager manager)
 309    {
 310    // no-op -- we don't do anything with the region manager
 311    }
 312   
 313  5 public void loadEntireState(ObjectOutputStream os) throws Exception
 314    {
 315  5 Iterator<CacheLoader> i = cacheLoaders.iterator();
 316  5 Iterator<CacheLoaderConfig.IndividualCacheLoaderConfig> cfgs = cacheLoaderConfigs.iterator();
 317  5 while (i.hasNext() && cfgs.hasNext())
 318    {
 319  5 CacheLoader l = i.next();
 320  5 CacheLoaderConfig.IndividualCacheLoaderConfig cfg = cfgs.next();
 321  5 if (cfg.isFetchPersistentState())
 322    {
 323  5 l.loadEntireState(os);
 324  5 break;
 325    }
 326    }
 327    }
 328   
 329  2 public void loadState(Fqn subtree, ObjectOutputStream os) throws Exception
 330    {
 331  2 Iterator<CacheLoader> i = cacheLoaders.iterator();
 332  2 Iterator<CacheLoaderConfig.IndividualCacheLoaderConfig> cfgs = cacheLoaderConfigs.iterator();
 333  2 while (i.hasNext() && cfgs.hasNext())
 334    {
 335  2 CacheLoader l = i.next();
 336  2 CacheLoaderConfig.IndividualCacheLoaderConfig cfg = cfgs.next();
 337  2 if (cfg.isFetchPersistentState())
 338    {
 339  2 l.loadState(subtree, os);
 340  2 break;
 341    }
 342    }
 343    }
 344   
 345  1 public void storeEntireState(ObjectInputStream is) throws Exception
 346    {
 347  1 Iterator<CacheLoader> i = writeCacheLoaders.iterator();
 348  1 Iterator<CacheLoaderConfig.IndividualCacheLoaderConfig> cfgs = cacheLoaderConfigs.iterator();
 349  1 while (i.hasNext())
 350    {
 351  1 CacheLoader l = i.next();
 352  1 CacheLoaderConfig.IndividualCacheLoaderConfig cfg = cfgs.next();
 353  1 if (cfg.isFetchPersistentState())
 354    {
 355  1 l.storeEntireState(is);
 356  1 break;
 357    }
 358    }
 359   
 360    }
 361   
 362  2 public void storeState(Fqn subtree, ObjectInputStream is) throws Exception
 363    {
 364  2 Iterator<CacheLoader> i = writeCacheLoaders.iterator();
 365  2 Iterator<CacheLoaderConfig.IndividualCacheLoaderConfig> cfgs = cacheLoaderConfigs.iterator();
 366  2 while (i.hasNext())
 367    {
 368  2 CacheLoader l = i.next();
 369  2 CacheLoaderConfig.IndividualCacheLoaderConfig cfg = cfgs.next();
 370  2 if (cfg.isFetchPersistentState())
 371    {
 372  2 l.storeState(subtree, is);
 373  2 break;
 374    }
 375    }
 376    }
 377   
 378    /**
 379    * Returns the number of cache loaders in the chain.
 380    */
 381  4 public int getSize()
 382    {
 383  4 return cacheLoaders.size();
 384    }
 385   
 386    /**
 387    * Returns a List<CacheLoader> of individual cache loaders configured.
 388    */
 389  15 public List<CacheLoader> getCacheLoaders()
 390    {
 391  15 return Collections.unmodifiableList(cacheLoaders);
 392    }
 393   
 394    /**
 395    * Adds a cache loader to the chain (always added at the end of the chain)
 396    *
 397    * @param l the cache loader to add
 398    * @param cfg and its configuration
 399    */
 400  151 public void addCacheLoader(CacheLoader l, CacheLoaderConfig.IndividualCacheLoaderConfig cfg)
 401    {
 402  151 synchronized (this)
 403    {
 404  151 cacheLoaderConfigs.add(cfg);
 405  151 cacheLoaders.add(l);
 406   
 407  151 if (!cfg.isIgnoreModifications())
 408    {
 409  147 writeCacheLoaders.add(l);
 410    }
 411    }
 412    }
 413   
 414  0 public String toString()
 415    {
 416  0 StringBuffer buf = new StringBuffer("ChainingCacheLoader{");
 417  0 Iterator<CacheLoader> i = cacheLoaders.iterator();
 418  0 Iterator<CacheLoaderConfig.IndividualCacheLoaderConfig> c = cacheLoaderConfigs.iterator();
 419  0 int count = 0;
 420  0 while (i.hasNext() && c.hasNext())
 421    {
 422  0 CacheLoader loader = i.next();
 423  0 CacheLoaderConfig.IndividualCacheLoaderConfig cfg = c.next();
 424   
 425  0 buf.append(++count);
 426  0 buf.append(": IgnoreMods? ");
 427  0 buf.append(cfg.isIgnoreModifications());
 428  0 buf.append(" CLoader: ");
 429  0 buf.append(loader);
 430  0 buf.append("; ");
 431    }
 432  0 buf.append("}");
 433  0 return buf.toString();
 434    }
 435   
 436  68 public void purgeIfNecessary() throws Exception
 437    {
 438  68 Iterator<CacheLoader> loaders = cacheLoaders.iterator();
 439  68 Iterator<CacheLoaderConfig.IndividualCacheLoaderConfig> configs = cacheLoaderConfigs.iterator();
 440   
 441  68 while (loaders.hasNext() && configs.hasNext())
 442    {
 443  136 CacheLoader myLoader = loaders.next();
 444  136 CacheLoaderConfig.IndividualCacheLoaderConfig myConfig = configs.next();
 445   
 446  2 if (!myConfig.isIgnoreModifications() && myConfig.isPurgeOnStartup()) myLoader.remove(Fqn.ROOT);
 447    }
 448   
 449   
 450    }
 451    }