1 /*
   2  * Copyright (c) 1997, 2015, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.security;
  27 
  28 import java.util.*;
  29 import java.util.stream.Stream;
  30 import java.util.stream.StreamSupport;
  31 
  32 /**
  33  * Abstract class representing a collection of Permission objects.
  34  *
  35  * <p>With a PermissionCollection, you can:
  36  * <UL>
  37  * <LI> add a permission to the collection using the {@code add} method.
  38  * <LI> check to see if a particular permission is implied in the
  39  *      collection, using the {@code implies} method.
  40  * <LI> enumerate all the permissions, using the {@code elements} method.
  41  * </UL>
  42  *
  43  * <p>When it is desirable to group together a number of Permission objects
  44  * of the same type, the {@code newPermissionCollection} method on that
  45  * particular type of Permission object should first be called. The default
  46  * behavior (from the Permission class) is to simply return null.
  47  * Subclasses of class Permission override the method if they need to store
  48  * their permissions in a particular PermissionCollection object in order
  49  * to provide the correct semantics when the
  50  * {@code PermissionCollection.implies} method is called.
  51  * If a non-null value is returned, that PermissionCollection must be used.
  52  * If null is returned, then the caller of {@code newPermissionCollection}
  53  * is free to store permissions of the
  54  * given type in any PermissionCollection they choose
  55  * (one that uses a Hashtable, one that uses a Vector, etc).
  56  *
  57  * <p>The PermissionCollection returned by the
  58  * {@code Permission.newPermissionCollection}
  59  * method is a homogeneous collection, which stores only Permission objects
  60  * for a given Permission type.  A PermissionCollection may also be
  61  * heterogeneous.  For example, Permissions is a PermissionCollection
  62  * subclass that represents a collection of PermissionCollections.
  63  * That is, its members are each a homogeneous PermissionCollection.
  64  * For example, a Permissions object might have a FilePermissionCollection
  65  * for all the FilePermission objects, a SocketPermissionCollection for all the
  66  * SocketPermission objects, and so on. Its {@code add} method adds a
  67  * permission to the appropriate collection.
  68  *
  69  * <p>Whenever a permission is added to a heterogeneous PermissionCollection
  70  * such as Permissions, and the PermissionCollection doesn't yet contain a
  71  * PermissionCollection of the specified permission's type, the
  72  * PermissionCollection should call
  73  * the {@code newPermissionCollection} method on the permission's class
  74  * to see if it requires a special PermissionCollection. If
  75  * {@code newPermissionCollection}
  76  * returns null, the PermissionCollection
  77  * is free to store the permission in any type of PermissionCollection it
  78  * desires (one using a Hashtable, one using a Vector, etc.). For example,
  79  * the Permissions object uses a default PermissionCollection implementation
  80  * that stores the permission objects in a Hashtable.
  81  *
  82  * <p> Subclass implementations of PermissionCollection should assume
  83  * that they may be called simultaneously from multiple threads,
  84  * and therefore should be synchronized properly.  Furthermore,
  85  * Enumerations returned via the {@code elements} method are
  86  * not <em>fail-fast</em>.  Modifications to a collection should not be
  87  * performed while enumerating over that collection.
  88  *
  89  * @see Permission
  90  * @see Permissions
  91  *
  92  *
  93  * @author Roland Schemers
  94  */
  95 
  96 public abstract class PermissionCollection implements java.io.Serializable {
  97 
  98     private static final long serialVersionUID = -6727011328946861783L;
  99 
 100     // when set, add will throw an exception.
 101     private volatile boolean readOnly;
 102 
 103     /**
 104      * Adds a permission object to the current collection of permission objects.
 105      *
 106      * @param permission the Permission object to add.
 107      *
 108      * @exception SecurityException -  if this PermissionCollection object
 109      *                                 has been marked readonly
 110      * @exception IllegalArgumentException - if this PermissionCollection
 111      *                object is a homogeneous collection and the permission
 112      *                is not of the correct type.
 113      */
 114     public abstract void add(Permission permission);
 115 
 116     /**
 117      * Checks to see if the specified permission is implied by
 118      * the collection of Permission objects held in this PermissionCollection.
 119      *
 120      * @param permission the Permission object to compare.
 121      *
 122      * @return true if "permission" is implied by the  permissions in
 123      * the collection, false if not.
 124      */
 125     public abstract boolean implies(Permission permission);
 126 
 127     /**
 128      * Returns an enumeration of all the Permission objects in the collection.
 129      *
 130      * @return an enumeration of all the Permissions.
 131      * @see #elementsAsStream()
 132      */
 133     public abstract Enumeration<Permission> elements();
 134 
 135     /**
 136      * Returns a stream of all the Permission objects in the collection.
 137      *
 138      * <p> The collection should not be modified (see {@link #add}) during the
 139      * execution of the terminal stream operation. Otherwise, the result of the
 140      * terminal stream operation is undefined.
 141      *
 142      * @implSpec
 143      * The default implementation creates a stream whose source is derived from
 144      * the enumeration returned from a call to {@link #elements()}.
 145      *
 146      * @return a stream of all the Permissions.
 147      * @since 9
 148      */
 149     public Stream<Permission> elementsAsStream() {
 150         int characteristics = isReadOnly()
 151                 ? Spliterator.NONNULL | Spliterator.IMMUTABLE
 152                 : Spliterator.NONNULL;
 153         return StreamSupport.stream(
 154                 Spliterators.spliteratorUnknownSize(
 155                         elements().asIterator(), characteristics),
 156                 false);
 157     }
 158 
 159     /**
 160      * Marks this PermissionCollection object as "readonly". After
 161      * a PermissionCollection object
 162      * is marked as readonly, no new Permission objects can be added to it
 163      * using {@code add}.
 164      */
 165     public void setReadOnly() {
 166         readOnly = true;
 167     }
 168 
 169     /**
 170      * Returns true if this PermissionCollection object is marked as readonly.
 171      * If it is readonly, no new Permission objects can be added to it
 172      * using {@code add}.
 173      *
 174      * <p>By default, the object is <i>not</i> readonly. It can be set to
 175      * readonly by a call to {@code setReadOnly}.
 176      *
 177      * @return true if this PermissionCollection object is marked as readonly,
 178      * false otherwise.
 179      */
 180     public boolean isReadOnly() {
 181         return readOnly;
 182     }
 183 
 184     /**
 185      * Returns a string describing this PermissionCollection object,
 186      * providing information about all the permissions it contains.
 187      * The format is:
 188      * <pre>
 189      * super.toString() (
 190      *   // enumerate all the Permission
 191      *   // objects and call toString() on them,
 192      *   // one per line..
 193      * )</pre>
 194      *
 195      * {@code super.toString} is a call to the {@code toString}
 196      * method of this
 197      * object's superclass, which is Object. The result is
 198      * this PermissionCollection's type name followed by this object's
 199      * hashcode, thus enabling clients to differentiate different
 200      * PermissionCollections object, even if they contain the same permissions.
 201      *
 202      * @return information about this PermissionCollection object,
 203      *         as described above.
 204      *
 205      */
 206     public String toString() {
 207         Enumeration<Permission> enum_ = elements();
 208         StringBuilder sb = new StringBuilder();
 209         sb.append(super.toString()+" (\n");
 210         while (enum_.hasMoreElements()) {
 211             try {
 212                 sb.append(" ");
 213                 sb.append(enum_.nextElement().toString());
 214                 sb.append("\n");
 215             } catch (NoSuchElementException e){
 216                 // ignore
 217             }
 218         }
 219         sb.append(")\n");
 220         return sb.toString();
 221     }
 222 }