/* * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package javax.management.namespace; import java.io.IOException; import javax.management.ListenerNotFoundException; import javax.management.NotificationFilter; import javax.management.NotificationListener; import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR; import javax.management.InstanceNotFoundException; import javax.management.MBeanServer; import javax.management.MBeanServerDelegate; import javax.management.ObjectName; /** * A special {@link JMXNamespace} that can handle part of * the MBeanServer local name space. *
* A {@code JMXDomain} makes a domain X of a * {@linkplain #getSourceServer() source MBean server} appear in the same domain * X of a containing {@code MBeanServer} in which the * {@code JMXDomain} MBean {@linkplain #getMBeanServer() is registered}. *
** The JMX infrastructure of the containing {@code MBeanServer} takes care of * routing all calls to MBeans whose names have domain X to the * {@linkplain #getSourceServer() source MBean server} exported by the * {@code JMXDomain} MBean in charge of domain X. *
** The {@linkplain #getSourceServer() source MBean server} of a {@code JMXDomain} * can, but need not be a regular {@code MBeanServer} created through * the {@link javax.management.MBeanServerFactory}. It could also be, * for instance, an instance of a subclass of {@link MBeanServerSupport}, * or a custom object implementing the {@link MBeanServer} interface. *
* ** A {@code JMXDomain} is a special kind of {@code JMXNamespace}. * A {@code JMXNamespace} such as {@code foo//} is triggered by an * {@code ObjectName} that begins with the string {@code foo//}, for example * {@code foo//bar:type=Baz}. A {@code JMXDomain} such as {@code foo} is * triggered by an {@code ObjectName} with that exact domain, for example * {@code foo:type=Baz}. A client can immediately see that an MBean is * handled by a {@code JMXNamespace} because of the {@code //} in the name. * A client cannot see whether a name such as {@code foo:type=Baz} is an * ordinary MBean or is handled by a {@code JMXDomain}. *
* ** A {@linkplain MBeanServer#queryNames query} on the containing {@code * MBeanserver} will return all MBeans from the {@code JMXDomain} that match * the query. In particular, {@code queryNames(null, null)} will return all * MBeans including those from {@code JMXDomain} domains. On the other hand, * a query will not include MBeans from a {@code JMXNamespace} unless the * {@code ObjectName} pattern in the query starts with the name of that * namespace. *
* ** When a JMXDomain MBean is registered in a containing * MBean server created through the default {@link * javax.management.MBeanServerBuilder}, and if a {@link * SecurityManager SecurityManager} is * {@linkplain System#getSecurityManager() present}, the containing MBeanServer will * check an {@link javax.management.MBeanPermission} before invoking * any method on the {@linkplain #getSourceServer() source MBeanServer} of the * JMXDomain. *
* *First, if there is no security manager ({@link * System#getSecurityManager()} is null), that containing * {@code MBeanServer} is free not to make any checks. *
* ** Assuming that there is a security manager, or that the * implementation chooses to make checks anyway, the containing * {@code MBeanServer} will perform * {@link javax.management.MBeanPermission MBeanPermission} checks * for access to the MBeans in domain X handled by a {@code JMXDomain} * in the same way that it would do for MBeans registered in its own local * repository, and as described in * the MBeanServer interface, with the following exceptions: *
* *
* For those permissions that require a {@code className}, the
* className
is the
* string returned by {@link #getSourceServer() getSourceServer()}.
* {@link MBeanServer#getObjectInstance(ObjectName)
* getObjectInstance(mbeanName)}.
* {@link javax.management.ObjectInstance#getClassName() getClassName()},
* except for {@code createMBean} and {@code registerMBean} operations,
* for which the permission checks are performed as follows:
*
For {@code createMBean} operations, the {@code className} of the * permission you need is the {@code className} passed as first parameter * to {@code createMBean}.
* *For {@code registerMBean} operations, the {@code className} of the * permission you need is the name of the class of the mbean object, as * returned by {@code mbean.getClass().getClassName()}, where * {@code mbean} is the mbean reference passed as first parameter * to {@code registerMBean}.
* *In addition, for {@code createMBean} and {@code registerMBean}, the * permission you need is checked with the {@linkplain ObjectName object name} of * the mbean that is passed as second parameter to the {@code createMBean} or * {@code registerMBean} operation. *
* *Contrarily to what is done for regular MBeans registered in the * MBeanServer local repository, the containing MBeanServer will not * check the {@link javax.management.MBeanTrustPermission#MBeanTrustPermission(String) * MBeanTrustPermission("register")} against the protection domain * of the MBean's class. This check can be performed by the * {@linkplain #getSourceServer source MBean server} implementation, * if necessary. *
*If a security check fails, the method throws {@link * SecurityException}.
* *For methods that can throw {@link InstanceNotFoundException},
* this exception is thrown for a non-existent MBean, regardless of
* permissions. This is because a non-existent MBean has no
* className
.
See the MBeanServer interface * for more details on permission checks.
* * @since 1.7 */ public class JMXDomain extends JMXNamespace { /** * This constant contains the value of the {@code type} * key used in defining a standard JMXDomain MBean object name. * By definition, a standard JMXDomain MBean object name must be of * the form: ** {@code "*/ public static final String TYPE = "JMXDomain"; /** * This constant contains the value of the standard * {@linkplain javax.management.ObjectName#getKeyPropertyListString() key * property list string} for JMXDomain MBean object names. * By definition, a standard JMXDomain MBean object name must be of * the form: *:"}+{@value javax.management.namespace.JMXDomain#TYPE_ASSIGNMENT} *
* {@code*/ public static final String TYPE_ASSIGNMENT = "type="+TYPE; /** * Creates a new instance of JMXDomain. The MBeans contained in this * domain are handled by the {@code virtualServer} object given to * this constructor. Frequently, this will be an instance of * {@link MBeanServerSupport}. * @param virtualServer The virtual server that acts as a container for * the MBeans handled by this JMXDomain object. Frequently, this will * be an instance of {@link MBeanServerSupport} * @see JMXNamespace#JMXNamespace(MBeanServer) */ public JMXDomain(MBeanServer virtualServer) { super(virtualServer); } /** * Return the name of domain handled by this JMXDomain. * @return the domain handled by this JMXDomain. * @throws IOException - if the domain cannot be determined, * for instance, if the MBean is not registered yet. */ @Override public final String getDefaultDomain() { final ObjectName name = getObjectName(); if (name == null) throw new IllegalStateException("DefaultDomain is not yet known"); final String dom = name.getDomain(); return dom; } /** * Returns a singleton array, containing the only domain handled by * this JMXDomain object. This is * {@code new String[] {getDefaultDomain()}}. * @return the only domain handled by this JMXDomain. * @throws IOException if the domain cannot be determined, * for instance, if the MBean is not registered yet. * @see #getDefaultDomain() */ @Override public final String[] getDomains() { return new String[] {getDefaultDomain()}; } /** * This method returns the number of MBeans in the domain handled * by this JMXDomain object. The default implementation is: *}+":"+{@value javax.management.namespace.JMXDomain#TYPE_ASSIGNMENT} *
* getSourceServer().queryNames( * new ObjectName(getObjectName().getDomain()+":*"), null).size(); ** If this JMXDomain is not yet registered, this method returns 0. * Subclasses can override the above behavior and provide a better * implementation. *
* The getMBeanCount() method is called when computing the number * of MBeans in the {@linkplain #getMBeanServer() containing MBeanServer}. * @return the number of MBeans in this domain, or 0. */ @Override public Integer getMBeanCount() { final ObjectName name = getObjectName(); if (name == null) return 0; try { return getSourceServer(). queryNames(ObjectName.WILDCARD.withDomain(name.getDomain()), null).size(); } catch (RuntimeException x) { throw x; } catch (Exception x) { throw new RuntimeException("Unexpected exception: "+x,x); } } /** * Return a canonical handler name for the provided local * domain name, or null if the provided domain name is * {@code null}. * If not null, the handler name returned will be * {@code domain+":type="+}{@link #TYPE TYPE}, for example * {@code foo:type=JMXDomain}. * @param domain A domain name * @return a canonical ObjectName for a domain handler. * @throws IllegalArgumentException if the provided * domain is not valid - e.g it contains "//". */ public static ObjectName getDomainObjectName(String domain) { if (domain == null) return null; if (domain.contains(NAMESPACE_SEPARATOR)) throw new IllegalArgumentException("domain contains " + NAMESPACE_SEPARATOR+": "+domain); return ObjectName.valueOf(domain, "type", TYPE); } /** * Validate the ObjectName supplied to preRegister. * This method is introduced to allow standard subclasses to use * an alternate naming scheme. For instance - if we want to * reuse JMXNamespace in order to implement sessions... * It is however only available for subclasses in this package. **/ @Override ObjectName validateHandlerName(ObjectName suppliedName) { if (suppliedName == null) throw new IllegalArgumentException("Must supply a valid name"); final String dirName = JMXNamespaces. normalizeNamespaceName(suppliedName.getDomain()); final ObjectName handlerName = getDomainObjectName(dirName); if (!suppliedName.equals(handlerName)) throw new IllegalArgumentException("invalid name space name: "+ suppliedName); return suppliedName; } /** * This method is called by the JMX framework to register a * NotificationListener that will forward {@linkplain * javax.management.MBeanServerNotification mbean server notifications} * through the delegate of the {@linkplain #getMBeanServer() * containing MBeanServer}. * The default implementation of this method is to call *
* getSourceServer().addNotificationListener( * MBeanServerDelegate.DELEGATE_NAME, listener, filter, null); ** Subclasses can redefine this behavior if needed. In particular, * subclasses can send their own instances of {@link * javax.management.MBeanServerNotification} by calling * {@code listener.handleNotification()}. * * @param listener The MBeanServerNotification listener for this domain. * @param filter A notification filter. */ public void addMBeanServerNotificationListener( NotificationListener listener, NotificationFilter filter) { try { getSourceServer().addNotificationListener( MBeanServerDelegate.DELEGATE_NAME, listener, filter, null); } catch(InstanceNotFoundException x) { throw new UnsupportedOperationException( "Unexpected exception: " + "Emission of MBeanServerNotification disabled.", x); } } /** * This method is called by the JMX framework to remove the * NotificationListener that was added with {@link * #addMBeanServerNotificationListener addMBeanServerNotificationListener}. * The default implementation of this method is to call *
* getSourceServer().removeNotificationListener( * MBeanServerDelegate.DELEGATE_NAME, listener); ** Subclasses can redefine this behavior if needed. * * @param listener The MBeanServerNotification listener for this domain. * @throws ListenerNotFoundException if the listener is not found. */ public void removeMBeanServerNotificationListener( NotificationListener listener) throws ListenerNotFoundException { try { getSourceServer().removeNotificationListener( MBeanServerDelegate.DELEGATE_NAME, listener); } catch(InstanceNotFoundException x) { throw new UnsupportedOperationException( "Unexpected exception: " + "Emission of MBeanServerNotification disabled.", x); } } }