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