You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by gi...@apache.org on 2005/12/23 17:18:06 UTC

svn commit: r358825 - in /cocoon/trunk: legal/ lib/core/ src/java/org/apache/cocoon/components/ src/java/org/apache/cocoon/core/container/ src/java/org/apache/cocoon/util/

Author: giacomo
Date: Fri Dec 23 08:17:55 2005
New Revision: 358825

URL: http://svn.apache.org/viewcvs?rev=358825&view=rev
Log:
added initial JMX support to the core

Added:
    cocoon/trunk/legal/mx4j-jmx-3.0.1.license.txt
    cocoon/trunk/lib/core/mx4j-jmx-3.0.1.jar   (with props)
    cocoon/trunk/src/java/org/apache/cocoon/util/JMXUtils.java
Modified:
    cocoon/trunk/src/java/org/apache/cocoon/components/ComponentInfo.java
    cocoon/trunk/src/java/org/apache/cocoon/core/container/CoreServiceManager.java

Added: cocoon/trunk/legal/mx4j-jmx-3.0.1.license.txt
URL: http://svn.apache.org/viewcvs/cocoon/trunk/legal/mx4j-jmx-3.0.1.license.txt?rev=358825&view=auto
==============================================================================
--- cocoon/trunk/legal/mx4j-jmx-3.0.1.license.txt (added)
+++ cocoon/trunk/legal/mx4j-jmx-3.0.1.license.txt Fri Dec 23 08:17:55 2005
@@ -0,0 +1,51 @@
+/* ====================================================================
+ * The MX4J License, Version 1.0
+ *
+ * Copyright (c) 2001 MX4J.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        MX4J project (http://mx4j.sourceforge.net)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "MX4J" and "mx4j" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact biorn_steedom@users.sourceforge.net
+ *
+ * 5. Products derived from this software may not be called "MX4J",
+ *    nor may "MX4J" appear in their name, without prior written
+ *    permission of Simone Bordet.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CARLOS QUIROZ OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of MX4J.  For more information on
+ * MX4J, please see
+ * <http://mx4j.sourceforge.net>.
+ */

Added: cocoon/trunk/lib/core/mx4j-jmx-3.0.1.jar
URL: http://svn.apache.org/viewcvs/cocoon/trunk/lib/core/mx4j-jmx-3.0.1.jar?rev=358825&view=auto
==============================================================================
Binary file - no diff available.

Propchange: cocoon/trunk/lib/core/mx4j-jmx-3.0.1.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/ComponentInfo.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/ComponentInfo.java?rev=358825&r1=358824&r2=358825&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/ComponentInfo.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/ComponentInfo.java Fri Dec 23 08:17:55 2005
@@ -16,6 +16,7 @@
 package org.apache.cocoon.components;
 
 import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.cocoon.core.container.CoreServiceManager;
 
 /**
  * Meta-information about a service
@@ -42,6 +43,8 @@
     private String serviceClassName;
     private Configuration configuration;
     private String loggerCategory;
+    private String jmxDomain;
+    private String jmxName;
 
     public ComponentInfo() {
         this.model = MODEL_PRIMITIVE;
@@ -175,6 +178,8 @@
         this.setDestroyMethodName(attr.getAttribute("destroy", null));
         // logging
         this.setLoggerCategory(attr.getAttribute("logger", null));
+        this.setJmxDomain(attr.getAttribute(CoreServiceManager.JMX_DOMAIN_ATTR_NAME, null));
+        this.setJmxName(attr.getAttribute(CoreServiceManager.JMX_NAME_ATTR_NAME, null));
     }
 
     public ComponentInfo duplicate() {
@@ -187,6 +192,8 @@
         info.serviceClassName = this.serviceClassName;
         info.configuration = this.configuration;
         info.loggerCategory = this.loggerCategory;
+        info.jmxDomain = this.jmxDomain;
+        info.jmxName = this.jmxName;
 
         return info;
     }
@@ -203,5 +210,39 @@
      */
     public void setLoggerCategory(String loggerCategory) {
         this.loggerCategory = loggerCategory;
+    }
+    
+    /**
+     * @return The JMX domain name
+     */
+    public String getJmxDomain() {
+        if (this.jmxDomain == null && this.configuration != null) {
+            this.setJmxDomain(getConfiguration().getAttribute(CoreServiceManager.JMX_DOMAIN_ATTR_NAME, null));
+        }
+        return this.jmxDomain;
+    }
+    
+    /**
+     * @param The JMX domain name
+     */
+    public void setJmxDomain(final String jmxDomain) {
+        this.jmxDomain = jmxDomain;
+    }
+    
+    /**
+     * @return The JMX object name (without domain prefix)
+     */
+    public String getJmxName() {
+        if (this.jmxName == null && this.configuration != null) {
+            this.setJmxName(getConfiguration().getAttribute(CoreServiceManager.JMX_NAME_ATTR_NAME, null));
+        }
+        return this.jmxName;
+    }
+    
+    /**
+     * @param The JMX object name (without domain prefix)
+     */
+    public void setJmxName(final String jmxName) {
+        this.jmxName = jmxName;
     }
 }

Modified: cocoon/trunk/src/java/org/apache/cocoon/core/container/CoreServiceManager.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/core/container/CoreServiceManager.java?rev=358825&r1=358824&r2=358825&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/core/container/CoreServiceManager.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/core/container/CoreServiceManager.java Fri Dec 23 08:17:55 2005
@@ -56,6 +56,7 @@
 import org.apache.cocoon.core.source.SimpleSourceResolver;
 import org.apache.cocoon.matching.helpers.WildcardHelper;
 import org.apache.cocoon.sitemap.impl.ComponentManager;
+import org.apache.cocoon.util.JMXUtils;
 import org.apache.excalibur.source.Source;
 import org.apache.excalibur.source.SourceResolver;
 import org.apache.excalibur.source.TraversableSource;
@@ -70,6 +71,15 @@
         extends AbstractLogEnabled
         implements Contextualizable, ThreadSafe, Disposable, Initializable, ServiceManager, Configurable {
 
+    /** The attribute containing the JMX domain name */
+    public static final String JMX_DOMAIN_ATTR_NAME = "jmx-domain";
+
+    /** The attribute containing the JMX domain name */
+    public static final String JMX_NAME_ATTR_NAME = "jmx-name";
+
+    /** The attribute containing the JMX domain name */
+    public static final String JMX_DEFAULT_DOMAIN_NAME = "Cocoon";
+    
     /**
      * An empty configuration object, that can be used when no configuration is known but one
      * is needed.
@@ -117,6 +127,8 @@
     /** The resolver used to resolve includes. It is lazily loaded in {@link #setupSourceResolver()}. */
     private SourceResolver cachedSourceResolver;
 
+    private String jmxDefaultDomain = null;
+    
     /** Create the ServiceManager with a parent ServiceManager */
     public CoreServiceManager( final ServiceManager parent ) {
         this(parent, null);
@@ -188,7 +200,6 @@
         // This is the default logger for all components defined with this sitemap/manager.
         if ( configuration.getAttribute("logger", null) != null ) {
             this.enableLogging(this.loggerManager.getLoggerForCategory(configuration.getAttribute("logger")));
-
         }
         this.componentEnv = new ComponentEnvironment(this.classloader, getLogger(), this.roleManager, this.loggerManager, this.context, this);
 
@@ -206,6 +217,9 @@
             currentURI = this.location.substring(0, pos-1);
         }
 
+        // find possible JMX domain name
+        this.jmxDefaultDomain = configuration.getAttribute(JMX_DOMAIN_ATTR_NAME, null);
+
         try {
             // and load configuration with a empty list of loaded configurations
             parseConfiguration(configuration, currentURI, new HashSet());
@@ -216,6 +230,19 @@
     }
 
     /**
+     * @return The default JMX domain name
+     */
+    public String getJmxDefaultDomain() {
+        if (this.jmxDefaultDomain == null) {
+            if (this.parentManager instanceof CoreServiceManager) {
+                return ((CoreServiceManager)this.parentManager).getJmxDefaultDomain();
+            }
+            return JMX_DEFAULT_DOMAIN_NAME;
+        }
+        return this.jmxDefaultDomain;
+    }
+    
+    /**
      * Return the service manager logger.
      */
     public Logger getServiceManagerLogger() {
@@ -662,22 +689,28 @@
             }
         }
 
+        ComponentHandler handler;
         if (lazyLoad) {
-            return new LazyHandler(role, className, configuration, componentEnv);
-        }
-        
-        // FIXME - we should ensure that we always get an info
-        ComponentInfo info;
-        if ( baseInfo != null ) {
-            info = baseInfo.duplicate();
+            handler = new LazyHandler(role, className, configuration, componentEnv);
         } else {
-            info = new ComponentInfo();
-            info.fill(configuration);
-        }
-        info.setConfiguration(configuration);
-        info.setServiceClassName(className);
+            
+            // FIXME - we should ensure that we always get an info
+            ComponentInfo info;
+            if ( baseInfo != null ) {
+                info = baseInfo.duplicate();
+            } else {
+                info = new ComponentInfo();
+                info.fill(configuration);
+                info.setJmxDomain(JMXUtils.findJmxDomain(info.getJmxDomain(), this));
+                info.setJmxName(JMXUtils.findJmxName(info.getJmxName(), className));
+            }
+            info.setConfiguration(configuration);
+            info.setServiceClassName(className);
 
-        return AbstractComponentHandler.getComponentHandler(role, this.componentEnv, info);
+            handler = AbstractComponentHandler.getComponentHandler(role, this.componentEnv, info);
+            JMXUtils.setupJmxFor(handler, info, getLogger());
+        }
+        return handler;
     }
 
     private void parseConfiguration(final Configuration configuration, String contextURI, Set loadedURIs) 
@@ -712,6 +745,8 @@
                 if (className == null) {
                     // Get the default class name for this role
                     final ComponentInfo info = roleManager.getDefaultServiceInfoForRole(role);
+                    info.setJmxDomain(JMXUtils.findJmxDomain(info.getJmxDomain(), this));
+                    info.setJmxName(JMXUtils.findJmxName(info.getJmxName(), info.getServiceClassName()));
                     if (info == null) {
                         throw new ConfigurationException("Cannot find a class for role " + role + " at " + componentConfig.getLocation());
                     }

Added: cocoon/trunk/src/java/org/apache/cocoon/util/JMXUtils.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/util/JMXUtils.java?rev=358825&view=auto
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/util/JMXUtils.java (added)
+++ cocoon/trunk/src/java/org/apache/cocoon/util/JMXUtils.java Fri Dec 23 08:17:55 2005
@@ -0,0 +1,197 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * 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.
+ */
+package org.apache.cocoon.util;
+
+import org.apache.avalon.framework.logger.ConsoleLogger;
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.components.ComponentInfo;
+import org.apache.cocoon.core.container.CoreServiceManager;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+/**
+ * Utility methods for JMX
+ *
+ */
+public class JMXUtils {
+    
+    /** The {@link MBeanServer} first found */
+    private static MBeanServer mbeanServer = getInitialMBeanServer();
+    
+    /**
+     * Private c'tor: its a Utility class
+     */
+    private JMXUtils() {
+        super();
+    }
+
+    /** Get the ev. found {@link MBeanServer} */
+    public static MBeanServer getMBeanServer() {
+        return JMXUtils.mbeanServer;
+    }
+    
+    /**
+     * Setup a component for possible JMX managability
+     * @param bean The bean to estabilsh JMX for
+     * @param info The component info
+     */
+    public static ObjectInstance setupJmxFor(final Object bean,
+                                             final ComponentInfo info)
+    {
+        return setupJmxFor(bean, info, new ConsoleLogger(ConsoleLogger.LEVEL_INFO));
+    }
+
+    /**
+     * Setup a component for possible JMX managability
+     * @param bean The bean to estabilsh JMX for
+     * @param info The component info
+     * @param logger The Logger
+     * @return
+     */
+    public static ObjectInstance setupJmxFor(final Object bean,
+                                             final ComponentInfo info,
+                                             final Logger logger)
+    {
+        if (getMBeanServer() != null) {
+            final Class clazz = bean.getClass();
+            final String mbeanClassName = clazz.getName() + "MBean";
+            ObjectName on = null;
+            Object comp = null;
+            try {
+                final Class mbeanClass = clazz.getClassLoader().loadClass(mbeanClassName);
+                final Constructor ctor = mbeanClass.getConstructor(new Class[] {clazz});
+                final Object mbean = ctor.newInstance( new Object[] {bean});
+                final String jmxDomain = info.getJmxDomain();
+                String jmxGroup = info.getConfiguration().getAttribute( CoreServiceManager.JMX_NAME_ATTR_NAME, null );
+                if (jmxGroup == null ) {
+                    // otherwise construct one from the service class name
+                    final StringBuffer sb = new StringBuffer();
+                    final List groups = new ArrayList();
+                    int i = info.getServiceClassName().indexOf('.');
+                    int j = 0;
+                    while(i > 0) {
+                        groups.add(info.getServiceClassName().substring(j,i));
+                        j = i+1;
+                        i = info.getServiceClassName().indexOf('.', i+1);
+                    }
+                    groups.add(info.getServiceClassName().substring(j));
+                    for (i = 0; i < groups.size()-1; i++) {
+                        sb.append("group");
+                        if (i > 0) {
+                            sb.append(i);
+                        }
+                        sb.append('=');
+                        sb.append(groups.get(i));
+                        sb.append(',');
+                    }
+                    sb.append("item=").append(groups.get(groups.size()-1));
+                    jmxGroup = sb.toString();
+                }
+                on = new ObjectName( jmxDomain + ":" + jmxGroup );
+                return mbeanServer.registerMBean(mbean,on);
+            } catch (final ClassNotFoundException cnfe) {
+                // happens if a component doesn't have a MBean to support it for management
+                logger.debug( "Class "+info.getServiceClassName()+" doesn't have a supporting MBean called " + mbeanClassName );
+            } catch (final NoSuchMethodException nsme) {
+                logger.warn( "MBean " + mbeanClassName + " doesn't have a constructor that accepts an instance of " + info.getServiceClassName(), nsme);
+            } catch (final InvocationTargetException ite) {
+                logger.warn( "Cannot instantiate class " + mbeanClassName, ite);
+            } catch (final InstantiationException ie) {
+                logger.warn( "Cannot instantiate class " + mbeanClassName, ie);
+            } catch (final IllegalAccessException iae) {
+                logger.warn( "Cannot instantiate class " + mbeanClassName, iae);
+            } catch (final MalformedObjectNameException mone) {
+                logger.warn( "Invalid ObjectName '" + on + "' for MBean " + mbeanClassName, mone);
+            } catch (final InstanceAlreadyExistsException iaee) {
+                logger.warn( "Instance for MBean " + mbeanClassName + "already exists", iaee);
+            } catch (final NotCompliantMBeanException ncme) {
+                logger.warn( "Not compliant MBean " + mbeanClassName, ncme);
+            } catch (final MBeanRegistrationException mre) {
+                logger.warn( "Cannot register MBean " + mbeanClassName, mre);
+            }
+        }
+        return null;
+    }
+
+    public static String findJmxDomain(final String pJmxDomain, final ServiceManager serviceManager) {
+        // try to find a JMX domain name first from this component configuration give as parameter
+        String jmxDomain = pJmxDomain;
+        if( jmxDomain == null )
+        {
+            // next from the CoreServiceManager managing this component
+            if( serviceManager != null && serviceManager instanceof CoreServiceManager )
+            {
+                // next from the CoreServiceManager managing this component
+                jmxDomain = ((CoreServiceManager)serviceManager).getJmxDefaultDomain();
+            } else {
+                // otherwise use default one
+                jmxDomain = CoreServiceManager.JMX_DEFAULT_DOMAIN_NAME;
+            }
+        }
+        return jmxDomain;
+    }
+
+    public static String findJmxName(final String pJmxName, final String pClassName) {
+        String jmxName = pJmxName;
+        final String className = (pClassName == null ? "unknown" : pClassName);
+        if (jmxName == null ) {
+            // otherwise construct one from the service class name
+            final StringBuffer sb = new StringBuffer();
+            final List groups = new ArrayList();
+            int i = className.indexOf('.');
+            int j = 0;
+            while(i > 0) {
+                groups.add(className.substring(j,i));
+                j = i+1;
+                i = className.indexOf('.', i+1);
+            }
+            groups.add(className.substring(j));
+            for (i = 0; i < groups.size()-1; i++) {
+                sb.append("group");
+                if (i > 0) {
+                    sb.append(i);
+                }
+                sb.append('=');
+                sb.append(groups.get(i));
+                sb.append(',');
+            }
+            sb.append("item=").append(groups.get(groups.size()-1));
+            jmxName = sb.toString();
+        }
+        return jmxName;
+    }
+    
+    private static MBeanServer getInitialMBeanServer() {
+        final List servers = MBeanServerFactory.findMBeanServer(null);
+        if( servers.size() > 0 ) {
+            return (MBeanServer)servers.get(0);
+        }
+        return null;
+    }
+}