Source for javax.management.MBeanServerPermission

   1: /* MBeanServerPermission.java -- Permissions controlling server creation.
   2:    Copyright (C) 2006 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package javax.management;
  39: 
  40: import java.security.BasicPermission;
  41: import java.security.Permission;
  42: import java.security.PermissionCollection;
  43: 
  44: import java.util.Enumeration;
  45: import java.util.NoSuchElementException;
  46: 
  47: /**
  48:  * <p>
  49:  * Represents the permissions required to perform
  50:  * operations provided by the {@link MBeanServerFactory}.
  51:  * As with all {@link java.security.Permission} objects, an
  52:  * instance of this class either represents a permission
  53:  * already held or one that is required to access a
  54:  * particular service.  In the case of {@link MBeanServerPermission}s,
  55:  * implication checks are made using an instance of this class
  56:  * when a user requests an operation from the factory, and a
  57:  * {@link SecurityManager} is in place.
  58:  * </p>
  59:  * <p>
  60:  * The permission is defined by its name, which may be
  61:  * either a <code>'*'</code> (to allow all) or one or
  62:  * more of the following, separated by a <code>','</code>:
  63:  * </p>
  64:  * <ul>
  65:  * <li><code>createMBeanServer</code> -- allows a registered
  66:  * instance of a server to be obtained from the factory.</li>
  67:  * <li><code>findMBeanServer</code> -- allows all or one
  68:  * particular server instance to be retrieved from the factory.</li>
  69:  * <li><code>newMBeanServer</code> -- allows an unregistered
  70:  * instance of a server to be obtained from the factory.</li>
  71:  * <li><code>releaseMBeanServer</code> -- allows a reference to
  72:  * a server instance to be removed from the factory.</li>
  73:  * </ul>
  74:  * <p>
  75:  * The names may be surrounded by arbitrary amounts of whitespace.
  76:  * <code>createMBeanServer</code> implies <code>newMBeanServer</code>.
  77:  * </p>
  78:  *
  79:  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
  80:  * @since 1.5
  81:  */
  82: public class MBeanServerPermission
  83:   extends BasicPermission
  84: {
  85: 
  86:   /**
  87:    * Compatible with JDK 1.5
  88:    */
  89:   private static final long serialVersionUID = -5661980843569388590L;
  90: 
  91:   /**
  92:    * <p>
  93:    * Constructs a new {@link MBeanServerPermission} with
  94:    * the given name.  The name must not be <code>null</code>
  95:    * and must be equal to either <code>"*"</code> or a
  96:    * comma-separated list of valid permissions.  The four
  97:    * valid constraints are:
  98:    * </p>
  99:    * <ol>
 100:    * <li><code>createMBeanServer</code></li>
 101:    * <li><code>findMBeanServer</code></li>
 102:    * <li><code>newMBeanServer</code></li>
 103:    * <li><code>releaseMBeanServer</code></li>
 104:    * </ol>
 105:    * <p>
 106:    * Calling this constructor is equivalent to calling
 107:    * <code>MBeanPermission(name, null)</code>.
 108:    * </p>
 109:    *
 110:    * @param name the name of this permission.
 111:    * @throws NullPointerException if <code>name</code>
 112:    *                              is <code>null</code>.
 113:    * @throws IllegalArgumentException if <code>name</code>
 114:    *                                  is not either equal to
 115:    *                                  <code>"*"</code> or forms
 116:    *                                  a comma-separated list of
 117:    *                                  valid constraints.
 118:    * @see #MBeanServerPermission(String,String)
 119:    */
 120:   public MBeanServerPermission(String name)
 121:   {
 122:     this(name, null);
 123:   }
 124: 
 125:   /**
 126:    * <p>
 127:    * Constructs a new {@link MBeanServerPermission} with
 128:    * the given name and actions.  The actions are unused,
 129:    * and must be either <code>null</code> or the empty
 130:    * string.  The name must not be <code>null</code>
 131:    * and must be equal to either <code>"*"</code> or a
 132:    * comma-separated list of valid permissions.  The four
 133:    * valid constraints are:
 134:    * </p>
 135:    * <ol>
 136:    * <li><code>createMBeanServer</code></li>
 137:    * <li><code>findMBeanServer</code></li>
 138:    * <li><code>newMBeanServer</code></li>
 139:    * <li><code>releaseMBeanServer</code></li>
 140:    * </ol>
 141:    * <p>
 142:    * Calling this constructor is equivalent to calling
 143:    * <code>MBeanPermission(name, null)</code>.
 144:    * </p>
 145:    *
 146:    * @param name the name of this permission.
 147:    * @throws NullPointerException if <code>name</code>
 148:    *                              is <code>null</code>.
 149:    * @throws IllegalArgumentException if <code>name</code>
 150:    *                                  is not either equal to
 151:    *                                  <code>"*"</code> or forms
 152:    *                                  a comma-separated list of
 153:    *                                  valid constraints, or if
 154:    *                                  <code>actions</code> is not
 155:    *                                  <code>null</code> or the
 156:    *                                  empty string.
 157:    * @see #MBeanServerPermission(String,String)
 158:    */
 159:   public MBeanServerPermission(String name, String actions)
 160:   {
 161:     super(checkName(name), actions);
 162:     if (actions != null && actions.length() > 0)
 163:       throw new IllegalArgumentException("The supplied action list " +
 164:                                          "was not equal to null or the " +
 165:                                          "empty string.");
 166:   }
 167: 
 168:   /**
 169:    * Returns true if the given object is also an {@link MBeanServerPermission}
 170:    * with the same name.
 171:    *
 172:    * @param obj the object to compare with this one.
 173:    * @return true if the object is an {@link MBeanPermission}
 174:    *         with the same name.
 175:    */
 176:   public boolean equals(Object obj)
 177:   {
 178:     if (obj instanceof MBeanServerPermission)
 179:       {
 180:         MBeanServerPermission o = (MBeanServerPermission) obj;
 181:         return o.getName().equals(getName());
 182:       }
 183:     return false;
 184:   }
 185: 
 186:   /**
 187:    * Returns a unique hash code for this permission.
 188:    * This is simply the hashcode of {@link BasicPermission#getName()}.
 189:    *
 190:    * @return the hashcode of this permission.
 191:    */
 192:   public int hashCode()
 193:   {
 194:     return getName().hashCode();
 195:   }
 196: 
 197:   /**
 198:    * Returns true if this {@link MBeanServerPermission} implies
 199:    * the given permission.  This occurs if the given permission
 200:    * is also an {@link MBeanServerPermission} and its target names
 201:    * are a subset of the target names of this permission.  Note that
 202:    * the name <code>createMBeanServer</code> implies
 203:    * <code>newMBeanServer</code>.
 204:    *
 205:    * @param p the permission to check for implication.
 206:    * @return true if this permission implies <code>p</code>.
 207:    */
 208:   public boolean implies(Permission p)
 209:   {
 210:     if (p instanceof MBeanServerPermission)
 211:       {
 212:         if (getName().equals("*"))
 213:           return true;
 214:         MBeanServerPermission msp = (MBeanServerPermission) p;
 215:         String[] thisCaps = getName().split(",");
 216:         String[] mspCaps = msp.getName().split(",");
 217:         for (int a = 0; a < mspCaps.length; ++a)
 218:           {
 219:             boolean found = false;
 220:             String mc = mspCaps[a].trim();
 221:             for (int b = 0; b < thisCaps.length; ++b)
 222:               {
 223:                 String tc = thisCaps[b].trim();
 224:                 if (tc.equals(mc))
 225:                   found = true;
 226:                 if (tc.equals("createMBeanServer") &&
 227:                     mc.equals("newMBeanServer"))
 228:                   found = true;
 229:               }
 230:             if (!found)
 231:               return false;
 232:           }
 233:         return true;
 234:       }
 235:     return false;
 236:   }
 237: 
 238:   /**
 239:    * Returns a {@link PermissionCollection} which stores
 240:    * a series of {@link MBeanServerPermission}s as the union
 241:    * of their capabilities.
 242:    *
 243:    * @return a collection for {@link MBeanServerPermission}s.
 244:    */
 245:   public PermissionCollection newPermissionCollection()
 246:   {
 247:     return new MBeanServerPermissionCollection();
 248:   }
 249: 
 250:   /**
 251:    * A collection of {@link MBeanServerPermission}s, stored
 252:    * as a single permission with the union of the capabilities
 253:    * as its capabilities.
 254:    *
 255:    * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 256:    * @since 1.5
 257:    */
 258:   private class MBeanServerPermissionCollection
 259:     extends PermissionCollection
 260:   {
 261: 
 262:     /**
 263:      * Compatible with JDK 1.5
 264:      */
 265:     private static final long serialVersionUID = -5661980843569388590L;
 266: 
 267:     /**
 268:      * The collected permission.  This is <code>null</code> or
 269:      * the union of the permissions held by all the collected
 270:      * permissions.
 271:      */
 272:     private MBeanServerPermission collectionPermission;
 273: 
 274:     /**
 275:      * Adds a new permission by unifying it with the existing
 276:      * collection permission.
 277:      *
 278:      * @param p the permission to add.
 279:      * @throws SecurityException if the collection is read only.
 280:      * @see #isReadOnly()
 281:      * @see #setReadOnly(boolean)
 282:      */
 283:     @Override
 284:     public void add(Permission p)
 285:     {
 286:       if (isReadOnly())
 287:         throw new SecurityException("This collection is read only.");
 288:       if (p instanceof MBeanServerPermission)
 289:         {
 290:           MBeanServerPermission msp = (MBeanServerPermission) p;
 291:           if (collectionPermission == null)
 292:             collectionPermission = msp;
 293:           else
 294:             {
 295:               String finalString = collectionPermission.getName();
 296:               String[] cp = finalString.split(",");
 297:               String[] np = msp.getName().split(",");
 298:               int createms = finalString.indexOf("createMBeanServer");
 299:               int newms = finalString.indexOf("newMBeanServer");
 300:               for (int a = 0; a < np.length; ++a)
 301:                 {
 302:                   boolean found = false;
 303:                   String nps = np[a].trim();
 304:                   for (int b = 0; b < cp.length; ++b)
 305:                     {
 306:                       String cps = cp[b].trim();
 307:                       if (cps.equals(nps))
 308:                         found = true;
 309:                       if (nps.equals("newMBeanServer")
 310:                           && createms != -1)
 311:                         found = true;
 312:                       if (nps.equals("createMBeanServer")
 313:                           && newms != -1)
 314:                         finalString =
 315:                           finalString.replace("newMBeanServer",
 316:                                               "createMBeanServer");
 317:                     }
 318:                   if (!found)
 319:                     finalString += "," + nps;
 320:                 }
 321:               collectionPermission =
 322:                 new MBeanServerPermission(finalString);
 323:             }
 324:         }
 325:     }
 326: 
 327:     /**
 328:      * Returns an enumeration over the single permission.
 329:      *
 330:      * @return an enumeration over the collection permission.
 331:      */
 332:     @Override
 333:     public Enumeration<Permission> elements()
 334:     {
 335:       return new
 336:         MBeanServerPermissionEnumeration(collectionPermission);
 337:     }
 338: 
 339:     /**
 340:      * Provides an enumeration over a comma-separated list
 341:      * of capabilities.
 342:      *
 343:      * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 344:      * @since 1.5
 345:      */
 346:     private class MBeanServerPermissionEnumeration
 347:       implements Enumeration<Permission>
 348:     {
 349: 
 350:       /**
 351:        * The collected permission.
 352:        */
 353:       private MBeanServerPermission p;
 354: 
 355:       /**
 356:        * True if we have returned the permission.
 357:        */
 358:       private boolean done;
 359: 
 360:       /**
 361:        * Constructs a new {@link MBeanServerPermissionEnumeration}
 362:        * using the given collected permission.
 363:        *
 364:        * @param p the collected permission.
 365:        */
 366:       public MBeanServerPermissionEnumeration(MBeanServerPermission p)
 367:       {
 368:         this.p = p;
 369:         done = false;
 370:       }
 371: 
 372:       /**
 373:        * Returns true if there are more capabilities to return.
 374:        *
 375:        * @return true if there are more capabilities available.
 376:        */
 377:       public boolean hasMoreElements()
 378:       {
 379:         return !done;
 380:       }
 381: 
 382:       /**
 383:        * Returns the next capability.
 384:        *
 385:        * @return the next capability.
 386:        */
 387:       public Permission nextElement()
 388:       {
 389:         if (hasMoreElements())
 390:           {
 391:             done = true;
 392:             return p;
 393:           }
 394:         else
 395:           throw new NoSuchElementException("No more elements are available.");
 396:       }
 397: 
 398:     }
 399: 
 400:     /**
 401:      * Returns true if the collected {@link MBeanServerPermission}
 402:      * implies the given permission.  This occurs if the given permission
 403:      * is also an {@link MBeanServerPermission} and its target names
 404:      * are a subset of the target names of this permission.  Note that
 405:      * the name <code>createMBeanServer</code> implies
 406:      * <code>newMBeanServer</code>.
 407:      *
 408:      * @param p the permission to check for implication.
 409:      * @return true if this permission implies <code>p</code>.
 410:      */
 411:     @Override
 412:     public boolean implies(Permission p)
 413:     {
 414:       return collectionPermission.implies(p);
 415:     }
 416:   }
 417: 
 418:   /**
 419:    * Checks the name is valid, including removing
 420:    * the <code>newMBeanServer</code> permission when
 421:    * <code>createMBeanServer</code> is present.
 422:    *
 423:    * @param name the name to check.
 424:    * @throws NullPointerException if <code>name</code>
 425:    *                              is <code>null</code>.
 426:    * @throws IllegalArgumentException if <code>name</code>
 427:    *                                  is not either equal to
 428:    *                                  <code>"*"</code> or forms
 429:    *                                  a comma-separated list of
 430:    *                                  valid constraints.
 431:    */
 432:   private static String checkName(String name)
 433:   {
 434:     if (!(name.equals("*")))
 435:       {
 436:         String[] constraints = name.split(",");
 437:         name = "";
 438:         boolean seenCreate = false;
 439:         boolean seenNew = false;
 440:         boolean start = true;
 441:         for (int a = 0; a < constraints.length; ++a)
 442:           {
 443:             String next = constraints[a].trim();
 444:             if (!(next.equals("createMBeanServer") ||
 445:                   next.equals("findMBeanServer") ||
 446:                   next.equals("newMBeanServer") ||
 447:                   next.equals("releaseMBeanServer")))
 448:               throw new IllegalArgumentException("An invalid constraint, " +
 449:                                                  next + ", was specified.");
 450:             if (next.equals("newMBeanServer"))
 451:               seenNew = true;
 452:             else if (next.equals("createMBeanServer"))
 453:               seenCreate = true;
 454:             else
 455:               {
 456:                 if (!start)
 457:                   name += ",";
 458:                 name += next;
 459:                 start = false;
 460:               }
 461:           }
 462:         if (seenNew && !seenCreate)
 463:           name += (start ? "" : ",") + "newMBeanServer";
 464:         else if (seenCreate)
 465:           name += (start ? "" : ",") + "createMBeanServer";
 466:       }
 467:     return name;
 468:   }
 469: 
 470: }