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