/* * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.distributed.internal.membership.gms; import org.apache.geode.CancelCriterion; import org.apache.geode.ForcedDisconnectException; import org.apache.geode.distributed.DistributedSystemDisconnectedException; import org.apache.geode.distributed.internal.DMStats; import org.apache.geode.distributed.internal.DistributionConfig; import org.apache.geode.distributed.internal.InternalLocator; import org.apache.geode.distributed.internal.membership.DistributedMembershipListener; import org.apache.geode.distributed.internal.membership.InternalDistributedMember; import org.apache.geode.distributed.internal.membership.MembershipManager; import org.apache.geode.distributed.internal.membership.NetView; import org.apache.geode.distributed.internal.membership.gms.auth.GMSAuthenticator; import org.apache.geode.distributed.internal.membership.gms.fd.GMSHealthMonitor; import org.apache.geode.distributed.internal.membership.gms.interfaces.*; import org.apache.geode.distributed.internal.membership.gms.locator.GMSLocator; import org.apache.geode.distributed.internal.membership.gms.membership.GMSJoinLeave; import org.apache.geode.distributed.internal.membership.gms.messenger.JGroupsMessenger; import org.apache.geode.distributed.internal.membership.gms.mgr.GMSMembershipManager; import org.apache.geode.internal.admin.remote.RemoteTransportConfig; import org.apache.geode.internal.logging.InternalLogWriter; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.LoggingThreadGroup; import org.apache.geode.security.AuthenticationFailedException; import org.apache.logging.log4j.Logger; import java.util.Timer; @SuppressWarnings("ConstantConditions") public class Services { private static final Logger logger = LogService.getLogger(); private static final ThreadGroup threadGroup = LoggingThreadGroup.createThreadGroup("GemFire Membership", logger); private static InternalLogWriter staticLogWriter; private static InternalLogWriter staticSecurityLogWriter; final private Manager manager; final private JoinLeave joinLeave; private Locator locator; final private HealthMonitor healthMon; final private Messenger messenger; final private Authenticator auth; final private ServiceConfig config; final private DMStats stats; final private Stopper cancelCriterion; private volatile boolean stopping; private volatile boolean stopped; private volatile Exception shutdownCause; private InternalLogWriter logWriter; private InternalLogWriter securityLogWriter; private final Timer timer = new Timer("Geode Membership Timer", true); /** * A common logger for membership classes */ public static Logger getLogger() { return logger; } /** * The thread group for all membership threads */ public static ThreadGroup getThreadGroup() { return threadGroup; } /** * a timer used for membership tasks */ public Timer getTimer() { return this.timer; } public boolean isStopped() { return this.stopped; } /** * for testing only - create a non-functional Services object with a Stopper */ public Services() { this.cancelCriterion = new Stopper(); this.stats = null; this.config = null; this.manager = null; this.joinLeave = null; this.healthMon = null; this.messenger = null; this.auth = null; } public Services(DistributedMembershipListener listener, DistributionConfig config, RemoteTransportConfig transport, DMStats stats) { this.cancelCriterion = new Stopper(); this.stats = stats; this.config = new ServiceConfig(transport, config); this.manager = new GMSMembershipManager(listener); this.joinLeave = new GMSJoinLeave(); this.healthMon = new GMSHealthMonitor(); this.messenger = new JGroupsMessenger(); this.auth = new GMSAuthenticator(); } protected void init() { // InternalDistributedSystem establishes this log writer at boot time // TODO fix this so that IDS doesn't know about Services securityLogWriter = staticSecurityLogWriter; staticSecurityLogWriter = null; logWriter = staticLogWriter; staticLogWriter = null; this.auth.init(this); this.messenger.init(this); this.manager.init(this); this.joinLeave.init(this); this.healthMon.init(this); InternalLocator l = (InternalLocator) org.apache.geode.distributed.Locator.getLocator(); if (l != null && l.getLocatorHandler() != null) { if (l.getLocatorHandler().setMembershipManager((MembershipManager) this.manager)) { this.locator = (Locator) l.getLocatorHandler(); } } } protected void start() { boolean started = false; try { logger.info("Starting membership services"); logger.debug("starting Authenticator"); this.auth.start(); logger.debug("starting Messenger"); this.messenger.start(); logger.debug("starting JoinLeave"); this.joinLeave.start(); logger.debug("starting HealthMonitor"); this.healthMon.start(); logger.debug("starting Manager"); this.manager.start(); started = true; } catch (RuntimeException e) { logger.fatal("Unexpected exception while booting membership services", e); throw e; } finally { if (!started) { this.manager.stop(); this.healthMon.stop(); this.joinLeave.stop(); this.messenger.stop(); this.auth.stop(); this.timer.cancel(); } } this.auth.started(); this.messenger.started(); this.joinLeave.started(); this.healthMon.started(); this.manager.started(); logger.debug("All membership services have been started"); try { this.manager.joinDistributedSystem(); } catch (Throwable e) { stop(); throw e; } } public void emergencyClose() { if (stopping) { return; } stopping = true; logger.info("Stopping membership services"); timer.cancel(); try { joinLeave.emergencyClose(); } finally { try { healthMon.emergencyClose(); } finally { try { auth.emergencyClose(); } finally { try { messenger.emergencyClose(); } finally { try { manager.emergencyClose(); } finally { cancelCriterion.cancel("Membership services are shut down"); stopped = true; } } } } } } public void stop() { if (stopping) { return; } logger.info("Stopping membership services"); stopping = true; try { timer.cancel(); } finally { try { joinLeave.stop(); } finally { try { healthMon.stop(); } finally { try { auth.stop(); } finally { try { messenger.stop(); } finally { try { manager.stop(); } finally { cancelCriterion.cancel("Membership services are shut down"); stopped = true; } } } } } } } public static void setLogWriter(InternalLogWriter writer) { staticLogWriter = writer; } public static void setSecurityLogWriter(InternalLogWriter securityWriter) { staticSecurityLogWriter = securityWriter; } public InternalLogWriter getLogWriter() { return this.logWriter; } public InternalLogWriter getSecurityLogWriter() { return this.securityLogWriter; } public Authenticator getAuthenticator() { return auth; } public void installView(NetView v) { try { auth.installView(v); } catch (AuthenticationFailedException e) { return; } if (locator != null) { locator.installView(v); } healthMon.installView(v); messenger.installView(v); manager.installView(v); } public void memberSuspected(InternalDistributedMember initiator, InternalDistributedMember suspect, String reason) { try { joinLeave.memberSuspected(initiator, suspect, reason); } finally { try { healthMon.memberSuspected(initiator, suspect, reason); } finally { try { auth.memberSuspected(initiator, suspect, reason); } finally { try { messenger.memberSuspected(initiator, suspect, reason); } finally { manager.memberSuspected(initiator, suspect, reason); } } } } } public Manager getManager() { return manager; } public Locator getLocator() { return locator; } public void setLocator(Locator locator) { this.locator = locator; } public JoinLeave getJoinLeave() { return joinLeave; } public HealthMonitor getHealthMonitor() { return healthMon; } public ServiceConfig getConfig() { return this.config; } public Messenger getMessenger() { return this.messenger; } public DMStats getStatistics() { return this.stats; } public Stopper getCancelCriterion() { return this.cancelCriterion; } public void setShutdownCause(Exception e) { this.shutdownCause = e; } public Exception getShutdownCause() { return shutdownCause; } public boolean isShutdownDueToForcedDisconnect() { return shutdownCause instanceof ForcedDisconnectException; } public boolean isAutoReconnectEnabled() { return !getConfig().getDistributionConfig().getDisableAutoReconnect(); } public byte[] getPublicKey(InternalDistributedMember mbr) { if (locator != null) { return ((GMSLocator) locator).getPublicKey(mbr); } return null; } public class Stopper extends CancelCriterion { volatile String reasonForStopping = null; public void cancel(String reason) { this.reasonForStopping = reason; } @Override public String cancelInProgress() { if (Services.this.shutdownCause != null) return Services.this.shutdownCause.toString(); return reasonForStopping; } @Override public RuntimeException generateCancelledException(Throwable e) { String reason = cancelInProgress(); if (reason == null) { return null; } else { if (e == null) { return new DistributedSystemDisconnectedException(reason); } else { return new DistributedSystemDisconnectedException(reason, e); } } } } }