All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.ehcache.distribution.MulticastKeepaliveHeartbeatReceiver Maven / Gradle / Ivy

/**
 *  Copyright Terracotta, Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package net.sf.ehcache.distribution;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.rmi.RemoteException;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import net.sf.ehcache.CacheManager;
import net.sf.ehcache.util.NamedThreadFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Receives heartbeats from any {@link MulticastKeepaliveHeartbeatSender}s out there.
 * 

* Our own multicast heartbeats are ignored. * * @author Greg Luck * @version $Id: MulticastKeepaliveHeartbeatReceiver.java 5631 2012-05-10 08:31:33Z teck $ */ public final class MulticastKeepaliveHeartbeatReceiver { private static final Logger LOG = LoggerFactory.getLogger(MulticastKeepaliveHeartbeatReceiver.class.getName()); private ExecutorService processingThreadPool; private Set rmiUrlsProcessingQueue = Collections.synchronizedSet(new HashSet()); private final InetAddress groupMulticastAddress; private final Integer groupMulticastPort; private MulticastReceiverThread receiverThread; private MulticastSocket socket; private volatile boolean stopped; private final MulticastRMICacheManagerPeerProvider peerProvider; private InetAddress hostAddress; /** * Constructor. * * @param peerProvider * @param multicastAddress * @param multicastPort * @param hostAddress */ public MulticastKeepaliveHeartbeatReceiver( MulticastRMICacheManagerPeerProvider peerProvider, InetAddress multicastAddress, Integer multicastPort, InetAddress hostAddress) { this.peerProvider = peerProvider; this.groupMulticastAddress = multicastAddress; this.groupMulticastPort = multicastPort; this.hostAddress = hostAddress; } /** * Start. * * @throws IOException */ final void init() throws IOException { socket = new MulticastSocket(groupMulticastPort.intValue()); if (hostAddress != null) { socket.setInterface(hostAddress); } socket.joinGroup(groupMulticastAddress); receiverThread = new MulticastReceiverThread(); receiverThread.start(); processingThreadPool = Executors.newCachedThreadPool(new NamedThreadFactory("Multicast keep-alive Heartbeat Receiver")); } /** * Shutdown the heartbeat. */ public final void dispose() { LOG.debug("dispose called"); processingThreadPool.shutdownNow(); stopped = true; receiverThread.interrupt(); } /** * A multicast receiver which continously receives heartbeats. */ private final class MulticastReceiverThread extends Thread { /** * Constructor */ public MulticastReceiverThread() { super("Multicast Heartbeat Receiver Thread"); setDaemon(true); } @Override public final void run() { byte[] buf = new byte[PayloadUtil.MTU]; try { while (!stopped) { DatagramPacket packet = new DatagramPacket(buf, buf.length); try { socket.receive(packet); byte[] payload = packet.getData(); processPayload(payload); } catch (IOException e) { if (!stopped) { LOG.error("Error receiving heartbeat. " + e.getMessage() + ". Initial cause was " + e.getMessage(), e); } } } } catch (Throwable t) { LOG.error("Multicast receiver thread caught throwable. Cause was " + t.getMessage() + ". Continuing..."); } } private void processPayload(byte[] compressedPayload) { byte[] payload = PayloadUtil.ungzip(compressedPayload); String rmiUrls = new String(payload); if (self(rmiUrls)) { return; } rmiUrls = rmiUrls.trim(); LOG.debug("rmiUrls received {}", rmiUrls); processRmiUrls(rmiUrls); } /** * This method forks a new executor to process the received heartbeat in a thread pool. * That way each remote cache manager cannot interfere with others. *

* In the worst case, we have as many concurrent threads as remote cache managers. * * @param rmiUrls */ private void processRmiUrls(final String rmiUrls) { if (rmiUrlsProcessingQueue.contains(rmiUrls)) { LOG.debug("We are already processing these rmiUrls. Another heartbeat came before we finished: {}", rmiUrls); return; } if (processingThreadPool == null) { return; } processingThreadPool.execute(new Runnable() { public void run() { try { // Add the rmiUrls we are processing. rmiUrlsProcessingQueue.add(rmiUrls); for (StringTokenizer stringTokenizer = new StringTokenizer(rmiUrls, PayloadUtil.URL_DELIMITER); stringTokenizer.hasMoreTokens();) { if (stopped) { return; } String rmiUrl = stringTokenizer.nextToken(); registerNotification(rmiUrl); if (!peerProvider.peerUrls.containsKey(rmiUrl)) { LOG.debug("Aborting processing of rmiUrls since failed to add rmiUrl: {}", rmiUrl); return; } } } finally { // Remove the rmiUrls we just processed rmiUrlsProcessingQueue.remove(rmiUrls); } } }); } /** * @param rmiUrls * @return true if our own hostname and listener port are found in the list. This then means we have * caught our onw multicast, and should be ignored. */ private boolean self(String rmiUrls) { CacheManager cacheManager = peerProvider.getCacheManager(); CacheManagerPeerListener cacheManagerPeerListener = cacheManager.getCachePeerListener("RMI"); if (cacheManagerPeerListener == null) { return false; } List boundCachePeers = cacheManagerPeerListener.getBoundCachePeers(); if (boundCachePeers == null || boundCachePeers.size() == 0) { return false; } CachePeer peer = (CachePeer) boundCachePeers.get(0); try { String cacheManagerUrlBase = peer.getUrlBase(); int baseUrlMatch = rmiUrls.indexOf(cacheManagerUrlBase); return baseUrlMatch != -1; } catch (RemoteException e) { LOG.error("Error geting url base", e); return false; } } private void registerNotification(String rmiUrl) { peerProvider.registerPeer(rmiUrl); } /** * {@inheritDoc} */ @Override public final void interrupt() { try { socket.leaveGroup(groupMulticastAddress); } catch (IOException e) { LOG.error("Error leaving group"); } socket.close(); super.interrupt(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy