Java tutorial
package org.red5.server.jmx; /* * RED5 Open Source Flash Server - http://www.osflash.org/red5 * * Copyright (c) 2006-2007 by respective authors (see below). All rights reserved. * * This library is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any later * version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ import java.io.File; import java.io.IOException; import java.rmi.ConnectException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.util.HashMap; import java.util.Set; import javax.management.InstanceAlreadyExistsException; import javax.management.MBeanServer; import javax.management.Notification; import javax.management.NotificationListener; import javax.management.ObjectName; import javax.management.StandardMBean; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; import javax.management.remote.rmi.RMIConnectorServer; import javax.rmi.ssl.SslRMIClientSocketFactory; import javax.rmi.ssl.SslRMIServerSocketFactory; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.sun.jdmk.comm.HtmlAdaptorServer; /** * Provides the connection adapters as well as registration and * unregistration of MBeans. * * @author The Red5 Project (red5@osflash.org) * @author Paul Gregoire (mondain@gmail.com) */ public class JMXAgent implements NotificationListener { private static JMXConnectorServer cs; private static boolean enableHtmlAdapter; private static boolean enableRmiAdapter; private static boolean startRegistry; private static boolean enableSsl; private static boolean enableMinaMonitor; private static HtmlAdaptorServer html; private static String htmlAdapterPort = "8082"; private static Logger log = LoggerFactory.getLogger(JMXAgent.class); private static MBeanServer mbs; private static String rmiAdapterPort = "9999"; private static String remotePasswordProperties; private static String remoteAccessProperties; static { //in the war version the jmxfactory is not created before //registration starts ?? so we check for it here and init //if needed if (null == mbs) { mbs = JMXFactory.getMBeanServer(); } } public static boolean registerMBean(Object instance, String className, Class interfaceClass) { boolean status = false; try { String cName = className; if (cName.indexOf('.') != -1) { cName = cName.substring(cName.lastIndexOf('.')).replaceFirst("[\\.]", ""); } log.debug("Register name: {}", cName); mbs.registerMBean(new StandardMBean(instance, interfaceClass), new ObjectName(JMXFactory.getDefaultDomain() + ":type=" + cName)); status = true; } catch (InstanceAlreadyExistsException iaee) { log.debug("Already registered: {}", className); } catch (Exception e) { log.error("Could not register the {} MBean. {}", className, e); } return status; } public static boolean registerMBean(Object instance, String className, Class interfaceClass, ObjectName name) { boolean status = false; try { String cName = className; if (cName.indexOf('.') != -1) { cName = cName.substring(cName.lastIndexOf('.')).replaceFirst("[\\.]", ""); } log.debug("Register name: {}", cName); mbs.registerMBean(new StandardMBean(instance, interfaceClass), name); status = true; } catch (InstanceAlreadyExistsException iaee) { log.debug("Already registered: {}", className); } catch (Exception e) { log.error("Could not register the {} MBean. {}", className, e); } return status; } public static boolean registerMBean(Object instance, String className, Class interfaceClass, String name) { boolean status = false; try { String cName = className; if (cName.indexOf('.') != -1) { cName = cName.substring(cName.lastIndexOf('.')).replaceFirst("[\\.]", ""); } log.debug("Register name: {}", cName); mbs.registerMBean(new StandardMBean(instance, interfaceClass), new ObjectName(JMXFactory.getDefaultDomain() + ":type=" + cName + ",name=" + name)); status = true; } catch (InstanceAlreadyExistsException iaee) { log.debug("Already registered: {}", className); } catch (Exception e) { log.error("Could not register the {} MBean. {}", className, e); } return status; } /** * Shuts down any instanced connectors. */ public static void shutdown() { log.info("Shutting down JMX agent"); if (null != cs) { try { //stop the connector cs.stop(); } catch (Exception e) { log.error("Exception stopping JMXConnector server {}", e); } } if (null != html) { html.stop(); } try { //unregister all the currently registered red5 mbeans String domain = JMXFactory.getDefaultDomain(); for (ObjectName oname : (Set<ObjectName>) mbs.queryNames(new ObjectName(domain + ":*"), null)) { log.debug("Bean domain: {}", oname.getDomain()); if (domain.equals(oname.getDomain())) { unregisterMBean(oname); } } } catch (Exception e) { log.error("Exception unregistering mbeans {}", e); } } /** * Unregisters an mbean instance. If the instance is not found or if a failure occurs, false will be returned. * @param oName * @return */ public static boolean unregisterMBean(ObjectName oName) { boolean unregistered = false; if (null != oName) { try { if (mbs.isRegistered(oName)) { log.debug("Mbean is registered"); mbs.unregisterMBean(oName); //set flag based on registration status unregistered = !mbs.isRegistered(oName); } else { log.debug("Mbean is not currently registered"); } } catch (Exception e) { log.warn("Exception unregistering mbean {}", e); } } log.debug("leaving unregisterMBean..."); return unregistered; } /** * Updates a named attribute of a registered mbean. * * @param oName * @param key * @param value * @return */ public static boolean updateMBeanAttribute(ObjectName oName, String key, int value) { boolean updated = false; if (null != oName) { try { // update the attribute if (mbs.isRegistered(oName)) { mbs.setAttribute(oName, new javax.management.Attribute("key", value)); updated = true; } } catch (Exception e) { log.error("Exception updating mbean attribute", e); } } return updated; } /** * Updates a named attribute of a registered mbean. * * @param oName * @param key * @param value * @return */ public static boolean updateMBeanAttribute(ObjectName oName, String key, String value) { boolean updated = false; if (null != oName) { try { // update the attribute if (mbs.isRegistered(oName)) { mbs.setAttribute(oName, new javax.management.Attribute("key", value)); updated = true; } } catch (Exception e) { log.error("Exception updating mbean attribute", e); } } return updated; } public String getHtmlAdapterPort() { return htmlAdapterPort; } public void handleNotification(Notification notification, Object handback) { log.debug("handleNotification " + notification.getMessage()); } public void init() { //environmental var holder HashMap env = null; if (enableHtmlAdapter) { // setup the adapter try { //instance an html adaptor int port = htmlAdapterPort == null ? 8082 : Integer.valueOf(htmlAdapterPort); html = new HtmlAdaptorServer(port); ObjectName htmlName = new ObjectName( JMXFactory.getDefaultDomain() + ":type=HtmlAdaptorServer,port=" + port); log.debug("Created HTML adaptor on port: " + port); //add the adaptor to the server mbs.registerMBean(html, htmlName); //start the adaptor html.start(); log.info("JMX HTML connector server successfully started"); } catch (Exception e) { log.error("Error in setup of JMX subsystem (HTML adapter)", e); } } else { log.info("JMX HTML adapter was not enabled"); } if (enableRmiAdapter) { // Create an RMI connector server log.debug("Create an RMI connector server"); try { Registry r = null; try { //lookup the registry r = LocateRegistry.getRegistry(Integer.valueOf(rmiAdapterPort)); //ensure we are not already registered with the registry for (String regName : r.list()) { if (regName.equals("red5")) { //unbind connector from rmi registry r.unbind("red5"); } } } catch (RemoteException re) { log.info("RMI Registry server was not found on port " + rmiAdapterPort); //if we didnt find the registry and the user wants it created if (startRegistry) { log.info("Starting an internal RMI registry"); // create registry for rmi port 9999 r = LocateRegistry.createRegistry(Integer.valueOf(rmiAdapterPort)); } } JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:" + rmiAdapterPort + "/red5"); //if SSL is requested to secure rmi connections if (enableSsl) { // Environment map log.debug("Initialize the environment map"); env = new HashMap(); // Provide SSL-based RMI socket factories SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory(); SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory(); env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf); env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf); } //if authentication is requested if (StringUtils.isNotBlank(remoteAccessProperties)) { //if ssl is not used this will be null if (null == env) { env = new HashMap(); } //check the existance of the files //in the war version the full path is needed File file = new File(remoteAccessProperties); if (!file.exists()) { log.debug("Access file was not found on path, will prepend config_root"); //pre-pend the system property set in war startup remoteAccessProperties = System.getProperty("red5.config_root") + '/' + remoteAccessProperties; remotePasswordProperties = System.getProperty("red5.config_root") + '/' + remotePasswordProperties; } env.put("jmx.remote.x.access.file", remoteAccessProperties); env.put("jmx.remote.x.password.file", remotePasswordProperties); } // create the connector server cs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); // add a listener for shutdown cs.addNotificationListener(this, null, null); // Start the RMI connector server log.debug("Start the RMI connector server"); cs.start(); log.info("JMX RMI connector server successfully started"); } catch (ConnectException e) { log.warn("Could not establish RMI connection to port " + rmiAdapterPort + ", please make sure \"rmiregistry\" is running and configured to listen on this port."); } catch (IOException e) { String errMsg = e.getMessage(); if (errMsg.indexOf("NameAlreadyBoundException") != -1) { log.error("JMX connector (red5) already registered, you will need to restart your rmiregistry"); } else { log.error("{}", e); } } catch (Exception e) { log.error("Error in setup of JMX subsystem (RMI connector)", e); } } else { log.info("JMX RMI adapter was not enabled"); } } public void setEnableHtmlAdapter(boolean enableHtmlAdapter) { JMXAgent.enableHtmlAdapter = enableHtmlAdapter; } public void setEnableHtmlAdapter(String enableHtmlAdapterString) { JMXAgent.enableHtmlAdapter = enableHtmlAdapterString.matches("true|on|yes"); } public void setEnableRmiAdapter(boolean enableRmiAdapter) { JMXAgent.enableRmiAdapter = enableRmiAdapter; } public void setEnableRmiAdapter(String enableRmiAdapterString) { JMXAgent.enableRmiAdapter = enableRmiAdapterString.matches("true|on|yes"); } public void setEnableSsl(boolean enableSsl) { JMXAgent.enableSsl = enableSsl; } public void setEnableSsl(String enableSslString) { JMXAgent.enableSsl = enableSslString.matches("true|on|yes"); } public void setHtmlAdapterPort(String htmlAdapterPort) { JMXAgent.htmlAdapterPort = htmlAdapterPort; } public void setRemoteAccessProperties(String remoteAccessProperties) { JMXAgent.remoteAccessProperties = remoteAccessProperties; } public void setRemotePasswordProperties(String remotePasswordProperties) { JMXAgent.remotePasswordProperties = remotePasswordProperties; } public void setRmiAdapterPort(String rmiAdapterPort) { JMXAgent.rmiAdapterPort = rmiAdapterPort; } public void setStartRegistry(boolean startRegistry) { JMXAgent.startRegistry = startRegistry; } public void setEnableMinaMonitor(boolean enableMinaMonitor) { JMXAgent.enableMinaMonitor = enableMinaMonitor; } public void setEnableMinaMonitor(String enableMinaMonitor) { JMXAgent.enableMinaMonitor = enableMinaMonitor.matches("true|on|yes"); } public static boolean isEnableMinaMonitor() { return enableMinaMonitor; } }