Author: pero Date: Mon Jun 4 23:19:13 2007 New Revision: 544401 URL: http://svn.apache.org/viewvc?view=rev&rev=544401 Log: Add JMXAdaptorLifecycleListener to start JMX Connector with fix naming and data port. This feature is needed to have stable remote access as your local firewall is activ.
Added: tomcat/container/tc5.5.x/catalina/src/share/org/apache/catalina/mbeans/JMXAdaptorLifecycleListener.java (with props) Modified: tomcat/container/tc5.5.x/webapps/docs/changelog.xml tomcat/container/tc5.5.x/webapps/docs/monitoring.xml Added: tomcat/container/tc5.5.x/catalina/src/share/org/apache/catalina/mbeans/JMXAdaptorLifecycleListener.java URL: http://svn.apache.org/viewvc/tomcat/container/tc5.5.x/catalina/src/share/org/apache/catalina/mbeans/JMXAdaptorLifecycleListener.java?view=auto&rev=544401 ============================================================================== --- tomcat/container/tc5.5.x/catalina/src/share/org/apache/catalina/mbeans/JMXAdaptorLifecycleListener.java (added) +++ tomcat/container/tc5.5.x/catalina/src/share/org/apache/catalina/mbeans/JMXAdaptorLifecycleListener.java Mon Jun 4 23:19:13 2007 @@ -0,0 +1,355 @@ +/* + * 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 org.apache.catalina.mbeans; + +import java.util.HashMap; +import java.util.Properties; +import java.io.IOException; +import java.io.FileInputStream; +import java.io.FileNotFoundException; + +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleEvent; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.core.StandardServer; + +import java.net.InetAddress; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.UnicastRemoteObject; +import javax.rmi.ssl.SslRMIServerSocketFactory; +import javax.rmi.ssl.SslRMIClientSocketFactory; + +import java.lang.management.ManagementFactory; +import javax.management.MBeanServer; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.rmi.RMIConnectorServer; + +/** + * Start JSR160 JMX Adapter with naming and jmx port! Add only as Server Listner + * to your tomcat <i>server.xml</i> <br/><pre> + * <Server ...> + * ... + * <Listener className="org.apache.catalina.mbeans.JMXAdaptorLifecycleListener"<br/> + * namingPort="8083" port="8084" host="myhost" /> + * ... + * </Server> + * </pre> + * + * You can use normal jmx system properties from command line or jmx config file: + * <ul> + * <li><code>-Dcom.sun.management.jmxremote.authenticate=true</code></li> + * <li><code>-Dcom.sun.management.jmxremote.ssl=false</code></li> + * <li><code>-Dcom.sun.management.jmxremote.access.file=$CATALINA_BASE/conf/access.file</code></li> + * <li><code>-Dcom.sun.management.jmxremote.password.file=$CATALINA_BASE/conf/password.file</code></li> + * <li><code>-Dcom.sun.management.config.file=$CATALINA_BASE/conf/jmx.properties</code></li> + * </ul> + * <br/> + * Then run jconsole with: + * <code> + * jconsole service:jmx:rmi://myhost:8084/jndi/rmi://myhost:8083/server + * </code> + * + * <p> + * It would be be better if this was built into Tomcat as a configuration + * option, rather than having to do it as part of every Tomcat instance. + * </p> + * <p>Origanal code idea comes from George Lindholm read + * <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=39055">Tomcat Bug 39055<a/> + * and other helpful links are:<br/> + * <ul> + * <li><a href="http://today.java.net/pub/a/today/2005/11/15/using-jmx-to-manage-web-applications.html">Using Web Apps</a></li> + * <li><a href="http://java.sun.com/j2se/1.5.0/docs/guide/management/agent.html#SSL_enabled">JVM 1.5 JMX Guide</a></li> + * </p> + * @author Peter Rossbach + * @author Juergen Herrmann + */ +public class JMXAdaptorLifecycleListener implements LifecycleListener { + + /** + * Logger + */ + private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory + .getLog(JMXAdaptorLifecycleListener.class); + + /** + * The descriptive information string for this implementation. + */ + private static final String info = "org.apache.catalina.mbeans.JMXAdaptorLifecycleListener/1.0"; + + private boolean enabled = true; + + private int namingPort = 0; + + private int port = 0; + + private String host = null; + + private String jmxUrl = null; + + private JMXConnectorServer connectorServer = null; + + private Properties managementProperties = null; + + /** + * create new jmx adaptor and read properties from file. + * Use jvm property <code>-Dcom.sun.management.config.file=xxx</code> as file. + * + */ + public JMXAdaptorLifecycleListener() { + final String configProperty = "com.sun.management.config.file"; + String configFileName = System.getProperty(configProperty); + + if (configFileName != null) { + try { + FileInputStream configFile = new FileInputStream(configFileName); + try { + managementProperties = new Properties(); + managementProperties.load(configFile); + } finally { + configFile.close(); + } + } catch (FileNotFoundException ex) { + log.error("Cannot open " + configFileName, ex); + } catch (IOException ex) { + log.error("Error while reading " + configFileName, ex); + } + } + } + + /** + * @return Returns the host. + */ + public String getHost() { + return host; + } + + /** + * @paramhost The host to set. + */ + public void setHost(String host) { + this.host = host; + } + + /** + * @return Returns the port. + */ + public int getPort() { + return port; + } + + /** + * @param port The port to set. + */ + public void setPort(int port) { + if (port < 1 || 65535 < port) { + log.warn("Illegal port value " + port); + port = 0; + } + this.port = port; + } + + /** + * @return Returns the namingPort. + */ + public int getNamingPort() { + return namingPort; + } + + /** + * @param namingPort The namingPort to set. + */ + public void setNamingPort(int namingPort) { + this.namingPort = namingPort; + if (namingPort < 1 || 65535 < namingPort) { + log.warn("Illegal namingPort value " + namingPort); + namingPort = 0; + } + this.namingPort = namingPort; + } + + /** + * @return Returns the enabled. + */ + public boolean isEnabled() { + return enabled; + } + + /** + * @param enabled The enabled to set. + */ + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + /** + * @return the jmxUrl + */ + public String getJmxUrl() { + return jmxUrl; + } + + /** + * Return descriptive information about this Listener implementation and the + * corresponding version number, in the format + * <code><description>/<version></code>. + */ + public String getInfo() { + + return (info); + + } + + /* + * Start/Stop JSR 160 Adaptor + * + * @see org.apache.catalina.LifecycleListener#lifecycleEvent(org.apache.catalina.LifecycleEvent) + */ + public void lifecycleEvent(LifecycleEvent event) { + Object source = event.getSource(); + if (!(source instanceof StandardServer)) + return; + + if (Lifecycle.AFTER_START_EVENT.equals(event.getType())) { + start(); + } + if (Lifecycle.BEFORE_STOP_EVENT.equals(event.getType())) { + stop(); + } + } + + /** + * stop jmx connector at tomcat normale shutdown + * + */ + protected void stop() { + if (connectorServer != null) { + if (log.isInfoEnabled()) + log.info("JMXConnectorServer stopping on " + jmxUrl); + + try { + // Stop connector, else shutdown takes a lot longer + connectorServer.stop(); + jmxUrl = null; + } catch (IOException ex) { + // We always get this (why?), so just trace it + log.error("Error while stopping remote JMX connector", ex); + } + connectorServer = null; + } + } + + /** + * get jmx config parameter from jmx config file or system property. + * @param name + * @return config parameter value + */ + protected String getConfigProperty(String name) { + String result = null; + if (managementProperties != null) { + result = managementProperties.getProperty(name); + } + if (result == null) { + result = System.getProperty(name); + } + return result; + } + + /** + * Start JMX connector and local name registry + * + */ + public void start() { + + if (enabled) { + if (namingPort == 0 || port == 0) + return; + + try { + if (host == null || "".equals(host)) { + final InetAddress address = InetAddress.getLocalHost(); + host = address.getHostName(); + } + + // naming + LocateRegistry.createRegistry(namingPort); + // tomcat normal mbeanserver + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + + // read ssl config + HashMap env = new HashMap(); + final String sslProperty = "com.sun.management.jmxremote.ssl"; + String value = getConfigProperty(sslProperty); + if (Boolean.valueOf(value).booleanValue()) { + if (log.isInfoEnabled()) + log.info("Activated SSL communication"); + 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); + } + + // read auth config + final String authenticateProperty = "com.sun.management.jmxremote.authenticate"; + value = getConfigProperty(authenticateProperty); + if (log.isTraceEnabled()) + log.trace(authenticateProperty + " is " + value); + + if (Boolean.valueOf(value).booleanValue()) { + final String accessFileProperty = "com.sun.management.jmxremote.access.file"; + value = getConfigProperty(accessFileProperty); + if (log.isTraceEnabled()) + log.trace(accessFileProperty + " is " + value); + if (value != null) { + env.put("jmx.remote.x.access.file", value); + } + + final String passwordFileProperty = "com.sun.management.jmxremote.password.file"; + value = getConfigProperty(passwordFileProperty); + if (log.isTraceEnabled()) + log.trace(passwordFileProperty + " is " + value); + if (value != null) { + env.put("jmx.remote.x.password.file", value); + } + } else { + log.warn("Unsafe JMX remote access!"); + } + + // create jmx adaptor + jmxUrl = "service:jmx:rmi://" + host + ":" + port + + "/jndi/rmi://" + host + ":" + namingPort + "/server"; + final JMXServiceURL url = new JMXServiceURL(jmxUrl); + connectorServer = JMXConnectorServerFactory + .newJMXConnectorServer(url, env, mbs); + + // start jmx adaptor + try { + connectorServer.start(); + if (log.isInfoEnabled()) + log.info("JMXConnectorServer started on " + jmxUrl); + } catch (IOException ex) { + log.warn("Cannot start JMXConnectorServer on " + jmxUrl, ex); + } + } catch (Exception ex) { + log.error("Error while setting up remote JMX connector", ex); + } + } + } + +} Propchange: tomcat/container/tc5.5.x/catalina/src/share/org/apache/catalina/mbeans/JMXAdaptorLifecycleListener.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/container/tc5.5.x/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/container/tc5.5.x/webapps/docs/changelog.xml?view=diff&rev=544401&r1=544400&r2=544401 ============================================================================== --- tomcat/container/tc5.5.x/webapps/docs/changelog.xml (original) +++ tomcat/container/tc5.5.x/webapps/docs/changelog.xml Mon Jun 4 23:19:13 2007 @@ -95,6 +95,11 @@ <fix> Allow for a forward/include to call getAttributeNames on the Request in a sandbox. (billbarker) </fix> + <add> + <bug>39055</bug>: Add JMXAdaptorLifecycleListener to start JMX Connector with fix naming and data port. + This feature is needed to have stable remote access as your local firewall is activ. The adaptor read all + standard JMX system properties (-Dcom.sun.management.jmxremote). Feature provided by George Lindholm and Juergen Herrman (pero) + </add> </changelog> </subsection> <subsection name="Webapps"> Modified: tomcat/container/tc5.5.x/webapps/docs/monitoring.xml URL: http://svn.apache.org/viewvc/tomcat/container/tc5.5.x/webapps/docs/monitoring.xml?view=diff&rev=544401&r1=544400&r2=544401 ============================================================================== --- tomcat/container/tc5.5.x/webapps/docs/monitoring.xml (original) +++ tomcat/container/tc5.5.x/webapps/docs/monitoring.xml Mon Jun 4 23:19:13 2007 @@ -63,9 +63,21 @@ </ol> <b>Note:</b>The JSR 160 JMX-Adaptor opens a second data protocol port. That is a problem when you have installed a local firewall. However, there is at least one possible - workaround: using a custom JMXConnectorServer. The code for this is available - at <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=39055" title="Bugzila 39055">Bugzilla 39055</a>. + workaround: using a custom JMXConnectorServer.</p> + <p>Start a JMX Adaptor with fix data port is supported with Tomcst 5.5.24 release: + <source> +<Server ...> +... +<Listener className="org.apache.catalina.mbeans.JMXAdaptorLifecycleListener" + namingPort="8083" port="8084" host="myhost" /> +... +</Server> + </source> + You can use all JMX system properties (<i>com.sun.management.jmxremote.xxx</i>) to configure the adaptor :-) <br/>At your remote jconsole + call the jmx adaptor with following command <br/><i>jconsole service:jmx:rmi://myhost:8084/jndi/rmi://myhost:8083/server</i> </p> + + <p>Activate JMX MX4J Http Adaptor with Java 1.4: <ol> <li>Install the tomcat compat package</li> @@ -99,7 +111,7 @@ <section name="Manage Tomcat with JMX remote Ant Tasks"> <p>For simple tomcat ant task usage with ant 1.6.x we have integrate import and antlib support.</p> - <p><b>antlib</b>Copy your catalina-ant.jar from $CATALINA_HOME/server/lib to $ANT_HOME/lib.</p> + <p><b>antlib support:</b><br/> Copy your catalina-ant.jar from $CATALINA_HOME/server/lib to $ANT_HOME/lib.</p> <p>Following example show the JMX Accessor usage:</p> <table border="1"> <tr><td><p><pre> --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]