You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2016/10/27 17:19:13 UTC

[21/50] [abbrv] incubator-geode git commit: GEODE-288: move admin packages to internal

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/20a32286/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/AgentImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/AgentImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/AgentImpl.java
new file mode 100644
index 0000000..6dbf134
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/AgentImpl.java
@@ -0,0 +1,1624 @@
+/*
+ * 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.internal.admin.api.jmx.impl;
+
+import java.io.File;
+import java.io.IOException;
+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 mx4j.tools.adaptor.http.HttpAdaptor;
+
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.GemFireException;
+import org.apache.geode.GemFireIOException;
+import org.apache.geode.LogWriter;
+import org.apache.geode.SystemFailure;
+import org.apache.geode.internal.admin.api.AdminDistributedSystem;
+import org.apache.geode.internal.admin.api.AdminException;
+import org.apache.geode.internal.admin.api.DistributedSystemConfig;
+import org.apache.geode.internal.admin.api.jmx.Agent;
+import org.apache.geode.internal.admin.api.jmx.AgentConfig;
+import org.apache.geode.internal.admin.api.jmx.AgentFactory;
+import org.apache.geode.distributed.internal.DistributionManager;
+import org.apache.geode.i18n.StringId;
+import org.apache.geode.internal.Banner;
+import org.apache.geode.internal.GemFireVersion;
+import org.apache.geode.internal.admin.remote.TailLogResponse;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.logging.InternalLogWriter;
+import org.apache.geode.internal.logging.LogConfig;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.logging.LogWriterFactory;
+import org.apache.geode.internal.logging.LoggingThreadGroup;
+import org.apache.geode.internal.logging.log4j.AlertAppender;
+import org.apache.geode.internal.logging.log4j.LocalizedMessage;
+import org.apache.geode.internal.logging.log4j.LogMarker;
+import org.apache.geode.internal.logging.log4j.LogWriterAppender;
+import org.apache.geode.internal.logging.log4j.LogWriterAppenders;
+
+/**
+ * The GemFire JMX Agent provides the ability to administrate one GemFire distributed system via
+ * JMX.
+ *
+ * @since GemFire 3.5
+ */
+public class AgentImpl implements Agent, ManagedResource {
+
+  private static final Logger logger = LogService.getLogger();
+
+  /**
+   * 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}";
+
+  /**
+   * 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");
+    }
+  }
+
+  /** 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 (VirtualMachineError err) {
+      SystemFailure.initiateFailure(err);
+      // If this ever returns, rethrow the error. We're poisoned
+      // now, so don't let this thread continue.
+      throw err;
+    } catch (Throwable t) {
+      // Whenever you catch Error or Throwable, you must also
+      // catch VirtualMachineError (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 LogWriterAppender logWriterAppender;
+  private InternalLogWriter logWriter;
+
+  /** 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 <code>AdminDistributedSystem</code> this Agent is currently connected to or
+   * <code>null</code>
+   */
+  private AdminDistributedSystem system;
+
+  /** The agent's configuration file */
+  private String propertyFile;
+
+  /**
+   * A lock object to guard the Connect and Disconnect calls being made on the agent for connections
+   * to the DS
+   **/
+  private 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 AdminException TODO-javadocs
+   * @throws IllegalArgumentException if agentConfig is null
+   */
+  public AgentImpl(AgentConfigImpl 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());
+
+    // LOG: create LogWriterAppender and LogWriterLogger
+    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) {
+      logger.info(LocalizedMessage
+          .create(LocalizedStrings.AgentImpl_FAILED_TO_INITIALIZE_MEMBERINFOWITHSTATSMBEAN), e);
+    } catch (MBeanRegistrationException e) {
+      logger.info(LocalizedMessage
+          .create(LocalizedStrings.AgentImpl_FAILED_TO_INITIALIZE_MEMBERINFOWITHSTATSMBEAN), e);
+    } catch (AdminException e) {
+      logger.info(LocalizedMessage
+          .create(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) {
+      AlertAppender.getInstance().shuttingDown();
+      LogWriterAppenders.stop(LogWriterAppenders.Identifier.MAIN);
+      LogWriterAppenders.destroy(LogWriterAppenders.Identifier.MAIN);
+      throw e;
+    }
+
+    try {
+      startRMIConnectorServer();
+    } catch (StartupException e) {
+      stopHttpAdaptor();
+      AlertAppender.getInstance().shuttingDown();
+      LogWriterAppenders.stop(LogWriterAppenders.Identifier.MAIN);
+      LogWriterAppenders.destroy(LogWriterAppenders.Identifier.MAIN);
+      throw e;
+    }
+
+    try {
+      startSnmpAdaptor();
+    } catch (StartupException e) {
+      stopRMIConnectorServer();
+      stopHttpAdaptor();
+      AlertAppender.getInstance().shuttingDown();
+      LogWriterAppenders.stop(LogWriterAppenders.Identifier.MAIN);
+      LogWriterAppenders.destroy(LogWriterAppenders.Identifier.MAIN);
+      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) {
+        logger.error(LocalizedMessage.create(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;
+        logger.error(LocalizedMessage.create(autoConnectFailed, ex.getMessage()));
+        this.stop();
+        throw new StartupException(new AdminException(
+            autoConnectFailed.toLocalizedString(new Object[] {ex.getMessage()}), ex));
+      }
+    } // getAutoConnect
+
+    logger.info(LocalizedMessage.create(LocalizedStrings.AgentImpl_GEMFIRE_JMX_AGENT_IS_RUNNING));
+    LogWriterAppenders.startupComplete(LogWriterAppenders.Identifier.MAIN);
+
+    if (memberInfoWithStatsMBean == null) {
+      initializeHelperMbean();
+    }
+  }
+
+  /**
+   * Deregisters everything this Agent registered and releases the MBeanServer.
+   */
+  public void stop() {
+    try {
+      logger.info(LocalizedMessage.create(LocalizedStrings.AgentImpl_STOPPING_JMX_AGENT));
+      AlertAppender.getInstance().shuttingDown();
+      LogWriterAppenders.stop(LogWriterAppenders.Identifier.MAIN);
+
+      // 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();
+
+      logger.info(LocalizedMessage.create(LocalizedStrings.AgentImpl_AGENT_HAS_STOPPED));
+    } finally {
+      LogWriterAppenders.destroy(LogWriterAppenders.Identifier.MAIN);
+      LoggingThreadGroup.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 (VirtualMachineError err) {
+      SystemFailure.initiateFailure(err);
+      throw err;
+    } catch (Error e) {
+      // Whenever you catch Error or Throwable, you must also catch VirtualMachineError (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
+   */
+  @edu.umd.cs.findbugs.annotations.SuppressWarnings(
+      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 = true;
+
+        AdminDistributedSystemJmxImpl systemJmx = (AdminDistributedSystemJmxImpl) this.system;
+        if (systemJmx == null) {
+          systemJmx = (AdminDistributedSystemJmxImpl) createDistributedSystem(this.agentConfig);
+          this.system = systemJmx;
+        }
+        systemJmx.connect(this.logWriter);
+
+        return new ObjectName(systemJmx.getMBeanName());
+      } catch (AdminException e) {
+        logger.warn(e.getMessage(), e);
+        throw e;
+      } catch (RuntimeException e) {
+        logger.warn(e.getMessage(), e);
+        throw e;
+      } catch (VirtualMachineError err) {
+        SystemFailure.initiateFailure(err);
+        // If this ever returns, rethrow the error. We're poisoned
+        // now, so don't let this thread continue.
+        throw err;
+      } catch (Error e) {
+        // Whenever you catch Error or Throwable, you must also
+        // catch VirtualMachineError (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();
+        logger.error(e.getMessage(), e);
+        throw e;
+      }
+    }
+  }
+
+  /**
+   * Disconnects from the current DistributedSystem (if connected to one).
+   */
+  @edu.umd.cs.findbugs.annotations.SuppressWarnings(
+      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) {
+        logger.warn(e.getMessage(), e);
+        throw e;
+      } catch (VirtualMachineError err) {
+        SystemFailure.initiateFailure(err);
+        // If this ever returns, rethrow the error. We're poisoned
+        // now, so don't let this thread continue.
+        throw err;
+      } catch (Error e) {
+        // Whenever you catch Error or Throwable, you must also
+        // catch VirtualMachineError (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();
+        logger.warn(e.getMessage(), 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.logWriterAppender.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.
+   * <p>
+   * 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.
+   * <p>
+   * 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.
+   * <p>
+   * 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.
+   * <p>
+   * 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);
+    LogWriterAppenders.configChanged(LogWriterAppenders.Identifier.MAIN);
+  }
+
+  /**
+   * 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);
+    LogWriterAppenders.configChanged(LogWriterAppenders.Identifier.MAIN);
+  }
+
+  /**
+   * 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);
+    LogWriterAppenders.configChanged(LogWriterAppenders.Identifier.MAIN);
+  }
+
+  /**
+   * 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);
+    LogWriterAppenders.configChanged(LogWriterAppenders.Identifier.MAIN);
+  }
+
+  /** 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 <code>null</code> 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 <code>File</code>. */
+  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
+   *
+   * @return the logWriter
+   */
+  public LogWriter getLogWriter() {
+    return this.logWriter;
+  }
+
+  private final Thread shutdownHook =
+      new Thread(LoggingThreadGroup.createThreadGroup("Shutdown"), "Shutdown") {
+        @Override
+        public void run() {
+          disconnectFromSystem();
+        }
+      };
+
+  /**
+   * Adds a ShutdownHook to the Agent for cleaning up any resources
+   */
+  private void addShutdownHook() {
+    if (!Boolean.getBoolean(
+        org.apache.geode.distributed.internal.InternalDistributedSystem.DISABLE_SHUTDOWN_HOOK_PROPERTY)) {
+      Runtime.getRuntime().addShutdownHook(shutdownHook);
+    }
+  }
+
+  private void removeShutdownHook() {
+    if (!Boolean.getBoolean(
+        org.apache.geode.distributed.internal.InternalDistributedSystem.DISABLE_SHUTDOWN_HOOK_PROPERTY)) {
+      Runtime.getRuntime().removeShutdownHook(shutdownHook);
+    }
+  }
+
+  /**
+   * Creates a LogWriterI18n for this Agent to use in logging.
+   */
+  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE",
+      justification = "Return value for file delete is not important here.")
+  private void initLogWriter() throws AdminException {
+    final LogConfig logConfig = this.agentConfig.createLogConfig();
+
+    // LOG: create logWriterAppender here
+    this.logWriterAppender = LogWriterAppenders
+        .getOrCreateAppender(LogWriterAppenders.Identifier.MAIN, false, logConfig, false);
+
+    // LOG: look in AgentConfigImpl for existing LogWriter to use
+    InternalLogWriter existingLogWriter = this.agentConfig.getInternalLogWriter();
+    if (existingLogWriter != null) {
+      this.logWriter = existingLogWriter;
+    } else {
+      // LOG: create LogWriterLogger
+      this.logWriter = LogWriterFactory.createLogWriterLogger(false, false, logConfig, false);
+      // LOG: changed statement from config to info
+      this.logWriter.info(Banner.getString(null));
+      // Set this log writer in AgentConfigImpl
+      this.agentConfig.setInternalLogWriter(this.logWriter);
+    }
+
+    // LOG: create logWriter here
+    this.logWriter = LogWriterFactory.createLogWriterLogger(false, false, logConfig, false);
+
+    // Set this log writer in AgentConfig
+    this.agentConfig.setInternalLogWriter(this.logWriter);
+
+    // Print Banner information
+    logger.info(Banner.getString(this.agentConfig.getOriginalArgs()));
+
+    // LOG:CONFIG: changed next three statements from config to info
+    logger.info(LogMarker.CONFIG, LocalizedStrings.AgentImpl_AGENT_CONFIG_PROPERTY_FILE_NAME_0
+        .toLocalizedString(AgentConfigImpl.retrievePropertyFile()));
+    logger.info(LogMarker.CONFIG, this.agentConfig.getPropertyFileDescription());
+    logger.info(LogMarker.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) {
+      logger.warn(e.getMessage(), e);
+    }
+
+    try {
+      MBeanUtil.unregisterMBean(getHttpAdaptorName());
+      MBeanUtil.unregisterMBean(getXsltProcessorName());
+    } catch (MalformedObjectNameException e) {
+      logger.warn(e.getMessage(), 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) {
+      logger.warn(e.getMessage(), 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) {
+      logger.warn(e.getMessage(), e);
+    } catch (InstanceNotFoundException e) {
+      logger.warn(e.getMessage(), e);
+    } catch (ReflectionException e) {
+      logger.warn(e.getMessage(), e);
+    } catch (MBeanException e) {
+      logger.warn(e.getMessage(), e);
+    }
+
+    try {
+      ObjectName rmiConnectorServerName = getRMIConnectorServerName();
+      if (mBeanServer.isRegistered(rmiConnectorServerName)) {
+        MBeanUtil.unregisterMBean(rmiConnectorServerName);
+      }
+    } catch (MalformedObjectNameException e) {
+      logger.warn(e.getMessage(), 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) {
+      logger.warn(e.getMessage(), e);
+    }
+
+    try {
+      MBeanUtil.unregisterMBean(getSnmpAdaptorName());
+    } catch (MalformedObjectNameException e) {
+      logger.warn(e.getMessage(), 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 <code>DistributedSystem</code>.
+   *
+   * @param config
+   */
+  private AdminDistributedSystem createDistributedSystem(AgentConfigImpl config)
+      throws AdminException {
+    return new AdminDistributedSystemJmxImpl(config);
+  }
+
+  // -------------------------------------------------------------------------
+  // Agent main
+  // -------------------------------------------------------------------------
+
+  /**
+   * Command-line main for running the GemFire Management Agent.
+   * <p>
+   * Accepts command-line arguments matching the options in {@link AgentConfig} and
+   * {@link DistributedSystemConfig}.
+   * <p>
+   * <code>AgentConfig</code> 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 (VirtualMachineError err) {
+      SystemFailure.initiateFailure(err);
+      // If this ever returns, rethrow the error. We're poisoned
+      // now, so don't let this thread continue.
+      throw err;
+    } catch (Throwable t) {
+      // Whenever you catch Error or Throwable, you must also
+      // catch VirtualMachineError (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) {
+      logger.info(LocalizedMessage.create(LocalizedStrings.AgentImpl_0__IS_ALREADY_REGISTERED,
+          registryName));
+    }
+    mbs.invoke(registryName, "start", null, null);
+  }
+
+  /**
+   * Defines and starts the JMX RMIConnector and service.
+   * <p>
+   * 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);
+      logger.info(LocalizedMessage.create(LocalizedStrings.AgentImpl_SETTING_0,
+          new StringBuilder(rmiStubServerNameKey).append(" = ").append(rmiBindAddress)));
+    }
+
+    try {
+      createRMIRegistry();
+      ObjectName objName = getRMIConnectorServerName();
+
+      // make sure this adaptor is not already registered...
+      if (getMBeanServer().isRegistered(objName)) {
+        // dunno how we got here...
+        logger.info(LocalizedMessage.create(
+            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://<rmi-binding-address>:<rmi-port><JNDI_NAME>
+       */
+      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);
+
+      logger.debug("JMX Service URL string is : \"{}\"", urlString);
+
+      // The address of the connector
+      JMXServiceURL url = new JMXServiceURL(urlString);
+
+      Map<String, Object> env = new HashMap<String, Object>();
+      // 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
+          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 (VirtualMachineError err) {
+      SystemFailure.initiateFailure(err);
+      // If this ever returns, rethrow the error. We're poisoned
+      // now, so don't let this thread continue.
+      throw err;
+    } catch (Throwable t) {
+      // Whenever you catch Error or Throwable, you must also
+      // catch VirtualMachineError (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();
+      logger.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.
+   * <p>
+   * 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...
+        logger.info(LocalizedMessage
+            .create(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 (VirtualMachineError err) {
+      SystemFailure.initiateFailure(err);
+      // If this ever returns, rethrow the error. We're poisoned
+      // now, so don't let this thread continue.
+      throw err;
+    } catch (Throwable t) {
+      // Whenever you catch Error or Throwable, you must also
+      // catch VirtualMachineError (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();
+      logger.error(LocalizedMessage
+          .create(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.
+   * <p>
+   * 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...
+        logger.info(LocalizedMessage
+            .create(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());
+        logger.info(LogMarker.CONFIG,
+            LocalizedMessage.create(LocalizedStrings.AgentImpl_HTTP_ADAPTOR_LISTENING_ON_PORT__0,
+                this.agentConfig.getHttpPort()));
+      } else {
+        logger.error(LocalizedMessage.create(LocalizedStrings.AgentImpl_INCORRECT_PORT_VALUE__0,
+            this.agentConfig.getHttpPort()));
+      }
+
+      if (this.agentConfig.getHttpBindAddress() != null) {
+        String host = this.agentConfig.getHttpBindAddress();
+        logger.info(LogMarker.CONFIG, LocalizedMessage
+            .create(LocalizedStrings.AgentImpl_HTTP_ADAPTOR_LISTENING_ON_ADDRESS__0, host));
+        this.httpAdaptor.setHost(host);
+      } else {
+        logger.error(LocalizedMessage.create(LocalizedStrings.AgentImpl_INCORRECT_NULL_HOSTNAME));
+      }
+
+      // SSL support...
+      MX4JServerSocketFactory socketFactory =
+          new MX4JServerSocketFactory(this.agentConfig.isAgentSSLEnabled(),
+              this.agentConfig.isHttpSSLRequireAuth(), this.agentConfig.getAgentSSLProtocols(),
+              this.agentConfig.getAgentSSLCiphers(), 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 (VirtualMachineError err) {
+      SystemFailure.initiateFailure(err);
+      // If this ever returns, rethrow the error. We're poisoned
+      // now, so don't let this thread continue.
+      throw err;
+    } catch (Throwable t) {
+      // Whenever you catch Error or Throwable, you must also
+      // catch VirtualMachineError (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();
+      logger.error(LocalizedMessage
+          .create(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...
+      logger.info(LocalizedMessage
+          .create(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()]);
+  // }
+
+  // -------------------------------------------------------------------------
+  // 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 GemFire 6.0
+   */
+  void updateRmiClientsCount() {
+    int noOfClientsConnected = 0;
+
+    String[] connectionIds = this.rmiConnector.getConnectionIds();
+
+    if (connectionIds != null) {
+      noOfClientsConnected = connectionIds.length;
+    }
+
+    logger.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
+ *
+ * @since GemFire 6.0
+ */
+class ConnectionNotificationAdapter implements NotificationListener {
+  private static final Logger logger = LogService.getLogger();
+
+  /**
+   * 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)
+   */
+  @edu.umd.cs.findbugs.annotations.SuppressWarnings(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;
+
+      if (logger.isDebugEnabled()) {
+        logger.debug("Connection notification for connection id : '{}'",
+            jmxNotifn.getConnectionId());
+      }
+
+      agent.updateRmiClientsCount();
+    }
+  }
+}
+
+
+/**
+ * Filters out the notifications of the type JMXConnectionNotification.OPENED,
+ * JMXConnectionNotification.CLOSED and JMXConnectionNotification.FAILED.
+ *
+ * @since GemFire 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;
+  }
+}
+