1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package net.sf.ehcache.distribution;
18
19 import net.sf.ehcache.CacheManager;
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22
23 import java.io.IOException;
24 import java.net.DatagramPacket;
25 import java.net.InetAddress;
26 import java.net.MulticastSocket;
27 import java.rmi.RemoteException;
28 import java.util.Set;
29 import java.util.Collections;
30 import java.util.HashSet;
31 import java.util.StringTokenizer;
32 import java.util.List;
33
34 import edu.emory.mathcs.backport.java.util.concurrent.ExecutorService;
35 import edu.emory.mathcs.backport.java.util.concurrent.Executors;
36
37
38
39
40
41
42
43
44
45 public final class MulticastKeepaliveHeartbeatReceiver {
46 private static final Log LOG = LogFactory.getLog(MulticastKeepaliveHeartbeatReceiver.class.getName());
47
48 private ExecutorService processingThreadPool;
49 private Set rmiUrlsProcessingQueue = Collections.synchronizedSet(new HashSet());
50 private final InetAddress groupMulticastAddress;
51 private final Integer groupMulticastPort;
52 private MulticastReceiverThread receiverThread;
53 private MulticastSocket socket;
54 private boolean stopped;
55 private final MulticastRMICacheManagerPeerProvider peerProvider;
56
57
58
59
60
61
62
63
64 public MulticastKeepaliveHeartbeatReceiver(
65 MulticastRMICacheManagerPeerProvider peerProvider, InetAddress multicastAddress, Integer multicastPort) {
66 this.peerProvider = peerProvider;
67 this.groupMulticastAddress = multicastAddress;
68 this.groupMulticastPort = multicastPort;
69 }
70
71
72
73
74
75
76 final void init() throws IOException {
77 socket = new MulticastSocket(groupMulticastPort.intValue());
78 socket.joinGroup(groupMulticastAddress);
79 receiverThread = new MulticastReceiverThread();
80 receiverThread.start();
81 processingThreadPool = Executors.newCachedThreadPool();
82 }
83
84
85
86
87 public final void dispose() {
88 LOG.debug("dispose called");
89 processingThreadPool.shutdownNow();
90 stopped = true;
91 receiverThread.interrupt();
92 }
93
94
95
96
97 private final class MulticastReceiverThread extends Thread {
98
99
100
101
102 public MulticastReceiverThread() {
103 super("Multicast Heartbeat Receiver Thread");
104 setDaemon(true);
105 }
106
107 public final void run() {
108 byte[] buf = new byte[PayloadUtil.MTU];
109 try {
110 while (!stopped) {
111 DatagramPacket packet = new DatagramPacket(buf, buf.length);
112 try {
113 socket.receive(packet);
114 byte[] payload = packet.getData();
115 processPayload(payload);
116
117
118 } catch (IOException e) {
119 if (!stopped) {
120 LOG.error("Error receiving heartbeat. " + e.getMessage() +
121 ". Initial cause was " + e.getMessage(), e);
122 }
123 }
124 }
125 } catch (Throwable t) {
126 LOG.error("Multicast receiver thread caught throwable. Cause was " + t.getMessage() + ". Continuing...");
127 }
128 }
129
130 private void processPayload(byte[] compressedPayload) {
131 byte[] payload = PayloadUtil.ungzip(compressedPayload);
132 String rmiUrls = new String(payload);
133 if (self(rmiUrls)) {
134 return;
135 }
136 rmiUrls = rmiUrls.trim();
137 if (LOG.isTraceEnabled()) {
138 LOG.trace("rmiUrls received " + rmiUrls);
139 }
140 processRmiUrls(rmiUrls);
141 }
142
143
144
145
146
147
148
149
150
151 private void processRmiUrls(final String rmiUrls) {
152 if (rmiUrlsProcessingQueue.contains(rmiUrls)) {
153 if (LOG.isDebugEnabled()) {
154 LOG.debug("We are already processing these rmiUrls. Another heartbeat came before we finished: " + rmiUrls);
155 }
156 return;
157 }
158
159 processingThreadPool.execute(new Runnable() {
160 public void run() {
161 try {
162
163 rmiUrlsProcessingQueue.add(rmiUrls);
164 for (StringTokenizer stringTokenizer = new StringTokenizer(rmiUrls,
165 PayloadUtil.URL_DELIMITER); stringTokenizer.hasMoreTokens();) {
166 if (stopped) {
167 return;
168 }
169 String rmiUrl = stringTokenizer.nextToken();
170 registerNotification(rmiUrl);
171 if (!peerProvider.peerUrls.containsKey(rmiUrl)) {
172 if (LOG.isDebugEnabled()) {
173 LOG.debug("Aborting processing of rmiUrls since failed to add rmiUrl: " + rmiUrl);
174 }
175 return;
176 }
177 }
178 } finally {
179
180 rmiUrlsProcessingQueue.remove(rmiUrls);
181 }
182 }
183 });
184 }
185
186
187
188
189
190
191
192 private boolean self(String rmiUrls) {
193 CacheManager cacheManager = peerProvider.getCacheManager();
194 CacheManagerPeerListener cacheManagerPeerListener = cacheManager.getCachePeerListener();
195 if (cacheManagerPeerListener == null) {
196 return false;
197 }
198 List boundCachePeers = cacheManagerPeerListener.getBoundCachePeers();
199 if (boundCachePeers == null || boundCachePeers.size() == 0) {
200 return false;
201 }
202 CachePeer peer = (CachePeer) boundCachePeers.get(0);
203 String cacheManagerUrlBase = null;
204 try {
205 cacheManagerUrlBase = peer.getUrlBase();
206 } catch (RemoteException e) {
207 LOG.error("Error geting url base");
208 }
209 int baseUrlMatch = rmiUrls.indexOf(cacheManagerUrlBase);
210 return baseUrlMatch != -1;
211 }
212
213 private void registerNotification(String rmiUrl) {
214 peerProvider.registerPeer(rmiUrl);
215 }
216
217
218
219
220
221 public final void interrupt() {
222 try {
223 socket.leaveGroup(groupMulticastAddress);
224 } catch (IOException e) {
225 LOG.error("Error leaving group");
226 }
227 socket.close();
228 super.interrupt();
229 }
230 }
231
232
233 }