1
16
17 package net.sf.ehcache.terracotta;
18
19 import java.util.Collection;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Set;
23 import java.util.concurrent.CopyOnWriteArrayList;
24
25 import net.sf.ehcache.CacheException;
26 import net.sf.ehcache.cluster.CacheCluster;
27 import net.sf.ehcache.cluster.ClusterNode;
28 import net.sf.ehcache.cluster.ClusterScheme;
29 import net.sf.ehcache.cluster.ClusterTopologyListener;
30
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34
41 public class TerracottaCacheCluster implements CacheCluster {
42
43 private static final Logger LOGGER = LoggerFactory.getLogger(TerracottaCacheCluster.class);
44 private final List<ClusterTopologyListener> listeners = new CopyOnWriteArrayList<ClusterTopologyListener>();
45 private volatile CacheCluster realCacheCluster;
46
47
52 public void setUnderlyingCacheCluster(CacheCluster newCacheCluster) {
53 if (newCacheCluster == null) {
54 throw new IllegalArgumentException("CacheCluster can't be null");
55 }
56 final CacheCluster oldRealCacheCluster = this.realCacheCluster;
57 this.realCacheCluster = newCacheCluster;
58 for (ClusterTopologyListener listener : listeners) {
59 this.realCacheCluster.addTopologyListener(listener);
60 }
61 if (oldRealCacheCluster != null) {
62 for (ClusterTopologyListener listener : listeners) {
63 oldRealCacheCluster.removeTopologyListener(listener);
64 }
65 }
66 }
67
68
75 void fireNodeRejoinedEvent(ClusterNode oldNode, ClusterNode newNode) {
76 Set<ClusterTopologyListener> firedToListeners = new HashSet<ClusterTopologyListener>();
77 for (ClusterTopologyListener listener : realCacheCluster.getTopologyListeners()) {
78 firedToListeners.add(listener);
79 fireRejoinEvent(oldNode, newNode, listener);
80 }
81 for (ClusterTopologyListener listener : listeners) {
82 if (firedToListeners.contains(listener)) {
83 continue;
84 }
85 fireRejoinEvent(oldNode, newNode, listener);
86 }
87 }
88
89 private void fireRejoinEvent(ClusterNode oldNode, ClusterNode newNode, ClusterTopologyListener listener) {
90 try {
91 listener.clusterRejoined(oldNode, newNode);
92 } catch (Throwable e) {
93 LOGGER.error("Caught exception while firing rejoin event", e);
94 }
95 }
96
97
100 public boolean addTopologyListener(ClusterTopologyListener listener) {
101 checkIfInitialized();
102 boolean added = realCacheCluster.addTopologyListener(listener);
103 if (added) {
104 listeners.add(listener);
105 }
106 return added;
107 }
108
109
112 public boolean removeTopologyListener(ClusterTopologyListener listener) {
113 checkIfInitialized();
114 boolean removed = realCacheCluster.removeTopologyListener(listener);
115 if (removed) {
116 listeners.remove(listener);
117 }
118 return removed;
119 }
120
121
124 public ClusterNode getCurrentNode() {
125 checkIfInitialized();
126 return realCacheCluster.getCurrentNode();
127 }
128
129
132 public Collection<ClusterNode> getNodes() {
133 checkIfInitialized();
134 return realCacheCluster.getNodes();
135 }
136
137
140 public ClusterScheme getScheme() {
141 checkIfInitialized();
142 return realCacheCluster.getScheme();
143 }
144
145
148 public boolean isClusterOnline() {
149 checkIfInitialized();
150 return realCacheCluster.isClusterOnline();
151 }
152
153
156 public ClusterNode waitUntilNodeJoinsCluster() {
157 checkIfInitialized();
158 return realCacheCluster.waitUntilNodeJoinsCluster();
159 }
160
161 private void checkIfInitialized() {
162 if (realCacheCluster == null) {
163 throw new CacheException(
164 "The underlying cache cluster has not been initialized. Probably the terracotta client has not been configured yet.");
165 }
166 }
167
168
171 public List<ClusterTopologyListener> getTopologyListeners() {
172 return this.listeners;
173 }
174
175 }
176