Clover coverage report -
Coverage timestamp: Thu Jul 5 2007 20:02:32 EDT
file stats: LOC: 351   Methods: 11
NCLOC: 279   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
ActivationInterceptor.java 36.7% 43.9% 63.6% 42.9%
coverage coverage
 1    package org.jboss.cache.interceptors;
 2   
 3    import org.jboss.cache.Fqn;
 4    import org.jboss.cache.InvocationContext;
 5    import org.jboss.cache.Modification;
 6    import org.jboss.cache.NodeSPI;
 7    import org.jboss.cache.marshall.MethodCall;
 8    import org.jboss.cache.marshall.MethodDeclarations;
 9    import org.jboss.cache.transaction.GlobalTransaction;
 10    import org.jboss.cache.transaction.TransactionEntry;
 11    import org.jboss.cache.transaction.TransactionTable;
 12   
 13    import javax.transaction.TransactionManager;
 14    import java.lang.reflect.Method;
 15    import java.util.ArrayList;
 16    import java.util.Collections;
 17    import java.util.HashMap;
 18    import java.util.List;
 19    import java.util.Map;
 20    import java.util.Set;
 21    import java.util.concurrent.ConcurrentHashMap;
 22   
 23    /**
 24    * Loads nodes that don't exist at the time of the call into memory from the CacheLoader.
 25    * If the nodes were evicted earlier then we remove them from the cache loader after
 26    * their attributes have been initialized and their children have been loaded in memory.
 27    *
 28    * @author <a href="mailto:{hmesha@novell.com}">{Hany Mesha}</a>
 29    * @version $Id: ActivationInterceptor.java,v 1.58 2007/06/11 12:58:17 msurtani Exp $
 30    */
 31    public class ActivationInterceptor extends CacheLoaderInterceptor implements ActivationInterceptorMBean
 32    {
 33   
 34    protected TransactionManager tx_mgr = null;
 35    protected TransactionTable tx_table = null;
 36    private HashMap m_txActivations = new HashMap();
 37    private long m_activations = 0;
 38   
 39    /**
 40    * List<Transaction> that we have registered for
 41    */
 42    protected ConcurrentHashMap transactions = new ConcurrentHashMap(16);
 43    protected static final Object NULL = new Object();
 44   
 45  247 public ActivationInterceptor()
 46    {
 47  247 this.useCacheStore = false;
 48  247 isActivation = true;
 49    }
 50   
 51    /**
 52    * Makes sure a node is loaded into memory before a call executes. If node is
 53    * already loaded and its attributes already initialized, then remove it from
 54    * the cache loader and notify the cache listeners that the node has been activated.
 55    *
 56    * @return
 57    * @throws Throwable
 58    */
 59  319844 public Object invoke(InvocationContext ctx) throws Throwable
 60    {
 61  319844 MethodCall m = ctx.getMethodCall();
 62  319844 Fqn fqn = null;
 63  319844 Object[] args = m.getArgs();
 64  319844 Object retval;
 65   
 66    // First call the parent class to load the node
 67  319844 retval = super.invoke(ctx);
 68   
 69    // is this a node removal operation?
 70  319843 boolean removeData = false, nodeRemoved = false;
 71   
 72    // Could be TRANSACTIONAL. If so, we register for TX completion (if we haven't done so yet)
 73  319843 if (tx_mgr != null && tx_mgr.getTransaction() != null)
 74    {
 75  0 GlobalTransaction gtx = ctx.getGlobalTransaction();
 76  0 switch (m.getMethodId())
 77    {
 78  0 case MethodDeclarations.commitMethod_id:
 79  0 if (hasModifications(args))
 80    {
 81  0 loader.commit(gtx);
 82  0 if (configuration.getExposeManagementStatistics() && getStatisticsEnabled())
 83    {
 84  0 Integer acts = (Integer) m_txActivations.get(gtx);
 85  0 if (acts != null)
 86    {
 87  0 m_activations = m_activations + acts;
 88    }
 89  0 m_txActivations.remove(gtx);
 90    }
 91    }
 92  0 break;
 93  0 case MethodDeclarations.rollbackMethod_id:
 94  0 if (hasModifications(args))
 95    {
 96  0 loader.rollback(gtx);
 97  0 if (configuration.getExposeManagementStatistics() && getStatisticsEnabled())
 98    {
 99  0 m_txActivations.remove(gtx);
 100    }
 101    }
 102  0 break;
 103  0 case MethodDeclarations.optimisticPrepareMethod_id:
 104  0 case MethodDeclarations.prepareMethod_id:
 105  0 prepareCacheLoader(ctx);
 106  0 break;
 107    }
 108    }
 109   
 110    // if we're here then it's not transactional
 111   
 112    // CacheLoaderInterceptor normally doesn't load the node
 113    // since CacheStoreInterceptor.put() returns the old value
 114  319843 switch (m.getMethodId())
 115    {
 116  0 case MethodDeclarations.putForExternalReadMethodLocal_id:
 117  357 case MethodDeclarations.putDataMethodLocal_id:
 118  0 case MethodDeclarations.putDataEraseMethodLocal_id:
 119  35629 case MethodDeclarations.putKeyValMethodLocal_id:
 120  53 case MethodDeclarations.removeKeyMethodLocal_id:
 121  0 case MethodDeclarations.addChildMethodLocal_id:
 122  36039 fqn = (Fqn) args[1];
 123  36039 break;
 124  1015 case MethodDeclarations.getKeyValueMethodLocal_id:
 125  280170 case MethodDeclarations.getNodeMethodLocal_id:
 126  56 case MethodDeclarations.getKeysMethodLocal_id:
 127  102 case MethodDeclarations.getChildrenNamesMethodLocal_id:
 128  0 case MethodDeclarations.releaseAllLocksMethodLocal_id:
 129  4 case MethodDeclarations.printMethodLocal_id:
 130  281347 fqn = (Fqn) args[0];
 131  281347 break;
 132  270 case MethodDeclarations.removeNodeMethodLocal_id:
 133  270 nodeRemoved = true;
 134  270 fqn = (Fqn) args[1];
 135  270 break;
 136  39 case MethodDeclarations.removeDataMethodLocal_id:
 137  39 removeData = true;
 138  39 fqn = (Fqn) args[1];
 139  39 break;
 140    }
 141   
 142  319843 synchronized (this)
 143    {
 144  319843 if (fqn != null)
 145    {
 146  317691 if (nodeRemoved)
 147    {
 148  270 log.trace("This is a remove operation; removing the node from the loader, no activation processing needed.");
 149  270 loader.remove(fqn);
 150    }
 151  317421 else if (removeData)
 152    {
 153  39 log.trace("This is a remove data operation; removing the data from the loader, no activation processing needed.");
 154  39 loader.removeData(fqn);
 155    }
 156  317382 else if (cache.peek(fqn, false) != null && loader.exists(fqn))
 157    {
 158    // Remove the node from the cache loader if it exists in memory,
 159    // its attributes have been initialized, its children have been loaded,
 160    // AND it was found in the cache loader (nodeLoaded = true).
 161    // Then notify the listeners that the node has been activated.
 162  1559 NodeSPI n = getNode(fqn);// don't load
 163    // node not null and attributes have been loaded?
 164  1559 if (n != null && n.getDataLoaded())
 165    {
 166  1559 if (!n.getChildrenDirect().isEmpty())
 167    {
 168  120 if (allInitialized(n))
 169    {
 170  22 log.debug("children all initialized");
 171  22 remove(ctx, fqn);
 172    }
 173    }
 174  1439 else if (loaderNoChildren(fqn))
 175    {
 176  0 if (log.isDebugEnabled()) log.debug("no children " + n);
 177  1392 remove(ctx, fqn);
 178    }
 179    }
 180    }
 181    }
 182    }
 183  319843 return retval;
 184    }
 185   
 186  1414 private void remove(InvocationContext ctx, Fqn fqn) throws Exception
 187    {
 188  1414 cache.getNotifier().notifyNodeActivated(fqn, true, Collections.emptyMap(), ctx);
 189  1414 loader.remove(fqn);
 190  1414 if (configuration.getExposeManagementStatistics() && getStatisticsEnabled())
 191    {
 192  1414 m_activations++;
 193    }
 194    }
 195   
 196    /**
 197    * Returns true if a node has all children loaded and initialized.
 198    */
 199  120 private boolean allInitialized(NodeSPI<?, ?> n)
 200    {
 201  120 if (!n.getChildrenLoaded())
 202    {
 203  68 return false;
 204    }
 205   
 206  52 for (NodeSPI child : n.getChildrenDirect())
 207    {
 208  96 if (!child.getDataLoaded())
 209    {
 210  30 return false;
 211    }
 212    }
 213  22 return true;
 214    }
 215   
 216    /**
 217    * Returns true if the loader indicates no children for this node.
 218    * Return false on error.
 219    */
 220  1439 private boolean loaderNoChildren(Fqn fqn)
 221    {
 222  1439 try
 223    {
 224  1439 Set children_names = loader.getChildrenNames(fqn);
 225  1439 return (children_names == null);
 226    }
 227    catch (Exception e)
 228    {
 229  0 log.error("failed getting the children names for " + fqn + " from the cache loader", e);
 230  0 return false;
 231    }
 232    }
 233   
 234  12 public long getActivations()
 235    {
 236  12 return m_activations;
 237    }
 238   
 239  1 public void resetStatistics()
 240    {
 241  1 super.resetStatistics();
 242  1 m_activations = 0;
 243    }
 244   
 245  0 public Map<String, Object> dumpStatistics()
 246    {
 247  0 Map<String, Object> retval = super.dumpStatistics();
 248  0 if (retval == null)
 249    {
 250  0 retval = new HashMap<String, Object>();
 251    }
 252  0 retval.put("Activations", m_activations);
 253  0 return retval;
 254    }
 255   
 256  0 protected boolean hasModifications(Object[] args)
 257    {
 258  0 int hint = 1;
 259  0 if (args[hint] instanceof Boolean) return (Boolean) args[hint];
 260  0 for (Object arg : args)
 261    {
 262  0 if (arg instanceof Boolean) return (Boolean) arg;
 263    }
 264  0 return false;
 265    }
 266   
 267  0 private void prepareCacheLoader(InvocationContext ctx) throws Exception
 268    {
 269  0 List<MethodCall> modifications;
 270  0 TransactionEntry entry;
 271  0 int txActs = 0;
 272  0 GlobalTransaction gtx = ctx.getGlobalTransaction();
 273   
 274  0 entry = tx_table.get(gtx);
 275  0 if (entry == null)
 276    {
 277  0 throw new Exception("entry for transaction " + gtx + " not found in transaction table");
 278    }
 279  0 modifications = entry.getCacheLoaderModifications();
 280  0 if (modifications.size() == 0)
 281    {
 282  0 return;
 283    }
 284  0 List cache_loader_modifications = new ArrayList();
 285  0 for (MethodCall methodCall : modifications)
 286    {
 287  0 Method method = methodCall.getMethod();
 288  0 Object[] args;
 289  0 if (method == null)
 290    {
 291  0 throw new Exception("method call has no method: " + methodCall);
 292    }
 293  0 args = methodCall.getArgs();
 294  0 switch (methodCall.getMethodId())
 295    {
 296  0 case MethodDeclarations.removeNodeMethodLocal_id:
 297    // just remove it from loader, don't trigger activation processing
 298  0 Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, (Fqn) args[1]);
 299  0 cache_loader_modifications.add(mod);
 300  0 break;
 301  0 case MethodDeclarations.putDataMethodLocal_id:
 302  0 case MethodDeclarations.putDataEraseMethodLocal_id:
 303  0 case MethodDeclarations.putKeyValMethodLocal_id:
 304    // On the way out, remove the node from the cache loader.
 305    // Only remove the node if it exists in memory, its attributes have
 306    // been initialized, its children have been loaded
 307    // AND it was found in the cache loader (nodeLoaded = true).
 308    // Then notify the listeners that the node has been activated.
 309  0 Fqn fqn = (Fqn) args[1];
 310  0 if (fqn != null && cache.peek(fqn, false) != null && loader.exists(fqn))
 311    {
 312  0 NodeSPI n = getNode(fqn);// don't load
 313    // node not null and attributes have been loaded?
 314  0 if (n != null && n.getDataLoaded())
 315    {
 316    // has children?
 317  0 if (!n.getChildrenDirect().isEmpty() && allInitialized(n))
 318    {
 319    // children have been loaded, remove the node
 320  0 addRemoveMod(ctx, cache_loader_modifications, fqn, n.getDataDirect());
 321  0 txActs++;
 322    }
 323    // doesn't have children, check the cache loader
 324  0 else if (loaderNoChildren(fqn))
 325    {
 326  0 addRemoveMod(ctx, cache_loader_modifications, fqn, n.getDataDirect());
 327  0 txActs++;
 328    }
 329    }
 330    }
 331  0 break;
 332    }
 333    }
 334  0 if (cache_loader_modifications.size() > 0)
 335    {
 336  0 loader.prepare(gtx, cache_loader_modifications, false);
 337  0 if (configuration.getExposeManagementStatistics() && getStatisticsEnabled() && txActs > 0)
 338    {
 339  0 m_txActivations.put(gtx, txActs);
 340    }
 341    }
 342    }
 343   
 344  0 private void addRemoveMod(InvocationContext ctx, List l, Fqn fqn, Map data)
 345    {
 346  0 Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, fqn);
 347  0 l.add(mod);
 348  0 cache.getNotifier().notifyNodeActivated(fqn, false, data, ctx);
 349    }
 350   
 351    }