Return-Path: Delivered-To: apmail-incubator-felix-commits-archive@www.apache.org Received: (qmail 70495 invoked from network); 19 Jul 2006 08:44:02 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 19 Jul 2006 08:44:02 -0000 Received: (qmail 37378 invoked by uid 500); 19 Jul 2006 08:44:02 -0000 Delivered-To: apmail-incubator-felix-commits-archive@incubator.apache.org Received: (qmail 37332 invoked by uid 500); 19 Jul 2006 08:44:01 -0000 Mailing-List: contact felix-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: felix-dev@incubator.apache.org Delivered-To: mailing list felix-commits@incubator.apache.org Delivered-To: moderator for felix-commits@incubator.apache.org Received: (qmail 37436 invoked by uid 99); 17 Jul 2006 12:15:04 -0000 X-ASF-Spam-Status: No, hits=-8.6 required=10.0 tests=ALL_TRUSTED,INFO_TLD,NO_REAL_NAME X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r422696 [2/4] - in /incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/mosgi/ src/main/java/or... Date: Mon, 17 Jul 2006 12:14:33 -0000 To: felix-commits@incubator.apache.org From: sfrenot@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20060717121440.6DF5B1A9822@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/log/Log.java URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/log/Log.java?rev=422696&view=auto ============================================================================== --- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/log/Log.java (added) +++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/log/Log.java Mon Jul 17 05:14:31 2006 @@ -0,0 +1,248 @@ +/* + * Copyright (C) MX4J. + * All rights reserved. + * + * This software is distributed under the terms of the MX4J License version 1.0. + * See the terms of the MX4J License in the documentation provided with this software. + */ +/* + * Copyright 2005 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.felix.mosgi.jmx.agent.mx4j.log; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Map; +import java.util.HashMap; + +import javax.management.RuntimeOperationsException; + +import org.apache.felix.mosgi.jmx.agent.mx4j.MX4JSystemKeys; + +/** + * Main class for the log service.

+ * The system property 'mx4j.log.priority' controls the priority of the standard logging, and defaults to 'warn'. + * Possible values are, from least to greatest priority, the following (case insensitive): + *

    + *
  • trace + *
  • debug + *
  • info + *
  • warn + *
  • error + *
  • fatal + *
+ * + * @author Simone Bordet + * @version $Revision: 1.1.1.1 $ + */ +public class Log +{ + private static Logger m_prototype; + private static Map m_prototypeMap = new HashMap(); + private static Map m_loggerCache = new HashMap(); + private static int m_defaultPriority; + + static + { + // Do not require callers up in the stack to have this permission + String priority = (String)AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return System.getProperty(MX4JSystemKeys.MX4J_LOG_PRIORITY); + } + }); + if ("trace".equalsIgnoreCase(priority)) {m_defaultPriority = Logger.TRACE;} + else if ("debug".equalsIgnoreCase(priority)) {m_defaultPriority = Logger.DEBUG;} + else if ("info".equalsIgnoreCase(priority)) {m_defaultPriority = Logger.INFO;} + else if ("warn".equalsIgnoreCase(priority)) {m_defaultPriority = Logger.WARN;} + else if ("error".equalsIgnoreCase(priority)) {m_defaultPriority = Logger.ERROR;} + else if ("fatal".equalsIgnoreCase(priority)) {m_defaultPriority = Logger.FATAL;} + else {m_defaultPriority = Logger.INFO;} + + String prototype = (String)AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return System.getProperty(MX4JSystemKeys.MX4J_LOG_PROTOTYPE); + } + }); + if (prototype != null && prototype.trim().length() > 0) + { + try + { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + Class cls = cl.loadClass(prototype); + redirectTo((Logger)cls.newInstance()); + } + catch (Exception x) + { + x.printStackTrace(); + // Do nothing else: the user will see the exception trace + // and understand that the property was wrong + } + } + } + + private Log() {} + + /** + * Sets the default priority for all loggers. + * @see #setDefaultPriority + */ + public static void setDefaultPriority(int priority) + { + switch (priority) + { + case Logger.TRACE: m_defaultPriority = Logger.TRACE; break; + case Logger.DEBUG: m_defaultPriority = Logger.DEBUG; break; + case Logger.INFO: m_defaultPriority = Logger.INFO; break; + case Logger.WARN: m_defaultPriority = Logger.WARN; break; + case Logger.ERROR: m_defaultPriority = Logger.ERROR; break; + case Logger.FATAL: m_defaultPriority = Logger.FATAL; break; + default: m_defaultPriority = Logger.WARN; break; + } + } + + /** + * Returns the default priority. + * @see #setDefaultPriority + */ + public static int getDefaultPriority() + { + return m_defaultPriority; + } + + /** + * Returns a new instance of a Logger associated with the given category; + * if {@link #redirectTo} has been called then a new instance of the prototype Logger, associated with the given + * category, is returned. This requires the prototype Logger class to have a public parameterless + * constructor. + */ + public static Logger getLogger(String category) + { + if (category == null) {throw new RuntimeOperationsException(new IllegalArgumentException("Category cannot be null"));} + + synchronized (m_loggerCache) + { + Logger logger = (Logger)m_loggerCache.get(category); + if (logger == null) + { + // Try to see if a delegate for this category overrides other settings + Logger prototype = null; + synchronized (m_prototypeMap) + { + prototype = (Logger)m_prototypeMap.get(category); + } + if (prototype == null) + { + // Try to see if a prototype for all categories has been set + if (m_prototype != null) + { + logger = createLogger(m_prototype, category); + } + else + { + logger = createLogger(null, category); + } + } + else + { + logger = createLogger(prototype, category); + } + + // cache it + m_loggerCache.put(category, logger); + } + return logger; + } + } + + private static Logger createLogger(Logger prototype, String category) + { + Logger logger = null; + try + { + logger = prototype == null ? new Logger() : (Logger)prototype.getClass().newInstance(); + } + catch (Exception x) + { + x.printStackTrace(); + logger = new Logger(); + } + logger.setCategory(category); + logger.setPriority(m_defaultPriority); + return logger; + } + + /** + * Tells to the log service to use the given delegate Logger to perform logging.
+ * Use a null delegate to remove redirection. + * @see #getLogger + */ + public static void redirectTo(Logger prototype) + { + m_prototype = prototype; + + // Clear the cache, as we want requests for new loggers to be generated again. + synchronized (m_loggerCache) + { + m_loggerCache.clear(); + } + } + + /** + * Tells to the log service to use the given delegate Logger to perform logging for the given + * category (that cannot be null).
+ * Settings made using this method overrides the ones made with {@link #redirectTo(Logger) redirectTo}, meaning + * that it is possible to redirect all the log to a certain delegate but certain categories. + * Use a null delegate to remove redirection for the specified category. + * @see #getLogger + */ + public static void redirectTo(Logger prototype, String category) + { + if (category == null) {throw new RuntimeOperationsException(new IllegalArgumentException("Category cannot be null"));} + + if (prototype == null) + { + // Remove the redirection + synchronized (m_prototypeMap) + { + m_prototypeMap.remove(category); + } + + // Clear the cache for this category + synchronized (m_loggerCache) + { + m_loggerCache.remove(category); + } + } + else + { + // Put or replace + synchronized (m_prototypeMap) + { + m_prototypeMap.put(category, prototype); + } + + // Clear the cache for this category + synchronized (m_loggerCache) + { + m_loggerCache.remove(category); + } + } + } +} Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/log/Logger.java URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/log/Logger.java?rev=422696&view=auto ============================================================================== --- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/log/Logger.java (added) +++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/log/Logger.java Mon Jul 17 05:14:31 2006 @@ -0,0 +1,82 @@ +/* + * Copyright (C) MX4J. + * All rights reserved. + * + * This software is distributed under the terms of the MX4J License version 1.0. + * See the terms of the MX4J License in the documentation provided with this software. + */ + +/* + * Copyright 2005 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.felix.mosgi.jmx.agent.mx4j.log; + +/** + * Base class for logging objects. + * + * @author Simone Bordet + * @version $Revision: 1.1.1.1 $ + */ +public class Logger +{ + public static final int TRACE = 0; + public static final int DEBUG = TRACE + 10; + public static final int INFO = DEBUG + 10; + public static final int WARN = INFO + 10; + public static final int ERROR = WARN + 10; + public static final int FATAL = ERROR + 10; + + private int m_priority = WARN; + private String m_category; + + protected Logger() {} + + public void setPriority(int priority) {m_priority = priority;} + public int getPriority() {return m_priority;} + + public String getCategory() {return m_category;} + protected void setCategory(String category) {m_category = category;} + + public final boolean isEnabledFor(int priority) + { + return priority >= getPriority(); + } + + public final void fatal(Object message) {log(FATAL, message, null);} + public final void fatal(Object message, Throwable t) {log(FATAL, message, t);} + public final void error(Object message) {log(ERROR, message, null);} + public final void error(Object message, Throwable t) {log(ERROR, message, t);} + public final void warn(Object message) {log(WARN, message, null);} + public final void warn(Object message, Throwable t) {log(WARN, message, t);} + public final void info(Object message) {log(INFO, message, null);} + public final void info(Object message, Throwable t) {log(INFO, message, t);} + public final void debug(Object message) {log(DEBUG, message, null);} + public final void debug(Object message, Throwable t) {log(DEBUG, message, t);} + public final void trace(Object message) {log(TRACE, message, null);} + public final void trace(Object message, Throwable t) {log(TRACE, message, t);} + + protected void log(int priority, Object message, Throwable t) + { + if (isEnabledFor(priority)) + { + System.out.println(message); + if (t != null) + { + t.printStackTrace(System.out); + } + } + } +} Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/DefaultClassLoaderRepository.java URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/DefaultClassLoaderRepository.java?rev=422696&view=auto ============================================================================== --- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/DefaultClassLoaderRepository.java (added) +++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/DefaultClassLoaderRepository.java Mon Jul 17 05:14:31 2006 @@ -0,0 +1,133 @@ +/* + * Copyright (C) MX4J. + * All rights reserved. + * + * This software is distributed under the terms of the MX4J License version 1.0. + * See the terms of the MX4J License in the documentation provided with this software. + */ +/* + * Copyright 2005 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.felix.mosgi.jmx.agent.mx4j.server; + +import java.util.ArrayList; + +import javax.management.loading.MLet; + +/** + * Default implementation of a ClassLoaderRepository + * + * @author Simone Bordet + * @version $Revision: 1.2 $ + */ +public class DefaultClassLoaderRepository extends ModifiableClassLoaderRepository implements java.io.Serializable +{ + private static final int WITHOUT = 1; + private static final int BEFORE = 2; + + private ArrayList classLoaders = new ArrayList(); + + public Class loadClass(String className) throws ClassNotFoundException + { + return loadClassWithout(null, className); + } + + public Class loadClassWithout(ClassLoader loader, String className) throws ClassNotFoundException + { + return loadClassFromRepository(loader, className, WITHOUT); + } + + public Class loadClassBefore(ClassLoader loader, String className) throws ClassNotFoundException + { + return loadClassFromRepository(loader, className, BEFORE); + } + + protected void addClassLoader(ClassLoader cl) + { + if (cl == null) return; + + ArrayList loaders = getClassLoaders(); + synchronized (loaders) + { + if (!loaders.contains(cl)) loaders.add(cl); + } + } + + protected void removeClassLoader(ClassLoader cl) + { + if (cl == null) return; + + ArrayList loaders = getClassLoaders(); + synchronized (loaders) + { + loaders.remove(cl); + } + } + + protected ArrayList cloneClassLoaders() + { + ArrayList loaders = getClassLoaders(); + synchronized (loaders) + { + return (ArrayList)loaders.clone(); + } + } + + protected ArrayList getClassLoaders() + { + return classLoaders; + } + + private Class loadClassFromRepository(ClassLoader loader, String className, int algorithm) throws ClassNotFoundException + { + ArrayList copy = cloneClassLoaders(); + for (int i = 0; i < copy.size(); ++i) + { + try + { + ClassLoader cl = (ClassLoader)copy.get(i); + if (cl.equals(loader)) + { + if (algorithm == BEFORE) break; + else continue; + } + + return loadClass(cl, className); + } + catch (ClassNotFoundException ignored) + { + } + } + throw new ClassNotFoundException(className); + } + + private Class loadClass(ClassLoader loader, String className) throws ClassNotFoundException + { + // This is an optimization: if the classloader is an MLet (and not a subclass) + // then the method MLet.loadClass(String, ClassLoaderRepository) is used. + if (loader.getClass() == MLet.class) return ((MLet)loader).loadClass(className, null); + return loader.loadClass(className); + } + + private int getSize() + { + ArrayList loaders = getClassLoaders(); + synchronized (loaders) + { + return loaders.size(); + } + } +} Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/DefaultMBeanRepository.java URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/DefaultMBeanRepository.java?rev=422696&view=auto ============================================================================== --- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/DefaultMBeanRepository.java (added) +++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/DefaultMBeanRepository.java Mon Jul 17 05:14:31 2006 @@ -0,0 +1,79 @@ +/* + * Copyright (C) MX4J. + * All rights reserved. + * + * This software is distributed under the terms of the MX4J License version 1.0. + * See the terms of the MX4J License in the documentation provided with this software. + */ +/* + * Copyright 2005 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.felix.mosgi.jmx.agent.mx4j.server; + +import java.util.HashMap; +import java.util.Iterator; + +import javax.management.ObjectName; + +/** + * Default implementation of the MBeanRepository interface. + * + * @author Simone Bordet + * @version $Revision: 1.1.1.1 $ + */ +class DefaultMBeanRepository implements MBeanRepository +{ + private HashMap m_map = new HashMap(); + + public MBeanMetaData get(ObjectName name) + { + return (MBeanMetaData)m_map.get(name); + } + + public void put(ObjectName name, MBeanMetaData metadata) + { + m_map.put(name, metadata); + } + + public void remove(ObjectName name) + { + m_map.remove(name); + } + + public int size() + { + return m_map.size(); + } + + public Iterator iterator() + { + return m_map.values().iterator(); + } + + public Object clone() + { + try + { + DefaultMBeanRepository repository = (DefaultMBeanRepository)super.clone(); + repository.m_map = (HashMap)m_map.clone(); + return repository; + } + catch (CloneNotSupportedException ignored) + { + return null; + } + } +} Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanIntrospector.java URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanIntrospector.java?rev=422696&view=auto ============================================================================== --- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanIntrospector.java (added) +++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanIntrospector.java Mon Jul 17 05:14:31 2006 @@ -0,0 +1,607 @@ +/* + * Copyright (C) MX4J. + * All rights reserved. + * + * This software is distributed under the terms of the MX4J License version 1.0. + * See the terms of the MX4J License in the documentation provided with this software. + */ +/* + * Copyright 2005 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.felix.mosgi.jmx.agent.mx4j.server; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.HashMap; + +import javax.management.DynamicMBean; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.NotificationBroadcaster; +import javax.management.loading.MLet; + +import org.apache.felix.mosgi.jmx.agent.mx4j.MBeanDescription; +import org.apache.felix.mosgi.jmx.agent.mx4j.MBeanDescriptionAdapter; +import org.apache.felix.mosgi.jmx.agent.mx4j.MX4JSystemKeys; +import org.apache.felix.mosgi.jmx.agent.mx4j.log.Log; +import org.apache.felix.mosgi.jmx.agent.mx4j.log.Logger; +import org.apache.felix.mosgi.jmx.agent.mx4j.util.Utils; + +/** + * Introspector for MBeans.

+ * Main purposes of this class are: + *

    + *
  • Given an mbean, gather all information regarding it into a {@link MBeanMetaData} instance, see {@link #introspect} + *
  • Given an introspected MBeanMetaData, decide if the MBean is compliant or not. + *
  • Act as a factory for {@link MBeanInvoker}s + *
+ * + * The following system properties are used to control this class' behavior: + *
    + *
  • mx4j.strict.mbean.interface, if set to 'no' then are treated as standard MBeans also classes that implement + * management interfaces beloging to different packages or that are inner classes; otherwise are treated as MBeans + * only classes that implement interfaces whose name if the fully qualified name of the MBean class + "MBean" + *
  • mx4j.mbean.invoker, if set to the qualified name of an implementation of the {@link MBeanInvoker} interface, + * then an instance of the class will be used to invoke methods on standard MBeans. By default the generated-on-the-fly + * MBeanInvoker is used; to revert to the version that uses reflection, for example, + * use mx4j.mbean.invoker = {@link ReflectedMBeanInvoker mx4j.server.ReflectedMBeanInvoker} + *
+ * + * @author Simone Bordet + * @version $Revision: 1.1.1.1 $ + */ +public class MBeanIntrospector +{ + private static MBeanDescriptionAdapter DEFAULT_DESCRIPTION = new MBeanDescriptionAdapter(); + + private boolean m_useExtendedMBeanInterfaces = false; + private boolean m_bcelClassesAvailable = false; + private final String m_customMBeanInvoker; + + public MBeanIntrospector() + { + String strict = (String)AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return System.getProperty(MX4JSystemKeys.MX4J_STRICT_MBEAN_INTERFACE); + } + }); + if (strict != null && !Boolean.valueOf(strict).booleanValue()) + { + m_useExtendedMBeanInterfaces = true; + } + + // Try to see if BCEL classes are present + /* SFR : removed BCEL management + try + { + getClass().getClassLoader().loadClass("org.apache.bcel.generic.Type"); + m_bcelClassesAvailable = true; + } + catch (Throwable ignored) + { + } + */ + + // See if someone specified which MBean invoker to use + m_customMBeanInvoker = (String)AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return System.getProperty(MX4JSystemKeys.MX4J_MBEAN_INVOKER); + } + }); + } + + /** + * Introspect the given mbean, storing the results in the given metadata. + * It expects that the mbean field and the classloader field are not null + * @see #isMBeanCompliant + */ + public void introspect(MBeanMetaData metadata) + { + introspectType(metadata); + introspectMBeanInfo(metadata); + } + + /** + * Returns whether the given already introspected metadata is compliant. + * Must be called after {@link #introspect} + */ + public boolean isMBeanCompliant(MBeanMetaData metadata) + { + return isMBeanClassCompliant(metadata) && isMBeanTypeCompliant(metadata) && isMBeanInfoCompliant(metadata); + } + + /** + * Used by the test cases, invoked via reflection, keep it private. + * Introspect the mbean and returns if it's compliant + */ + private boolean testCompliance(MBeanMetaData metadata) + { + introspect(metadata); + return isMBeanCompliant(metadata); + } + + private boolean isMBeanClassCompliant(MBeanMetaData metadata) + { + // From JMX 1.1: no requirements (can be abstract, non public and no accessible constructors) + return true; + } + + private boolean isMBeanTypeCompliant(MBeanMetaData metadata) + { + Logger logger = getLogger(); + + if (metadata.standard && metadata.dynamic) + { + if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("MBean is both standard and dynamic"); + return false; + } + if (!metadata.standard && !metadata.dynamic) + { + if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("MBean is not standard nor dynamic"); + return false; + } + + return true; + } + + private boolean isMBeanInfoCompliant(MBeanMetaData metadata) + { + Logger logger = getLogger(); + + if (metadata.info == null) + { + if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("MBeanInfo is null"); + return false; + } + return true; + } + + private void introspectType(MBeanMetaData metadata) + { + // Some information is already provided (StandardMBean) + if (metadata.standard) + { + introspectStandardMBean(metadata); + return; + } + + if (metadata.mbean instanceof DynamicMBean) + { + metadata.dynamic = true; + return; + } + else + { + metadata.dynamic = false; + // Continue and see if it's a plain standard MBean + } + + // We have a plain standard MBean, introspect it + introspectStandardMBean(metadata); + } + + private void introspectStandardMBean(MBeanMetaData metadata) + { + if (metadata.management != null) + { + // Be sure the MBean implements the management interface + if (metadata.management.isInstance(metadata.mbean)) + { + if (metadata.invoker == null) metadata.invoker = createInvoker(metadata); + return; + } + else + { + // Not compliant, reset the values + metadata.standard = false; + metadata.management = null; + metadata.invoker = null; + return; + } + } + else + { + Class cls = metadata.mbean.getClass(); + for (Class c = cls; c != null; c = c.getSuperclass()) + { + Class[] intfs = c.getInterfaces(); + for (int i = 0; i < intfs.length; ++i) + { + Class intf = intfs[i]; + + if (implementsMBean(c.getName(), intf.getName())) + { + // OK, found the MBean interface for this class + metadata.standard = true; + metadata.management = intf; + metadata.invoker = createInvoker(metadata); + return; + } + } + } + + // Management interface not found, it's not compliant, reset the values + metadata.standard = false; + metadata.management = null; + metadata.invoker = null; + } + } + + private void introspectMBeanInfo(MBeanMetaData metadata) + { + if (metadata.dynamic) + { + metadata.info = getDynamicMBeanInfo(metadata); + } + else if (metadata.standard) + { + metadata.info = createStandardMBeanInfo(metadata); + } + else + { + // Not a valid MBean, reset the MBeanInfo: this will cause an exception later + metadata.info = null; + } + } + + private MBeanInfo getDynamicMBeanInfo(MBeanMetaData metadata) + { + Logger logger = getLogger(); + + MBeanInfo info = null; + + try { + info = ((DynamicMBean) metadata.mbean).getMBeanInfo(); + } catch (Exception x) { + if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("getMBeanInfo threw: " + x.toString()); + } + + if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Dynamic MBeanInfo is: " + info); + + if (info == null) + { + if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("MBeanInfo cannot be null"); + return null; + } + + return info; + } + + private MBeanInfo createStandardMBeanInfo(MBeanMetaData metadata) + { + // This is a non-standard extension: description for standard MBeans + MBeanDescription description = createMBeanDescription(metadata); + + MBeanConstructorInfo[] ctors = createMBeanConstructorInfo(metadata, description); + if (ctors == null) return null; + MBeanAttributeInfo[] attrs = createMBeanAttributeInfo(metadata, description); + if (attrs == null) return null; + MBeanOperationInfo[] opers = createMBeanOperationInfo(metadata, description); + if (opers == null) return null; + MBeanNotificationInfo[] notifs = createMBeanNotificationInfo(metadata); + if (notifs == null) return null; + + return new MBeanInfo(metadata.mbean.getClass().getName(), description.getMBeanDescription(), attrs, ctors, opers, notifs); + } + + private MBeanDescription createMBeanDescription(MBeanMetaData metadata) + { + // This is a non-standard extension + + Logger logger = getLogger(); + if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Looking for standard MBean description..."); + + Class mbeanClass = metadata.mbean.getClass(); + + for (Class cls = mbeanClass; cls != null; cls = cls.getSuperclass()) + { + String clsName = cls.getName(); + if (clsName.startsWith("java.")) break; + + // Use full qualified name only + String descrClassName = clsName + "MBeanDescription"; + // Try to load the class + try + { + Class descrClass = null; + ClassLoader loader = metadata.classloader; + if (loader != null) + { + // Optimize lookup of the description class in case of MLets: we lookup the description class + // only in the classloader of the mbean, not in the whole CLR (since MLets delegates to the CLR) + if (loader.getClass() == MLet.class) + descrClass = ((MLet)loader).loadClass(descrClassName, null); + else + descrClass = loader.loadClass(descrClassName); + } + else + { + descrClass = Class.forName(descrClassName, false, null); + } + + Object descrInstance = descrClass.newInstance(); + if (descrInstance instanceof MBeanDescription) + { + MBeanDescription description = (MBeanDescription)descrInstance; + if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Found provided standard MBean description: " + description); + return description; + } + } + catch (ClassNotFoundException ignored) + { + } + catch (InstantiationException ignored) + { + } + catch (IllegalAccessException ignored) + { + } + } + + MBeanDescription description = DEFAULT_DESCRIPTION; + if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Cannot find standard MBean description, using default: " + description); + return description; + } + + private MBeanOperationInfo[] createMBeanOperationInfo(MBeanMetaData metadata, MBeanDescription description) + { + ArrayList operations = new ArrayList(); + + Method[] methods = metadata.management.getMethods(); + for (int j = 0; j < methods.length; ++j) + { + Method method = methods[j]; + if (!Utils.isAttributeGetter(method) && !Utils.isAttributeSetter(method)) + { + String descr = description == null ? null : description.getOperationDescription(method); + Class[] params = method.getParameterTypes(); + MBeanParameterInfo[] paramsInfo = new MBeanParameterInfo[params.length]; + for (int k = 0; k < params.length; ++k) + { + Class param = params[k]; + String paramName = description == null ? null : description.getOperationParameterName(method, k); + String paramDescr = description == null ? null : description.getOperationParameterDescription(method, k); + paramsInfo[k] = new MBeanParameterInfo(paramName, param.getName(), paramDescr); + } + MBeanOperationInfo info = new MBeanOperationInfo(method.getName(), descr, paramsInfo, method.getReturnType().getName(), MBeanOperationInfo.UNKNOWN); + operations.add(info); + } + } + + return (MBeanOperationInfo[])operations.toArray(new MBeanOperationInfo[operations.size()]); + } + + private MBeanAttributeInfo[] createMBeanAttributeInfo(MBeanMetaData metadata, MBeanDescription description) + { + Logger logger = getLogger(); + + HashMap attributes = new HashMap(); + HashMap getterNames = new HashMap(); + + Method[] methods = metadata.management.getMethods(); + for (int j = 0; j < methods.length; ++j) + { + Method method = methods[j]; + if (Utils.isAttributeGetter(method)) + { + String name = method.getName(); + boolean isIs = name.startsWith("is"); + + String attribute = null; + if (isIs) + attribute = name.substring(2); + else + attribute = name.substring(3); + + String descr = description == null ? null : description.getAttributeDescription(attribute); + + MBeanAttributeInfo info = (MBeanAttributeInfo)attributes.get(attribute); + + if (info != null) + { + // JMX spec does not allow overloading attributes. + // If an attribute with the same name already exists the MBean is not compliant + if (!info.getType().equals(method.getReturnType().getName())) + { + if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("MBean is not compliant: has overloaded attribute " + attribute); + return null; + } + else + { + // They return the same value, + if (getterNames.get(name) != null) + { + // This is the case of an attribute being present in multiple interfaces + // Ignore all but the first, since they resolve to the same method anyways + continue; + } + + // there is a chance that one is a get-getter and one is a is-getter + // for a boolean attribute. In this case, the MBean is not compliant. + if (info.isReadable()) + { + if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("MBean is not compliant: has overloaded attribute " + attribute); + return null; + } + + // MBeanAttributeInfo is already present due to a setter method, just update its readability + info = new MBeanAttributeInfo(attribute, info.getType(), info.getDescription(), true, info.isWritable(), isIs); + } + } + else + { + info = new MBeanAttributeInfo(attribute, method.getReturnType().getName(), descr, true, false, isIs); + } + + // Replace if exists + attributes.put(attribute, info); + getterNames.put(name,method); + } + else if (Utils.isAttributeSetter(method)) + { + String name = method.getName(); + String attribute = name.substring(3); + + String descr = description == null ? null : description.getAttributeDescription(attribute); + + MBeanAttributeInfo info = (MBeanAttributeInfo)attributes.get(attribute); + + if (info != null) + { + // JMX spec does not allow overloading attributes. + // If an attribute with the same name already exists the MBean is not compliant + if (!info.getType().equals(method.getParameterTypes()[0].getName())) + { + if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("MBean is not compliant: has overloaded attribute " + attribute); + return null; + } + else + { + // MBeanAttributeInfo is already present due to a getter method, just update its writability + info = new MBeanAttributeInfo(info.getName(), info.getType(), info.getDescription(), info.isReadable(), true, info.isIs()); + } + } + else + { + info = new MBeanAttributeInfo(attribute, method.getParameterTypes()[0].getName(), descr, false, true, false); + } + + // Replace if exists + attributes.put(attribute, info); + } + } + + return (MBeanAttributeInfo[])attributes.values().toArray(new MBeanAttributeInfo[attributes.size()]); + } + + private MBeanNotificationInfo[] createMBeanNotificationInfo(MBeanMetaData metadata) + { + MBeanNotificationInfo[] notifs = null; + if (metadata.mbean instanceof NotificationBroadcaster) + { + notifs = ((NotificationBroadcaster)metadata.mbean).getNotificationInfo(); + } + if (notifs == null) notifs = new MBeanNotificationInfo[0]; + return notifs; + } + + private MBeanConstructorInfo[] createMBeanConstructorInfo(MBeanMetaData metadata, MBeanDescription descrs) + { + Class mbeanClass = metadata.mbean.getClass(); + + Constructor[] ctors = mbeanClass.getConstructors(); + MBeanConstructorInfo[] constructors = new MBeanConstructorInfo[ctors.length]; + for (int i = 0; i < ctors.length; ++i) + { + Constructor constructor = ctors[i]; + String descr = descrs == null ? null : descrs.getConstructorDescription(constructor); + Class[] params = constructor.getParameterTypes(); + MBeanParameterInfo[] paramsInfo = new MBeanParameterInfo[params.length]; + for (int j = 0; j < params.length; ++j) + { + Class param = params[j]; + String paramName = descrs == null ? null : descrs.getConstructorParameterName(constructor, j); + String paramDescr = descrs == null ? null : descrs.getConstructorParameterDescription(constructor, j); + paramsInfo[j] = new MBeanParameterInfo(paramName, param.getName(), paramDescr); + } + + String ctorName = constructor.getName(); + MBeanConstructorInfo info = new MBeanConstructorInfo(ctorName.substring(ctorName.lastIndexOf('.') + 1), descr, paramsInfo); + constructors[i] = info; + } + return constructors; + } + + private boolean implementsMBean(String clsName, String intfName) + { + if (intfName.equals(clsName + "MBean")) return true; + + if (m_useExtendedMBeanInterfaces) + { + // Check also that the may be in different packages and/or inner classes + + // Trim packages + int clsDot = clsName.lastIndexOf('.'); + if (clsDot > 0) clsName = clsName.substring(clsDot + 1); + int intfDot = intfName.lastIndexOf('.'); + if (intfDot > 0) intfName = intfName.substring(intfDot + 1); + // Try again + if (intfName.equals(clsName + "MBean")) return true; + + // Trim inner classes + int clsDollar = clsName.lastIndexOf('$'); + if (clsDollar > 0) clsName = clsName.substring(clsDollar + 1); + int intfDollar = intfName.lastIndexOf('$'); + if (intfDollar > 0) intfName = intfName.substring(intfDollar + 1); + // Try again + if (intfName.equals(clsName + "MBean")) return true; + } + + // Give up + return false; + } + + private MBeanInvoker createInvoker(MBeanMetaData metadata) + { + Logger logger = getLogger(); + + if (m_customMBeanInvoker != null) + { + if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Custom MBeanInvoker class is: " + m_customMBeanInvoker); + try + { + MBeanInvoker mbeanInvoker = (MBeanInvoker)Thread.currentThread().getContextClassLoader().loadClass(m_customMBeanInvoker).newInstance(); + if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Using custom MBeanInvoker: " + mbeanInvoker); + return mbeanInvoker; + } + catch (Exception x) + { + if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Cannot instantiate custom MBeanInvoker, using default", x); + } + } + +/* SFR + if (m_bcelClassesAvailable) + { + MBeanInvoker mbeanInvoker = BCELMBeanInvoker.create(metadata); + if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Using default BCEL MBeanInvoker for MBean " + metadata.name + ", " + mbeanInvoker); + return mbeanInvoker; + } + else + { +*/ + MBeanInvoker mbeanInvoker = new ReflectedMBeanInvoker(); + if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Using default Reflection MBeanInvoker for MBean " + metadata.name + ", " + mbeanInvoker); + return mbeanInvoker; +/* SFR } */ + } + + private Logger getLogger() + { + return Log.getLogger(getClass().getName()); + } +} Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanInvoker.java URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanInvoker.java?rev=422696&view=auto ============================================================================== --- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanInvoker.java (added) +++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanInvoker.java Mon Jul 17 05:14:31 2006 @@ -0,0 +1,57 @@ +/* + * Copyright (C) MX4J. + * All rights reserved. + * + * This software is distributed under the terms of the MX4J License version 1.0. + * See the terms of the MX4J License in the documentation provided with this software. + */ +/* + * Copyright 2005 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.felix.mosgi.jmx.agent.mx4j.server; + +import javax.management.Attribute; +import javax.management.AttributeNotFoundException; +import javax.management.InvalidAttributeValueException; +import javax.management.MBeanException; +import javax.management.ReflectionException; + +/** + * Invokes methods on standard MBeans.

+ * Actually two implementations are available: one that uses reflection and one that generates on-the-fly a customized + * MBeanInvoker per each particular MBean and that is implemented with direct calls.
+ * The default is the direct call version, that uses the BCEL to generate + * the required bytecode on-the-fly.
+ * In the future may be the starting point for MBean interceptors. + * + * @author Simone Bordet + * @version $Revision: 1.1.1.1 $ + */ +public interface MBeanInvoker +{ + /** + * Invokes the specified operation on the MBean instance + */ + public Object invoke(MBeanMetaData metadata, String method, String[] signature, Object[] args) throws MBeanException, ReflectionException; + /** + * Returns the value of the specified attribute. + */ + public Object getAttribute(MBeanMetaData metadata, String attribute) throws MBeanException, AttributeNotFoundException, ReflectionException; + /** + * Sets the value of the specified attribute. + */ + public void setAttribute(MBeanMetaData metadata, Attribute attribute) throws MBeanException, AttributeNotFoundException, InvalidAttributeValueException, ReflectionException; +} Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanMetaData.java URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanMetaData.java?rev=422696&view=auto ============================================================================== --- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanMetaData.java (added) +++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanMetaData.java Mon Jul 17 05:14:31 2006 @@ -0,0 +1,82 @@ +/* + * Copyright (C) MX4J. + * All rights reserved. + * + * This software is distributed under the terms of the MX4J License version 1.0. + * See the terms of the MX4J License in the documentation provided with this software. + */ +/* + * Copyright 2005 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.felix.mosgi.jmx.agent.mx4j.server; + +import javax.management.MBeanInfo; +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +/** + * Objects of this class hold metadata information about MBeans. + * + * @author Simone Bordet + * @version $Revision: 1.1.1.1 $ + */ +public class MBeanMetaData +{ + /** + * The MBean instance. + */ + public Object mbean; + + /** + * The classloader of the MBean + */ + public ClassLoader classloader; + + /** + * The ObjectInstance of the MBean + */ + public ObjectInstance instance; + + /** + * The ObjectName of the MBean + */ + public ObjectName name; + + /** + * The MBeanInfo of the MBean + */ + public MBeanInfo info; + + /** + * True if the MBean is dynamic + */ + public boolean dynamic; + + /** + * True if the MBean is standard + */ + public boolean standard; + + /** + * The management interface of the MBean, if it is a standard MBean + */ + public Class management; + + /** + * The invoker for the MBean, if it is a standard MBean + */ + public MBeanInvoker invoker; +} Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanRepository.java URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanRepository.java?rev=422696&view=auto ============================================================================== --- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanRepository.java (added) +++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MBeanRepository.java Mon Jul 17 05:14:31 2006 @@ -0,0 +1,70 @@ +/* + * Copyright (C) MX4J. + * All rights reserved. + * + * This software is distributed under the terms of the MX4J License version 1.0. + * See the terms of the MX4J License in the documentation provided with this software. + */ +/* + * Copyright 2005 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.felix.mosgi.jmx.agent.mx4j.server; + +import java.util.Iterator; +import javax.management.ObjectName; + +/** + * The MBeanServer implementation delegates to implementations of this interface the storage of registered MBeans.

+ * All necessary synchronization code is taken care by the MBeanServer, so implementations can be coded without caring + * of synchronization issues. + * + * @author Simone Bordet + * @version $Revision: 1.1.1.1 $ + */ +public interface MBeanRepository extends Cloneable +{ + /** + * Returns the metadata information associated with the given object name. + * @see #put + */ + public MBeanMetaData get(ObjectName name); + + /** + * Inserts the given metadata associated with the given object name into this repository. + * @see #get + */ + public void put(ObjectName name, MBeanMetaData metadata); + + /** + * Removes the metadata associated with the given object name from this repository. + */ + public void remove(ObjectName name); + + /** + * Returns the size of this repository. + */ + public int size(); + + /** + * Returns an iterator on the metadata stored in this repository. + */ + public Iterator iterator(); + + /** + * Clones this MBean repository + */ + public Object clone(); +}