- /*
- * @(#)MBeanServerPermission.java 1.26 03/12/19
- *
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package javax.management;
-
- import java.io.IOException;
- import java.io.ObjectInputStream;
- import java.security.BasicPermission;
- import java.security.Permission;
- import java.security.PermissionCollection;
- import java.util.Collections;
- import java.util.Enumeration;
- import java.util.Set;
- import java.util.StringTokenizer;
-
- /** A Permission to perform actions related to MBeanServers.
- The <em>name</em> of the permission specifies the operation requested
- or granted by the permission. For a granted permission, it can be
- <code>*</code> to allow all of the MBeanServer operations specified below.
- Otherwise, for a granted or requested permission, it must be one of the
- following:
- <dl>
- <dt>createMBeanServer</dt>
- <dd>Create a new MBeanServer object using the method
- {@link MBeanServerFactory#createMBeanServer()} or
- {@link MBeanServerFactory#createMBeanServer(java.lang.String)}.
- <dt>findMBeanServer</dt>
- <dd>Find an MBeanServer with a given name, or all MBeanServers in this
- JVM, using the method {@link MBeanServerFactory#findMBeanServer}.
- <dt>newMBeanServer</dt>
- <dd>Create a new MBeanServer object without keeping a reference to it,
- using the method {@link MBeanServerFactory#newMBeanServer()} or
- {@link MBeanServerFactory#newMBeanServer(java.lang.String)}.
- <dt>releaseMBeanServer</dt>
- <dd>Remove the MBeanServerFactory's reference to an MBeanServer,
- using the method {@link MBeanServerFactory#releaseMBeanServer}.
- </dl>
- The <em>name</em> of the permission can also denote a list of one or more
- comma-separated operations. Spaces are allowed at the beginning and
- end of the <em>name</em> and before and after commas.
- <p>
- <code>MBeanServerPermission("createMBeanServer")</code> implies
- <code>MBeanServerPermission("newMBeanServer")</code>.
- *
- * @since 1.5
- * @since.unbundled JMX 1.1
- */
- public class MBeanServerPermission extends BasicPermission {
- private static final long serialVersionUID = -5661980843569388590L;
-
- private final static int
- CREATE = 0,
- FIND = 1,
- NEW = 2,
- RELEASE = 3,
- N_NAMES = 4;
-
- private final static String[] names = {
- "createMBeanServer",
- "findMBeanServer",
- "newMBeanServer",
- "releaseMBeanServer",
- };
-
- private final static int
- CREATE_MASK = 1<<CREATE,
- FIND_MASK = 1<<FIND,
- NEW_MASK = 1<<NEW,
- RELEASE_MASK = 1<<RELEASE,
- ALL_MASK = CREATE_MASK|FIND_MASK|NEW_MASK|RELEASE_MASK;
-
- /*
- * Map from permission masks to canonical names. This array is
- * filled in on demand.
- *
- * This isn't very scalable. If we have more than five or six
- * permissions, we should consider doing this differently,
- * e.g. with a Map.
- */
- private final static String[] canonicalNames = new String[1 << N_NAMES];
-
- /*
- * The target names mask. This is not private to avoid having to
- * generate accessor methods for accesses from the collection class.
- *
- * This mask includes implied bits. So if it has CREATE_MASK then
- * it necessarily has NEW_MASK too.
- */
- transient int mask;
-
- /** <p>Create a new MBeanServerPermission with the given name.</p>
- <p>This constructor is equivalent to
- <code>MBeanServerPermission(name,null)</code>.</p>
- @param name the name of the granted permission. It must
- respect the constraints spelt out in the description of the
- {@link MBeanServerPermission} class.
- @exception NullPointerException if the name is null.
- @exception IllegalArgumentException if the name is not
- <code>*</code> or one of the allowed names or a comma-separated
- list of the allowed names.
- */
- public MBeanServerPermission(String name) {
- this(name, null);
- }
-
- /** <p>Create a new MBeanServerPermission with the given name.</p>
- @param name the name of the granted permission. It must
- respect the constraints spelt out in the description of the
- {@link MBeanServerPermission} class.
- @param actions the associated actions. This parameter is not
- currently used and must be null or the empty string.
- @exception NullPointerException if the name is null.
- @exception IllegalArgumentException if the name is not
- <code>*</code> or one of the allowed names or a comma-separated
- list of the allowed names, or if <code>actions</code> is a non-null
- non-empty string. */
- public MBeanServerPermission(String name, String actions) {
- super(getCanonicalName(parseMask(name)), actions);
-
- /* It's annoying to have to parse the name twice, but since
- Permission.getName() is final and since we can't access "this"
- until after the call to the superclass constructor, there
- isn't any very clean way to do this. MBeanServerPermission
- objects aren't constructed very often, luckily. */
- mask = parseMask(name);
-
- /* Check that actions is a null empty string */
- if (actions != null && actions.length() > 0)
- throw new IllegalArgumentException("MBeanServerPermission " +
- "actions must be null: " +
- actions);
- }
-
- MBeanServerPermission(int mask) {
- super(getCanonicalName(mask));
- this.mask = impliedMask(mask);
- }
-
- private void readObject(ObjectInputStream in)
- throws IOException, ClassNotFoundException {
- in.defaultReadObject();
- mask = parseMask(getName());
- }
-
- static int simplifyMask(int mask) {
- if ((mask & CREATE_MASK) != 0)
- mask &= ~NEW_MASK;
- return mask;
- }
-
- static int impliedMask(int mask) {
- if ((mask & CREATE_MASK) != 0)
- mask |= NEW_MASK;
- return mask;
- }
-
- static String getCanonicalName(int mask) {
- if (mask == ALL_MASK)
- return "*";
-
- mask = simplifyMask(mask);
-
- synchronized (canonicalNames) {
- if (canonicalNames[mask] == null)
- canonicalNames[mask] = makeCanonicalName(mask);
- }
-
- return canonicalNames[mask];
- }
-
- private static String makeCanonicalName(int mask) {
- StringBuffer buf = new StringBuffer();
- for (int i = 0; i < N_NAMES; i++) {
- if ((mask & (1<<i)) != 0) {
- if (buf.length() > 0)
- buf.append(',');
- buf.append(names[i]);
- }
- }
- return buf.toString().intern();
- /* intern() avoids duplication when the mask has only
- one bit, so is equivalent to the string constants
- we have for the names[] array. */
- }
-
- /* Convert the string into a bitmask, including bits that
- are implied by the permissions in the string. */
- private static int parseMask(String name) {
- /* Check that target name is a non-null non-empty string */
- if (name == null) {
- throw new NullPointerException("MBeanServerPermission: " +
- "target name can't be null");
- }
-
- name = name.trim();
- if (name.equals("*"))
- return ALL_MASK;
-
- /* If the name is empty, nameIndex will barf. */
- if (name.indexOf(',') < 0)
- return impliedMask(1 << nameIndex(name.trim()));
-
- int mask = 0;
-
- StringTokenizer tok = new StringTokenizer(name, ",");
- while (tok.hasMoreTokens()) {
- String action = tok.nextToken();
- int i = nameIndex(action.trim());
- mask |= (1 << i);
- }
-
- return impliedMask(mask);
- }
-
- private static int nameIndex(String name)
- throws IllegalArgumentException {
- for (int i = 0; i < N_NAMES; i++) {
- if (names[i].equals(name))
- return i;
- }
- final String msg =
- "Invalid MBeanServerPermission name: \"" + name + "\"";
- throw new IllegalArgumentException(msg);
- }
-
- public int hashCode() {
- return mask;
- }
-
- /**
- * <p>Checks if this MBeanServerPermission object "implies" the specified
- * permission.</p>
- *
- * <p>More specifically, this method returns true if:</p>
- *
- * <ul>
- * <li> <i>p</i> is an instance of MBeanServerPermission,</li>
- * <li> <i>p</i>'s target names are a subset of this object's target
- * names</li>
- * </ul>
- *
- * <p>The <code>createMBeanServer</code> permission implies the
- * <code>newMBeanServer</code> permission.</p>
- *
- * @param p the permission to check against.
- * @return true if the specified permission is implied by this object,
- * false if not.
- */
- public boolean implies(Permission p) {
- if (!(p instanceof MBeanServerPermission))
- return false;
-
- MBeanServerPermission that = (MBeanServerPermission) p;
-
- return ((this.mask & that.mask) == that.mask);
- }
-
- /**
- * Checks two MBeanServerPermission objects for equality. Checks that
- * <i>obj</i> is an MBeanServerPermission, and represents the same
- * list of allowable actions as this object.
- * <P>
- * @param obj the object we are testing for equality with this object.
- * @return true if the objects are equal.
- */
- public boolean equals(Object obj) {
- if (obj == this)
- return true;
-
- if (! (obj instanceof MBeanServerPermission))
- return false;
-
- MBeanServerPermission that = (MBeanServerPermission) obj;
-
- return (this.mask == that.mask);
- }
-
- public PermissionCollection newPermissionCollection() {
- return new MBeanServerPermissionCollection();
- }
- }
-
- /**
- * Class returned by {@link MBeanServerPermission#newPermissionCollection()}.
- *
- * @serial include
- */
-
- /*
- * Since every collection of MBSP can be represented by a single MBSP,
- * that is what our PermissionCollection does. We need to define a
- * PermissionCollection because the one inherited from BasicPermission
- * doesn't know that createMBeanServer implies newMBeanServer.
- *
- * Though the serial form is defined, the TCK does not check it. We do
- * not require independent implementations to duplicate it. Even though
- * PermissionCollection is Serializable, instances of this class will
- * hardly ever be serialized, and different implementations do not
- * typically exchange serialized permission collections.
- *
- * If we did require that a particular form be respected here, we would
- * logically also have to require it for
- * MBeanPermission.newPermissionCollection, which would preclude an
- * implementation from defining a PermissionCollection there with an
- * optimized "implies" method.
- */
- class MBeanServerPermissionCollection extends PermissionCollection {
- /** @serial Null if no permissions in collection, otherwise a
- single permission that is the union of all permissions that
- have been added. */
- private MBeanServerPermission collectionPermission;
-
- private static final long serialVersionUID = -5661980843569388590L;
-
- public synchronized void add(Permission permission) {
- if (!(permission instanceof MBeanServerPermission)) {
- final String msg =
- "Permission not an MBeanServerPermission: " + permission;
- throw new IllegalArgumentException(msg);
- }
- if (isReadOnly())
- throw new SecurityException("Read-only permission collection");
- MBeanServerPermission mbsp = (MBeanServerPermission) permission;
- if (collectionPermission == null)
- collectionPermission = mbsp;
- else if (!collectionPermission.implies(permission)) {
- int newmask = collectionPermission.mask | mbsp.mask;
- collectionPermission = new MBeanServerPermission(newmask);
- }
- }
-
- public synchronized boolean implies(Permission permission) {
- return (collectionPermission != null &&
- collectionPermission.implies(permission));
- }
-
- public synchronized Enumeration elements() {
- Set set;
- if (collectionPermission == null)
- set = Collections.EMPTY_SET;
- else
- set = Collections.singleton(collectionPermission);
- return Collections.enumeration(set);
- }
- }