You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by sf...@apache.org on 2006/07/17 14:14:33 UTC
svn commit: r422696 [3/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...
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MX4JMBeanServer.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/MX4JMBeanServer.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/MX4JMBeanServer.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MX4JMBeanServer.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,1489 @@
+/*
+ * 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.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.BadAttributeValueExpException;
+import javax.management.BadBinaryOpValueExpException;
+import javax.management.BadStringOperationException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidApplicationException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.JMRuntimeException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanPermission;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanServerNotification;
+import javax.management.MBeanServerPermission;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.NotificationBroadcaster;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.QueryExp;
+import javax.management.ReflectionException;
+import javax.management.RuntimeErrorException;
+import javax.management.RuntimeOperationsException;
+import javax.management.StandardMBean;
+import javax.management.loading.ClassLoaderRepository;
+import javax.management.loading.PrivateClassLoader;
+
+import org.apache.felix.mosgi.jmx.agent.mx4j.ImplementationException;
+import org.apache.felix.mosgi.jmx.agent.mx4j.MX4JSystemKeys;
+import org.apache.felix.mosgi.jmx.agent.mx4j.loading.ClassLoaderObjectInputStream;
+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.server.interceptor.InvokerMBeanServerInterceptor;
+import org.apache.felix.mosgi.jmx.agent.mx4j.server.interceptor.MBeanServerInterceptor;
+import org.apache.felix.mosgi.jmx.agent.mx4j.server.interceptor.MBeanServerInterceptorConfigurator;
+import org.apache.felix.mosgi.jmx.agent.mx4j.util.Utils;
+
+/**
+ * The MX4J MBeanServer implementation. <br>
+ * The MBeanServer accomplishes these roles:
+ * <ul>
+ * <li> Returns information about the Agent
+ * <li> Acts as a repository for MBeans
+ * <li> Acts as an invoker, on behalf of the user, on MBeans
+ * </ul>
+ * <br>
+ * The repository function is delegated to instances of {@link MBeanRepository} classes.
+ * This class acts as a factory for MBeanRepository instances, that can be controlled via the system property
+ * {@link mx4j.MX4JSystemKeys#MX4J_MBEANSERVER_REPOSITORY} to the qualified name of the implementation class. <br>
+ *
+ * This class also acts as an invoker on MBeans. The architecture is interceptor-based, that is whenever you call
+ * from a client an MBeanServer method that will end up to call the MBean instance, the call is dispatched to
+ * the interceptor chain and eventually to the MBean. <br>
+ * The interceptors are configurable via the MBean {@link MBeanServerInterceptorConfigurator}.
+ * When the call is about to arrive to the MBean instance, the last interceptor dispatches the call depending on
+ * the MBean type: if the MBean is a dynamic MBean, the call is dispatched directly; if the MBean is a standard
+ * MBean an {@link MBeanInvoker} is delegated to invoke on the MBean instance.
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.3 $
+ */
+public class MX4JMBeanServer implements MBeanServer, java.io.Serializable
+{
+ private String defaultDomain;
+ private MBeanRepository mbeanRepository;
+ private MBeanServerDelegate delegate;
+ private ObjectName delegateName;
+ private MBeanIntrospector introspector;
+ private MBeanServerInterceptorConfigurator invoker;
+ private static long notifications;
+ private ModifiableClassLoaderRepository classLoaderRepository;
+ private Map domains = new HashMap();
+
+ private static final String[] EMPTY_PARAMS = new String[0];
+ private static final Object[] EMPTY_ARGS = new Object[0];
+
+ /**
+ * Create a new MBeanServer implementation with the specified default domain.
+ * If the default domain is null, then the empty string is assumed.
+ *
+ * @param defaultDomain The default domain to be used
+ * @throws SecurityException if access is not granted to create an MBeanServer instance
+ */
+ public MX4JMBeanServer(String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate)
+ {
+ Logger logger = getLogger();
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Creating MBeanServer instance...");
+
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Checking permission to create MBeanServer...");
+ sm.checkPermission(new MBeanServerPermission("newMBeanServer"));
+ }
+
+ if (defaultDomain == null) defaultDomain = "";
+ this.defaultDomain = defaultDomain;
+
+ if (delegate==null) throw new JMRuntimeException("Delegate can't be null");
+ this.delegate = delegate;
+
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("MBeanServer default domain is: '" + this.defaultDomain + "'");
+
+ mbeanRepository = createMBeanRepository();
+
+ classLoaderRepository = createClassLoaderRepository();
+ // JMX 1.2 requires the CLR to have as first entry the classloader of this class
+ classLoaderRepository.addClassLoader(getClass().getClassLoader());
+
+ introspector = new MBeanIntrospector();
+
+ // This is the official name of the delegate, it is used as a source for MBeanServerNotifications
+ try
+ {
+ delegateName = new ObjectName("JMImplementation", "type", "MBeanServerDelegate");
+ }
+ catch (MalformedObjectNameException ignored)
+ {
+ }
+
+ try
+ {
+ ObjectName invokerName = new ObjectName(MBeanServerInterceptorConfigurator.OBJECT_NAME);
+ invoker = new MBeanServerInterceptorConfigurator(this);
+
+// ContextClassLoaderMBeanServerInterceptor ccl = new ContextClassLoaderMBeanServerInterceptor();
+// NotificationListenerMBeanServerInterceptor notif = new NotificationListenerMBeanServerInterceptor();
+// SecurityMBeanServerInterceptor sec = new SecurityMBeanServerInterceptor();
+ InvokerMBeanServerInterceptor inv = new InvokerMBeanServerInterceptor(outer==null ? this : outer);
+
+// invoker.addPreInterceptor(ccl);
+// invoker.addPreInterceptor(notif);
+// invoker.addPostInterceptor(sec);
+ invoker.addPostInterceptor(inv);
+
+ invoker.start();
+
+ // The interceptor stack is in place, register the configurator and all interceptors
+ privilegedRegisterMBean(invoker, invokerName);
+
+// ObjectName cclName = new ObjectName("JMImplementation", "interceptor", "contextclassloader");
+// ObjectName notifName = new ObjectName("JMImplementation", "interceptor", "notificationwrapper");
+// ObjectName secName = new ObjectName("JMImplementation", "interceptor", "security");
+ ObjectName invName = new ObjectName("JMImplementation", "interceptor", "invoker");
+
+// privilegedRegisterMBean(ccl, cclName);
+// privilegedRegisterMBean(notif, notifName);
+// privilegedRegisterMBean(sec, secName);
+ privilegedRegisterMBean(inv, invName);
+ }
+ catch (Exception x)
+ {
+ logger.error("MBeanServerInterceptorConfigurator cannot be registered", x);
+ throw new ImplementationException();
+ }
+
+ // Now register the delegate
+ try
+ {
+ privilegedRegisterMBean(delegate, delegateName);
+ }
+ catch (Exception x)
+ {
+ logger.error("MBeanServerDelegate cannot be registered", x);
+ throw new ImplementationException(x.toString());
+ }
+
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("MBeanServer instance created successfully");
+ }
+
+ /**
+ * Returns the ClassLoaderRepository for this MBeanServer.
+ * When first the ClassLoaderRepository is created in the constructor, the system property
+ * {@link mx4j.MX4JSystemKeys#MX4J_MBEANSERVER_CLASSLOADER_REPOSITORY} is tested;
+ * if it is non-null and defines a subclass of
+ * {@link ModifiableClassLoaderRepository}, then that class is used instead of the default one.
+ */
+ public ClassLoaderRepository getClassLoaderRepository()
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ sm.checkPermission(new MBeanPermission("-#-[-]", "getClassLoaderRepository"));
+ }
+
+ return getModifiableClassLoaderRepository();
+ }
+
+ private ModifiableClassLoaderRepository getModifiableClassLoaderRepository()
+ {
+ return classLoaderRepository;
+ }
+
+ public ClassLoader getClassLoader(ObjectName name) throws InstanceNotFoundException
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ name = secureObjectName(name);
+
+ if (name == null)
+ {
+ sm.checkPermission(new MBeanPermission("-#-[-]", "getClassLoader"));
+ }
+ else
+ {
+ MBeanMetaData metadata = findMBeanMetaData(name);
+ sm.checkPermission(new MBeanPermission(metadata.info.getClassName(), "-", name, "getClassLoader"));
+ }
+ }
+
+ return getClassLoaderImpl(name);
+ }
+
+ public ClassLoader getClassLoaderFor(ObjectName name) throws InstanceNotFoundException
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ name = secureObjectName(name);
+ }
+
+ // If name is null, I get InstanceNotFoundException
+ MBeanMetaData metadata = findMBeanMetaData(name);
+
+ if (sm != null)
+ {
+ sm.checkPermission(new MBeanPermission(metadata.info.getClassName(), "-", name, "getClassLoaderFor"));
+ }
+
+ return metadata.mbean.getClass().getClassLoader();
+ }
+
+ /**
+ * Returns the MBean classloader corrispondent to the given ObjectName.
+ * If <code>name</code> is null, the classloader of this class is returned.
+ */
+ private ClassLoader getClassLoaderImpl(ObjectName name) throws InstanceNotFoundException
+ {
+ if (name == null)
+ {
+ return getClass().getClassLoader();
+ }
+ else
+ {
+ MBeanMetaData metadata = findMBeanMetaData(name);
+ if (metadata.mbean instanceof ClassLoader)
+ {
+ return (ClassLoader)metadata.mbean;
+ }
+ else
+ {
+ throw new InstanceNotFoundException(name.getCanonicalName());
+ }
+ }
+ }
+
+ public ObjectInputStream deserialize(String className, ObjectName loaderName, byte[] bytes)
+ throws InstanceNotFoundException, OperationsException, ReflectionException
+ {
+ if (className == null || className.trim().length() == 0)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("Invalid class name '" + className + "'"));
+ }
+
+ ClassLoader cl = getClassLoader(loaderName);
+
+ try
+ {
+ Class cls = cl.loadClass(className);
+ return deserializeImpl(cls.getClassLoader(), bytes);
+ }
+ catch (ClassNotFoundException x)
+ {
+ throw new ReflectionException(x);
+ }
+ }
+
+ public ObjectInputStream deserialize(String className, byte[] bytes)
+ throws OperationsException, ReflectionException
+ {
+ if (className == null || className.trim().length() == 0)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("Invalid class name '" + className + "'"));
+ }
+
+ // Find the classloader that can load the given className using the ClassLoaderRepository
+ try
+ {
+ Class cls = getClassLoaderRepository().loadClass(className);
+ return deserializeImpl(cls.getClassLoader(), bytes);
+ }
+ catch (ClassNotFoundException x)
+ {
+ throw new ReflectionException(x);
+ }
+ }
+
+ public ObjectInputStream deserialize(ObjectName objectName, byte[] bytes)
+ throws InstanceNotFoundException, OperationsException
+ {
+ ClassLoader cl = getClassLoaderFor(objectName);
+ return deserializeImpl(cl, bytes);
+ }
+
+ /**
+ * Deserializes the given bytes using the specified classloader.
+ */
+ private ObjectInputStream deserializeImpl(ClassLoader classloader, byte[] bytes) throws OperationsException
+ {
+ if (bytes == null || bytes.length == 0)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("Invalid byte array " + bytes));
+ }
+
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ try
+ {
+ return new ClassLoaderObjectInputStream(bais, classloader);
+ }
+ catch (IOException x)
+ {
+ throw new OperationsException(x.toString());
+ }
+ }
+
+ private MBeanServerInterceptor getHeadInterceptor()
+ {
+ MBeanServerInterceptor head = invoker.getHeadInterceptor();
+
+ if (head == null) throw new IllegalStateException("No MBeanServer interceptor, probably the configurator has been stopped");
+
+ return head;
+ }
+
+ private Logger getLogger()
+ {
+ return Log.getLogger(getClass().getName());
+ }
+
+ /**
+ * Creates a new repository for MBeans.
+ * The system property {@link mx4j.MX4JSystemKeys#MX4J_MBEANSERVER_REPOSITORY} is tested
+ * for a full qualified name of a class implementing the {@link MBeanRepository} interface.
+ * In case the system property is not defined or the class is not loadable or instantiable, a default
+ * implementation is returned.
+ */
+ private MBeanRepository createMBeanRepository()
+ {
+ Logger logger = getLogger();
+
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Checking for system property " + MX4JSystemKeys.MX4J_MBEANSERVER_REPOSITORY);
+
+ String value = (String)AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ return System.getProperty(MX4JSystemKeys.MX4J_MBEANSERVER_REPOSITORY);
+ }
+ });
+
+ if (value != null)
+ {
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Property found for custom MBeanServer registry; class is: " + value);
+
+ try
+ {
+ MBeanRepository registry = (MBeanRepository)Thread.currentThread().getContextClassLoader().loadClass(value).newInstance();
+ if (logger.isEnabledFor(Logger.TRACE))
+ {
+ logger.trace("Custom MBeanServer registry created successfully");
+ }
+ return registry;
+ }
+ catch (Exception x)
+ {
+ if (logger.isEnabledFor(Logger.TRACE))
+ {
+ logger.trace("Custom MBeanServer registry could not be created", x);
+ }
+ }
+ }
+
+ return new DefaultMBeanRepository();
+ }
+
+ /**
+ * Creates a new ClassLoaderRepository for ClassLoader MBeans.
+ * The system property {@link mx4j.MX4JSystemKeys#MX4J_MBEANSERVER_CLASSLOADER_REPOSITORY}
+ * is tested for a full qualified name of a class
+ * extending the {@link ModifiableClassLoaderRepository} class.
+ * In case the system property is not defined or the class is not loadable or instantiable, a default
+ * implementation is returned.
+ */
+ private ModifiableClassLoaderRepository createClassLoaderRepository()
+ {
+ Logger logger = getLogger();
+
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Checking for system property " + MX4JSystemKeys.MX4J_MBEANSERVER_CLASSLOADER_REPOSITORY);
+
+ String value = (String)AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ return System.getProperty(MX4JSystemKeys.MX4J_MBEANSERVER_CLASSLOADER_REPOSITORY);
+ }
+ });
+
+ if (value != null)
+ {
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Property found for custom ClassLoaderRepository; class is: " + value);
+
+ try
+ {
+ ModifiableClassLoaderRepository repository = (ModifiableClassLoaderRepository)Thread.currentThread().getContextClassLoader().loadClass(value).newInstance();
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Custom ClassLoaderRepository created successfully " + repository);
+ return repository;
+ }
+ catch (Exception x)
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Custom ClassLoaderRepository could not be created", x);
+ }
+ }
+ return new DefaultClassLoaderRepository();
+ }
+
+ /**
+ * Returns the repository of MBeans for this MBeanServer
+ */
+ private MBeanRepository getMBeanRepository()
+ {
+ return mbeanRepository;
+ }
+
+ /**
+ * Looks up the metadata associated with the given ObjectName.
+ * @throws InstanceNotFoundException if the given ObjectName is not a registered MBean
+ */
+ private MBeanMetaData findMBeanMetaData(ObjectName objectName) throws InstanceNotFoundException
+ {
+ MBeanMetaData metadata = null;
+ if (objectName != null)
+ {
+ objectName = normalizeObjectName(objectName);
+
+ MBeanRepository repository = getMBeanRepository();
+ synchronized (repository)
+ {
+ metadata = repository.get(objectName);
+ }
+ }
+ if (metadata == null)
+ {
+ throw new InstanceNotFoundException("MBeanServer cannot find MBean with ObjectName " + objectName);
+ }
+ return metadata;
+ }
+
+ public void addNotificationListener(ObjectName observed, ObjectName listener, NotificationFilter filter, Object handback)
+ throws InstanceNotFoundException
+ {
+ listener = secureObjectName(listener);
+
+ Object mbean = findMBeanMetaData(listener).mbean;
+ if (!(mbean instanceof NotificationListener))
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("MBean " + listener + " is not a NotificationListener"));
+ }
+ addNotificationListener(observed, (NotificationListener)mbean, filter, handback);
+ }
+
+ public void addNotificationListener(ObjectName observed, NotificationListener listener, NotificationFilter filter, Object handback)
+ throws InstanceNotFoundException
+ {
+ if (listener == null)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("NotificationListener cannot be null"));
+ }
+
+ observed = secureObjectName(observed);
+
+ MBeanMetaData metadata = findMBeanMetaData(observed);
+
+ Object mbean = metadata.mbean;
+
+ if (!(mbean instanceof NotificationBroadcaster))
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("MBean " + observed + " is not a NotificationBroadcaster"));
+ }
+
+ addNotificationListenerImpl(metadata, listener, filter, handback);
+ }
+
+ private void addNotificationListenerImpl(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback)
+ {
+ getHeadInterceptor().addNotificationListener(metadata, listener, filter, handback);
+ }
+
+ public void removeNotificationListener(ObjectName observed, ObjectName listener)
+ throws InstanceNotFoundException, ListenerNotFoundException
+ {
+ listener = secureObjectName(listener);
+
+ Object mbean = findMBeanMetaData(listener).mbean;
+ if (!(mbean instanceof NotificationListener))
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("MBean " + listener + " is not a NotificationListener"));
+ }
+ removeNotificationListener(observed, (NotificationListener)mbean);
+ }
+
+ public void removeNotificationListener(ObjectName observed, NotificationListener listener)
+ throws InstanceNotFoundException, ListenerNotFoundException
+ {
+ if (listener == null)
+ {
+ throw new ListenerNotFoundException("NotificationListener cannot be null");
+ }
+
+ observed = secureObjectName(observed);
+
+ MBeanMetaData metadata = findMBeanMetaData(observed);
+ Object mbean = metadata.mbean;
+
+ if (!(mbean instanceof NotificationBroadcaster))
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("MBean " + observed + " is not a NotificationBroadcaster"));
+ }
+
+ removeNotificationListenerImpl(metadata, listener);
+ }
+
+ public void removeNotificationListener(ObjectName observed, ObjectName listener, NotificationFilter filter, Object handback)
+ throws InstanceNotFoundException, ListenerNotFoundException
+ {
+ listener = secureObjectName(listener);
+
+ Object mbean = findMBeanMetaData(listener).mbean;
+ if (!(mbean instanceof NotificationListener))
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("MBean " + listener + " is not a NotificationListener"));
+ }
+ removeNotificationListener(observed, (NotificationListener)mbean, filter, handback);
+ }
+
+ public void removeNotificationListener(ObjectName observed, NotificationListener listener, NotificationFilter filter, Object handback)
+ throws InstanceNotFoundException, ListenerNotFoundException
+ {
+ if (listener == null)
+ {
+ throw new ListenerNotFoundException("NotificationListener cannot be null");
+ }
+
+ observed = secureObjectName(observed);
+
+ MBeanMetaData metadata = findMBeanMetaData(observed);
+ Object mbean = metadata.mbean;
+
+ if (!(mbean instanceof NotificationEmitter))
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("MBean " + observed + " is not a NotificationEmitter"));
+ }
+
+ removeNotificationListenerImpl(metadata, listener, filter, handback);
+ }
+
+ private void removeNotificationListenerImpl(MBeanMetaData metadata, NotificationListener listener)
+ throws ListenerNotFoundException
+ {
+ getHeadInterceptor().removeNotificationListener(metadata, listener);
+ }
+
+ private void removeNotificationListenerImpl(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback)
+ throws ListenerNotFoundException
+ {
+ getHeadInterceptor().removeNotificationListener(metadata, listener, filter, handback);
+ }
+
+ public Object instantiate(String className)
+ throws ReflectionException, MBeanException
+ {
+ return instantiate(className, null, null);
+ }
+
+ public Object instantiate(String className, Object[] args, String[] parameters)
+ throws ReflectionException, MBeanException
+ {
+ if (className == null || className.trim().length() == 0)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("Class name cannot be null or empty"));
+ }
+
+ try
+ {
+ Class cls = getModifiableClassLoaderRepository().loadClass(className);
+ return instantiateImpl(className, cls.getClassLoader(), null, parameters, args).mbean;
+ }
+ catch (ClassNotFoundException x)
+ {
+ throw new ReflectionException(x);
+ }
+ }
+
+ public Object instantiate(String className, ObjectName loaderName)
+ throws ReflectionException, MBeanException, InstanceNotFoundException
+ {
+ return instantiate(className, loaderName, null, null);
+ }
+
+ public Object instantiate(String className, ObjectName loaderName, Object[] args, String[] parameters)
+ throws ReflectionException, MBeanException, InstanceNotFoundException
+ {
+ if (className == null || className.trim().length() == 0)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("Class name cannot be null or empty"));
+ }
+
+ // loaderName can be null: means using this class' ClassLoader
+
+ loaderName = secureObjectName(loaderName);
+ if (loaderName != null && loaderName.isPattern())
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("ObjectName for the ClassLoader cannot be a pattern ObjectName: " + loaderName));
+ }
+
+ ClassLoader cl = getClassLoaderImpl(loaderName);
+ return instantiateImpl(className, cl, null, parameters, args).mbean;
+ }
+
+ private MBeanMetaData instantiateImpl(String className, ClassLoader classloader, ObjectName name, String[] params, Object[] args)
+ throws ReflectionException, MBeanException
+ {
+ if (params == null) params = EMPTY_PARAMS;
+ if (args == null) args = EMPTY_ARGS;
+
+ MBeanMetaData metadata = createMBeanMetaData();
+ metadata.classloader = classloader;
+ metadata.name = secureObjectName(name);
+
+ getHeadInterceptor().instantiate(metadata, className, params, args);
+
+ return metadata;
+ }
+
+ public ObjectInstance createMBean(String className, ObjectName objectName)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException
+ {
+ return createMBean(className, objectName, null, null);
+ }
+
+ public ObjectInstance createMBean(String className, ObjectName objectName, Object[] args, String[] parameters)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException
+ {
+ try
+ {
+ Class cls = getModifiableClassLoaderRepository().loadClass(className);
+ MBeanMetaData metadata = instantiateImpl(className, cls.getClassLoader(), objectName, parameters, args);
+
+ registerImpl(metadata, false);
+
+ return metadata.instance;
+ }
+ catch (ClassNotFoundException x)
+ {
+ throw new ReflectionException(x);
+ }
+ }
+
+ public ObjectInstance createMBean(String className, ObjectName objectName, ObjectName loaderName)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException
+ {
+ return createMBean(className, objectName, loaderName, null, null);
+ }
+
+ public ObjectInstance createMBean(String className, ObjectName objectName, ObjectName loaderName, Object[] args, String[] parameters)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException
+ {
+ loaderName = secureObjectName(loaderName);
+
+ ClassLoader cl = getClassLoaderImpl(loaderName);
+
+ MBeanMetaData metadata = instantiateImpl(className, cl, objectName, parameters, args);
+
+ registerImpl(metadata, false);
+
+ return metadata.instance;
+ }
+
+ public ObjectInstance registerMBean(Object mbean, ObjectName objectName)
+ throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException
+ {
+ return registerMBeanImpl(mbean, objectName, false);
+ }
+
+ private ObjectInstance registerMBeanImpl(Object mbean, ObjectName objectName, boolean privileged)
+ throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException
+ {
+ if (mbean == null)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("MBean instance cannot be null"));
+ }
+
+ MBeanMetaData metadata = createMBeanMetaData();
+ metadata.mbean = mbean;
+ metadata.classloader = mbean.getClass().getClassLoader();
+ metadata.name = secureObjectName(objectName);
+
+ registerImpl(metadata, privileged);
+
+ return metadata.instance;
+ }
+
+ /**
+ * Returns a new instance of the metadata class used to store MBean information.
+ */
+ private MBeanMetaData createMBeanMetaData()
+ {
+ return new MBeanMetaData();
+ }
+
+ /**
+ * This method is called only to register implementation MBeans from the constructor.
+ * Since to create an instance of this class already requires a permission, here we hide the registration
+ * of implementation MBeans to the client that thus need no further permissions.
+ */
+ private ObjectInstance privilegedRegisterMBean(final Object mbean, final ObjectName name)
+ throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException
+ {
+ try
+ {
+ return (ObjectInstance)AccessController.doPrivileged(new PrivilegedExceptionAction()
+ {
+ public Object run() throws Exception
+ {
+ return registerMBeanImpl(mbean, name, true);
+ }
+ });
+ }
+ catch (PrivilegedActionException x)
+ {
+ Exception xx = x.getException();
+ if (xx instanceof InstanceAlreadyExistsException)
+ throw (InstanceAlreadyExistsException)xx;
+ else if (xx instanceof MBeanRegistrationException)
+ throw (MBeanRegistrationException)xx;
+ else if (xx instanceof NotCompliantMBeanException)
+ throw (NotCompliantMBeanException)xx;
+ else
+ throw new MBeanRegistrationException(xx);
+ }
+ }
+
+ private void registerImpl(MBeanMetaData metadata, boolean privileged) throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException
+ {
+ introspector.introspect(metadata);
+
+ if (!introspector.isMBeanCompliant(metadata)) throw new NotCompliantMBeanException("MBean is not compliant");
+
+ MBeanServerInterceptor head = getHeadInterceptor();
+
+ try
+ {
+ // With this call, the MBean implementor can replace the ObjectName with a subclass that is not secure, secure it again
+ head.registration(metadata, MBeanServerInterceptor.PRE_REGISTER);
+ metadata.name = secureObjectName(metadata.name);
+
+ metadata.instance = new ObjectInstance(metadata.name, metadata.info.getClassName());
+
+ register(metadata, privileged);
+
+ head.registration(metadata, MBeanServerInterceptor.POST_REGISTER_TRUE);
+ }
+ catch (Throwable x)
+ {
+ try
+ {
+ head.registration(metadata, MBeanServerInterceptor.POST_REGISTER_FALSE);
+ }
+ catch (MBeanRegistrationException ignored)
+ {/* Ignore this one to rethrow the other one */
+ }
+
+ if (x instanceof SecurityException)
+ {
+ throw (SecurityException)x;
+ }
+ else if (x instanceof InstanceAlreadyExistsException)
+ {
+ throw (InstanceAlreadyExistsException)x;
+ }
+ else if (x instanceof MBeanRegistrationException)
+ {
+ throw (MBeanRegistrationException)x;
+ }
+ else if (x instanceof RuntimeOperationsException)
+ {
+ throw (RuntimeOperationsException)x;
+ }
+ else if (x instanceof JMRuntimeException)
+ {
+ throw (JMRuntimeException)x;
+ }
+ else if (x instanceof Exception)
+ {
+ throw new MBeanRegistrationException((Exception)x);
+ }
+ else if (x instanceof Error)
+ {
+ throw new MBeanRegistrationException(new RuntimeErrorException((Error)x));
+ }
+ else
+ {
+ throw new ImplementationException();
+ }
+ }
+
+ if (metadata.mbean instanceof ClassLoader && !(metadata.mbean instanceof PrivateClassLoader))
+ {
+ ClassLoader cl = (ClassLoader)metadata.mbean;
+ getModifiableClassLoaderRepository().addClassLoader(cl);
+ }
+ }
+
+ private void register(MBeanMetaData metadata, boolean privileged) throws InstanceAlreadyExistsException
+ {
+ metadata.name = normalizeObjectName(metadata.name);
+
+ ObjectName objectName = metadata.name;
+ if (objectName == null || objectName.isPattern())
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("ObjectName cannot be null or a pattern ObjectName"));
+ }
+ if (objectName.getDomain().equals("JMImplementation") && !privileged)
+ {
+ throw new JMRuntimeException("Domain 'JMImplementation' is reserved for the JMX Agent");
+ }
+
+ MBeanRepository repository = getMBeanRepository();
+ synchronized (repository)
+ {
+ if (repository.get(objectName) != null) throw new InstanceAlreadyExistsException(objectName.toString());
+
+ repository.put(objectName, metadata);
+ }
+ addDomain(objectName.getDomain());
+
+ notify(objectName, MBeanServerNotification.REGISTRATION_NOTIFICATION);
+ }
+
+ private void notify(ObjectName objectName, String notificationType)
+ {
+ long sequenceNumber = 0;
+ synchronized (MX4JMBeanServer.class)
+ {
+ sequenceNumber = notifications;
+ ++notifications;
+ }
+
+ delegate.sendNotification(new MBeanServerNotification(notificationType, delegateName, sequenceNumber, objectName));
+ }
+
+ private void addDomain(String domain)
+ {
+ synchronized (domains)
+ {
+ Integer count = (Integer)domains.get(domain);
+ if (count == null)
+ domains.put(domain, new Integer(1));
+ else
+ domains.put(domain, new Integer(count.intValue() + 1));
+ }
+ }
+
+ private void removeDomain(String domain)
+ {
+ synchronized (domains)
+ {
+ Integer count = (Integer)domains.get(domain);
+ if (count == null) throw new ImplementationException();
+ if (count.intValue() < 2)
+ domains.remove(domain);
+ else
+ domains.put(domain, new Integer(count.intValue() - 1));
+ }
+ }
+
+ public void unregisterMBean(ObjectName objectName)
+ throws InstanceNotFoundException, MBeanRegistrationException
+ {
+ objectName = secureObjectName(objectName);
+
+ if (objectName == null || objectName.isPattern())
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("ObjectName cannot be null or a pattern ObjectName"));
+ }
+
+ if (objectName.getDomain().equals("JMImplementation"))
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("Domain 'JMImplementation' is reserved for the JMX Agent"));
+ }
+
+ MBeanMetaData metadata = findMBeanMetaData(objectName);
+
+ try
+ {
+ MBeanServerInterceptor head = getHeadInterceptor();
+ head.registration(metadata, MBeanServerInterceptor.PRE_DEREGISTER);
+
+ unregister(metadata);
+
+ getHeadInterceptor().registration(metadata, MBeanServerInterceptor.POST_DEREGISTER);
+
+ if (metadata.mbean instanceof ClassLoader && !(metadata.mbean instanceof PrivateClassLoader))
+ {
+ getModifiableClassLoaderRepository().removeClassLoader((ClassLoader)metadata.mbean);
+ }
+ }
+ catch (MBeanRegistrationException x)
+ {
+ throw x;
+ }
+ catch (SecurityException x)
+ {
+ throw x;
+ }
+ catch (Exception x)
+ {
+ throw new MBeanRegistrationException(x);
+ }
+ catch (Error x)
+ {
+ throw new MBeanRegistrationException(new RuntimeErrorException(x));
+ }
+ }
+
+ private void unregister(MBeanMetaData metadata)
+ {
+ ObjectName objectName = metadata.name;
+
+ MBeanRepository repository = getMBeanRepository();
+ synchronized (repository)
+ {
+ repository.remove(objectName);
+ }
+ removeDomain(objectName.getDomain());
+
+ notify(objectName, MBeanServerNotification.UNREGISTRATION_NOTIFICATION);
+ }
+
+ public Object getAttribute(ObjectName objectName, String attribute)
+ throws InstanceNotFoundException, MBeanException, AttributeNotFoundException, ReflectionException
+ {
+ if (attribute == null || attribute.trim().length() == 0)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("Invalid attribute"));
+ }
+
+ objectName = secureObjectName(objectName);
+
+ MBeanMetaData metadata = findMBeanMetaData(objectName);
+
+ return getHeadInterceptor().getAttribute(metadata, attribute);
+ }
+
+
+ public void setAttribute(ObjectName objectName, Attribute attribute)
+ throws InstanceNotFoundException, AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException
+ {
+ if (attribute == null || attribute.getName().trim().length() == 0)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("Invalid attribute"));
+ }
+
+ objectName = secureObjectName(objectName);
+
+ MBeanMetaData metadata = findMBeanMetaData(objectName);
+
+ getHeadInterceptor().setAttribute(metadata, attribute);
+ }
+
+ public AttributeList getAttributes(ObjectName objectName, String[] attributes)
+ throws InstanceNotFoundException, ReflectionException
+ {
+ if (attributes == null || attributes.length == 0)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("Invalid attribute list"));
+ }
+
+ objectName = secureObjectName(objectName);
+
+ MBeanMetaData metadata = findMBeanMetaData(objectName);
+
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ // Must check if the user has the right to call this method, regardless of the attributes
+ sm.checkPermission(new MBeanPermission(metadata.info.getClassName(), "-", objectName, "getAttribute"));
+ }
+
+ return getHeadInterceptor().getAttributes(metadata, attributes);
+ }
+
+ public AttributeList setAttributes(ObjectName objectName, AttributeList attributes)
+ throws InstanceNotFoundException, ReflectionException
+ {
+ if (attributes == null)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("Invalid attribute list"));
+ }
+
+ objectName = secureObjectName(objectName);
+
+ MBeanMetaData metadata = findMBeanMetaData(objectName);
+
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ // Must check if the user has the right to call this method, regardless of the attributes
+ sm.checkPermission(new MBeanPermission(metadata.info.getClassName(), "-", objectName, "setAttribute"));
+ }
+
+ return getHeadInterceptor().setAttributes(metadata, attributes);
+ }
+
+ public Object invoke(ObjectName objectName, String methodName, Object[] args, String[] parameters)
+ throws InstanceNotFoundException, MBeanException, ReflectionException
+ {
+ if (methodName == null || methodName.trim().length() == 0)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("Invalid operation name '" + methodName + "'"));
+ }
+
+ if (args == null) args = EMPTY_ARGS;
+ if (parameters == null) parameters = EMPTY_PARAMS;
+
+ objectName = secureObjectName(objectName);
+
+ MBeanMetaData metadata = findMBeanMetaData(objectName);
+
+ return getHeadInterceptor().invoke(metadata, methodName, parameters, args);
+ }
+
+ public String getDefaultDomain()
+ {
+ return defaultDomain;
+ }
+
+ public String[] getDomains()
+ {
+ synchronized (domains)
+ {
+ Set keys = domains.keySet();
+ return (String[])keys.toArray(new String[keys.size()]);
+ }
+ }
+
+ public Integer getMBeanCount()
+ {
+ MBeanRepository repository = getMBeanRepository();
+ synchronized (repository)
+ {
+ return new Integer(repository.size());
+ }
+ }
+
+ public boolean isRegistered(ObjectName objectName)
+ {
+ try
+ {
+ return findMBeanMetaData(objectName) != null;
+ }
+ catch (InstanceNotFoundException x)
+ {
+ return false;
+ }
+ }
+
+ public MBeanInfo getMBeanInfo(ObjectName objectName)
+ throws InstanceNotFoundException, IntrospectionException, ReflectionException
+ {
+ objectName = secureObjectName(objectName);
+
+ MBeanMetaData metadata = findMBeanMetaData(objectName);
+
+ MBeanInfo info = getHeadInterceptor().getMBeanInfo(metadata);
+ if (info == null) throw new JMRuntimeException("MBeanInfo returned for MBean " + objectName + " is null");
+ return info;
+ }
+
+ public ObjectInstance getObjectInstance(ObjectName objectName)
+ throws InstanceNotFoundException
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ objectName = secureObjectName(objectName);
+ }
+
+ MBeanMetaData metadata = findMBeanMetaData(objectName);
+
+ if (sm != null)
+ {
+ sm.checkPermission(new MBeanPermission(metadata.info.getClassName(), "-", objectName, "getObjectInstance"));
+ }
+
+ return metadata.instance;
+ }
+
+ public boolean isInstanceOf(ObjectName objectName, String className)
+ throws InstanceNotFoundException
+ {
+ if (className == null || className.trim().length() == 0)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("Invalid class name"));
+ }
+
+ objectName = secureObjectName(objectName);
+
+ MBeanMetaData metadata = findMBeanMetaData(objectName);
+
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ sm.checkPermission(new MBeanPermission(metadata.info.getClassName(), "-", objectName, "isInstanceOf"));
+ }
+
+ try
+ {
+ ClassLoader loader = metadata.classloader;
+ Class cls = null;
+ if (loader != null)
+ cls = loader.loadClass(className);
+ else
+ cls = Class.forName(className, false, null);
+
+ if (metadata.mbean instanceof StandardMBean)
+ {
+ Object impl = ((StandardMBean) metadata.mbean).getImplementation();
+ return cls.isInstance(impl);
+ }
+ else
+ {
+ return cls.isInstance(metadata.mbean);
+ }
+ }
+ catch (ClassNotFoundException x)
+ {
+ return false;
+ }
+ }
+
+ public Set queryMBeans(ObjectName patternName, QueryExp filter)
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ patternName = secureObjectName(patternName);
+ // Must check if the user has the right to call this method,
+ // no matter which ObjectName has been passed.
+ sm.checkPermission(new MBeanPermission("-#-[-]", "queryMBeans"));
+ }
+
+ Set match = queryObjectNames(patternName, filter, true);
+
+ Set set = new HashSet();
+ for (Iterator i = match.iterator(); i.hasNext();)
+ {
+ ObjectName name = (ObjectName)i.next();
+ try
+ {
+ MBeanMetaData metadata = findMBeanMetaData(name);
+ set.add(metadata.instance);
+ }
+ catch (InstanceNotFoundException ignored)
+ {
+ // A concurrent thread removed the MBean after queryNames, ignore
+ }
+ }
+ return set;
+ }
+
+ public Set queryNames(ObjectName patternName, QueryExp filter)
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ patternName = secureObjectName(patternName);
+ // Must check if the user has the right to call this method,
+ // no matter which ObjectName has been passed.
+ sm.checkPermission(new MBeanPermission("-#-[-]", "queryNames"));
+ }
+
+ return queryObjectNames(patternName, filter, false);
+ }
+
+ /**
+ * Utility method for queryNames and queryMBeans that returns a set of ObjectNames.
+ * It does 3 things:
+ * 1) filter the MBeans following the given ObjectName pattern
+ * 2) filter the MBeans following the permissions that client code has
+ * 3) filter the MBeans following the given QueryExp
+ * It is important that these 3 operations are done in this order
+ */
+ private Set queryObjectNames(ObjectName patternName, QueryExp filter, boolean instances)
+ {
+ // First, retrieve the scope of the query: all mbeans matching the patternName
+ Set scope = findMBeansByPattern(patternName);
+
+ // Second, filter the scope by checking the caller's permissions
+ Set secureScope = filterMBeansBySecurity(scope, instances);
+
+ // Third, filter the scope using the given QueryExp
+ Set match = filterMBeansByQuery(secureScope, filter);
+
+ return match;
+ }
+
+ /**
+ * Returns a set of ObjectNames of the registered MBeans that match the given ObjectName pattern
+ */
+ private Set findMBeansByPattern(ObjectName pattern)
+ {
+ if (pattern == null)
+ {
+ try
+ {
+ pattern = new ObjectName("*:*");
+ }
+ catch (MalformedObjectNameException ignored)
+ {
+ }
+ }
+
+ pattern = normalizeObjectName(pattern);
+
+ String patternDomain = pattern.getDomain();
+ Hashtable patternProps = pattern.getKeyPropertyList();
+
+ Set set = new HashSet();
+
+ // Clone the repository, we are faster than holding the lock while iterating
+ MBeanRepository repository = (MBeanRepository)getMBeanRepository().clone();
+
+ for (Iterator i = repository.iterator(); i.hasNext();)
+ {
+ MBeanMetaData metadata = (MBeanMetaData)i.next();
+ ObjectName name = metadata.name;
+ Hashtable props = name.getKeyPropertyList();
+
+ String domain = name.getDomain();
+ if (Utils.wildcardMatch(patternDomain, domain))
+ {
+ // Domain matches, now check properties
+ if (pattern.isPropertyPattern())
+ {
+ // A property pattern with no entries, can only be '*'
+ if (patternProps.size() == 0)
+ {
+ // User wants all properties
+ set.add(name);
+ }
+ else
+ {
+ // Loop on the properties of the pattern.
+ // If one is not found then the current ObjectName does not match
+ boolean found = true;
+ for (Iterator j = patternProps.entrySet().iterator(); j.hasNext();)
+ {
+ Map.Entry entry = (Map.Entry)j.next();
+ Object patternKey = entry.getKey();
+ Object patternValue = entry.getValue();
+ if (patternKey.equals("*"))
+ {
+ continue;
+ }
+
+ // Try to see if the current ObjectName contains this entry
+ if (!props.containsKey(patternKey))
+ {
+ // Not even the key is present
+ found = false;
+ break;
+ }
+ else
+ {
+ // The key is present, let's check if the values are equal
+ Object value = props.get(patternKey);
+ if (value == null && patternValue == null)
+ {
+ // Values are equal, go on with next pattern entry
+ continue;
+ }
+ if (value != null && value.equals(patternValue))
+ {
+ // Values are equal, go on with next pattern entry
+ continue;
+ }
+ // Here values are different
+ found = false;
+ break;
+ }
+ }
+ if (found) set.add(name);
+ }
+ }
+ else
+ {
+ if (props.entrySet().equals(patternProps.entrySet())) set.add(name);
+ }
+ }
+ }
+ return set;
+ }
+
+ /**
+ * Filters the given set of ObjectNames following the permission that client code has granted.
+ * Returns a set containing the allowed ObjectNames.
+ */
+ private Set filterMBeansBySecurity(Set mbeans, boolean instances)
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm == null) return mbeans;
+
+ HashSet set = new HashSet();
+ for (Iterator i = mbeans.iterator(); i.hasNext();)
+ {
+ ObjectName name = (ObjectName)i.next();
+ try
+ {
+ MBeanMetaData metadata = findMBeanMetaData(name);
+ String className = metadata.info.getClassName();
+ sm.checkPermission(new MBeanPermission(className, "-", name, instances ? "queryMBeans" : "queryNames"));
+ set.add(name);
+ }
+ catch (InstanceNotFoundException ignored)
+ {
+ // A concurrent thread removed this MBean, continue
+ continue;
+ }
+ catch (SecurityException ignored)
+ {
+ // Don't add the name to the list, and go on.
+ }
+ }
+ return set;
+ }
+
+ /**
+ * Filters the given set of ObjectNames following the given QueryExp.
+ * Returns a set of ObjectNames that match the given QueryExp.
+ */
+ private Set filterMBeansByQuery(Set scope, QueryExp filter)
+ {
+ if (filter == null) return scope;
+
+ Set set = new HashSet();
+ for (Iterator i = scope.iterator(); i.hasNext();)
+ {
+ ObjectName name = (ObjectName)i.next();
+ filter.setMBeanServer(this);
+ try
+ {
+ if (filter.apply(name)) set.add(name);
+ }
+ catch (BadStringOperationException ignored)
+ {
+ }
+ catch (BadBinaryOpValueExpException ignored)
+ {
+ }
+ catch (BadAttributeValueExpException x)
+ {
+ }
+ catch (InvalidApplicationException x)
+ {
+ }
+ catch (SecurityException x)
+ {
+ }
+ catch (Exception x)
+ {
+ // The 1.2 spec says Exceptions must not be propagated
+ }
+ }
+ return set;
+ }
+
+ /**
+ * Returns a normalized ObjectName from the given one.
+ * If an ObjectName is specified with the abbreviated notation for the default domain, that is ':key=value'
+ * this method returns an ObjectName whose domain is the default domain of this MBeanServer and with the same
+ * properties.
+ */
+ private ObjectName normalizeObjectName(ObjectName name)
+ {
+ if (name == null) return null;
+
+ String defaultDomain = getDefaultDomain();
+ String domain = name.getDomain();
+
+ if (domain.length() == 0 && defaultDomain.length() > 0)
+ {
+ // The given object name specifies the abbreviated form to indicate the default domain,
+ // ie ':key=value', the empty string as domain. I must convert this abbreviated form
+ // to the full one, if the default domain of this mbeanserver is not the empty string as well
+ StringBuffer buffer = new StringBuffer(defaultDomain).append(":").append(name.getKeyPropertyListString());
+ if (name.isPropertyPattern())
+ {
+ if (name.getKeyPropertyList().size() > 0)
+ buffer.append(",*");
+ else
+ buffer.append("*");
+ }
+ try
+ {
+ name = new ObjectName(buffer.toString());
+ }
+ catch (MalformedObjectNameException ignored)
+ {
+ }
+ }
+ return name;
+ }
+
+ /**
+ * Returns an ObjectName instance even if the provided ObjectName is a subclass.
+ * This is done to avoid security holes: a nasty ObjectName subclass can bypass security checks.
+ */
+ private ObjectName secureObjectName(ObjectName name)
+ {
+ // I cannot trust ObjectName, since a malicious user can send a subclass that overrides equals and hashcode
+ // to match another ObjectName for which it does not have permission, or returns different results from
+ // ObjectName.getCanonicalName() for different calls, so that passes the security checks but in fact will
+ // later refer to a different ObjectName for which it does not have permission.
+ if (name == null) return null;
+ return ObjectName.getInstance(name);
+ }
+}
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MX4JMBeanServerBuilder.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/MX4JMBeanServerBuilder.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/MX4JMBeanServerBuilder.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MX4JMBeanServerBuilder.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,71 @@
+/*
+ * 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.MBeanServer;
+import javax.management.MBeanServerBuilder;
+import javax.management.MBeanServerDelegate;
+
+/**
+ * <p>This class is responsible for creating new instances of {@link MBeanServerDelegate}
+ * and {@link MBeanServer}. It creates instances from the implementation in the
+ * <code>mx4j.server</code> package.</p>
+ *
+ * <p>The {@link javax.management.MBeanServerFactory} first creates the delegate, then it
+ * creates the MBeanServer and provides a reference to the created delegate to it.
+ * Note that the delegate passed to the MBeanServer might not be the instance returned
+ * by this builder; for example, it could be a wrapper around it.</p>
+ *
+ * @see MBeanServer
+ * @see javax.management.MBeanServerFactory
+ *
+ * @author <a href="mailto:oreinert@users.sourceforge.net">Olav Reinert</a>
+ * @version $Revision: 1.1.1.1 $
+ **/
+
+public class MX4JMBeanServerBuilder extends MBeanServerBuilder
+{
+ /**
+ * Returns a new {@link MX4JMBeanServerDelegate} instance for a new MBeanServer.
+ * @return a new {@link MX4JMBeanServerDelegate} instance for a new MBeanServer.
+ **/
+ public MBeanServerDelegate newMBeanServerDelegate()
+ {
+ return new MX4JMBeanServerDelegate();
+ }
+
+ /**
+ * Returns a new {@link MX4JMBeanServer} instance.
+ * @param defaultDomain the default domain name for the new server.
+ * @param outer the {@link MBeanServer} that is passed in calls to
+ * {@link javax.management.MBeanRegistration#preRegister(javax.management.MBeanServer, javax.management.ObjectName)}.
+ * @param delegate the {@link MBeanServerDelegate} instance for the new server.
+ * @return a new {@link MX4JMBeanServer} instance.
+ **/
+ public MBeanServer newMBeanServer(String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate)
+ {
+ return new MX4JMBeanServer(defaultDomain, outer, delegate);
+ }
+}
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MX4JMBeanServerDelegate.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/MX4JMBeanServerDelegate.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/MX4JMBeanServerDelegate.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/MX4JMBeanServerDelegate.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,52 @@
+/*
+ * 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.MBeanServerDelegate;
+
+/**
+ * The MBeanServerDelegate subclass typical of the MX4J implementation.
+ *
+ * @see javax.management.MBeanServerBuilder
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class MX4JMBeanServerDelegate extends MBeanServerDelegate
+{
+ public String getImplementationName()
+ {
+ return "MX4J";
+ }
+
+ public String getImplementationVendor()
+ {
+ return "The MX4J Team";
+ }
+
+ public String getImplementationVersion()
+ {
+ return "2.0-beta-1";
+ }
+}
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/ModifiableClassLoaderRepository.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/ModifiableClassLoaderRepository.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/ModifiableClassLoaderRepository.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/ModifiableClassLoaderRepository.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,54 @@
+/*
+ * 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.loading.ClassLoaderRepository;
+
+/**
+ * Base class to extend to create custom ClassLoaderRepositories.
+ * MX4J's MBeanServer can use a custom ClassLoaderRepository instead of the default one
+ * by simply specifying a suitable system property, see {@link mx4j.MX4JSystemKeys}.
+ * It must be a class, otherwise it opens up a security hole, as anyone can cast the MBeanServer's
+ * ClassLoaderRepository down to this class and call addClassLoader or removeClassLoader
+ * since, if this class is an interface, they must be public.
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public abstract class ModifiableClassLoaderRepository implements ClassLoaderRepository
+{
+ /**
+ * Adds, if does not already exist, the specified ClassLoader to this repository.
+ * @param cl The classloader to add
+ * @see #removeClassLoader
+ */
+ protected abstract void addClassLoader(ClassLoader cl);
+
+ /**
+ * Removes, if exists, the specified ClassLoader from this repository.
+ * @param cl The classloader to remove
+ * @see #addClassLoader
+ */
+ protected abstract void removeClassLoader(ClassLoader cl);
+}
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/ReflectedMBeanInvoker.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/ReflectedMBeanInvoker.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/ReflectedMBeanInvoker.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/ReflectedMBeanInvoker.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,302 @@
+/*
+ * 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.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.Attribute;
+import javax.management.AttributeNotFoundException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.JMRuntimeException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.ReflectionException;
+import javax.management.RuntimeErrorException;
+import javax.management.RuntimeMBeanException;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.felix.mosgi.jmx.agent.mx4j.ImplementationException;
+import org.apache.felix.mosgi.jmx.agent.mx4j.util.Utils;
+import org.apache.felix.mosgi.jmx.agent.mx4j.util.MethodTernaryTree;
+
+/**
+ * MBeanInvoker that uses reflection to invoke on MBean instances.
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class ReflectedMBeanInvoker implements MBeanInvoker
+{
+ private static final String[] EMPTY_PARAMS = new String[0];
+ private static final Object[] EMPTY_ARGS = new Object[0];
+
+ private final Map attributes = new HashMap();
+ private final Map attributeNames = new HashMap();
+ private final MethodTernaryTree operations = new MethodTernaryTree();
+ private final MethodTernaryTree methods = new MethodTernaryTree();
+
+ public Object invoke(MBeanMetaData metadata, String method, String[] params, Object[] args) throws MBeanException, ReflectionException
+ {
+ MBeanOperationInfo oper = getStandardOperationInfo(metadata, method, params);
+ if (oper != null)
+ {
+ try
+ {
+ return invokeImpl(metadata, method, params, args);
+ }
+ catch (IllegalArgumentException x)
+ {
+ throw new RuntimeOperationsException(x);
+ }
+ }
+ else
+ {
+ throw new ReflectionException(new NoSuchMethodException("Operation " + method + " does not belong to the management interface"));
+ }
+ }
+
+ public Object getAttribute(MBeanMetaData metadata, String attribute) throws MBeanException, AttributeNotFoundException, ReflectionException
+ {
+ MBeanAttributeInfo attr = getStandardAttributeInfo(metadata, attribute, false);
+ if (attr != null)
+ {
+ String attributeName = getAttributeName(attr, true);
+ try
+ {
+ return invokeImpl(metadata, attributeName, EMPTY_PARAMS, EMPTY_ARGS);
+ }
+ catch (IllegalArgumentException x)
+ {
+ // Never thrown, since there are no arguments
+ throw new ImplementationException();
+ }
+ }
+ else
+ {
+ throw new AttributeNotFoundException(attribute);
+ }
+ }
+
+ public void setAttribute(MBeanMetaData metadata, Attribute attribute) throws MBeanException, AttributeNotFoundException, InvalidAttributeValueException, ReflectionException
+ {
+ String name = attribute.getName();
+ MBeanAttributeInfo attr = getStandardAttributeInfo(metadata, name, true);
+ if (attr != null)
+ {
+ String attributeName = getAttributeName(attr, false);
+ try
+ {
+ invokeImpl(metadata, attributeName, new String[]{attr.getType()}, new Object[]{attribute.getValue()});
+ }
+ catch (IllegalArgumentException x)
+ {
+ throw new InvalidAttributeValueException("Invalid value for attribute " + name + ": " + attribute.getValue());
+ }
+ }
+ else
+ {
+ throw new AttributeNotFoundException(name);
+ }
+ }
+
+ protected Object invokeImpl(MBeanMetaData metadata, String method, String[] signature, Object[] args) throws ReflectionException, MBeanException, IllegalArgumentException
+ {
+ Method m = getStandardManagementMethod(metadata, method, signature);
+
+ try
+ {
+ return m.invoke(metadata.mbean, args);
+ }
+ catch (IllegalAccessException x)
+ {
+ throw new ReflectionException(x);
+ }
+ catch (InvocationTargetException x)
+ {
+ Throwable t = x.getTargetException();
+ if (t instanceof Error) throw new RuntimeErrorException((Error)t);
+ if (t instanceof JMRuntimeException) throw (JMRuntimeException)t;
+ if (t instanceof RuntimeException) throw new RuntimeMBeanException((RuntimeException)t);
+ throw new MBeanException((Exception)t);
+ }
+ }
+
+ private MBeanAttributeInfo getStandardAttributeInfo(MBeanMetaData metadata, String attribute, boolean isWritable)
+ {
+ MBeanAttributeInfo attr = null;
+ synchronized (attributes)
+ {
+ attr = (MBeanAttributeInfo)attributes.get(attribute);
+ }
+ if (attr != null)
+ {
+ if (isWritable && attr.isWritable()) return attr;
+ if (!isWritable && attr.isReadable()) return attr;
+ }
+ else
+ {
+ MBeanAttributeInfo[] attrs = metadata.info.getAttributes();
+ if (attrs != null)
+ {
+ for (int i = 0; i < attrs.length; ++i)
+ {
+ attr = attrs[i];
+ String name = attr.getName();
+ if (attribute.equals(name))
+ {
+ synchronized (attributes)
+ {
+ attributes.put(attribute, attr);
+ }
+ if (isWritable && attr.isWritable()) return attr;
+ if (!isWritable && attr.isReadable()) return attr;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private MBeanOperationInfo getStandardOperationInfo(MBeanMetaData metadata, String method, String[] signature)
+ {
+ MBeanOperationInfo oper = null;
+
+ synchronized (operations)
+ {
+ oper = (MBeanOperationInfo)operations.get(method, signature);
+ }
+
+ if (oper != null) return oper;
+
+ // The MBeanOperationInfo is not in the cache, look it up
+ MBeanInfo info = metadata.info;
+ MBeanOperationInfo[] opers = info.getOperations();
+ if (opers != null)
+ {
+ for (int i = 0; i < opers.length; ++i)
+ {
+ oper = opers[i];
+ String name = oper.getName();
+ if (method.equals(name))
+ {
+ // Same method name, check number of parameters
+ MBeanParameterInfo[] params = oper.getSignature();
+ if (signature.length == params.length)
+ {
+ boolean match = true;
+ for (int j = 0; j < params.length; ++j)
+ {
+ MBeanParameterInfo param = params[j];
+ if (!signature[j].equals(param.getType()))
+ {
+ match = false;
+ break;
+ }
+ }
+ if (match)
+ {
+ synchronized (operations)
+ {
+ operations.put(method, signature, oper);
+ }
+ return oper;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private Method getStandardManagementMethod(MBeanMetaData metadata, String name, String[] signature) throws ReflectionException
+ {
+ Method method = null;
+ synchronized (methods)
+ {
+ method = (Method)methods.get(name, signature);
+ }
+ if (method != null) return method;
+
+ // Method is not in cache, look it up
+ try
+ {
+ Class[] params = Utils.loadClasses(metadata.classloader, signature);
+ method = metadata.mbean.getClass().getMethod(name, params);
+ synchronized (methods)
+ {
+ methods.put(name, signature, method);
+ }
+ return method;
+ }
+ catch (ClassNotFoundException x)
+ {
+ throw new ReflectionException(x);
+ }
+ catch (NoSuchMethodException x)
+ {
+ throw new ReflectionException(x);
+ }
+ }
+
+ private String getAttributeName(MBeanAttributeInfo attribute, boolean getter)
+ {
+ AttributeName attributeName = null;
+ String name = attribute.getName();
+ synchronized (attributeNames)
+ {
+ attributeName = (AttributeName)attributeNames.get(name);
+ }
+ if (attributeName == null)
+ {
+ String prefix = attribute.isIs() ? "is" : "get";
+ attributeName = new AttributeName(prefix + name, "set" + name);
+ synchronized (attributeNames)
+ {
+ attributeNames.put(name, attributeName);
+ }
+ }
+
+ if (getter) return attributeName.getter;
+ return attributeName.setter;
+ }
+
+ private static class AttributeName
+ {
+ private final String getter;
+ private final String setter;
+
+ public AttributeName(String getter, String setter)
+ {
+ this.getter = getter;
+ this.setter = setter;
+ }
+ }
+}
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/ContextClassLoaderMBeanServerInterceptor.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/interceptor/ContextClassLoaderMBeanServerInterceptor.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/interceptor/ContextClassLoaderMBeanServerInterceptor.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/ContextClassLoaderMBeanServerInterceptor.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,329 @@
+/*
+ * 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.interceptor;
+
+import java.security.PrivilegedAction;
+import java.security.AccessController;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ReflectionException;
+
+import org.apache.felix.mosgi.jmx.agent.mx4j.server.MBeanMetaData;
+
+/**
+ * This interceptor sets the context class loader to the proper value for incoming calls.
+ * It saves the current context class loader, set the context class loader to be the MBean's class loader for
+ * the current call, and on return re-set the context class loader to the previous value
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class ContextClassLoaderMBeanServerInterceptor extends DefaultMBeanServerInterceptor
+{
+ public ContextClassLoaderMBeanServerInterceptor()
+ {
+ // Disabled by default
+ setEnabled(false);
+ }
+
+ public String getType()
+ {
+ return "contextclassloader";
+ }
+
+ public void addNotificationListener(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback)
+ {
+ if (isEnabled())
+ {
+ ClassLoader context = getContextClassLoader();
+ if (metadata.classloader != context)
+ {
+ try
+ {
+ setContextClassLoader(metadata.classloader);
+ super.addNotificationListener(metadata, listener, filter, handback);
+ return;
+ }
+ finally
+ {
+ setContextClassLoader(context);
+ }
+ }
+ }
+
+ super.addNotificationListener(metadata, listener, filter, handback);
+ }
+
+ public void removeNotificationListener(MBeanMetaData metadata, NotificationListener listener) throws ListenerNotFoundException
+ {
+ if (isEnabled())
+ {
+ ClassLoader context = getContextClassLoader();
+ if (metadata.classloader != context)
+ {
+ try
+ {
+ setContextClassLoader(metadata.classloader);
+ super.removeNotificationListener(metadata, listener);
+ return;
+ }
+ finally
+ {
+ setContextClassLoader(context);
+ }
+ }
+ }
+
+ super.removeNotificationListener(metadata, listener);
+ }
+
+ public void removeNotificationListener(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException
+ {
+ if (isEnabled())
+ {
+ ClassLoader context = getContextClassLoader();
+ if (metadata.classloader != context)
+ {
+ try
+ {
+ setContextClassLoader(metadata.classloader);
+ super.removeNotificationListener(metadata, listener, filter, handback);
+ return;
+ }
+ finally
+ {
+ setContextClassLoader(context);
+ }
+ }
+ }
+
+ super.removeNotificationListener(metadata, listener, filter, handback);
+ }
+
+ public void instantiate(MBeanMetaData metadata, String className, String[] params, Object[] args) throws ReflectionException, MBeanException
+ {
+ if (isEnabled())
+ {
+ ClassLoader context = getContextClassLoader();
+ if (metadata.classloader != context)
+ {
+ try
+ {
+ setContextClassLoader(metadata.classloader);
+ super.instantiate(metadata, className, params, args);
+ return;
+ }
+ finally
+ {
+ setContextClassLoader(context);
+ }
+ }
+ }
+
+ super.instantiate(metadata, className, params, args);
+ }
+
+ public void registration(MBeanMetaData metadata, int operation) throws MBeanRegistrationException
+ {
+ if (isEnabled())
+ {
+ ClassLoader context = getContextClassLoader();
+ if (metadata.classloader != context)
+ {
+ try
+ {
+ setContextClassLoader(metadata.classloader);
+ super.registration(metadata, operation);
+ return;
+ }
+ finally
+ {
+ setContextClassLoader(context);
+ }
+ }
+ }
+
+ super.registration(metadata, operation);
+ }
+
+ public MBeanInfo getMBeanInfo(MBeanMetaData metadata)
+ {
+ if (isEnabled())
+ {
+ ClassLoader context = getContextClassLoader();
+ if (metadata.classloader != context)
+ {
+ try
+ {
+ setContextClassLoader(metadata.classloader);
+ return super.getMBeanInfo(metadata);
+ }
+ finally
+ {
+ setContextClassLoader(context);
+ }
+ }
+ }
+
+ return super.getMBeanInfo(metadata);
+ }
+
+ public Object invoke(MBeanMetaData metadata, String method, String[] params, Object[] args) throws MBeanException, ReflectionException
+ {
+ if (isEnabled())
+ {
+ ClassLoader context = getContextClassLoader();
+ if (metadata.classloader != context)
+ {
+ try
+ {
+ setContextClassLoader(metadata.classloader);
+ return super.invoke(metadata, method, params, args);
+ }
+ finally
+ {
+ setContextClassLoader(context);
+ }
+ }
+ }
+
+ return super.invoke(metadata, method, params, args);
+ }
+
+ public AttributeList getAttributes(MBeanMetaData metadata, String[] attributes)
+ {
+ if (isEnabled())
+ {
+ ClassLoader context = getContextClassLoader();
+ if (metadata.classloader != context)
+ {
+ try
+ {
+ setContextClassLoader(metadata.classloader);
+ return super.getAttributes(metadata, attributes);
+ }
+ finally
+ {
+ setContextClassLoader(context);
+ }
+ }
+ }
+
+ return super.getAttributes(metadata, attributes);
+ }
+
+ public AttributeList setAttributes(MBeanMetaData metadata, AttributeList attributes)
+ {
+ if (isEnabled())
+ {
+ ClassLoader context = getContextClassLoader();
+ if (metadata.classloader != context)
+ {
+ try
+ {
+ setContextClassLoader(metadata.classloader);
+ return super.setAttributes(metadata, attributes);
+ }
+ finally
+ {
+ setContextClassLoader(context);
+ }
+ }
+ }
+
+ return super.setAttributes(metadata, attributes);
+ }
+
+ public Object getAttribute(MBeanMetaData metadata, String attribute) throws MBeanException, AttributeNotFoundException, ReflectionException
+ {
+ if (isEnabled())
+ {
+ ClassLoader context = getContextClassLoader();
+ if (metadata.classloader != context)
+ {
+ try
+ {
+ setContextClassLoader(metadata.classloader);
+ return super.getAttribute(metadata, attribute);
+ }
+ finally
+ {
+ setContextClassLoader(context);
+ }
+ }
+ }
+
+ return super.getAttribute(metadata, attribute);
+ }
+
+ public void setAttribute(MBeanMetaData metadata, Attribute attribute) throws MBeanException, AttributeNotFoundException, InvalidAttributeValueException, ReflectionException
+ {
+ if (isEnabled())
+ {
+ ClassLoader context = getContextClassLoader();
+ if (metadata.classloader != context)
+ {
+ try
+ {
+ setContextClassLoader(metadata.classloader);
+ super.setAttribute(metadata, attribute);
+ return;
+ }
+ finally
+ {
+ setContextClassLoader(context);
+ }
+ }
+ }
+
+ super.setAttribute(metadata, attribute);
+ }
+
+ private ClassLoader getContextClassLoader()
+ {
+ return Thread.currentThread().getContextClassLoader();
+ }
+
+ private void setContextClassLoader(final ClassLoader cl)
+ {
+ AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ Thread.currentThread().setContextClassLoader(cl);
+ return null;
+ }
+ });
+ }
+}