/**
* VMware Continuent Tungsten Replicator
* Copyright (C) 2015 VMware, Inc. All rights reserved.
*
* 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.
*
* Initial developer(s): Robert Hodges
* Contributor(s): Edward Archibald, Stephane Giron
*/
package com.continuent.tungsten.common.jmx;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.NoSuchObjectException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.text.MessageFormat;
import java.util.HashMap;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.MBeanServerNotification;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;
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 javax.management.remote.rmi.RMIConnectorServer;
import javax.net.ssl.SSLHandshakeException;
import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import com.continuent.tungsten.common.config.cluster.ConfigurationException;
import com.continuent.tungsten.common.security.AuthenticationInfo;
import com.continuent.tungsten.common.security.PasswordManager;
import com.continuent.tungsten.common.security.PasswordManager.ClientApplicationType;
import com.continuent.tungsten.common.security.RealmJMXAuthenticator;
import com.continuent.tungsten.common.security.SecurityHelper;
/**
* Encapsulates JMX server start/stop and provides static utility methods to
* register MBeans on the server side as well as get proxies for them on the
* client side.
*
* @author <a href="mailto:robert.hodges@continuent.com">Robert Hodges</a>
* @version 1.0
*/
public class JmxManager implements NotificationListener
{
private static final Logger logger = Logger
.getLogger(JmxManager.class);
// RMI registry and connector server we are managing.
protected Registry rmiRegistry;
protected JMXConnectorServer jmxConnectorServer;
// JMX server parameters.
private final String host;
private final int registryPort;
private final int beanPort;
private final String serviceName;
public final static String CREATE_MBEAN_HELPER = "createHelper";
// Authentication and Encryption parameters
private volatile AuthenticationInfo authenticationInfo = null;
public JmxManager(String host, int beanPort, int registryPort,
String serviceName)
{
this(host, beanPort, registryPort, serviceName, null);
}
/**
* Creates an instance to manage a JMX service
*
* @param host The host name or IP to use
* @param beanPort The port used for JMX beans
* @param registryPort The JMX server RMI registryPort
* @param serviceName The JMX service name
* @param authInfo Authentication information from security.properties or
* null if no security settings are available
*/
public JmxManager(String host, int beanPort, int registryPort,
String serviceName, AuthenticationInfo authInfo)
{
this.host = host;
this.beanPort = beanPort;
this.registryPort = registryPort;
this.serviceName = serviceName;
this.authenticationInfo = authInfo;
// Load security information from security.properties
// Load password from file
// CONT-1069
if (authenticationInfo == null)
{
try
{
authenticationInfo = SecurityHelper
.loadAuthenticationInformation();
// Sets the username and password in the authenticationInfo.
// This will be used as credentials when connecting
// Password is provided "as is" (potentially encrypted) and will
// be decrypted by the server if needed
if (authenticationInfo.isAuthenticationNeeded())
{
PasswordManager passwordManager = new PasswordManager(
authenticationInfo, ClientApplicationType.RMI_JMX);
String goodPassword = passwordManager
.getEncryptedPasswordForUser(
authenticationInfo.getUsername());
authenticationInfo.setPassword(goodPassword);
}
}
catch (ConfigurationException e)
{
logger.error(MessageFormat.format(
"Could not get security information. Will use default values: {0}",
e));
}
}
}
/**
* Creates an instance to manage a JMX service
*
* @param host The host name or IP to use
* @param registryPort The JMX server RMI registryPort
* @param serviceName The JMX service name
*/
public JmxManager(String host, int registryPort, String serviceName)
{
this(host, registryPort + 1, registryPort, serviceName);
}
/**
* Creates an instance to manage a JMX service Called when using
* authentication (and) encryption
*
* @see <a href=
* "http://download.java.net/jdk8/docs/technotes/guides/jmx/tutorial/security.html">
* JMX Tutorial on Security</a>
* @param host
* @param registryPort
* @param serviceName
* @param authInfo
*/
public JmxManager(String host, int registryPort, String serviceName,
AuthenticationInfo authInfo)
{
this(host, registryPort + 1, registryPort, serviceName, authInfo);
}
/**
* Starts the JXM server.
*/
public synchronized void start()
{
createRegistry(registryPort);
startJmxConnector();
}
/**
* Stops the JXM server.
*/
public synchronized void stop()
{
stopRMI();
stopJmxConnector();
}
protected Registry locateDefaultRegistry()
{
Registry registry = null;
try
{
registry = LocateRegistry.getRegistry();
}
catch (Exception r)
{
throw new ServerRuntimeException(String.format(
"Unable to locate the default registry on registryPort 1099, reason='%s'",
r.getMessage()));
}
return registry;
}
/**
* Starts the rmi registry.
*/
protected void createRegistry(int port)
{
// Create a registry if we don't already have one.
if (rmiRegistry == null)
{
try
{
if (logger.isDebugEnabled())
{
logger.debug(
"Starting RMI registry on registryPort: " + port);
}
rmiRegistry = LocateRegistry.createRegistry(port);
}
catch (Throwable e)
{
throw new ServerRuntimeException(
"Unable to start rmi registry on registryPort: " + port,
e);
}
}
}
/**
* Deallocates the RMI registry.
*/
protected void stopRMI()
{
if (rmiRegistry != null)
{
try
{
UnicastRemoteObject.unexportObject(rmiRegistry, true);
}
catch (NoSuchObjectException e)
{
logger.warn("Unexpected error while shutting down RMI registry",
e);
}
rmiRegistry = null;
}
}
/**
* Starts the JMX connector for the server.
*/
protected void startJmxConnector()
{
String serviceAddress = null;
try
{
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
serviceAddress = generateServiceAddress(host, beanPort,
registryPort, serviceName);
JMXServiceURL address = new JMXServiceURL(serviceAddress);
// --- Define security attributes ---
HashMap<String, Object> env = new HashMap<String, Object>();
// --- Authentication based on password and access files---
if (authenticationInfo != null
&& authenticationInfo.isAuthenticationNeeded())
{
if (authenticationInfo.isUseTungstenAuthenticationRealm())
env.put(JMXConnectorServer.AUTHENTICATOR,
new RealmJMXAuthenticator(authenticationInfo));
else
env.put("jmx.remote.x.password.file",
authenticationInfo.getPasswordFileLocation());
env.put("jmx.remote.x.access.file",
authenticationInfo.getAccessFileLocation());
}
// --- SSL encryption ---
if (authenticationInfo != null
&& authenticationInfo.isEncryptionNeeded())
{
// Keystore
System.setProperty("javax.net.ssl.keyStore",
authenticationInfo.getKeystoreLocation());
System.setProperty("javax.net.ssl.keyStorePassword",
authenticationInfo.getKeystorePassword());
/**
* Configure SSL. Protocols and ciphers are set in
* securityHelper.setSecurityProperties and used by
* SslRMIClientSocketFactory
*/
try
{
String[] protocolArray = authenticationInfo
.getEnabledProtocols().toArray(new String[0]);
String[] allowedCipherSuites = authenticationInfo
.getEnabledCipherSuites().toArray(new String[0]);
String[] cipherArray;
if (protocolArray.length == 0)
protocolArray = null;
if (allowedCipherSuites.length == 0)
cipherArray = null;
else
{
// Ensure we choose an allowed cipher suite.
cipherArray = authenticationInfo
.getJvmEnabledCipherSuites()
.toArray(new String[0]);
if (cipherArray.length == 0)
{
// We don't have any cipher suites in common. This
// is not good!
String message = "Unable to find approved ciphers in the supported cipher suites on this JVM";
StringBuffer sb = new StringBuffer(message)
.append("\n");
sb.append(String.format(
"JVM supported cipher suites: %s\n",
StringUtils.join(SecurityHelper
.getJvmSupportedCiphers())));
sb.append(String.format(
"Approved cipher suites from security.properties: %s\n",
StringUtils.join(allowedCipherSuites)));
logger.error(sb.toString());
throw new RuntimeException(message);
}
}
logger.info("Setting allowed JMX server protocols: "
+ StringUtils.join(protocolArray, ","));
logger.info("Setting allowed JMX server ciphers: "
+ StringUtils.join(cipherArray, ","));
SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory(
cipherArray, protocolArray, false);
env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE,
csf);
env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
ssf);
}
catch (IllegalArgumentException ie)
{
logger.warn(
"Some of the protocols or ciphers are not supported. "
+ ie.getMessage());
throw new RuntimeException(ie.getLocalizedMessage(), ie);
}
}
env.put(RMIConnectorServer.JNDI_REBIND_ATTRIBUTE, "true");
JMXConnectorServer connector = JMXConnectorServerFactory
.newJMXConnectorServer(address, env, mbs);
connector.start();
logger.info(MessageFormat.format(
"JMXConnector: security.properties={0}",
(authenticationInfo != null)
? authenticationInfo
.getParentPropertiesFileLocation()
: "No security.properties file found !..."));
if (authenticationInfo != null)
logger.info(authenticationInfo.toString());
logger.info(String.format("JMXConnector started at address %s",
serviceAddress));
jmxConnectorServer = connector;
}
catch (Throwable e)
{
throw new ServerRuntimeException(MessageFormat.format(
"Unable to create RMI listener: {0} -> {1}",
getServiceProps(), e), e);
}
}
private String getServiceProps()
{
return ("RMI {host=" + host + ", registryPort=" + registryPort
+ ", service=" + serviceName + "}");
}
/**
* Stops the JMX connector if it is running.
*/
protected void stopJmxConnector()
{
// Shut down the JMX server.
try
{
if (jmxConnectorServer != null)
jmxConnectorServer.stop();
}
catch (IOException e)
{
logger.warn("Unexpected error while shutting down JMX server", e);
}
}
/**
* Server helper method to register a JMX MBean. MBeans are registered by a
* combination of their MBean interface and the custom mbeanName argument.
* The mbeanName permits multiple mBeans to be registered under the same
* name.
*
* @param mbean The MBean instance that should be registered
* @param mbeanInterface The MBean interface this instance implements
* @param mbeanName A custom name for this MBean
* @throws ServerRuntimeException
*/
public static void registerMBean(Object mbean, Class<?> mbeanInterface,
String mbeanName, boolean ignored)
{
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
try
{
if (logger.isDebugEnabled())
logger.debug("Registering mbean: " + mbean.getClass());
ObjectName name = generateMBeanObjectName(mbeanInterface.getName(),
mbeanName);
if (mbs.isRegistered(name))
mbs.unregisterMBean(name);
mbs.registerMBean(mbean, name);
}
catch (Exception e)
{
throw new ServerRuntimeException("Unable to register mbean: class="
+ mbean.getClass() + " interface=" + mbeanInterface
+ " name=" + mbeanName, e);
}
}
/**
* Server helper method to register a JMX MBean. MBeans are registered by a
* combination of their MBean interface and the custom mbeanName argument.
* The mbeanName permits multiple mBeans to be registered under the same
* name.
*
* @param mbean The MBean instance that should be registered
* @param mbeanClass The base class for the mbean
* @throws ServerRuntimeException
*/
public static void registerMBean(Object mbean, Class<?> mbeanClass)
{
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
try
{
if (logger.isDebugEnabled())
logger.debug("Registering mbean: " + mbean.getClass());
ObjectName name = generateMBeanObjectName(mbeanClass);
if (mbs.isRegistered(name))
mbs.unregisterMBean(name);
mbs.registerMBean(mbean, name);
}
catch (Exception e)
{
throw new ServerRuntimeException(String.format(
"Unable to register mbean for class %s because '%s'",
mbeanClass.getName(), e), e);
}
}
/**
* Server helper method to register a JMX MBean. MBeans are registered by a
* combination of their MBean interface and the custom mbeanName argument.
* The mbeanName permits multiple mBeans to be registered under the same
* name.
*
* @param mbeanInterface The MBean interface this instance implements
* @param mbeanName A custom name for this MBean
* @throws ServerRuntimeException
*/
public static void unregisterMBean(Class<?> mbeanInterface,
String mbeanName)
{
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
try
{
ObjectName name = generateMBeanObjectName(mbeanInterface.getName(),
mbeanName);
if (mbs.isRegistered(name))
{
logger.info("Unregistering mbean: " + name.toString());
mbs.unregisterMBean(name);
}
else
{
logger.warn("Ignoring attempt to unregister unknown mbean: "
+ name.toString());
}
}
catch (Exception e)
{
throw new ServerRuntimeException(
"Unable to unregister mbean: interface=" + mbeanInterface
+ " name=" + mbeanName,
e);
}
}
/**
* Server helper method to register a JMX MBean. MBeans are registered by a
* combination of their MBean interface and the custom mbeanName argument.
* The mbeanName permits multiple mBeans to be registered under the same
* name.
*
* @param mbeanInterface The MBean interface this instance implements
* @throws ServerRuntimeException
*/
public static void unregisterMBean(Class<?> mbeanInterface)
{
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
try
{
ObjectName name = generateMBeanObjectName(mbeanInterface);
if (mbs.isRegistered(name))
{
logger.info("Unregistering mbean: " + name.toString());
mbs.unregisterMBean(name);
}
else
{
logger.warn("Ignoring attempt to unregister unknown mbean: "
+ name.toString());
}
}
catch (Exception e)
{
throw new ServerRuntimeException(
"Unable to unregister mbean: interface=" + mbeanInterface,
e);
}
}
/**
* Client helper method to return an RMI connection on the server whose
* properties are the same as this manager instance.
*
* @return a connection to the server
*/
public JMXConnector getLocalRMIConnector()
{
String serviceAddress = null;
try
{
// --- Define security attributes ---
HashMap<String, Object> env = new HashMap<String, Object>();
// --- Authentication based on password and access files---
if (authenticationInfo != null
&& authenticationInfo.isAuthenticationNeeded())
{
// Build credentials
String[] credentials;
if (authenticationInfo.isUseTungstenAuthenticationRealm())
credentials = new String[]{authenticationInfo.getUsername(),
authenticationInfo.getDecryptedPassword(),
AuthenticationInfo.TUNGSTEN_AUTHENTICATION_REALM};
else
credentials = new String[]{authenticationInfo.getUsername(),
authenticationInfo.getDecryptedPassword()};
env.put("jmx.remote.credentials", credentials);
}
// --- SSL ---
if (authenticationInfo != null
&& authenticationInfo.isEncryptionNeeded())
{
// Truststore
System.setProperty("javax.net.ssl.trustStore",
authenticationInfo.getTruststoreLocation());
System.setProperty("javax.net.ssl.trustStorePassword",
authenticationInfo.getTruststorePassword());
}
serviceAddress = generateServiceAddress(host, beanPort,
registryPort, serviceName);
JMXServiceURL address = new JMXServiceURL(serviceAddress);
JMXConnector connector = JMXConnectorFactory.connect(address, env);
return connector;
}
catch (Exception e)
{
// --- Try to get more details on the connection problem
// String errorMessage = String
// .format("Cannot establish a connection with component '%s' at
// address %s:%d\n",
// serviceName, host, registryPort);
String errorMessage = MessageFormat.format(
"Cannot establish a connection with component {0} at address {1}:{2}\n{3}",
serviceName, host, registryPort, e);
String errorReason = null;
AssertionError assertionError = null;
// Authentication required by server
if (e instanceof SecurityException)
{
errorReason = String.format("Reason=%s\n", e.toString());
assertionError = new AssertionError(
"Authentication required by server");
}
// Encryption required by server
else if (e.getCause() instanceof SSLHandshakeException)
{
errorReason = String.format("Reason="
+ "javax.net.ssl.SSLHandshakeException: Server requires SSL.\n");
assertionError = new AssertionError(
"Encryption required by server");
}
else if (e instanceof ConfigurationException)
{
errorMessage = e.getMessage();
assertionError = new AssertionError("Configuration error");
}
// Other IOException
else if (e instanceof IOException)
{
errorMessage = String.format(
"A component of type '%s' at address %s:%d is not available.\n %s\n",
serviceName, host, registryPort, e);
errorReason = "Check to be sure that the service is running.\n";
}
if (logger.isDebugEnabled())
{
logger.debug(String.format(errorMessage + errorReason), e);
}
throw new ServerRuntimeException(
String.format(errorMessage + errorReason),
(assertionError != null) ? assertionError : e);
}
}
/**
* Client helper method to connector to a JMX manager.
*/
public static JMXConnector getRMIConnector(String host, int port,
String beanServiceName)
{
JmxManager jmxMgr = new JmxManager(host, port, beanServiceName);
return jmxMgr.getLocalRMIConnector();
}
/**
* Client helper method to obtain a proxy that implements the given
* interface by forwarding its methods through the given MBean server to the
* named MBean.
*
* @param clientConnection the MBean server to forward to
* @param mbeanClass The MBean interface this instance implements
* @param mbeanName A custom name for this MBean
* @param notificationBroadcaster If true make the returned proxy implement
* NotificationEmitter by forwarding its methods via connection
* @return An MBean proxy
*/
public static Object getMBeanProxy(JMXConnector clientConnection,
Class<?> mbeanClass, String mbeanName,
boolean notificationBroadcaster, boolean ignored)
{
try
{
ObjectName objectName = generateMBeanObjectName(
mbeanClass.getName(), mbeanName);
return MBeanServerInvocationHandler.newProxyInstance(
clientConnection.getMBeanServerConnection(), objectName,
mbeanClass, notificationBroadcaster);
}
catch (Exception e)
{
throw new ServerRuntimeException(
"Unable to get proxy connection to bean", e);
}
}
/**
* Client helper method to obtain a proxy that implements the given
* interface by forwarding its methods through the given MBean server to the
* named MBean.
*
* @param clientConnection the MBean server to forward to
* @param mbeanClass The class for which an MBean exists
* @param notificationBroadcaster If true make the returned proxy implement
* NotificationEmitter by forwarding its methods via connection
* @return An MBean proxy
*/
public static Object getMBeanProxy(JMXConnector clientConnection,
Class<?> mbeanClass, boolean notificationBroadcaster)
{
String mbeanInterfaceClassName = mbeanClass.getName() + "MBean";
Class<?> mbeanInterfaceClass = null;
try
{
mbeanInterfaceClass = Class.forName(mbeanInterfaceClassName);
}
catch (ClassNotFoundException c)
{
throw new ServerRuntimeException(String.format(
"Cannot get an RMI proxy for class %s because the interface class %s was not found",
mbeanClass.getName(), mbeanInterfaceClassName));
}
try
{
ObjectName objectName = generateMBeanObjectName(mbeanClass);
return MBeanServerInvocationHandler.newProxyInstance(
clientConnection.getMBeanServerConnection(), objectName,
mbeanInterfaceClass, notificationBroadcaster);
}
catch (Exception e)
{
throw new ServerRuntimeException(String.format(
"Cannot get an RMI proxy for class %s because of this exception: %s",
mbeanClass.getName(), e), e);
}
}
/**
* Client helper method to obtain a proxy that implements the given
* interface by forwarding its methods through the given MBean server to the
* named MBean.
*
* @param clientConnection the MBean server to forward to
* @param mbeanClass The MBean interface this instance implements
* @param mbeanName A custom name for this MBean
* @param notificationBroadcaster If true make the returned proxy implement
* NotificationEmitter by forwarding its methods via connection
* @return An MBean proxy
*/
public static Object getMBeanProxy(JMXConnector clientConnection,
Class<?> mbeanClass, Class<?> mbeanInterface, String mbeanName,
boolean notificationBroadcaster, boolean ignored)
{
try
{
ObjectName objectName = generateMBeanObjectName(
mbeanClass.getName(), mbeanName);
return MBeanServerInvocationHandler.newProxyInstance(
clientConnection.getMBeanServerConnection(), objectName,
mbeanInterface, notificationBroadcaster);
}
catch (Exception e)
{
throw new ServerRuntimeException(
"Unable to get proxy connection to bean", e);
}
}
/**
* Attach NotificationListener that can be used to listen notifications
* emitted by MBean server.
*
* @param jmxConnector The MBean server connector.
* @param mbeanInterface The MBean interface this instance implements.
* @param mbeanName A custom name for the MBean.
* @param notificationListener User provided NotificationListener instance.
* @throws InstanceNotFoundException
* @throws Exception
*/
static public void addNotificationListener(JMXConnector jmxConnector,
Class<?> mbeanInterface, String mbeanName,
NotificationListener notificationListener, boolean ignored)
throws InstanceNotFoundException, Exception
{
MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection();
ObjectName objectName = generateMBeanObjectName(
mbeanInterface.getName(), mbeanName);
mbsc.addNotificationListener(objectName, notificationListener, null,
null);
}
public static MBeanServerConnection getServerConnection(
JMXConnector jmxConnector) throws Exception
{
return jmxConnector.getMBeanServerConnection();
}
/**
* Attach NotificationListener that can be used to listen notifications
* emitted by MBean server.
*
* @param jmxConnector The MBean server connector.
* @param mbeanClass The class for which an MBean exists.
* @param notificationListener User provided NotificationListener instance.
* @throws InstanceNotFoundException
* @throws Exception
*/
static public void addNotificationListener(JMXConnector jmxConnector,
Class<?> mbeanClass, NotificationListener notificationListener)
throws InstanceNotFoundException, Exception
{
MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection();
ObjectName objectName = generateMBeanObjectName(mbeanClass);
mbsc.addNotificationListener(objectName, notificationListener, null,
null);
}
/**
* Remove NotificationListener from this MBean.
*
* @param jmxConnector The MBean server connector.
* @param mbeanInterface The MBean interface this instance implements.
* @param mbeanName A custom name for the MBean.
* @param notificationListener Previously added NotificationListener
* instance.
* @throws Exception
*/
static public void removeNotificationListener(JMXConnector jmxConnector,
Class<?> mbeanInterface, String mbeanName,
NotificationListener notificationListener, boolean ignored)
throws Exception
{
MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection();
ObjectName objectName = generateMBeanObjectName(
mbeanInterface.getName(), mbeanName);
mbsc.removeNotificationListener(objectName, notificationListener);
}
/**
* Remove NotificationListener from this MBean.
*
* @param jmxConnector The MBean server connector.
* @param mbeanClass The class for which an MBean exists.
* @param notificationListener Previously added NotificationListener
* instance.
* @throws Exception
*/
static public void removeNotificationListener(JMXConnector jmxConnector,
Class<?> mbeanClass, NotificationListener notificationListener)
throws Exception
{
MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection();
ObjectName objectName = generateMBeanObjectName(mbeanClass);
mbsc.removeNotificationListener(objectName, notificationListener);
}
// Create a service address.addNotificationListener
private static String generateServiceAddress(String host, int beanPort,
int registryPort, String serviceName)
{
String serviceAddress = null;
if (beanPort == -1)
{
serviceAddress = String.format(
"service:jmx:rmi:///jndi/rmi://%s:%d/%s", host,
registryPort, serviceName);
}
else
{
serviceAddress = String.format(
"service:jmx:rmi://%s:%d/jndi/rmi://%s:%d/%s", host,
beanPort, host, registryPort, serviceName);
}
if (logger.isDebugEnabled())
{
logger.debug("Service address for mbean is: " + serviceAddress);
}
return serviceAddress;
}
// Create an MBean name.
public static ObjectName generateMBeanObjectName(Class<?> mbeanClass)
throws Exception
{
String className = mbeanClass.getName();
String type = className;
String domain = "default";
int lastPeriod = className.lastIndexOf('.');
if (lastPeriod != -1)
{
domain = className.substring(0, lastPeriod);
type = className.substring(className.lastIndexOf('.') + 1);
}
String name = String.format("%s:type=%s", domain, type);
ObjectName objName = new ObjectName(name);
if (logger.isDebugEnabled())
{
logger.debug("ObjectName is: " + objName.toString());
}
return objName;
}
// Create an MBean name.
public static ObjectName generateMBeanObjectName(String mbeanName,
String typeName) throws Exception
{
ObjectName name = new ObjectName(mbeanName + ":type=" + typeName);
if (logger.isDebugEnabled())
{
logger.debug("ObjectName is: " + name.toString());
}
return name;
}
public void handleNotification(Notification notification, Object handback)
{
ObjectName objectName = ((MBeanServerNotification) notification)
.getMBeanName();
if (logger.isDebugEnabled())
{
logger.debug(String.format(
"MBean Added to the MBean server at %s:%d, ObjectName=%s",
host, registryPort, objectName));
}
}
public static DynamicMBeanHelper createHelper(Class<?> mbeanClass)
throws Exception
{
ObjectName mbeanName = generateMBeanObjectName(mbeanClass);
MBeanInfo info = ManagementFactory.getPlatformMBeanServer()
.getMBeanInfo(mbeanName);
DynamicMBeanHelper helper = new DynamicMBeanHelper(mbeanClass,
mbeanName, info);
return helper;
}
/**
* Get the hostname from the local host. Returns the IP address, in textual
* form, if no hostname can be found.
*
* @return the hostname for the local host
*/
public static String getHostName()
{
String hostName = null;
try
{
hostName = InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException e)
{
// Intentionally blank
}
return hostName;
}
public Registry getRegistry()
{
if (rmiRegistry == null)
rmiRegistry = locateDefaultRegistry();
return rmiRegistry;
}
public int getBeanPort()
{
return beanPort;
}
public static DynamicMBeanHelper createHelper(Class<?> mbeanClass,
String alias) throws Exception
{
ObjectName mbeanName = generateMBeanObjectName(mbeanClass.getName(),
alias);
// ObjectName mbeanName = generateMBeanObjectName(mbeanClass);
MBeanInfo info = ManagementFactory.getPlatformMBeanServer()
.getMBeanInfo(mbeanName);
DynamicMBeanHelper helper = new DynamicMBeanHelper(mbeanClass,
mbeanName, info);
return helper;
}
}