| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.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); |
| } |
| } |