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

brooklyn.util.jmx.jmxrmi.JmxRmiAgent Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
/*
 * 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 brooklyn.util.jmx.jmxrmi;

import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.registry.LocateRegistry;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

import javax.management.MBeanServer;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;

/**
 * This exposes JMX support for going through firewalls by starting an RMI registry server
 * on a well-known port.
 * 

* This implementation DOES NOT support port-forwarding however. The same hostname used internally * (specified in {@link #RMI_HOSTNAME_PROPERTY} or autodetected by java) must also be addressable * by the JMX client. This is due to how the property is used internally by java during the * RMI registry re-direction. *

* If you require that the client connects to a different hostname/IP than the one where the * service is bound, consider using the Brooklyn JmxmpAgent, as this will not work! *

* This listens on {@value #RMI_REGISTRY_PORT_PROPERTY} unless overridden by system property * {@link #RMI_REGISTRY_PORT_PROPERTY} ({@value #RMI_REGISTRY_PORT_PROPERTY}). * * @see brooklyn.util.jmx.jmxmp.JmxmpAgent * @see https://blogs.oracle.com/jmxetc/entry/connecting_through_firewall_using_jmx * @see https://blogs.oracle.com/jmxetc/entry/more_on_premain_and_jmx */ public class JmxRmiAgent { /** Port for RMI registry to listen on. Default to {@link #RMI_REGISTRY_DEFAULT_PORT}. */ public static final String RMI_REGISTRY_PORT_PROPERTY = "brooklyn.jmx-agent.rmi-port"; public static final String RMI_REGISTRY_DEFAULT_PORT = "9001"; /** Port for JMX server (sometimes called JMX_RMI server) to listen on. Default to {@link #JMX_SERVER_DEFAULT_PORT}. */ public static final String JMX_SERVER_PORT_PROPERTY = "brooklyn.jmx-agent.jmx-port"; public static final String JMX_SERVER_DEFAULT_PORT = "11099"; /** Hostname to advertise, and if {@value #JMX_SERVER_ADDRESS_WILDCARD_PROPERTY} is false also the hostname/interface to bind to. * Should never be 0.0.0.0 as it is publicly advertised. */ public static final String RMI_HOSTNAME_PROPERTY = "java.rmi.server.hostname"; /** Whether JMX should bind to all interfaces. */ public static final String JMX_SERVER_ADDRESS_WILDCARD_PROPERTY = "jmx.remote.server.address.wildcard"; /** * The entry point, uses the JDK dynamic agent loading feature. */ public static void premain(String agentArgs) { doMain(agentArgs); } public static void agentmain(String agentArgs) { doMain(agentArgs); } public static void doMain(final String agentArgs) { // taken from JmxmpAgent in sister project // do the work in a daemon thread so that if the main class terminates abnormally, // such that shutdown hooks aren't called, we don't keep the application running // (e.g. if the app is compiled with java7 then run with java6, with a java6 agent here; // that causes the agent to launch, the main to fail, but the process to keep going) Thread t = new Thread() { public void run() { doMainForeground(agentArgs); } }; t.setDaemon(true); t.start(); } public static void doMainForeground(String agentArgs) { final JMXConnectorServer connector = new JmxRmiAgent().startServer(System.getProperties()); if (connector != null) { Runtime.getRuntime().addShutdownHook(new Thread("jmxrmi-agent-shutdownHookThread") { @Override public void run() { try { connector.stop(); } catch (Exception e) { System.err.println("Error closing jmxrmi connector in shutdown hook (continuing): "+e); } }}); } } public JMXConnectorServer startServer(Properties properties) { try { // Ensure cryptographically strong random number generator used // to choose the object number - see java.rmi.server.ObjID System.setProperty("java.rmi.server.randomIDs", "true"); // Start an RMI registry on port specified final int rmiPort = Integer.parseInt(System.getProperty(RMI_REGISTRY_PORT_PROPERTY, RMI_REGISTRY_DEFAULT_PORT)); final int jmxPort = Integer.parseInt(System.getProperty(JMX_SERVER_PORT_PROPERTY, JMX_SERVER_DEFAULT_PORT)); final String hostname = getLocalhostHostname(properties); System.out.println("Setting up JmxRmiAgent for: "+hostname+" "+rmiPort+" / "+jmxPort); LocateRegistry.createRegistry(rmiPort); // Retrieve the PlatformMBeanServer. MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); // Environment map. Map env = new LinkedHashMap(); propagate(properties, env, JMX_SERVER_ADDRESS_WILDCARD_PROPERTY, "true"); // TODO Security // Create an RMI connector server. JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://" + hostname + ":" + jmxPort + "/jndi/rmi://" + hostname + ":" + rmiPort + "/jmxrmi"); // Now create the server from the JMXServiceURL JMXConnectorServer connector = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); // Start the RMI connector server. connector.start(); System.out.println("JmxRmiAgent JMXConnectorServer active at: " + url); return connector; } catch (RuntimeException e) { System.err.println("Unable to start JMXConnectorServer: " + e); throw e; } catch (Exception e) { System.err.println("Unable to start JMXConnectorServer: " + e); throw new RuntimeException(e); } } /** * Copies the value of key from the source to the target, if set. Otherwise * sets the {@code defaultValueIfNotNull} if that is not null. * * @return whether anything is set */ private static boolean propagate(Properties source, Map target, String key, Object defaultValueIfNotNull) { Object v = source.getProperty(key); if (v == null) v = defaultValueIfNotNull; if (v == null) return false; target.put(key, v); return true; } private String getLocalhostHostname(Properties properties) throws UnknownHostException { String hostname = properties == null ? null : properties.getProperty(RMI_HOSTNAME_PROPERTY); if ("0.0.0.0".equals(hostname)) { System.err.println("WARN: invalid hostname 0.0.0.0 specified for JmxRmiAgent; " + "it typically must be an address or hostname which is bindable on the machine where " + "this service is running AND accessible by a client machine (access will likely be impossible)"); } if (hostname == null || hostname.isEmpty()) { hostname = InetAddress.getLocalHost().getHostName(); } return hostname; } /** * Convenience main method. */ public static void main(String[] args) throws Exception { premain(""); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy