1 /*
   2  * Copyright (c) 1997, 2019, 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  * @since 1.2
  95  */
  96 
  97 public abstract class PermissionCollection implements java.io.Serializable {
  98 
  99     @java.io.Serial
 100     private static final long serialVersionUID = -6727011328946861783L;
 101 
 102     // when set, add will throw an exception.
 103     private volatile boolean readOnly;
 104 
 105     /**
 106      * Adds a permission object to the current collection of permission objects.
 107      *
 108      * @param permission the Permission object to add.
 109      *
 110      * @throws    SecurityException -  if this PermissionCollection object
 111      *                                 has been marked readonly
 112      * @throws    IllegalArgumentException - if this PermissionCollection
 113      *                object is a homogeneous collection and the permission
 114      *                is not of the correct type.
 115      */
 116     public abstract void add(Permission permission);
 117 
 118     /**
 119      * Checks to see if the specified permission is implied by
 120      * the collection of Permission objects held in this PermissionCollection.
 121      *
 122      * @param permission the Permission object to compare.
 123      *
 124      * @return true if "permission" is implied by the  permissions in
 125      * the collection, false if not.
 126      */
 127     public abstract boolean implies(Permission permission);
 128 
 129     /**
 130      * Returns an enumeration of all the Permission objects in the collection.
 131      *
 132      * @return an enumeration of all the Permissions.
 133      * @see #elementsAsStream()
 134      */
 135     public abstract Enumeration<Permission> elements();
 136 
 137     /**
 138      * Returns a stream of all the Permission objects in the collection.
 139      *
 140      * <p> The collection should not be modified (see {@link #add}) during the
 141      * execution of the terminal stream operation. Otherwise, the result of the
 142      * terminal stream operation is undefined.
 143      *
 144      * @implSpec
 145      * The default implementation creates a stream whose source is derived from
 146      * the enumeration returned from a call to {@link #elements()}.
 147      *
 148      * @return a stream of all the Permissions.
 149      * @since 9
 150      */
 151     public Stream<Permission> elementsAsStream() {
 152         int characteristics = isReadOnly()
 153                 ? Spliterator.NONNULL | Spliterator.IMMUTABLE
 154                 : Spliterator.NONNULL;
 155         return StreamSupport.stream(
 156                 Spliterators.spliteratorUnknownSize(
 157                         elements().asIterator(), characteristics),
 158                 false);
 159     }
 160 
 161     /**
 162      * Marks this PermissionCollection object as "readonly". After
 163      * a PermissionCollection object
 164      * is marked as readonly, no new Permission objects can be added to it
 165      * using {@code add}.
 166      */
 167     public void setReadOnly() {
 168         readOnly = true;
 169     }
 170 
 171     /**
 172      * Returns true if this PermissionCollection object is marked as readonly.
 173      * If it is readonly, no new Permission objects can be added to it
 174      * using {@code add}.
 175      *
 176      * <p>By default, the object is <i>not</i> readonly. It can be set to
 177      * readonly by a call to {@code setReadOnly}.
 178      *
 179      * @return true if this PermissionCollection object is marked as readonly,
 180      * false otherwise.
 181      */
 182     public boolean isReadOnly() {
 183         return readOnly;
 184     }
 185 
 186     /**
 187      * Returns a string describing this PermissionCollection object,
 188      * providing information about all the permissions it contains.
 189      * The format is:
 190      * <pre>
 191      * super.toString() (
 192      *   // enumerate all the Permission
 193      *   // objects and call toString() on them,
 194      *   // one per line..
 195      * )</pre>
 196      *
 197      * {@code super.toString} is a call to the {@code toString}
 198      * method of this
 199      * object's superclass, which is Object. The result is
 200      * this PermissionCollection's type name followed by this object's
 201      * hashcode, thus enabling clients to differentiate different
 202      * PermissionCollections object, even if they contain the same permissions.
 203      *
 204      * @return information about this PermissionCollection object,
 205      *         as described above.
 206      *
 207      */
 208     public String toString() {
 209         Enumeration<Permission> enum_ = elements();
 210         StringBuilder sb = new StringBuilder();
 211         sb.append(super.toString()+" (\n");
 212         while (enum_.hasMoreElements()) {
 213             try {
 214                 sb.append(" ");
 215                 sb.append(enum_.nextElement().toString());
 216                 sb.append("\n");
 217             } catch (NoSuchElementException e){
 218                 // ignore
 219             }
 220         }
 221         sb.append(")\n");
 222         return sb.toString();
 223     }
 224 }