jdk/src/share/classes/javax/management/namespace/JMXNamespacePermission.java
changeset 1156 bbc2d15aaf7a
child 1709 392dd6db361a
equal deleted inserted replaced
1155:a9a142fcf1b5 1156:bbc2d15aaf7a
       
     1 /*
       
     2  * Copyright 2002-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 javax.management.*;
       
    29 import com.sun.jmx.mbeanserver.Util;
       
    30 import java.io.IOException;
       
    31 import java.io.ObjectInputStream;
       
    32 import java.security.Permission;
       
    33 
       
    34 /**
       
    35  * <p>A permission controlling access to MBeans located in namespaces.
       
    36  * If a security manager has been set using {@link
       
    37  * System#setSecurityManager}, most operations on an MBean mounted in a
       
    38  * namespace require that the caller's permissions imply a
       
    39  * JMXNamespacePermission appropriate for the operation.
       
    40  * This is described in detail in the
       
    41  * documentation for the
       
    42  * <a href="JMXNamespace.html#PermissionChecks">JMXNamespace</a>
       
    43  * class.</p>
       
    44  *
       
    45  * <p>As with other {@link Permission} objects,
       
    46  * a JMXNamespacePermission can represent either a permission that
       
    47  * you <em>have</em> or a permission that you <em>need</em>.
       
    48  * When a sensitive operation is being checked for permission,
       
    49  * a JMXNamespacePermission is constructed
       
    50  * representing the permission you need.  The operation is only
       
    51  * allowed if the permissions you have {@linkplain #implies imply} the
       
    52  * permission you need.</p>
       
    53  *
       
    54  * <p>A JMXNamespacePermission contains four items of information:</p>
       
    55  *
       
    56  * <ul>
       
    57  *
       
    58  * <li id="Action"><p>The <em>action</em>.</p>
       
    59  * <p>For a permission you need,
       
    60  * this is one of the actions in the list <a
       
    61  * href="#action-list">below</a>.  For a permission you have, this is
       
    62  * a comma-separated list of those actions, or <code>*</code>,
       
    63  * representing all actions.</p>
       
    64  *
       
    65  * <p>The action is returned by {@link #getActions()}.</p>
       
    66  *
       
    67  * <li id="MBeanServerName"><p>The <em>MBean Server name</em>.</p>
       
    68  *
       
    69  * <p>For a permission you need, this is the {@linkplain
       
    70  * javax.management.MBeanServerFactory#getMBeanServerName
       
    71  * name of the MBeanServer}
       
    72  * from which the <a href="#MBeanName">MBean</a> is accessed.</p>
       
    73  *
       
    74  * <p>For a permission you have, this is either the  {@linkplain
       
    75  * javax.management.MBeanServerFactory#getMBeanServerName
       
    76  * name of the MBeanServer} from which the <a href="#MBeanName">MBean</a>
       
    77  * for which you have this permission is accessed,
       
    78  * or a pattern against which that MBean Server name will be matched.<br>
       
    79  * An {@code mbeanServername} pattern can also be empty, or the single
       
    80  * character {@code "*"}, both of which match any {@code MBeanServer} name.
       
    81  * The string {@code "-"} doesn't match any MBeanServer name.
       
    82  * </p>
       
    83  *
       
    84  * <p>Example:</p>
       
    85  * <pre>
       
    86  *   // grant permission to invoke the operation "stop" on any MBean
       
    87  *   // whose name matches "a//*&#42;//*:type=JMXConnectorServer" when
       
    88  *   // accessed from any MBeanServer whose name matches myapp.*"
       
    89  *   permission javax.management.namespace.JMXNamespacePermission "myapp.*::stop[a//*&#42;//*:type=JMXConnectorServer]", "invoke";
       
    90  * </pre>
       
    91  *
       
    92  * <li id="Member"><p>The <em>member</em>.</p>
       
    93  *
       
    94  * <p>For a permission you need, this is the name of the attribute or
       
    95  * operation you are accessing.  For operations that do not reference
       
    96  * an attribute or operation, the member is null.</p>
       
    97  *
       
    98  * <p>For a permission you have, this is either the name of an attribute
       
    99  * or operation you can access, or it is empty or the single character
       
   100  * "<code>*</code>", both of which grant access to any member.</p>
       
   101  *
       
   102  * <p>There is a special case for actions {@code registerMBean} and
       
   103  *    {@code instantiate}, where for a permission you need, {@code member}
       
   104  *    indicates the name of the class for which you are trying
       
   105  *    to create, instantiate, or register an MBean instance. For a
       
   106  *    permission you have, it is a pattern that will be matched against
       
   107  *    the full class name of the MBean being created, instantiated, or
       
   108  *    registered.
       
   109  * </p>
       
   110  *
       
   111  *
       
   112  * <li id="MBeanName"><p>The <em>object name</em>.</p>
       
   113  *
       
   114  * <p>For a permission you need, this is the {@link ObjectName} of the
       
   115  * MBean you are accessing. It is of the form {@code <namespace>//<mbean name>}
       
   116  * where {@code <namespace>} is the name of the name space for which the
       
   117  * permission is checked, and {@code <mbean name>} is the name of the MBean
       
   118  * within that namespace.
       
   119  * <br>
       
   120  * For operations that do not reference a
       
   121  * single MBean, the <em>object name</em> is null.  It is never an object
       
   122  * name pattern.
       
   123  * </p>
       
   124  *
       
   125  * <p>For a permission you have, this is the {@link ObjectName} of the
       
   126  * MBean or MBeans you can access. It is of the form
       
   127  * {@code <namespace>//<mbean name>}
       
   128  * where {@code <namespace>} is the name of the name space for which the
       
   129  * permission is checked, and
       
   130  * {@code <mbean name>} is the name of the MBean
       
   131  * within that namespace. Both {@code <namespace>} and {@code <mbean name>}
       
   132  * can be patterns. The <em>object name</em>
       
   133  * may also be empty, which grants access to all MBeans whatever their
       
   134  * name and namespace.
       
   135  * When included in a namespace path the special path element
       
   136  * <code>**</code> matches any number of sub namespaces
       
   137  * recursively, but only if used as a complete namespace path element,
       
   138  * as in <code>*&#42;//b//c//D:k=v</code> or <code>a//*&#42;//c//D:k=v</code>
       
   139  * - see <a href="#metawildcard">below</a>.
       
   140  * </p>
       
   141  *
       
   142  *
       
   143  * </ul>
       
   144  *
       
   145  * <p>If you have a JMXNamespacePermission, it allows operations only
       
   146  * if all four of the items match.</p>
       
   147  *
       
   148  * <p>The <a href="#MBeanServerName">MBeanServer name</a>,
       
   149  * <a href="#Member">member</a>, and <a href="#MBeanName">object name</a>
       
   150  * can be written together
       
   151  * as a single string, which is the <em>name</em> of this permission.
       
   152  * The name of the permission is the string returned by {@link
       
   153  * java.security.Permission#getName() getName()}.
       
   154  * The format of the string is:</p>
       
   155  *
       
   156  * <blockquote>
       
   157  * {@code <mbean server name>::<member>[<namespace>//<mbean name>]}
       
   158  * </blockquote>
       
   159  *
       
   160  * <p>
       
   161  * The {@code <mbean server name>} is optional. If omitted, {@code "*"} is
       
   162  * assumed, and these three permission names
       
   163  * are thus equivalent:
       
   164  * </p>
       
   165  * <blockquote>
       
   166  * {@code *::<member>[<namespace>//<mbean name>]}<br>
       
   167  * {@code ::<member>[<namespace>//<mbean name>]}<br>
       
   168  * {@code <member>[<namespace>//<mbean name>]}<br>
       
   169  * </blockquote>
       
   170  * <p>
       
   171  *    The {@code <namespace>//<mbean name>} string can be in the form
       
   172  *    of a traditional ObjectName
       
   173  *    pattern - meaning that <code>?</code> will match any single
       
   174  *    character, and <code>*</code> will match any sequence of characters,
       
   175  *    except {@value
       
   176  *    javax.management.namespace.JMXNamespaces#NAMESPACE_SEPARATOR}
       
   177  *    In addition, when included in a namespace path the special
       
   178  *    path element <code>**</code> matches any number of sub namespaces
       
   179  *    recursively.
       
   180  *    A {@code <namespace>//<mbean name>} string of the form
       
   181  *    <code>*&#42;//*:*</code> thus means that the permission is
       
   182  *    granted for all MBeans in all namespaces, recursively (see
       
   183  *    <a href="#metawildcard">below</a> for more details.
       
   184  * </p>
       
   185  * <p>Namespace permission checking may be tricky to configure, depending
       
   186  *    on whether the namespaces crossed to reach the MBean are local or
       
   187  *    remote.<br>
       
   188  *    For instance, let <code>a//b//D:k=v</code> be an MBean exposing an
       
   189  *    attribute <code>Foo</code>.
       
   190  *    If namespace <code>a</code> is a plain JMXNamespace pointing to
       
   191  *    a local MBeanServer in the same JVM, then the permissions you need
       
   192  *    to get the attribute <code>Foo</code> will be:
       
   193  * </p>
       
   194  * <pre>
       
   195  *    // granting permission to access attribute 'Foo' of MBean a//b//D:k=v
       
   196  *    // from MBeanServer named 'srv1'
       
   197  *    // This permission will be checked by the MBeanServer that contains 'a'.
       
   198  *    srv1::Foo[a//b//D:k=v]
       
   199  *
       
   200  *    // Since a is local, you also need the following additional permission,
       
   201  *    // which will be checked by the MBeanServer 'srv2' that contains 'b':
       
   202  *    //
       
   203  *    // granting permission to access attribute 'Foo' of MBean b//D:k=v from
       
   204  *    // 'srv2'
       
   205  *    srv2::Foo[b//D:k=v]
       
   206  * </pre>
       
   207  * <p>On the other hand, if namespace <code>a</code> is a JMXRemoteNamespace
       
   208  *    pointing to an MBeanServer in a remote JVM, then the only permission you
       
   209  *    need to get the attribute <code>Foo</code> will be:
       
   210  * </p>
       
   211  * <pre>
       
   212  *    // granting permission to access attribute 'Foo' of MBean a//b//D:k=v
       
   213  *    // from 'srv1'
       
   214  *    srv1::Foo[a//b//D:k=v]
       
   215  * </pre>
       
   216  * <p>The namespace <code>b</code> resides in the remote JVM, and
       
   217  *    therefore the permissions concerning access to MBeans from
       
   218  *    namespace 'b' will only be checked in the remote JVM, if that JVM is
       
   219  *    configured to do so.
       
   220  * </p>
       
   221  *
       
   222  * <p>The {@code <mbean name>} is written using the usual syntax for {@link
       
   223  * ObjectName}.  It may contain any legal characters, including
       
   224  * <code>]</code>.  It is terminated by a <code>]</code> character
       
   225  * that is the last character in the string.
       
   226  * </p>
       
   227  * <p>Below are some examples of permission names:</p>
       
   228  * <pre>
       
   229  *    // allows access to Foo in 'a//b//*:*' from any MBeanServer in the JVM.
       
   230  *    Foo[a//b//*:*]
       
   231  *
       
   232  *    // allows access to Foo in all subnamespaces of 'a//b', but only for
       
   233  *    // MBeanServers whose name matches 'myapp.*'
       
   234  *    myapp.*::Foo[a//b//*&#42;//*:*]
       
   235  *
       
   236  *    // allows access to Foo from all namespaces in the MBeanServer named
       
   237  *    // 'myapp.srv1' - but not recursively.
       
   238  *    myapp.srv1::Foo[&#42;//*:*]
       
   239  * </pre>
       
   240  * <p>For instance, the first two permissions listed above
       
   241  *    will let through {@code getAttribute("a//b//D:k=v","Foo");} in
       
   242  *    all MBeanServers, but will block access to
       
   243  *    {@code getAttribute("a//b//c//D:k=v","Foo");} in MBeanServers whose
       
   244  *    name do not start with {@code "myapp."}.
       
   245  * </p>
       
   246  * <p><a name="metawildcard">Depending on how your namespace hierarchy
       
   247  *    is defined some of these wildcard permission names can be useful</a>:</p>
       
   248  * <pre>
       
   249  *    // allows access to Foo in all namespaces, recursively.
       
   250  *    //
       
   251  *    *::Foo[*&#42;//*:*]
       
   252  *
       
   253  *    // This permission name is the equivalent to the permission names above:
       
   254  *    // Foo[*&#42;//*:*] and Foo[] are equivalent.
       
   255  *    //
       
   256  *    Foo[]
       
   257  *
       
   258  *    // This permission name is the equivalent to the two permission names
       
   259  *    // above:
       
   260  *    // Foo[*&#42;//*:*], Foo[], Foo are equivalent.
       
   261  *    //
       
   262  *    Foo
       
   263  *
       
   264  *    // allows access to Foo from all namespaces - but not recursively.
       
   265  *    // This wildcard permission complements the previous one: it allows
       
   266  *    // access to 'Foo' from an MBean directly registered in any local namespace.
       
   267  *    //
       
   268  *    Foo[&#42;//*:*]
       
   269  *
       
   270  * </pre>
       
   271  * <p><b>Note on wildcards:</b> In an object name pattern, a path element
       
   272  *    of exactly <code>**</code> corresponds to a meta
       
   273  *    wildcard that will match any number of sub namespaces. Hence:</p>
       
   274  * <ul>
       
   275  * <table border="1">
       
   276  * <thead><th>pattern</th><th>matches</th><th>doesn't match</th></thead>
       
   277  * <tbody>
       
   278  * <tr><td><code>*&#42;//D:k=v</code></td>
       
   279  *     <td><code>a//D:k=v</code><br>
       
   280  *         <code>a//b//D:k=v</code><br>
       
   281  *         <code>a//b//c//D:k=v</code></td>
       
   282  *     <td><code>D:k=v</code></td></tr>
       
   283  * <tr><td><code>a//*&#42;//D:k=v</code></td>
       
   284  *     <td><code>a//b//D:k=v</code><br>
       
   285  *         <code>a//b//c//D:k=v</code></td>
       
   286  *     <td><code>b//b//c//D:k=v</code><br>
       
   287  *         <code>a//D:k=v</code><br>
       
   288  *         <code>D:k=v</code></td></tr>
       
   289  * <tr><td><code>a//*&#42;//e//D:k=v</code></td>
       
   290  *     <td><code>a//b//e//D:k=v</code><br>
       
   291  *         <code>a//b//c//e//D:k=v</code></td>
       
   292  *     <td><code>a//b//c//c//D:k=v</code><br>
       
   293  *         <code>b//b//c//e//D:k=v</code><br>
       
   294  *         <code>a//e//D:k=v</code><br>
       
   295  *         <code>e//D:k=v</code></td></tr>
       
   296  * <tr><td><code>a//b*&#42;//e//D:k=v</code></td>
       
   297  *      <td><code>a//b//e//D:k=v</code></td>
       
   298  *      <td><code>a//b//c//e//D:k=v</code><br>
       
   299  *          because in that case <code>b*&#42;</code><br>
       
   300  *         is not a meta-wildcard - and <code>b**</code><br>
       
   301  *         is thus equivalent to <code>b*</code>.</td></tr>
       
   302  * </tbody>
       
   303  * </table>
       
   304  *</ul>
       
   305  *
       
   306  * <p>If {@code <mbean server name>::} is omitted, then one of
       
   307  * <code>member</code> or <code>object name</code> may be omitted.
       
   308  * If the <code>object name</code> is omitted,
       
   309  * the <code>[]</code> may be too (but does not have to be).  It is
       
   310  * not legal to omit all items, that is to have a <em>name</em>
       
   311  * which is the empty string.</p>
       
   312  * <p>If {@code <mbean server name>} is present, it <b>must be followed</b> by
       
   313  *    the {@code "::"} separator - otherwise it will be interpreted as
       
   314  *    a {@code member name}.
       
   315  * </p>
       
   316  *
       
   317  * <p>
       
   318  * One or more of the <a href="#MBeanServerName">MBean Server name</a>,
       
   319  * <a href="#Member">member</a>
       
   320  * or <a href="#MBeanName">object name</a> may be the character "<code>-</code>",
       
   321  * which is equivalent to a null value.  A null value is implied by
       
   322  * any value (including another null value) but does not imply any
       
   323  * other value.
       
   324  * </p>
       
   325  *
       
   326  * <p><a name="action-list">The possible actions are these:</a></p>
       
   327  *
       
   328  * <ul>
       
   329  * <li>addNotificationListener</li>
       
   330  * <li>getAttribute</li>
       
   331  * <li>getClassLoader</li>
       
   332  * <li>getClassLoaderFor</li>
       
   333  * <li>getClassLoaderRepository</li>
       
   334  * <li>getMBeanInfo</li>
       
   335  * <li>getObjectInstance</li>
       
   336  * <li>instantiate</li>
       
   337  * <li>invoke</li>
       
   338  * <li>isInstanceOf</li>
       
   339  * <li>queryMBeans</li>
       
   340  * <li>queryNames</li>
       
   341  * <li>registerMBean</li>
       
   342  * <li>removeNotificationListener</li>
       
   343  * <li>setAttribute</li>
       
   344  * <li>unregisterMBean</li>
       
   345  * </ul>
       
   346  *
       
   347  * <p>In a comma-separated list of actions, spaces are allowed before
       
   348  * and after each action.</p>
       
   349  *
       
   350  * @since 1.7
       
   351  */
       
   352 public class JMXNamespacePermission extends Permission {
       
   353 
       
   354     private static final long serialVersionUID = -2416928705275160661L;
       
   355 
       
   356     private static final String WILDPATH = "**" +
       
   357                 JMXNamespaces.NAMESPACE_SEPARATOR + "*";
       
   358 
       
   359     /**
       
   360      * Actions list.
       
   361      */
       
   362     private static final int AddNotificationListener    = 0x00001;
       
   363     private static final int GetAttribute               = 0x00002;
       
   364     private static final int GetClassLoader             = 0x00004;
       
   365     private static final int GetClassLoaderFor          = 0x00008;
       
   366     private static final int GetClassLoaderRepository   = 0x00010;
       
   367     // No GetDomains because it is not possible to route a call to
       
   368     // getDomains() on a NamespaceInterceptor - getDomains() doesn't
       
   369     // have any ObjectName.
       
   370     // private static final int GetDomains                 = 0x00020;
       
   371     private static final int GetMBeanInfo               = 0x00040;
       
   372     private static final int GetObjectInstance          = 0x00080;
       
   373     private static final int Instantiate                = 0x00100;
       
   374     private static final int Invoke                     = 0x00200;
       
   375     private static final int IsInstanceOf               = 0x00400;
       
   376     private static final int QueryMBeans                = 0x00800;
       
   377     private static final int QueryNames                 = 0x01000;
       
   378     private static final int RegisterMBean              = 0x02000;
       
   379     private static final int RemoveNotificationListener = 0x04000;
       
   380     private static final int SetAttribute               = 0x08000;
       
   381     private static final int UnregisterMBean            = 0x10000;
       
   382 
       
   383     /**
       
   384      * No actions.
       
   385      */
       
   386     private static final int NONE = 0x00000;
       
   387 
       
   388     /**
       
   389      * All actions.
       
   390      */
       
   391     // No GetDomains because it is not possible to route a call to
       
   392     // getDomains() on a NamespaceInterceptor - getDomains() doesn't
       
   393     // have any ObjectName.
       
   394     //
       
   395     private static final int ALL =
       
   396         AddNotificationListener    |
       
   397         GetAttribute               |
       
   398         GetClassLoader             |
       
   399         GetClassLoaderFor          |
       
   400         GetClassLoaderRepository   |
       
   401         GetMBeanInfo               |
       
   402         GetObjectInstance          |
       
   403         Instantiate                |
       
   404         Invoke                     |
       
   405         IsInstanceOf               |
       
   406         QueryMBeans                |
       
   407         QueryNames                 |
       
   408         RegisterMBean              |
       
   409         RemoveNotificationListener |
       
   410         SetAttribute               |
       
   411         UnregisterMBean;
       
   412 
       
   413     /**
       
   414      * The actions string.
       
   415      */
       
   416     private String actions;
       
   417 
       
   418     /**
       
   419      * The actions mask.
       
   420      */
       
   421     private transient int mask;
       
   422 
       
   423     /**
       
   424      * The name of the MBeanServer in which this permission is checked, or
       
   425      * granted.  If null, is implied by any MBean server name
       
   426      * but does not imply any non-null MBean server name.
       
   427      */
       
   428     private transient String mbeanServerName;
       
   429 
       
   430     /**
       
   431      * The member that must match.  If null, is implied by any member
       
   432      * but does not imply any non-null member.
       
   433      */
       
   434     private transient String member;
       
   435 
       
   436     /**
       
   437      * The objectName that must match.  If null, is implied by any
       
   438      * objectName but does not imply any non-null objectName.
       
   439      */
       
   440     private transient ObjectName objectName;
       
   441 
       
   442     /**
       
   443      * If objectName is missing from name, then allnames will be
       
   444      * set to true.
       
   445      */
       
   446     private transient boolean  allnames = false;
       
   447 
       
   448     /**
       
   449      * Parse <code>actions</code> parameter.
       
   450      */
       
   451     private void parseActions() {
       
   452 
       
   453         int amask;
       
   454 
       
   455         if (actions == null)
       
   456             throw new IllegalArgumentException("JMXNamespaceAccessPermission: " +
       
   457                                                "actions can't be null");
       
   458         if (actions.equals(""))
       
   459             throw new IllegalArgumentException("JMXNamespaceAccessPermission: " +
       
   460                                                "actions can't be empty");
       
   461 
       
   462         amask = getMask(actions);
       
   463 
       
   464         if ((amask & ALL) != amask)
       
   465             throw new IllegalArgumentException("Invalid actions mask");
       
   466         if (amask == NONE)
       
   467             throw new IllegalArgumentException("Invalid actions mask");
       
   468         this.mask = amask;
       
   469     }
       
   470 
       
   471     /**
       
   472      * Parse <code>name</code> parameter.
       
   473      */
       
   474     private void parseName() {
       
   475         String name = getName();
       
   476 
       
   477         if (name == null)
       
   478             throw new IllegalArgumentException("JMXNamespaceAccessPermission name " +
       
   479                                                "cannot be null");
       
   480 
       
   481         if (name.equals(""))
       
   482             throw new IllegalArgumentException("JMXNamespaceAccessPermission name " +
       
   483                                                "cannot be empty");
       
   484         final int sepIndex = name.indexOf("::");
       
   485         if (sepIndex < 0) {
       
   486             setMBeanServerName("*");
       
   487         } else {
       
   488             setMBeanServerName(name.substring(0,sepIndex));
       
   489         }
       
   490 
       
   491         /* The name looks like "mbeanServerName::member[objectname]".
       
   492            We subtract elements from the right as we parse, so after
       
   493            parsing the objectname we have "class#member" and after parsing the
       
   494            member we have "class".  Each element is optional.  */
       
   495 
       
   496         // Parse ObjectName
       
   497 
       
   498         final int start = (sepIndex<0)?0:sepIndex+2;
       
   499         int openingBracket = name.indexOf("[",start);
       
   500         if (openingBracket == -1) {
       
   501             // If "[on]" missing then ObjectName("*:*")
       
   502             //
       
   503             objectName = null;
       
   504             allnames = true;
       
   505             openingBracket=name.length();
       
   506         } else {
       
   507             if (!name.endsWith("]")) {
       
   508                 throw new IllegalArgumentException("JMXNamespaceAccessPermission: " +
       
   509                                                    "The ObjectName in the " +
       
   510                                                    "target name must be " +
       
   511                                                    "included in square " +
       
   512                                                    "brackets");
       
   513             } else {
       
   514                 // Create ObjectName
       
   515                 //
       
   516                 String on = name.substring(openingBracket + 1,
       
   517                                            name.length() - 1);
       
   518                 try {
       
   519                     // If "[]" then allnames are implied
       
   520                     //
       
   521                     final ObjectName target;
       
   522                     final boolean    all;
       
   523                     if (on.equals("")) {
       
   524                         target = null;
       
   525                         all = true;
       
   526                     } else if (on.equals("-")) {
       
   527                         target = null;
       
   528                         all = false;
       
   529                     } else {
       
   530                         target = new ObjectName(on);
       
   531                         all    = false;
       
   532                     }
       
   533                     setObjectName(target,all);
       
   534                 } catch (MalformedObjectNameException e) {
       
   535                     throw new IllegalArgumentException(
       
   536                             "JMXNamespaceAccessPermission: " +
       
   537                             "The target name does " +
       
   538                             "not specify a valid " +
       
   539                             "ObjectName", e);
       
   540                 }
       
   541             }
       
   542         }
       
   543 
       
   544         final String memberName = name.substring(start,openingBracket);
       
   545         setMember(memberName);
       
   546     }
       
   547 
       
   548     private void setObjectName(ObjectName target, boolean all) {
       
   549         if (target != null &&
       
   550             !Util.wildpathmatch(target.getDomain(), WILDPATH)) {
       
   551             throw new IllegalArgumentException(
       
   552                     "The target name does not contain " +
       
   553                     "any namespace: "+String.valueOf(target));
       
   554         } else if (target != null) {
       
   555             final String domain = target.getDomain();
       
   556             final int seplen = JMXNamespaces.NAMESPACE_SEPARATOR.length();
       
   557             final int sepc = domain.indexOf(JMXNamespaces.NAMESPACE_SEPARATOR);
       
   558             if (sepc < 0 || (sepc+seplen)==domain.length()) {
       
   559                 throw new IllegalArgumentException(String.valueOf(target)+
       
   560                         ": no namespace in domain");
       
   561             }
       
   562         }
       
   563         objectName = target;
       
   564         allnames = all;
       
   565     }
       
   566 
       
   567     /**
       
   568      * Assign fields based on className, member, and objectName
       
   569      * parameters.
       
   570      */
       
   571 //    private void initName(String namespaceName, String member,
       
   572 //                          ObjectName objectName, boolean allnames) {
       
   573 //        setNamespace(namespaceName);
       
   574     private void initName(String mbeanServerName, String member,
       
   575                           ObjectName mbeanName, boolean all) {
       
   576         setMBeanServerName(mbeanServerName);
       
   577         setMember(member);
       
   578         setObjectName(mbeanName, all);
       
   579     }
       
   580 
       
   581     private void setMBeanServerName(String mbeanServerName) {
       
   582         if (mbeanServerName == null || mbeanServerName.equals("-")) {
       
   583             this.mbeanServerName = null;
       
   584         } else if (mbeanServerName.equals("")) {
       
   585             this.mbeanServerName = "*";
       
   586         } else {
       
   587             this.mbeanServerName = mbeanServerName;
       
   588         }
       
   589     }
       
   590 
       
   591     private void setMember(String member) {
       
   592         if (member == null || member.equals("-"))
       
   593             this.member = null;
       
   594         else if (member.equals(""))
       
   595             this.member = "*";
       
   596         else
       
   597             this.member = member;
       
   598     }
       
   599 
       
   600     /**
       
   601      * <p>Create a new JMXNamespacePermission object with the
       
   602      * specified target name and actions.</p>
       
   603      *
       
   604      * <p>The target name is of the form
       
   605      * "<code>mbeanServerName::member[objectName]</code>" where each part is
       
   606      * optional. This target name must not be empty or null.
       
   607      * If <code>objectName</code> is present, it is of
       
   608      * the form <code>namespace//MBeanName</code>.
       
   609      * </p>
       
   610      * <p>
       
   611      * For a permission you need, {@code mbeanServerName} is the
       
   612      * <a href="#MBeanServerName">name of the MBeanServer</a> from
       
   613      * which {@code objectName} is being accessed.
       
   614      * </p>
       
   615      * <p>
       
   616      * For a permission you have, {@code mbeanServerName} is the
       
   617      * <a href="#MBeanServerName">name of the MBeanServer</a> from
       
   618      * which access to {@code objectName} is granted.
       
   619      * It can also be a pattern, and if omitted, {@code "*"} is assumed,
       
   620      * meaning that access to {@code objectName} is granted in all
       
   621      * MBean servers in the JVM.
       
   622      * </p>
       
   623      *
       
   624      * <p>The actions parameter contains a comma-separated list of the
       
   625      * desired actions granted on the target name.  It must not be
       
   626      * empty or null.</p>
       
   627      *
       
   628      * @param name the triplet "mbeanServerName::member[objectName]".
       
   629      * If <code>objectName</code> is present, it is of
       
   630      * the form <code>namespace//MBeanName</code>.
       
   631      * @param actions the action string.
       
   632      *
       
   633      * @exception IllegalArgumentException if the <code>name</code> or
       
   634      * <code>actions</code> is invalid.
       
   635      */
       
   636     public JMXNamespacePermission(String name, String actions) {
       
   637         super(name);
       
   638 
       
   639         parseName();
       
   640 
       
   641         this.actions = actions;
       
   642         parseActions();
       
   643     }
       
   644 
       
   645     /**
       
   646      * <p>Create a new JMXNamespacePermission object with the specified
       
   647      * target name (namespace name, member, object name) and actions.</p>
       
   648      *
       
   649      * <p>The {@code MBeanServer} name, member and object name
       
   650      * parameters define a target name of the form
       
   651      * "<code>mbeanServerName::member[objectName]</code>" where each
       
   652      * part is optional.  This will be the result of {@link #getName()} on the
       
   653      * resultant JMXNamespacePermission.
       
   654      * If the <code>mbeanServerName</code> is empty or exactly {@code "*"}, then
       
   655      * "{@code mbeanServerName::}" is omitted in that result.
       
   656      * </p>
       
   657      *
       
   658      * <p>The actions parameter contains a comma-separated list of the
       
   659      * desired actions granted on the target name.  It must not be
       
   660      * empty or null.</p>
       
   661      *
       
   662      * @param mbeanServerName the name of the {@code MBeanServer} to which this
       
   663      * permission applies.
       
   664      * May be null or <code>"-"</code>, which represents an MBeanServer name
       
   665      * that is implied by any MBeanServer name but does not imply any other
       
   666      * MBeanServer name.
       
   667      * @param member the member to which this permission applies.  May
       
   668      * be null or <code>"-"</code>, which represents a member that is
       
   669      * implied by any member but does not imply any other member.
       
   670      * @param objectName the object name to which this permission
       
   671      * applies.
       
   672      * May be null, which represents an object name that is
       
   673      * implied by any object name but does not imply any other object
       
   674      * name. If not null, the {@code objectName} must be of the
       
   675      * form {@code <namespace>//<mbean name>} - where {@code <namespace>}
       
   676      * can be a domain pattern, and {@code <mbean name>} can be an ObjectName
       
   677      * pattern.
       
   678      * For a permission you need, {@code <namespace>} is the name of the
       
   679      * name space for which the permission is checked, and {@code <mbean name>}
       
   680      * is the name of the MBean in that namespace.
       
   681      * The composed name {@code <namespace>//<mbean name>} thus represents the
       
   682      * name of the MBean as seen by the {@code mbeanServerName} containing
       
   683      * {@code <namespace>}.
       
   684      *
       
   685      * @param actions the action string.
       
   686      */
       
   687     public JMXNamespacePermission(
       
   688                            String mbeanServerName,
       
   689                            String member,
       
   690                            ObjectName objectName,
       
   691                            String actions) {
       
   692         this(mbeanServerName, member, objectName, false, actions);
       
   693 //        this(member, objectName, false, actions);
       
   694     }
       
   695 
       
   696     /**
       
   697      * <p>Create a new JMXNamespacePermission object with the specified
       
   698      * MBean Server name, member, and actions.</p>
       
   699      *
       
   700      * <p>The {@code MBeanServer} name and member
       
   701      * parameters define a target name of the form
       
   702      * "<code>mbeanServerName::member[]</code>" where each
       
   703      * part is optional.  This will be the result of {@link #getName()} on the
       
   704      * resultant JMXNamespacePermission.
       
   705      * If the <code>mbeanServerName</code> is empty or exactly {@code "*"}, then
       
   706      * "{@code mbeanServerName::}" is omitted in that result.
       
   707      * </p>
       
   708      *
       
   709      * <p>The actions parameter contains a comma-separated list of the
       
   710      * desired actions granted on the target name.  It must not be
       
   711      * empty or null.</p>
       
   712      *
       
   713      * @param mbeanServerName the name of the {@code MBeanServer} to which this
       
   714      * permission applies.
       
   715      * May be null or <code>"-"</code>, which represents an MBeanServer name
       
   716      * that is implied by any MBeanServer name but does not imply any other
       
   717      * MBeanServer name.
       
   718      * @param member the member to which this permission applies.  May
       
   719      * be null or <code>"-"</code>, which represents a member that is
       
   720      * implied by any member but does not imply any other member.
       
   721      * @param actions the action string.
       
   722      */
       
   723     public JMXNamespacePermission(String mbeanServerName,
       
   724                            String member,
       
   725                            String actions) {
       
   726         this(mbeanServerName,member,null,true,actions);
       
   727         // this(member,null,allnames,actions);
       
   728     }
       
   729 
       
   730     /**
       
   731      * <p>Create a new JMXNamespacePermission object with the specified
       
   732      * target name (namespace name, member, object name) and actions.</p>
       
   733      *
       
   734      * <p>The MBean Server name, member and object name parameters define a
       
   735      * target name of the form
       
   736      * "<code>mbeanServerName::member[objectName]</code>" where each part is
       
   737      * optional.  This will be the result of {@link
       
   738      * java.security.Permission#getName() getName()} on the
       
   739      * resultant JMXNamespacePermission.</p>
       
   740      *
       
   741      * <p>The actions parameter contains a comma-separated list of the
       
   742      * desired actions granted on the target name.  It must not be
       
   743      * empty or null.</p>
       
   744      *
       
   745      * @param mbeanServerName the name of the {@code MBeanServer} to which this
       
   746      * permission applies.
       
   747      * May be null or <code>"-"</code>, which represents an MBeanServer name
       
   748      * that is implied by any MBeanServer name but does not imply any other
       
   749      * MBeanServer name.
       
   750      * @param member the member to which this permission applies.  May
       
   751      * be null or <code>"-"</code>, which represents a member that is
       
   752      * implied by any member but does not imply any other member.
       
   753      * @param objectName the object name to which this permission
       
   754      * applies.  If null, and allnames is false, represents an object
       
   755      * name that is implied by any object name but does not imply any
       
   756      * other object name. Otherwise, if allnames is true, it represents
       
   757      * a meta wildcard that matches all object names. It is equivalent to
       
   758      * a missing objectName ("[]") in the {@link
       
   759      * java.security.Permission#getName() name} property.
       
   760      * @param allnames represent a meta wildcard indicating that the
       
   761      *        objectName was not specified. This implies all objectnames
       
   762      *        that match "*:*" and all object names that match
       
   763      *        "*&#42;//*:*"
       
   764      * @param actions the action string.
       
   765      */
       
   766     private JMXNamespacePermission(String mbeanServerName,
       
   767                            String member,
       
   768                            ObjectName objectName,
       
   769                            boolean allnames,
       
   770                            String actions) {
       
   771 
       
   772         super(makeName(mbeanServerName,
       
   773                 member, objectName, allnames));
       
   774         initName(mbeanServerName,
       
   775                 member, objectName, allnames);
       
   776 
       
   777         this.actions = actions;
       
   778         parseActions();
       
   779     }
       
   780 
       
   781     private static String makeName(String mbeanServerName,
       
   782             String memberName, ObjectName objName, boolean allMBeans) {
       
   783         final StringBuilder name = new StringBuilder();
       
   784         if (mbeanServerName == null)
       
   785             mbeanServerName = "-";
       
   786         if (!mbeanServerName.equals("") && !mbeanServerName.equals("*"))
       
   787             name.append(mbeanServerName).append("::");
       
   788         if (memberName == null)
       
   789             memberName = "-";
       
   790         name.append(memberName);
       
   791         if (objName == null) {
       
   792             if (allMBeans)
       
   793                 name.append("[]");
       
   794             else
       
   795                 name.append("[-]");
       
   796         } else {
       
   797             final String domain = objName.getDomain();
       
   798             final int seplen = JMXNamespaces.NAMESPACE_SEPARATOR.length();
       
   799             final int sepc = domain.indexOf(JMXNamespaces.NAMESPACE_SEPARATOR);
       
   800             if (sepc < 0 || (sepc+seplen)==domain.length()) {
       
   801                 throw new IllegalArgumentException(String.valueOf(objName)+
       
   802                         ": no namespace in domain");
       
   803             }
       
   804             final String can = objName.getCanonicalName();
       
   805             name.append("[").append(can).append("]");
       
   806         }
       
   807         return name.toString();
       
   808     }
       
   809 
       
   810     /**
       
   811      * Returns the "canonical string representation" of the actions. That is,
       
   812      * this method always returns actions in alphabetical order.
       
   813      *
       
   814      * @return the canonical string representation of the actions.
       
   815      */
       
   816     public String getActions() {
       
   817 
       
   818         if (actions == null)
       
   819             actions = getActions(this.mask);
       
   820 
       
   821         return actions;
       
   822     }
       
   823 
       
   824     /**
       
   825      * Returns the "canonical string representation"
       
   826      * of the actions from the mask.
       
   827      */
       
   828     private static String getActions(int mask) {
       
   829         final StringBuilder sb = new StringBuilder();
       
   830         boolean comma = false;
       
   831 
       
   832         if ((mask & AddNotificationListener) == AddNotificationListener) {
       
   833             comma = true;
       
   834             sb.append("addNotificationListener");
       
   835         }
       
   836 
       
   837         if ((mask & GetAttribute) == GetAttribute) {
       
   838             if (comma) sb.append(',');
       
   839             else comma = true;
       
   840             sb.append("getAttribute");
       
   841         }
       
   842 
       
   843         if ((mask & GetClassLoader) == GetClassLoader) {
       
   844             if (comma) sb.append(',');
       
   845             else comma = true;
       
   846             sb.append("getClassLoader");
       
   847         }
       
   848 
       
   849         if ((mask & GetClassLoaderFor) == GetClassLoaderFor) {
       
   850             if (comma) sb.append(',');
       
   851             else comma = true;
       
   852             sb.append("getClassLoaderFor");
       
   853         }
       
   854 
       
   855         if ((mask & GetClassLoaderRepository) == GetClassLoaderRepository) {
       
   856             if (comma) sb.append(',');
       
   857             else comma = true;
       
   858             sb.append("getClassLoaderRepository");
       
   859         }
       
   860 
       
   861         if ((mask & GetMBeanInfo) == GetMBeanInfo) {
       
   862             if (comma) sb.append(',');
       
   863             else comma = true;
       
   864             sb.append("getMBeanInfo");
       
   865         }
       
   866 
       
   867         if ((mask & GetObjectInstance) == GetObjectInstance) {
       
   868             if (comma) sb.append(',');
       
   869             else comma = true;
       
   870             sb.append("getObjectInstance");
       
   871         }
       
   872 
       
   873         if ((mask & Instantiate) == Instantiate) {
       
   874             if (comma) sb.append(',');
       
   875             else comma = true;
       
   876             sb.append("instantiate");
       
   877         }
       
   878 
       
   879         if ((mask & Invoke) == Invoke) {
       
   880             if (comma) sb.append(',');
       
   881             else comma = true;
       
   882             sb.append("invoke");
       
   883         }
       
   884 
       
   885         if ((mask & IsInstanceOf) == IsInstanceOf) {
       
   886             if (comma) sb.append(',');
       
   887             else comma = true;
       
   888             sb.append("isInstanceOf");
       
   889         }
       
   890 
       
   891         if ((mask & QueryMBeans) == QueryMBeans) {
       
   892             if (comma) sb.append(',');
       
   893             else comma = true;
       
   894             sb.append("queryMBeans");
       
   895         }
       
   896 
       
   897         if ((mask & QueryNames) == QueryNames) {
       
   898             if (comma) sb.append(',');
       
   899             else comma = true;
       
   900             sb.append("queryNames");
       
   901         }
       
   902 
       
   903         if ((mask & RegisterMBean) == RegisterMBean) {
       
   904             if (comma) sb.append(',');
       
   905             else comma = true;
       
   906             sb.append("registerMBean");
       
   907         }
       
   908 
       
   909         if ((mask & RemoveNotificationListener) == RemoveNotificationListener) {
       
   910             if (comma) sb.append(',');
       
   911             else comma = true;
       
   912             sb.append("removeNotificationListener");
       
   913         }
       
   914 
       
   915         if ((mask & SetAttribute) == SetAttribute) {
       
   916             if (comma) sb.append(',');
       
   917             else comma = true;
       
   918             sb.append("setAttribute");
       
   919         }
       
   920 
       
   921         if ((mask & UnregisterMBean) == UnregisterMBean) {
       
   922             if (comma) sb.append(',');
       
   923             else comma = true;
       
   924             sb.append("unregisterMBean");
       
   925         }
       
   926 
       
   927         // No GetDomains because it is not possible to route a call to
       
   928         // getDomains() on a NamespaceInterceptor - getDomains() doesn't
       
   929         // have any ObjectName.
       
   930 
       
   931         return sb.toString();
       
   932     }
       
   933 
       
   934     @Override
       
   935     public int hashCode() {
       
   936         return this.getName().hashCode() + this.getActions().hashCode();
       
   937     }
       
   938 
       
   939     /**
       
   940      * Converts an action String to an integer action mask.
       
   941      *
       
   942      * @param action the action string.
       
   943      * @return the action mask.
       
   944      */
       
   945     private static int getMask(String action) {
       
   946 
       
   947         /*
       
   948          * BE CAREFUL HERE! PARSING ORDER IS IMPORTANT IN THIS ALGORITHM.
       
   949          *
       
   950          * The 'string length' test must be performed for the lengthiest
       
   951          * strings first.
       
   952          *
       
   953          * In this permission if the "unregisterMBean" string length test is
       
   954          * performed after the "registerMBean" string length test the algorithm
       
   955          * considers the 'unregisterMBean' action as being the 'registerMBean'
       
   956          * action and a parsing error is returned.
       
   957          */
       
   958 
       
   959         int mask = NONE;
       
   960 
       
   961         if (action == null) {
       
   962             return mask;
       
   963         }
       
   964 
       
   965         if (action.equals("*")) {
       
   966             return ALL;
       
   967         }
       
   968 
       
   969         char[] a = action.toCharArray();
       
   970 
       
   971         int i = a.length - 1;
       
   972         if (i < 0)
       
   973             return mask;
       
   974 
       
   975         while (i != -1) {
       
   976             char c;
       
   977 
       
   978             // skip whitespace
       
   979             while ((i!=-1) && ((c = a[i]) == ' ' ||
       
   980                                c == '\r' ||
       
   981                                c == '\n' ||
       
   982                                c == '\f' ||
       
   983                                c == '\t'))
       
   984                 i--;
       
   985 
       
   986             // check for the known strings
       
   987             int matchlen;
       
   988 
       
   989             // No GetDomains because it is not possible to route a call to
       
   990             // getDomains() on a NamespaceInterceptor - getDomains() doesn't
       
   991             // have any ObjectName.
       
   992 
       
   993             if (i >= 25 && /* removeNotificationListener */
       
   994                 (a[i-25] == 'r') &&
       
   995                 (a[i-24] == 'e') &&
       
   996                 (a[i-23] == 'm') &&
       
   997                 (a[i-22] == 'o') &&
       
   998                 (a[i-21] == 'v') &&
       
   999                 (a[i-20] == 'e') &&
       
  1000                 (a[i-19] == 'N') &&
       
  1001                 (a[i-18] == 'o') &&
       
  1002                 (a[i-17] == 't') &&
       
  1003                 (a[i-16] == 'i') &&
       
  1004                 (a[i-15] == 'f') &&
       
  1005                 (a[i-14] == 'i') &&
       
  1006                 (a[i-13] == 'c') &&
       
  1007                 (a[i-12] == 'a') &&
       
  1008                 (a[i-11] == 't') &&
       
  1009                 (a[i-10] == 'i') &&
       
  1010                 (a[i-9] == 'o') &&
       
  1011                 (a[i-8] == 'n') &&
       
  1012                 (a[i-7] == 'L') &&
       
  1013                 (a[i-6] == 'i') &&
       
  1014                 (a[i-5] == 's') &&
       
  1015                 (a[i-4] == 't') &&
       
  1016                 (a[i-3] == 'e') &&
       
  1017                 (a[i-2] == 'n') &&
       
  1018                 (a[i-1] == 'e') &&
       
  1019                 (a[i] == 'r')) {
       
  1020                 matchlen = 26;
       
  1021                 mask |= RemoveNotificationListener;
       
  1022             } else if (i >= 23 && /* getClassLoaderRepository */
       
  1023                        (a[i-23] == 'g') &&
       
  1024                        (a[i-22] == 'e') &&
       
  1025                        (a[i-21] == 't') &&
       
  1026                        (a[i-20] == 'C') &&
       
  1027                        (a[i-19] == 'l') &&
       
  1028                        (a[i-18] == 'a') &&
       
  1029                        (a[i-17] == 's') &&
       
  1030                        (a[i-16] == 's') &&
       
  1031                        (a[i-15] == 'L') &&
       
  1032                        (a[i-14] == 'o') &&
       
  1033                        (a[i-13] == 'a') &&
       
  1034                        (a[i-12] == 'd') &&
       
  1035                        (a[i-11] == 'e') &&
       
  1036                        (a[i-10] == 'r') &&
       
  1037                        (a[i-9] == 'R') &&
       
  1038                        (a[i-8] == 'e') &&
       
  1039                        (a[i-7] == 'p') &&
       
  1040                        (a[i-6] == 'o') &&
       
  1041                        (a[i-5] == 's') &&
       
  1042                        (a[i-4] == 'i') &&
       
  1043                        (a[i-3] == 't') &&
       
  1044                        (a[i-2] == 'o') &&
       
  1045                        (a[i-1] == 'r') &&
       
  1046                        (a[i] == 'y')) {
       
  1047                 matchlen = 24;
       
  1048                 mask |= GetClassLoaderRepository;
       
  1049             } else if (i >= 22 && /* addNotificationListener */
       
  1050                        (a[i-22] == 'a') &&
       
  1051                        (a[i-21] == 'd') &&
       
  1052                        (a[i-20] == 'd') &&
       
  1053                        (a[i-19] == 'N') &&
       
  1054                        (a[i-18] == 'o') &&
       
  1055                        (a[i-17] == 't') &&
       
  1056                        (a[i-16] == 'i') &&
       
  1057                        (a[i-15] == 'f') &&
       
  1058                        (a[i-14] == 'i') &&
       
  1059                        (a[i-13] == 'c') &&
       
  1060                        (a[i-12] == 'a') &&
       
  1061                        (a[i-11] == 't') &&
       
  1062                        (a[i-10] == 'i') &&
       
  1063                        (a[i-9] == 'o') &&
       
  1064                        (a[i-8] == 'n') &&
       
  1065                        (a[i-7] == 'L') &&
       
  1066                        (a[i-6] == 'i') &&
       
  1067                        (a[i-5] == 's') &&
       
  1068                        (a[i-4] == 't') &&
       
  1069                        (a[i-3] == 'e') &&
       
  1070                        (a[i-2] == 'n') &&
       
  1071                        (a[i-1] == 'e') &&
       
  1072                        (a[i] == 'r')) {
       
  1073                 matchlen = 23;
       
  1074                 mask |= AddNotificationListener;
       
  1075             } else if (i >= 16 && /* getClassLoaderFor */
       
  1076                        (a[i-16] == 'g') &&
       
  1077                        (a[i-15] == 'e') &&
       
  1078                        (a[i-14] == 't') &&
       
  1079                        (a[i-13] == 'C') &&
       
  1080                        (a[i-12] == 'l') &&
       
  1081                        (a[i-11] == 'a') &&
       
  1082                        (a[i-10] == 's') &&
       
  1083                        (a[i-9] == 's') &&
       
  1084                        (a[i-8] == 'L') &&
       
  1085                        (a[i-7] == 'o') &&
       
  1086                        (a[i-6] == 'a') &&
       
  1087                        (a[i-5] == 'd') &&
       
  1088                        (a[i-4] == 'e') &&
       
  1089                        (a[i-3] == 'r') &&
       
  1090                        (a[i-2] == 'F') &&
       
  1091                        (a[i-1] == 'o') &&
       
  1092                        (a[i] == 'r')) {
       
  1093                 matchlen = 17;
       
  1094                 mask |= GetClassLoaderFor;
       
  1095             } else if (i >= 16 && /* getObjectInstance */
       
  1096                        (a[i-16] == 'g') &&
       
  1097                        (a[i-15] == 'e') &&
       
  1098                        (a[i-14] == 't') &&
       
  1099                        (a[i-13] == 'O') &&
       
  1100                        (a[i-12] == 'b') &&
       
  1101                        (a[i-11] == 'j') &&
       
  1102                        (a[i-10] == 'e') &&
       
  1103                        (a[i-9] == 'c') &&
       
  1104                        (a[i-8] == 't') &&
       
  1105                        (a[i-7] == 'I') &&
       
  1106                        (a[i-6] == 'n') &&
       
  1107                        (a[i-5] == 's') &&
       
  1108                        (a[i-4] == 't') &&
       
  1109                        (a[i-3] == 'a') &&
       
  1110                        (a[i-2] == 'n') &&
       
  1111                        (a[i-1] == 'c') &&
       
  1112                        (a[i] == 'e')) {
       
  1113                 matchlen = 17;
       
  1114                 mask |= GetObjectInstance;
       
  1115             } else if (i >= 14 && /* unregisterMBean */
       
  1116                        (a[i-14] == 'u') &&
       
  1117                        (a[i-13] == 'n') &&
       
  1118                        (a[i-12] == 'r') &&
       
  1119                        (a[i-11] == 'e') &&
       
  1120                        (a[i-10] == 'g') &&
       
  1121                        (a[i-9] == 'i') &&
       
  1122                        (a[i-8] == 's') &&
       
  1123                        (a[i-7] == 't') &&
       
  1124                        (a[i-6] == 'e') &&
       
  1125                        (a[i-5] == 'r') &&
       
  1126                        (a[i-4] == 'M') &&
       
  1127                        (a[i-3] == 'B') &&
       
  1128                        (a[i-2] == 'e') &&
       
  1129                        (a[i-1] == 'a') &&
       
  1130                        (a[i] == 'n')) {
       
  1131                 matchlen = 15;
       
  1132                 mask |= UnregisterMBean;
       
  1133             } else if (i >= 13 && /* getClassLoader */
       
  1134                        (a[i-13] == 'g') &&
       
  1135                        (a[i-12] == 'e') &&
       
  1136                        (a[i-11] == 't') &&
       
  1137                        (a[i-10] == 'C') &&
       
  1138                        (a[i-9] == 'l') &&
       
  1139                        (a[i-8] == 'a') &&
       
  1140                        (a[i-7] == 's') &&
       
  1141                        (a[i-6] == 's') &&
       
  1142                        (a[i-5] == 'L') &&
       
  1143                        (a[i-4] == 'o') &&
       
  1144                        (a[i-3] == 'a') &&
       
  1145                        (a[i-2] == 'd') &&
       
  1146                        (a[i-1] == 'e') &&
       
  1147                        (a[i] == 'r')) {
       
  1148                 matchlen = 14;
       
  1149                 mask |= GetClassLoader;
       
  1150             } else if (i >= 12 && /* registerMBean */
       
  1151                        (a[i-12] == 'r') &&
       
  1152                        (a[i-11] == 'e') &&
       
  1153                        (a[i-10] == 'g') &&
       
  1154                        (a[i-9] == 'i') &&
       
  1155                        (a[i-8] == 's') &&
       
  1156                        (a[i-7] == 't') &&
       
  1157                        (a[i-6] == 'e') &&
       
  1158                        (a[i-5] == 'r') &&
       
  1159                        (a[i-4] == 'M') &&
       
  1160                        (a[i-3] == 'B') &&
       
  1161                        (a[i-2] == 'e') &&
       
  1162                        (a[i-1] == 'a') &&
       
  1163                        (a[i] == 'n')) {
       
  1164                 matchlen = 13;
       
  1165                 mask |= RegisterMBean;
       
  1166             } else if (i >= 11 && /* getAttribute */
       
  1167                        (a[i-11] == 'g') &&
       
  1168                        (a[i-10] == 'e') &&
       
  1169                        (a[i-9] == 't') &&
       
  1170                        (a[i-8] == 'A') &&
       
  1171                        (a[i-7] == 't') &&
       
  1172                        (a[i-6] == 't') &&
       
  1173                        (a[i-5] == 'r') &&
       
  1174                        (a[i-4] == 'i') &&
       
  1175                        (a[i-3] == 'b') &&
       
  1176                        (a[i-2] == 'u') &&
       
  1177                        (a[i-1] == 't') &&
       
  1178                        (a[i] == 'e')) {
       
  1179                 matchlen = 12;
       
  1180                 mask |= GetAttribute;
       
  1181             } else if (i >= 11 && /* getMBeanInfo */
       
  1182                        (a[i-11] == 'g') &&
       
  1183                        (a[i-10] == 'e') &&
       
  1184                        (a[i-9] == 't') &&
       
  1185                        (a[i-8] == 'M') &&
       
  1186                        (a[i-7] == 'B') &&
       
  1187                        (a[i-6] == 'e') &&
       
  1188                        (a[i-5] == 'a') &&
       
  1189                        (a[i-4] == 'n') &&
       
  1190                        (a[i-3] == 'I') &&
       
  1191                        (a[i-2] == 'n') &&
       
  1192                        (a[i-1] == 'f') &&
       
  1193                        (a[i] == 'o')) {
       
  1194                 matchlen = 12;
       
  1195                 mask |= GetMBeanInfo;
       
  1196             } else if (i >= 11 && /* isInstanceOf */
       
  1197                        (a[i-11] == 'i') &&
       
  1198                        (a[i-10] == 's') &&
       
  1199                        (a[i-9] == 'I') &&
       
  1200                        (a[i-8] == 'n') &&
       
  1201                        (a[i-7] == 's') &&
       
  1202                        (a[i-6] == 't') &&
       
  1203                        (a[i-5] == 'a') &&
       
  1204                        (a[i-4] == 'n') &&
       
  1205                        (a[i-3] == 'c') &&
       
  1206                        (a[i-2] == 'e') &&
       
  1207                        (a[i-1] == 'O') &&
       
  1208                        (a[i] == 'f')) {
       
  1209                 matchlen = 12;
       
  1210                 mask |= IsInstanceOf;
       
  1211             } else if (i >= 11 && /* setAttribute */
       
  1212                        (a[i-11] == 's') &&
       
  1213                        (a[i-10] == 'e') &&
       
  1214                        (a[i-9] == 't') &&
       
  1215                        (a[i-8] == 'A') &&
       
  1216                        (a[i-7] == 't') &&
       
  1217                        (a[i-6] == 't') &&
       
  1218                        (a[i-5] == 'r') &&
       
  1219                        (a[i-4] == 'i') &&
       
  1220                        (a[i-3] == 'b') &&
       
  1221                        (a[i-2] == 'u') &&
       
  1222                        (a[i-1] == 't') &&
       
  1223                        (a[i] == 'e')) {
       
  1224                 matchlen = 12;
       
  1225                 mask |= SetAttribute;
       
  1226             } else if (i >= 10 && /* instantiate */
       
  1227                        (a[i-10] == 'i') &&
       
  1228                        (a[i-9] == 'n') &&
       
  1229                        (a[i-8] == 's') &&
       
  1230                        (a[i-7] == 't') &&
       
  1231                        (a[i-6] == 'a') &&
       
  1232                        (a[i-5] == 'n') &&
       
  1233                        (a[i-4] == 't') &&
       
  1234                        (a[i-3] == 'i') &&
       
  1235                        (a[i-2] == 'a') &&
       
  1236                        (a[i-1] == 't') &&
       
  1237                        (a[i] == 'e')) {
       
  1238                 matchlen = 11;
       
  1239                 mask |= Instantiate;
       
  1240             } else if (i >= 10 && /* queryMBeans */
       
  1241                        (a[i-10] == 'q') &&
       
  1242                        (a[i-9] == 'u') &&
       
  1243                        (a[i-8] == 'e') &&
       
  1244                        (a[i-7] == 'r') &&
       
  1245                        (a[i-6] == 'y') &&
       
  1246                        (a[i-5] == 'M') &&
       
  1247                        (a[i-4] == 'B') &&
       
  1248                        (a[i-3] == 'e') &&
       
  1249                        (a[i-2] == 'a') &&
       
  1250                        (a[i-1] == 'n') &&
       
  1251                        (a[i] == 's')) {
       
  1252                 matchlen = 11;
       
  1253                 mask |= QueryMBeans;
       
  1254             } else if (i >= 9 && /* queryNames */
       
  1255                        (a[i-9] == 'q') &&
       
  1256                        (a[i-8] == 'u') &&
       
  1257                        (a[i-7] == 'e') &&
       
  1258                        (a[i-6] == 'r') &&
       
  1259                        (a[i-5] == 'y') &&
       
  1260                        (a[i-4] == 'N') &&
       
  1261                        (a[i-3] == 'a') &&
       
  1262                        (a[i-2] == 'm') &&
       
  1263                        (a[i-1] == 'e') &&
       
  1264                        (a[i] == 's')) {
       
  1265                 matchlen = 10;
       
  1266                 mask |= QueryNames;
       
  1267             } else if (i >= 5 && /* invoke */
       
  1268                        (a[i-5] == 'i') &&
       
  1269                        (a[i-4] == 'n') &&
       
  1270                        (a[i-3] == 'v') &&
       
  1271                        (a[i-2] == 'o') &&
       
  1272                        (a[i-1] == 'k') &&
       
  1273                        (a[i] == 'e')) {
       
  1274                 matchlen = 6;
       
  1275                 mask |= Invoke;
       
  1276             } else {
       
  1277                 // parse error
       
  1278                 throw new IllegalArgumentException("Invalid permission: " +
       
  1279                                                    action);
       
  1280             }
       
  1281 
       
  1282             // make sure we didn't just match the tail of a word
       
  1283             // like "ackbarfaccept".  Also, skip to the comma.
       
  1284             boolean seencomma = false;
       
  1285             while (i >= matchlen && !seencomma) {
       
  1286                 switch(a[i-matchlen]) {
       
  1287                 case ',':
       
  1288                     seencomma = true;
       
  1289                     break;
       
  1290                 case ' ': case '\r': case '\n':
       
  1291                 case '\f': case '\t':
       
  1292                     break;
       
  1293                 default:
       
  1294                     throw new IllegalArgumentException("Invalid permission: " +
       
  1295                                                        action);
       
  1296                 }
       
  1297                 i--;
       
  1298             }
       
  1299 
       
  1300             // point i at the location of the comma minus one (or -1).
       
  1301             i -= matchlen;
       
  1302         }
       
  1303 
       
  1304         return mask;
       
  1305     }
       
  1306 
       
  1307     /**
       
  1308      * <p>Checks if this JMXNamespacePermission object "implies" the
       
  1309      * specified permission.</p>
       
  1310      *
       
  1311      * <p>More specifically, this method returns true if:</p>
       
  1312      *
       
  1313      * <ul>
       
  1314      *
       
  1315      * <li> <i>p</i> is an instance of JMXNamespacePermission; and</li>
       
  1316      *
       
  1317      * <li> <i>p</i> has a null mbeanServerName or <i>p</i>'s mbeanServerName
       
  1318      * matches this object's mbeanServerName; and</li>
       
  1319      *
       
  1320      * <li> <i>p</i> has a null member or <i>p</i>'s member matches this
       
  1321      * object's member; and</li>
       
  1322      *
       
  1323      * <li> <i>p</i> has a null object name or <i>p</i>'s
       
  1324      * object name matches this object's object name; and</li>
       
  1325      *
       
  1326      * <li> <i>p</i>'s actions are a subset of this object's actions</li>
       
  1327      *
       
  1328      * </ul>
       
  1329      *
       
  1330      * <p>If this object's mbeanServerName is a pattern, then <i>p</i>'s
       
  1331      *    mbeanServerName is matched against that pattern. An empty
       
  1332      *    mbeanServerName is equivalent to "{@code *}". A null
       
  1333      *    mbeanServerName is equivalent to "{@code -}".</p>
       
  1334      * <p>If this object's mbeanServerName is "<code>*</code>" or is
       
  1335      * empty, <i>p</i>'s mbeanServerName always matches it.</p>
       
  1336      *
       
  1337      * <p>If this object's member is "<code>*</code>", <i>p</i>'s
       
  1338      * member always matches it.</p>
       
  1339      *
       
  1340      * <p>If this object's objectName <i>n1</i> is an object name pattern,
       
  1341      * <i>p</i>'s objectName <i>n2</i> matches it if
       
  1342      * {@link ObjectName#equals <i>n1</i>.equals(<i>n2</i>)} or if
       
  1343      * {@link ObjectName#apply <i>n1</i>.apply(<i>n2</i>)}.</p>
       
  1344      *
       
  1345      * <p>A permission that includes the <code>queryMBeans</code> action
       
  1346      * is considered to include <code>queryNames</code> as well.</p>
       
  1347      *
       
  1348      * @param p the permission to check against.
       
  1349      * @return true if the specified permission is implied by this object,
       
  1350      * false if not.
       
  1351      */
       
  1352     public boolean implies(Permission p) {
       
  1353         if (!(p instanceof JMXNamespacePermission))
       
  1354             return false;
       
  1355 
       
  1356         JMXNamespacePermission that = (JMXNamespacePermission) p;
       
  1357 
       
  1358         // Actions
       
  1359         //
       
  1360         // The actions in 'this' permission must be a
       
  1361         // superset of the actions in 'that' permission
       
  1362         //
       
  1363 
       
  1364         /* "queryMBeans" implies "queryNames" */
       
  1365         if ((this.mask & QueryMBeans) == QueryMBeans) {
       
  1366             if (((this.mask | QueryNames) & that.mask) != that.mask) {
       
  1367                 //System.out.println("action [with QueryNames] does not imply");
       
  1368                 return false;
       
  1369             }
       
  1370         } else {
       
  1371             if ((this.mask & that.mask) != that.mask) {
       
  1372                 //System.out.println("action does not imply");
       
  1373                 return false;
       
  1374             }
       
  1375         }
       
  1376 
       
  1377         // Target name
       
  1378         //
       
  1379         // The 'mbeanServerName' check is true iff:
       
  1380         // 1) the mbeanServerName in 'this' permission is omitted or "*", or
       
  1381         // 2) the mbeanServerName in 'that' permission is omitted or "*", or
       
  1382         // 3) the mbeanServerName in 'this' permission does pattern
       
  1383         //    matching with the mbeanServerName in 'that' permission.
       
  1384         //
       
  1385         // The 'member' check is true iff:
       
  1386         // 1) the member in 'this' member is omitted or "*", or
       
  1387         // 2) the member in 'that' member is omitted or "*", or
       
  1388         // 3) the member in 'this' permission equals the member in
       
  1389         //    'that' permission.
       
  1390         //
       
  1391         // The 'object name' check is true iff:
       
  1392         // 1) the object name in 'this' permission is omitted, or
       
  1393         // 2) the object name in 'that' permission is omitted, or
       
  1394         // 3) the object name in 'this' permission does pattern
       
  1395         //    matching with the object name in 'that' permission.
       
  1396         //
       
  1397 
       
  1398         if (that.mbeanServerName == null) {
       
  1399             // bottom is implied
       
  1400         } else if (this.mbeanServerName == null) {
       
  1401             // bottom implies nothing but itself
       
  1402             return false;
       
  1403         } else if (that.mbeanServerName.equals(this.mbeanServerName)) {
       
  1404             // exact match
       
  1405         } else if (!Util.wildmatch(that.mbeanServerName,this.mbeanServerName)) {
       
  1406             return false; // no match
       
  1407         }
       
  1408 
       
  1409         /* Check if this.member implies that.member */
       
  1410 
       
  1411         if (that.member == null) {
       
  1412             // bottom is implied
       
  1413         } else if (this.member == null) {
       
  1414             // bottom implies nothing but itself
       
  1415             return false;
       
  1416         } else if (this.member.equals("*")) {
       
  1417             // wildcard implies everything (including itself)
       
  1418         } else if (this.member.equals(that.member)) {
       
  1419             // exact match
       
  1420         } else if (!Util.wildmatch(that.member,this.member)) {
       
  1421             return false; // no match
       
  1422         }
       
  1423 
       
  1424         /* Check if this.objectName implies that.objectName */
       
  1425 
       
  1426         if (that.objectName == null) {
       
  1427             // bottom is implied
       
  1428         } else if (this.objectName == null) {
       
  1429             // bottom implies nothing but itself
       
  1430             if (allnames == false) return false;
       
  1431         } else if (!this.objectName.apply(that.objectName)) {
       
  1432             /* ObjectName.apply returns false if that.objectName is a
       
  1433                wildcard so we also allow equals for that case.  This
       
  1434                never happens during real permission checks, but means
       
  1435                the implies relation is reflexive.  */
       
  1436             if (!this.objectName.equals(that.objectName))
       
  1437                 return false;
       
  1438         }
       
  1439 
       
  1440         return true;
       
  1441     }
       
  1442 
       
  1443     /**
       
  1444      * Checks two JMXNamespacePermission objects for equality. Checks
       
  1445      * that <i>obj</i> is an JMXNamespacePermission, and has the same
       
  1446      * name and actions as this object.
       
  1447      * <P>
       
  1448      * @param obj the object we are testing for equality with this object.
       
  1449      * @return true if obj is an JMXNamespacePermission, and has the
       
  1450      * same name and actions as this JMXNamespacePermission object.
       
  1451      */
       
  1452     public boolean equals(Object obj) {
       
  1453         if (obj == this)
       
  1454             return true;
       
  1455 
       
  1456         if (! (obj instanceof JMXNamespacePermission))
       
  1457             return false;
       
  1458 
       
  1459         JMXNamespacePermission that = (JMXNamespacePermission) obj;
       
  1460 
       
  1461         return (this.mask == that.mask) &&
       
  1462             (this.getName().equals(that.getName()));
       
  1463     }
       
  1464 
       
  1465     /**
       
  1466      * Deserialize this object based on its name and actions.
       
  1467      */
       
  1468     private void readObject(ObjectInputStream in)
       
  1469             throws IOException, ClassNotFoundException {
       
  1470         in.defaultReadObject();
       
  1471         parseName();
       
  1472         parseActions();
       
  1473     }
       
  1474 }