/** * Starts the Listener so it's actively listening for election results and broadcasts of * replication group changes. * * <p>The Monitor must have been previously registered with the replication group via the <code> * register()</code> method so that other nodes in the group are aware of it and can keep it * current. If the monitor has not been registered, it will not be updated, that is, its listener * will not be invoked. The registration needs to be done exactly once. * * <p>Once the registration has been completed, the Monitor can start listening even when none of * the other nodes in the group are available. It will be contacted automatically by the other * nodes when they come up and hold a successful election. * * <p>Invoking <code>startListener</code> results in a synchronous callback to the application via * the {@link MonitorChangeListener#notify(NewMasterEvent)} method, if there is a current Master. * If there is no Master at this time then the callback takes place asynchronously, after the * method returns, when a Master is eventually elected. * * @param newListener the listener used to monitor events of interest. * @throws EnvironmentFailureException if an unexpected, internal or environment-wide failure * occurs. * @throws IOException if the monitor socket could not be set up * @throws IllegalArgumentException if an invalid parameter is specified. * @throws IllegalStateException if the monitor has been shutdown, or a listener has already been * established. */ public void startListener(MonitorChangeListener newListener) throws DatabaseException, IOException { if (shutdown.get()) { throw new IllegalStateException("The monitor has been shutdown"); } if (newListener == null) { throw new IllegalArgumentException( "A MonitorChangeListener must be associated with " + " this Monitor when invoking this method"); } if (this.monitorChangeListener != null) { throw new IllegalStateException("A Listener has already been established"); } this.monitorChangeListener = newListener; serviceDispatcher = new ServiceDispatcher(monitorConfig.getNodeSocketAddress()); serviceDispatcher.start(); Protocol electionProtocol = new Protocol( TimebasedProposalGenerator.getParser(), MasterValue.getParser(), monitorConfig.getGroupName(), nameIdPair, null); learner = new Learner(electionProtocol, serviceDispatcher, nameIdPair); serviceDispatcher.register(new MonitorService(this, serviceDispatcher)); masterChangeListener = new MasterChangeListener(); learner.addListener(masterChangeListener); learner.start(); try { /* Notify the listener about the current master. */ final ReplicationGroup repGroup = repGroupAdmin.getGroup(); final RepGroupImpl group = RepInternal.getRepGroupImpl(repGroup); /* * In the absence of a network failure, the query should result in * a call to the notify method of MonitorChanegListener. */ learner.queryForMaster(group.getLearnerSockets()); /* Notify JoinGroupEvents for those current active nodes. */ notifyJoinGroupEventsForActiveNodes(repGroup); } catch (UnknownMasterException ume) { /* The Listener will be informed when a Master is elected. */ LoggerUtils.logMsg(logger, formatter, Level.INFO, "No current master."); } }
/** * Release monitor resources and shut down the monitor. * * @throws InterruptedException */ public synchronized void shutdown() throws InterruptedException { boolean changed = shutdown.compareAndSet(false, true); if (!changed) { return; } LoggerUtils.logMsg(logger, formatter, Level.INFO, "Shutting down monitor " + nameIdPair); if (learner != null) { learner.shutdown(); } if (serviceDispatcher != null) { serviceDispatcher.shutdown(); } }