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

org.eclipse.persistence.sessions.coordination.DiscoveryManager Maven / Gradle / Ivy

There is a newer version: 5.0.0-B03
Show newest version
/*
 * Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.sessions.coordination;

import java.net.*;
import java.io.IOException;
import org.eclipse.persistence.exceptions.DiscoveryException;
import org.eclipse.persistence.internal.sessions.coordination.*;
import org.eclipse.persistence.sessions.SessionProfiler;

/**
 * 

* Purpose: Detects new members of a logical EclipseLink cluster. *

* Description: Each RemoteCommandManager has its own DiscoveryManager, * which handles the detection of other remote command services as they become available. * The DiscoveryManager is an active object (in that it extends Thread) and becomes * a separate thread when it is started using startDiscovery(). *

* Discovery is done through the use of a multicast. Each discovery manager * joins the multicast group and announces itself to the group. As it receives * service announcements from other discovery managers it notifies the RCM to * establish connections to and from the new service. * * @see RemoteCommandManager * @see java.net.MulticastSocket * @author Steven Vo * @since OracleAS TopLink 10g (9.0.4) */ public class DiscoveryManager implements Runnable { /** Default value constants */ public static final String DEFAULT_MULTICAST_GROUP = "226.10.12.64"; public static final int DEFAULT_MULTICAST_PORT = 3121; public static final int DEFAULT_PACKET_TIME_TO_LIVE = 2; public static final int DEFAULT_ANNOUNCEMENT_DELAY = 1000; /** Defines the IP address of the multicast group */ protected String multicastGroupAddress = DEFAULT_MULTICAST_GROUP; /** Defines the port the multicast socket will be using */ protected int multicastPort = DEFAULT_MULTICAST_PORT; /** The multicast socket used for discovery */ protected MulticastSocket communicationSocket; /** * Number of hops in the life of the datapacket * Default is 2, a hub and an interface card to prevent the data packets from leaving the localnetwork. */ protected int packetTimeToLive = DEFAULT_PACKET_TIME_TO_LIVE; /** Indicates to the listening thread that it should stop */ protected boolean stopListening = false; /** Delay time in millis between initialization and when the announcement is sent */ protected int announcementDelay = DEFAULT_ANNOUNCEMENT_DELAY; /** The remote command manager responsible for this service */ protected RemoteCommandManager rcm; /** * Constructors to create a discovery manager. */ public DiscoveryManager(RemoteCommandManager mgr) { this.rcm = mgr; } public DiscoveryManager(String address, int port, RemoteCommandManager mgr) { this(mgr); this.multicastGroupAddress = address; this.multicastPort = port; } public DiscoveryManager(String address, int port, int delay, RemoteCommandManager mgr) { this(address, port, mgr); this.announcementDelay = delay; } /** * INTERNAL: * Send out an announcement that we are here. */ public void announceSession() { rcm.logDebug("sending_announcement", null); ServiceAnnouncement outMsg = new ServiceAnnouncement(rcm.getServiceId()); byte[] outBytes = outMsg.toBytes(); try { // Create a packet to send and send it out to everyone listening DatagramPacket sendPacket = new DatagramPacket(outBytes, outBytes.length, InetAddress.getByName(multicastGroupAddress), multicastPort); getCommunicationSocket().send(sendPacket); Object[] args = null; rcm.logInfo("announcement_sent", args); } catch (Exception ex) { // We got an exception. Map it to an RCM exception and call the handler DiscoveryException discoveryEx = DiscoveryException.errorSendingAnnouncement(ex); rcm.handleException(discoveryEx); } } /** * ADVANCED: * Announce the local service and join the cluster */ public void startDiscovery() { this.rcm.getCommandProcessor().updateProfile(SessionProfiler.RcmStatus, "Started"); // Only start if we are currently stopped if (this.isDiscoveryStopped()) { this.rcm.getServerPlatform().launchContainerRunnable(this); } } /** * ADVANCED: * Stop accepting announcements from other services becoming available. * Note that this does not remove the local service from the cluster. */ public void stopDiscovery() { this.rcm.getCommandProcessor().updateProfile(SessionProfiler.RcmStatus, "Stopped"); stopListening(); try { // Put in a sleep to give the listener thread a chance to stop Thread.sleep(500); } catch (InterruptedException exception) { } this.communicationSocket = null; } /** * ADVANCED: * Return true if discovery has been stopped at the time this method is called. * If false is returned then it is undefined whether discovery is started or * stopped. It may be started, or it may be in the process of starting or * stopping. */ public boolean isDiscoveryStopped() { return (communicationSocket == null); } /** * INTERNAL: * Create the multicast socket and join the multicast group. */ public void createCommunicationSocket() { Object[] args = { multicastGroupAddress, "" + multicastPort }; rcm.logDebug("initializing_discovery_resources", args); if (communicationSocket == null) { try { communicationSocket = new MulticastSocket(multicastPort); communicationSocket.setTimeToLive(getPacketTimeToLive()); communicationSocket.joinGroup(InetAddress.getByName(multicastGroupAddress)); } catch (IOException ex) { // Either we couldn't create the socket or we couldn't join the group DiscoveryException discoveryEx = DiscoveryException.errorJoiningMulticastGroup(ex); rcm.handleException(discoveryEx); } } } /** * INTERNAL: * Return the socket that will be used for the multicast. */ public MulticastSocket getCommunicationSocket() { return communicationSocket; } /** * INTERNAL: * This is the main execution method of discovery. It will create a socket to * listen on, create a local connection for this service and announce that we are * open for business. */ @Override public void run() { //Initialize the communication socket createCommunicationSocket(); // Create the local connection from which we will receive commands rcm.getTransportManager().createLocalConnection(); // Announce to all other discovery managers that this service is up. The // delay allows time for posting of connections to the name service try { Thread.sleep(announcementDelay); } catch (InterruptedException exception) { } announceSession(); // Listen for other sessions that are joining startListening(); } /** * INTERNAL: * This method puts us into the listening mode loop. This thread blocks, waiting * on announcements that we receive from other discovery managers. */ public void startListening() { byte[] recvBuf = new byte[128]; // Only stop when we get the directive to stop stopListening = false; rcm.logInfo("discovery_manager_active", null); while (!stopListening) { DatagramPacket recvPacket = new DatagramPacket(recvBuf, recvBuf.length); ServiceAnnouncement inMsg; // Block waiting for a message try { getCommunicationSocket().receive(recvPacket); } catch (IOException exception) { if (stopListening) { // We caused the exception by closing the socket rcm.logInfo("discovery_manager_stopped", null); return; } else { // Exception was caused by something else (e.g. network error, etc.) rcm.handleException(DiscoveryException.errorReceivingAnnouncement(exception)); } } // We received a message, unmarshall it into an announcement try { inMsg = new ServiceAnnouncement(recvPacket.getData()); } catch (Exception ex) { // Log a warning that we couldn't process the announcement Object[] args = { ex }; rcm.logWarning("received_corrupt_announcement", args); continue; } // If the msg is not from ourselves, and is announcing a service on // the same channel as we are on then we should do something about it if (!rcm.getServiceId().getId().equals(inMsg.getServiceId().getId()) && (rcm.getServiceId().getChannel().equalsIgnoreCase(inMsg.getServiceId().getChannel()))) { receivedAnnouncement(inMsg.getServiceId()); } } } /** * INTERNAL: * Signal this instance to stop listening. */ public void stopListening() { this.stopListening = true; if (getCommunicationSocket() != null) { getCommunicationSocket().close(); } } /** * INTERNAL: * Process the announcement that indicates that a new service is online */ public void receivedAnnouncement(ServiceId serviceId) { Object[] args = { serviceId }; rcm.logInfo("announcement_received", args); // Notify the RCM that a new service has been detected rcm.newServiceDiscovered(serviceId); } /** * PUBLIC: * Set the amount of time in millis that the service should wait between the time * that this Remote Service is available and a session announcement is sent out * to other discovery managers. This may be needed to give some systems more time * to post their connections into the naming service. Takes effect the next time * listening is started. */ public void setAnnouncementDelay(int millisecondsToDelay) { announcementDelay = millisecondsToDelay; } /** * PUBLIC: * Return the amount of time in millis that the service should wait between the time * that this Remote Service is available and a session announcement is sent out * to other discovery managers. */ public int getAnnouncementDelay() { return announcementDelay; } /** * PUBLIC: * Return the host address of the multicast group. */ public String getMulticastGroupAddress() { return (multicastGroupAddress); } /** * PUBLIC: * Set the host address of the multicast group. Takes effect the next time * listening is started. */ public void setMulticastGroupAddress(String address) { this.multicastGroupAddress = address; } /** * PUBLIC: * Set the multicast port used for discovery. Takes effect the next time * listening is started. */ public void setMulticastPort(int port) { this.multicastPort = port; } /** * PUBLIC: * Return the multicast port used for discovery. */ public int getMulticastPort() { return (multicastPort); } /** * INTERNAL: invoke when the RCM shutdown. Subclass overrides this method if necessary. */ protected void shallowCopy(DiscoveryManager dmgr) { this.multicastGroupAddress = dmgr.multicastGroupAddress; this.multicastPort = dmgr.multicastPort; this.announcementDelay = dmgr.announcementDelay; this.rcm = dmgr.rcm; } /** * PUBLIC: * Returns the number of hops the data packets of the session announcement will take before expiring. * The default is 2, a hub and an interface card to prevent the data packets from leaving the local network. */ public int getPacketTimeToLive() { return this.packetTimeToLive; } /** * PUBLIC: * Set the number of hops the data packets of the session announcement will take before expiring. * The default is 2, a hub and an interface card to prevent the data packets from leaving the local network. * * Note that if sessions are hosted on different LANs that are part of WAN, the announcement sending by one session * may not reach other sessions. In this case, consult your network administrator for the right time-to-live value * or test your network by increase the value until sessions receive announcement sent by others. */ public void setPacketTimeToLive(int newPacketTimeToLive) { this.packetTimeToLive = newPacketTimeToLive; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy