/* * 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. */ /** *

The javax.management.namespace package makes it possible * to federate MBeanServers into a hierarchical name space.

* *

What Is a Name Space?

*

* A name space is like an {@link javax.management.MBeanServer} within * an {@code MBeanServer}. Just as a file system folder can contain * another file system folder, an {@code MBeanServer} can contain another * {@code MBeanServer}. Similarly, just as a remote folder on a remote * disk can be mounted on a parent folder on a local disk, a remote name * space in a remote {@code MBeanServer} can be mounted on a name * space in a local parent {@code MBeanServer}. *

*

* The javax.management.namespace API thus makes it possible to * create a hierarchy of MBean servers federated in a hierarchical name * space inside a single {@code MBeanServer}. *

*

How To Create a Name Space?

*

* To create a name space, you only need to register a * {@link javax.management.namespace.JMXNamespace} MBean in * an MBean server. We have seen that a namespace is like * an {@code MBeanServer} within an {@code MBeanServer}, and * therefore, it is possible to create a namespace that shows the * content of another {@code MBeanServer}. The simplest case is * when that {@code MBeanServer} is another {@code MBeanServer} * created by the {@link javax.management.MBeanServerFactory} as * shown in the extract below: *

*
 *  final MBeanServer server = ....;
 *  final String namespace = "foo";
 *  final ObjectName namespaceName = {@link javax.management.namespace.JMXNamespaces#getNamespaceObjectName
 *        JMXNamespaces.getNamespaceObjectName(namespace)};
 *  server.registerMBean(new JMXNamespace(MBeanServerFactory.newMBeanServer()),
 *                      namespaceName);
 *  
*

* To navigate in namespaces and view their content, the easiest way is * to use an instance of {@link javax.management.namespace.JMXNamespaceView}. For instance, given * the {@code server} above, in which we created a namespace {@code "foo"}, * it is possible to create a {@code JMXNamespaceView} that will make it * possible to navigate easily in the namespaces and sub-namespaces of that * server: *

*
 *  // create a namespace view for 'server'
 *  final JMXNamespaceView view = new JMXNamespaceView(server);
 *
 *  // list all top level namespaces in 'server'
 *  System.out.println("List of namespaces: " + Arrays.toString({@link javax.management.namespace.JMXNamespaceView#list() view.list()}));
 *
 *  // go down into namespace 'foo': provides a namespace view of 'foo' and its
 *  // sub namespaces...
 *  final JMXNamespaceView foo = {@link javax.management.namespace.JMXNamespaceView#down view.down("foo")};
 *
 *  // list all MBeans contained in namespace 'foo'
 *  System.out.println({@link javax.management.namespace.JMXNamespaceView#where() foo.where()} + " contains: " +
 *         {@link javax.management.namespace.JMXNamespaceView#getMBeanServerConnection foo.getMBeanServerConnection()}.queryNames(null,null));
 *  
*

* It is also possible to create more complex namespaces, such as namespaces * that point to MBean servers located in remote JVMs. *

*

* For instance, to mount the MBeanServer accessible * at service:jmx:rmi:///jndi/rmi://localhost:9000/jmxrmi * in a name space {@code "foo"} inside the {@linkplain * java.lang.management.ManagementFactory#getPlatformMBeanServer platform * MBeanServer} you would write the following piece of code: *

*
 *      final JMXServiceURL sourceURL =
 *         new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9000/jmxrmi");
 *      final MBeanServer platform = ManagementFactory.getPlatformMBeanServer();
 *      final Map<String,Object> options = Collections.emptyMap();
 *      final JMXRemoteNamespace mbean = {@link
 *            javax.management.namespace.JMXRemoteNamespace JMXRemoteNamespace}.
 *         {@link javax.management.namespace.JMXRemoteNamespace#newJMXRemoteNamespace newJMXRemoteNamespace(sourceURL, options)};
 *      final ObjectName name = {@link javax.management.namespace.JMXNamespaces JMXNamespaces}.{@link javax.management.namespace.JMXNamespaces#getNamespaceObjectName(String) getNamespaceObjectName("foo")};
 *      final ObjectInstance ref = platform.registerMBean(mbean,name);
 *      platform.invoke(ref.getObjectName(),"connect",null,null);
 *  
* *

What Does a Name Space Look Like?

* *

* We have seen that {@link javax.management.namespace.JMXNamespaceView} class * provides an easy way to navigate within namespaces. It is however also * possible to interact with namespaces directly from the top level * {@code MBeanServer} in which they have been created. * From the outside, a name space only appears as a special MBean in * the MBean server. There's nothing much you can do with this MBean * directly. *

*

* For instance, let's assume you have registered a {@link * javax.management.namespace.JMXRemoteNamespaceMBean * JMXRemoteNamespaceMBean} to manage the name space {@code "foo"}. *
If you query for * platform.queryNames("*//:*",null), then you will see * one MBean named {@code "foo//:type=JMXNamespace"}. *
This is the {@link javax.management.namespace.JMXNamespace} * MBean which is in charge of handling the namespace {@code "foo"}. *

*

* In fact, name space handler MBeans are instances of * the class {@link javax.management.namespace.JMXNamespace} - or * instances of a subclass of that class. * They have a special {@link javax.management.ObjectName} defined by * {@link javax.management.namespace.JMXNamespaces#getNamespaceObjectName * JMXNamespaces.getNamespaceObjectName}.
* {@link javax.management.namespace.JMXNamespace} instances are able * to return an {@link * javax.management.namespace.JMXNamespace#getSourceServer MBeanServer} * which corresponds to the MBeanServer within (= the name space itself). *

*

* So how does it work? How can you see the MBeans contained in the new * name space? *

*

In order to address scalability issues, MBeans registered in * namespaces (such as our namespace {@code "foo"} above) can not be * seen with {@code mbeanServer.queryNames("*:*",null)}. To see the MBeans * contained in a namespace, you can use one of these methods: *

*
    *
  1. * You can use the {@link javax.management.namespace.JMXNamespaceView} * class shown above, *
  2. *
  3. * or you can directly look for MBeans * whose names match * {@code "foo//*:*"}, *
  4. *
  5. * or you can narrow down to the namespace * and obtain an MBeanServer * proxy that corresponds to an MBeanServer view of that namespace. * The JMXNamespaces class provides a static method that * allows you to narrow down to a name space, by calling * {@link javax.management.namespace.JMXNamespaces#narrowToNamespace(MBeanServer,String) * JMXNamespaces.narrowToNamespace}. *
  6. *
* *

Using Name Space Prefixes

*

* As we have explained above, MBeans contained in name * spaces are not returned by {@code server.queryNames(null,null)} - or * server.queryNames({@link javax.management.ObjectName#WILDCARD ObjectName.WILDCARD},null). *
* However, these MBeans can still be accessed from the top level * {@code MBeanServer} interface, without using any API specific to the * version 2.0 of the JMX API, simply by using object names with * name space prefixes: *
To list MBeans contained in a namespace {@code "foo"} you can * query for MBeans whose names match {@code "foo//*:*"}, as shown * earlier in this document: *

 *         server.queryNames(new ObjectName("foo//*:*", null);
 *         // or equivalently:
 *         server.queryNames(JMXNamespaces.getWildcardFor("foo"), null);
 *      
* This will return a list of MBean names whose domain name starts * with {@code foo//}. *

* Using these names, you can invoke any operation on the corresponding * MBeans. For instance, to get the {@link javax.management.MBeanInfo * MBeanInfo} of an MBean * contained in name space {@code "foo"} (assuming * the name of the MBean within its name space is domain:type=Thing, * then simply call: *

 *         server.getMBeanInfo(new ObjectName("foo//domain:type=Thing"));
 *      
* An easier way to access MBeans contained in a name space is to * cd inside the name space, as shown in the following paragraph. *

* *

Narrowing Down Into a Name Spaces

*

* As we have seen, name spaces are like MBean servers within MBean servers. * Therefore, it is possible to view a name space just as if it were * an other MBean server. This is similar to opening a sub * folder from a parent folder.
* This operation is illustrated in the code extract below: *

 *          final MBeanServer foo =
 *                JMXNamespaces.narrowToNamespace(platform, "foo");
 *          final MBeanInfo info =
 *                foo.getMBeanInfo(new ObjectName("domain:type=Thing"));
 *      
* The {@code MBeanServer} returned by {@link * javax.management.namespace.JMXNamespaces#narrowToNamespace(MBeanServer,String) * JMXNamespaces.narrowToNamespace} is an {@code MBeanServer} view that * narrows down into a given namespace. The MBeans contained inside that * namespace can now be accessed by their regular local name.
* The MBean server obtained by narrowing down * to name space {@code "foo"} behaves just like a regular MBean server. * However, it may sometimes throw an {@link * java.lang.UnsupportedOperationException UnsupportedOperationException} * wrapped in a JMX exception if you try to call an operation which is not * supported by the underlying name space handler. *
For instance, {@link javax.management.MBeanServer#registerMBean * registerMBean} is not supported for name spaces mounted from remote * MBean servers. *

*

* Note: If you have a deep hierarchy of namespaces, and if you * are switching from one namespace to another in the course of your * application, it might be more convenient to use a * {@link javax.management.namespace.JMXNamespaceView} * in order to navigate in your namespaces. *

* *

Different Types of Name Spaces

*

* This API lets you create several types of name spaces: *

*

* *

Name Spaces And Special Operations

*

* MBean Naming considerations aside, Name Spaces are transparent for * most {@code MBeanServer} operations. There are however a few * exceptions: *

* * *

Crossing Several Name Spaces

*

* Just as folders can contain other folders, name spaces can contain * other name spaces. For instance, if an {@code MBeanServer} S1 * containing a name space {@code "bar"} is mounted in another * {@code MBeanServer} S2 with name space {@code "foo"}, then * an MBean M1 named {@code "domain:type=Thing"} in namespace * {@code "bar"} will appear as {@code "foo//bar//domain:type=Thing"} in * {@code MBeanServer} S2. *

*

* When accessing the MBean M1 from server S2, the * method call will traverse in a cascade {@code MBeanServer} S2, * then the name space handler for name space {@code "foo"}, then * {@code MBeanServer} S1, before coming to the name space * handler for name space {@code "bar"}. Any operation invoked * on the MBean from a "top-level" name space will therefore need to * traverse all the name spaces along the name space path until * it eventually reaches the named MBean. This means that an operation * like registerMBean for instance, * can only succeed if all the name spaces along the path support it. *

*

* Narrowing to a nested name space works just the same as narrowing * to a top level name space: *

 *          final MBeanServer S2 = .... ;
 *          final MBeanServer bar =
 *                JMXNamespaces.narrowToNamespace(S2, "foo//bar");
 *          final MBeanInfo info =
 *                foo.getMBeanInfo(new ObjectName("domain:type=Thing"));
 *      
*

* *

Name Spaces And Operation Results

*

* Operation results, as well as attribute values returned by an MBean * contained in a name space must be interpreted in the context of that * name space.
* In other words, if an MBean in name space "foo" has an attribute of * type {@code ObjectName}, then it must be assumed that the * {@code ObjectName} returned by that MBean is relative to * name space "foo".
* The same rule aplies for MBean names that can be returned by * operations invoked on such an MBean. If one of the MBean operations * return, say, a {@code Set} then those MBean names must * also be assumed to be relative to name space "foo".
*

*

* In the usual case, a JMX client will first * narrow to a name space before invoking * any operation on the MBeans it contains. In that case the names * returned by the MBean invoked can be directly fed back to the * narrowed connection. *
* If however, the JMX client directly invoked the MBean from a higher * name space, without having narrowed to that name space first, then * the names that might be returned by that MBean will not be directly * usable - the JMX client will need to either * narrow to the name space before using the * returned names, or convert the names to the higher level name space * context. *
* The {@link javax.management.namespace.JMXNamespaces JMXNamespaces} * class provides methods that can be used to perform that conversion. *

* *

Name Spaces And Notifications

*

* As already explained, name spaces are very * similar to {@code MBeanServer}s. It is thus possible to get * {@link javax.management.MBeanServerNotification MBeanServerNotifications} * when MBeans are added or removed within a name space, by registering * with the {@link javax.management.MBeanServerDelegate * MBeanServerDelegate} MBean of the corresponding name space.
* However, it must be noted that the notifications emitted by a * name space must be interpreted in the context of that name space. * For instance, if an MBean {@code "domain:type=Thing"} contained in * namespace "foo//bar" emits a notification, the source of the * notification will be {@code "domain:type=Thing"}, not * {@code "foo//bar//domain:type=Thing"}.
* It is therefore recommended to keep track of the name space * information when registering a listener with an MBean contained in * a name space, especially if the same listener is used to receive * notifications from different name spaces. An easy solution is to * use the handback, as illustrated in the code below. *

 *            final MBeanServer server = ...;
 *            final NotificationListener listener = new NotificationListener() {
 *                public void handleNotification(Notification n, Object handback) {
 *                    if (!(n instanceof MBeanServerNotification)) {
 *                        System.err.println("Error: expected MBeanServerNotification");
 *                        return;
 *                    }
 *                    final MBeanServerNotification mbsn =
 *                            (MBeanServerNotification) n;
 *
 *                    // We will pass the namespace path in the handback.
 *                    //
 *                    // The received notification must be interpreted in
 *                    // the context of its source - therefore
 *                    // mbsn.getMBeanName() does not include the name space
 *                    // path...
 *                    //
 *                    final String namespace = (String) handback;
 *                    System.out.println("Received " + mbsn.getType() +
 *                            " for MBean " + mbsn.getMBeanName() +
 *                            " from name space " + namespace);
 *                }
 *            };
 *            server.addNotificationListener(JMXNamespaces.insertPath("foo//bar",
 *                    MBeanServerDelegate.DELEGATE_NAME),listener,null,"foo//bar");
 *            server.addNotificationListener(JMXNamespaces.insertPath("foo//joe",
 *                    MBeanServerDelegate.DELEGATE_NAME),listener,null,"foo//joe");
 *          
*

*

* JMX Connectors may require some configuration in order to be able * to forward notifications from MBeans located in name spaces. * The RMI JMX Connector Server * in the Java SE 7 platform is configured by default to internally * use the new {@linkplain javax.management.event event service} on * the server side. * When the connector server is configured in this way, JMX clients * which use the old JMX Notifications mechanism (such as clients * running on prior versions of the JDK) will be able to * to receive notifications from MBeans located in sub name spaces. * This is because the connector server will transparently delegate * their subscriptions to the underlying {@linkplain * javax.management.event event service}. In summary: *

*

*

* These configuration issues apply at each node in the name space path, * whenever the name space points to a remote server. The * {@link javax.management.namespace.JMXRemoteNamespace * JMXRemoteNamespace} can be configured in such a way that it will * explicitly use an {@link javax.management.event.EventClient EventClient} * when forwarding subscription to the remote side. Note that this can be * unnecessary (and a waste of resources) if the underlying JMXConnector * returned by the JMXConnectorFactory (client side) already uses the * {@linkplain javax.management.event event service} to register for * notifications with the server side. *

* *

Name Spaces And Access Control

*

* Access to MBeans exposed through JMX namespaces is controlled by * {@linkplain javax.management.namespace.JMXNamespacePermission * jmx namespace permissions}. These permissions are checked by the * MBeanServer in which the {@link * javax.management.namespace.JMXNamespace JMXNamespace} MBean is registered. * This is described in * details in the {@link * javax.management.namespace.JMXNamespace JMXNamespace} class. *

*

* To implement a "firewall-like" access control in a JMX agent you * can also place an {@link * javax.management.remote.MBeanServerForwarder} in the JMX Connector * Server which exposes the top-level MBeanServer of your application. * This {@code MBeanServerForwarder} will be able to perform * authorization checks for all MBeans, including those located in * sub name spaces. *

*

* For a tighter access control we recommend using a {@link * java.lang.SecurityManager security manager}. *

* @since 1.7 *

**/ package javax.management.namespace;