/* * 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 java.util.UUID; import javax.management.MBeanRegistration; import javax.management.MBeanServer; import javax.management.ObjectName; /** * MBean Servers can be federated into a single hierarchical name space: * A JMXNamespace is an MBean that handles a sub name space in that * hierarchical name space. *
* A name space is created simply by registering a {@code JMXNamespace} * MBean in the MBean Server. The name of the created name space is defined * by the {@linkplain JMXNamespaces#getNamespaceObjectName name of the JMXNamespace} * that handles it. A name space is equivalent to * an MBean Server within an MBean Server. When creating a {@code JMXNamespace}, * the MBean Server within is passed to the constructor. *
** The {@code JMXNamespace} class is the base class for implementing * all name space handlers. All name space handlers must be instances of * {@code JMXNamespace} or a subclass of it. *
** A concrete example of a {@code JMXNamespace} MBean subclass * is the {@link JMXRemoteNamespace JMXRemoteNamespace} MBean which * is able to mirror all MBeans contained in a remote MBean server known by its * {@link javax.management.remote.JMXServiceURL}. *
** You can create a local namespace by supplying a newly created MBean Server * to an instance of {@code JMXNamespace}. For instance: *
* final String namespace = "foo"; * final ObjectName namespaceName = {@link JMXNamespaces#getNamespaceObjectName * JMXNamespaces.getNamespaceObjectName(namespace)}; * server.registerMBean(new JMXNamespace(MBeanServerFactory.newMBeanServer()), * namespaceName); ** *
* Note: A JMXNamespace MBean cannot be registered * simultaneously in two different * MBean servers, or indeed in the same MBean Server with two * different names. It is however possible to give the same MBeanServer * instance to two different JMXNamespace MBeans, and thus create a graph * rather than a tree. *
* *To view the content of a namespace, you will usually use an * instance of {@link JMXNamespaceView}. For instance, given the * namespace {@code "foo"} created above, you would do: *
** final JMXNamespaceView view = new JMXNamespaceView(server); * System.out.println("List of namespaces: "+Arrays.toString({@link JMXNamespaceView#list() view.list()})); * * final JMXNamespaceView foo = {@link JMXNamespaceView#down view.down("foo")}; * System.out.println({@link JMXNamespaceView#where() foo.where()}+" contains: " + * {@link JMXNamespaceView#getMBeanServerConnection foo.getMBeanServerConnection()}.queryNames(null,null)); ** *
A special {@link JMXNamespacePermission} is defined to check access * to MBean within namespaces.
*When a JMXNamespace MBean is registered in an
* MBean server created through the default {@link
* javax.management.MBeanServerBuilder}, and if a {@link
* SecurityManager SecurityManager} is
* {@linkplain System#getSecurityManager() present}, the MBeanServer will
* check a {@link JMXNamespacePermission} before invoking
* any method on the {@linkplain #getSourceServer source MBeanServer} of the
* JMXNamespace.
* {@linkplain JMXNamespacePermission JMX Namespace Permissions} are similar to
* {@linkplain javax.management.MBeanPermission MBean Permissions}, except
* that you usually cannot specify an MBean class name. You can however
* specify object name patterns - which will allow you for example to only grant
* permissions for MBeans having a specific {@code type=
* Another difference is that {@link JMXNamespacePermission
* JMXNamespacePermission} also specifies from which namespace and which
* MBean server the permission is granted.
* In the rest of this document, the following terms are used: {@code server name} is the
* name of the
* MBeanServer in which the permission is granted.
* The name of an {@code MBeanServer} can be obtained by calling {@link
* javax.management.MBeanServerFactory#getMBeanServerName
* MBeanServerFactory.getMBeanServerName(mbeanServer)}
* {@code namespace} is the name of the namespace
* in the named MBean server for which the
* permission is granted. It doesn't contain any
* {@link JMXNamespaces#NAMESPACE_SEPARATOR namespace separator}.
* {@code mbean} is the name
* of the MBean in that {@code namespace}. This is the name of the MBean
* in the namespace's {@link JMXNamespace#getSourceServer() source mbean server}.
* It might contain no, one, or several {@link
* JMXNamespaces#NAMESPACE_SEPARATOR namespace separators}.
* For instance let's assume that some piece of code calls:
* Assuming that there is a security manager, or that the
* implementation chooses to make checks anyway, the checks that will
* be made in that case are:
* For any of these MBean servers, if no name was supplied when
* creating that MBeanServer the {@link JMXNamespacePermission} is
* created with an {@code mbeanServerName} equal to
* {@value javax.management.MBeanServerFactory#DEFAULT_MBEANSERVER_NAME}.
* If the namespace {@code a} is in fact a remote {@code MBeanServer},
* for instance because namespace {@code a} is implemented by a {@link
* JMXRemoteNamespace} pointing to a distant MBeanServer located in
* another JMX agent, then checks 2,
* 3, and 4 will not
* be performed in the local JVM. They might or might not be performed in
* the remote agent, depending on how access control and permission
* checking are configured in the remote agent, and how authentication
* is configured in the connector used by the {@link
* JMXRemoteNamespace}.
* In all cases, {@linkplain JMXNamespacePermission JMX Namespace Permissions}
* are checked as follows: First, if there is no security manager ({@link
* System#getSecurityManager()} is null), then an implementation of
* of MBeanServer that supports JMX namespaces is free not to make any
* checks. Assuming that there is a security manager, or that the
* implementation chooses to make checks anyway, the checks are made
* as detailed below. If a security check fails, the method throws {@link
* SecurityException}. For the {@link MBeanServer#invoke invoke} method, the caller's
* permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, <operation name>, <namespace>//<mbean>, "invoke")},
* where mbean server name is the name of the
* {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
* namespace is registered, and
* mbean is the name of the MBean on which the action
* is performed, in that namespace.
* For the {@link MBeanServer#getAttribute getAttribute} method, the
* caller's permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, <attribute>, <namespace>//<mbean>, "getAttribute")}.
* For the {@link MBeanServer#getAttributes getAttributes} method, the
* caller's permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, <null>, <namespace>//<mbean>, "getAttribute")},
* where mbean server name is the name of the
* {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
* namespace is registered, and
* mbean is the name of the MBean on which the action
* is performed, in that namespace.
* Additionally, for each attribute att in the {@link
* javax.management.AttributeList}, if the caller's permissions do not
* imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, att,
* <namespace>//<mbean>, "getAttribute")}, the
* MBean server will behave as if that attribute had not been in the
* supplied list. For the {@link MBeanServer#setAttribute setAttribute} method, the
* caller's permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, <attrName>, <namespace>//<mbean>, "setAttribute")},
* where mbean server name is the name of the
* {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
* namespace is registered, and
* mbean is the name of the MBean on which the action
* is performed, in that namespace, and
* For the {@link MBeanServer#setAttributes setAttributes} method, the
* caller's permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>, "setAttribute")},
* where mbean server name is the name of the
* {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
* namespace is registered, and
* mbean is the name of the MBean on which the action
* is performed, in that namespace.
* Additionally, for each attribute att in the {@link
* javax.management.AttributeList}, if the caller's permissions do not
* imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, att, <namespace>//<mbean>, "setAttribute")},
* the MBean server will behave as if that attribute had not been in the
* supplied list. For the For the For the {@link MBeanServer#getMBeanInfo getMBeanInfo} method, the
* caller's permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
* "getMBeanInfo")},
* where mbean server name is the name of the
* {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
* namespace is registered, and
* mbean is the name of the MBean on which the action
* is performed, in that namespace.
* For the {@link MBeanServer#getObjectInstance getObjectInstance} method,
* the caller's permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
* "getObjectInstance")},
* where mbean server name/a> is the name of the
* {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
* namespace is registered, and
* mbean is the name of the MBean on which the action
* is performed, in that namespace.
* For the {@link MBeanServer#isInstanceOf isInstanceOf} method, the
* caller's permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
* "isInstanceOf")},
* where mbean server name is the name of the
* {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
* namespace is registered, and
* mbean is the name of the MBean on which the action
* is performed, in that namespace.
* For the {@link MBeanServer#queryMBeans queryMBeans} method, the
* caller's permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, null, null,
* "queryMBeans")}.
* Additionally, for each MBean {@code mbean} that matches {@code pattern},
* if the caller's permissions do not imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
* "queryMBeans")}, the
* MBean server will behave as if that MBean did not exist. Certain query elements perform operations on the MBean server.
* However these operations are usually performed by the MBeanServer at the
* bottom of the namespace path, and therefore, do not involve any
* {@link JMXNamespacePermission} permission check. They might involve
* {@link javax.management.MBeanPermission} checks depending on how security
* in the JVM in which the bottom MBeanServer resides is implemented.
* See {@link javax.management.MBeanServer} for more details.
* For the {@link MBeanServer#queryNames queryNames} method, the checks
* are the same as for For the {@link MBeanServer#getClassLoader getClassLoader} method, the
* caller's permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, null, <namespace>//<loaderName>,
* "getClassLoader")},
* where mbean server name/a> is the name of the
* {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
* namespace is registered, and
* loaderName is the name of the ClassLoader MBean
* which is accessed, in that namespace.
* For the {@link MBeanServer#getClassLoaderFor getClassLoaderFor} method,
* the caller's permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
* "getClassLoaderFor")},
* where mbean server name is the name of the
* {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
* namespace is registered, and
* mbean is the name of the MBean on which the action
* is performed, in that namespace.
* For the {@link MBeanServer#registerMBean registerMBean} method, the
* caller's permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, <class name>, <namespace>//<mbean>,
* "registerMBean")}. Here
* For the For the {@link MBeanServer#unregisterMBean unregisterMBean} method,
* the caller's permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
* "unregisterMBean")},
* where mbean server name is the name of the
* {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
* namespace is registered, and
* mbean is the name of the MBean on which is
* being unregistered, relative to that namespace.
*
*
*
*
* final MBeanServer mbeanServer = ...;
* final ObjectName name = new ObjectName("a//b//c//D:k=v");
* mbeanServer.getAttribute(name,"Foo");
*
*
*
* JMXNamespacePermission(mbeanServerName, "Foo", "a//b//c//D:k=v",
* "getAttribute")
* (where {@code mbeanServerName=MBeanServerFactory.getMBeanServerName(mbeanServer)},
* namespace="a"
, and {@code mbean="b//c//D:k=v"})
* JMXNamespacePermission(aSourceServerName,"Foo","b//c//D:k=v",
* "getAttribute")}
* (where
* {@code aSourceServerName=MBeanServerFactory.getMBeanServerName(sourceServer(a))},
* namespace="b"
, and {@code mbean="c//D:k=v"}),
* JMXNamespacePermission(bSourceServerName,"Foo","c//D:k=v",
* "getAttribute")}
* (where
* {@code bSourceServerName=MBeanServerFactory.getMBeanServerName(sourceServer(b))},
* namespace="c"
, and {@code mbean="D:k=v"}),
*
*
*
* attrName
is {@link javax.management.Attribute#getName()
* attribute.getName()}.addNotificationListener
methods,
* the caller's permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
* "addNotificationListener")},
* where mbean server name is the name of the
* {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
* namespace is registered, and
* mbean is the name of the MBean on which the action
* is performed, in that namespace.
* removeNotificationListener
methods,
* the caller's permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
* "removeNotificationListener")},
* where mbean server name is the name of the
* {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
* namespace is registered, and
* mbean is the name of the MBean on which the action
* is performed, in that namespace.
* queryMBeans
except that
* "queryNames"
is used instead of
* "queryMBeans"
in the JMXNamespacePermission
* objects. Note that a "queryMBeans"
permission implies
* the corresponding "queryNames"
permission.class name
is the string returned by {@code
* obj.getClass().getName()} where {@code obj} is the mbean reference,
* is the name of the
* {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
* namespace is registered, and
* mbean is the name of the MBean which is being
* registered, relative to that namespace.
*
* createMBean
methods, the caller's
* permissions must imply {@link
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, <class name>, <namespace>//<mbean>,
* "instantiate")} and
* JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
* JMXNamespacePermission(<mbean server name>, <class name>, <namespace>//<mbean>,
* "registerMBean")}, where
* class name
is the string passed as first argument to the {@code
* createMBean} method,
* mbean server name is the name of the
* {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
* namespace is registered, and
* mbean is the name of the MBean which is being
* created, relative to that namespace.
*
*
It must be noted that if all namespaces are local, and all * local namespaces are implemented by regular MBean servers, that is, there * are no {@linkplain MBeanServerSupport Virtual Namespaces}, then * simple {@linkplain javax.management.MBeanPermission MBean Permission} * checks might be enough to secure an application. * In that case, it is possible to specify the following {@link * JMXNamespacePermission} permission in the policy file, which implies all * other JMX namespace permissions: *
** permission javax.management.namespace.JMXNamespacePermission "*::*[]", "*"; ** * @since 1.7 */ public class JMXNamespace implements JMXNamespaceMBean, MBeanRegistration { /** * The standard value of the {@code type} * property key that must be used to construct valid {@link * JMXNamespaceMBean} ObjectNames.
{@value #TYPE_ASSIGNMENT}
.
**/
public static final String TYPE_ASSIGNMENT = "type="+TYPE;
private volatile MBeanServer mbeanServer; // the mbean server in which
// this MBean is registered.
private volatile ObjectName objectName; // the ObjectName of this MBean.
private final MBeanServer sourceServer; // the MBeanServer within = the
// name space (or the MBean server
// that contains it).
private final String uuid;
/**
* Creates a new JMXNamespace implemented by means of an MBean Server.
* A namespace is equivalent to an MBeanServer within an MBean Server.
* The {@code sourceServer} provided to this constructor is the MBean Server
* within.
* @param sourceServer the MBean server that implemented by this namespace.
* @see #getSourceServer
*/
public JMXNamespace(MBeanServer sourceServer) {
this.sourceServer = sourceServer;
this.uuid = UUID.randomUUID().toString();
}
/**
* This method is part of the {@link MBeanRegistration} interface.
* The {@link JMXNamespace} class uses the {@link MBeanRegistration}
* interface in order to get a handle to the MBean server in which it is
* registered. It also check the validity of its own ObjectName.
* * This method is called by the MBean server. * Application classes should never call this method directly. *
* If this method is overridden, the overriding method should call * {@code super.preRegister(server,name)}. * @see MBeanRegistration#preRegister MBeanRegistration * @see JMXNamespaces#getNamespaceObjectName getNamespaceObjectName * @param name The object name of the MBean. name must be a * syntactically valid JMXNamespace name, as returned by * {@link JMXNamespaces#getNamespaceObjectName(java.lang.String) * getNamespaceObjectName(namespace)}. * @return The name under which the MBean is to be registered. * @throws IllegalArgumentException if the name supplied is not valid. * @throws Exception can be thrown by subclasses. */ public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { if (objectName != null && ! objectName.equals(name)) throw new IllegalStateException( "Already registered under another name: " + objectName); objectName = validateHandlerName(name); mbeanServer = server; return name; } /** * 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. **/ ObjectName validateHandlerName(ObjectName supliedName) { if (supliedName == null) throw new IllegalArgumentException("Must supply a valid name"); final String dirName = JMXNamespaces. normalizeNamespaceName(supliedName.getDomain()); final ObjectName handlerName = JMXNamespaces.getNamespaceObjectName(dirName); if (!supliedName.equals(handlerName)) throw new IllegalArgumentException("invalid name space name: "+ supliedName); return supliedName; } /** * This method is part of the {@link MBeanRegistration} interface. * The {@link JMXNamespace} class uses the {@link MBeanRegistration} * interface in order to get a handle to the MBean server in which it is * registered. *
* This method is called by the MBean server. Application classes should * not call this method directly. Subclasses are free to override this * method with their own specific behavior - but the overriding method * shoud still call {@code super.postRegister(registrationDone)}. * @see MBeanRegistration#postRegister MBeanRegistration */ public void postRegister(Boolean registrationDone) { // nothing to do } /** * This method is part of the {@link MBeanRegistration} interface. * The {@link JMXNamespace} class uses the {@link MBeanRegistration} * interface in order to get a handle to the MBean server in which it is * registered. *
* This method is called by the MBean server. Application classes should * not call this method directly. Subclasses are free to override this * method with their own specific behavior - but the overriding method * shoud still call {@code super.preDeregister()}. * @see MBeanRegistration#preDeregister MBeanRegistration */ public void preDeregister() throws Exception { // nothing to do } /** * This method is part of the {@link MBeanRegistration} interface. * It allows the {@code JMXNamespace} MBean to perform any operations * needed after having been unregistered in the MBean server. *
* This method is called by the MBean server. Application classes should
* not call this method directly. If a subclass overrides this
* method, the overriding method shoud call {@code super.postDeregister()}.
* @see MBeanRegistration#postDeregister MBeanRegistration
*/
public void postDeregister() {
mbeanServer = null;
objectName = null;
}
/**
* Returns the MBeanServer in which this MBean is registered,
* or null. Chiefly of interest for subclasses.
* @return the MBeanServer supplied to {@link #preRegister}.
**/
public final MBeanServer getMBeanServer() {
return mbeanServer;
}
/**
* Returns the MBeanServer that contains or emulates the source
* namespace. When a JMXNamespace MBean is registered in an
* MBean server created through the default {@link
* javax.management.MBeanServerBuilder}, the MBeanServer will
* check {@link JMXNamespacePermission} before invoking
* any method on the source MBeanServer of the JMXNamespace.
* See JMX Namespace Permission Checks
* above.
* @return an MBeanServer view of the source namespace
**/
public MBeanServer getSourceServer() {
return sourceServer;
}
/**
* Returns the ObjectName with which this MBean was registered,
* or null. Chiefly of interest for subclasses.
* @return the ObjectName supplied to {@link #preRegister}.
**/
public final ObjectName getObjectName() {
return objectName;
}
/**
* HandlerName used in traces.
**/
String getHandlerName() {
final ObjectName name = getObjectName();
if (name != null) return name.toString();
return this.toString();
}
/**
* In this class, this method returns {@link #getSourceServer
* getSourceServer()}.{@link javax.management.MBeanServer#getMBeanCount
* getMBeanCount()}.
*
This default behaviour may be redefined in subclasses.
* @throws java.io.IOException can be thrown by subclasses.
*/
public Integer getMBeanCount() throws IOException {
return getSourceServer().getMBeanCount();
}
/**
* In this class, this method returns {@link #getSourceServer
* getSourceServer()}.{@link javax.management.MBeanServer#getDomains
* getDomains()}.
*
This default behaviour may be redefined in subclasses.
* @throws java.io.IOException can be thrown by subclasses.
*/
public String[] getDomains() throws IOException {
return getSourceServer().getDomains();
}
/**
* In this class, this method returns {@link #getSourceServer
* getSourceServer()}.{@link javax.management.MBeanServer#getDefaultDomain
* getDefaultDomain()}.
*
This default behaviour may be redefined in subclasses.
* @throws java.io.IOException can be thrown by subclasses.
*/
public String getDefaultDomain() throws IOException {
return getSourceServer().getDefaultDomain();
}
public final String getUUID() {
return uuid;
}
}