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

com.gemstone.gemfire.admin.jmx.internal.AgentImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * 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. See accompanying
 * LICENSE file.
 */
package com.gemstone.gemfire.admin.jmx.internal;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.OperationsException;
import javax.management.ReflectionException;
import javax.management.modelmbean.ModelMBean;
import javax.management.remote.JMXConnectionNotification;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnectorServer;
import javax.rmi.ssl.SslRMIClientSocketFactory;

import com.gemstone.gemfire.GemFireException;
import com.gemstone.gemfire.GemFireIOException;
import com.gemstone.gemfire.LogWriter;
import com.gemstone.gemfire.SystemFailure;
import com.gemstone.gemfire.admin.AdminDistributedSystem;
import com.gemstone.gemfire.admin.AdminException;
import com.gemstone.gemfire.admin.jmx.Agent;
import com.gemstone.gemfire.admin.jmx.AgentConfig;
import com.gemstone.gemfire.admin.jmx.AgentFactory;
import com.gemstone.gemfire.distributed.internal.DistributionManager;
import com.gemstone.gemfire.i18n.LogWriterI18n;
import com.gemstone.gemfire.internal.Banner;
import com.gemstone.gemfire.internal.ClassPathLoader;
import com.gemstone.gemfire.internal.GemFireVersion;
import com.gemstone.gemfire.internal.LogWriterImpl;
import com.gemstone.gemfire.internal.ManagerLogWriter;
import com.gemstone.gemfire.internal.admin.remote.TailLogResponse;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import com.gemstone.gemfire.internal.util.IOUtils;

import com.gemstone.org.jgroups.util.StringId;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

import mx4j.tools.adaptor.http.HttpAdaptor;

/**
 * The GemFire JMX Agent provides the ability to administrate one GemFire
 * distributed system via JMX.
 *
 * @author    Kirk Lund
 * @author    David Whitlock
 * @since     3.5
 */
public class AgentImpl
implements com.gemstone.gemfire.admin.jmx.Agent,
           com.gemstone.gemfire.admin.jmx.internal.ManagedResource {

  /**
   * MX4J HttpAdaptor only supports "basic" as an authentication method.
   * Enabling HttpAdaptor authentication ({@link
   * AgentConfig#HTTP_AUTHENTICATION_ENABLED_NAME}) causes the browser to
   * require a login with username ({@link
   * AgentConfig#HTTP_AUTHENTICATION_USER_NAME}) and password ({@link
   * AgentConfig#HTTP_AUTHENTICATION_PASSWORD_NAME}).
   */
  private static final String MX4J_HTTPADAPTOR_BASIC_AUTHENTICATION = "basic";

  /** JMX Service URL template for JMX/RMI Connector Server */
  private static final String JMX_SERVICE_URL =
                              "service:jmx:rmi://{0}:{1}/jndi/rmi://{2}:{3}{4}";
  
  private static boolean isGemFireXD = false;

  /**
   * Set third-party logging configration: MX4J, Jakarta Commons-Logging.
   */
  static {
    checkDebug();
    String commonsLog = System.getProperty("org.apache.commons.logging.log");
    if (commonsLog == null || commonsLog.length() == 0) {
      System.setProperty("org.apache.commons.logging.log",
                         "org.apache.commons.logging.impl.SimpleLog");
    }

    try {
      ClassPathLoader.getLatest().forName(
          "com.pivotal.gemfirexd.internal.GemFireXDVersion");
      isGemFireXD = true;
    } catch (ClassNotFoundException e) {
      isGemFireXD = false;
    } finally {
      System.setProperty("isSqlFire", String.valueOf(isGemFireXD));
    }
  }

  /** Enables mx4j tracing if Agent debugging is enabled. */
  private static void checkDebug() {
    try {
      if (Boolean.getBoolean("gfAgentDebug")) {
        mx4j.log.Log.setDefaultPriority(mx4j.log.Logger.TRACE); // .DEBUG
      }
    }
    catch (Throwable t) {
      Error err;
      if (t instanceof Error && SystemFailure.isJVMFailureError(
          err = (Error)t)) {
        SystemFailure.initiateFailure(err);
        // If this ever returns, rethrow the error. We're poisoned
        // now, so don't let this thread continue.
        throw err;
      }
      // Whenever you catch Error or Throwable, you must also
      // check for fatal JVM error (see above).  However, there is
      // _still_ a possibility that you are dealing with a cascading
      // error condition, so you also need to check to see if the JVM
      // is still usable:
      SystemFailure.checkFailure();
      /*ignore*/
      }
  }

  // -------------------------------------------------------------------------
  //   Member variables
  // -------------------------------------------------------------------------

  /** This Agent's log writer */
  private ManagerLogWriter logWriter;
  private FileOutputStream logFileOutputStream;

  /** This Agent's JMX http adaptor from MX4J */
  private HttpAdaptor httpAdaptor;

  /** This Agent's RMI Connector Server from MX4J */
  private JMXConnectorServer rmiConnector;

  /** The name of the MBean manages this resource */
  private final String mbeanName;

  /** The ObjectName of the MBean that manages this resource */
  private final ObjectName objectName;

  /** The actual ModelMBean that manages this resource */
  private ModelMBean modelMBean;

  /** The configuration for this Agent */
  private final AgentConfigImpl agentConfig;

  /** The AdminDistributedSystem this Agent is currently
   * connected to or null */
  private AdminDistributedSystem system;

  /** The agent's configuration file */
  private String propertyFile;

  /** Set to non-null if a local log file is opened on startup */
  private LogConfigImpl logConfig;

  /** A lock object to guard the Connect and Disconnect calls being
    * made on the agent for connections to the DS **/
  private final Object CONN_SYNC = new Object();

  protected MemberInfoWithStatsMBean memberInfoWithStatsMBean;

  private MBeanServer mBeanServer;

  // -------------------------------------------------------------------------
  //   Constructor(s)
  // -------------------------------------------------------------------------

  /**
   * Constructs a new Agent using the specified configuration.
   *
   * @param agentConfig instance of configuration for Agent
   * @throws com.gemstone.gemfire.admin.AdminException TODO-javadocs
   * @throws IllegalArgumentException if agentConfig is null
   */
  public AgentImpl(AgentConfig agentConfig)
    throws AdminException, IllegalArgumentException {
    addShutdownHook();
    if (agentConfig == null) {
      throw new IllegalArgumentException(LocalizedStrings.AgentImpl_AGENTCONFIG_MUST_NOT_BE_NULL.toLocalizedString());
    }
    this.agentConfig = (AgentConfigImpl)agentConfig;
    this.mbeanName   = MBEAN_NAME_PREFIX + MBeanUtil.makeCompliantMBeanNameProperty("Agent");

    try {
      this.objectName = new ObjectName(this.mbeanName);
    } catch (MalformedObjectNameException ex) {
      String s = LocalizedStrings.AgentImpl_WHILE_CREATING_OBJECTNAME_0.toLocalizedString(new Object[] { this.mbeanName });
      throw new AdminException(s, ex);
    }

    this.propertyFile = this.agentConfig.getPropertyFile().getAbsolutePath();

    // bind address only affects how the Agent VM connects to the system...
    // It should be set only once in the agent lifecycle
    this.agentConfig.setBindAddress(getBindAddress());

    // init the logger
    initLogWriter();

    mBeanServer = MBeanUtil.start();

    MBeanUtil.createMBean(this);

    initializeHelperMbean();
  }

  private void initializeHelperMbean() {
    try {
      memberInfoWithStatsMBean = new MemberInfoWithStatsMBean(this);

      MBeanServer mbs = getMBeanServer();
      mbs.registerMBean(memberInfoWithStatsMBean, memberInfoWithStatsMBean.getObjectName());
      /*
       * We are not re-throwing these exceptions as failure create/register the
       * GemFireTypesWrapper will not stop the Agent from working. But we are
       * logging it as it could be an indication of some problem.
       * Also not creating Localized String for the exception.
       */
    } catch (OperationsException e) {
      getLogWriterI18n().info(LocalizedStrings.AgentImpl_FAILED_TO_INITIALIZE_MEMBERINFOWITHSTATSMBEAN, e);
    } catch (MBeanRegistrationException e) {
      getLogWriterI18n().info(LocalizedStrings.AgentImpl_FAILED_TO_INITIALIZE_MEMBERINFOWITHSTATSMBEAN, e);
    } catch (AdminException e) {
      getLogWriterI18n().info(LocalizedStrings.AgentImpl_FAILED_TO_INITIALIZE_MEMBERINFOWITHSTATSMBEAN, e);
    }
  }

  // -------------------------------------------------------------------------
  //   Public operations
  // -------------------------------------------------------------------------

  public AgentConfig getConfig() {
    return this.agentConfig;
  }

  public AdminDistributedSystem getDistributedSystem() {
    return this.system;
  }

  /**
   * Persists the current Agent configuration to its property file.
   *
   * @throws GemFireIOException if unable to persist the configuration to props
   * @see #getPropertyFile
   */
  public void saveProperties() {
    throw new GemFireIOException("saveProperties is no longer supported for security reasons");
  }

  /**
   * Starts the jmx agent
   */
  public void start() {
    checkDebug();

    this.agentConfig.validate();

    if (mBeanServer == null) {
      mBeanServer = MBeanUtil.start();
    }

    try {
      startHttpAdaptor();
    } catch (StartupException e) {
      logWriter.shuttingDown();
      throw e;
    }

    try {
      startRMIConnectorServer();
    } catch (StartupException e) {
      stopHttpAdaptor();
      logWriter.shuttingDown();
      throw e;
    }

    try {
      startSnmpAdaptor();
    } catch (StartupException e) {
      stopRMIConnectorServer();
      stopHttpAdaptor();
      logWriter.shuttingDown();
      throw e;
    }

    if (this.agentConfig.getAutoConnect()) {
      try {
        connectToSystem();
        /*
         * Call Agent.stop() if connectToSystem() fails. This should clean up
         * agent-DS connection & stop all the HTTP/RMI/SNMP adapters started
         * earlier.
         */
      } catch (AdminException ex) {
        getLogWriterI18n().error(LocalizedStrings.AgentImpl_AUTO_CONNECT_FAILED__0, ex.getMessage());
        this.stop();
        throw new StartupException(ex);
      } catch (MalformedObjectNameException ex) {
        StringId autoConnectFailed = LocalizedStrings.AgentImpl_AUTO_CONNECT_FAILED__0;
        getLogWriterI18n().error(autoConnectFailed, ex.getMessage());
        this.stop();
        throw new StartupException(new AdminException(autoConnectFailed.toLocalizedString(new Object[] { ex.getMessage() }), ex));
      }
    } // getAutoConnect

    this.logWriter.info(LocalizedStrings.AgentImpl_GEMFIRE_JMX_AGENT_IS_RUNNING);
    this.logWriter.startupComplete();

    if (memberInfoWithStatsMBean == null) {
      initializeHelperMbean();
    }
  }

  /**
   * Deregisters everything this Agent registered and releases the MBeanServer.
   */
  public void stop() {
    try {
      this.logWriter.info(LocalizedStrings.AgentImpl_STOPPING_JMX_AGENT);
      this.logWriter.shuttingDown();

      // stop the GemFire Distributed System
      stopDistributedSystem();

      // stop all JMX Adaptors and Connectors...
      stopHttpAdaptor();
      stopRMIConnectorServer();
      memberInfoWithStatsMBean = null;
      stopSnmpAdaptor();

      // release the MBeanServer for cleanup...
      MBeanUtil.stop();
      mBeanServer = null;

      // remove the register shutdown hook which disconnects the Agent from the Distributed System upon JVM shutdown
      removeShutdownHook();

      this.logWriter.info(LocalizedStrings.AgentImpl_AGENT_HAS_STOPPED);
    }
    finally {
      if (this.logFileOutputStream != null) {
        this.logWriter.closingLogFile();
        IOUtils.close(this.logFileOutputStream);
      }
      LogWriterImpl.cleanUpThreadGroups(); // bug35388 - logwriters accumulate, causing mem leak
    }

  }

  private void stopDistributedSystem() {
    // disconnect from the distributed system...
    try {
      disconnectFromSystem();
    }
    catch (Exception e) {
      // disconnectFromSystem already prints any Exceptions
    }
    catch (Error e) {
      if (SystemFailure.isJVMFailureError(e)) {
        SystemFailure.initiateFailure(e);
        // If this ever returns, rethrow the error. We're poisoned
        // now, so don't let this thread continue.
        throw e;
      }
      // Whenever you catch Error or Throwable, you must also
      // check for fatal JVM error (see above).  However, there is
      // _still_ a possibility that you are dealing with a cascading
      // error condition, so you also need to check to see if the JVM
      // is still usable:
      SystemFailure.checkFailure();
    }
  }

  public ObjectName manageDistributedSystem()
  throws MalformedObjectNameException {
    synchronized (CONN_SYNC) {
      if (isConnected()) {
        return ((AdminDistributedSystemJmxImpl) this.system).getObjectName();
      }
      return null;
    }
  }

  /**
   * Connects to the DistributedSystem currently described by this Agent's
   * attributes for administration and monitoring.
   *
   * @return the object name of the system that the Agent is now connected to
   */
  @SuppressFBWarnings(value="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification="This is only a style warning.") 
  public ObjectName connectToSystem()
  throws AdminException, MalformedObjectNameException {
    synchronized(CONN_SYNC) {
      try {
        if (isConnected()) {
          return ((AdminDistributedSystemJmxImpl) this.system).getObjectName();
        }

        DistributionManager.isDedicatedAdminVM = isGemFireXD ? false : true;

        AdminDistributedSystemJmxImpl systemJmx =
          (AdminDistributedSystemJmxImpl) this.system;
        if (systemJmx == null) {
          systemJmx = (AdminDistributedSystemJmxImpl)
            createDistributedSystem(this.agentConfig);
          this.system = systemJmx;
        }
        systemJmx.connect(getLogWriterI18n());

        return new ObjectName(systemJmx.getMBeanName());
      } catch (AdminException e) {
        logWriter.warning(e);
        throw e;
      } catch (RuntimeException e) {
        logWriter.warning(e);
        throw e;
      } catch (Error e) {
        if (SystemFailure.isJVMFailureError(e)) {
          SystemFailure.initiateFailure(e);
          // If this ever returns, rethrow the error. We're poisoned
          // now, so don't let this thread continue.
          throw e;
        }
        // Whenever you catch Error or Throwable, you must also
        // check for fatal JVM error (see above).  However, there is
        // _still_ a possibility that you are dealing with a cascading
        // error condition, so you also need to check to see if the JVM
        // is still usable:
        SystemFailure.checkFailure();
        logWriter.error(e);
        throw e;
      }
    }
  }

  /**
   * Disconnects from the current DistributedSystem (if connected to one).
   */
  @SuppressFBWarnings(value="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification="This is only a style warning.") 
  public void disconnectFromSystem() {
    synchronized(CONN_SYNC) {
      try {
        if (this.system == null || !this.system.isConnected()) {
          return;
        }
        ((AdminDistributedSystemJmxImpl)this.system).disconnect();
//         this.system = null;
      } catch (RuntimeException e) {
        logWriter.warning(e);
        throw e;
      } catch (Error e) {
        if (SystemFailure.isJVMFailureError(e)) {
          SystemFailure.initiateFailure(e);
          // If this ever returns, rethrow the error. We're poisoned
          // now, so don't let this thread continue.
          throw e;
        }
        // Whenever you catch Error or Throwable, you must also
        // check for fatal JVM error (see above).  However, there is
        // _still_ a possibility that you are dealing with a cascading
        // error condition, so you also need to check to see if the JVM
        // is still usable:
        SystemFailure.checkFailure();
        logWriter.warning(e);
        throw e;
      } finally {
        DistributionManager.isDedicatedAdminVM = false;
      }
    }
  }

  /**
   * Retrieves a displayable snapshot of this Agent's log.
   *
   * @return snapshot of the current log
   */
  public String getLog() {
    String childTail = tailFile(this.logWriter.getChildLogFile());
    String mainTail = tailFile(new File(this.agentConfig.getLogFile()));
    if (childTail == null && mainTail == null) {
      return LocalizedStrings.AgentImpl_NO_LOG_FILE_CONFIGURED_LOG_MESSAGES_WILL_BE_DIRECTED_TO_STDOUT.toLocalizedString();
    } else {
      StringBuffer result = new StringBuffer();
      if (mainTail != null) {
        result.append(mainTail);
      }
      if (childTail != null) {
        result.append("\n" + LocalizedStrings.AgentImpl_TAIL_OF_CHILD_LOG.toLocalizedString() + "\n");
        result.append(childTail);
      }
      return result.toString();
    }
  }

  /**
   * Retrieves display-friendly GemFire version information.
   */
  public String getVersion() {
    return GemFireVersion.asString();
  }

  // -------------------------------------------------------------------------
  //   Public attribute accessors/mutators
  // -------------------------------------------------------------------------

  /** Returns true if this Agent is currently connected to a system. */
  public boolean isConnected() {
    boolean result = false;
    synchronized (CONN_SYNC) {
     result = ((this.system != null) && this.system.isConnected());
    }
    return result;
  }

  /**
   * Gets the agent's property file. This is the file it will use
   * when saving its configuration. It was also used when the agent
   * started to initialize its configuration.
   * @return the agent's property file
   */
  public String getPropertyFile() {
    return this.propertyFile;
  }

  /**
   * Sets the agent's property file.
   *
   * @param value the name of the file to save the agent properties in.
   * @throws IllegalArgumentException if the specified file is a directory.
   * @throws IllegalArgumentException if the specified file's parent is not an existing directory.
   */
  public void setPropertyFile(String value) {
    File f = (new File(value)).getAbsoluteFile();
    if (f.isDirectory()) {
        throw new IllegalArgumentException(LocalizedStrings.AgentImpl_THE_FILE_0_IS_A_DIRECTORY.toLocalizedString(f));
    }
    File parent = f.getParentFile();
    if (parent != null) {
      if (!parent.isDirectory()) {
        throw new IllegalArgumentException(LocalizedStrings.AgentImpl_THE_DIRECTORY_0_DOES_NOT_EXIST.toLocalizedString(parent));
      }
    }
    this.propertyFile = f.getPath();
  }

  /**
   * Gets the mcastAddress of the distributed system that this Agent is
   * managing.
   *
   * @return   The mcastAddress value
   */
  public String getMcastAddress() {
    return this.agentConfig.getMcastAddress();
  }

  /**
   * Sets the mcastAddress of the distributed system that this Agent is
   * managing.
   *
   * @param mcastAddress  The new mcastAddress value
   */
  public void setMcastAddress(String mcastAddress) {
    this.agentConfig.setMcastAddress(mcastAddress);
  }

  /**
   * Gets the mcastPort of the distributed system that this Agent is managing.
   *
   * @return   The mcastPort value
   */
  public int getMcastPort() {
    return this.agentConfig.getMcastPort();
  }

  /**
   * Sets the mcastPort of the distributed system that this Agent is managing.
   *
   * @param mcastPort  The new mcastPort value
   */
  public void setMcastPort(int mcastPort) {
    this.agentConfig.setMcastPort(mcastPort);
  }

  /**
   * Gets the locators of the distributed system that this Agent is managing.
   * 

* Format is a comma-delimited list of "host[port]" entries. * * @return The locators value */ public String getLocators() { return this.agentConfig.getLocators(); } /** * Sets the locators of the distributed system that this Agent is managing. *

* Format is a comma-delimited list of "host[port]" entries. * * @param locators The new locators value */ public void setLocators(String locators) { this.agentConfig.setLocators(locators); } /** * Gets the membership UDP port range in the distributed system that this * Agent is monitoring. *

* This range is given as two numbers separated by a minus sign like "min-max" * * @return membership UDP port range */ public String getMembershipPortRange() { return this.agentConfig.getMembershipPortRange(); } /** * Sets the membership UDP port range in the distributed system that this * Agent is monitoring. *

* This range is given as two numbers separated by a minus sign like "min-max" * * @param membershipPortRange membership UDP port range */ public void setMembershipPortRange(String membershipPortRange) { this.agentConfig.setMembershipPortRange(membershipPortRange); } /** * Gets the bindAddress of the distributed system that this Agent is managing. * * @return The bindAddress value */ public String getBindAddress() { return this.agentConfig.getBindAddress(); } /** * Sets the bindAddress of the distributed system that this Agent is managing. * * @param bindAddress The new bindAddress value */ public void setBindAddress(String bindAddress) { this.agentConfig.setBindAddress(bindAddress); } /** * Retrieves the command that the DistributedSystem will use to perform remote * manipulation of config files and log files. * * @return the remote command for DistributedSystem */ public String getRemoteCommand() { return this.agentConfig.getRemoteCommand(); } /** * Sets the command that the DistributedSystem will use to perform remote * manipulation of config files and log files. * * @param remoteCommand the remote command for DistributedSystem */ public void setRemoteCommand(String remoteCommand) { this.agentConfig.setRemoteCommand(remoteCommand); } /** Returns the system identity for the DistributedSystem */ public String getSystemId() { return this.agentConfig.getSystemId(); } /** Sets the system identity for the DistributedSystem */ public void setSystemId(String systemId) { this.agentConfig.setSystemId(systemId); } /** * Gets the logFileSizeLimit in megabytes of this Agent. Zero indicates no * limit. * * @return The logFileSizeLimit value */ public int getLogFileSizeLimit() { return this.agentConfig.getLogFileSizeLimit(); } /** * Sets the logFileSizeLimit in megabytes of this Agent. Zero indicates no * limit. * * @param logFileSizeLimit The new logFileSizeLimit value */ public void setLogFileSizeLimit(int logFileSizeLimit) { this.agentConfig.setLogFileSizeLimit(logFileSizeLimit); this.logWriter.configChanged(); } /** * Gets the logDiskSpaceLimit in megabytes of this Agent. Zero indicates no * limit. * * @return The logDiskSpaceLimit value */ public int getLogDiskSpaceLimit() { return this.agentConfig.getLogDiskSpaceLimit(); } /** * Sets the logDiskSpaceLimit in megabytes of this Agent. Zero indicates no * limit. * * @param logDiskSpaceLimit The new logDiskSpaceLimit value */ public void setLogDiskSpaceLimit(int logDiskSpaceLimit) { this.agentConfig.setLogDiskSpaceLimit(logDiskSpaceLimit); this.logWriter.configChanged(); } /** * Gets the logFile name for this Agent to log to. * * @return The logFile value */ public String getLogFile() { return this.agentConfig.getLogFile(); } /** * Sets the logFile name for this Agent to log to. * * @param logFile The new logFile value */ public void setLogFile(String logFile) { this.agentConfig.setLogFile(logFile); this.logWriter.configChanged(); } /** * Gets the logLevel of this Agent. * * @return The logLevel value */ public String getLogLevel() { return this.agentConfig.getLogLevel(); } /** * Sets the logLevel of this Agent. * * @param logLevel The new logLevel value */ public void setLogLevel(String logLevel) { this.agentConfig.setLogLevel(logLevel); this.logWriter.configChanged(); } /** Returns true if the Agent is set to auto connect to a system. */ public boolean getAutoConnect() { return this.agentConfig.getAutoConnect(); } /** Returns true if the Agent is set to auto connect to a system. */ public boolean isAutoConnect() { return this.agentConfig.getAutoConnect(); } /** Sets or unsets the option to auto connect to a system. */ public void setAutoConnect(boolean v) { this.agentConfig.setAutoConnect(v); } /** * Returns the address (URL) on which the RMI connector server runs * or null if the RMI connector server has not been * started. This method is used primarily for testing purposes. * * @see JMXConnectorServer#getAddress() */ public JMXServiceURL getRMIAddress() { if (this.rmiConnector != null) { return this.rmiConnector.getAddress(); } else { return null; } } /** * Gets the configuration for this Agent. * * @return the configuration for this Agent */ protected AgentConfig getAgentConfig() { return this.agentConfig; } // ------------------------------------------------------------------------- // Internal implementation methods // ------------------------------------------------------------------------- /** Returns the tail of the system log specified by File. */ private String tailFile(File f) { try { return TailLogResponse.tailSystemLog(f); } catch (IOException ex) { return LocalizedStrings.AgentImpl_COULD_NOT_TAIL_0_BECAUSE_1.toLocalizedString(new Object[] {f, ex}); } } /** * Returns the active MBeanServer which has any GemFire MBeans registered. * * @return the GemFire mbeanServer */ public MBeanServer getMBeanServer() { return mBeanServer; } // /** // * Returns the active modeler Registry which has been initialized with all // * the ModelMBean descriptors needed for GemFire MBeans. // * // * @return the modeler registry // */ // private Registry getRegistry() { // return MBeanUtil.getRegistry(); // } /** * Gets the current instance of LogWriter for logging * NOTE: Since 6.0 use {@link AgentImpl#getLogWriterI18n()} instead. * * @return the logWriter */ public LogWriter getLogWriter() { return this.logWriter; } private final Thread shutdownHook = new Thread(LogWriterImpl.createThreadGroup( "Shutdown", (LogWriterI18n) null), "Shutdown") { @Override public void run() { disconnectFromSystem(); } }; /** * Gets the current instance of LogWriterI18n for logging * * @return the logWriter * @since 6.0 */ LogWriterI18n getLogWriterI18n() { return this.logWriter; } /** * Adds a ShutdownHook to the Agent for cleaning up any resources */ private void addShutdownHook() { if( ! Boolean.getBoolean( com.gemstone.gemfire.distributed.internal.InternalDistributedSystem.DISABLE_SHUTDOWN_HOOK_PROPERTY)) { Runtime.getRuntime().addShutdownHook(shutdownHook); } } private void removeShutdownHook() { if( ! Boolean.getBoolean( com.gemstone.gemfire.distributed.internal.InternalDistributedSystem.DISABLE_SHUTDOWN_HOOK_PROPERTY)) { Runtime.getRuntime().removeShutdownHook(shutdownHook); } } /** * Creates a LogWriterI18n for this Agent to use in logging. */ @SuppressFBWarnings(value="RV_RETURN_VALUE_IGNORED_BAD_PRACTICE", justification="Return value for file delete is not important here.") private void initLogWriter() throws com.gemstone.gemfire.admin.AdminException { LogWriterI18n acLogger = this.agentConfig.getLogWriter(); // If a logger exists use it if ((acLogger != null) && acLogger instanceof ManagerLogWriter) { this.logConfig = new LogConfigImpl(); this.logWriter = (ManagerLogWriter) acLogger; this.logWriter.setConfig(this.logConfig); // write all config props to the log... // check if config enabled, for all 3 calls prior to logging if (this.logWriter.configEnabled()) { this.logWriter.config(LocalizedStrings.AgentImpl_AGENT_CONFIG_PROPERTY_FILE_NAME_0.toLocalizedString(AgentConfigImpl.retrievePropertyFile())); this.logWriter.config(this.agentConfig.getPropertyFileDescription()); this.logWriter.config(this.agentConfig.toPropertiesAsString()); } return; } final PrintStream out; if (this.agentConfig.getLogFile() == null || this.agentConfig.getLogFile().length() == 0) { out = System.out; } else { try { File f = new File(this.agentConfig.getLogFile()); // attempt to delete it and then append if the delete failed f.delete(); this.logFileOutputStream = new FileOutputStream(f, true); out = new PrintStream(this.logFileOutputStream); } catch (IOException ex) { try { this.logFileOutputStream.close(); } catch (Exception ignore) { // ignore... just trying to clean up if possible } throw new AdminException(LocalizedStrings.AgentImpl_COULD_NOT_OPEN_LOG_FILE_0.toLocalizedString(this.agentConfig.getLogFile()), ex); } } this.logConfig = new LogConfigImpl(); this.logWriter = new ManagerLogWriter(this.logConfig.getLogLevel(), out); this.logWriter.setConfig(this.logConfig); // Set this log writer in AgentConfig this.agentConfig.setLogWriter(this.logWriter); // Print Banner information this.logWriter.info(Banner.getString(this.agentConfig.getOriginalArgs())); // write all config props to the log... // check if config enabled, for all 3 calls prior to logging if (this.logWriter.configEnabled()) { this.logWriter.config(LocalizedStrings.AgentImpl_AGENT_CONFIG_PROPERTY_FILE_NAME_0.toLocalizedString(AgentConfigImpl.retrievePropertyFile())); this.logWriter.config(this.agentConfig.getPropertyFileDescription()); this.logWriter.config(this.agentConfig.toPropertiesAsString()); } } /** * Stops the HttpAdaptor and its XsltProcessor. Unregisters the associated * MBeans. */ private void stopHttpAdaptor() { if (!this.agentConfig.isHttpEnabled()) return; // stop the adaptor... try { this.httpAdaptor.stop(); } catch (Exception e) { logWriter.warning(e); } try { MBeanUtil.unregisterMBean(getHttpAdaptorName()); MBeanUtil.unregisterMBean(getXsltProcessorName()); } catch (MalformedObjectNameException e) { logWriter.warning(e); } } /** Stops the RMIConnectorServer and unregisters its MBean. */ private void stopRMIConnectorServer() { if (!this.agentConfig.isRmiEnabled()) return; // stop the RMI Connector server... try { this.rmiConnector.stop(); } catch (Exception e) { logWriter.warning(e); } try { ObjectName rmiRegistryNamingName = getRMIRegistryNamingName(); if (this.agentConfig.isRmiRegistryEnabled() && mBeanServer.isRegistered(rmiRegistryNamingName)) { String[] empty = new String[0]; mBeanServer.invoke(rmiRegistryNamingName, "stop", empty, empty); MBeanUtil.unregisterMBean(rmiRegistryNamingName); } } catch (MalformedObjectNameException e) { logWriter.warning(e); } catch (InstanceNotFoundException e) { logWriter.warning(e); } catch (ReflectionException e) { logWriter.warning(e); } catch (MBeanException e) { logWriter.warning(e); } try { ObjectName rmiConnectorServerName = getRMIConnectorServerName(); if (mBeanServer.isRegistered(rmiConnectorServerName)) { MBeanUtil.unregisterMBean(rmiConnectorServerName); } } catch (MalformedObjectNameException e) { logWriter.warning(e); } } /** Stops the SnmpAdaptor and unregisters its MBean. */ private void stopSnmpAdaptor() { if (!this.agentConfig.isSnmpEnabled()) return; // stop the SnmpAdaptor... try { getMBeanServer().invoke(getSnmpAdaptorName(), "unbind", new Object[0], new String[0]); } catch (Exception e) { logWriter.warning(e); } try { MBeanUtil.unregisterMBean(getSnmpAdaptorName()); } catch (MalformedObjectNameException e) { logWriter.warning(e); } } /** Returns the JMX ObjectName for the RMI registry Naming MBean. */ private ObjectName getRMIRegistryNamingName() throws javax.management.MalformedObjectNameException { return ObjectName.getInstance("naming:type=rmiregistry"); } /** Returns the JMX ObjectName for the HttpAdaptor. */ private ObjectName getHttpAdaptorName() throws javax.management.MalformedObjectNameException { return new ObjectName("Server:name=HttpAdaptor"); } /** Returns the JMX ObjectName for the RMIConnectorServer. */ private ObjectName getRMIConnectorServerName() throws javax.management.MalformedObjectNameException { return new ObjectName("connectors:protocol=rmi"); } /** Returns the JMX ObjectName for the SnmpAdaptor. */ private ObjectName getSnmpAdaptorName() throws javax.management.MalformedObjectNameException { return new ObjectName("Adaptors:protocol=SNMP"); } /** Returns the JMX ObjectName for the HttpAdaptor's XsltProcessor. */ private ObjectName getXsltProcessorName() throws javax.management.MalformedObjectNameException { return new ObjectName("Server:name=XSLTProcessor"); } // ------------------------------------------------------------------------- // Factory method for creating DistributedSystem // ------------------------------------------------------------------------- /** * Creates and connects to a DistributedSystem. * * @param config */ protected AdminDistributedSystem createDistributedSystem(AgentConfig config) throws com.gemstone.gemfire.admin.AdminException { return new AdminDistributedSystemJmxImpl(config); } // ------------------------------------------------------------------------- // Agent main // ------------------------------------------------------------------------- /** * Command-line main for running the GemFire Management Agent. *

* Accepts command-line arguments matching the options in {@link AgentConfig} * and {@link com.gemstone.gemfire.admin.DistributedSystemConfig}. *

* AgentConfig will convert -Jarguments to System properties. */ public static void main(String[] args) { SystemFailure.loadEmergencyClasses(); AgentConfigImpl ac; try { ac = new AgentConfigImpl(args); } catch (RuntimeException ex) { System.err.println(LocalizedStrings.AgentImpl_FAILED_READING_CONFIGURATION_0.toLocalizedString(ex)); System.exit(1); return; } try { Agent agent = AgentFactory.getAgent(ac); agent.start(); } catch (Throwable t) { Error err; if (t instanceof Error && SystemFailure.isJVMFailureError( err = (Error)t)) { SystemFailure.initiateFailure(err); // If this ever returns, rethrow the error. We're poisoned // now, so don't let this thread continue. throw err; } // Whenever you catch Error or Throwable, you must also // check for fatal JVM error (see above). However, there is // _still_ a possibility that you are dealing with a cascading // error condition, so you also need to check to see if the JVM // is still usable: SystemFailure.checkFailure(); t.printStackTrace(); System.exit(1); } } // ------------------------------------------------------------------------- // MX4J Connectors/Adaptors // ------------------------------------------------------------------------- private void createRMIRegistry() throws Exception { if (!this.agentConfig.isRmiRegistryEnabled()) { return; } MBeanServer mbs = getMBeanServer(); String host = this.agentConfig.getRmiBindAddress(); int port = this.agentConfig.getRmiPort(); /* Register and start the rmi-registry naming MBean, which is * needed by JSR 160 RMIConnectorServer */ ObjectName registryName = getRMIRegistryNamingName(); try { RMIRegistryService registryNamingService = null; if (host != null && !("".equals(host.trim()))) { registryNamingService = new RMIRegistryService(host, port); } else { registryNamingService = new RMIRegistryService(port); } mbs.registerMBean(registryNamingService, registryName); } catch (javax.management.InstanceAlreadyExistsException e) { this.logWriter.info(LocalizedStrings.AgentImpl_0__IS_ALREADY_REGISTERED, registryName); } mbs.invoke(registryName, "start", null, null); } /** * Defines and starts the JMX RMIConnector and service. *

* If {@link AgentConfig#isRmiEnabled} returns false, then this adaptor will * not be started. */ private void startRMIConnectorServer() { if (!this.agentConfig.isRmiEnabled()) return; String rmiBindAddress = this.agentConfig.getRmiBindAddress(); // Set RMI Stubs to use the given RMI Bind Address // Default bindAddress is "", if none is set - ignore if not set // If java.rmi.server.hostname property is specified then // that override is not changed String rmiStubServerNameKey = "java.rmi.server.hostname"; String overrideHostName = System.getProperty(rmiStubServerNameKey); if ((overrideHostName == null || overrideHostName.trim().length()==0) && (rmiBindAddress != null && rmiBindAddress.trim().length()!=0) ) { System.setProperty(rmiStubServerNameKey, rmiBindAddress); this.logWriter.info(LocalizedStrings.AgentImpl_SETTING_0, rmiStubServerNameKey + " = " + rmiBindAddress); } try { createRMIRegistry(); ObjectName objName = getRMIConnectorServerName(); // make sure this adaptor is not already registered... if (getMBeanServer().isRegistered(objName)) { // dunno how we got here... this.logWriter.info(LocalizedStrings.AgentImpl_RMICONNECTORSERVER_ALREADY_REGISTERED_AS__0, objName); return; } /* * url defined as: service:jmx:protocol:sap * where * 1. protocol: rmi * 2. sap is: [host[:port]][url-path] * where * host: rmi-binding-address * port: rmi-server-port * url-path: /jndi/rmi://: */ String urlString = null; String connectorServerHost = ""; int connectorServerPort = this.agentConfig.getRmiServerPort(); String rmiRegistryHost = ""; int rmiRegistryPort = this.agentConfig.getRmiPort(); // Set registryHost to localhost if not specified // RMI stubs would use a default IP if namingHost is left empty if (rmiBindAddress == null || rmiBindAddress.trim().length()==0) { connectorServerHost = "localhost"; rmiRegistryHost = ""; } else { connectorServerHost = applyRFC2732(rmiBindAddress); rmiRegistryHost = connectorServerHost; } urlString = MessageFormat.format(AgentImpl.JMX_SERVICE_URL, connectorServerHost, String.valueOf(connectorServerPort), rmiRegistryHost, String.valueOf(rmiRegistryPort), JNDI_NAME); this.logWriter.fine("JMX Service URL string is : \""+urlString+"\""); // The address of the connector JMXServiceURL url = new JMXServiceURL(urlString); Map env = new HashMap(); // env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); // env.put(Context.PROVIDER_URL, "rmi://localhost:1099"); RMIServerSocketFactory ssf = new MX4JServerSocketFactory( this.agentConfig.isAgentSSLEnabled(), // true, this.agentConfig.isAgentSSLRequireAuth(), // true, this.agentConfig.getAgentSSLProtocols(), // "any", this.agentConfig.getAgentSSLCiphers(), // "any", this.agentConfig.getRmiBindAddress(), 10, // backlog getLogWriterI18n(), this.agentConfig.getGfSecurityProperties()); env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf); if (this.agentConfig.isAgentSSLEnabled()) { RMIClientSocketFactory csf = new SslRMIClientSocketFactory(); env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf); } MBeanServer mbs = null; // will be set by registering w/ mbeanServer this.rmiConnector = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); // for cleanup this.rmiConnector.addNotificationListener( new ConnectionNotificationAdapter(), new ConnectionNotificationFilterImpl(), this); // Register the JMXConnectorServer in the MBeanServer getMBeanServer().registerMBean(this.rmiConnector, objName); // Start the JMXConnectorServer this.rmiConnector.start(); } catch (Throwable t) { Error err; if (t instanceof Error && SystemFailure.isJVMFailureError( err = (Error)t)) { SystemFailure.initiateFailure(err); // If this ever returns, rethrow the error. We're poisoned // now, so don't let this thread continue. throw err; } // Whenever you catch Error or Throwable, you must also // check for fatal JVM error (see above). However, there is // _still_ a possibility that you are dealing with a cascading // error condition, so you also need to check to see if the JVM // is still usable: SystemFailure.checkFailure(); this.logWriter.error(LocalizedStrings.AgentImpl_FAILED_TO_START_RMICONNECTORSERVER, t); throw new StartupException(LocalizedStrings.AgentImpl_FAILED_TO_START_RMI_SERVICE.toLocalizedString(), t); } } /** * Starts the optional third-party AdventNet SNMP Adaptor. *

* If {@link AgentConfig#isSnmpEnabled} returns false, then this adaptor will * not be started. */ private void startSnmpAdaptor() { if (!this.agentConfig.isSnmpEnabled()) return; try { ObjectName objName = getSnmpAdaptorName(); // make sure this adaptor is not already registered... if (getMBeanServer().isRegistered(objName)) { // dunno how we got here... getLogWriterI18n().info(LocalizedStrings.AgentImpl_SNMPADAPTOR_ALREADY_REGISTERED_AS__0, objName); return; } String className = "com.adventnet.adaptors.snmp.snmpsupport.SmartSnmpAdaptor"; String snmpDir = this.agentConfig.getSnmpDirectory(); // ex:/merry2/users/klund/agent // validate the directory... if (snmpDir == null || snmpDir.length() == 0) { throw new IllegalArgumentException(LocalizedStrings.AgentImpl_SNMPDIRECTORY_MUST_BE_SPECIFIED_BECAUSE_SNMP_IS_ENABLED.toLocalizedString()); } File root = new File(snmpDir); if (!root.exists()) { throw new IllegalArgumentException(LocalizedStrings.AgentImpl_SNMPDIRECTORY_DOES_NOT_EXIST.toLocalizedString()); } // create the adaptor... String[] sigs = new String[] { "java.lang.String" }; Object[] args = new Object[] { snmpDir }; String bindAddress = this.agentConfig.getSnmpBindAddress(); if (bindAddress != null && bindAddress.length() > 0) { sigs = new String[] { "java.lang.String", sigs[0] }; args = new Object[] { bindAddress, args[0] }; } // go... getMBeanServer().createMBean(className, objName, args, sigs); } catch(Throwable t) { Error err; if (t instanceof Error && SystemFailure.isJVMFailureError( err = (Error)t)) { SystemFailure.initiateFailure(err); // If this ever returns, rethrow the error. We're poisoned // now, so don't let this thread continue. throw err; } // Whenever you catch Error or Throwable, you must also // check for fatal JVM error (see above). However, there is // _still_ a possibility that you are dealing with a cascading // error condition, so you also need to check to see if the JVM // is still usable: SystemFailure.checkFailure(); this.logWriter.error(LocalizedStrings.AgentImpl_FAILED_TO_START_SNMPADAPTOR__0, t.getMessage()); throw new StartupException(LocalizedStrings.AgentImpl_FAILED_TO_START_SNMPADAPTOR__0.toLocalizedString(t.getMessage()), t); } } /** * Defines and starts the JMX Http Adaptor service from MX4J. *

* If {@link AgentConfig#isHttpEnabled} returns false, then this adaptor will * not be started. */ private void startHttpAdaptor() { if (!this.agentConfig.isHttpEnabled()) return; try { ObjectName objName = getHttpAdaptorName(); // make sure this adaptor is not already registered... if (getMBeanServer().isRegistered(objName)) { // dunno how we got here... getLogWriterI18n().info(LocalizedStrings.AgentImpl_HTTPADAPTOR_ALREADY_REGISTERED_AS__0, objName); return; } this.httpAdaptor = new HttpAdaptor(); // validate and set host and port values... if (this.agentConfig.getHttpPort() > 0) { this.httpAdaptor.setPort(this.agentConfig.getHttpPort()); getLogWriterI18n().config(LocalizedStrings.AgentImpl_HTTP_ADAPTOR_LISTENING_ON_PORT__0, this.agentConfig.getHttpPort()); } else { getLogWriterI18n().error(LocalizedStrings.AgentImpl_INCORRECT_PORT_VALUE__0, this.agentConfig.getHttpPort()); } if (this.agentConfig.getHttpBindAddress() != null) { String host = this.agentConfig.getHttpBindAddress(); getLogWriterI18n().config(LocalizedStrings.AgentImpl_HTTP_ADAPTOR_LISTENING_ON_ADDRESS__0, host); this.httpAdaptor.setHost(host); } else { getLogWriterI18n().error(LocalizedStrings.AgentImpl_INCORRECT_NULL_HOSTNAME); } // SSL support... MX4JServerSocketFactory socketFactory = new MX4JServerSocketFactory( this.agentConfig.isAgentSSLEnabled(), this.agentConfig.isHttpSSLRequireAuth(), this.agentConfig.getAgentSSLProtocols(), this.agentConfig.getAgentSSLCiphers(), getLogWriterI18n(), this.agentConfig.getGfSecurityProperties()); this.httpAdaptor.setSocketFactory(socketFactory); // authentication (user login) support... if (this.agentConfig.isHttpAuthEnabled()) { // this pops up a login dialog from the browser... this.httpAdaptor.setAuthenticationMethod( MX4J_HTTPADAPTOR_BASIC_AUTHENTICATION); // only basic works this.httpAdaptor.addAuthorization( this.agentConfig.getHttpAuthUser(), this.agentConfig.getHttpAuthPassword()); } // add the XsltProcessor... this.httpAdaptor.setProcessorName(createXsltProcessor()); // register the HttpAdaptor and snap on the XsltProcessor... getMBeanServer().registerMBean(this.httpAdaptor, objName); this.httpAdaptor.start(); } catch (Throwable t) { Error err; if (t instanceof Error && SystemFailure.isJVMFailureError( err = (Error)t)) { SystemFailure.initiateFailure(err); // If this ever returns, rethrow the error. We're poisoned // now, so don't let this thread continue. throw err; } // Whenever you catch Error or Throwable, you must also // check for fatal JVM error (see above). However, there is // _still_ a possibility that you are dealing with a cascading // error condition, so you also need to check to see if the JVM // is still usable: SystemFailure.checkFailure(); this.logWriter.error(LocalizedStrings.AgentImpl_FAILED_TO_START_HTTPADAPTOR__0, t.getMessage()); throw new StartupException(LocalizedStrings.AgentImpl_FAILED_TO_START_HTTPADAPTOR__0.toLocalizedString(t.getMessage()), t); } } /** * Defines and starts the Xslt Processor helper service for the Http Adaptor. */ private ObjectName createXsltProcessor() throws javax.management.JMException { ObjectName objName = getXsltProcessorName(); // make sure this mbean is not already registered... if (getMBeanServer().isRegistered(objName)) { // dunno how we got here... getLogWriterI18n().info(LocalizedStrings.AgentImpl_XSLTPROCESSOR_ALREADY_REGISTERED_AS__0, objName); return objName; } getMBeanServer().registerMBean( new mx4j.tools.adaptor.http.XSLTProcessor(), objName); return objName; } // ------------------------------------------------------------------------- // Private support methods... // ------------------------------------------------------------------------- // /** Not used anymore but seems moderately useful... */ // private String[] parseSSLCiphers(String ciphers) { // List list = new ArrayList(); // StringTokenizer st = new StringTokenizer(ciphers); // while (st.hasMoreTokens()) { // list.add(st.nextToken()); // } // return (String[]) list.toArray(new String[list.size()]); // } // ------------------------------------------------------------------------- // Inner class for configuration of logging // ------------------------------------------------------------------------- /** * Used by our {@link ManagerLogWriter} instance to access the Agent's config. */ protected class LogConfigImpl implements ManagerLogWriter.LogConfig { public int getLogLevel() { return LogWriterImpl.levelNameToCode(AgentImpl.this.getAgentConfig().getLogLevel()); } public File getLogFile() { return new File(AgentImpl.this.getAgentConfig().getLogFile()); } public int getLogFileSizeLimit() { return AgentImpl.this.getAgentConfig().getLogFileSizeLimit(); } public int getLogDiskSpaceLimit() { return AgentImpl.this.getAgentConfig().getLogDiskSpaceLimit(); } } // ------------------------------------------------------------------------- // SSL configuration for GemFire // ------------------------------------------------------------------------- public boolean isSSLEnabled() { return this.agentConfig.isSSLEnabled(); } public void setSSLEnabled(boolean enabled) { this.agentConfig.setSSLEnabled(enabled); } public String getSSLProtocols() { return this.agentConfig.getSSLProtocols(); } public void setSSLProtocols(String protocols) { this.agentConfig.setSSLProtocols(protocols); } public String getSSLCiphers() { return this.agentConfig.getSSLCiphers(); } public void setSSLCiphers(String ciphers) { this.agentConfig.setSSLCiphers(ciphers); } public boolean isSSLAuthenticationRequired() { return this.agentConfig.isSSLAuthenticationRequired(); } public void setSSLAuthenticationRequired(boolean authRequired) { this.agentConfig.setSSLAuthenticationRequired(authRequired); } public Properties getSSLProperties() { return this.agentConfig.getSSLProperties(); } public void setSSLProperties(Properties sslProperties) { this.agentConfig.setSSLProperties(sslProperties); } public void addSSLProperty(String key, String value) { this.agentConfig.addSSLProperty(key, value); } public void removeSSLProperty(String key) { this.agentConfig.removeSSLProperty(key); } // ------------------------------------------------------------------------- // ManagedResource implementation // ------------------------------------------------------------------------- public String getMBeanName() { return this.mbeanName; } public ModelMBean getModelMBean() { return this.modelMBean; } public void setModelMBean(ModelMBean modelMBean) { this.modelMBean = modelMBean; } public ObjectName getObjectName() { return this.objectName; } public ManagedResourceType getManagedResourceType() { return ManagedResourceType.AGENT; } public void cleanupResource() {} static class StartupException extends GemFireException { private static final long serialVersionUID = 6614145962199330348L; StartupException(Throwable cause) { super(cause); } StartupException(String reason, Throwable cause) { super(reason, cause); } } // ------------------------------------------------------------------------- // Other Support methods // ------------------------------------------------------------------------- /** * Checks the no. of active RMI clients and updates a flag in the Admin * Distributed System. * * @see AdminDistributedSystemJmxImpl#setRmiClientCountZero(boolean) * @since 6.0 */ void updateRmiClientsCount() { int noOfClientsConnected = 0; String[] connectionIds = this.rmiConnector.getConnectionIds(); if (connectionIds != null) { noOfClientsConnected = connectionIds.length; } logWriter.info("No. of RMI clients connected :: "+noOfClientsConnected); AdminDistributedSystemJmxImpl adminDSJmx = (AdminDistributedSystemJmxImpl) this.system; adminDSJmx.setRmiClientCountZero(noOfClientsConnected == 0); } @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append("AgentImpl["); sb.append("config=" + agentConfig.toProperties().toString()); // sb.append("; adaptor=" + httpAdaptor.toString()); sb.append("; mbeanName=" + mbeanName); sb.append("; modelMBean=" + modelMBean); sb.append("; objectName=" + objectName); sb.append("; propertyFile=" + propertyFile); sb.append(": rmiConnector=" + rmiConnector); // sb.append("; system=" + system);) sb.append("]"); return sb.toString(); } /** Process the String form of a hostname to make it comply with Jmx URL * restrictions. Namely wrap IPv6 literal address with "[", "]" * @param hostname the name to safeguard. * @return a string representation suitable for use in a Jmx connection URL */ private static String applyRFC2732(String hostname) { if(hostname.indexOf(":") != -1) { //Assuming an IPv6 literal because of the ':' return "[" + hostname + "]"; } return hostname; } } /** * Adapter class for NotificationListener that listens to notifications of type * javax.management.remote.JMXConnectionNotification * * @author abhishek * @since 6.0 */ class ConnectionNotificationAdapter implements NotificationListener { /** * If the handback object passed is an AgentImpl, updates the JMX client count * * @param notification * JMXConnectionNotification for change in client connection status * @param handback * An opaque object which helps the listener to associate information * regarding the MBean emitter. This object is passed to the MBean * during the addListener call and resent, without modification, to * the listener. The MBean object should not use or modify the * object. (NOTE: copied from javax.management.NotificationListener) */ @SuppressFBWarnings(value="BC_UNCONFIRMED_CAST", justification="Only JMXConnectionNotification instances are used.") public void handleNotification(Notification notification, Object handback) { if (handback instanceof AgentImpl) { AgentImpl agent = (AgentImpl) handback; JMXConnectionNotification jmxNotifn = (JMXConnectionNotification) notification; LogWriterI18n logWriter = agent.getLogWriterI18n(); logWriter.fine("Connection notification for connection id : '" + jmxNotifn.getConnectionId() + "'"); agent.updateRmiClientsCount(); } } } /** * Filters out the notifications of the type JMXConnectionNotification.OPENED, * JMXConnectionNotification.CLOSED and JMXConnectionNotification.FAILED. * * @author abhishek * @since 6.0 */ class ConnectionNotificationFilterImpl implements NotificationFilter { /** * Default serialVersionUID */ private static final long serialVersionUID = 1L; /** * Invoked before sending the specified notification to the listener. * Returns whether the given notification is to be sent to the listener. * * @param notification * The notification to be sent. * @return true if the notification has to be sent to the listener, false * otherwise. */ public boolean isNotificationEnabled(Notification notification) { boolean isThisNotificationEnabled = false; if (notification.getType().equals(JMXConnectionNotification.OPENED) || notification.getType().equals(JMXConnectionNotification.CLOSED) || notification.getType().equals(JMXConnectionNotification.FAILED) ) { isThisNotificationEnabled = true; } return isThisNotificationEnabled; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy