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

com.oracle.bedrock.runtime.java.container.ContainerMBeanServerBuilder Maven / Gradle / Ivy

Go to download

Interfaces, classes and resources to construct, inspect and manage runtime processes.

There is a newer version: 7.0.5
Show newest version
/*
 * File: ContainerMBeanServerBuilder.java
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * The contents of this file are subject to the terms and conditions of 
 * the Common Development and Distribution License 1.0 (the "License").
 *
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the License by consulting the LICENSE.txt file
 * distributed with this file, or by consulting https://oss.oracle.com/licenses/CDDL
 *
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file LICENSE.txt.
 *
 * MODIFICATIONS:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 */

package com.oracle.bedrock.runtime.java.container;

import com.oracle.bedrock.annotations.Internal;
import com.oracle.bedrock.runtime.LocalPlatform;
import com.oracle.bedrock.runtime.java.JavaApplication;
import com.oracle.bedrock.runtime.java.features.JmxFeature;
import com.oracle.bedrock.runtime.network.AvailablePortIterator;

import javax.management.MBeanServer;
import javax.management.MBeanServerBuilder;
import javax.management.MBeanServerDelegate;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import java.io.IOException;
import java.net.URL;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.ExportException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * A {@link ContainerMBeanServerBuilder} is an {@link MBeanServerBuilder}
 * that contains and isolates {@link MBeanServer}s.
 * 

* Additionally, a {@link ContainerMBeanServerBuilder} automatically * manages the creation of {@link JMXConnectorServer}s when remote JMX * has been enabled. *

* Copyright (c) 2013. All Rights Reserved. Oracle Corporation.
* Oracle is a registered trademark of Oracle Corporation and/or its affiliates. * * @author Brian Oliver * @author Jonathan Knight */ @Internal public class ContainerMBeanServerBuilder extends MBeanServerBuilder { /** * The {@link URL} format for JMX RMI connections. */ public static final String JMX_RMI_URL_FORMAT = "service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi"; /** * The jmx.remote.x.password.file property. */ public static final String PROPERTY_JMX_REMOTE_PASSWORD_FILE = "jmx.remote.x.password.file"; /** * The jmx.remote.x.access.file property. */ public static final String PROPERTY_JMX_REMOTE_ACCESS_FILE = "jmx.remote.x.access.file"; /** * The jmx.remote.rmi.client.socket.factory property. */ public static final String PROPERTY_JMX_REMOTE_RMI_CLIENT_SOCKET_FACTORY = "jmx.remote.rmi.client.socket.factory"; /** * The jmx.remote.rmi.server.socket.factory property. */ public static final String PROPERTY_JMX_REMOTE_RMI_SERVER_SOCKET_FACTORY = "jmx.remote.rmi.server.socket.factory"; /** * The javax.management.builder.initial property. */ public static final String PROPERTY_JMX_MBEAN_SERVER_BUILDER = "javax.management.builder.initial"; /** * The remote jmx password file. */ public static final String DEFAULT_JMXREMOTE_PASSWORD_FILE = "/lib/management/jmxremote.password"; /** * The remote jmx access file */ public static final String DEFAULT_JMXREMOTE_ACCESS_FILE = "/lib/management/jmxremote.access"; /** * The RMI Client Socket Factory class name. */ public static final String DEFAULT_RMICLIENT_SOCKET_FACTORY = "javax.rmi.ssl.SslRMIClientSocketFactory"; /** * The RMI Server Socket Factory class name. */ public static final String DEFAULT_RMISERVER_SOCKET_FACTORY = "javax.rmi.ssl.SslRMIServerSocketFactory"; /** * The class name of the {@link MBeanServerBuilder} prior to virtualizing. */ private final String m_mBeanServerBuilderClassName; /** * The {@link ConnectorFactory}. */ private final ConnectorFactory m_jmxConnectorFactory; /** * The {@link RmiRegistryFactory}. */ private final RmiRegistryFactory m_rmiRegistryFactory; /** * The {@link AvailablePortIterator} to use for creating * remote jmx server connectors. */ private AvailablePortIterator m_availablePortIterator; /** * The current {@link MBeanServer}s created by this * {@link ContainerMBeanServerBuilder} by domain name. */ private Map m_mBeanServers; /** * The current {@link JMXConnectorServer}s by {@link MBeanServer}. */ private Map m_jmxConnectorServers; /** * Constructs a {@link ContainerMBeanServerBuilder}. * * @param availablePortIterator the {@link AvailablePortIterator} to use for * acquiring ports for server connectors */ public ContainerMBeanServerBuilder(AvailablePortIterator availablePortIterator) { this(new DefaultConnectorFactory(), new DefaultRmiRegistryFactory(), availablePortIterator); } /** * Constructs a {@link ContainerMBeanServerBuilder}. * * @param jmxConnectorFactory the {@link ConnectorFactory} * @param rmiRegistryFactory the {@link RmiRegistryFactory} * @param availablePortIterator the {@link AvailablePortIterator} to use for * acquiring ports for server connectors */ public ContainerMBeanServerBuilder(ConnectorFactory jmxConnectorFactory, RmiRegistryFactory rmiRegistryFactory, AvailablePortIterator availablePortIterator) { m_mBeanServerBuilderClassName = System.getProperties().containsKey(PROPERTY_JMX_MBEAN_SERVER_BUILDER) ? System.getProperty(PROPERTY_JMX_MBEAN_SERVER_BUILDER) : MBeanServerBuilder.class.getCanonicalName(); m_mBeanServers = new HashMap<>(); m_jmxConnectorServers = new HashMap<>(); m_jmxConnectorFactory = jmxConnectorFactory; m_rmiRegistryFactory = rmiRegistryFactory; m_availablePortIterator = availablePortIterator; } /** * Obtains the name of the {@link MBeanServerBuilder} class that * was defined prior to this {@link ContainerMBeanServerBuilder} being * created. * * @return the {@link MBeanServerBuilder} class name */ public String getPreviousMBeanServerBuilderClassName() { return m_mBeanServerBuilderClassName; } /** * Obtains the {@link MBeanServer} registered with the specified domain. *

* @param domain the domain of the {@link MBeanServer} in the {@link Container}. * * @return the {@link MBeanServer} or null if not associated * with a domain */ public synchronized MBeanServer getMBeanServer(String domain) { return m_mBeanServers.get(domain); } /** * Obtains the {@link JMXConnectorServer} that was started for the specified * {@link MBeanServer}. * * @param mBeanServer the {@link MBeanServer} * * @return the {@link JMXConnectorServer} or null if the * {@link MBeanServer} is unknown to this builder */ public synchronized JMXConnectorServer getJMXConnectorServer(MBeanServer mBeanServer) { // determine the "real" MBeanServer if this one is a DelegatingMBeanServer mBeanServer = mBeanServer instanceof DelegatingMBeanServer ? getMBeanServer(((DelegatingMBeanServer) mBeanServer).getDomain()) : mBeanServer; return m_jmxConnectorServers.get(mBeanServer); } @Override public synchronized MBeanServer newMBeanServer(String domain, MBeanServer outer, MBeanServerDelegate delegate) { // attempt to locate the mbean server locally MBeanServer mBeanServer = m_mBeanServers.get(domain); if (mBeanServer == null) { // delegate the creation of the server to the super-class mBeanServer = super.newMBeanServer(domain, outer, delegate); // save the mBeanServer (it's scoped by this builder) m_mBeanServers.put(domain, mBeanServer); // establish an server connector for the mbean server when remote jmx is enabled boolean isRemoteJMXEnabled = System.getProperties().containsKey(JmxFeature.SUN_MANAGEMENT_JMXREMOTE) &&!"false".equalsIgnoreCase(System.getProperty(JmxFeature .SUN_MANAGEMENT_JMXREMOTE)); if (isRemoteJMXEnabled) { createJMXConnectorServer(mBeanServer, System.getProperties()); } } return new DelegatingMBeanServer(domain); } @Override public MBeanServerDelegate newMBeanServerDelegate() { // always have the super-class provide the delegate return super.newMBeanServerDelegate(); } /** * Creates a {@link JMXConnectorServer} for the specified {@link MBeanServer} * using the provided connection properties. * * @param mBeanServer the {@link MBeanServer} * @param properties the {@link Properties} for the connection * * @return a {@link JMXConnectorServer} */ JMXConnectorServer createJMXConnectorServer(MBeanServer mBeanServer, Properties properties) { try { String hostName; if (properties.containsKey(JavaApplication.JAVA_RMI_SERVER_HOSTNAME)) { hostName = properties.getProperty(JavaApplication.JAVA_RMI_SERVER_HOSTNAME); } else { hostName = LocalPlatform.get().getAddress().getHostAddress(); } int port; if (properties.containsKey(JmxFeature.SUN_MANAGEMENT_JMXREMOTE_PORT)) { port = Integer.parseInt(properties.getProperty(JmxFeature.SUN_MANAGEMENT_JMXREMOTE_PORT)); } else { port = m_availablePortIterator.next(); properties.setProperty(JmxFeature.SUN_MANAGEMENT_JMXREMOTE_PORT, String.valueOf(port)); } m_rmiRegistryFactory.createRegistry(port); String remoteJMXConnectionUrl = String.format(JMX_RMI_URL_FORMAT, hostName, port); properties.setProperty(JmxFeature.SUN_MANAGEMENT_JMXREMOTE_URL, remoteJMXConnectionUrl); JMXServiceURL url = new JMXServiceURL(remoteJMXConnectionUrl); Map environment = new HashMap(); if (Boolean.parseBoolean(properties.getProperty(JmxFeature.SUN_MANAGEMENT_JMXREMOTE_AUTHENTICATE))) { String javaHome = System.getProperty(JavaApplication.JAVA_HOME); String authFileName = properties.getProperty(JmxFeature.SUN_MANAGEMENT_JMXREMOTE_PASSWORD_FILE); if (authFileName == null) { authFileName = javaHome + DEFAULT_JMXREMOTE_PASSWORD_FILE; } if (authFileName != null) { environment.put(PROPERTY_JMX_REMOTE_PASSWORD_FILE, authFileName); } String accessFileName = properties.getProperty(JmxFeature.SUN_MANAGEMENT_JMXREMOTE_ACCESS_FILE); if (accessFileName == null) { accessFileName = javaHome + DEFAULT_JMXREMOTE_ACCESS_FILE; } if (accessFileName != null) { environment.put(PROPERTY_JMX_REMOTE_ACCESS_FILE, accessFileName); } } if (Boolean.parseBoolean(properties.getProperty(JmxFeature.SUN_MANAGEMENT_JMXREMOTE_SSL))) { try { environment.put(PROPERTY_JMX_REMOTE_RMI_CLIENT_SOCKET_FACTORY, Class.forName(DEFAULT_RMICLIENT_SOCKET_FACTORY).getDeclaredConstructor().newInstance()); environment.put(PROPERTY_JMX_REMOTE_RMI_SERVER_SOCKET_FACTORY, Class.forName(DEFAULT_RMISERVER_SOCKET_FACTORY).getDeclaredConstructor().newInstance()); } catch (ClassNotFoundException e) { throw new RuntimeException("JMXConnectorServer not started. SSL security requires the Java Dynamic Management Kit or Java 1.5.", e); } } // create the connector JMXConnectorServer connector = m_jmxConnectorFactory.createJMXConnectorServer(url, environment, mBeanServer); // remember the connector so we can clean up in the future m_jmxConnectorServers.put(mBeanServer, connector); // start server connector so external jmx management can work connector.start(); return connector; } catch (Exception e) { throw new RuntimeException("Could not start JMXConnectorServer", e); } } /** * Closes the JMXConnectorServers created for this ContainerMBeanServerBuilder. */ public void close() { for (JMXConnectorServer connector : m_jmxConnectorServers.values()) { try { connector.stop(); } catch (IOException e) { // TODO: don't worry if we fail to shutdown the connector } } m_jmxConnectorServers.clear(); } /** * A {@link JMXConnectorFactory} defines factory methods to acquire * JMX Connectors for clients and servers. */ public static interface ConnectorFactory { /** * Creates a new {@link JMXConnectorServer}. * * @param url the {@link JMXServiceURL} * @param environment the environment variables for the connector * @param mBeanServer the {@link MBeanServer} to which to connect * * @return a new {@link JMXConnectorServer} * * @throws IOException when we fail to create a {@link JMXConnectorServer} */ public JMXConnectorServer createJMXConnectorServer(JMXServiceURL url, Map environment, MBeanServer mBeanServer) throws IOException; /** * Creates a new {@link JMXConnector}. * * @param url the {@link JMXServiceURL} * @param environment the environment variables for the connector * * @return the {@link JMXConnector} * * @throws IOException when we fail to create a {@link JMXConnectorServer} */ public JMXConnector createJMXConnector(JMXServiceURL url, Map environment) throws IOException; } /** * A {@link RmiRegistryFactory} provides the ability to create Rmi {@link Registry}s. */ public static interface RmiRegistryFactory { /** * Attempt to create an Rmi {@link Registry} on the specified port. * * @param port the port number to use * * @throws RemoteException if the {@link Registry} could not be created */ public void createRegistry(int port) throws RemoteException; } /** * The default implementation of the {@link ConnectorFactory}. */ public static class DefaultConnectorFactory implements ConnectorFactory { @Override public JMXConnectorServer createJMXConnectorServer(JMXServiceURL url, Map environment, MBeanServer mBeanServer) throws IOException { return JMXConnectorServerFactory.newJMXConnectorServer(url, environment, mBeanServer); } @Override public JMXConnector createJMXConnector(JMXServiceURL url, Map environment) throws IOException { return JMXConnectorFactory.newJMXConnector(url, environment); } } /** * The default implementation of an {@link RmiRegistryFactory}. */ public static class DefaultRmiRegistryFactory implements RmiRegistryFactory { @Override public void createRegistry(int port) throws RemoteException { try { LocateRegistry.createRegistry(port); } catch (ExportException e) { // Ignored as the most likely cause is that we // have already bound a registry to this port } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy