com.cisco.oss.foundation.monitoring.RMIMonitoringAgent.java Source code

Java tutorial

Introduction

Here is the source code for com.cisco.oss.foundation.monitoring.RMIMonitoringAgent.java

Source

/*
 * Copyright 2014 Cisco Systems, Inc.
 *
 *  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.
 */

package com.cisco.oss.foundation.monitoring;

import com.cisco.oss.foundation.configuration.ConfigurationFactory;
import com.cisco.oss.foundation.monitoring.component.config.*;
import com.cisco.oss.foundation.monitoring.component.data.ComponentInfo;
import com.cisco.oss.foundation.monitoring.exception.AgentAlreadyRegisteredException;
import com.cisco.oss.foundation.monitoring.exception.AgentRegistrationException;
import com.cisco.oss.foundation.monitoring.exception.IncompatibleClassException;
import com.cisco.oss.foundation.monitoring.notification.NotificationInfoMXBean;
import com.cisco.oss.foundation.monitoring.notification.NotificationMXBean;
import com.cisco.oss.foundation.monitoring.notification.NotificationSender;
import com.cisco.oss.foundation.monitoring.serverconnection.ConnectionInfo;
import com.cisco.oss.foundation.monitoring.services.ServiceInfo;
import org.apache.commons.configuration.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.remoting.support.RemoteInvocation;

import javax.management.*;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * RMIMonitoringAgent is the main class of monitoring library. It allows
 * Java components to plug into the Monitoring infrastructure allowing them
 * to expose the monitoring information in the form of JMX.
 *
 * @author manojc
 * @see MonitoringMXBean
 */
public enum RMIMonitoringAgent implements MonitoringAgent {
    INSTANCE;
    private static final AtomicBoolean firstTime = new AtomicBoolean(true);
    private static final String COLON = ":";
    private static Logger LOGGER = LoggerFactory.getLogger(RMIMonitoringAgent.class.getName());
    private static NotificationMXBean notificationDetails = null;
    private Configuration configuration;
    //    private static Map<String, RMIMonitoringAgent> registeredAgents = new HashMap<String, RMIMonitoringAgent>();
    private MBeanServer mbs;
    private ServerInfo serverInfo;
    private ObjectName appObjectName;
    private ObjectName servicesObjectName;
    private ObjectName connetctionsObjectName;
    private ObjectName monitorAndManagementSettingsObjectName = null;
    private ObjectName componentInfoObjectName = null;
    private JMXConnectorServer rmis;
    //    private boolean isRegistered = false;
    private boolean isNotificationRegistered = false;
    private Thread serverThread;
    private MonitoringMXBean exposedObject = null;
    private String exposedServiceURL = null;
    private String exposedObjectName = null;
    private Map<String, String> jmxEnvironmentMap = null;
    private JMXServiceURL jurl;
    //    private static ServiceInfo serviceInfo;
    //    private static ConnectionInfo connectionInfo;
    //    private boolean isComponentRegisted = false;
    //    private boolean isInfraRegisted = false;
    private ObjectName notificationObjectName;

    /**
     * This is the default constructor for <code>RMIMonitoringAgent</code>.
     * <code>register</code> method needs to be explicitly called in order to
     * initialize the monitoring infrastructure.
     *
     * @see #register(MonitoringMXBean)
     */
    private RMIMonitoringAgent() {

    }

    //    /**
    //     * This constructor not just creates an instance of
    //     * <code>RMIMonitoringAgent</code> but also initializes the monitoring
    //     * infrastructure and registers the mxBean object.
    //     *
    //     * @param mXBean
    //     *
    //     * @throws com.cisco.oss.foundation.monitoring.exception.AgentAlreadyRegisteredException
    //     * @throws com.cisco.oss.foundation.monitoring.exception.AgentRegistrationException
    //     * @throws com.cisco.oss.foundation.monitoring.exception.IncompatibleClassException
    //     *
    //     * @see MonitoringMXBean
    //     */
    /*   public RMIMonitoringAgent(MonitoringMXBean mXBean) throws AgentAlreadyRegisteredException, AgentRegistrationException,
        IncompatibleClassException {
        
          AppProperties.loadProperties();
          LOGGER.debug("New RMIMonitoringAgent object getting created");
          register(mXBean);
       }*/

    //    /**
    //     * This constructor not just creates an instance of
    //     * <code>RMIMonitoringAgent</code> but also initializes the monitoring
    //     * infrastructure with the custom configuration, and registers the mxBean
    //     * object.
    //     *
    //     * @param mXBean
    //     * @param configuration
    //     * @throws com.cisco.oss.foundation.monitoring.exception.AgentAlreadyRegisteredException
    //     * @throws com.cisco.oss.foundation.monitoring.exception.AgentRegistrationException
    //     * @throws com.cisco.oss.foundation.monitoring.exception.IncompatibleClassException
    //     * @see MonitoringMXBean
    //     * @see MXConfiguration
    //     * @see com.cisco.oss.foundation.monitoring.component.config.MonitorAndManagementSettingsMXBean
    //     */
    /*public RMIMonitoringAgent(MonitoringMXBean mXBean, MXConfiguration configuration)
        throws AgentAlreadyRegisteredException, AgentRegistrationException, IncompatibleClassException {
        
      AppProperties.loadProperties(configuration);
      setConfiguration(configuration);
      LOGGER.debug("New RMIMonitoringAgent object getting created");
      register(mXBean);
    }*/
    //    public static RMIMonitoringAgent getInstance() {
    //        return INSTANCE;
    //    }

    //    /**
    //     * Two or more instance/modules of applications sharing same instance of JVM
    //     * can also share an instance of RMIMonitoringAgent. One instance/module can
    //     * register into RMIMonitoringAgent by supplying an authentication key. Other
    //     * instance/module can access already registered instance of RMIMonitoringAgent
    //     * only if it knows the authentication key in addition to the name and
    //     * instance of the application.
    //     *
    //     * @param name     Registered application name
    //     * @param instance Registered instance
    //     * @param authKey  Authentication key supplied while registering
    //     * @return Instance of RMIMonitoringAgent
    //     */
    //    public static RMIMonitoringAgent getRegistedAgent(String name, String instance, String authKey) {
    //        LOGGER.debug("Getting RMIMonitoringAgent instance for (" + name + ", " + instance + ")");
    //
    //        return registeredAgents.get(name + COLON + instance + COLON + authKey);
    //    }
    private static URL getSpringUrl() {

        final ProtectionDomain protectionDomain = RemoteInvocation.class.getProtectionDomain();
        String errorMessage = "creation of jar file failed for UNKNOWN reason";

        if (protectionDomain == null) {

            errorMessage = "class protection domain is null";

        } else {

            final CodeSource codeSource = protectionDomain.getCodeSource();

            if (codeSource == null) {

                errorMessage = "class code source is null";

            } else {

                final URL location = codeSource.getLocation();

                if (location == null) {

                    errorMessage = "class code source location is null";

                } else {

                    return location;

                }

            }

        }

        throw new UnsupportedOperationException(errorMessage);

    }

    private static MonitorAndManagementSettings getMonitorAndManagementSettings() {
        MonitorAndManagementSettings settings = new MonitorAndManagementSettings();
        ControlSettings controlSettings = new ControlSettings();
        OtherSettings otherSettings = new OtherSettings();
        controlSettings.setStartCommandSettings(getStartCommandSettings());
        controlSettings.setStopCommandSettings(getStopCommandSettings());
        controlSettings.setStatusCommandSettings(getStatusCommandSettings());
        otherSettings.setCommandLine(System.getenv("_PROCESS_ID_LIST"));
        settings.setControlSettings(controlSettings);
        settings.setOtherSettings(otherSettings);
        return settings;
    }

    private static StartCommandSettings getStartCommandSettings() {
        StartCommandSettings startCommandSettings = new StartCommandSettings();
        startCommandSettings.setCommand(System.getenv("_START_COMMAND"));
        startCommandSettings.setMatchPolicy(MatchPolicy.PartialMatch);
        startCommandSettings.setSuccessIndication(System.getenv("_START_COMMAND_SUCCESS"));
        return startCommandSettings;
    }

    private static StopCommandSettings getStopCommandSettings() {
        StopCommandSettings stopCommandSettings = new StopCommandSettings();
        stopCommandSettings.setCommand(System.getenv("_STOP_COMMAND"));
        stopCommandSettings.setMatchPolicy(MatchPolicy.PartialMatch);
        stopCommandSettings.setSuccessIndication(System.getenv("_STOP_COMMAND_SUCCESS"));
        return stopCommandSettings;
    }

    private static StatusCommandSettings getStatusCommandSettings() {
        StatusCommandSettings statusCommandSettings = new StatusCommandSettings();
        statusCommandSettings.setCommand(System.getenv("_STATUS_COMMAND"));
        statusCommandSettings.setMatchPolicy(MatchPolicy.PartialMatch);
        statusCommandSettings.setUpIndication(System.getenv("_UP_INDICATION"));
        statusCommandSettings.setDownIndication(System.getenv("_DOWN_INDICATION"));
        return statusCommandSettings;
    }

    /**
     * Registers the mxBean object and exposes it to the outside world. Any
     * changes to this object will automatically be reflected and seen by the
     * monitoring applications.
     *
     * @param mxBean
     * @throws com.cisco.oss.foundation.monitoring.exception.AgentAlreadyRegisteredException
     * @throws com.cisco.oss.foundation.monitoring.exception.AgentRegistrationException
     * @throws com.cisco.oss.foundation.monitoring.exception.IncompatibleClassException
     * @see RMIMonitoringAgent#unregister()
     */

    private synchronized void register(MonitoringMXBean mxBean)
            throws AgentAlreadyRegisteredException, AgentRegistrationException, IncompatibleClassException {

        LOGGER.info("Registering RMIMonitoringAgent for " + ComponentInfo.INSTANCE.getName() + COLON
                + ComponentInfo.INSTANCE.getInstance());
        final URL jarUrl = getSpringUrl();

        System.setProperty("java.rmi.server.codebase", jarUrl.toString().replace(" ", "%20"));

        try {

            Utility.validateJavaVersion();
            this.exposedObject = mxBean;
            Utility.validateGenericParams(this.exposedObject);

            String serviceURL = Utility.getServiceURL(configuration, this.exposedObject);
            String strAppObjectName = null;

            strAppObjectName = javaRegister(mxBean, serviceURL);
            Runtime.getRuntime().addShutdownHook(new ShutdownHookThread());

            //            registeredAgents.put(ComponentInfo.INSTANCE.getName() + COLON + ComponentInfo.INSTANCE.getInstance() + COLON + authKey, this);
            exposedServiceURL = serviceURL;
            exposedObjectName = strAppObjectName;
            LOGGER.info(
                    "RMIMonitoringAgent successfully registered. Java Version=" + System.getProperty("java.version")
                            + ", URL=" + exposedServiceURL + ", ObjectName=" + exposedObjectName);
            TransactionMonitorThread.getInstance().startTread();
        } catch (MalformedURLException muEx) {
            String message = "Failed to register RMIMonitoringAgent. Name/Instance attributes does not follow the naming standard.";
            LOGGER.error(message, muEx);
            throw new AgentRegistrationException(message, muEx);
        } catch (MalformedObjectNameException monEx) {
            String message = "Failed to register RMIMonitoringAgent. Name/Instance attributes does not follow the naming standard.";
            LOGGER.error(message, monEx);
            throw new AgentRegistrationException(message, monEx);
        } catch (InstanceAlreadyExistsException existsEx) {
            String message = "Failed to register RMIMonitoringAgent. There is an another instance of RMIMonitoringAgent already registered for "
                    + ComponentInfo.INSTANCE.getName() + COLON + ComponentInfo.INSTANCE.getInstance();
            LOGGER.error(message, existsEx);
            throw new AgentAlreadyRegisteredException(message, existsEx);
        } catch (NotCompliantMBeanException notComplEx) {
            String message = "Failed to register RMIMonitoringAgent. The MonitoringMXBean object tried to register is not JMX compliant.";
            LOGGER.error(message, notComplEx);
            throw new IncompatibleClassException(message, notComplEx);
        } catch (MBeanRegistrationException mrE) {
            String message = "Failed to register RMIMonitoringAgent. Check the log for more details.";
            LOGGER.error(message, mrE);
            throw new AgentRegistrationException(message, mrE);
        } catch (IOException ioEx) {
            String message = "Failed to register RMIMonitoringAgent. Check the log for more details.";
            LOGGER.error(message, ioEx);
            throw new AgentRegistrationException(message, ioEx);
        }
    }

    private String javaRegister(MonitoringMXBean mxBean, String serviceURL) throws MalformedObjectNameException,
            IOException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
        serverInfo = new ServerInfo(mxBean, configuration);

        String strAppObjectName = Utility.getObjectName("Application", this.exposedObject);

        jurl = new JMXServiceURL(serviceURL);
        appObjectName = new ObjectName(strAppObjectName);

        jmxEnvironmentMap = null;

        int agentPort = configuration.getInt(FoundationMonitoringConstants.MX_PORT);
        if (!RMIRegistryManager.isRMIRegistryRunning(configuration, agentPort)) {
            RMIRegistryManager.startRMIRegistry(configuration, agentPort);
        } else {
            LOGGER.info("rmiregistry is already running on port " + agentPort);
        }

        String serviceName = serviceURL.substring(serviceURL.indexOf("jmxrmi/"));
        if (isServiceExported(configuration, serviceName)) {
            MonitoringClient client = new MonitoringClient(serviceURL, strAppObjectName);
            if (client.connect()) {
                client.disconnect();
            } else {
                jmxEnvironmentMap = Utility.prepareJmxEnvironmentMap();
                LOGGER.info("Found a stale entry for " + serviceName + " in rmiregistry , it will be overwritten");
            }
        }
        mbs = ManagementFactory.getPlatformMBeanServer();
        rmis = JMXConnectorServerFactory.newJMXConnectorServer(jurl, jmxEnvironmentMap, mbs);

        mbs.registerMBean(mxBean, appObjectName);
        registerComponentInfo();
        registerMonitoringConfiguration();
        registerServices();
        registerConnections();
        registerNotificationDetails();
        rmis.start();

        if (mxBean instanceof INotifier) {
            INotifier notifier = (INotifier) mxBean;
            notifier.setNotificationSender(serverInfo);
        }

        serverThread = new ServerRecoveryDaemon();
        serverThread.start();

        return strAppObjectName;
    }

    public ObjectInstance registerMBean(Object object) {

        String objName = FoundationMonitoringConstants.DOMAIN_NAME + ":name=" + ComponentInfo.INSTANCE.getName();

        if ((ComponentInfo.INSTANCE.getInstance() != null)
                && (!ComponentInfo.INSTANCE.getInstance().trim().equals(""))) {
            objName = objName + ",instance=" + ComponentInfo.INSTANCE.getInstance();
        }

        objName = objName + ",contentSource=" + object.getClass().getSimpleName();

        try {
            return mbs.registerMBean(object, new ObjectName(objName));
        } catch (Exception e) {
            LOGGER.error("Problem registering bean: {}. error is: {}", objName, e, e);
            throw new IllegalArgumentException(e);
        }
    }

    private void registerComponentInfo() throws MalformedObjectNameException, InstanceAlreadyExistsException,
            MBeanRegistrationException, NotCompliantMBeanException {
        String strMonComponentObjectName = Utility.getObjectName("ComponentInfo", this.exposedObject);
        this.componentInfoObjectName = new ObjectName(strMonComponentObjectName);
        mbs.registerMBean(ComponentInfo.INSTANCE, this.componentInfoObjectName);

    }

    private void registerMonitoringConfiguration() throws MalformedObjectNameException,
            InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
        MonitorAndManagementSettings monitorAndManagementSettings = getMonitorAndManagementSettings();
        String strMonConfigObjectName = Utility.getObjectName("MonitorAndManagementSettings", this.exposedObject);
        this.monitorAndManagementSettingsObjectName = new ObjectName(strMonConfigObjectName);
        mbs.registerMBean(monitorAndManagementSettings, this.monitorAndManagementSettingsObjectName);

    }

    private void registerServices() {
        try {
            String strMonConfigObjectName = Utility.getObjectName("ServiceInfo", this.exposedObject);
            servicesObjectName = new ObjectName(strMonConfigObjectName);
            mbs.registerMBean(ServiceInfo.INSTANCE, servicesObjectName);
        } catch (MalformedObjectNameException e) {
            LOGGER.trace("Failed to register services" + e.getMessage());
        } catch (InstanceAlreadyExistsException e) {
            LOGGER.trace("Failed to register services" + e.getMessage());
        } catch (MBeanRegistrationException e) {
            LOGGER.trace("Failed to register services" + e.getMessage());
        } catch (NotCompliantMBeanException e) {
            LOGGER.trace("Failed to register services" + e.getMessage());
        }

    }

    public void sendNotification(NotificationInfoMXBean data) {
        try {
            if (!isNotificationRegistered) {

                registerNotificationDetails();
            }
            notificationDetails.sendNotification(data);
        } catch (Exception e) {
            LOGGER.trace("Failed to invoke sendNotification Method" + e.getMessage());
        }
    }

    private void registerNotificationDetails() {
        try {
            notificationDetails = new NotificationMXBean();
            String strNotifObjectName = Utility.getObjectName("NotificationMXBean", this.exposedObject);
            notificationObjectName = new ObjectName(strNotifObjectName);
            mbs.registerMBean(notificationDetails, notificationObjectName);
            isNotificationRegistered = true;
        } catch (MalformedObjectNameException e) {
            LOGGER.trace("Failed to register services" + e.getMessage());
        } catch (InstanceAlreadyExistsException e) {
            LOGGER.trace("Failed to register services" + e.getMessage());
        } catch (MBeanRegistrationException e) {
            LOGGER.trace("Failed to register services" + e.getMessage());
        } catch (NotCompliantMBeanException e) {
            LOGGER.trace("Failed to register services" + e.getMessage());
        } catch (IllegalArgumentException e) {
            LOGGER.trace("Failed to register services" + e.getMessage());
        }

    }

    private void registerConnections() {
        try {
            String strMonConfigObjectName = Utility.getObjectName("ConnectionInfo", this.exposedObject);
            connetctionsObjectName = new ObjectName(strMonConfigObjectName);
            mbs.registerMBean(ConnectionInfo.INSTANCE, connetctionsObjectName);
        } catch (MalformedObjectNameException e) {
            LOGGER.trace("Failed to register connetctions" + e.getMessage());
        } catch (InstanceAlreadyExistsException e) {
            LOGGER.trace("Failed to register connetctions" + e.getMessage());
        } catch (MBeanRegistrationException e) {
            LOGGER.trace("Failed to register connetctions" + e.getMessage());
        } catch (NotCompliantMBeanException e) {
            LOGGER.trace("Failed to register connetctions" + e.getMessage());
        }
    }

    private void unregisterMonitoringConfiguration() throws InstanceNotFoundException, MBeanRegistrationException {
        if (this.monitorAndManagementSettingsObjectName != null) {
            mbs.unregisterMBean(this.monitorAndManagementSettingsObjectName);
        }

    }

    private void unregisterServices() {
        try {
            if (this.servicesObjectName != null)
                mbs.unregisterMBean(this.servicesObjectName);
        } catch (InstanceNotFoundException e) {
            LOGGER.trace("Failed to unregister services" + e.getMessage());
        } catch (MBeanRegistrationException e) {
            LOGGER.trace("Failed to unregister services" + e.getMessage());
        }
    }

    private void unregisterComponentInfo() {
        try {
            if (this.connetctionsObjectName != null)
                mbs.unregisterMBean(this.componentInfoObjectName);
        } catch (InstanceNotFoundException e) {
            LOGGER.trace("Failed to unregister ComponentInfo" + e.getMessage());
        } catch (MBeanRegistrationException e) {
            LOGGER.trace("Failed to unregister ComponentInfo" + e.getMessage());
        }
    }

    private void unregisterConnetctions() {
        try {
            if (this.connetctionsObjectName != null)
                mbs.unregisterMBean(this.connetctionsObjectName);
        } catch (InstanceNotFoundException e) {
            LOGGER.trace("Failed to unregister server connetctions" + e.getMessage());
        } catch (MBeanRegistrationException e) {
            LOGGER.trace("Failed to unregister server connetctions" + e.getMessage());
        }
    }

    /**
     * Unregisters <code>RMIMonitoringAgent</code> instance and makes the
     * application unavailable for monitoring. Calling unregister() on a
     * RMIMonitoringAgent that is already unregistered will have no effect.
     *
     * @throws com.cisco.oss.foundation.monitoring.exception.AgentRegistrationException
     */
    private void unregister() throws AgentRegistrationException {

        LOGGER.info("Unregistering RMIMonitoringAgent for " + ComponentInfo.INSTANCE.getName() + COLON
                + ComponentInfo.INSTANCE.getInstance());

        try {
            serverThread.interrupt();
            rmis.stop();
            mbs.unregisterMBean(appObjectName);
            unregisterComponentInfo();
            unregisterMonitoringConfiguration();
            unregisterServices();
            unregisterConnetctions();

            if (notificationObjectName != null && mbs.isRegistered(notificationObjectName)) {
                mbs.unregisterMBean(notificationObjectName);
            }

            LOGGER.info("RMIMonitoringAgent successfully unregistered. Java Version="
                    + System.getProperty("java.version") + ", URL=" + exposedServiceURL + ", ObjectName="
                    + exposedObjectName);

            exposedServiceURL = null;
            exposedObjectName = null;
            isNotificationRegistered = false;
        } catch (IOException ex) {
            String message = "Failed to unregister RMIMonitoringAgent. Check the log for more details.";
            LOGGER.error(message, ex);
            throw new AgentRegistrationException(message, ex);
        } catch (InstanceNotFoundException ex) {
            String message = "Failed to unregister RMIMonitoringAgent. Check the log for more details.";
            LOGGER.error(message, ex);
            throw new AgentRegistrationException(message, ex);
        } catch (MBeanRegistrationException ex) {
            String message = "Failed to unregister RMIMonitoringAgent. Check the log for more details.";
            LOGGER.error(message, ex);
            throw new AgentRegistrationException(message, ex);
        } catch (LinkageError ex) {

        }
    }

    private NotificationSender getNotificationSender() {
        return serverInfo;
    }

    private MonitoringAgentMXBean getAgentDetails() {
        return serverInfo;
    }

    private boolean isServiceExported(Configuration configuration, String serviceName) {
        boolean isJmxServiceExported = RMIRegistryManager.isServiceExported(configuration,
                configuration.getInt(FoundationMonitoringConstants.MX_PORT), serviceName);
        return isJmxServiceExported;
    }

    /**
     * empty implementation. this is just needed for the initial init and registration of the monitoring agent.
     * this function can be called repeatedly with no side effects.
     */
    public void register() {
        register(ConfigurationFactory.getConfiguration());
    }

    public void register(Configuration configuration) {
        this.configuration = configuration;
        if (firstTime.compareAndSet(true, false)) {
            try {
                CommunicationInfo.getCommunicationInfo().setConfiguration(configuration);
                register(new DefaultMonitoringMXBean());
            } catch (Exception e) {
                LOGGER.error("error creating monitoring agent: {}", e, e);
            }
        }
    }

    final class ShutdownHookThread extends Thread {
        public void run() {
            try {
                LOGGER.debug("ShutdownHookThread called.");
                unregister();
                ServiceInfo.INSTANCE.serviceActorThread.stop();
                ConnectionInfo.INSTANCE.serverConnectionActorThread.stop();
                CommunicationInfo.INSTANCE.actorsThreadPool.shutdown();
            } catch (AgentRegistrationException agentregEx) {
                LOGGER.debug("ShutdownHookThread failed to unregister RMIMonitoringAgent.");
            }
        }
    }

    private class ServerRecoveryDaemon extends Thread {
        private static final String SERVER_RECOVERY_DAEMON_POLLING = "foundation.mx.recoverydaemon.polling";
        private long timeInterval = 20000;

        public ServerRecoveryDaemon() {
            timeInterval = Long.parseLong(System.getProperty(SERVER_RECOVERY_DAEMON_POLLING, "20000"));
        }

        @Override
        public void run() {
            LOGGER.info("ServerRecoveryDaemon started.");
            while (true) {
                try {
                    Thread.sleep(timeInterval);
                    synchronized (RMIMonitoringAgent.this) {
                        String serviceName = exposedServiceURL.substring(exposedServiceURL.indexOf("jmxrmi/"));
                        if (!isServiceExported(configuration, serviceName)) {
                            LOGGER.warn(
                                    "RMI Connector Server " + serviceName + " is found to be not running on port "
                                            + configuration.getInt(FoundationMonitoringConstants.MX_PORT)
                                            + ", reregistering RMI Connector Server.");

                            try {
                                rmis.stop();
                            } catch (IOException e) {
                                LOGGER.error("Failed to stop JMX RMI Connector server.");
                            }

                            RMIRegistryManager.startRMIRegistry(configuration,
                                    configuration.getInt(FoundationMonitoringConstants.MX_PORT));

                            rmis = JMXConnectorServerFactory.newJMXConnectorServer(jurl, jmxEnvironmentMap, mbs);
                            rmis.start();
                            LOGGER.info("Recreated RMI Connector Server.");
                        }
                    }
                } catch (InterruptedException e) {
                    break;
                } catch (Exception e) {
                    LOGGER.error("ServerRecoveryDaemon failed to reregister RMI Connector Server on port "
                            + configuration.getInt(FoundationMonitoringConstants.MX_PORT)
                            + ". Next attempt will be made after " + timeInterval + "ms.", e);
                }
            }

            LOGGER.info("ServerRecoveryDaemon stopped.");
        }
    }

}