0N/A/*
2362N/A * Copyright (c) 2001, 2007, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage javax.management;
0N/A
0N/Aimport java.io.IOException;
0N/Aimport java.io.ObjectInputStream;
0N/Aimport java.security.BasicPermission;
0N/Aimport java.security.Permission;
0N/Aimport java.security.PermissionCollection;
0N/Aimport java.util.Collections;
0N/Aimport java.util.Enumeration;
0N/Aimport java.util.Set;
0N/Aimport java.util.StringTokenizer;
0N/A
0N/A/** A Permission to perform actions related to MBeanServers.
0N/A The <em>name</em> of the permission specifies the operation requested
0N/A or granted by the permission. For a granted permission, it can be
0N/A <code>*</code> to allow all of the MBeanServer operations specified below.
0N/A Otherwise, for a granted or requested permission, it must be one of the
0N/A following:
0N/A <dl>
0N/A <dt>createMBeanServer</dt>
0N/A <dd>Create a new MBeanServer object using the method
0N/A {@link MBeanServerFactory#createMBeanServer()} or
0N/A {@link MBeanServerFactory#createMBeanServer(java.lang.String)}.
0N/A <dt>findMBeanServer</dt>
0N/A <dd>Find an MBeanServer with a given name, or all MBeanServers in this
0N/A JVM, using the method {@link MBeanServerFactory#findMBeanServer}.
0N/A <dt>newMBeanServer</dt>
0N/A <dd>Create a new MBeanServer object without keeping a reference to it,
0N/A using the method {@link MBeanServerFactory#newMBeanServer()} or
0N/A {@link MBeanServerFactory#newMBeanServer(java.lang.String)}.
0N/A <dt>releaseMBeanServer</dt>
0N/A <dd>Remove the MBeanServerFactory's reference to an MBeanServer,
0N/A using the method {@link MBeanServerFactory#releaseMBeanServer}.
0N/A </dl>
0N/A The <em>name</em> of the permission can also denote a list of one or more
0N/A comma-separated operations. Spaces are allowed at the beginning and
0N/A end of the <em>name</em> and before and after commas.
0N/A <p>
0N/A <code>MBeanServerPermission("createMBeanServer")</code> implies
0N/A <code>MBeanServerPermission("newMBeanServer")</code>.
0N/A *
0N/A * @since 1.5
0N/A */
0N/Apublic class MBeanServerPermission extends BasicPermission {
0N/A private static final long serialVersionUID = -5661980843569388590L;
0N/A
0N/A private final static int
0N/A CREATE = 0,
0N/A FIND = 1,
0N/A NEW = 2,
0N/A RELEASE = 3,
0N/A N_NAMES = 4;
0N/A
0N/A private final static String[] names = {
0N/A "createMBeanServer",
0N/A "findMBeanServer",
0N/A "newMBeanServer",
0N/A "releaseMBeanServer",
0N/A };
0N/A
0N/A private final static int
0N/A CREATE_MASK = 1<<CREATE,
0N/A FIND_MASK = 1<<FIND,
0N/A NEW_MASK = 1<<NEW,
0N/A RELEASE_MASK = 1<<RELEASE,
0N/A ALL_MASK = CREATE_MASK|FIND_MASK|NEW_MASK|RELEASE_MASK;
0N/A
0N/A /*
0N/A * Map from permission masks to canonical names. This array is
0N/A * filled in on demand.
0N/A *
0N/A * This isn't very scalable. If we have more than five or six
0N/A * permissions, we should consider doing this differently,
0N/A * e.g. with a Map.
0N/A */
0N/A private final static String[] canonicalNames = new String[1 << N_NAMES];
0N/A
0N/A /*
0N/A * The target names mask. This is not private to avoid having to
0N/A * generate accessor methods for accesses from the collection class.
0N/A *
0N/A * This mask includes implied bits. So if it has CREATE_MASK then
0N/A * it necessarily has NEW_MASK too.
0N/A */
0N/A transient int mask;
0N/A
0N/A /** <p>Create a new MBeanServerPermission with the given name.</p>
0N/A <p>This constructor is equivalent to
0N/A <code>MBeanServerPermission(name,null)</code>.</p>
0N/A @param name the name of the granted permission. It must
0N/A respect the constraints spelt out in the description of the
0N/A {@link MBeanServerPermission} class.
0N/A @exception NullPointerException if the name is null.
0N/A @exception IllegalArgumentException if the name is not
0N/A <code>*</code> or one of the allowed names or a comma-separated
0N/A list of the allowed names.
0N/A */
0N/A public MBeanServerPermission(String name) {
0N/A this(name, null);
0N/A }
0N/A
0N/A /** <p>Create a new MBeanServerPermission with the given name.</p>
0N/A @param name the name of the granted permission. It must
0N/A respect the constraints spelt out in the description of the
0N/A {@link MBeanServerPermission} class.
0N/A @param actions the associated actions. This parameter is not
0N/A currently used and must be null or the empty string.
0N/A @exception NullPointerException if the name is null.
0N/A @exception IllegalArgumentException if the name is not
0N/A <code>*</code> or one of the allowed names or a comma-separated
0N/A list of the allowed names, or if <code>actions</code> is a non-null
0N/A non-empty string.
0N/A *
0N/A * @throws NullPointerException if <code>name</code> is <code>null</code>.
0N/A * @throws IllegalArgumentException if <code>name</code> is empty or
0N/A * if arguments are invalid.
0N/A */
0N/A public MBeanServerPermission(String name, String actions) {
0N/A super(getCanonicalName(parseMask(name)), actions);
0N/A
0N/A /* It's annoying to have to parse the name twice, but since
0N/A Permission.getName() is final and since we can't access "this"
0N/A until after the call to the superclass constructor, there
0N/A isn't any very clean way to do this. MBeanServerPermission
0N/A objects aren't constructed very often, luckily. */
0N/A mask = parseMask(name);
0N/A
0N/A /* Check that actions is a null empty string */
0N/A if (actions != null && actions.length() > 0)
0N/A throw new IllegalArgumentException("MBeanServerPermission " +
0N/A "actions must be null: " +
0N/A actions);
0N/A }
0N/A
0N/A MBeanServerPermission(int mask) {
0N/A super(getCanonicalName(mask));
0N/A this.mask = impliedMask(mask);
0N/A }
0N/A
0N/A private void readObject(ObjectInputStream in)
0N/A throws IOException, ClassNotFoundException {
0N/A in.defaultReadObject();
0N/A mask = parseMask(getName());
0N/A }
0N/A
0N/A static int simplifyMask(int mask) {
0N/A if ((mask & CREATE_MASK) != 0)
0N/A mask &= ~NEW_MASK;
0N/A return mask;
0N/A }
0N/A
0N/A static int impliedMask(int mask) {
0N/A if ((mask & CREATE_MASK) != 0)
0N/A mask |= NEW_MASK;
0N/A return mask;
0N/A }
0N/A
0N/A static String getCanonicalName(int mask) {
0N/A if (mask == ALL_MASK)
0N/A return "*";
0N/A
0N/A mask = simplifyMask(mask);
0N/A
0N/A synchronized (canonicalNames) {
0N/A if (canonicalNames[mask] == null)
0N/A canonicalNames[mask] = makeCanonicalName(mask);
0N/A }
0N/A
0N/A return canonicalNames[mask];
0N/A }
0N/A
0N/A private static String makeCanonicalName(int mask) {
0N/A final StringBuilder buf = new StringBuilder();
0N/A for (int i = 0; i < N_NAMES; i++) {
0N/A if ((mask & (1<<i)) != 0) {
0N/A if (buf.length() > 0)
0N/A buf.append(',');
0N/A buf.append(names[i]);
0N/A }
0N/A }
0N/A return buf.toString().intern();
0N/A /* intern() avoids duplication when the mask has only
0N/A one bit, so is equivalent to the string constants
0N/A we have for the names[] array. */
0N/A }
0N/A
0N/A /* Convert the string into a bitmask, including bits that
0N/A are implied by the permissions in the string. */
0N/A private static int parseMask(String name) {
0N/A /* Check that target name is a non-null non-empty string */
0N/A if (name == null) {
0N/A throw new NullPointerException("MBeanServerPermission: " +
0N/A "target name can't be null");
0N/A }
0N/A
0N/A name = name.trim();
0N/A if (name.equals("*"))
0N/A return ALL_MASK;
0N/A
0N/A /* If the name is empty, nameIndex will barf. */
0N/A if (name.indexOf(',') < 0)
0N/A return impliedMask(1 << nameIndex(name.trim()));
0N/A
0N/A int mask = 0;
0N/A
0N/A StringTokenizer tok = new StringTokenizer(name, ",");
0N/A while (tok.hasMoreTokens()) {
0N/A String action = tok.nextToken();
0N/A int i = nameIndex(action.trim());
0N/A mask |= (1 << i);
0N/A }
0N/A
0N/A return impliedMask(mask);
0N/A }
0N/A
0N/A private static int nameIndex(String name)
0N/A throws IllegalArgumentException {
0N/A for (int i = 0; i < N_NAMES; i++) {
0N/A if (names[i].equals(name))
0N/A return i;
0N/A }
0N/A final String msg =
0N/A "Invalid MBeanServerPermission name: \"" + name + "\"";
0N/A throw new IllegalArgumentException(msg);
0N/A }
0N/A
0N/A public int hashCode() {
0N/A return mask;
0N/A }
0N/A
0N/A /**
0N/A * <p>Checks if this MBeanServerPermission object "implies" the specified
0N/A * permission.</p>
0N/A *
0N/A * <p>More specifically, this method returns true if:</p>
0N/A *
0N/A * <ul>
0N/A * <li> <i>p</i> is an instance of MBeanServerPermission,</li>
0N/A * <li> <i>p</i>'s target names are a subset of this object's target
0N/A * names</li>
0N/A * </ul>
0N/A *
0N/A * <p>The <code>createMBeanServer</code> permission implies the
0N/A * <code>newMBeanServer</code> permission.</p>
0N/A *
0N/A * @param p the permission to check against.
0N/A * @return true if the specified permission is implied by this object,
0N/A * false if not.
0N/A */
0N/A public boolean implies(Permission p) {
0N/A if (!(p instanceof MBeanServerPermission))
0N/A return false;
0N/A
0N/A MBeanServerPermission that = (MBeanServerPermission) p;
0N/A
0N/A return ((this.mask & that.mask) == that.mask);
0N/A }
0N/A
0N/A /**
0N/A * Checks two MBeanServerPermission objects for equality. Checks that
0N/A * <i>obj</i> is an MBeanServerPermission, and represents the same
0N/A * list of allowable actions as this object.
0N/A * <P>
0N/A * @param obj the object we are testing for equality with this object.
0N/A * @return true if the objects are equal.
0N/A */
0N/A public boolean equals(Object obj) {
0N/A if (obj == this)
0N/A return true;
0N/A
0N/A if (! (obj instanceof MBeanServerPermission))
0N/A return false;
0N/A
0N/A MBeanServerPermission that = (MBeanServerPermission) obj;
0N/A
0N/A return (this.mask == that.mask);
0N/A }
0N/A
0N/A public PermissionCollection newPermissionCollection() {
0N/A return new MBeanServerPermissionCollection();
0N/A }
0N/A}
0N/A
0N/A/**
0N/A * Class returned by {@link MBeanServerPermission#newPermissionCollection()}.
0N/A *
0N/A * @serial include
0N/A */
0N/A
0N/A/*
0N/A * Since every collection of MBSP can be represented by a single MBSP,
0N/A * that is what our PermissionCollection does. We need to define a
0N/A * PermissionCollection because the one inherited from BasicPermission
0N/A * doesn't know that createMBeanServer implies newMBeanServer.
0N/A *
0N/A * Though the serial form is defined, the TCK does not check it. We do
0N/A * not require independent implementations to duplicate it. Even though
0N/A * PermissionCollection is Serializable, instances of this class will
0N/A * hardly ever be serialized, and different implementations do not
0N/A * typically exchange serialized permission collections.
0N/A *
0N/A * If we did require that a particular form be respected here, we would
0N/A * logically also have to require it for
0N/A * MBeanPermission.newPermissionCollection, which would preclude an
0N/A * implementation from defining a PermissionCollection there with an
0N/A * optimized "implies" method.
0N/A */
0N/Aclass MBeanServerPermissionCollection extends PermissionCollection {
0N/A /** @serial Null if no permissions in collection, otherwise a
0N/A single permission that is the union of all permissions that
0N/A have been added. */
0N/A private MBeanServerPermission collectionPermission;
0N/A
0N/A private static final long serialVersionUID = -5661980843569388590L;
0N/A
0N/A public synchronized void add(Permission permission) {
0N/A if (!(permission instanceof MBeanServerPermission)) {
0N/A final String msg =
0N/A "Permission not an MBeanServerPermission: " + permission;
0N/A throw new IllegalArgumentException(msg);
0N/A }
0N/A if (isReadOnly())
0N/A throw new SecurityException("Read-only permission collection");
0N/A MBeanServerPermission mbsp = (MBeanServerPermission) permission;
0N/A if (collectionPermission == null)
0N/A collectionPermission = mbsp;
0N/A else if (!collectionPermission.implies(permission)) {
0N/A int newmask = collectionPermission.mask | mbsp.mask;
0N/A collectionPermission = new MBeanServerPermission(newmask);
0N/A }
0N/A }
0N/A
0N/A public synchronized boolean implies(Permission permission) {
0N/A return (collectionPermission != null &&
0N/A collectionPermission.implies(permission));
0N/A }
0N/A
0N/A public synchronized Enumeration<Permission> elements() {
0N/A Set<Permission> set;
0N/A if (collectionPermission == null)
0N/A set = Collections.emptySet();
0N/A else
0N/A set = Collections.singleton((Permission) collectionPermission);
0N/A return Collections.enumeration(set);
0N/A }
0N/A}