org.springframework.jmx.support.ConnectorServerFactoryBean.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.jmx.support.ConnectorServerFactoryBean.java

Source

/*
 * Copyright 2002-2005 the original author or authors.
 *
 * 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 org.springframework.jmx.support;

import java.io.IOException;
import java.util.Map;
import java.util.Properties;

import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.NestedRuntimeException;

/**
 * <code>FactoryBean</code> that creates a JSR-160 <code>JMXConnectorServer</code>,
 * optionally registers it with the <code>MBeanServer</code> and then starts it.
 *
 * <p>The <code>JMXConnectorServer</code> can be started in a separate thread by setting the
 * <code>threaded</code> property to <code>true</code>. You can configure this thread to be a
 * daemon thread by setting the <code>daemon</code> property to <code>true</code>.
 *
 * <p>The <code>JMXConnectorServer</code> is correctly shutdown when an instance of this
 * class is destroyed on shutdown of the containing <code>ApplicationContext</code>.
 *
 * @author Rob Harrop
 * @author Juergen Hoeller
 * @since 1.2
 * @see   FactoryBean
 * @see JMXConnectorServer
 * @see MBeanServer
 */
public class ConnectorServerFactoryBean implements FactoryBean, InitializingBean, DisposableBean {

    /**
     * The default service URL.
     */
    public static final String DEFAULT_SERVICE_URL = "service:jmx:jmxmp://localhost:9875";

    protected final Log logger = LogFactory.getLog(getClass());

    private MBeanServer server;

    private String serviceUrl = DEFAULT_SERVICE_URL;

    private Map environment;

    private ObjectName objectName;

    private boolean threaded = false;

    private boolean daemon = false;

    private JMXConnectorServer connectorServer;

    /**
     * Set the <code>MBeanServer</code> that the <code>JMXConnectorServer</code>
     * should expose.
     */
    public void setServer(MBeanServer server) {
        this.server = server;
    }

    /**
     * Set the service URL for the <code>JMXConnectorServer</code>.
     */
    public void setServiceUrl(String serviceUrl) {
        this.serviceUrl = serviceUrl;
    }

    /**
     * Set the environment properties used to construct the <code>JMXConnectorServer</code>
     * as <code>java.util.Properties</code> (String key/value pairs).
     */
    public void setEnvironment(Properties environment) {
        this.environment = environment;
    }

    /**
     * Set the environment properties used to construct the <code>JMXConnector</code>
     * as a <code>Map</code> of String keys and arbitrary Object values.
     */
    public void setEnvironmentMap(Map environment) {
        this.environment = environment;
    }

    /**
     * Set the <code>ObjectName</code> used to register the <code>JMXConnectorServer</code>
     * itself with the <code>MBeanServer</code>.
     * @throws MalformedObjectNameException if the <code>ObjectName</code> is malformed
     */
    public void setObjectName(String objectName) throws MalformedObjectNameException {
        this.objectName = ObjectNameManager.getInstance(objectName);
    }

    /**
     * Set whether the <code>JMXConnectorServer</code> should be started in a separate thread.
     */
    public void setThreaded(boolean threaded) {
        this.threaded = threaded;
    }

    /**
     * Set whether any threads started for the <code>JMXConnectorServer</code> should be
     * started as daemon threads.
     */
    public void setDaemon(boolean daemon) {
        this.daemon = daemon;
    }

    /**
     * Start the connector server. If the <code>threaded</code> flag is set to <code>true</code>,
     * the <code>JMXConnectorServer</code> will be started in a separate thread.
     * If the <code>daemon</code> flag is set to <code>true</code>, that thread will be
     * started as a daemon thread.
     * @throws JMException if a problem occured when registering the connector server
     * with the <code>MBeanServer</code>
     * @throws IOException if there is a problem starting the connector server
     */
    public void afterPropertiesSet() throws JMException, IOException {
        if (this.server == null) {
            this.server = JmxUtils.locateMBeanServer();
        }

        // Create the JMX service URL.
        JMXServiceURL url = new JMXServiceURL(this.serviceUrl);

        // Create the connector server now.
        this.connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url, this.environment, this.server);

        // Do we want to register the connector with the MBean server?
        if (this.objectName != null) {
            this.server.registerMBean(this.connectorServer, this.objectName);
        }

        try {
            if (this.threaded) {
                // Start the connector server asynchronously (in a separate thread).
                Thread connectorThread = new Thread() {
                    public void run() {
                        try {
                            connectorServer.start();
                        } catch (IOException ex) {
                            throw new DelayedConnectorStartException(ex);
                        }
                    }
                };

                connectorThread.setName("JMX Connector Thread [" + this.serviceUrl + "]");
                connectorThread.setDaemon(this.daemon);
                connectorThread.start();
            } else {
                // Start the connector server in the same thread.
                this.connectorServer.start();
            }

            if (logger.isInfoEnabled()) {
                logger.info("JMX connector server started: " + this.connectorServer);
            }
        }

        catch (IOException ex) {
            // Unregister the connector server if startup failed.
            unregisterConnectorServer();
            throw ex;
        }
    }

    public Object getObject() {
        return this.connectorServer;
    }

    public Class getObjectType() {
        return (this.connectorServer != null ? this.connectorServer.getClass() : JMXConnectorServer.class);
    }

    public boolean isSingleton() {
        return true;
    }

    /**
     * Stop the <code>JMXConnectorServer</code> managed by an instance of this class.
     * Automatically called on <code>ApplicationContext</code> shutdown.
     * @throws IOException if there is an error stopping the connector server
     */
    public void destroy() throws IOException {
        if (logger.isInfoEnabled()) {
            logger.info("Stopping JMX connector server: " + this.connectorServer);
        }
        try {
            this.connectorServer.stop();
        } finally {
            unregisterConnectorServer();
        }
    }

    /**
     * Unregister the connection server from the <code>MBeanServer</code>.
     * Logs an exception instead of rethrowing it.
     */
    private void unregisterConnectorServer() {
        if (this.objectName != null) {
            try {
                this.server.unregisterMBean(this.objectName);
            } catch (JMException ex) {
                logger.error("Could not unregister JMX connector server", ex);
            }
        }
    }

    /**
     * Exception to be thrown if the JMX connector server cannot be started
     * (in a concurrent thread).
     */
    public static class DelayedConnectorStartException extends NestedRuntimeException {

        private DelayedConnectorStartException(IOException ex) {
            super("Could not start JMX connector server after delay", ex);
        }
    }

}