Clover coverage report -
Coverage timestamp: Thu Jul 5 2007 20:02:32 EDT
file stats: LOC: 4,364   Methods: 221
NCLOC: 2,868   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
CacheImpl.java 73.5% 82.5% 86% 80.6%
coverage coverage
 1    /*
 2    * JBoss, the OpenSource J2EE webOS
 3    *
 4    * Distributable under LGPL license.
 5    * See terms of license at gnu.org.
 6    */
 7    package org.jboss.cache;
 8   
 9    import org.apache.commons.logging.Log;
 10    import org.apache.commons.logging.LogFactory;
 11    import org.jboss.cache.buddyreplication.BuddyGroup;
 12    import org.jboss.cache.buddyreplication.BuddyManager;
 13    import org.jboss.cache.buddyreplication.BuddyNotInitException;
 14    import org.jboss.cache.buddyreplication.GravitateResult;
 15    import org.jboss.cache.config.BuddyReplicationConfig;
 16    import org.jboss.cache.config.Configuration;
 17    import org.jboss.cache.config.Configuration.NodeLockingScheme;
 18    import org.jboss.cache.config.Option;
 19    import org.jboss.cache.config.RuntimeConfig;
 20    import org.jboss.cache.factories.InterceptorChainFactory;
 21    import org.jboss.cache.interceptors.Interceptor;
 22    import org.jboss.cache.loader.CacheLoader;
 23    import org.jboss.cache.loader.CacheLoaderManager;
 24    import org.jboss.cache.lock.IsolationLevel;
 25    import org.jboss.cache.lock.LockStrategyFactory;
 26    import org.jboss.cache.lock.LockUtil;
 27    import org.jboss.cache.lock.LockingException;
 28    import org.jboss.cache.lock.NodeLock;
 29    import org.jboss.cache.lock.TimeoutException;
 30    import org.jboss.cache.marshall.InactiveRegionAwareRpcDispatcher;
 31    import org.jboss.cache.marshall.Marshaller;
 32    import org.jboss.cache.marshall.MethodCall;
 33    import org.jboss.cache.marshall.MethodCallFactory;
 34    import org.jboss.cache.marshall.MethodDeclarations;
 35    import org.jboss.cache.marshall.NodeData;
 36    import org.jboss.cache.marshall.VersionAwareMarshaller;
 37    import org.jboss.cache.notifications.Notifier;
 38    import org.jboss.cache.notifications.event.NodeModifiedEvent;
 39    import org.jboss.cache.optimistic.DataVersion;
 40    import org.jboss.cache.statetransfer.StateTransferManager;
 41    import org.jboss.cache.transaction.GlobalTransaction;
 42    import org.jboss.cache.transaction.OptimisticTransactionEntry;
 43    import org.jboss.cache.transaction.TransactionEntry;
 44    import org.jboss.cache.transaction.TransactionManagerLookup;
 45    import org.jboss.cache.transaction.TransactionTable;
 46    import org.jboss.cache.util.ExposedByteArrayOutputStream;
 47    import org.jboss.cache.util.concurrent.ConcurrentHashSet;
 48    import org.jboss.util.stream.MarshalledValueInputStream;
 49    import org.jboss.util.stream.MarshalledValueOutputStream;
 50    import org.jgroups.Address;
 51    import org.jgroups.Channel;
 52    import org.jgroups.ChannelClosedException;
 53    import org.jgroups.ChannelException;
 54    import org.jgroups.ChannelFactory;
 55    import org.jgroups.ChannelNotConnectedException;
 56    import org.jgroups.ExtendedMembershipListener;
 57    import org.jgroups.ExtendedMessageListener;
 58    import org.jgroups.JChannel;
 59    import org.jgroups.Message;
 60    import org.jgroups.View;
 61    import org.jgroups.blocks.GroupRequest;
 62    import org.jgroups.blocks.RpcDispatcher;
 63    import org.jgroups.util.Rsp;
 64    import org.jgroups.util.RspList;
 65    import org.jgroups.util.Util;
 66   
 67    import javax.transaction.Status;
 68    import javax.transaction.SystemException;
 69    import javax.transaction.Transaction;
 70    import javax.transaction.TransactionManager;
 71    import java.io.ByteArrayInputStream;
 72    import java.io.InputStream;
 73    import java.io.NotSerializableException;
 74    import java.io.OutputStream;
 75    import java.lang.reflect.Method;
 76    import java.util.ArrayList;
 77    import java.util.Collections;
 78    import java.util.HashSet;
 79    import java.util.LinkedList;
 80    import java.util.List;
 81    import java.util.Map;
 82    import java.util.Set;
 83    import java.util.Vector;
 84    import java.util.concurrent.ConcurrentHashMap;
 85   
 86    /**
 87    * The default implementation class of {@link org.jboss.cache.Cache} and {@link org.jboss.cache.CacheSPI}. This class
 88    * has its roots in the legacy (JBoss Cache 1.x.x) org.jboss.cache.TreeCache class.
 89    * <p/>
 90    * You should not use this class directly, or attempt to cast {@link org.jboss.cache.Cache} or {@link org.jboss.cache.CacheSPI}
 91    * interfaces directly to this class.
 92    *
 93    * @author Bela Ban
 94    * @author Ben Wang
 95    * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
 96    * @author Brian Stansberry
 97    * @author Daniel Huang (dhuang@jboss.org)
 98    * @see org.jboss.cache.Cache
 99    */
 100    public class CacheImpl<K, V> implements CacheSPI<K, V>
 101    {
 102   
 103    /**
 104    * CacheImpl log.
 105    */
 106    private Log log = LogFactory.getLog(CacheImpl.class);
 107   
 108    /**
 109    * Root node.
 110    */
 111    private NodeSPI<K, V> root;
 112   
 113    /**
 114    * Cache's region manager.
 115    */
 116    private RegionManager regionManager = null;
 117   
 118    /**
 119    * The JGroups JChannel in use.
 120    */
 121    protected Channel channel = null;
 122   
 123    /**
 124    * True if this CacheImpl is the coordinator.
 125    */
 126    private boolean coordinator = false;
 127   
 128    /**
 129    * List of cluster group members.
 130    */
 131    private final Vector<Address> members = new Vector<Address>();
 132   
 133    /**
 134    * JGroups RpcDispatcher in use.
 135    */
 136    private RpcDispatcher disp = null;
 137   
 138    /**
 139    * JGroups message listener.
 140    */
 141    private MessageListenerAdaptor ml = new MessageListenerAdaptor();
 142   
 143    /**
 144    * Maintains mapping of transactions (keys) and Modifications/Undo-Operations
 145    */
 146    private final TransactionTable tx_table = new TransactionTable();
 147   
 148    /**
 149    * HashMap<Thread, List<Lock>, maintains locks acquired by threads (used when no TXs are used)
 150    */
 151    private Map<Thread, List<NodeLock>> lock_table;
 152   
 153    /**
 154    * Set<Fqn> of Fqns of the topmost node of internal regions that should
 155    * not included in standard state transfers.
 156    */
 157    private Set<Fqn> internalFqns = new ConcurrentHashSet<Fqn>();
 158   
 159    /**
 160    * True if state was initialized during start-up.
 161    */
 162    private volatile boolean isStateSet = false;
 163   
 164    /**
 165    * Class name used to handle evictions.
 166    */
 167    private String evictionInterceptorClass = "org.jboss.cache.interceptors.EvictionInterceptor";
 168   
 169    /**
 170    * Marshaller if register to handle marshalling
 171    */
 172    private Marshaller marshaller_ = null;
 173   
 174    /**
 175    * {@link #invokeMethod(org.jboss.cache.marshall.MethodCall,boolean)} will dispatch to this chain of interceptors.
 176    * In the future, this will be replaced with JBossAop. This is a first step towards refactoring JBossCache.
 177    */
 178    private Interceptor interceptor_chain = null;
 179   
 180    /**
 181    * Method to acquire a TransactionManager. By default we use JBossTransactionManagerLookup. Has
 182    * to be set before calling {@link #start()}
 183    */
 184    private TransactionManagerLookup tm_lookup = null;
 185   
 186    /**
 187    * Used to get the Transaction associated with the current thread
 188    */
 189    private TransactionManager tm = null;
 190   
 191    /**
 192    * Cache loader manager.
 193    */
 194    private CacheLoaderManager cacheLoaderManager;
 195   
 196    /**
 197    * Queue used to replicate updates when mode is repl-async
 198    */
 199    private ReplicationQueue repl_queue = null;
 200   
 201    /**
 202    * The current lifecycle state.
 203    */
 204    private CacheStatus cacheStatus;
 205   
 206    /**
 207    * Buddy Manager
 208    */
 209    private BuddyManager buddyManager;
 210   
 211    /**
 212    * State transfer manager. Do not access this field directly -- use the getter
 213    */
 214    private StateTransferManager stateTransferManager;
 215   
 216    /**
 217    * Cache notifier handler class.
 218    */
 219    private Notifier notifier;
 220   
 221    private ThreadLocal<InvocationContext> invocationContextContainer = new ThreadLocal<InvocationContext>()
 222    {
 223  7269 @Override
 224    protected InvocationContext initialValue()
 225    {
 226  7281 return new InvocationContext();
 227    }
 228    };
 229   
 230    private Configuration configuration;
 231   
 232    /**
 233    * Constructs an uninitialized CacheImpl.
 234    */
 235  2871 protected CacheImpl() throws Exception
 236    {
 237  2871 configuration = new Configuration(this);
 238  2871 notifier = new Notifier(this);
 239  2871 regionManager = new RegionManager(this);
 240  2871 cacheStatus = CacheStatus.INSTANTIATED;
 241    }
 242   
 243  1549 public StateTransferManager getStateTransferManager()
 244    {
 245  1549 if (stateTransferManager == null)
 246    {
 247  972 stateTransferManager = new StateTransferManager(this);
 248    }
 249  1549 return stateTransferManager;
 250    }
 251   
 252  0 public void setStateTransferManager(StateTransferManager manager)
 253    {
 254  0 this.stateTransferManager = manager;
 255    }
 256   
 257  8942233 public Configuration getConfiguration()
 258    {
 259  8942233 return configuration;
 260    }
 261   
 262    /**
 263    * Returns the CacheImpl implementation version.
 264    */
 265  2809 public String getVersion()
 266    {
 267  2809 return Version.printVersion();
 268    }
 269   
 270    /**
 271    * Returns the root node.
 272    */
 273  1585416 public NodeSPI<K, V> getRoot()
 274    {
 275  1585416 return root;
 276    }
 277   
 278    /**
 279    * Returns the local channel address.
 280    */
 281  1430211 public Address getLocalAddress()
 282    {
 283  1430211 return channel != null ? channel.getLocalAddress() : null;
 284    }
 285   
 286    /**
 287    * Returns the members as a List.
 288    * This list may be concurrently modified.
 289    */
 290  235197 public List<Address> getMembers()
 291    {
 292  235197 synchronized (members)
 293    {
 294  235197 return new ArrayList<Address>(members);
 295    }
 296    }
 297   
 298    /**
 299    * Returns <code>true</code> if this node is the group coordinator.
 300    */
 301  441 public boolean isCoordinator()
 302    {
 303  441 return coordinator;
 304    }
 305   
 306    /**
 307    * Returns the transaction table.
 308    */
 309  586021 public TransactionTable getTransactionTable()
 310    {
 311  586021 return tx_table;
 312    }
 313   
 314    /**
 315    * Returns the lock table.
 316    */
 317  9686 public Map<Thread, List<NodeLock>> getLockTable()
 318    {
 319  9686 if (lock_table == null)
 320    {
 321  2400 lock_table = new ConcurrentHashMap<Thread, List<NodeLock>>();
 322    }
 323  9686 return lock_table;
 324    }
 325   
 326    /**
 327    * Returns the contents of the TransactionTable as a string.
 328    */
 329  0 public String dumpTransactionTable()
 330    {
 331  0 return tx_table.toString(true);
 332    }
 333   
 334    /**
 335    * Used for testing only - sets the interceptor chain.
 336    */
 337  86 public void setInterceptorChain(Interceptor i)
 338    {
 339  86 interceptor_chain = i;
 340    }
 341   
 342    /**
 343    * @return the list of interceptors.
 344    */
 345  3565 public List<Interceptor> getInterceptors()
 346    {
 347  3565 return InterceptorChainFactory.getInstance().asList(interceptor_chain);
 348    }
 349   
 350    /**
 351    * Returns the underlying cache loader in use.
 352    */
 353  926 public CacheLoader getCacheLoader()
 354    {
 355  926 if (cacheLoaderManager == null)
 356  621 return null;
 357  305 return cacheLoaderManager.getCacheLoader();
 358    }
 359   
 360  376 public String getEvictionInterceptorClass()
 361    {
 362  376 return this.evictionInterceptorClass;
 363    }
 364   
 365  2832 private void setUseReplQueue(boolean flag)
 366    {
 367  2832 if (flag)
 368    {
 369  0 if (repl_queue == null)
 370    {
 371  0 repl_queue = new ReplicationQueue(this, configuration.getReplQueueInterval(), configuration.getReplQueueMaxElements());
 372  0 if (configuration.getReplQueueInterval() >= 0)
 373    {
 374  0 repl_queue.start();
 375    }
 376    }
 377    }
 378    else
 379    {
 380  2832 if (repl_queue != null)
 381    {
 382  0 repl_queue.stop();
 383  0 repl_queue = null;
 384    }
 385    }
 386    }
 387   
 388   
 389    /**
 390    * Returns the replication queue.
 391    */
 392  10771 public ReplicationQueue getReplicationQueue()
 393    {
 394  10771 return repl_queue;
 395    }
 396   
 397    /**
 398    * Sets the cache locking isolation level.
 399    */
 400  2832 private void setIsolationLevel(IsolationLevel level)
 401    {
 402  2832 LockStrategyFactory.setIsolationLevel(level);
 403    }
 404   
 405    /**
 406    * Sets the TransactionManagerLookup object
 407    */
 408  2 public void setTransactionManagerLookup(TransactionManagerLookup l)
 409    {
 410  2 this.tm_lookup = l;
 411    }
 412   
 413    /**
 414    * Returns the transaction manager in use.
 415    */
 416  209820 public TransactionManager getTransactionManager()
 417    {
 418  209820 return tm;
 419    }
 420   
 421    /**
 422    * Fetches the group state from the current coordinator. If successful, this
 423    * will trigger JChannel setState() call.
 424    */
 425  0 public void fetchState(long timeout) throws ChannelClosedException, ChannelNotConnectedException
 426    {
 427  0 if (channel == null)
 428    {
 429  0 throw new ChannelNotConnectedException();
 430    }
 431  0 boolean rc = channel.getState(null, timeout);
 432  0 if (rc)
 433    {
 434  0 log.debug("fetchState(): state was retrieved successfully");
 435    }
 436    else
 437    {
 438  0 log.debug("fetchState(): state could not be retrieved (first member)");
 439    }
 440    }
 441   
 442  8 void fetchPartialState(List<Address> sources, Fqn sourceTarget, Fqn integrationTarget) throws Exception
 443    {
 444  8 String encodedStateId = sourceTarget + StateTransferManager.PARTIAL_STATE_DELIMITER + integrationTarget;
 445  8 fetchPartialState(sources, encodedStateId);
 446    }
 447   
 448  195 void fetchPartialState(List<Address> sources, Fqn subtree) throws Exception
 449    {
 450  195 if (subtree == null)
 451    {
 452  0 throw new IllegalArgumentException("Cannot fetch partial state. Null subtree.");
 453    }
 454  195 fetchPartialState(sources, subtree.toString());
 455    }
 456   
 457  203 private void fetchPartialState(List<Address> sources, String stateId) throws Exception
 458    {
 459  203 if (sources == null || sources.isEmpty() || stateId == null)
 460    {
 461    // should this really be throwing an exception? Are there valid use cases where partial state may not be available? - Manik
 462    // Yes -- cache is configured LOCAL but app doesn't know it -- Brian
 463    //throw new IllegalArgumentException("Cannot fetch partial state, targets are " + sources + " and stateId is " + stateId);
 464  4 if (log.isWarnEnabled())
 465    {
 466  4 log.warn("Cannot fetch partial state, targets are " + sources +
 467    " and stateId is " + stateId);
 468    }
 469  4 return;
 470    }
 471   
 472  199 List<Address> targets = new LinkedList<Address>(sources);
 473   
 474    //skip *this* node as a target
 475  199 targets.remove(getLocalAddress());
 476   
 477  199 if (targets.isEmpty())
 478    {
 479    // Definitely no exception here -- this happens every time the 1st node in the
 480    // cluster activates a region!! -- Brian
 481  65 log.debug("Cannot fetch partial state. There are no target members specified");
 482  65 return;
 483    }
 484   
 485  134 log.debug("Node " + getLocalAddress() + " fetching partial state " + stateId + " from members " + targets);
 486  134 boolean successfulTransfer = false;
 487  134 for (Address target : targets)
 488    {
 489  156 log.debug("Node " + getLocalAddress() + " fetching partial state " + stateId + " from member " + target);
 490  156 isStateSet = false;
 491  156 successfulTransfer = channel.getState(target, stateId, configuration.getStateRetrievalTimeout());
 492  152 if (successfulTransfer)
 493    {
 494  148 try
 495    {
 496  148 ml.waitForState();
 497    }
 498    catch (Exception transferFailed)
 499    {
 500  36 successfulTransfer = false;
 501    }
 502    }
 503  152 log.debug("Node " + getLocalAddress() + " fetching partial state " + stateId + " from member " + target + (successfulTransfer ? " successful" : " failed"));
 504  152 if (successfulTransfer)
 505  112 break;
 506    }
 507   
 508  130 if (!successfulTransfer)
 509    {
 510  18 log.debug("Node " + getLocalAddress() + " could not fetch partial state " + stateId + " from any member " + targets);
 511    }
 512    }
 513   
 514    /**
 515    * Lifecycle method. This is like initialize.
 516    *
 517    * @throws Exception
 518    */
 519  2863 public void create() throws CacheException
 520    {
 521  2863 if (!cacheStatus.createAllowed())
 522    {
 523  31 if (cacheStatus.needToDestroyFailedCache())
 524  0 destroy();
 525    else
 526  31 return;
 527    }
 528   
 529  2832 try
 530    {
 531  2832 internalCreate();
 532    }
 533    catch (Throwable t)
 534    {
 535  0 handleLifecycleTransitionFailure(t);
 536    }
 537    }
 538   
 539    /**
 540    * Sets the cacheStatus to FAILED and rethrows the problem as one
 541    * of the declared types. Converts any non-RuntimeException Exception
 542    * to CacheException.
 543    *
 544    * @param t
 545    * @throws CacheException
 546    * @throws RuntimeException
 547    * @throws Error
 548    */
 549  19 private void handleLifecycleTransitionFailure(Throwable t)
 550    throws CacheException, RuntimeException, Error
 551    {
 552  19 cacheStatus = CacheStatus.FAILED;
 553  19 if (t instanceof CacheException)
 554  19 throw (CacheException) t;
 555  0 else if (t instanceof RuntimeException)
 556  0 throw (RuntimeException) t;
 557  0 else if (t instanceof Error)
 558  0 throw (Error) t;
 559    else
 560  0 throw new CacheException(t);
 561    }
 562   
 563    /**
 564    * The actual create implementation.
 565    *
 566    * @throws CacheException
 567    */
 568  2832 private void internalCreate() throws CacheException
 569    {
 570    // Include our clusterName in our log category
 571  2832 configureLogCategory();
 572   
 573    // initialise the node factory and set this in the runtime.
 574  2832 NodeFactory<K, V> nf;
 575  ? if ((nf = configuration.getRuntimeConfig().getNodeFactory()) == null)
 576    {
 577  2806 nf = new NodeFactory<K, V>(this);
 578  2806 configuration.getRuntimeConfig().setNodeFactory(nf);
 579    }
 580    else
 581    {
 582    // don't create a new one each and every time. After stopping and starting the cache, the old NodeFactory may still be valid.
 583  26 nf.init();
 584    }
 585   
 586  2832 if (notifier == null)
 587  26 notifier = new Notifier(this);
 588   
 589    // create a new root temporarily.
 590  2832 NodeSPI<K, V> tempRoot = nf.createRootDataNode();
 591    // if we don't already have a root or the new (temp) root is of a different class (optimistic vs pessimistic) to
 592    // the current root, then we use the new one. Helps preserve data between cache restarts.
 593  2832 if (root == null || !root.getClass().equals(tempRoot.getClass()))
 594  2806 root = tempRoot;
 595   
 596  2832 if (configuration.getCacheLoaderConfig() != null && cacheLoaderManager == null)
 597    {
 598  929 initialiseCacheLoaderManager();
 599    }
 600    // first set up the Buddy Manager and an RPCManager
 601  2832 if (configuration.getCacheMode() != Configuration.CacheMode.LOCAL)
 602    {
 603  1106 getConfiguration().getRuntimeConfig().setRPCManager(new RPCManagerImpl(this));
 604  1106 setBuddyReplicationConfig(configuration.getBuddyReplicationConfig());
 605    }
 606    // build interceptor chain
 607  2832 try
 608    {
 609  2832 interceptor_chain = InterceptorChainFactory.getInstance().buildInterceptorChain(this);
 610    }
 611    catch (Exception e)
 612    {
 613  0 throw new CacheException("Unable to build interceptor chain", e);
 614    }
 615   
 616   
 617  2832 setUseReplQueue(configuration.isUseReplQueue());
 618  2832 setIsolationLevel(configuration.getIsolationLevel());
 619   
 620  2832 getRegionManager();// make sure we create one
 621  2832 createEvictionPolicy();
 622   
 623  2832 getRegionManager().setDefaultInactive(configuration.isInactiveOnStartup());
 624   
 625  2832 cacheStatus = CacheStatus.CREATED;
 626    }
 627   
 628  2825 private void createTransactionManager()
 629    {
 630    // See if we had a TransactionManager injected into our config
 631  2825 this.tm = configuration.getRuntimeConfig().getTransactionManager();
 632  2825 if (tm == null)
 633    {
 634    // Nope. See if we can look it up from JNDI
 635  2773 if (this.tm_lookup == null && configuration.getTransactionManagerLookupClass() != null)
 636    {
 637  2511 try
 638    {
 639  2511 Class clazz = Thread.currentThread().getContextClassLoader().loadClass(configuration.getTransactionManagerLookupClass());
 640  2511 this.tm_lookup = (TransactionManagerLookup) clazz.newInstance();
 641    }
 642    catch (Exception e)
 643    {
 644  0 throw new CacheException("Problems creating the cache", e);
 645    }
 646    }
 647   
 648  2773 try
 649    {
 650  2773 if (tm_lookup != null)
 651    {
 652  2513 tm = tm_lookup.getTransactionManager();
 653  2513 configuration.getRuntimeConfig().setTransactionManager(tm);
 654    }
 655    else
 656    {
 657  260 if (configuration.getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC)
 658    {
 659  1 log.fatal("No transaction manager lookup class has been defined. Transactions cannot be used and thus OPTIMISTIC locking cannot be used");
 660    }
 661    else
 662    {
 663  259 log.info("No transaction manager lookup class has been defined. Transactions cannot be used");
 664    }
 665    }
 666    }
 667    catch (Exception e)
 668    {
 669  0 log.debug("failed looking up TransactionManager, will not use transactions", e);
 670    }
 671    }
 672    }
 673   
 674  1097 protected boolean shouldFetchStateOnStartup()
 675    {
 676  1097 boolean loaderFetch = cacheLoaderManager != null && cacheLoaderManager.isFetchPersistentState();
 677  1097 return !configuration.isInactiveOnStartup() && buddyManager == null && (configuration.isFetchInMemoryState() || loaderFetch);
 678    }
 679   
 680    /**
 681    * Lifecyle method.
 682    *
 683    * @throws CacheException
 684    */
 685  2849 public void start() throws CacheException
 686    {
 687  2849 if (!cacheStatus.startAllowed())
 688    {
 689  1552 if (cacheStatus.needToDestroyFailedCache())
 690  1 destroy(); // this will take us back to DESTROYED
 691   
 692  1552 if (cacheStatus.needCreateBeforeStart())
 693  1528 create();
 694    else
 695  24 return;
 696    }
 697   
 698  2825 try
 699    {
 700  2825 internalStart();
 701    }
 702    catch (Throwable t)
 703    {
 704  16 handleLifecycleTransitionFailure(t);
 705    }
 706    }
 707   
 708    /**
 709    * The actual start implementation.
 710    *
 711    * @throws CacheException
 712    * @throws IllegalArgumentException
 713    */
 714  2825 private void internalStart() throws CacheException, IllegalArgumentException
 715    {
 716  2825 cacheStatus = CacheStatus.STARTING;
 717   
 718  2825 createTransactionManager();
 719   
 720    // cache loaders should be initialised *before* any state transfers take place to prevent
 721    // exceptions involving cache loaders not being started. - Manik
 722    // create cache loader
 723  2825 if (cacheLoaderManager != null)
 724    {
 725  1032 cacheLoaderManager.startCacheLoader();
 726    }
 727    // now that we have a TM we can init the interceptor chain
 728  2824 InterceptorChainFactory.getInstance().initialiseInterceptors(interceptor_chain, this);
 729   
 730  2824 switch (configuration.getCacheMode())
 731    {
 732  1725 case LOCAL:
 733  1725 log.debug("cache mode is local, will not create the channel");
 734  1725 break;
 735  818 case REPL_SYNC:
 736  209 case REPL_ASYNC:
 737  24 case INVALIDATION_ASYNC:
 738  48 case INVALIDATION_SYNC:
 739  0 if (log.isDebugEnabled()) log.debug("cache mode is " + configuration.getCacheMode());
 740  1099 initialiseChannelAndRpcDispatcher();
 741   
 742  1097 try
 743    {
 744  1097 channel.connect(configuration.getClusterName());
 745    }
 746    catch (ChannelException e)
 747    {
 748  0 throw new CacheException("Unable to connect to JGroups channel", e);
 749    }
 750   
 751  1097 if (log.isInfoEnabled())
 752    {
 753  1097 log.info("CacheImpl local address is " + channel.getLocalAddress());
 754    }
 755  1097 if (shouldFetchStateOnStartup())
 756    {
 757  815 try
 758    {
 759  815 fetchStateOnStartup();
 760    }
 761    catch (Exception e)
 762    {
 763    // make sure we disconnect from the channel before we throw this exception!
 764    // JBCACHE-761
 765  11 channel.disconnect();
 766  11 channel.close();
 767  11 throw new CacheException("Unable to fetch state on startup", e);
 768    }
 769    }
 770  1086 if (buddyManager != null)
 771    {
 772  164 buddyManager.init(this);
 773  164 if (configuration.isUseReplQueue())
 774    {
 775  0 log.warn("Replication queue not supported when using buddy replication. Disabling repliction queue.");
 776  0 configuration.setUseReplQueue(false);
 777  0 repl_queue = null;
 778    }
 779    }
 780  1086 break;
 781  0 default:
 782  0 throw new IllegalArgumentException("cache mode " + configuration.getCacheMode() + " is invalid");
 783    }
 784   
 785    //now attempt to preload the cache from the loader - Manik
 786  2811 if (cacheLoaderManager != null)
 787    {
 788  1029 cacheLoaderManager.preloadCache();
 789    }
 790   
 791    // Find out if we are coordinator (blocks until view is received)
 792  2811 determineCoordinator();
 793   
 794    // start any eviction threads.
 795  2811 if (regionManager.isUsingEvictions())
 796    {
 797  377 regionManager.startEvictionThread();
 798    }
 799   
 800  2811 notifier.notifyCacheStarted(this, getInvocationContext());
 801   
 802    // install a VM shutdown hook
 803  2809 Thread shutdownHook = new Thread()
 804    {
 805  1672 public void run()
 806    {
 807  1884 CacheImpl.this.stop();
 808    }
 809    };
 810   
 811  2809 Runtime.getRuntime().addShutdownHook(shutdownHook);
 812   
 813  2809 log.info("JBoss Cache version: " + getVersion());
 814   
 815  2809 cacheStatus = CacheStatus.STARTED;
 816    }
 817   
 818    /**
 819    * Lifecycle method.
 820    */
 821  1436 public void destroy()
 822    {
 823  1436 if (!cacheStatus.destroyAllowed())
 824    {
 825  42 if (cacheStatus.needStopBeforeDestroy())
 826    {
 827  9 try
 828    {
 829  9 stop();
 830    }
 831    catch (CacheException e)
 832    {
 833  0 log.warn("Needed to call stop() before destroying but stop() " +
 834    "threw exception. Proceeding to destroy", e);
 835    }
 836    }
 837    else
 838  33 return;
 839    }
 840   
 841  1403 try
 842    {
 843  1403 internalDestroy();
 844    }
 845    finally
 846    {
 847    // We always progress to destroyed
 848  1403 cacheStatus = CacheStatus.DESTROYED;
 849    }
 850    }
 851   
 852    /**
 853    * The actual destroy implementation.
 854    */
 855  1403 private void internalDestroy()
 856    {
 857  1403 cacheStatus = CacheStatus.DESTROYING;
 858  1403 regionManager = null;
 859  1403 notifier = null;
 860   
 861    // The rest of these should have already been taken care of in stop,
 862    // but we do it here as well in case stop failed.
 863   
 864  1403 if (channel != null)
 865    {
 866  0 if (channel.isOpen())
 867    {
 868  0 try
 869    {
 870  0 channel.close();
 871  0 channel.disconnect();
 872    }
 873    catch (Exception toLog)
 874    {
 875  0 log.error("Problem closing channel; setting it to null", toLog);
 876    }
 877    }
 878  0 channel = null;
 879  0 configuration.getRuntimeConfig().setChannel(null);
 880    }
 881  1403 disp = null;
 882  1403 tm = null;
 883    }
 884   
 885    /**
 886    * Lifecycle method.
 887    */
 888  4536 public void stop()
 889    {
 890  4748 if (!cacheStatus.stopAllowed())
 891    {
 892  1919 return;
 893    }
 894   
 895    // Trying to stop() from FAILED is valid, but may not work
 896  2798 boolean failed = cacheStatus == CacheStatus.FAILED;
 897   
 898  2798 try
 899    {
 900  2798 internalStop();
 901    }
 902    catch (Throwable t)
 903    {
 904  3 if (failed)
 905    {
 906  0 log.warn("Attempted to stop() from FAILED state, " +
 907    "but caught exception; try calling destroy()", t);
 908    }
 909  3 handleLifecycleTransitionFailure(t);
 910    }
 911    }
 912   
 913    /**
 914    * The actual stop implementation.
 915    */
 916  2784 private void internalStop()
 917    {
 918  2798 cacheStatus = CacheStatus.STOPPING;
 919   
 920    // before closing the channel stop the buddy manager
 921  2798 if (buddyManager != null && buddyManager.isEnabled())
 922    {
 923  164 log.debug("stop(): stopping buddy manager");
 924  164 buddyManager.stop();
 925    }
 926   
 927  2798 if (channel != null)
 928    {
 929  1092 log.info("stop(): closing the channel");
 930  1092 killChannel();
 931  1080 channel = null;
 932  1080 configuration.getRuntimeConfig().setChannel(null);
 933    }
 934   
 935  2786 if (disp != null)
 936    {
 937  1080 log.info("stop(): stopping the dispatcher");
 938  1080 disp.stop();
 939  1080 disp = null;
 940    }
 941  2800 if (members != null)
 942    {
 943  2786 synchronized (members)
 944    {
 945  2786 members.clear();
 946    }
 947    }
 948   
 949  2786 coordinator = false;
 950   
 951  2800 if (repl_queue != null)
 952    {
 953  0 repl_queue.stop();
 954    }
 955   
 956  2786 if (cacheLoaderManager != null)
 957    {
 958  1024 log.debug("stop(): stopping cache loader manager");
 959  1024 cacheLoaderManager.stopCacheLoader();
 960    }
 961   
 962  360 if (regionManager.isUsingEvictions()) regionManager.stopEvictionThread();
 963   
 964  2799 if (notifier != null)
 965    {
 966  2785 notifier.notifyCacheStopped(this, getInvocationContext());
 967  2783 notifier.removeAllCacheListeners();
 968    }
 969   
 970    // unset transaction manager reference
 971  2783 tm = null;
 972   
 973  2783 cacheStatus = CacheStatus.STOPPED;
 974   
 975    // empty in-memory state
 976  2783 root.clearDataDirect();
 977  2783 root.removeChildrenDirect();
 978    }
 979   
 980  9201 public CacheStatus getCacheStatus()
 981    {
 982  9201 return cacheStatus;
 983    }
 984   
 985    /* ----------------------- End of MBeanSupport ----------------------- */
 986   
 987    /* ----------------------- Start of buddy replication specific methods ------------*/
 988   
 989    /**
 990    * Sets the buddy replication configuration element
 991    *
 992    * @param config
 993    */
 994  1106 private void setBuddyReplicationConfig(BuddyReplicationConfig config)
 995    {
 996  1106 if (config != null)
 997    {
 998  166 buddyManager = new BuddyManager(config);
 999  166 if (!buddyManager.isEnabled())
 1000    {
 1001  0 buddyManager = null;
 1002    }
 1003    else
 1004    {
 1005  166 internalFqns.add(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
 1006    }
 1007    }
 1008    }
 1009   
 1010    /**
 1011    * Retrieves the Buddy Manager configured.
 1012    *
 1013    * @return null if buddy replication is not enabled.
 1014    */
 1015  6539 public BuddyManager getBuddyManager()
 1016    {
 1017  6539 return buddyManager;
 1018    }
 1019   
 1020    /**
 1021    * Returns a Set<Fqn> of Fqns of the topmost node of internal regions that
 1022    * should not included in standard state transfers. Will include
 1023    * {@link BuddyManager#BUDDY_BACKUP_SUBTREE} if buddy replication is
 1024    * enabled.
 1025    *
 1026    * @return an unmodifiable Set<Fqn>. Will not return <code>null</code>.
 1027    */
 1028  1458 public Set<Fqn> getInternalFqns()
 1029    {
 1030  1458 return Collections.unmodifiableSet(internalFqns);
 1031    }
 1032   
 1033    /* ----------------------- End of buddy replication specific methods ------------*/
 1034   
 1035  2832 protected void createEvictionPolicy()
 1036    {
 1037  2832 if (configuration.getEvictionConfig() != null
 1038    && configuration.getEvictionConfig().isValidConfig())
 1039    {
 1040  375 regionManager.setEvictionConfig(configuration.getEvictionConfig());
 1041  375 regionManager.setUsingEvictions(true);
 1042    }
 1043    else
 1044    {
 1045  2457 regionManager.setUsingEvictions(false);
 1046  2457 log.debug("Not using an EvictionPolicy");
 1047    }
 1048    }
 1049   
 1050    /**
 1051    * Loads the indicated Fqn, plus all parents recursively from the
 1052    * CacheLoader. If no CacheLoader is present, this is a no-op
 1053    *
 1054    * @param fqn
 1055    * @throws Exception
 1056    */
 1057  14 public void load(String fqn) throws Exception
 1058    {
 1059  14 if (cacheLoaderManager != null)
 1060    {
 1061  14 cacheLoaderManager.preload(Fqn.fromString(fqn), true, true);
 1062    }
 1063    }
 1064   
 1065  3242 private void determineCoordinator()
 1066    {
 1067    // Synchronize on members to make the answer atomic for the current view
 1068  3242 synchronized (members)
 1069    {
 1070  3242 Address coord = getCoordinator();
 1071  3242 coordinator = (coord == null ? false : coord.equals(getLocalAddress()));
 1072    }
 1073    }
 1074   
 1075    /**
 1076    * Returns the address of the coordinator or null if there is no
 1077    * coordinator.
 1078    * Waits until the membership view is updated.
 1079    */
 1080  3242 public Address getCoordinator()
 1081    {
 1082  3242 if (channel == null)
 1083    {
 1084  1725 return null;
 1085    }
 1086   
 1087  1517 synchronized (members)
 1088    {
 1089  1517 while (members.isEmpty())
 1090    {
 1091  0 log.debug("getCoordinator(): waiting on viewAccepted()");
 1092  0 try
 1093    {
 1094  0 members.wait();
 1095    }
 1096    catch (InterruptedException e)
 1097    {
 1098  0 log.error("getCoordinator(): Interrupted while waiting for members to be set", e);
 1099  0 break;
 1100    }
 1101    }
 1102  1517 return members.size() > 0 ? members.get(0) : null;
 1103    }
 1104    }
 1105   
 1106    // ----------- Marshalling and State Transfer -----------------------
 1107   
 1108    /**
 1109    * Creates a subtree in the local cache.
 1110    * Returns the DataNode created.
 1111    */
 1112  197 protected Node createSubtreeRootNode(Fqn<?> subtree) throws CacheException
 1113    {
 1114  197 NodeSPI<K, V> parent = root;
 1115  197 NodeSPI<K, V> child = null;
 1116  197 Object owner = getOwnerForLock();
 1117  197 Object name;
 1118  197 NodeFactory<K, V> factory = configuration.getRuntimeConfig().getNodeFactory();
 1119   
 1120  197 for (int i = 0; i < subtree.size(); i++)
 1121    {
 1122  382 name = subtree.get(i);
 1123  382 child = parent.getChildDirect(name);
 1124  382 if (child == null)
 1125    {
 1126    // Lock the parent, create and add the child
 1127  254 try
 1128    {
 1129  254 parent.getLock().acquire(owner, configuration.getSyncReplTimeout(), NodeLock.LockType.WRITE);
 1130    }
 1131    catch (InterruptedException e)
 1132    {
 1133  0 log.error("Interrupted while locking" + parent.getFqn(), e);
 1134  0 throw new CacheException(e.getLocalizedMessage(), e);
 1135    }
 1136   
 1137  254 try
 1138    {
 1139  254 child = factory.createDataNode(name,
 1140    subtree.getAncestor(i + 1),
 1141    parent, null, true);
 1142  254 parent.addChild(name, child);
 1143    }
 1144    finally
 1145    {
 1146  254 if (log.isDebugEnabled())
 1147    {
 1148  0 log.debug("forcing release of locks in " + parent.getFqn());
 1149    }
 1150  254 try
 1151    {
 1152  254 parent.getLock().releaseAll();
 1153    }
 1154    catch (Throwable t)
 1155    {
 1156  0 log.error("failed releasing locks", t);
 1157    }
 1158    }
 1159    }
 1160   
 1161  382 parent = child;
 1162    }
 1163   
 1164  197 return child;
 1165    }
 1166   
 1167    /**
 1168    * Evicts the node at <code>subtree</code> along with all descendant nodes.
 1169    *
 1170    * @param subtree Fqn indicating the uppermost node in the
 1171    * portion of the cache that should be evicted.
 1172    * @throws CacheException
 1173    */
 1174  11 protected void _evictSubtree(Fqn subtree) throws CacheException
 1175    {
 1176   
 1177  11 if (!exists(subtree))
 1178    {
 1179  0 return;// node does not exist. Maybe it has been recursively removed.
 1180    }
 1181   
 1182  11 if (log.isTraceEnabled())
 1183    {
 1184  0 log.trace("_evictSubtree(" + subtree + ")");
 1185    }
 1186   
 1187    // Recursively remove any children
 1188  11 Set children = getChildrenNames(subtree);
 1189  11 if (children != null)
 1190    {
 1191  11 for (Object s : children)
 1192    {
 1193   
 1194  21 Fqn<Object> tmp = new Fqn<Object>(subtree, s);
 1195  21 _remove(null, // no tx
 1196    tmp,
 1197    false, // no undo ops
 1198    false, // no nodeEvent
 1199    true);// is an eviction
 1200    }
 1201    }
 1202   
 1203    // Remove the root node of the subtree
 1204  11 _remove(null, subtree, false, false, true);
 1205   
 1206    }
 1207   
 1208  25830 private void removeLocksForDeadMembers(NodeSPI<K, V> node, List deadMembers)
 1209    {
 1210  25830 Set<GlobalTransaction> deadOwners = new HashSet<GlobalTransaction>();
 1211  25830 NodeLock lock = node.getLock();
 1212  25830 Object owner = lock.getWriterOwner();
 1213   
 1214  25830 if (isLockOwnerDead(owner, deadMembers))
 1215    {
 1216  0 deadOwners.add((GlobalTransaction) owner);
 1217    }
 1218   
 1219  25830 for (Object readOwner : lock.getReaderOwners())
 1220    {
 1221  56 if (isLockOwnerDead(readOwner, deadMembers))
 1222    {
 1223  1 deadOwners.add((GlobalTransaction) readOwner);
 1224    }
 1225    }
 1226   
 1227  25830 for (GlobalTransaction deadOwner : deadOwners)
 1228    {
 1229  1 boolean localTx = deadOwner.getAddress().equals(getLocalAddress());
 1230  1 boolean broken = LockUtil.breakTransactionLock(lock, deadOwner, localTx, this);
 1231   
 1232  1 if (broken && log.isTraceEnabled())
 1233    {
 1234  0 log.trace("Broke lock for node " + node.getFqn() +
 1235    " held by " + deadOwner);
 1236    }
 1237    }
 1238   
 1239    // Recursively unlock children
 1240  25830 for (NodeSPI<K, V> child : node.getChildrenDirect())
 1241    {
 1242  23357 removeLocksForDeadMembers(child, deadMembers);
 1243    }
 1244    }
 1245   
 1246  25886 private boolean isLockOwnerDead(Object owner, List deadMembers)
 1247    {
 1248  25886 boolean result = false;
 1249  25886 if (owner != null && owner instanceof GlobalTransaction)
 1250    {
 1251  82 Object addr = ((GlobalTransaction) owner).getAddress();
 1252  82 result = deadMembers.contains(addr);
 1253    }
 1254  25886 return result;
 1255    }
 1256   
 1257  815 protected void fetchStateOnStartup() throws Exception
 1258    {
 1259  815 long start, stop;
 1260  815 isStateSet = false;
 1261  815 start = System.currentTimeMillis();
 1262  815 boolean rc = channel.getState(null, configuration.getStateRetrievalTimeout());
 1263  814 if (rc)
 1264    {
 1265  383 ml.waitForState();
 1266  377 stop = System.currentTimeMillis();
 1267  377 if (log.isDebugEnabled())
 1268    {
 1269  0 log.debug("state was retrieved successfully (in " + (stop - start) + " milliseconds)");
 1270    }
 1271    }
 1272    else
 1273    {
 1274    // No one provided us with state. We need to find out if that's because
 1275    // we are the coordinator. But we don't know if the viewAccepted() callback
 1276    // has been invoked, so call determineCoordinator(), which will block until
 1277    // viewAccepted() is called at least once
 1278  431 determineCoordinator();
 1279   
 1280  431 if (isCoordinator())
 1281    {
 1282  427 log.debug("State could not be retrieved (we are the first member in group)");
 1283    }
 1284    else
 1285    {
 1286  4 throw new CacheException("Initial state transfer failed: " +
 1287    "Channel.getState() returned false");
 1288    }
 1289    }
 1290    }
 1291   
 1292    // ----------- End Marshalling and State Transfer -----------------------
 1293   
 1294    /**
 1295    * @param fqn fqn String name to retrieve from cache
 1296    * @return DataNode corresponding to the fqn. Null if does not exist. No guarantees wrt replication,
 1297    * cache loading are given if the underlying node is modified
 1298    */
 1299  7257 public Node get(String fqn) throws CacheException
 1300    {
 1301  7257 return get(Fqn.fromString(fqn));
 1302    }
 1303   
 1304    /**
 1305    * Returns a DataNode corresponding to the fully qualified name or null if
 1306    * does not exist.
 1307    * No guarantees wrt replication, cache loading are given if the underlying node is modified
 1308    *
 1309    * @param fqn name of the DataNode to retreive
 1310    */
 1311  374294 public Node<K, V> get(Fqn<?> fqn) throws CacheException
 1312    {
 1313  374294 MethodCall m = MethodCallFactory.create(MethodDeclarations.getNodeMethodLocal, fqn);
 1314  374294 return (Node<K, V>) invokeMethod(m, true);
 1315    }
 1316   
 1317    /**
 1318    * Returns the raw data of the node; called externally internally.
 1319    */
 1320  373059 public Node<K, V> _get(Fqn<?> fqn) throws CacheException
 1321    {
 1322  373059 return findNode(fqn);
 1323    }
 1324   
 1325    /**
 1326    * Returns the raw data of the node; called externally internally.
 1327    */
 1328  40037 public Map _getData(Fqn<?> fqn)
 1329    {
 1330  40037 NodeSPI n = findNode(fqn);
 1331  7 if (n == null) return null;
 1332  40030 return n.getDataDirect();
 1333    }
 1334   
 1335    /**
 1336    * Returns a set of attribute keys for the Fqn.
 1337    * Returns null if the node is not found, otherwise a Set.
 1338    * The set is a copy of the actual keys for this node.
 1339    *
 1340    * @param fqn name of the node
 1341    */
 1342  2176 public Set getKeys(String fqn) throws CacheException
 1343    {
 1344  2176 return getKeys(Fqn.fromString(fqn));
 1345    }
 1346   
 1347    /**
 1348    * Returns a set of attribute keys for the Fqn.
 1349    * Returns null if the node is not found, otherwise a Set.
 1350    * The set is a copy of the actual keys for this node.
 1351    *
 1352    * @param fqn name of the node
 1353    */
 1354  2679 public Set<K> getKeys(Fqn<?> fqn) throws CacheException
 1355    {
 1356  2679 MethodCall m = MethodCallFactory.create(MethodDeclarations.getKeysMethodLocal, fqn);
 1357  2679 return (Set<K>) invokeMethod(m, true);
 1358    }
 1359   
 1360   
 1361  2646 public Set _getKeys(Fqn<?> fqn) throws CacheException
 1362    {
 1363  2646 NodeSPI<K, V> n = findNode(fqn);
 1364  2646 if (n == null)
 1365    {
 1366  28 return null;
 1367    }
 1368  2618 Set<K> keys = n.getKeysDirect();
 1369  2618 return new HashSet<K>(keys);
 1370    }
 1371   
 1372    /**
 1373    * Finds a node given its name and returns the value associated with a given key in its <code>data</code>
 1374    * map. Returns null if the node was not found in the cache or the key was not found in the hashmap.
 1375    *
 1376    * @param fqn The fully qualified name of the node.
 1377    * @param key The key.
 1378    */
 1379  20654 public V get(String fqn, K key) throws CacheException
 1380    {
 1381  20654 return get(Fqn.fromString(fqn), key);
 1382    }
 1383   
 1384   
 1385    /**
 1386    * Finds a node given its name and returns the value associated with a given key in its <code>data</code>
 1387    * map. Returns null if the node was not found in the cache or the key was not found in the hashmap.
 1388    *
 1389    * @param fqn The fully qualified name of the node.
 1390    * @param key The key.
 1391    */
 1392  1511843 public V get(Fqn<?> fqn, K key) throws CacheException
 1393    {
 1394  1511843 return get(fqn, key, true);
 1395    }
 1396   
 1397  463465 public V _get(Fqn<?> fqn, K key, boolean sendNodeEvent) throws CacheException
 1398    {
 1399  463465 InvocationContext ctx = getInvocationContext();
 1400  463465 if (log.isTraceEnabled())
 1401    {
 1402  0 log.trace(new StringBuffer("_get(").append("\"").append(fqn).append("\", \"").append(key).append("\", \"").
 1403    append(sendNodeEvent).append("\")"));
 1404    }
 1405  463458 if (sendNodeEvent) notifier.notifyNodeVisited(fqn, true, ctx);
 1406  463465 NodeSPI<K, V> n = findNode(fqn);
 1407  463465 if (n == null)
 1408    {
 1409  39764 log.trace("node not found");
 1410  39764 return null;
 1411    }
 1412  423695 if (sendNodeEvent) notifier.notifyNodeVisited(fqn, false, ctx);
 1413  423701 return n.getDirect(key);
 1414    }
 1415   
 1416   
 1417  1511843 protected V get(Fqn<?> fqn, K key, boolean sendNodeEvent) throws CacheException
 1418    {
 1419  1511843 MethodCall m = MethodCallFactory.create(MethodDeclarations.getKeyValueMethodLocal, fqn, key, sendNodeEvent);
 1420  1511843 return (V) invokeMethod(m, true);
 1421    }
 1422   
 1423    /**
 1424    * Checks whether a given node exists in current in-memory state of the cache.
 1425    * Does not acquire any locks in doing so (result may be dirty read). Does
 1426    * not attempt to load nodes from a cache loader (may return false if a
 1427    * node has been evicted).
 1428    *
 1429    * @param fqn The fully qualified name of the node
 1430    * @return boolean Whether or not the node exists
 1431    */
 1432  363 public boolean exists(String fqn)
 1433    {
 1434  363 return exists(Fqn.fromString(fqn));
 1435    }
 1436   
 1437   
 1438    /**
 1439    * Checks whether a given node exists in current in-memory state of the cache.
 1440    * Does not acquire any locks in doing so (result may be dirty read). Does
 1441    * not attempt to load nodes from a cache loader (may return false if a
 1442    * node has been evicted).
 1443    *
 1444    * @param fqn The fully qualified name of the node
 1445    * @return boolean Whether or not the node exists
 1446    */
 1447  119394 public boolean exists(Fqn<?> fqn)
 1448    {
 1449  119394 Node n = peek(fqn, false);
 1450  119394 return n != null;
 1451    }
 1452   
 1453    /**
 1454    * Gets node without attempt to load it from CacheLoader if not present
 1455    *
 1456    * @param fqn
 1457    */
 1458  4432744 public NodeSPI<K, V> peek(Fqn<?> fqn, boolean includeDeletedNodes)
 1459    {
 1460  7091 if (fqn == null || fqn.size() == 0) return root;
 1461  4425216 NodeSPI<K, V> n = root;
 1462  4425653 int fqnSize = fqn.size();
 1463  4425653 for (int i = 0; i < fqnSize; i++)
 1464    {
 1465  17801390 Object obj = fqn.get(i);
 1466  17800723 n = n.getChildDirect(obj);
 1467  17800869 if (n == null)
 1468    {
 1469  94486 return null;
 1470    }
 1471  17706904 else if (!includeDeletedNodes && n.isDeleted())
 1472    {
 1473  5319 return null;
 1474    }
 1475    }
 1476  4325848 return n;
 1477    }
 1478   
 1479   
 1480    /**
 1481    * @param fqn
 1482    * @param key
 1483    */
 1484  45 public boolean exists(String fqn, Object key)
 1485    {
 1486  45 return exists(Fqn.fromString(fqn), key);
 1487    }
 1488   
 1489   
 1490    /**
 1491    * Checks whether a given key exists in the given node. Does not interact with CacheLoader, so the behavior is
 1492    * different from {@link #get(Fqn,Object)}
 1493    *
 1494    * @param fqn The fully qualified name of the node
 1495    * @param key
 1496    * @return boolean Whether or not the node exists
 1497    */
 1498  48 public boolean exists(Fqn<?> fqn, Object key)
 1499    {
 1500  48 NodeSPI n = peek(fqn, false);
 1501  48 return n != null && n.getKeysDirect().contains(key);
 1502    }
 1503   
 1504   
 1505    /**
 1506    * Adds a new node to the cache and sets its data. If the node doesn not yet exist, it will be created.
 1507    * Also, parent nodes will be created if not existent. If the node already has data, then the new data
 1508    * will override the old one. If the node already existed, a nodeModified() notification will be generated.
 1509    * Otherwise a nodeCreated() motification will be emitted.
 1510    *
 1511    * @param fqn The fully qualified name of the new node
 1512    * @param data The new data. May be null if no data should be set in the node.
 1513    */
 1514  840 public void put(String fqn, Map data) throws CacheException
 1515    {
 1516  840 put(Fqn.fromString(fqn), data);
 1517    }
 1518   
 1519    /**
 1520    * Sets a node's data. If the node does not yet exist, it will be created.
 1521    * Also, parent nodes will be created if not existent. If the node already has data, then the new data
 1522    * will override the old one. If the node already existed, a nodeModified() notification will be generated.
 1523    * Otherwise a nodeCreated() motification will be emitted.
 1524    *
 1525    * @param fqn The fully qualified name of the new node
 1526    * @param data The new data. May be null if no data should be set in the node.
 1527    */
 1528  11611 public void put(Fqn<?> fqn, Map<K, V> data) throws CacheException
 1529    {
 1530  11611 put(fqn, data, false);
 1531    }
 1532   
 1533  11614 public void put(Fqn<?> fqn, Map<K, V> data, boolean erase) throws CacheException
 1534    {
 1535  11614 GlobalTransaction tx = getCurrentTransaction();
 1536  11614 MethodCall m;
 1537  11614 if (erase)
 1538    {
 1539  3 m = MethodCallFactory.create(MethodDeclarations.putDataEraseMethodLocal, tx, fqn, data, true, true);
 1540    }
 1541    else
 1542    {
 1543  11611 m = MethodCallFactory.create(MethodDeclarations.putDataMethodLocal, tx, fqn, data, true);
 1544    }
 1545  11614 invokeMethod(m, true);
 1546    }
 1547   
 1548    /**
 1549    * Adds a key and value to a given node. If the node doesn't exist, it will be created. If the node
 1550    * already existed, a nodeModified() notification will be generated. Otherwise a
 1551    * nodeCreated() motification will be emitted.
 1552    *
 1553    * @param fqn The fully qualified name of the node
 1554    * @param key The key
 1555    * @param value The value
 1556    * @return Object The previous value (if any), if node was present
 1557    */
 1558  114321 public V put(String fqn, K key, V value) throws CacheException
 1559    {
 1560  114321 return put(Fqn.fromString(fqn), key, value);
 1561    }
 1562   
 1563    /**
 1564    * Adds a key and value to a given node. If the node doesn't exist, it will be created. If the node
 1565    * already existed, a nodeModified() notification will be generated. Otherwise a
 1566    * nodeCreated() motification will be emitted.
 1567    *
 1568    * @param fqn The fully qualified name of the node
 1569    * @param key The key
 1570    * @param value The value
 1571    * @return Object The previous value (if any), if node was present
 1572    */
 1573  364114 public V put(Fqn<?> fqn, K key, V value) throws CacheException
 1574    {
 1575  364114 GlobalTransaction tx = getCurrentTransaction();
 1576  364114 MethodCall m = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal, tx, fqn, key, value, true);
 1577  364114 return (V) invokeMethod(m, true);
 1578    }
 1579   
 1580    /**
 1581    * Removes the node from the cache.
 1582    *
 1583    * @param fqn The fully qualified name of the node.
 1584    */
 1585  1044 public void remove(String fqn) throws CacheException
 1586    {
 1587  1044 remove(Fqn.fromString(fqn));
 1588    }
 1589   
 1590    /**
 1591    * Removes the node from the cache.
 1592    *
 1593    * @param fqn The fully qualified name of the node.
 1594    */
 1595  17897 public boolean remove(Fqn fqn) throws CacheException
 1596    {
 1597  17897 GlobalTransaction tx = getCurrentTransaction();
 1598    // special case if we are removing the root. Remove all children instead.
 1599  17897 if (fqn.isRoot())
 1600    {
 1601  1115 boolean result = true;
 1602    // we need to preserve options
 1603  1115 InvocationContext ctx = getInvocationContext();
 1604  1115 Option o = ctx.getOptionOverrides();
 1605  1115 for (Object childName : _getChildrenNames(fqn))
 1606    {
 1607  774 ctx.setOptionOverrides(o);
 1608  774 result = remove(new Fqn<Object>(fqn, childName)) && result;
 1609    }
 1610   
 1611  1115 return result;
 1612    }
 1613    else
 1614    {
 1615  16782 MethodCall m = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, tx, fqn, true);
 1616  16782 Object retval = invokeMethod(m, true);
 1617  16777 return retval != null && (Boolean) retval;
 1618    }
 1619    }
 1620   
 1621    /**
 1622    * Called by eviction policy provider. Note that eviction is done only in
 1623    * local mode, that is, it doesn't replicate the node removal. This will
 1624    * cause the replication nodes to not be synchronizing, which is fine since
 1625    * the value will be fetched again when {@link #get} returns null. After
 1626    * that, the contents will be in sync.
 1627    *
 1628    * @param fqn Will remove everythign assoicated with this fqn.
 1629    * @throws CacheException
 1630    */
 1631  118129 public void evict(Fqn fqn) throws CacheException
 1632    {
 1633  118129 if (fqn.isRoot())
 1634    {
 1635    // special treatment for root eviction
 1636    // we need to preserve options
 1637  28 InvocationContext ctx = getInvocationContext();
 1638  28 Option o = ctx.getOptionOverrides();
 1639  28 for (Object childName : _getChildrenNames(fqn))
 1640    {
 1641  0 ctx.setOptionOverrides(o);
 1642  0 evict(new Fqn<Object>(fqn, childName));
 1643    }
 1644    }
 1645    else
 1646    {
 1647  118101 MethodCall m = MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, fqn);
 1648  118101 invokeMethod(m, true);
 1649    }
 1650    }
 1651   
 1652    /**
 1653    * Removes <code>key</code> from the node's hashmap
 1654    *
 1655    * @param fqn The fullly qualified name of the node
 1656    * @param key The key to be removed
 1657    * @return The previous value, or null if none was associated with the given key
 1658    */
 1659  90 public V remove(String fqn, K key) throws CacheException
 1660    {
 1661  90 return remove(Fqn.fromString(fqn), key);
 1662    }
 1663   
 1664    /**
 1665    * Removes <code>key</code> from the node's hashmap
 1666    *
 1667    * @param fqn The fullly qualified name of the node
 1668    * @param key The key to be removed
 1669    * @return The previous value, or null if none was associated with the given key
 1670    */
 1671  4261 public V remove(Fqn<?> fqn, K key) throws CacheException
 1672    {
 1673  4261 GlobalTransaction tx = getCurrentTransaction();
 1674  4261 MethodCall m = MethodCallFactory.create(MethodDeclarations.removeKeyMethodLocal, tx, fqn, key, true);
 1675  4261 return (V) invokeMethod(m, true);
 1676    }
 1677   
 1678    /**
 1679    * Removes the keys and properties from a node.
 1680    */
 1681  18 public void removeData(String fqn) throws CacheException
 1682    {
 1683  18 removeData(Fqn.fromString(fqn));
 1684    }
 1685   
 1686    /**
 1687    * Removes the keys and properties from a named node.
 1688    */
 1689  1950 public void removeData(Fqn fqn) throws CacheException
 1690    {
 1691  1950 GlobalTransaction tx = getCurrentTransaction();
 1692  1950 MethodCall m = MethodCallFactory.create(MethodDeclarations.removeDataMethodLocal, tx, fqn, true);
 1693  1950 invokeMethod(m, true);
 1694    }
 1695   
 1696    /**
 1697    * Lock a given node (or the entire subtree starting at this node)
 1698    * @param fqn The FQN of the node
 1699    * @param owner The owner. This is simply a key into a hashtable, and can be anything, e.g.
 1700    * a GlobalTransaction, the current thread, or a special object. If null, it is set to Thread.currentThread()
 1701    * @param lock_type The type of lock (RO, RW). Needs to be of type DataNode.LOCK_TYPE_READ or DataNode.LOCK_TYPE_WRITE
 1702    * @param lock_recursive If true, the entire subtree is locked, else only the given node
 1703    * @throws CacheException If node doesn't exist, a NodeNotExistsException is throw. Other exceptions are
 1704    * LockingException, TimeoutException and UpgradeException
 1705    */
 1706    // public void lock(Fqn fqn, Object owner, int lock_type, boolean lock_recursive) throws CacheException {
 1707    //
 1708    // }
 1709   
 1710    /**
 1711    * Unlock a given node (or the entire subtree starting at this node)
 1712    * @param fqn The FQN of the node
 1713    * @param owner The owner. This is simply a key into a hashtable, and can be anything, e.g.
 1714    * a GlobalTransaction, the current thread, or a special object. If null, it is set to Thread.currentThread()
 1715    * @param unlock_recursive If true, the entire subtree is unlocked, else only the given node
 1716    * @param force Release the lock even if we're not the owner
 1717    */
 1718    // public void unlock(Fqn fqn, Object owner, boolean unlock_recursive, boolean force) {
 1719    //
 1720    // }
 1721   
 1722    /**
 1723    * Releases all locks for this node and the entire node subtree.
 1724    */
 1725  2 public void releaseAllLocks(String fqn)
 1726    {
 1727  2 releaseAllLocks(Fqn.fromString(fqn));
 1728    }
 1729   
 1730    /**
 1731    * Releases all locks for this node and the entire node subtree.
 1732    */
 1733  2 public void releaseAllLocks(Fqn fqn)
 1734    {
 1735  2 MethodCall m = MethodCallFactory.create(MethodDeclarations.releaseAllLocksMethodLocal, fqn);
 1736  2 try
 1737    {
 1738  2 invokeMethod(m, true);
 1739    }
 1740    catch (CacheException e)
 1741    {
 1742  0 log.error("failed releasing all locks for " + fqn, e);
 1743    }
 1744    }
 1745   
 1746    /**
 1747    * Prints a representation of the node defined by <code>fqn</code>.
 1748    * Output includes name, fqn and data.
 1749    */
 1750  4 public String print(String fqn)
 1751    {
 1752  4 return print(Fqn.fromString(fqn));
 1753    }
 1754   
 1755    /**
 1756    * Prints a representation of the node defined by <code>fqn</code>.
 1757    * Output includes name, fqn and data.
 1758    */
 1759  21 public String print(Fqn fqn)
 1760    {
 1761  21 MethodCall m = MethodCallFactory.create(MethodDeclarations.printMethodLocal, fqn);
 1762  21 Object retval = null;
 1763  21 try
 1764    {
 1765  21 retval = invokeMethod(m, true);
 1766    }
 1767    catch (Throwable e)
 1768    {
 1769  0 retval = e;
 1770    }
 1771  21 if (retval != null)
 1772    {
 1773  21 return retval.toString();
 1774    }
 1775    else
 1776    {
 1777  0 return "";
 1778    }
 1779    }
 1780   
 1781   
 1782    /**
 1783    * Returns all children of a given node.
 1784    * Returns null of the parent node was not found, or if there are no
 1785    * children.
 1786    * The set is unmodifiable.
 1787    *
 1788    * @param fqn The fully qualified name of the node
 1789    * @return Set A list of child names (as Strings)
 1790    * @see #getChildrenNames(Fqn)
 1791    */
 1792  279 public Set getChildrenNames(String fqn) throws CacheException
 1793    {
 1794  279 return getChildrenNames(Fqn.fromString(fqn));
 1795    }
 1796   
 1797    /**
 1798    * Returns all children of a given node. Returns an empty set if there are no children.
 1799    * The set is unmodifiable.
 1800    *
 1801    * @param fqn The fully qualified name of the node
 1802    * @return Set an unmodifiable set of children names, Object.
 1803    */
 1804  25178 public <E> Set<E> getChildrenNames(Fqn<E> fqn) throws CacheException
 1805    {
 1806  25178 MethodCall m = MethodCallFactory.create(MethodDeclarations.getChildrenNamesMethodLocal, fqn);
 1807  25178 Set<E> retval = null;
 1808  25178 retval = (Set<E>) invokeMethod(m, true);
 1809  25178 if (retval != null)
 1810  25138 retval = Collections.unmodifiableSet(new HashSet<E>(retval));
 1811    else
 1812  40 retval = Collections.emptySet();
 1813  25178 return retval;
 1814    }
 1815   
 1816  106049 public <E> Set<E> _getChildrenNames(Fqn<E> fqn) throws CacheException
 1817    {
 1818  106049 NodeSPI<K, V> n = findNode(fqn);
 1819  41 if (n == null) return null;
 1820  106008 Set<E> s = (Set<E>) n.getChildrenNamesDirect();
 1821  106008 return s;
 1822    }
 1823   
 1824    /**
 1825    * Returns true if the FQN exists and the node has children.
 1826    */
 1827  87903 public boolean hasChild(Fqn fqn)
 1828    {
 1829  0 if (fqn == null) return false;
 1830   
 1831  87903 NodeSPI n = findNode(fqn);
 1832  87903 return n != null && n.hasChildrenDirect();
 1833    }
 1834   
 1835    /**
 1836    * Returns a debug string with few details.
 1837    */
 1838  839 public String toString()
 1839    {
 1840  839 return toString(true);
 1841    }
 1842   
 1843   
 1844    /**
 1845    * Returns a debug string with optional details of contents.
 1846    */
 1847  910 public String toString(boolean details)
 1848    {
 1849  910 StringBuffer sb = new StringBuffer();
 1850  910 int indent = 0;
 1851   
 1852  910 if (!details)
 1853    {
 1854  0 sb.append(getClass().getName()).append(" [").append(getNumberOfNodes()).append(" nodes, ");
 1855  0 sb.append(getNumberOfLocksHeld()).append(" locks]");
 1856    }
 1857    else
 1858    {
 1859  910 if (root == null)
 1860  0 return sb.toString();
 1861  910 for (NodeSPI n : root.getChildrenDirect())
 1862    {
 1863  1573 n.print(sb, indent);
 1864  1573 sb.append("\n");
 1865    }
 1866    }
 1867  910 return sb.toString();
 1868    }
 1869   
 1870   
 1871    /**
 1872    * Prints information about the contents of the nodes in the cache's current
 1873    * in-memory state. Does not load any previously evicted nodes from a
 1874    * cache loader, so evicted nodes will not be included.
 1875    */
 1876  68 public String printDetails()
 1877    {
 1878  68 StringBuffer sb = new StringBuffer();
 1879  68 root.printDetails(sb, 0);
 1880  68 sb.append("\n");
 1881  68 return sb.toString();
 1882    }
 1883   
 1884    /**
 1885    * Returns lock information.
 1886    */
 1887  532 public String printLockInfo()
 1888    {
 1889  532 StringBuffer sb = new StringBuffer("\n");
 1890  532 int indent = 0;
 1891   
 1892  532 for (NodeSPI n : root.getChildrenDirect())
 1893    {
 1894  522 n.getLock().printLockInfo(sb, indent);
 1895  522 sb.append("\n");
 1896    }
 1897  532 return sb.toString();
 1898    }
 1899   
 1900    /**
 1901    * Returns the number of read or write locks held across the entire cache.
 1902    */
 1903  390 public int getNumberOfLocksHeld()
 1904    {
 1905  390 return numLocks(root);
 1906    }
 1907   
 1908  223621 private int numLocks(NodeSPI<K, V> n)
 1909    {
 1910  223621 int num = 0;
 1911  223621 if (n.getLock().isLocked())
 1912    {
 1913  236 num++;
 1914    }
 1915  223621 for (NodeSPI<K, V> cn : n.getChildrenDirect(true))
 1916    {
 1917  223231 num += numLocks(cn);
 1918    }
 1919  223621 return num;
 1920    }
 1921   
 1922    /**
 1923    * Returns an <em>approximation</em> of the total number of nodes in the
 1924    * cache. Since this method doesn't acquire any locks, the number might be
 1925    * incorrect, or the method might even throw a
 1926    * ConcurrentModificationException
 1927    */
 1928  93 public int getNumberOfNodes()
 1929    {
 1930  93 return numNodes(root) - 1;
 1931    }
 1932   
 1933  227506 private int numNodes(NodeSPI<K, V> n)
 1934    {
 1935  227506 int count = 1;// for n
 1936  227506 for (NodeSPI<K, V> child : n.getChildrenDirect())
 1937    {
 1938  227413 count += numNodes(child);
 1939    }
 1940  227506 return count;
 1941    }
 1942   
 1943    /**
 1944    * Returns an <em>approximation</em> of the total number of attributes in
 1945    * the cache. Since this method doesn't acquire any locks, the number might
 1946    * be incorrect, or the method might even throw a
 1947    * ConcurrentModificationException
 1948    */
 1949  10 public int getNumberOfAttributes()
 1950    {
 1951  10 return numAttributes(root);
 1952    }
 1953   
 1954    /**
 1955    * Returns an <em>approximation</em> of the total number of attributes in
 1956    * this sub cache.
 1957    *
 1958    * @see #getNumberOfAttributes
 1959    */
 1960  0 public int getNumberOfAttributes(Fqn fqn)
 1961    {
 1962  0 return numAttributes(findNode(fqn));
 1963    }
 1964   
 1965  51 private int numAttributes(NodeSPI<K, V> n)
 1966    {
 1967  51 int count = 0;
 1968  51 for (NodeSPI<K, V> child : n.getChildrenDirect())
 1969    {
 1970  41 count += numAttributes(child);
 1971    }
 1972  51 count += n.getDataDirect().size();
 1973  51 return count;
 1974    }
 1975   
 1976    /* ---------------------- Remote method calls -------------------- */
 1977   
 1978    /**
 1979    * @param mbrs
 1980    * @param method_call
 1981    * @param synchronous
 1982    * @param exclude_self
 1983    * @param timeout
 1984    * @return
 1985    * @throws Exception
 1986    * @deprecated Note this is due to be moved to an interceptor.
 1987    */
 1988  113894 @Deprecated
 1989    public List callRemoteMethods(List<Address> mbrs, MethodCall method_call,
 1990    boolean synchronous, boolean exclude_self, long timeout)
 1991    throws Exception
 1992    {
 1993  113894 return callRemoteMethods(mbrs, method_call, synchronous ? GroupRequest.GET_ALL : GroupRequest.GET_NONE, exclude_self, timeout);
 1994    }
 1995   
 1996   
 1997    /**
 1998    * Overloaded to allow a finer grained control over JGroups mode
 1999    *
 2000    * @param mbrs
 2001    * @param method_call
 2002    * @param mode
 2003    * @param exclude_self
 2004    * @param timeout
 2005    * @return
 2006    * @throws Exception
 2007    * @deprecated Note this is due to be moved to an interceptor.
 2008    */
 2009  233983 @Deprecated
 2010    public List callRemoteMethods(List<Address> mbrs, MethodCall method_call, int mode, boolean exclude_self, long timeout)
 2011    throws Exception
 2012    {
 2013  233983 RspList rsps;
 2014  233983 Rsp rsp;
 2015  233983 List retval;
 2016  233983 Vector<Address> validMembers;
 2017   
 2018  233983 if (disp == null)
 2019    {
 2020  11 return null;
 2021    }
 2022   
 2023  233972 validMembers = null;
 2024  233972 if (mbrs != null)
 2025  233640 validMembers = new Vector<Address>(mbrs);
 2026    else
 2027    {
 2028  332 synchronized (members)
 2029    {
 2030  332 validMembers = new Vector<Address>(this.members);
 2031    }
 2032    }
 2033   
 2034  233972 if (exclude_self && !validMembers.isEmpty())
 2035    {
 2036  233946 Object local_addr = getLocalAddress();
 2037  233946 if (local_addr != null)
 2038    {
 2039  233946 validMembers.remove(local_addr);
 2040    }
 2041    }
 2042  233972 if (validMembers.isEmpty())
 2043    {
 2044  70460 if (log.isTraceEnabled())
 2045    {
 2046  0 log.trace("destination list is empty, discarding call");
 2047    }
 2048  70460 return null;
 2049    }
 2050   
 2051  163512 if (log.isTraceEnabled())
 2052    {
 2053  0 log.trace("callRemoteMethods(): valid members are " + validMembers + " methods: " + method_call.getArgs()[0]);
 2054    }
 2055   
 2056  163512 rsps = disp.callRemoteMethods(validMembers, method_call, mode, timeout, buddyManager != null && buddyManager.isEnabled());
 2057   
 2058    // a null response is 99% likely to be due to a marshalling problem - we throw a NSE, this needs to be changed when
 2059    // JGroups supports http://jira.jboss.com/jira/browse/JGRP-193
 2060  163507 if (rsps == null)
 2061    {
 2062    // return null;
 2063  0 throw new NotSerializableException("RpcDispatcher returned a null. This is most often caused by args for " + method_call + " not being serializable.");
 2064    }
 2065  163507 if (mode == GroupRequest.GET_NONE)
 2066    {
 2067  537 return Collections.EMPTY_LIST;// async case
 2068    }
 2069   
 2070  162970 if (log.isTraceEnabled())
 2071    {
 2072  0 log.trace("(" + getLocalAddress() + "): responses for method " + method_call.getName() + ":\n" + rsps);
 2073    }
 2074   
 2075  162970 retval = new ArrayList(rsps.size());
 2076  162970 for (int i = 0; i < rsps.size(); i++)
 2077    {
 2078  163296 rsp = (Rsp) rsps.elementAt(i);
 2079  163296 if (rsp.wasSuspected() || !rsp.wasReceived())
 2080    {
 2081  22 CacheException ex;
 2082  22 if (rsp.wasSuspected())
 2083    {
 2084  3 ex = new SuspectException("Suspected member: " + rsp.getSender());
 2085    }
 2086    else
 2087    {
 2088  19 ex = new TimeoutException("Replication timeout for " + rsp.getSender());
 2089    }
 2090  22 retval.add(new ReplicationException("rsp=" + rsp, ex));
 2091    }
 2092    else
 2093    {
 2094  163274 retval.add(rsp.getValue());
 2095    }
 2096    }
 2097  162969 return retval;
 2098    }
 2099   
 2100    /**
 2101    * @param members
 2102    * @param method
 2103    * @param args
 2104    * @param synchronous
 2105    * @param exclude_self
 2106    * @param timeout
 2107    * @return
 2108    * @throws Exception
 2109    * @deprecated Note this is due to be moved to an interceptor.
 2110    */
 2111  113266 @Deprecated
 2112    public List callRemoteMethods(List<Address> members, Method method, Object[] args,
 2113    boolean synchronous, boolean exclude_self, long timeout)
 2114    throws Exception
 2115    {
 2116  113266 return callRemoteMethods(members, MethodCallFactory.create(method, args), synchronous, exclude_self, timeout);
 2117    }
 2118   
 2119    /**
 2120    * @param members
 2121    * @param method_name
 2122    * @param types
 2123    * @param args
 2124    * @param synchronous
 2125    * @param exclude_self
 2126    * @param timeout
 2127    * @return
 2128    * @throws Exception
 2129    * @deprecated Note this is due to be moved to an interceptor.
 2130    */
 2131  0 @Deprecated
 2132    public List callRemoteMethods(Vector<Address> members, String method_name,
 2133    Class[] types, Object[] args,
 2134    boolean synchronous, boolean exclude_self, long timeout)
 2135    throws Exception
 2136    {
 2137  0 Method method = getClass().getDeclaredMethod(method_name, types);
 2138  0 return callRemoteMethods(members, method, args, synchronous, exclude_self, timeout);
 2139    }
 2140   
 2141    /* -------------------- End Remote method calls ------------------ */
 2142   
 2143    /* --------------------- Callbacks -------------------------- */
 2144   
 2145    /* ----- These are VERSIONED callbacks to facilitate JBCACHE-843. Also see docs/design/DataVersion.txt --- */
 2146   
 2147  0 public void _putForExternalRead(GlobalTransaction gtx, Fqn fqn, K key, V value, DataVersion dv) throws CacheException
 2148    {
 2149  0 _putForExternalRead(gtx, fqn, key, value);
 2150    }
 2151   
 2152  0 public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops, DataVersion dv) throws CacheException
 2153    {
 2154  0 _put(tx, fqn, data, create_undo_ops, false, dv);
 2155    }
 2156   
 2157  0 public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops, boolean erase_contents, DataVersion dv) throws CacheException
 2158    {
 2159  0 _put(tx, fqn, data, create_undo_ops, erase_contents);
 2160    }
 2161   
 2162  0 public Object _put(GlobalTransaction tx, Fqn fqn, K key, V value, boolean create_undo_ops, DataVersion dv) throws CacheException
 2163    {
 2164  0 return _put(tx, fqn, key, value, create_undo_ops);
 2165    }
 2166   
 2167  0 public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, DataVersion dv) throws CacheException
 2168    {
 2169  0 return _remove(tx, fqn, create_undo_ops, true);
 2170    }
 2171   
 2172  0 public Object _remove(GlobalTransaction tx, Fqn fqn, K key, boolean create_undo_ops, DataVersion dv) throws CacheException
 2173    {
 2174  0 return _remove(tx, fqn, key, create_undo_ops);
 2175    }
 2176   
 2177  0 public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, DataVersion dv) throws CacheException
 2178    {
 2179   
 2180  0 _removeData(tx, fqn, create_undo_ops, true);
 2181    }
 2182   
 2183    /* ----- End VERSIONED callbacks - Now for the NORMAL callbacks. -------- */
 2184   
 2185    /**
 2186    * Internal put method.
 2187    * Does the real work. Needs to acquire locks if accessing nodes, depending on
 2188    * the value of <tt>locking</tt>. If run inside a transaction, needs to (a) add
 2189    * newly acquired locks to {@link TransactionEntry}'s lock list, (b) add nodes
 2190    * that were created to {@link TransactionEntry}'s node list and (c) create
 2191    * {@link Modification}s and add them to {@link TransactionEntry}'s modification
 2192    * list and (d) create compensating modifications to undo the changes in case
 2193    * of a rollback
 2194    *
 2195    * @param fqn
 2196    * @param data
 2197    * @param create_undo_ops If true, undo operations will be created (default is true).
 2198    * Otherwise they will not be created (used by rollback()).
 2199    */
 2200  0 public void _put(GlobalTransaction tx, String fqn, Map<K, V> data, boolean create_undo_ops)
 2201    throws CacheException
 2202    {
 2203  0 _put(tx, Fqn.fromString(fqn), data, create_undo_ops);
 2204    }
 2205   
 2206   
 2207    /**
 2208    * Internal put method.
 2209    * Does the real work. Needs to acquire locks if accessing nodes, depending on
 2210    * the value of <tt>locking</tt>. If run inside a transaction, needs to (a) add
 2211    * newly acquired locks to {@link TransactionEntry}'s lock list, (b) add nodes
 2212    * that were created to {@link TransactionEntry}'s node list and (c) create
 2213    * {@link Modification}s and add them to {@link TransactionEntry}'s modification
 2214    * list and (d) create compensating modifications to undo the changes in case
 2215    * of a rollback
 2216    *
 2217    * @param fqn
 2218    * @param data
 2219    * @param create_undo_ops If true, undo operations will be created (default is true).
 2220    * Otherwise they will not be created (used by rollback()).
 2221    */
 2222  11998 public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops)
 2223    throws CacheException
 2224    {
 2225  11998 _put(tx, fqn, data, create_undo_ops, false);
 2226    }
 2227   
 2228    /**
 2229    * Internal put method.
 2230    * Does the real work. Needs to acquire locks if accessing nodes, depending on
 2231    * the value of <tt>locking</tt>. If run inside a transaction, needs to (a) add
 2232    * newly acquired locks to {@link TransactionEntry}'s lock list, (b) add nodes
 2233    * that were created to {@link TransactionEntry}'s node list and (c) create
 2234    * {@link Modification}s and add them to {@link TransactionEntry}'s modification
 2235    * list and (d) create compensating modifications to undo the changes in case
 2236    * of a rollback
 2237    *
 2238    * @param fqn
 2239    * @param data
 2240    * @param create_undo_ops If true, undo operations will be created (default is true).
 2241    * @param erase_contents Clear the existing hashmap before putting the new data into it
 2242    * Otherwise they will not be created (used by rollback()).
 2243    */
 2244  12101 public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops, boolean erase_contents)
 2245    throws CacheException
 2246    {
 2247  12101 if (log.isTraceEnabled())
 2248    {
 2249  0 log.trace("_put(" + tx + ", \"" + fqn + "\", " + data + " undo=" + create_undo_ops + " erase=" + erase_contents + ")");
 2250    }
 2251  12101 InvocationContext ctx = getInvocationContext();
 2252  12101 boolean isRollback = checkIsRollingBack(ctx.getTransaction());
 2253  12101 NodeSPI<K, V> n = findNodeCheck(tx, fqn);
 2254  12100 Map<K, V> rawData = n.getDataDirect();
 2255  11972 if (!isRollback) notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.PUT_MAP, rawData, ctx);
 2256   
 2257    // create a compensating method call (reverting the effect of
 2258    // this modification) and put it into the TX's undo list.
 2259  12100 if (tx != null && create_undo_ops)
 2260    {
 2261    // erase and set to previous hashmap contents
 2262  8530 MethodCall undo_op = MethodCallFactory.create(MethodDeclarations.putDataEraseMethodLocal, tx, fqn, rawData, false, true);
 2263  8530 tx_table.addUndoOperation(tx, undo_op);
 2264    }
 2265   
 2266  12100 if (erase_contents)
 2267  101 n.clearDataDirect();
 2268  12100 n.putAllDirect(data);
 2269   
 2270  12100 if (!isRollback)
 2271  11972 notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.PUT_MAP, n.getDataDirect(), ctx);
 2272    }
 2273   
 2274    /**
 2275    * Internal put method.
 2276    *
 2277    * @return Previous value (if any)
 2278    */
 2279  0 public Object _put(GlobalTransaction tx, String fqn, K key, V value, boolean create_undo_ops)
 2280    throws CacheException
 2281    {
 2282  0 return _put(tx, Fqn.fromString(fqn), key, value, create_undo_ops);
 2283    }
 2284   
 2285  530164 private boolean checkIsRollingBack(Transaction tx)
 2286    {
 2287  530164 try
 2288    {
 2289  530164 return tx != null && (
 2290    tx.getStatus() == javax.transaction.Status.STATUS_ROLLEDBACK ||
 2291    tx.getStatus() == javax.transaction.Status.STATUS_ROLLING_BACK ||
 2292    tx.getStatus() == javax.transaction.Status.STATUS_MARKED_ROLLBACK);
 2293    }
 2294    catch (Exception e)
 2295    {
 2296    // can't get a hold of a transaction - probably no tx rolling back
 2297  0 return false;
 2298    }
 2299    }
 2300   
 2301    /**
 2302    * Internal put method.
 2303    *
 2304    * @return Previous value (if any)
 2305    */
 2306  406969 public Object _put(GlobalTransaction tx, Fqn fqn, K key, V value, boolean create_undo_ops)
 2307    throws CacheException
 2308    {
 2309  406969 if (log.isTraceEnabled())
 2310    {
 2311  0 log.trace(new StringBuffer("_put(").append(tx).append(", \"").
 2312    append(fqn).append("\", k=").append(key).append(", v=").append(value).append(")"));
 2313    }
 2314   
 2315   
 2316  406969 InvocationContext ctx = getInvocationContext();
 2317    // if this is a rollback then don't fire notifications.
 2318  406969 boolean isRollback = checkIsRollingBack(ctx.getTransaction());
 2319   
 2320  406969 NodeSPI<K, V> n = findNodeCheck(tx, fqn);
 2321  406969 Map<K, V> rawData = n.getDataDirect();
 2322  406969 if (!isRollback)
 2323  406576 notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.PUT_DATA, rawData, ctx);
 2324   
 2325  406969 V old_value = n.putDirect(key, value);
 2326   
 2327    // create a compensating method call (reverting the effect of
 2328    // this modification) and put it into the TX's undo list.
 2329  406969 if (tx != null && create_undo_ops)
 2330    {
 2331  142050 MethodCall undo_op;
 2332  142050 if (old_value == null)
 2333    {
 2334  48443 undo_op = MethodCallFactory.create(MethodDeclarations.removeKeyMethodLocal, tx, fqn, key, false);
 2335    }
 2336    else
 2337    {
 2338  93607 undo_op = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal, tx, fqn, key, old_value, false);
 2339    }
 2340    // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
 2341  142050 tx_table.addUndoOperation(tx, undo_op);
 2342    }
 2343   
 2344  406969 Map<K, V> newData = Collections.singletonMap(key, value);
 2345  406969 if (!isRollback)
 2346  406576 notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.PUT_DATA, newData, ctx);
 2347  406969 return old_value;
 2348    }
 2349   
 2350    /**
 2351    * Internal remove method.
 2352    */
 2353  0 public void _remove(GlobalTransaction tx, String fqn, boolean create_undo_ops) throws CacheException
 2354    {
 2355  0 _remove(tx, Fqn.fromString(fqn), create_undo_ops);
 2356    }
 2357   
 2358    /**
 2359    * Internal remove method.
 2360    */
 2361  17478 public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops) throws CacheException
 2362    {
 2363  17478 return _remove(tx, fqn, create_undo_ops, true);
 2364    }
 2365   
 2366  17478 public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent)
 2367    throws CacheException
 2368    {
 2369  17478 return _remove(tx, fqn, create_undo_ops, sendNodeEvent, false);
 2370    }
 2371   
 2372    /**
 2373    * Internal method to remove a node.
 2374    *
 2375    * @param tx
 2376    * @param fqn
 2377    * @param create_undo_ops
 2378    * @param sendNodeEvent
 2379    */
 2380  105243 public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction)
 2381    throws CacheException
 2382    {
 2383  105243 return _remove(tx, fqn, create_undo_ops, sendNodeEvent, eviction, null);
 2384    }
 2385   
 2386    /**
 2387    * Internal method to remove a node.
 2388    * Performs a remove on a node, passing in a {@link DataVersion} which is used with optimistically locked nodes. Pass
 2389    * in a null if optimistic locking is not used.
 2390    *
 2391    * @param tx
 2392    * @param fqn
 2393    * @param create_undo_ops
 2394    * @param sendNodeEvent
 2395    * @param eviction
 2396    * @param version
 2397    * @return true if the node was removed, false if not found
 2398    * @throws CacheException
 2399    */
 2400  105243 public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction, DataVersion version)
 2401    throws CacheException
 2402    {
 2403   
 2404  105243 NodeSPI<K, V> n;
 2405  105243 NodeSPI<K, V> parent_node;
 2406  105243 MethodCall undo_op = null;
 2407   
 2408  105243 if (log.isTraceEnabled())
 2409    {
 2410  0 log.trace("_remove(" + tx + ", \"" + fqn + "\", undo=" + create_undo_ops + ")");
 2411    }
 2412  105243 InvocationContext ctx = getInvocationContext();
 2413    // check if this is triggered by a rollback operation ...
 2414  105243 boolean isRollback = checkIsRollingBack(ctx.getTransaction());
 2415  105243 if (tx != null)
 2416    {
 2417  11951 try
 2418    {
 2419  11951 if (isRollback)
 2420    {
 2421  419 log.trace("This remove call is triggered by a transaction rollback, as a compensation operation. Do a realRemove() instead.");
 2422  419 return realRemove(fqn, true);
 2423    }
 2424    }
 2425    catch (Exception e)
 2426    {
 2427    // what do we do here?
 2428  0 log.warn("Unable to get a hold of the transaction for a supposedly transactional call! This *may* result in stale locks!", e);
 2429    }
 2430    }
 2431   
 2432    // Find the node. This will add the temporarily created parent nodes to the TX's node list if tx != null)
 2433  104824 n = findNode(fqn, version);
 2434  104824 if (n == null)
 2435    {
 2436  2904 if (log.isTraceEnabled())
 2437    {
 2438  0 log.trace("node " + fqn + " not found");
 2439    }
 2440  2904 return false;
 2441    }
 2442   
 2443  101920 if (!isRollback)
 2444    {
 2445  101920 if (eviction)
 2446    {
 2447  87765 notifier.notifyNodeEvicted(fqn, true, ctx);
 2448    }
 2449    else
 2450    {
 2451  14155 notifier.notifyNodeRemoved(fqn, true, n.getDataDirect(), ctx);
 2452    }
 2453    }
 2454   
 2455  101920 parent_node = n.getParent();
 2456  101920 boolean found;
 2457   
 2458    // remove subtree from parent
 2459  101920 if (eviction || configuration.isNodeLockingOptimistic())
 2460    {
 2461    // if there is no parent node and the fqn is root, found == true otherwise found == false.
 2462  87765 found = parent_node == null ? fqn.isRoot() : parent_node.removeChildDirect(n.getFqn().getLastElement());
 2463    }
 2464    else
 2465    {
 2466  14155 found = !n.isDeleted();
 2467  14155 n.markAsDeleted(true);
 2468    }
 2469   
 2470  101920 if (eviction && parent_node != null)
 2471    {
 2472  87761 parent_node.setChildrenLoaded(false);
 2473    }
 2474   
 2475    // release all locks for the entire subtree
 2476    // n.getNodeSPI().getLock().releaseAll(tx != null ? tx : (Object) Thread.currentThread());
 2477   
 2478    // create a compensating method call (reverting the effect of
 2479    // this modification) and put it into the TX's undo list.
 2480  101920 if (tx != null && create_undo_ops && !eviction)
 2481    {
 2482  10836 undo_op = MethodCallFactory.create(MethodDeclarations.addChildMethodLocal, tx, parent_node.getFqn(), n.getFqn().getLastElement(), n, false);
 2483   
 2484    // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
 2485  10836 tx_table.addUndoOperation(tx, undo_op);
 2486    }
 2487   
 2488  101920 if (!isRollback)
 2489    {
 2490  101920 if (eviction)
 2491    {
 2492  87765 notifier.notifyNodeEvicted(fqn, false, ctx);
 2493    }
 2494    else
 2495    {
 2496  14155 notifier.notifyNodeRemoved(fqn, false, null, ctx);
 2497    }
 2498    }
 2499   
 2500  101920 return found;
 2501    }
 2502   
 2503    /**
 2504    * Internal method to remove a key.
 2505    *
 2506    * @param fqn
 2507    * @param key
 2508    * @return Object
 2509    */
 2510  0 public V _remove(GlobalTransaction tx, String fqn, K key, boolean create_undo_ops)
 2511    throws CacheException
 2512    {
 2513  0 return _remove(tx, Fqn.fromString(fqn), key, create_undo_ops);
 2514    }
 2515   
 2516    /**
 2517    * Internal method to remove a key.
 2518    *
 2519    * @param fqn
 2520    * @param key
 2521    * @return Object
 2522    */
 2523  4604 public V _remove(GlobalTransaction tx, Fqn fqn, K key, boolean create_undo_ops)
 2524    throws CacheException
 2525    {
 2526  4604 MethodCall undo_op = null;
 2527  4604 V old_value = null;
 2528   
 2529  4604 if (log.isTraceEnabled())
 2530    {
 2531  0 log.trace("_remove(" + tx + ", \"" + fqn + "\", key=" + key + ")");
 2532    }
 2533   
 2534    // Find the node. This will lock it (if <tt>locking</tt> is true) and
 2535    // add the temporarily created parent nodes to the TX's node list if tx != null)
 2536  4604 NodeSPI<K, V> n = findNode(fqn);
 2537  4604 if (n == null)
 2538    {
 2539  1069 log.warn("node " + fqn + " not found");
 2540  1069 return null;
 2541    }
 2542  3535 InvocationContext ctx = getInvocationContext();
 2543  3535 boolean isRollback = checkIsRollingBack(ctx.getTransaction());
 2544  3535 if (!isRollback)
 2545  3240 notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.REMOVE_DATA, n.getDataDirect(), ctx);
 2546   
 2547  3535 old_value = n.removeDirect(key);
 2548   
 2549    // create a compensating method call (reverting the effect of
 2550    // this modification) and put it into the TX's undo list.
 2551  3535 if (tx != null && create_undo_ops && old_value != null)
 2552    {
 2553  2081 undo_op = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal, tx, fqn, key, old_value, false);
 2554    // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
 2555  2081 tx_table.addUndoOperation(tx, undo_op);
 2556    }
 2557   
 2558  3535 Map<K, V> removedData = Collections.singletonMap(key, old_value);
 2559  3535 if (!isRollback)
 2560  3240 notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.REMOVE_DATA, removedData, ctx);
 2561   
 2562  3535 return old_value;
 2563    }
 2564   
 2565    /**
 2566    * Internal method to remove data from a node.
 2567    */
 2568  0 public void _removeData(GlobalTransaction tx, String fqn, boolean create_undo_ops)
 2569    throws CacheException
 2570    {
 2571  0 _removeData(tx, Fqn.fromString(fqn), create_undo_ops);
 2572    }
 2573   
 2574    /**
 2575    * Internal method to remove data from a node.
 2576    */
 2577  1998 public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops)
 2578    throws CacheException
 2579    {
 2580  1998 _removeData(tx, fqn, create_undo_ops, true);
 2581    }
 2582   
 2583    /**
 2584    * Internal method to remove data from a node.
 2585    */
 2586  1998 public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent)
 2587    throws CacheException
 2588    {
 2589  1998 _removeData(tx, fqn, create_undo_ops, sendNodeEvent, false);
 2590    }
 2591   
 2592    /**
 2593    * Internal method to remove data from a node.
 2594    */
 2595  2168 public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction)
 2596    throws CacheException
 2597    {
 2598  2168 _removeData(tx, fqn, create_undo_ops, sendNodeEvent, eviction, null);
 2599    }
 2600   
 2601    /**
 2602    * Internal method to remove data from a node.
 2603    */
 2604  2168 public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction, DataVersion version)
 2605    throws CacheException
 2606    {
 2607  2168 MethodCall undo_op = null;
 2608   
 2609  2168 if (log.isTraceEnabled())
 2610    {
 2611  0 log.trace("_removeData(" + tx + ", \"" + fqn + "\")");
 2612    }
 2613   
 2614    // Find the node. This will lock it (if <tt>locking</tt> is true) and
 2615    // add the temporarily created parent nodes to the TX's node list if tx != null)
 2616  2168 NodeSPI n = findNode(fqn, version);
 2617  2168 if (n == null)
 2618    {
 2619  12 log.warn("node " + fqn + " not found");
 2620  12 return;
 2621    }
 2622   
 2623  2156 Map<K, V> data = n.getDataDirect();
 2624  2156 InvocationContext ctx = getInvocationContext();
 2625  2156 boolean isRollback = checkIsRollingBack(ctx.getTransaction());
 2626    // create a compensating method call (reverting the effect of
 2627    // this modification) and put it into the TX's undo list.
 2628  2156 if (tx != null && create_undo_ops && !eviction)
 2629    {
 2630  1939 if (!data.isEmpty())
 2631    {
 2632  1939 undo_op = MethodCallFactory.create(MethodDeclarations.putDataMethodLocal,
 2633    tx, fqn, data, false);
 2634    }
 2635    }
 2636   
 2637  2156 if (!isRollback)
 2638    {
 2639  2156 if (eviction)
 2640    {
 2641  170 notifier.notifyNodeEvicted(fqn, true, ctx);
 2642    }
 2643    else
 2644    {
 2645  1986 notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.REMOVE_DATA, data, ctx);
 2646    }
 2647    }
 2648   
 2649  2156 n.clearDataDirect();
 2650  2156 if (eviction)
 2651    {
 2652  170 n.setDataLoaded(false);
 2653    }
 2654   
 2655  2156 if (!isRollback)
 2656    {
 2657  2156 if (sendNodeEvent)
 2658    {
 2659  1986 notifier.notifyNodeVisited(fqn, false, ctx);
 2660    }
 2661    else
 2662    {// FIXME Bela did this so GUI view can refresh the view after node is evicted. But this breaks eviction policy, especially AOP!!!!
 2663  170 if (eviction)
 2664    {
 2665  170 notifier.notifyNodeEvicted(fqn, false, ctx);
 2666    }
 2667    else
 2668    {
 2669  0 notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.REMOVE_DATA, data, ctx);
 2670    }
 2671    }
 2672    }
 2673   
 2674    // put undo-op in TX' undo-operations list (needed to rollback TX)
 2675  2156 if (tx != null && create_undo_ops)
 2676    {
 2677  1939 tx_table.addUndoOperation(tx, undo_op);
 2678    }
 2679    }
 2680   
 2681   
 2682    /**
 2683    * Internal evict method called by eviction policy provider.
 2684    *
 2685    * @param fqn removes everything assoicated with this FQN
 2686    * @return <code>true</code> if the node has been completely removed,
 2687    * <code>false</code> if only the data map was removed, due
 2688    * to the presence of children
 2689    * @throws CacheException
 2690    */
 2691  118240 public boolean _evict(Fqn fqn) throws CacheException
 2692    {
 2693  118240 if (!exists(fqn))
 2694  30337 return true;// node does not exist. Maybe it has been recursively removed.
 2695    // use remove method now if there is a child node. Otherwise, it is removed
 2696  87903 boolean create_undo_ops = false;
 2697  87903 boolean sendNodeEvent = false;
 2698  87903 boolean eviction = true;
 2699  87903 if (log.isTraceEnabled())
 2700    {
 2701  0 log.trace("_evict(" + fqn + ")");
 2702    }
 2703  87903 if (hasChild(fqn))
 2704    {
 2705  170 _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction);
 2706  170 return false;
 2707    }
 2708    else
 2709    {
 2710  87733 _remove(null, fqn, create_undo_ops, sendNodeEvent, eviction);
 2711  87733 return true;
 2712    }
 2713    }
 2714   
 2715    /**
 2716    * Internal evict method called by eviction policy provider.
 2717    *
 2718    * @param fqn
 2719    * @param version
 2720    * @return <code>true</code> if the node has been completely removed,
 2721    * <code>false</code> if only the data map was removed, due
 2722    * to the presence of children
 2723    * @throws CacheException
 2724    */
 2725  0 public boolean _evict(Fqn fqn, DataVersion version) throws CacheException
 2726    {
 2727  0 if (!exists(fqn))
 2728  0 return true;// node does not exist
 2729   
 2730  0 boolean create_undo_ops = false;
 2731  0 boolean sendNodeEvent = false;
 2732  0 boolean eviction = true;
 2733  0 if (log.isTraceEnabled())
 2734    {
 2735  0 log.trace("_evict(" + fqn + ", " + version + ")");
 2736    }
 2737  0 if (hasChild(fqn))
 2738    {
 2739  0 _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction, version);
 2740  0 return false;
 2741    }
 2742    else
 2743    {
 2744  0 _remove(null, fqn, create_undo_ops, sendNodeEvent, eviction, version);
 2745  0 return true;
 2746    }
 2747    }
 2748   
 2749    /**
 2750    * Evicts a key/value pair from a node's attributes. Note that this is <em>local</em>, will not be replicated.
 2751    * @param fqn
 2752    * @param key
 2753    * @throws CacheException
 2754    */
 2755    // public void _evict(Fqn fqn, Object key) throws CacheException {
 2756    // if(!exists(fqn)) return;
 2757    // boolean create_undo_ops = false;
 2758    // boolean sendNodeEvent = false;
 2759    // boolean eviction=true;
 2760    // _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction);
 2761    // }
 2762   
 2763   
 2764    /**
 2765    * Compensating method to {@link #_remove(GlobalTransaction,Fqn,boolean)}.
 2766    */
 2767  107 public void _addChild(GlobalTransaction gtx, Fqn parent_fqn, Object child_name, Node cn, boolean undoOps)
 2768    throws CacheException
 2769    {
 2770  107 NodeSPI childNode = (NodeSPI) cn;
 2771  107 if (log.isTraceEnabled())
 2772    {
 2773  0 log.trace("_addChild(\"" + parent_fqn + "\", \"" + child_name + "\", node=" + childNode + ")");
 2774    }
 2775   
 2776  107 if (parent_fqn == null || child_name == null || childNode == null)
 2777    {
 2778  0 log.error("parent_fqn or child_name or childNode was null");
 2779  0 return;
 2780    }
 2781  107 NodeSPI parentNode = findNode(parent_fqn);
 2782  107 if (parentNode == null)
 2783    {
 2784  0 log.warn("node " + parent_fqn + " not found");
 2785  0 return;
 2786    }
 2787  107 InvocationContext ctx = getInvocationContext();
 2788  107 boolean isRollback = checkIsRollingBack(ctx.getTransaction());
 2789  107 Fqn fqn = new Fqn(parent_fqn, child_name);
 2790  0 if (!isRollback) notifier.notifyNodeCreated(fqn, true, ctx);
 2791  107 parentNode.addChild(child_name, childNode);
 2792   
 2793  107 childNode.markAsDeleted(false, true);
 2794   
 2795  107 if (gtx != null && undoOps)
 2796    {
 2797    // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
 2798  0 tx_table.addUndoOperation(gtx, MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, gtx, fqn, false));
 2799    }
 2800   
 2801  0 if (!isRollback) notifier.notifyNodeCreated(fqn, false, ctx);
 2802    }
 2803   
 2804   
 2805    /**
 2806    * Replicates changes across to other nodes in the cluster. Invoked by the
 2807    * ReplicationInterceptor. Calls need to be forwarded to the
 2808    * ReplicationInterceptor in this interceptor chain. This method will later
 2809    * be moved entirely into the ReplicationInterceptor.
 2810    */
 2811  43746 public Object _replicate(MethodCall method_call) throws Throwable
 2812    {
 2813  43746 try
 2814    {
 2815  43746 Object retVal = invokeMethod(method_call, false);
 2816    // we only need to return values for a set of remote calls; not every call.
 2817  43715 if (MethodDeclarations.returnValueForRemoteCall(method_call.getMethodId()))
 2818    {
 2819  4 return retVal;
 2820    }
 2821    else
 2822    {
 2823  43711 return null;
 2824    }
 2825    }
 2826    catch (Throwable ex)
 2827    {
 2828  31 log.warn("replication failure with method_call " + method_call + " exception", ex);
 2829  31 throw ex;
 2830    }
 2831    }
 2832   
 2833    /**
 2834    * Replicates a list of method calls.
 2835    */
 2836  0 public void _replicate(List<MethodCall> methodCalls) throws Throwable
 2837    {
 2838  0 for (MethodCall methodCall : methodCalls) _replicate(methodCall);
 2839    }
 2840   
 2841    /**
 2842    * A 'clustered get' call, called from a remote ClusteredCacheLoader.
 2843    *
 2844    * @return a List containing 2 elements: (true or false) and a value (Object). If buddy replication
 2845    * is used one further element is added - an Fqn of the backup subtree in which this node may be found.
 2846    */
 2847  120056 public List _clusteredGet(MethodCall methodCall, Boolean searchBackupSubtrees)
 2848    {
 2849  120056 MethodCall call = methodCall;
 2850  0 if (log.isTraceEnabled()) log.trace("Clustered Get called with params: " + call + ", " + searchBackupSubtrees);
 2851  120056 Method m = call.getMethod();
 2852  120056 Object[] args = call.getArgs();
 2853   
 2854  120056 Object callResults = null;
 2855   
 2856  120056 try
 2857    {
 2858  120056 Fqn fqn = (Fqn) args[0];
 2859   
 2860  0 if (log.isTraceEnabled()) log.trace("Clustered get: invoking call " + m + " with Fqn " + fqn);
 2861  120056 callResults = m.invoke(this, args);
 2862  120055 boolean found = validResult(callResults, call, fqn);
 2863  0 if (log.isTraceEnabled()) log.trace("Got result " + callResults + ", found=" + found);
 2864  0 if (found && callResults == null) callResults = createEmptyResults(call);
 2865    }
 2866    catch (Exception e)
 2867    {
 2868  1 log.warn("Problems processing clusteredGet call", e);
 2869    }
 2870   
 2871  120056 List<Object> results = new ArrayList<Object>(2);
 2872  120056 if (callResults != null)
 2873    {
 2874  120047 results.add(true);
 2875  120047 results.add(callResults);
 2876    }
 2877    else
 2878    {
 2879  9 results.add(false);
 2880  9 results.add(null);
 2881    }
 2882  120056 return results;
 2883    }
 2884   
 2885    /**
 2886    * Used with buddy replication's data gravitation interceptor. If marshalling is necessary, ensure that the cache is
 2887    * configured to use {@link org.jboss.cache.config.Configuration#useRegionBasedMarshalling} and the {@link org.jboss.cache.Region}
 2888    * pertaining to the Fqn passed in is activated, and has an appropriate ClassLoader.
 2889    *
 2890    * @param fqn the fqn to gravitate
 2891    * @param searchSubtrees if true, buddy backup subtrees are searched and if false, they are not.
 2892    * @return a GravitateResult which contains the data for the gravitation
 2893    */
 2894  68 public GravitateResult gravitateData(Fqn fqn, boolean searchSubtrees)
 2895    throws CacheException
 2896    {
 2897    // we need to get the state for this Fqn and its sub-nodes.
 2898   
 2899    // for now, perform a very simple series of getData calls.
 2900  68 InvocationContext ctx = getInvocationContext();
 2901   
 2902  68 log.debug("*****************>>>>> " + printLockInfo());
 2903   
 2904  68 try
 2905    {
 2906  68 ctx.setOriginLocal(false);
 2907   
 2908  68 NodeSPI<K, V> actualNode = findNode(fqn);
 2909  68 Fqn backupNodeFqn = null;
 2910  68 if (actualNode == null && searchSubtrees)
 2911    {
 2912  50 NodeSPI backupSubtree = findNode(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
 2913  50 if (backupSubtree != null)
 2914    {
 2915    // need to loop through backupSubtree's children
 2916  50 Set childNames = backupSubtree.getChildrenNamesDirect();
 2917  50 if (childNames != null)
 2918    {
 2919  50 for (Object childName : childNames)
 2920    {
 2921    // childName is the name of a buddy group since all child names in this
 2922    // collection are direct children of BUDDY_BACKUP_SUBTREE_FQN
 2923  52 backupNodeFqn = BuddyManager.getBackupFqn(childName.toString(), fqn);
 2924  52 actualNode = findNode(backupNodeFqn);
 2925  34 if (actualNode != null) break;
 2926    }
 2927    }
 2928    /*Map children = backupSubtree.getChildrenMapDirect();
 2929    if (children != null)
 2930    {
 2931    Iterator childNames = children.keySet().iterator();
 2932    while (childNames.hasNext() && actualNode == null)
 2933    {
 2934    backupNodeFqn = BuddyManager.getBackupFqn(childNames.next().toString(), fqn);
 2935    actualNode = findNode(backupNodeFqn);
 2936    }
 2937    }*/
 2938    }
 2939    }
 2940   
 2941  68 if (actualNode == null)
 2942    {
 2943  16 return GravitateResult.noDataFound();
 2944    }
 2945   
 2946  52 if (backupNodeFqn == null && searchSubtrees)
 2947    {
 2948  16 backupNodeFqn = BuddyManager.getBackupFqn(BuddyManager.getGroupNameFromAddress(getLocalAddress()), fqn);
 2949    }
 2950   
 2951  52 List<NodeData> list = getNodeData(new LinkedList<NodeData>(), actualNode);
 2952   
 2953  52 return GravitateResult.subtreeResult(list, backupNodeFqn);
 2954    }
 2955    finally
 2956    {
 2957  68 ctx.setOriginLocal(true);
 2958    }
 2959    }
 2960   
 2961  60 private List<NodeData> getNodeData(List<NodeData> list, NodeSPI<K, V> node)
 2962    {
 2963  60 NodeData data = new NodeData(BuddyManager.getActualFqn(node.getFqn()), node.getDataDirect());
 2964  60 list.add(data);
 2965  60 for (NodeSPI<K, V> childNode : node.getChildrenDirect())
 2966    {
 2967  8 getNodeData(list, childNode);
 2968    }
 2969  60 return list;
 2970    }
 2971   
 2972    // ------------- start: buddy replication specific 'lifecycle' method calls
 2973   
 2974  251 public void _remoteAssignToBuddyGroup(BuddyGroup group, Map<Fqn, byte[]> state) throws Exception
 2975    {
 2976  251 if (buddyManager != null)
 2977  250 buddyManager.handleAssignToBuddyGroup(group, state);
 2978  1 else if (log.isWarnEnabled())
 2979  1 log.warn("Received assignToBuddyGroup call from group owner [" + group.getDataOwner() + "] but buddy replication is not enabled on this node!");
 2980    }
 2981   
 2982  46 public void _remoteRemoveFromBuddyGroup(String groupName) throws BuddyNotInitException
 2983    {
 2984  46 if (buddyManager != null)
 2985  45 buddyManager.handleRemoveFromBuddyGroup(groupName);
 2986  1 else if (log.isWarnEnabled())
 2987  1 log.warn("Received removeFromBuddyGroup call for group name [" + groupName + "] but buddy replication is not enabled on this node!");
 2988   
 2989    }
 2990   
 2991  492 public void _remoteAnnounceBuddyPoolName(Address address, String buddyPoolName)
 2992    {
 2993  492 if (buddyManager != null)
 2994  489 buddyManager.handlePoolNameBroadcast(address, buddyPoolName);
 2995  3 else if (log.isWarnEnabled())
 2996  3 log.warn("Received annouceBuddyPoolName call from [" + address + "] but buddy replication is not enabled on this node!");
 2997    }
 2998   
 2999  50 public void _dataGravitationCleanup(GlobalTransaction gtx, Fqn primary, Fqn backup) throws Exception
 3000    {
 3001  50 MethodCall primaryDataCleanup, backupDataCleanup;
 3002  50 if (buddyManager.isDataGravitationRemoveOnFind())
 3003    {
 3004  42 if (log.isTraceEnabled())
 3005  0 log.trace("DataGravitationCleanup: Removing primary (" + primary + ") and backup (" + backup + ")");
 3006  42 primaryDataCleanup = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, null, primary, false);
 3007  42 backupDataCleanup = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, null, backup, false);
 3008    }
 3009    else
 3010    {
 3011  8 if (log.isTraceEnabled())
 3012  0 log.trace("DataGravitationCleanup: Evicting primary (" + primary + ") and backup (" + backup + ")");
 3013  8 primaryDataCleanup = MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, primary);
 3014  8 backupDataCleanup = MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, backup);
 3015    }
 3016   
 3017  50 invokeMethod(primaryDataCleanup, true);
 3018  50 invokeMethod(backupDataCleanup, true);
 3019    }
 3020   
 3021    // ------------- end: buddy replication specific 'lifecycle' method calls
 3022   
 3023   
 3024    /**
 3025    * Returns true if the call results returned a valid result.
 3026    */
 3027  120055 private boolean validResult(Object callResults, MethodCall mc, Fqn fqn)
 3028    {
 3029  120055 switch (mc.getMethodId())
 3030    {
 3031  40034 case MethodDeclarations.getDataMapMethodLocal_id:
 3032  80010 case MethodDeclarations.getChildrenNamesMethodLocal_id:
 3033  120044 return callResults != null || exists(fqn);
 3034  10 case MethodDeclarations.existsMethod_id:
 3035  10 return (Boolean) callResults;
 3036  1 default:
 3037  1 return false;
 3038    }
 3039    }
 3040   
 3041    /**
 3042    * Creates an empty Collection class based on the return type of the method called.
 3043    */
 3044  0 private Object createEmptyResults(MethodCall mc)
 3045    {
 3046  0 switch (mc.getMethodId())
 3047    {
 3048  0 case MethodDeclarations.getDataMapMethodLocal_id:
 3049  0 case MethodDeclarations.getChildrenNamesMethodLocal_id:
 3050  0 return Collections.emptyMap();
 3051  0 default:
 3052  0 return null;
 3053    }
 3054    }
 3055   
 3056    /**
 3057    * Releases all locks for a FQN.
 3058    */
 3059  3 public void _releaseAllLocks(Fqn fqn)
 3060    {
 3061  3 NodeSPI<K, V> n;
 3062   
 3063  3 try
 3064    {
 3065  3 n = findNode(fqn);
 3066  3 if (n == null)
 3067    {
 3068  0 log.error("releaseAllLocks(): node " + fqn + " not found");
 3069  0 return;
 3070    }
 3071  3 releaseAll(n);
 3072    }
 3073    catch (Throwable t)
 3074    {
 3075  0 log.error("releaseAllLocks(): failed", t);
 3076    }
 3077    }
 3078   
 3079  3 private void releaseAll(NodeSPI<K, V> n)
 3080    {
 3081  3 for (NodeSPI<K, V> child : n.getChildrenDirect())
 3082    {
 3083  0 releaseAll(child);
 3084    }
 3085  3 n.getLock().releaseAll();
 3086    }
 3087   
 3088   
 3089    /**
 3090    * Finds and returns the string value for the Fqn.
 3091    * Returns null if not found or upon error.
 3092    */
 3093  22 public String _print(Fqn fqn)
 3094    {
 3095  22 try
 3096    {
 3097  22 Node n = findNode(fqn);
 3098  0 if (n == null) return null;
 3099  22 return n.toString();
 3100    }
 3101    catch (Throwable t)
 3102    {
 3103  0 return null;
 3104    }
 3105    }
 3106   
 3107    /**
 3108    * Should not be called.
 3109    */
 3110  0 public void _lock(Fqn fqn, NodeLock.LockType lock_type, boolean recursive)
 3111    throws TimeoutException, LockingException
 3112    {
 3113  0 throw new UnsupportedOperationException("method _lock() should not be invoked on CacheImpl");
 3114    }
 3115   
 3116    /**
 3117    * Throws UnsupportedOperationException.
 3118    */
 3119  0 public void optimisticPrepare(GlobalTransaction gtx, List modifications, Map data, Address address, boolean onePhaseCommit)
 3120    {
 3121  0 throw new UnsupportedOperationException("optimisticPrepare() should not be called on CacheImpl directly");
 3122    }
 3123   
 3124    /**
 3125    * Throws UnsupportedOperationException.
 3126    */
 3127  0 public void prepare(GlobalTransaction global_tx, List modifications, Address coord, boolean onePhaseCommit)
 3128    {
 3129  0 throw new UnsupportedOperationException("prepare() should not be called on CacheImpl directly");
 3130    }
 3131   
 3132    /**
 3133    * Throws UnsupportedOperationException.
 3134    */
 3135  0 public void commit(GlobalTransaction tx)
 3136    {
 3137  0 throw new UnsupportedOperationException("commit() should not be called on CacheImpl directly");
 3138    }
 3139   
 3140    /**
 3141    * Throws UnsupportedOperationException.
 3142    */
 3143  0 public void rollback(GlobalTransaction tx)//, Boolean hasMods)
 3144    {
 3145  0 throw new UnsupportedOperationException("rollback() should not be called on CacheImpl directly");
 3146    }
 3147   
 3148    /* ----------------- End of Callbacks ---------------------- */
 3149   
 3150    /**
 3151    * Adds an undo operatoin to the transaction table.
 3152    */
 3153  17738 public void addUndoOperation(GlobalTransaction gtx, MethodCall undo_op)
 3154    {
 3155  17738 tx_table.addUndoOperation(gtx, undo_op);
 3156    }
 3157   
 3158    /**
 3159    * Returns the CacheLoaderManager.
 3160    */
 3161  179310 public CacheLoaderManager getCacheLoaderManager()
 3162    {
 3163  179310 return cacheLoaderManager;
 3164    }
 3165   
 3166    /**
 3167    * Sets the CacheLoaderManager.
 3168    */
 3169  0 public void setCacheLoaderManager(CacheLoaderManager cacheLoaderManager)
 3170    {
 3171  0 this.cacheLoaderManager = cacheLoaderManager;
 3172    }
 3173   
 3174  3756 public void setConfiguration(Configuration configuration)
 3175    {
 3176  3756 this.configuration = configuration;
 3177  3756 configuration.setCacheImpl(this);
 3178    }
 3179   
 3180    /**
 3181    * @return an instance of {@link Notifier} which has been configured with this instance of CacheImpl.
 3182    */
 3183  2623723 public Notifier getNotifier()
 3184    {
 3185  2623723 return notifier;
 3186    }
 3187   
 3188  5352023 public InvocationContext getInvocationContext()
 3189    {
 3190  5352036 InvocationContext ctx = invocationContextContainer.get();
 3191  5351986 if (ctx == null)
 3192    {
 3193  521 ctx = new InvocationContext();
 3194  521 invocationContextContainer.set(ctx);
 3195    }
 3196  5351996 return ctx;
 3197    }
 3198   
 3199  9071 public void setInvocationContext(InvocationContext ctx)
 3200    {
 3201  9071 invocationContextContainer.set(ctx);
 3202    }
 3203   
 3204    /**
 3205    * New API to efficiently relocate a node
 3206    *
 3207    * @since 2.0.0
 3208    */
 3209  62 public void move(Fqn<?> nodeToMove, Fqn<?> newParent)
 3210    {
 3211    // this needs to be passed up the interceptor chain
 3212  62 MethodCall m = MethodCallFactory.create(MethodDeclarations.moveMethodLocal, nodeToMove, newParent);
 3213  62 invokeMethod(m, true);
 3214    }
 3215   
 3216    /**
 3217    * Called by reflection
 3218    *
 3219    * @param newParentFqn
 3220    * @param nodeToMoveFqn
 3221    */
 3222  53 public void _move(Fqn nodeToMoveFqn, Fqn newParentFqn)
 3223    {
 3224    // the actual move algorithm.
 3225  53 NodeSPI<K, V> newParent = findNode(newParentFqn);
 3226   
 3227  53 if (newParent == null)
 3228    {
 3229  0 throw new NodeNotExistsException("New parent node " + newParentFqn + " does not exist when attempting to move node!!");
 3230    }
 3231   
 3232  53 NodeSPI<K, V> node = findNode(nodeToMoveFqn);
 3233   
 3234  53 if (node == null)
 3235    {
 3236  0 throw new NodeNotExistsException("Node " + nodeToMoveFqn + " does not exist when attempting to move node!!");
 3237    }
 3238   
 3239  53 NodeSPI oldParent = node.getParent();
 3240  53 Object nodeName = nodeToMoveFqn.getLastElement();
 3241   
 3242    // now that we have the parent and target nodes:
 3243    // first correct the pointers at the pruning point
 3244  53 oldParent.removeChildDirect(nodeName);
 3245  53 newParent.addChild(nodeName, node);
 3246  53 InvocationContext ctx = getInvocationContext();
 3247    // parent pointer is calculated on the fly using Fqns.
 3248  53 boolean isRollback = checkIsRollingBack(ctx.getTransaction());
 3249   
 3250    // notify
 3251  53 if (!isRollback)
 3252  51 notifier.notifyNodeMoved(nodeToMoveFqn, new Fqn(newParentFqn, nodeToMoveFqn.getLastElement()), true, ctx);
 3253   
 3254    // now adjust Fqns of node and all children.
 3255  53 moveFqns(node, newParent.getFqn());
 3256   
 3257  53 if (!isRollback)
 3258  51 notifier.notifyNodeMoved(nodeToMoveFqn, new Fqn(newParentFqn, nodeToMoveFqn.getLastElement()), false, ctx);
 3259   
 3260    // now register an undo op
 3261  53 if (ctx.getTransaction() != null)
 3262    {
 3263  18 MethodCall undo = MethodCallFactory.create(MethodDeclarations.moveMethodLocal, new Fqn(newParentFqn, nodeToMoveFqn.getLastElement()), oldParent.getFqn());
 3264  18 tx_table.addUndoOperation(ctx.getGlobalTransaction(), undo);
 3265    }
 3266    }
 3267   
 3268  2938 public void _block()
 3269    {
 3270    //intentionally empty, used only for reflection in MethodDeclarations.blockChannelLocal
 3271    }
 3272   
 3273  2589 public void _unblock()
 3274    {
 3275    //intentionally empty, used only for reflection in MethodDeclarations.unblockChannelLocal
 3276    }
 3277   
 3278  53 private void moveFqns(NodeSPI node, Fqn newBase)
 3279    {
 3280  53 Fqn newFqn = new Fqn(newBase, node.getFqn().getLastElement());
 3281  53 node.setFqn(newFqn);
 3282    }
 3283   
 3284    /**
 3285    * Set our log category to include our clusterName, if we have one.
 3286    */
 3287  2832 private void configureLogCategory()
 3288    {
 3289  2832 StringBuffer category = new StringBuffer(getClass().getName());
 3290  2832 if (configuration != null)
 3291    {
 3292  2832 String clusterName = configuration.getClusterName();
 3293  2832 if (clusterName != null)
 3294    {
 3295  2832 category.append('.');
 3296  2832 category.append(clusterName);
 3297    }
 3298    }
 3299   
 3300  2832 log = LogFactory.getLog(category.toString());
 3301    }
 3302   
 3303    /**
 3304    * Kills the JGroups channel; an unclean channel disconnect
 3305    */
 3306  1217 public void killChannel()
 3307    {
 3308  1220 if (channel != null)
 3309    {
 3310  1218 channel.close();
 3311  1206 channel.disconnect();
 3312    }
 3313    }
 3314   
 3315    protected class MessageListenerAdaptor implements ExtendedMessageListener
 3316    {
 3317    /**
 3318    * Reference to an exception that was raised during
 3319    * state installation on this node.
 3320    */
 3321    protected volatile Exception setStateException;
 3322    private final Object stateLock = new Object();
 3323   
 3324  2873 protected MessageListenerAdaptor()
 3325    {
 3326    }
 3327   
 3328  531 public void waitForState() throws Exception
 3329    {
 3330  531 synchronized (stateLock)
 3331    {
 3332  531 while (!isStateSet)
 3333    {
 3334  169 if (setStateException != null)
 3335    {
 3336  42 throw setStateException;
 3337    }
 3338   
 3339  127 try
 3340    {
 3341  127 stateLock.wait();
 3342    }
 3343    catch (InterruptedException iex)
 3344    {
 3345    }
 3346    }
 3347    }
 3348    }
 3349   
 3350  490 protected void stateReceivedSuccess()
 3351    {
 3352  490 isStateSet = true;
 3353  490 setStateException = null;
 3354    }
 3355   
 3356  49 protected void stateReceivingFailed(Throwable t)
 3357    {
 3358  49 if (t instanceof CacheException)
 3359    {
 3360  43 log.debug(t);
 3361    }
 3362    else
 3363    {
 3364  6 log.error("failed setting state", t);
 3365    }
 3366  49 if (t instanceof Exception)
 3367    {
 3368  49 setStateException = (Exception) t;
 3369    }
 3370    else
 3371    {
 3372  0 setStateException = new Exception(t);
 3373    }
 3374    }
 3375   
 3376  44 protected void stateProducingFailed(Throwable t)
 3377    {
 3378  44 if (t instanceof CacheException)
 3379    {
 3380  42 log.debug(t);
 3381    }
 3382    else
 3383    {
 3384  2 log.error("Caught " + t.getClass().getName()
 3385    + " while responding to state transfer request", t);
 3386    }
 3387    }
 3388   
 3389    /**
 3390    * Callback, does nothing.
 3391    */
 3392  0 public void receive(Message msg)
 3393    {
 3394    }
 3395   
 3396  177 public byte[] getState()
 3397    {
 3398  177 MarshalledValueOutputStream out = null;
 3399  177 byte[] result = null;
 3400  177 try
 3401    {
 3402  177 ExposedByteArrayOutputStream baos = new ExposedByteArrayOutputStream(16 * 1024);
 3403  177 out = new MarshalledValueOutputStream(baos);
 3404   
 3405  177 getStateTransferManager().getState(out, Fqn.ROOT, configuration.getStateRetrievalTimeout(), true, true);
 3406  175 result = baos.getRawBuffer();
 3407    }
 3408    catch (Throwable t)
 3409    {
 3410  2 stateProducingFailed(t);
 3411    }
 3412    finally
 3413    {
 3414  177 Util.close(out);
 3415    }
 3416  177 return result;
 3417    }
 3418   
 3419  177 public void setState(byte[] new_state)
 3420    {
 3421  177 if (new_state == null)
 3422    {
 3423  2 log.debug("transferred state is null (may be first member in cluster)");
 3424  2 return;
 3425    }
 3426  175 ByteArrayInputStream bais = new ByteArrayInputStream(new_state);
 3427  175 MarshalledValueInputStream in = null;
 3428  175 try
 3429    {
 3430  175 in = new MarshalledValueInputStream(bais);
 3431  175 getStateTransferManager().setState(in, Fqn.ROOT);
 3432  175 stateReceivedSuccess();
 3433    }
 3434    catch (Throwable t)
 3435    {
 3436  0 stateReceivingFailed(t);
 3437    }
 3438    finally
 3439    {
 3440  175 Util.close(in);
 3441  175 synchronized (stateLock)
 3442    {
 3443    // Notify wait that state has been set.
 3444  175 stateLock.notifyAll();
 3445    }
 3446    }
 3447    }
 3448   
 3449  0 public byte[] getState(String state_id)
 3450    {
 3451  0 MarshalledValueOutputStream out = null;
 3452  0 String sourceRoot = state_id;
 3453  0 byte[] result = null;
 3454   
 3455  0 boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
 3456  0 if (hasDifferentSourceAndIntegrationRoots)
 3457    {
 3458  0 sourceRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[0];
 3459    }
 3460   
 3461  0 try
 3462    {
 3463  0 ExposedByteArrayOutputStream baos = new ExposedByteArrayOutputStream(16 * 1024);
 3464  0 out = new MarshalledValueOutputStream(baos);
 3465   
 3466  0 getStateTransferManager().getState(out, Fqn.fromString(sourceRoot),
 3467    configuration.getStateRetrievalTimeout(), true, true);
 3468  0 result = baos.getRawBuffer();
 3469    }
 3470    catch (Throwable t)
 3471    {
 3472  0 stateProducingFailed(t);
 3473    }
 3474    finally
 3475    {
 3476  0 Util.close(out);
 3477    }
 3478  0 return result;
 3479    }
 3480   
 3481  210 public void getState(OutputStream ostream)
 3482    {
 3483  210 MarshalledValueOutputStream out = null;
 3484  210 try
 3485    {
 3486  210 out = new MarshalledValueOutputStream(ostream);
 3487  210 getStateTransferManager().getState(out, Fqn.ROOT, configuration.getStateRetrievalTimeout(), true, true);
 3488    }
 3489    catch (Throwable t)
 3490    {
 3491  6 stateProducingFailed(t);
 3492    }
 3493    finally
 3494    {
 3495  210 Util.close(out);
 3496    }
 3497    }
 3498   
 3499  155 public void getState(String state_id, OutputStream ostream)
 3500    {
 3501  155 String sourceRoot = state_id;
 3502  155 MarshalledValueOutputStream out = null;
 3503  155 boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
 3504  155 if (hasDifferentSourceAndIntegrationRoots)
 3505    {
 3506  8 sourceRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[0];
 3507    }
 3508  155 try
 3509    {
 3510  155 out = new MarshalledValueOutputStream(ostream);
 3511  155 getStateTransferManager().getState(out, Fqn.fromString(sourceRoot), configuration.getStateRetrievalTimeout(), true, true);
 3512    }
 3513    catch (Throwable t)
 3514    {
 3515  36 stateProducingFailed(t);
 3516    }
 3517    finally
 3518    {
 3519  155 Util.close(out);
 3520    }
 3521    }
 3522   
 3523  209 public void setState(InputStream istream)
 3524    {
 3525  209 if (istream == null)
 3526    {
 3527  0 log.debug("stream is null (may be first member in cluster)");
 3528  0 return;
 3529    }
 3530  209 MarshalledValueInputStream in = null;
 3531  209 try
 3532    {
 3533  209 in = new MarshalledValueInputStream(istream);
 3534  209 getStateTransferManager().setState(in, Fqn.ROOT);
 3535  203 stateReceivedSuccess();
 3536    }
 3537    catch (Throwable t)
 3538    {
 3539  6 stateReceivingFailed(t);
 3540    }
 3541    finally
 3542    {
 3543  209 Util.close(in);
 3544  209 synchronized (stateLock)
 3545    {
 3546    // Notify wait that state has been set.
 3547  209 stateLock.notifyAll();
 3548    }
 3549    }
 3550    }
 3551   
 3552  0 public void setState(String state_id, byte[] state)
 3553    {
 3554  0 if (state == null)
 3555    {
 3556  0 log.debug("partial transferred state is null");
 3557  0 return;
 3558    }
 3559   
 3560  0 MarshalledValueInputStream in = null;
 3561  0 String targetRoot = state_id;
 3562  0 boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
 3563  0 if (hasDifferentSourceAndIntegrationRoots)
 3564    {
 3565  0 targetRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[1];
 3566    }
 3567  0 try
 3568    {
 3569  0 log.debug("Setting received partial state for subroot " + state_id);
 3570  0 Fqn subroot = Fqn.fromString(targetRoot);
 3571    // Region region = regionManager.getRegion(subroot, false);
 3572    // ClassLoader cl = null;
 3573    // if (region != null)
 3574    // {
 3575    // // If a classloader is registered for the node's region, use it
 3576    // cl = region.getClassLoader();
 3577    // }
 3578  0 ByteArrayInputStream bais = new ByteArrayInputStream(state);
 3579  0 in = new MarshalledValueInputStream(bais);
 3580    //getStateTransferManager().setState(in, subroot, cl);
 3581  0 getStateTransferManager().setState(in, subroot);
 3582  0 stateReceivedSuccess();
 3583    }
 3584    catch (Throwable t)
 3585    {
 3586  0 stateReceivingFailed(t);
 3587    }
 3588    finally
 3589    {
 3590  0 Util.close(in);
 3591  0 synchronized (stateLock)
 3592    {
 3593    // Notify wait that state has been set.
 3594  0 stateLock.notifyAll();
 3595    }
 3596    }
 3597    }
 3598   
 3599  155 public void setState(String state_id, InputStream istream)
 3600    {
 3601  155 String targetRoot = state_id;
 3602  155 MarshalledValueInputStream in = null;
 3603  155 boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
 3604  155 if (hasDifferentSourceAndIntegrationRoots)
 3605    {
 3606  8 targetRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[1];
 3607    }
 3608  155 if (istream == null)
 3609    {
 3610  0 log.debug("stream is null (may be first member in cluster). State is not set");
 3611  0 return;
 3612    }
 3613   
 3614  155 try
 3615    {
 3616  155 log.debug("Setting received partial state for subroot " + state_id);
 3617  155 in = new MarshalledValueInputStream(istream);
 3618  155 Fqn subroot = Fqn.fromString(targetRoot);
 3619    // Region region = regionManager.getRegion(subroot, false);
 3620    // ClassLoader cl = null;
 3621    // if (region != null)
 3622    // {
 3623    // // If a classloader is registered for the node's region, use it
 3624    // cl = region.getClassLoader();
 3625    // }
 3626    //getStateTransferManager().setState(in, subroot, cl);
 3627  155 getStateTransferManager().setState(in, subroot);
 3628  112 stateReceivedSuccess();
 3629    }
 3630    catch (Throwable t)
 3631    {
 3632  43 stateReceivingFailed(t);
 3633    }
 3634    finally
 3635    {
 3636  155 Util.close(in);
 3637  155 synchronized (stateLock)
 3638    {
 3639    // Notify wait that state has been set.
 3640  155 stateLock.notifyAll();
 3641    }
 3642    }
 3643    }
 3644    }
 3645   
 3646    /*-------------------- End of MessageListener ----------------------*/
 3647   
 3648    /*----------------------- MembershipListener ------------------------*/
 3649   
 3650    protected class MembershipListenerAdaptor implements ExtendedMembershipListener
 3651    {
 3652   
 3653  2473 public void viewAccepted(View new_view)
 3654    {
 3655  2473 Vector<Address> new_mbrs = new_view.getMembers();
 3656  2473 if (log.isInfoEnabled()) log.info("viewAccepted(): " + new_view);
 3657  2473 synchronized (members)
 3658    {
 3659  2473 boolean needNotification = false;
 3660  2473 if (new_mbrs != null)
 3661    {
 3662    // Determine what members have been removed
 3663    // and roll back any tx and break any locks
 3664  2473 Vector<Address> removed = new Vector<Address>(members);
 3665  2473 removed.removeAll(new_mbrs);
 3666  2473 removeLocksForDeadMembers(root, removed);
 3667   
 3668  2473 members.removeAllElements();
 3669  2473 members.addAll(new_mbrs);
 3670   
 3671  2473 needNotification = true;
 3672    }
 3673   
 3674    // Now that we have a view, figure out if we are the coordinator
 3675  2473 coordinator = (members.size() != 0 && members.get(0).equals(getLocalAddress()));
 3676   
 3677    // now notify listeners - *after* updating the coordinator. - JBCACHE-662
 3678  2473 if (needNotification && notifier != null)
 3679    {
 3680  2473 InvocationContext ctx = getInvocationContext();
 3681  2473 notifier.notifyViewChange(new_view, ctx);
 3682    }
 3683   
 3684    // Wake up any threads that are waiting to know who the members
 3685    // are so they can figure out who the coordinator is
 3686  2473 members.notifyAll();
 3687    }
 3688    }
 3689   
 3690    /**
 3691    * Called when a member is suspected.
 3692    */
 3693  7 public void suspect(Address suspected_mbr)
 3694    {
 3695    }
 3696   
 3697    /**
 3698    * Indicates that a channel has received a BLOCK event from FLUSH protocol.
 3699    */
 3700  2937 public void block()
 3701    {
 3702  2937 if (log.isDebugEnabled())
 3703    {
 3704  0 log.debug("Block received at " + getLocalAddress());
 3705    }
 3706  2937 MethodCall m = MethodCallFactory.create(MethodDeclarations.blockChannelLocal);
 3707  2937 invokeMethod(m, true);
 3708  2937 if (log.isDebugEnabled())
 3709    {
 3710  0 log.debug("Block processed at " + getLocalAddress());
 3711    }
 3712    }
 3713   
 3714    /**
 3715    * Indicates that a channel has received a UNBLOCK event from FLUSH protocol.
 3716    */
 3717  2588 public void unblock()
 3718    {
 3719  2588 if (log.isDebugEnabled())
 3720    {
 3721  0 log.debug("UnBlock received at " + getLocalAddress());
 3722    }
 3723  2588 MethodCall m = MethodCallFactory.create(MethodDeclarations.unblockChannelLocal);
 3724  2588 invokeMethod(m, true);
 3725  2588 if (log.isDebugEnabled())
 3726    {
 3727  0 log.debug("UnBlock processed at " + getLocalAddress());
 3728    }
 3729    }
 3730   
 3731    }
 3732   
 3733    /*------------------- End of MembershipListener ----------------------*/
 3734   
 3735    /* ------------------------------ Private methods --------------------------- */
 3736   
 3737    /**
 3738    * Returns the transaction associated with the current thread. We get the
 3739    * initial context and a reference to the TransactionManager to get the
 3740    * transaction. This method is used by {@link #getCurrentTransaction()}
 3741    */
 3742  401945 protected Transaction getLocalTransaction()
 3743    {
 3744  401945 if (tm == null)
 3745    {
 3746  41033 return null;
 3747    }
 3748  360912 try
 3749    {
 3750  360912 return tm.getTransaction();
 3751    }
 3752    catch (Throwable t)
 3753    {
 3754  0 return null;
 3755    }
 3756    }
 3757   
 3758   
 3759    /**
 3760    * Returns true if transaction is ACTIVE or PREPARING, false otherwise.
 3761    */
 3762  164157 private boolean isValid(Transaction tx)
 3763    {
 3764  0 if (tx == null) return false;
 3765  164157 int status = -1;
 3766  164157 try
 3767    {
 3768  164157 status = tx.getStatus();
 3769  164157 return status == Status.STATUS_ACTIVE || status == Status.STATUS_PREPARING;
 3770    }
 3771    catch (SystemException e)
 3772    {
 3773  0 log.error("failed getting transaction status", e);
 3774  0 return false;
 3775    }
 3776    }
 3777   
 3778   
 3779    /**
 3780    * Returns the transaction associated with the current thread.
 3781    * If a local transaction exists, but doesn't yet have a mapping to a
 3782    * GlobalTransaction, a new GlobalTransaction will be created and mapped to
 3783    * the local transaction. Note that if a local transaction exists, but is
 3784    * not ACTIVE or PREPARING, null is returned.
 3785    *
 3786    * @return A GlobalTransaction, or null if no (local) transaction was associated with the current thread
 3787    */
 3788  401945 public GlobalTransaction getCurrentTransaction()
 3789    {
 3790  401945 return getCurrentTransaction(true);
 3791    }
 3792   
 3793    /**
 3794    * Returns the transaction associated with the thread; optionally creating
 3795    * it if is does not exist.
 3796    */
 3797  401945 public GlobalTransaction getCurrentTransaction(boolean createIfNotExists)
 3798    {
 3799  401945 Transaction tx;
 3800   
 3801  ? if ((tx = getLocalTransaction()) == null)
 3802    {// no transaction is associated with the current thread
 3803  237788 return null;
 3804    }
 3805   
 3806  164157 if (!isValid(tx))
 3807    {// we got a non-null transaction, but it is not active anymore
 3808  77 int status = -1;
 3809  77 try
 3810    {
 3811  77 status = tx.getStatus();
 3812    }
 3813    catch (SystemException e)
 3814    {
 3815    }
 3816   
 3817    // JBCACHE-982 -- don't complain if COMMITTED
 3818  77 if (status != Status.STATUS_COMMITTED)
 3819    {
 3820  77 log.warn("status is " + status + " (not ACTIVE or PREPARING); returning null)", new Throwable());
 3821    }
 3822    else
 3823    {
 3824  0 log.trace("status is COMMITTED; returning null");
 3825    }
 3826   
 3827  77 return null;
 3828    }
 3829   
 3830  164079 return getCurrentTransaction(tx, createIfNotExists);
 3831    }
 3832   
 3833    /**
 3834    * Returns the global transaction for this local transaction.
 3835    */
 3836  85 public GlobalTransaction getCurrentTransaction(Transaction tx)
 3837    {
 3838  85 return getCurrentTransaction(tx, true);
 3839    }
 3840   
 3841    /**
 3842    * Returns the global transaction for this local transaction.
 3843    *
 3844    * @param createIfNotExists if true, if a global transaction is not found; one is created
 3845    */
 3846  3767064 public GlobalTransaction getCurrentTransaction(Transaction tx, boolean createIfNotExists)
 3847    {
 3848    // removed synchronization on tx_table because underlying implementation is thread safe
 3849    // and JTA spec (section 3.4.3 Thread of Control, par 2) says that only one thread may
 3850    // operate on the transaction at one time so no concern about 2 threads trying to call
 3851    // this method for the same Transaction instance at the same time
 3852    //
 3853  3767065 GlobalTransaction gtx = tx_table.get(tx);
 3854  3767064 if (gtx == null && createIfNotExists)
 3855    {
 3856  1121224 Address addr = getLocalAddress();
 3857  1121224 gtx = GlobalTransaction.create(addr);
 3858  1121224 tx_table.put(tx, gtx);
 3859  1121224 TransactionEntry ent = configuration.isNodeLockingOptimistic() ? new OptimisticTransactionEntry() : new TransactionEntry();
 3860  1121224 ent.setTransaction(tx);
 3861  1121224 tx_table.put(gtx, ent);
 3862  1121224 if (log.isTraceEnabled())
 3863    {
 3864  0 log.trace("created new GTX: " + gtx + ", local TX=" + tx);
 3865    }
 3866    }
 3867  3767065 return gtx;
 3868    }
 3869   
 3870   
 3871    /**
 3872    * Invokes a method against this object. Contains the logger_ic for handling
 3873    * the various use cases, e.g. mode (local, repl_async, repl_sync),
 3874    * transaction (yes or no) and locking (yes or no).
 3875    * <p/>
 3876    * Only sets originLocal on the invocation context IF this is explicitly passed in as <tt>false</tt>
 3877    * If passed in as <tt>true</tt> then it is not set; but whatever default exists in the invocation
 3878    * context is used. For example, it may be set prior to calling invokeMethod()
 3879    */
 3880  2480292 protected Object invokeMethod(MethodCall m, boolean originLocal) throws CacheException
 3881    {
 3882    // don't create a new one; get it from ThreadLocal just this once, in case a user has added any overrides.
 3883  2480292 InvocationContext ctx = getInvocationContext();
 3884  2480292 MethodCall oldCall = null;
 3885  2480292 try
 3886    {
 3887    // check if we had a method call lurking around
 3888  2480292 oldCall = ctx.getMethodCall();
 3889  2480292 ctx.setMethodCall(m);
 3890    // only set this if originLocal is EXPLICITLY passed in as FALSE. Otherwise leave it as a default.
 3891  43746 if (!originLocal) ctx.setOriginLocal(false);
 3892  2480292 return interceptor_chain.invoke(ctx);
 3893    }
 3894    catch (CacheException e)
 3895    {
 3896  65 throw e;
 3897    }
 3898    catch (RuntimeException e)
 3899    {
 3900  13 throw e;
 3901    }
 3902    catch (Throwable t)
 3903    {
 3904  10 throw new RuntimeException(t);
 3905    }
 3906    finally
 3907    {
 3908  43746 if (!originLocal) ctx.setOriginLocal(true);
 3909    // reset old method call
 3910  2480291 ctx.setMethodCall(oldCall);
 3911    }
 3912    }
 3913   
 3914    /**
 3915    * Returns an object suitable for use in node locking, either the current
 3916    * transaction or the current thread if there is no transaction.
 3917    */
 3918  208 protected Object getOwnerForLock()
 3919    {
 3920  208 Object owner = getCurrentTransaction();
 3921  208 if (owner == null)
 3922    {
 3923  208 owner = Thread.currentThread();
 3924    }
 3925   
 3926  208 return owner;
 3927    }
 3928   
 3929    /**
 3930    * Finds a node given a fully qualified name.
 3931    * Whenever nodes are created, and the global transaction is not null, the created
 3932    * nodes have to be added to the transaction's {@link TransactionEntry}
 3933    * field.<br>
 3934    * When a lock is acquired on a node, a reference to the lock has to be
 3935    * {@link TransactionEntry#addLock(org.jboss.cache.lock.NodeLock) added to the list of locked nodes}
 3936    * in the {@link TransactionEntry}.
 3937    * <p>This operation will also apply different locking to the cache nodes, depending on
 3938    * <tt>operation_type</tt>. If it is <tt>read</tt> type, all nodes will be acquired with
 3939    * read lock. Otherwise, the operation is <tt>write</tt> type, all parent nodes will be acquired
 3940    * with read lock while the destination node acquires write lock.</p>
 3941    *
 3942    * @param fqn Fully qualified name for the corresponding node.
 3943    * @return DataNode
 3944    */
 3945  1499957 public NodeSPI<K, V> findNode(Fqn fqn)
 3946    {
 3947  1499957 try
 3948    {
 3949  1499957 return findNode(fqn, null);
 3950    }
 3951    catch (CacheException e)
 3952    {
 3953  0 log.warn("Unexpected error", e);
 3954  0 return null;
 3955    }
 3956    }
 3957   
 3958  419070 private NodeSPI<K, V> findNodeCheck(GlobalTransaction tx, Fqn fqn)
 3959    {
 3960  419070 NodeSPI<K, V> n = findNode(fqn);
 3961  419070 if (n == null)
 3962    {
 3963  1 String errStr = "node " + fqn + " not found (gtx=" + tx + ", caller=" + Thread.currentThread() + ")";
 3964  1 if (log.isTraceEnabled())
 3965    {
 3966  0 log.trace(errStr);
 3967    }
 3968  1 throw new NodeNotExistsException(errStr);
 3969    }
 3970  419069 return n;
 3971    }
 3972   
 3973    /**
 3974    * Internal method; not to be used externally.
 3975    * Returns true if the node was found, false if not.
 3976    *
 3977    * @param f
 3978    */
 3979  16830 public boolean realRemove(Fqn f, boolean skipMarkerCheck)
 3980    {
 3981  16830 NodeSPI n = peek(f, true);
 3982  16830 if (n == null)
 3983    {
 3984  2266 return false;
 3985    }
 3986   
 3987  0 if (log.isTraceEnabled()) log.trace("Performing a real remove for node " + f + ", marked for removal.");
 3988  14564 if (skipMarkerCheck || n.isDeleted())
 3989    {
 3990  14115 if (n.getFqn().isRoot())
 3991    {
 3992    // do not actually delete; just remove deletion marker
 3993  0 n.markAsDeleted(true);
 3994    // but now remove all children, since the call has been to remove("/")
 3995  0 n.removeChildrenDirect();
 3996  0 return true;
 3997    }
 3998    else
 3999    {
 4000  14115 return n.getParent().removeChildDirect(n.getFqn().getLastElement());
 4001    }
 4002    }
 4003    else
 4004    {
 4005  0 if (log.isDebugEnabled()) log.debug("Node " + f + " NOT marked for removal as expected, not removing!");
 4006  449 return false;
 4007    }
 4008    }
 4009   
 4010    /**
 4011    * Finds a node given a fully qualified name and DataVersion.
 4012    */
 4013  1606949 private NodeSPI<K, V> findNode(Fqn fqn, DataVersion version) throws CacheException
 4014    {
 4015  17 if (fqn == null) return null;
 4016   
 4017  1606932 NodeSPI<K, V> toReturn = peek(fqn, false);
 4018   
 4019  1606932 if (version != null && configuration.isNodeLockingOptimistic())
 4020    {
 4021    // we need to check the version of the data node...
 4022  0 DataVersion nodeVersion = toReturn.getVersion();
 4023  0 if (log.isTraceEnabled())
 4024    {
 4025  0 log.trace("looking for optimistic node [" + fqn + "] with version [" + version + "]. My version is [" + nodeVersion + "]");
 4026    }
 4027  0 if (nodeVersion.newerThan(version))
 4028    {
 4029    // we have a versioning problem; throw an exception!
 4030  0 throw new CacheException("Unable to validate versions.");
 4031    }
 4032    }
 4033  1606932 return toReturn;
 4034    }
 4035   
 4036  40066 public synchronized RegionManager getRegionManager()
 4037    {
 4038  40066 if (regionManager == null)
 4039    {
 4040  26 regionManager = new RegionManager(this);
 4041    }
 4042  40066 return regionManager;
 4043    }
 4044   
 4045   
 4046  79610 public Marshaller getMarshaller()
 4047    {
 4048  79610 if (marshaller_ == null)
 4049    {
 4050  1472 synchronized (this)
 4051    {
 4052  1472 if (marshaller_ == null)
 4053    {
 4054  1472 if (configuration.getMarshallerClass() == null || configuration.getMarshallerClass().equals(VersionAwareMarshaller.class.getName()))
 4055    {
 4056  1472 marshaller_ = new VersionAwareMarshaller(getRegionManager(), configuration);
 4057    }
 4058    else
 4059    {
 4060  0 try
 4061    {
 4062  0 marshaller_ = (Marshaller) org.jboss.cache.util.Util.loadClass(configuration.getMarshallerClass()).newInstance();
 4063    }
 4064    catch (Exception e)
 4065    {
 4066  0 log.error("Unable to load marshaller " + configuration.getMarshallerClass() + ". Falling back to default (" + VersionAwareMarshaller.class.getName() + ")");
 4067  0 marshaller_ = new VersionAwareMarshaller(getRegionManager(), configuration);
 4068    }
 4069    }
 4070  1472 if (log.isInfoEnabled()) log.info("Using marshaller " + marshaller_.getClass().getName());
 4071    }
 4072    }
 4073    }
 4074  79610 return marshaller_;
 4075    }
 4076   
 4077    /**
 4078    * Returns the default JGroup properties.
 4079    * Subclasses may wish to override this method.
 4080    */
 4081  335 protected String getDefaultProperties()
 4082    {
 4083  335 return "UDP(mcast_addr=224.0.0.36;mcast_port=55566;ip_ttl=32;" +
 4084    "mcast_send_buf_size=150000;mcast_recv_buf_size=80000):" +
 4085    "PING(timeout=1000;num_initial_members=2):" +
 4086    "MERGE2(min_interval=5000;max_interval=10000):" +
 4087    "FD_SOCK:" +
 4088    "VERIFY_SUSPECT(timeout=1500):" +
 4089    "pbcast.NAKACK(gc_lag=50;max_xmit_size=8192;retransmit_timeout=600,1200,2400,4800):" +
 4090    "UNICAST(timeout=600,1200,2400,4800):" +
 4091    "pbcast.STABLE(desired_avg_gossip=20000):" +
 4092    "FRAG(frag_size=8192;down_thread=false;up_thread=false):" +
 4093    "pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;" +
 4094    "shun=false;print_local_addr=true):" +
 4095    "pbcast.STATE_TRANSFER";
 4096    }
 4097   
 4098  1036 private void initialiseCacheLoaderManager() throws CacheException
 4099    {
 4100  1036 if (cacheLoaderManager == null)
 4101    {
 4102  1036 cacheLoaderManager = new CacheLoaderManager();
 4103    }
 4104  1036 cacheLoaderManager.setConfig(configuration.getCacheLoaderConfig(), this);
 4105    }
 4106   
 4107    /**
 4108    * Sets the CacheLoader to use.
 4109    * Provided for backwards compatibility.
 4110    *
 4111    * @param loader
 4112    * @deprecated only provided for backward compat
 4113    */
 4114  109 @Deprecated
 4115    public void setCacheLoader(CacheLoader loader)
 4116    {
 4117  109 log.warn("Using deprecated config method setCacheLoader. This element will be removed in future, please use CacheLoaderConfiguration instead.");
 4118   
 4119  109 try
 4120    {
 4121  107 if (cacheLoaderManager == null) initialiseCacheLoaderManager();
 4122    }
 4123    catch (Exception e)
 4124    {
 4125  1 log.warn("Problem setting cache loader. Perhaps your cache loader config has not been set yet?");
 4126    }
 4127  109 cacheLoaderManager.setCacheLoader(loader);
 4128    }
 4129   
 4130    /**
 4131    * Purges the contents of all configured {@link CacheLoader}s
 4132    */
 4133  0 public void purgeCacheLoaders() throws Exception
 4134    {
 4135  0 if (cacheLoaderManager != null) cacheLoaderManager.purgeLoaders(true);
 4136    }
 4137   
 4138    // ---------------------------------------------------------------
 4139    // END: Methods to provide backward compatibility with older cache loader config settings
 4140    // ---------------------------------------------------------------
 4141   
 4142  1099 private void initialiseChannelAndRpcDispatcher() throws CacheException
 4143    {
 4144  1099 channel = configuration.getRuntimeConfig().getChannel();
 4145  1099 if (channel == null)
 4146    {
 4147    // Try to create a multiplexer channel
 4148  1095 channel = getMultiplexerChannel();
 4149   
 4150  1093 if (channel != null)
 4151    {
 4152  65 configuration.setUsingMultiplexer(true);
 4153  65 if (log.isDebugEnabled())
 4154    {
 4155  0 log.debug("Created Multiplexer Channel for cache cluster " + configuration.getClusterName() +
 4156    " using stack " + configuration.getMultiplexerStack());
 4157    }
 4158    }
 4159    else
 4160    {
 4161  1028 if (configuration.getClusterConfig() == null)
 4162    {
 4163  335 log.debug("setting cluster properties to default value");
 4164  335 configuration.setClusterConfig(getDefaultProperties());
 4165    }
 4166  1028 try
 4167    {
 4168  1028 channel = new JChannel(configuration.getClusterConfig());
 4169    }
 4170    catch (Exception e)
 4171    {
 4172  0 throw new CacheException("Unable to create JGroups channel", e);
 4173    }
 4174  1028 if (log.isTraceEnabled())
 4175    {
 4176  0 log.trace("cache properties: " + configuration.getClusterConfig());
 4177    }
 4178    }
 4179   
 4180  1093 configuration.getRuntimeConfig().setChannel(channel);
 4181    }
 4182   
 4183  1097 channel.setOpt(Channel.AUTO_RECONNECT, true);
 4184  1097 channel.setOpt(Channel.AUTO_GETSTATE, true);
 4185  1097 channel.setOpt(Channel.BLOCK, true);
 4186   
 4187    // always use the InactiveRegionAwareRpcDispatcher - exceptions due to regions not being active should not propagate to remote
 4188    // nodes as errors. - Manik
 4189  1097 disp = new InactiveRegionAwareRpcDispatcher(channel, ml, new MembershipListenerAdaptor(), this);
 4190    // disp = new RpcDispatcher(channel, ml, this, this);
 4191   
 4192  1097 disp.setRequestMarshaller(getMarshaller());
 4193  1097 disp.setResponseMarshaller(getMarshaller());
 4194    }
 4195   
 4196  1095 private JChannel getMultiplexerChannel() throws CacheException
 4197    {
 4198  1095 String stackName = configuration.getMultiplexerStack();
 4199   
 4200  1095 RuntimeConfig rtc = configuration.getRuntimeConfig();
 4201  1095 ChannelFactory channelFactory = rtc.getMuxChannelFactory();
 4202  1095 JChannel muxchannel = null;
 4203   
 4204  1095 if (channelFactory != null)
 4205    {
 4206  67 try
 4207    {
 4208  67 muxchannel = (JChannel) channelFactory.createMultiplexerChannel(stackName, configuration.getClusterName());
 4209    }
 4210    catch (Exception e)
 4211    {
 4212  2 throw new CacheException("Failed to create multiplexed channel using stack " + stackName, e);
 4213    }
 4214    }
 4215   
 4216  1093 return muxchannel;
 4217    }
 4218   
 4219    // ================== methods to implement Cache and CacheSPI interfaces ============================
 4220   
 4221  3545 public List<Interceptor> getInterceptorChain()
 4222    {
 4223  3545 List<Interceptor> modifiable = getInterceptors();
 4224  3545 return modifiable == null ? null : Collections.unmodifiableList(modifiable);
 4225    }
 4226   
 4227  339 public void addCacheListener(Object listener)
 4228    {
 4229  339 getNotifier().addCacheListener(listener);
 4230    }
 4231   
 4232  2 public void addCacheListener(Fqn<?> region, Object listener)
 4233    {
 4234  2 throw new UnsupportedOperationException("Not implemented in this release");
 4235    }
 4236   
 4237  308 public void removeCacheListener(Object listener)
 4238    {
 4239    // BES 2007/5/23 workaround to avoid NPE while we decide whether
 4240    // to remove notifier in destroy()
 4241  308 Notifier n = getNotifier();
 4242  308 if (n != null)
 4243  308 n.removeCacheListener(listener);
 4244    }
 4245   
 4246  2 public void removeCacheListener(Fqn<?> region, Object listener)
 4247    {
 4248  2 throw new UnsupportedOperationException("Not implemented in this release");
 4249    }
 4250   
 4251  6 public Set<Object> getCacheListeners()
 4252    {
 4253  6 return getNotifier().getCacheListeners();
 4254    }
 4255   
 4256  2 public Set<Object> getCacheListeners(Fqn<?> region)
 4257    {
 4258  2 throw new UnsupportedOperationException("Not implemented in this release");
 4259    }
 4260   
 4261  4 public synchronized void addInterceptor(Interceptor i, int position)
 4262    {
 4263  4 List<Interceptor> interceptors = getInterceptors();
 4264   
 4265  4 i.setCache(this);
 4266   
 4267  4 interceptors.add(position, i);
 4268   
 4269    // now correct the chaining of interceptors...
 4270  3 Interceptor linkedChain = InterceptorChainFactory.getInstance().correctInterceptorChaining(interceptors);
 4271   
 4272  3 setInterceptorChain(linkedChain);
 4273    }
 4274   
 4275  4 public synchronized void removeInterceptor(int position)
 4276    {
 4277  4 List<Interceptor> i = getInterceptors();
 4278  4 i.remove(position);
 4279  3 setInterceptorChain(InterceptorChainFactory.getInstance().correctInterceptorChaining(i));
 4280    }
 4281   
 4282  244788 public RPCManager getRPCManager()
 4283    {
 4284  244788 return configuration.getRuntimeConfig().getRPCManager();
 4285    }
 4286   
 4287  194 public String getClusterName()
 4288    {
 4289  194 return getConfiguration().getClusterName();
 4290    }
 4291   
 4292  86796 public void evict(Fqn<?> fqn, boolean recursive)
 4293    {
 4294  86796 if (recursive)
 4295    {
 4296  26 Node<K, V> n = get(fqn);
 4297  26 if (n != null)
 4298    {
 4299  26 evictChildren((NodeSPI<K, V>) n);
 4300    }
 4301    }
 4302    else
 4303    {
 4304  86770 evict(fqn);
 4305    }
 4306    }
 4307   
 4308  98 private void evictChildren(NodeSPI<K, V> n)
 4309    {
 4310  98 for (NodeSPI<K, V> child : n.getChildrenDirect())
 4311    {
 4312  72 evictChildren(child);
 4313    }
 4314  98 evict(n.getFqn());
 4315    }
 4316   
 4317  29994 public Region getRegion(Fqn<?> fqn, boolean createIfAbsent)
 4318    {
 4319  29994 return getRegionManager().getRegion(fqn, createIfAbsent);
 4320    }
 4321   
 4322  0 public boolean removeRegion(Fqn<?> fqn)
 4323    {
 4324  0 return getRegionManager().removeRegion(fqn);
 4325    }
 4326   
 4327  12883 public boolean removeNode(Fqn<?> fqn)
 4328    {
 4329  12883 return remove(fqn);
 4330    }
 4331   
 4332  24 public void putForExternalRead(Fqn<?> fqn, K key, V value)
 4333    {
 4334    // if the node exists then this should be a no-op.
 4335  24 if (!exists(fqn))
 4336    {
 4337  20 getInvocationContext().getOptionOverrides().setFailSilently(true);
 4338  20 GlobalTransaction tx = getCurrentTransaction();
 4339  20 MethodCall m = MethodCallFactory.create(MethodDeclarations.putForExternalReadMethodLocal, tx, fqn, key, value);
 4340  20 invokeMethod(m, true);
 4341    }
 4342    else
 4343    {
 4344  4 if (log.isDebugEnabled())
 4345  0 log.debug("putForExternalRead() called with Fqn " + fqn + " and this node already exists. This method is hence a no op.");
 4346    }
 4347    }
 4348   
 4349  12 public void _putForExternalRead(GlobalTransaction gtx, Fqn fqn, K key, V value)
 4350    {
 4351  12 _put(gtx, fqn, key, value, true);
 4352    }
 4353   
 4354  9103 public boolean isStarted()
 4355    {
 4356  9103 return getCacheStatus() == CacheStatus.STARTED;
 4357    }
 4358   
 4359  2 protected void setMessageListener(MessageListenerAdaptor ml)
 4360    {
 4361  2 this.ml = ml;
 4362    }
 4363   
 4364    }