PageRenderTime 40ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/servers/cluster/core/src/main/java/org/mobicents/cluster/DefaultMobicentsCluster.java

http://mobicents.googlecode.com/
Java | 638 lines | 373 code | 68 blank | 197 comment | 98 complexity | 45c0613c8cffdc8cea4c4826763a4499 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0, LGPL-2.1, GPL-2.0, CC-BY-SA-3.0, CC0-1.0, Apache-2.0, BSD-3-Clause
  1. /*
  2. * JBoss, Home of Professional Open Source
  3. * Copyright 2011, Red Hat, Inc. and individual contributors
  4. * by the @authors tag. See the copyright.txt in the distribution for a
  5. * full listing of individual contributors.
  6. *
  7. * This is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation; either version 2.1 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This software is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this software; if not, write to the Free
  19. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  21. */
  22. package org.mobicents.cluster;
  23. import java.util.ArrayList;
  24. import java.util.Collections;
  25. import java.util.List;
  26. import java.util.Map;
  27. import java.util.Set;
  28. import java.util.SortedSet;
  29. import java.util.TreeSet;
  30. import java.util.concurrent.ConcurrentHashMap;
  31. import javax.transaction.TransactionManager;
  32. import org.apache.log4j.Logger;
  33. import org.jboss.cache.Cache;
  34. import org.jboss.cache.Fqn;
  35. import org.jboss.cache.Node;
  36. import org.jboss.cache.buddyreplication.BuddyGroup;
  37. import org.jboss.cache.config.Configuration;
  38. import org.jboss.cache.config.Configuration.CacheMode;
  39. import org.jboss.cache.notifications.annotation.BuddyGroupChanged;
  40. import org.jboss.cache.notifications.annotation.CacheListener;
  41. import org.jboss.cache.notifications.annotation.NodeRemoved;
  42. import org.jboss.cache.notifications.annotation.ViewChanged;
  43. import org.jboss.cache.notifications.event.BuddyGroupChangedEvent;
  44. import org.jboss.cache.notifications.event.NodeRemovedEvent;
  45. import org.jboss.cache.notifications.event.ViewChangedEvent;
  46. import org.jgroups.Address;
  47. import org.mobicents.cache.MobicentsCache;
  48. import org.mobicents.cluster.cache.ClusteredCacheData;
  49. import org.mobicents.cluster.cache.ClusteredCacheDataIndexingHandler;
  50. import org.mobicents.cluster.cache.DefaultClusteredCacheDataIndexingHandler;
  51. import org.mobicents.cluster.election.ClientLocalListenerElector;
  52. import org.mobicents.cluster.election.ClusterElector;
  53. /**
  54. * Listener that is to be used for cluster wide replication(meaning no buddy
  55. * replication, no data gravitation). It will index activity on nodes marking
  56. * current node as owner(this is semi-gravitation behavior (we don't delete, we
  57. * just mark)).
  58. *
  59. * Indexing is only at node level, i.e., there is no
  60. * reverse indexing, so it has to iterate through whole resource group data FQNs to check which
  61. * nodes should be taken over.
  62. *
  63. * @author <a href="mailto:baranowb@gmail.com">Bartosz Baranowski </a>
  64. * @author martins
  65. */
  66. @CacheListener(sync = false)
  67. public class DefaultMobicentsCluster implements MobicentsCluster {
  68. private static final String FQN_SEPARATOR = Fqn.SEPARATOR;
  69. private static final String BUDDY_BACKUP_FQN_ROOT = "/_BUDDY_BACKUP_/";
  70. private static final Logger logger = Logger.getLogger(DefaultMobicentsCluster.class);
  71. private static final String BUDDIES_STORE = "MC_BUDDIES";
  72. private final SortedSet<FailOverListener> failOverListeners;
  73. @SuppressWarnings("unchecked")
  74. private final ConcurrentHashMap<Fqn, DataRemovalListener> dataRemovalListeners;
  75. private final MobicentsCache mobicentsCache;
  76. private final TransactionManager txMgr;
  77. private final ClusterElector elector;
  78. private final DefaultClusteredCacheDataIndexingHandler clusteredCacheDataIndexingHandler;
  79. private List<Address> currentView;
  80. private boolean started;
  81. @SuppressWarnings("unchecked")
  82. public DefaultMobicentsCluster(MobicentsCache watchedCache, TransactionManager txMgr, ClusterElector elector) {
  83. this.failOverListeners = Collections.synchronizedSortedSet(new TreeSet<FailOverListener>(new FailOverListenerPriorityComparator()));
  84. this.dataRemovalListeners = new ConcurrentHashMap<Fqn, DataRemovalListener>();
  85. this.mobicentsCache = watchedCache;
  86. this.txMgr = txMgr;
  87. this.elector = elector;
  88. this.clusteredCacheDataIndexingHandler = new DefaultClusteredCacheDataIndexingHandler();
  89. }
  90. /* (non-Javadoc)
  91. * @see org.mobicents.cluster.MobicentsCluster#getLocalAddress()
  92. */
  93. public Address getLocalAddress() {
  94. return mobicentsCache.getJBossCache().getLocalAddress();
  95. }
  96. /* (non-Javadoc)
  97. * @see org.mobicents.cluster.MobicentsCluster#getClusterMembers()
  98. */
  99. public List<Address> getClusterMembers() {
  100. if (currentView != null) {
  101. return Collections.unmodifiableList(currentView);
  102. }
  103. else {
  104. final Address localAddress = getLocalAddress();
  105. if (localAddress == null) {
  106. return Collections.emptyList();
  107. }
  108. else {
  109. final List<Address> list = new ArrayList<Address>();
  110. list.add(localAddress);
  111. return Collections.unmodifiableList(list);
  112. }
  113. }
  114. }
  115. /* (non-Javadoc)
  116. * @see org.mobicents.cluster.MobicentsCluster#isHeadMember()
  117. */
  118. public boolean isHeadMember() {
  119. final Address localAddress = getLocalAddress();
  120. if (localAddress != null) {
  121. final List<Address> clusterMembers = getClusterMembers();
  122. return !clusterMembers.isEmpty() && clusterMembers.get(0).equals(localAddress);
  123. }
  124. else {
  125. return true;
  126. }
  127. }
  128. /*
  129. * (non-Javadoc)
  130. * @see org.mobicents.cluster.MobicentsCluster#isSingleMember()
  131. */
  132. public boolean isSingleMember() {
  133. final Address localAddress = getLocalAddress();
  134. if (localAddress != null) {
  135. final List<Address> clusterMembers = getClusterMembers();
  136. return clusterMembers.size() == 1;
  137. }
  138. else {
  139. return true;
  140. }
  141. }
  142. /**
  143. * Method handle a change on the cluster members set
  144. * @param event
  145. */
  146. @ViewChanged
  147. public synchronized void onViewChangeEvent(ViewChangedEvent event) {
  148. if (logger.isDebugEnabled()) {
  149. logger.debug("onViewChangeEvent : pre[" + event.isPre() + "] : event local address[" + event.getCache().getLocalAddress() + "]");
  150. }
  151. final List<Address> oldView = currentView;
  152. currentView = new ArrayList<Address>(event.getNewView().getMembers());
  153. final Address localAddress = getLocalAddress();
  154. //just a precaution, it can be null!
  155. if (oldView != null) {
  156. final Cache jbossCache = mobicentsCache.getJBossCache();
  157. final Configuration config = jbossCache.getConfiguration();
  158. final boolean isBuddyReplicationEnabled = config.getBuddyReplicationConfig() != null && config.getBuddyReplicationConfig().isEnabled();
  159. // recover stuff from lost members
  160. Runnable runnable = new Runnable() {
  161. public void run() {
  162. for (Address oldMember : oldView) {
  163. if (!currentView.contains(oldMember)) {
  164. if (logger.isDebugEnabled()) {
  165. logger.debug("onViewChangeEvent : processing lost member " + oldMember);
  166. }
  167. for (FailOverListener localListener : failOverListeners) {
  168. ClientLocalListenerElector localListenerElector = localListener.getElector();
  169. if (localListenerElector != null && !isBuddyReplicationEnabled) {
  170. // going to use the local listener elector instead, which gives results based on data
  171. performTakeOver(localListener,oldMember,localAddress, true, isBuddyReplicationEnabled);
  172. }
  173. else {
  174. List<Address> electionView = getElectionView(oldMember);
  175. if(electionView!=null && elector.elect(electionView).equals(localAddress))
  176. {
  177. performTakeOver(localListener, oldMember, localAddress, false, isBuddyReplicationEnabled);
  178. }
  179. cleanAfterTakeOver(localListener, oldMember);
  180. }
  181. }
  182. }
  183. }
  184. }
  185. };
  186. Thread t = new Thread(runnable);
  187. t.start();
  188. }
  189. }
  190. @BuddyGroupChanged
  191. public void onBuddyGroupChangedEvent(BuddyGroupChangedEvent event) {
  192. //here we only update stored information, it happens after view change, so take over should be taken care off.
  193. Node root = event.getCache().getRoot();
  194. root.put(BUDDIES_STORE, event.getBuddyGroup().getBuddies());
  195. }
  196. /**
  197. *
  198. */
  199. @SuppressWarnings("unchecked")
  200. private void performTakeOver(FailOverListener localListener, Address lostMember, Address localAddress, boolean useLocalListenerElector, boolean isBuddyReplicationEnabled) {
  201. //WARNING1: avoid using string representation, it may look ok, but hash is different if Fqn is not composed only from strings
  202. //WARNING2: use Fqn.fromRelativeElemenets(); -- Fqn.fromElements(); adds Fqn.SEPARATOR at beggin of Fqn.
  203. if (logger.isDebugEnabled()) {
  204. logger.debug("onViewChangeEvent : " + localAddress + " failing over lost member " + lostMember + ", useLocalListenerElector=" + useLocalListenerElector + ", isBuddyReplicationEnabled=" + isBuddyReplicationEnabled);
  205. }
  206. //final boolean useLocalListenerElector = localListener.getElector()!=null;
  207. final Cache jbossCache = mobicentsCache.getJBossCache();
  208. final Fqn rootFqnOfChanges = localListener.getBaseFqn();
  209. boolean createdTx = false;
  210. boolean doRollback = true;
  211. try {
  212. if (txMgr != null && txMgr.getTransaction() == null) {
  213. txMgr.begin();
  214. createdTx = true;
  215. }
  216. if(isBuddyReplicationEnabled) {
  217. // replace column to underscore in the couple ipaddress:port of the jgroups address
  218. // to match the BUDDY GROUP Fqn pattern in the cache
  219. String fqn = getBuddyBackupFqn(lostMember) + localListener.getBaseFqn();
  220. Node buddyGroupRootNode = jbossCache.getNode(Fqn.fromString(fqn));
  221. if (buddyGroupRootNode != null) {
  222. Set<Node> children = buddyGroupRootNode.getChildren();
  223. if (logger.isDebugEnabled()) {
  224. logger.debug("Fqn : " + fqn + " : children " + children);
  225. }
  226. // force data gravitation for each node under the base fqn
  227. // we want to retrieve from the buddy that died
  228. for (Node child : children) {
  229. Fqn childFqn = Fqn.fromRelativeElements(localListener.getBaseFqn(), child.getFqn().getLastElement());
  230. if (logger.isDebugEnabled()) {
  231. logger.debug("forcing data gravitation on following child fqn " + childFqn);
  232. }
  233. jbossCache.getInvocationContext().getOptionOverrides().setForceDataGravitation(true);
  234. Node n = jbossCache.getNode(childFqn);
  235. }
  236. } else {
  237. if (logger.isDebugEnabled()) {
  238. logger.debug("Fqn : " + fqn + " : doesn't return any node, this node " + localAddress
  239. + "might not be a buddy group of the failed node " + lostMember);
  240. }
  241. }
  242. }
  243. if (createdTx) {
  244. txMgr.commit();
  245. createdTx = false;
  246. }
  247. if (txMgr != null && txMgr.getTransaction() == null) {
  248. txMgr.begin();
  249. createdTx = true;
  250. }
  251. localListener.failOverClusterMember(lostMember);
  252. Set<Object> children = jbossCache.getChildrenNames(rootFqnOfChanges);
  253. for (Object childName : children) {
  254. // Here in values we store data and... inet node., we must match
  255. // passed one.
  256. final ClusteredCacheData clusteredCacheData = new ClusteredCacheData(Fqn.fromRelativeElements(rootFqnOfChanges, childName),this);
  257. if (clusteredCacheData.exists()) {
  258. Address address = clusteredCacheData.getClusterNodeAddress();
  259. if (address != null && address.equals(lostMember)) {
  260. // may need to do election using client local listener
  261. if (!isBuddyReplicationEnabled && useLocalListenerElector) {
  262. if(!localAddress.equals(localListener.getElector().elect(currentView, clusteredCacheData))) {
  263. // not elected, move on
  264. continue;
  265. }
  266. }
  267. // call back the listener
  268. localListener.wonOwnership(clusteredCacheData);
  269. // change ownership
  270. clusteredCacheData.setClusterNodeAddress(localAddress);
  271. }
  272. }else
  273. {
  274. //FIXME: debug?
  275. if(logger.isDebugEnabled())
  276. {
  277. logger.debug(" Attempt to index: "+Fqn.fromRelativeElements(rootFqnOfChanges, childName)+" failed, node does not exist.");
  278. }
  279. }
  280. }
  281. doRollback = false;
  282. } catch (Exception e) {
  283. logger.error(e.getMessage(),e);
  284. } finally {
  285. if (createdTx) {
  286. try {
  287. if (!doRollback) {
  288. txMgr.commit();
  289. }
  290. else {
  291. txMgr.rollback();
  292. }
  293. } catch (Exception e) {
  294. logger.error(e.getMessage(),e);
  295. }
  296. }
  297. }
  298. }
  299. @NodeRemoved
  300. public void onNodeRemovedEvent(NodeRemovedEvent event) {
  301. if(!event.isOriginLocal() && !event.isPre()) {
  302. final DataRemovalListener dataRemovalListener = dataRemovalListeners.get(event.getFqn().getParent());
  303. if (dataRemovalListener != null) {
  304. dataRemovalListener.dataRemoved(event.getFqn());
  305. }
  306. }
  307. }
  308. private List<Address> getElectionView(Address deadMember) {
  309. final Cache jbossCache = mobicentsCache.getJBossCache();
  310. final Configuration config = jbossCache.getConfiguration();
  311. final boolean isBuddyReplicationEnabled = config.getBuddyReplicationConfig() != null
  312. && config.getBuddyReplicationConfig().isEnabled();
  313. if (isBuddyReplicationEnabled) {
  314. boolean createdTx = false;
  315. boolean doRollback = true;
  316. try {
  317. if (txMgr != null && txMgr.getTransaction() == null) {
  318. txMgr.begin();
  319. createdTx = true;
  320. }
  321. // than election view is a buddy view
  322. String fqnBackupRoot = getBuddyBackupFqn(deadMember);
  323. // check if we were a buddy
  324. Node backupRoot = jbossCache.getNode(fqnBackupRoot);
  325. if (backupRoot != null) {
  326. // we were a buddy it seems
  327. List<Address> buddies = (List<Address>) backupRoot.get(BUDDIES_STORE);
  328. if (buddies == null) {
  329. // which is weird
  330. buddies = new ArrayList<Address>();
  331. buddies.add(config.getRuntimeConfig().getChannel().getLocalAddress());
  332. }
  333. return buddies;
  334. } else {
  335. return null;
  336. }
  337. } catch (Exception e) {
  338. logger.error(e.getMessage(), e);
  339. } finally {
  340. if (createdTx) {
  341. try {
  342. if (!doRollback) {
  343. txMgr.commit();
  344. } else {
  345. txMgr.rollback();
  346. }
  347. } catch (Exception e) {
  348. logger.error(e.getMessage(), e);
  349. }
  350. }
  351. }
  352. // in case of failure
  353. return null;
  354. } else {
  355. // no buddies, its cluster wide election
  356. return currentView;
  357. }
  358. }
  359. private String getBuddyBackupFqn(Address owner)
  360. {
  361. //FIXME: switch to BuddyFqnTransformer
  362. String lostMemberFqnizied = owner.toString().replace(":", "_");
  363. String fqn = BUDDY_BACKUP_FQN_ROOT + lostMemberFqnizied ;
  364. return fqn;
  365. }
  366. private void cleanAfterTakeOver(FailOverListener localListener, Address deadMember)
  367. {
  368. final Cache jbossCache = mobicentsCache.getJBossCache();
  369. final Configuration config = jbossCache.getConfiguration();
  370. final boolean isBuddyReplicationEnabled = config.getBuddyReplicationConfig() != null && config.getBuddyReplicationConfig().isEnabled();
  371. if(isBuddyReplicationEnabled)
  372. {
  373. //1. clean backup of the base fqn only
  374. String fqn = getBuddyBackupFqn(deadMember) + localListener.getBaseFqn();
  375. jbossCache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
  376. jbossCache.removeNode(Fqn.fromString(fqn));
  377. //2. if that member is our single buddy, we need to clean MC_BUDDIES
  378. BuddyGroup bg = config.getRuntimeConfig().getBuddyGroup();
  379. if(bg!=null && bg.getBuddies().size() == 1 && bg.getBuddies().contains(deadMember))
  380. {
  381. jbossCache.getRoot().remove(BUDDIES_STORE);
  382. }
  383. }
  384. }
  385. // NOTE USED FOR NOW
  386. /*
  387. @NodeCreated
  388. public void onNodeCreateddEvent(NodeCreatedEvent event) {
  389. if (log.isDebugEnabled()) {
  390. log.debug("onNodeCreateddEvent : " + event.getFqn() + " : local[" + event.isOriginLocal() + "] pre[" + event.isPre() + "] : event local address[" + event.getCache().getLocalAddress()
  391. + "]");
  392. }
  393. }
  394. @NodeModified
  395. public void onNodeModifiedEvent(NodeModifiedEvent event) {
  396. if (log.isDebugEnabled()) {
  397. log.debug("onNodeModifiedEvent : pre[" + event.isPre() + "] : event local address[" + event.getCache().getLocalAddress() + "]");
  398. }
  399. }
  400. @NodeMoved
  401. public void onNodeMovedEvent(NodeMovedEvent event) {
  402. if (log.isDebugEnabled()) {
  403. log.debug("onNodeMovedEvent : " + event.getFqn() + " : local[" + event.isOriginLocal() + "] pre[" + event.isPre() + "] ");
  404. }
  405. }
  406. @NodeVisited
  407. public void onNodeVisitedEvent(NodeVisitedEvent event) {
  408. if (log.isDebugEnabled()) {
  409. log.debug("onNodeVisitedEvent : " + event.getFqn() + " : local[" + event.isOriginLocal() + "] pre[" + event.isPre() + "] ");
  410. }
  411. }
  412. @NodeLoaded
  413. public void onNodeLoadedEvent(NodeLoadedEvent event) {
  414. if (log.isDebugEnabled()) {
  415. log.debug("onNodeLoadedEvent : " + event.getFqn() + " : local[" + event.isOriginLocal() + "] pre[" + event.isPre() + "] ");
  416. }
  417. }
  418. @NodeEvicted
  419. public void onNodeEvictedEvent(NodeEvictedEvent event) {
  420. if (log.isDebugEnabled()) {
  421. log.debug("onNodeEvictedEvent : " + event.getFqn() + " : local[" + event.isOriginLocal() + "] pre[" + event.isPre() + "] ");
  422. }
  423. }
  424. @NodeInvalidated
  425. public void onNodeInvalidatedEvent(NodeInvalidatedEvent event) {
  426. if (log.isDebugEnabled()) {
  427. log.debug("onNodeInvalidatedEvent : " + event.getFqn() + " : local[" + event.isOriginLocal() + "] pre[" + event.isPre() + "] ");
  428. }
  429. }
  430. @NodeActivated
  431. public void onNodeActivatedEvent(NodeActivatedEvent event) {
  432. if (log.isDebugEnabled()) {
  433. log.debug("onNodeActivatedEvent : " + event.getFqn() + " : local[" + event.isOriginLocal() + "] pre[" + event.isPre() + "] ");
  434. }
  435. }
  436. @NodePassivated
  437. public void onNodePassivatedEvent(NodePassivatedEvent event) {
  438. if (log.isDebugEnabled()) {
  439. log.debug("onNodePassivatedEvent : " + event.getFqn() + " : local[" + event.isOriginLocal() + "] pre[" + event.isPre() + "] ");
  440. }
  441. }
  442. @BuddyGroupChanged
  443. public void onBuddyGroupChangedEvent(BuddyGroupChangedEvent event) {
  444. if (log.isDebugEnabled()) {
  445. log.debug("onBuddyGroupChangedEvent : pre[" + event.isPre() + "] ");
  446. }
  447. }
  448. @CacheStarted
  449. public void onCacheStartedEvent(CacheStartedEvent event) {
  450. if (log.isDebugEnabled()) {
  451. log.debug("onCacheStartedEvent : pre[" + event.isPre() + "] ");
  452. }
  453. }
  454. @CacheStopped
  455. public void onCacheStoppedEvent(CacheStoppedEvent event) {
  456. if (log.isDebugEnabled()) {
  457. log.debug("onCacheStoppedEvent : pre[" + event.isPre() + "] ");
  458. }
  459. }
  460. */
  461. // LOCAL LISTENERS MANAGEMENT
  462. /*
  463. * (non-Javadoc)
  464. * @see org.mobicents.cluster.MobicentsCluster#addFailOverListener(org.mobicents.cluster.FailOverListener)
  465. */
  466. public boolean addFailOverListener(FailOverListener localListener) {
  467. if (logger.isDebugEnabled()) {
  468. logger.debug("Adding local listener " + localListener);
  469. }
  470. for(FailOverListener failOverListener : failOverListeners) {
  471. if (failOverListener.getBaseFqn().equals(localListener.getBaseFqn())) {
  472. return false;
  473. }
  474. }
  475. return failOverListeners.add(localListener);
  476. }
  477. /*
  478. * (non-Javadoc)
  479. * @see org.mobicents.cluster.MobicentsCluster#removeFailOverListener(org.mobicents.cluster.FailOverListener)
  480. */
  481. public boolean removeFailOverListener(FailOverListener localListener) {
  482. if (logger.isDebugEnabled()) {
  483. logger.debug("Removing local listener " + localListener);
  484. }
  485. return failOverListeners.remove(localListener);
  486. }
  487. /*
  488. * (non-Javadoc)
  489. * @see org.mobicents.cluster.MobicentsCluster#addDataRemovalListener(org.mobicents.cluster.DataRemovalListener)
  490. */
  491. public boolean addDataRemovalListener(DataRemovalListener listener) {
  492. return dataRemovalListeners.putIfAbsent(listener.getBaseFqn(), listener) == null;
  493. }
  494. /*
  495. * (non-Javadoc)
  496. * @see org.mobicents.cluster.MobicentsCluster#removeDataRemovalListener(org.mobicents.cluster.DataRemovalListener)
  497. */
  498. public boolean removeDataRemovalListener(DataRemovalListener listener) {
  499. return dataRemovalListeners.remove(listener.getBaseFqn()) != null;
  500. }
  501. /*
  502. * (non-Javadoc)
  503. * @see org.mobicents.cluster.MobicentsCluster#getMobicentsCache()
  504. */
  505. public MobicentsCache getMobicentsCache() {
  506. return mobicentsCache;
  507. }
  508. /* (non-Javadoc)
  509. * @see org.mobicents.cluster.MobicentsCluster#getClusteredCacheDataIndexingHandler()
  510. */
  511. public ClusteredCacheDataIndexingHandler getClusteredCacheDataIndexingHandler() {
  512. return clusteredCacheDataIndexingHandler;
  513. }
  514. @Override
  515. public void startCluster() {
  516. synchronized (this) {
  517. if (started) {
  518. throw new IllegalStateException("cluster already started");
  519. }
  520. mobicentsCache.startCache();
  521. final Cache<?,?> cache = mobicentsCache.getJBossCache();
  522. if (!cache.getConfiguration().getCacheMode().equals(CacheMode.LOCAL)) {
  523. // get current cluster members
  524. currentView = new ArrayList<Address>(cache.getConfiguration().getRuntimeConfig().getChannel().getView().getMembers());
  525. // start listening to events
  526. cache.addCacheListener(this);
  527. Configuration conf=cache.getConfiguration();
  528. if(conf.getBuddyReplicationConfig()!=null && conf.getBuddyReplicationConfig().isEnabled())
  529. {
  530. //here we store our buddies in case we already have some
  531. //it will happen if cache started before MC cluster registers listener.
  532. if(conf.getRuntimeConfig().getBuddyGroup()!=null)
  533. {
  534. Node root = cache.getRoot();
  535. root.put(BUDDIES_STORE, conf.getRuntimeConfig().getBuddyGroup().getBuddies());
  536. }
  537. }
  538. }
  539. started = true;
  540. }
  541. }
  542. @Override
  543. public boolean isStarted() {
  544. synchronized (this) {
  545. return started;
  546. }
  547. }
  548. @Override
  549. public void stopCluster() {
  550. synchronized (this) {
  551. if (!started) {
  552. throw new IllegalStateException("cluster already started");
  553. }
  554. mobicentsCache.stopCache();
  555. started = false;
  556. }
  557. }
  558. }