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

com.addthis.basis.jmx.MBeanRemotingSupport Maven / Gradle / Ivy

/*
 * 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.addthis.basis.jmx;

import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnectorServer;

import java.io.IOException;

import java.lang.management.ManagementFactory;

import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;

import java.util.Collections;

import java.rmi.registry.LocateRegistry;
import java.rmi.server.RMIServerSocketFactory;

public class MBeanRemotingSupport implements RMIServerSocketFactory {
    static final String URL_PATTERN = "service:jmx:rmi:///jndi/rmi://:{PORT}/jmxrmi";
    static final String PROP_RIDS = "java.rmi.server.randomIDs";
    static final String PROP_SOCK = RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE;

    int port;
    Acceptor acceptor;
    JMXServiceURL url;
    JMXConnectorServer connector;

    /**
     * Same as this(port, null);
     */
    public MBeanRemotingSupport(int port) {
        this(port, null);
    }

    /**
     * Creates one of these suckers to listen on the specified port
     *
     * @param port     the port to listen on
     * @param acceptor an acceptor to filter client connections
     * @throws IllegalArgumentException
     */
    public MBeanRemotingSupport(int port, Acceptor acceptor) {
        this.port = port;
        this.acceptor = acceptor;
        this.connector = null;

        try {
            url = new JMXServiceURL(URL_PATTERN.replace("{PORT}", Integer.toString(port)));
        } catch (MalformedURLException e) {
            throw new IllegalArgumentException("WTF?", e); // shouldn't happen
        }

        System.setProperty(PROP_RIDS, "true");
    }

    /**
     * @return the port number this guy is listening on
     */
    public int getPort() {
        return port;
    }

    /**
     * @return the JMX url this guy will respond to
     */
    public JMXServiceURL getUrl() {
        return url;
    }

    /**
     * @return the underlying JMX connector server (this will be null until
     *         start() has been called, and after stop() is called)
     */
    public JMXConnectorServer getConnectorServer() {
        return connector;
    }

    /**
     * Starts this guy listening on his specified port
     *
     * @throws IOException              if the port couldn't be opened
     * @throws IllegalArgumentException if he's already started
     */
    public void start() throws IOException {
        if (connector != null) {
            throw new IllegalArgumentException("already started");
        }

        LocateRegistry.createRegistry(port);

        connector = JMXConnectorServerFactory.newJMXConnectorServer(
                url,
                Collections.singletonMap(PROP_SOCK, this),
                ManagementFactory.getPlatformMBeanServer());
        connector.start();
    }

    /**
     * Stops this guy listening
     *
     * @throws IOException if an error prevents the stop
     */
    public void stop() throws IOException {
        try {
            if (connector != null) {
                connector.stop();
            }
        } finally {
            connector = null;
        }
    }

    /**
     * @return a server socket that will filter connections through the
     *         supplied acceptor (if there is one)
     */
    @Override
    public ServerSocket createServerSocket(int port) throws IOException {
        return new ServerSocket(port) {
            @Override
            public Socket accept() throws IOException {
                Socket client = null;
                while (client == null) {
                    client = super.accept();
                    if (acceptor != null && !acceptor.accept(client)) {
                        client.close();
                        client = null;
                    }
                }
                return client;
            }
        };
    }

    /**
     * Interface for something that knows how to accept/reject connections
     * based on originating server.
     */
    public static interface Acceptor {
        /**
         * @return should the supplied socket connection be allowed to
         *         continue?
         */
        public boolean accept(Socket socket);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy