jdk/src/share/classes/javax/management/namespace/JMXDomain.java
changeset 1156 bbc2d15aaf7a
child 1222 78e3d021d528
equal deleted inserted replaced
1155:a9a142fcf1b5 1156:bbc2d15aaf7a
       
     1 /*
       
     2  * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package javax.management.namespace;
       
    27 
       
    28 import java.io.IOException;
       
    29 import javax.management.ListenerNotFoundException;
       
    30 import javax.management.NotificationFilter;
       
    31 import javax.management.NotificationListener;
       
    32 import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
       
    33 
       
    34 
       
    35 import javax.management.InstanceNotFoundException;
       
    36 import javax.management.MBeanServer;
       
    37 import javax.management.MBeanServerDelegate;
       
    38 import javax.management.MalformedObjectNameException;
       
    39 import javax.management.ObjectName;
       
    40 
       
    41 /**
       
    42  * A special {@link JMXNamespace} that can handle part of
       
    43  * the MBeanServer local name space.
       
    44  * <p>
       
    45  * A {@code JMXDomain} makes a domain <i>X</i> of a
       
    46  * {@linkplain #getSourceServer() source MBean server} appear in the same domain
       
    47  * <i>X</i> of a containing {@code MBeanServer} in which the
       
    48  * {@code JMXDomain} MBean {@linkplain #getMBeanServer() is registered}.
       
    49  * </p>
       
    50  * <p>
       
    51  * The JMX infrastructure of the containing {@code MBeanServer} takes care of
       
    52  * routing all calls to MBeans whose names have domain <i>X</i> to the
       
    53  * {@linkplain #getSourceServer() source MBean server} exported by the
       
    54  * {@code JMXDomain} MBean in charge of domain <i>X</i>.
       
    55  * </p>
       
    56  * <p>
       
    57  * The {@linkplain #getSourceServer() source MBean server} of a {@code JMXDomain}
       
    58  * can, but need not be a regular {@code MBeanServer} created through
       
    59  * the {@link javax.management.MBeanServerFactory}. It could also be,
       
    60  * for instance, an instance of a subclass of {@link MBeanServerSupport},
       
    61  * or a custom object implementing the {@link MBeanServer} interface.
       
    62  * </p>
       
    63  *
       
    64  * <h4>Differences between {@code JMXNamespace} and {@code JMXDomain}</h4>
       
    65  *
       
    66  * <p>
       
    67  * A {@code JMXDomain} is a special kind of {@code JMXNamespace}.
       
    68  * A {@code JMXNamespace} such as {@code foo//} is triggered by an
       
    69  * {@code ObjectName} that begins with the string {@code foo//}, for example
       
    70  * {@code foo//bar:type=Baz}.  A {@code JMXDomain} such as {@code foo} is
       
    71  * triggered by an {@code ObjectName} with that exact domain, for example
       
    72  * {@code foo:type=Baz}.  A client can immediately see that an MBean is
       
    73  * handled by a {@code JMXNamespace} because of the {@code //} in the name.
       
    74  * A client cannot see whether a name such as {@code foo:type=Baz} is an
       
    75  * ordinary MBean or is handled by a {@code JMXDomain}.
       
    76  * </p>
       
    77  *
       
    78  * <p>
       
    79  * A {@linkplain MBeanServer#queryNames query} on the containing {@code
       
    80  * MBeanserver} will return all MBeans from the {@code JMXDomain} that match
       
    81  * the query.  In particular, {@code queryNames(null, null)} will return all
       
    82  * MBeans including those from {@code JMXDomain} domains.  On the other hand,
       
    83  * a query will not include MBeans from a {@code JMXNamespace} unless the
       
    84  * {@code ObjectName} pattern in the query starts with the name of that
       
    85  * namespace.
       
    86  * </p>
       
    87  *
       
    88  * <h4 id="security">Permission checks</h4>
       
    89  *
       
    90  * <p>
       
    91  * When a JMXDomain MBean is registered in a containing
       
    92  * MBean server created through the default {@link
       
    93  * javax.management.MBeanServerBuilder}, and if a {@link
       
    94  * SecurityManager SecurityManager} is
       
    95  * {@linkplain System#getSecurityManager() present}, the containing MBeanServer will
       
    96  * check an {@link javax.management.MBeanPermission} before invoking
       
    97  * any method on the {@linkplain #getSourceServer() source MBeanServer} of the
       
    98  * JMXDomain.
       
    99  * </p>
       
   100  *
       
   101  * <p>First, if there is no security manager ({@link
       
   102  * System#getSecurityManager()} is null), that containing
       
   103  * {@code MBeanServer} is free not to make any checks.
       
   104  * </p>
       
   105  *
       
   106  * <p>
       
   107  * Assuming that there is a security manager, or that the
       
   108  * implementation chooses to make checks anyway, the containing
       
   109  * {@code MBeanServer} will perform
       
   110  * {@link javax.management.MBeanPermission MBeanPermission} checks
       
   111  * for access to the MBeans in domain <i>X</i> handled by a {@code JMXDomain}
       
   112  * in the same way that it would do for MBeans registered in its own local
       
   113  * repository, and as <a href="../MBeanServer.html#security">described in
       
   114  * the MBeanServer interface</a>, with the following exceptions:
       
   115  * </p>
       
   116  *
       
   117  * <p>
       
   118  * For those permissions that require a {@code className}, the
       
   119  * <code>className</code> is the
       
   120  * string returned by {@link #getSourceServer() getSourceServer()}.
       
   121  * {@link MBeanServer#getObjectInstance(ObjectName)
       
   122  * getObjectInstance(mbeanName)}.
       
   123  * {@link javax.management.ObjectInstance#getClassName() getClassName()},
       
   124  * except for {@code createMBean} and {@code registerMBean} operations,
       
   125  * for which the permission checks are performed as follows:
       
   126  * </p>
       
   127  * <ul>
       
   128  * <li><p>For {@code createMBean} operations, the {@code className} of the
       
   129  * permission you need is the {@code className} passed as first parameter
       
   130  * to {@code createMBean}.</p>
       
   131  *
       
   132  * <li><p>For {@code registerMBean} operations, the {@code className} of the
       
   133  * permission you need is the name of the class of the mbean object, as
       
   134  * returned by {@code mbean.getClass().getClassName()}, where
       
   135  * {@code mbean} is the mbean reference passed as first parameter
       
   136  * to {@code registerMBean}.</p>
       
   137  *
       
   138  * <li><p>In addition, for {@code createMBean} and {@code registerMBean}, the
       
   139  * permission you need is checked with the {@linkplain ObjectName object name} of
       
   140  * the mbean that is passed as second parameter to the {@code createMBean} or
       
   141  * {@code registerMBean} operation.
       
   142  * </p>
       
   143  *
       
   144  * <li><p>Contrarily to what is done for regular MBeans registered in the
       
   145  *     MBeanServer local repository, the containing MBeanServer will not
       
   146  *     check the {@link javax.management.MBeanTrustPermission#MBeanTrustPermission(String)
       
   147  *     MBeanTrustPermission("register")} against the protection domain
       
   148  *     of the MBean's class. This check can be performed by the
       
   149  *     {@linkplain #getSourceServer source MBean server} implementation,
       
   150  *     if necessary.
       
   151  * </p>
       
   152  * </ul>
       
   153  *
       
   154  * <p>If a security check fails, the method throws {@link
       
   155  * SecurityException}.</p>
       
   156  *
       
   157  * <p>For methods that can throw {@link InstanceNotFoundException},
       
   158  * this exception is thrown for a non-existent MBean, regardless of
       
   159  * permissions.  This is because a non-existent MBean has no
       
   160  * <code>className</code>.</p>
       
   161  *
       
   162  * All these checks are performed by the containing {@code MBeanServer},
       
   163  * before accessing the JMXDomain {@linkplain #getSourceServer source MBean server}.
       
   164  * The implementation of the JMXDomain {@linkplain #getSourceServer source MBean
       
   165  * server} is free to make any additional checks. In fact, if the JMXDomain
       
   166  * {@linkplain #getSourceServer source MBean server} is an {@code MBeanServer}
       
   167  * obtained through the {@link javax.management.MBeanServerFactory}, it will
       
   168  * again make permission checks as described in the
       
   169  * <a href="../MBeanServer.html#security">MBeanServer</a> interface.
       
   170  *
       
   171  * <p>See the <a href="../MBeanServer.html#security">MBeanServer</a> interface
       
   172  * for more details on permission checks.</p>
       
   173  *
       
   174  * @since 1.7
       
   175  */
       
   176 public class JMXDomain extends JMXNamespace {
       
   177 
       
   178 
       
   179     /**
       
   180      * This constant contains the value of the {@code type}
       
   181      * key used in defining a standard JMXDomain MBean object name.
       
   182      * By definition, a standard JMXDomain MBean object name must be of
       
   183      * the form:
       
   184      * <pre>
       
   185      * {@code "<domain>:"}+{@value javax.management.namespace.JMXDomain#TYPE_ASSIGNMENT}
       
   186      * </pre>
       
   187      */
       
   188     public static final String TYPE = "JMXDomain";
       
   189 
       
   190     /**
       
   191      * This constant contains the value of the standard
       
   192      * {@linkplain javax.management.ObjectName#getKeyPropertyListString() key
       
   193      * property list string} for JMXDomain MBean object names.
       
   194      * By definition, a standard JMXDomain MBean object name must be of
       
   195      * the form:
       
   196      * <pre>
       
   197      * {@code <domain>}+":"+{@value javax.management.namespace.JMXDomain#TYPE_ASSIGNMENT}
       
   198      * </pre>
       
   199      */
       
   200     public static final String TYPE_ASSIGNMENT = "type="+TYPE;
       
   201 
       
   202 
       
   203 
       
   204     /**
       
   205      * Creates a new instance of JMXDomain. The MBeans contained in this
       
   206      * domain are handled by the {@code virtualServer} object given to
       
   207      * this constructor. Frequently, this will be an instance of
       
   208      * {@link MBeanServerSupport}.
       
   209      * @param virtualServer The virtual server that acts as a container for
       
   210      *        the MBeans handled by this JMXDomain object. Frequently, this will
       
   211      *        be an instance of {@link MBeanServerSupport}
       
   212      * @see JMXNamespace#JMXNamespace(MBeanServer)
       
   213      */
       
   214     public JMXDomain(MBeanServer virtualServer) {
       
   215         super(virtualServer);
       
   216     }
       
   217 
       
   218     /**
       
   219      * Return the name of domain handled by this JMXDomain.
       
   220      * @return the domain handled by this JMXDomain.
       
   221      * @throws IOException - if the domain cannot be determined,
       
   222      *         for instance, if the MBean is not registered yet.
       
   223      */
       
   224     @Override
       
   225     public final String getDefaultDomain() {
       
   226         final ObjectName name = getObjectName();
       
   227         if (name == null)
       
   228             throw new IllegalStateException("DefaultDomain is not yet known");
       
   229         final String dom = name.getDomain();
       
   230         return dom;
       
   231     }
       
   232 
       
   233     /**
       
   234      * Returns a singleton array, containing the only domain handled by
       
   235      * this JMXDomain object. This is
       
   236      * {@code new String[] {getDefaultDomain()}}.
       
   237      * @return the only domain handled by this JMXDomain.
       
   238      * @throws IOException if the domain cannot be determined,
       
   239      *         for instance, if the MBean is not registered yet.
       
   240      * @see #getDefaultDomain()
       
   241      */
       
   242     @Override
       
   243     public final String[] getDomains() {
       
   244         return new String[] {getDefaultDomain()};
       
   245     }
       
   246 
       
   247     /**
       
   248      * This method returns the number of MBeans in the domain handled
       
   249      * by this JMXDomain object. The default implementation is:
       
   250      * <pre>
       
   251      *    getSourceServer().queryNames(
       
   252      *        new ObjectName(getObjectName().getDomain()+":*"), null).size();
       
   253      * </pre>
       
   254      * If this JMXDomain is not yet registered, this method returns 0.
       
   255      * Subclasses can override the above behavior and provide a better
       
   256      * implementation.
       
   257      * <p>
       
   258      * The getMBeanCount() method is called when computing the number
       
   259      * of MBeans in the {@linkplain #getMBeanServer() containing MBeanServer}.
       
   260      * @return the number of MBeans in this domain, or 0.
       
   261      */
       
   262     @Override
       
   263     public Integer getMBeanCount()  {
       
   264         final ObjectName name = getObjectName();
       
   265         if (name == null) return 0;
       
   266         try {
       
   267             return getSourceServer().
       
   268                queryNames(ObjectName.WILDCARD.withDomain(name.getDomain()),
       
   269                null).size();
       
   270         } catch (RuntimeException x) {
       
   271             throw x;
       
   272         } catch (Exception x) {
       
   273             throw new RuntimeException("Unexpected exception: "+x,x);
       
   274         }
       
   275     }
       
   276 
       
   277 
       
   278 
       
   279     /**
       
   280      * Return a canonical handler name for the provided local
       
   281      * <var>domain</var> name, or null if the provided domain name is
       
   282      * {@code null}.
       
   283      * If not null, the handler name returned will be
       
   284      * {@code domain+":type="+}{@link #TYPE TYPE}, for example
       
   285      * {@code foo:type=JMXDomain}.
       
   286      * @param domain A domain name
       
   287      * @return a canonical ObjectName for a domain handler.
       
   288      * @throws IllegalArgumentException if the provided
       
   289      *         <var>domain</var> is not valid - e.g it contains "//".
       
   290      */
       
   291     public static ObjectName getDomainObjectName(String domain) {
       
   292         if (domain == null) return null;
       
   293         if (domain.contains(NAMESPACE_SEPARATOR))
       
   294             throw new IllegalArgumentException(domain);
       
   295         try {
       
   296             return ObjectName.getInstance(domain, "type", TYPE);
       
   297         } catch (MalformedObjectNameException x) {
       
   298             throw new IllegalArgumentException(domain,x);
       
   299         }
       
   300     }
       
   301 
       
   302 
       
   303     /**
       
   304      * Validate the ObjectName supplied to preRegister.
       
   305      * This method is introduced to allow standard subclasses to use
       
   306      * an alternate naming scheme. For instance - if we want to
       
   307      * reuse JMXNamespace in order to implement sessions...
       
   308      * It is however only available for subclasses in this package.
       
   309      **/
       
   310     @Override
       
   311     ObjectName validateHandlerName(ObjectName supliedName) {
       
   312         if (supliedName == null)
       
   313             throw new IllegalArgumentException("Must supply a valid name");
       
   314         final String dirName = JMXNamespaces.
       
   315                 normalizeNamespaceName(supliedName.getDomain());
       
   316         final ObjectName handlerName = getDomainObjectName(dirName);
       
   317         if (!supliedName.equals(handlerName))
       
   318             throw new IllegalArgumentException("invalid name space name: "+
       
   319                         supliedName);
       
   320 
       
   321         return supliedName;
       
   322     }
       
   323 
       
   324     /**
       
   325      * This method is called by the JMX framework to register a
       
   326      * NotificationListener that will forward {@linkplain
       
   327      * javax.management.MBeanServerNotification mbean server notifications}
       
   328      * through the delegate of the {@linkplain #getMBeanServer()
       
   329      * containing MBeanServer}.
       
   330      * The default implementation of this method is to call
       
   331      * <pre>
       
   332      *    getSourceServer().addNotificationListener(
       
   333      *           MBeanServerDelegate.DELEGATE_NAME, listener, filter, null);
       
   334      * </pre>
       
   335      * Subclasses can redefine this behavior if needed. In particular,
       
   336      * subclasses can send their own instances of {@link
       
   337      * javax.management.MBeanServerNotification} by calling
       
   338      * {@code listener.handleNotification()}.
       
   339      *
       
   340      * @param listener The MBeanServerNotification listener for this domain.
       
   341      * @param filter   A notification filter.
       
   342      */
       
   343     public void addMBeanServerNotificationListener(
       
   344             NotificationListener listener, NotificationFilter filter) {
       
   345         try {
       
   346             getSourceServer().addNotificationListener(
       
   347                 MBeanServerDelegate.DELEGATE_NAME, listener, filter, null);
       
   348         } catch(InstanceNotFoundException x) {
       
   349             throw new UnsupportedOperationException(
       
   350                     "Unexpected exception: " +
       
   351                     "Emission of MBeanServerNotification disabled.", x);
       
   352         }
       
   353     }
       
   354 
       
   355     /**
       
   356      * This method is called by the JMX framework to remove the
       
   357      * NotificationListener that was added with {@link
       
   358      * #addMBeanServerNotificationListener addMBeanServerNotificationListener}.
       
   359      * The default implementation of this method is to call
       
   360      * <pre>
       
   361      *    getSourceServer().removeNotificationListener(
       
   362      *           MBeanServerDelegate.DELEGATE_NAME, listener);
       
   363      * </pre>
       
   364      * Subclasses can redefine this behavior if needed.
       
   365      *
       
   366      * @param listener The MBeanServerNotification listener for this domain.
       
   367      * @throws ListenerNotFoundException if the listener is not found.
       
   368      */
       
   369     public void removeMBeanServerNotificationListener(
       
   370             NotificationListener listener)
       
   371             throws ListenerNotFoundException {
       
   372         try {
       
   373             getSourceServer().removeNotificationListener(
       
   374                 MBeanServerDelegate.DELEGATE_NAME, listener);
       
   375         } catch(InstanceNotFoundException x) {
       
   376             throw new UnsupportedOperationException(
       
   377                     "Unexpected exception: " +
       
   378                     "Emission of MBeanServerNotification disabled.", x);
       
   379         }
       
   380     }
       
   381 
       
   382 }