jdk/src/java.base/share/classes/java/security/Permissions.java
changeset 31080 00a25f4c4d44
parent 30033 b9c86c17164a
child 31538 0981099a3e54
equal deleted inserted replaced
31062:a6b5f444cb68 31080:00a25f4c4d44
    31 import java.util.Map;
    31 import java.util.Map;
    32 import java.util.HashMap;
    32 import java.util.HashMap;
    33 import java.util.List;
    33 import java.util.List;
    34 import java.util.Iterator;
    34 import java.util.Iterator;
    35 import java.util.Collections;
    35 import java.util.Collections;
       
    36 import java.util.concurrent.ConcurrentHashMap;
    36 import java.io.Serializable;
    37 import java.io.Serializable;
    37 import java.io.ObjectStreamField;
    38 import java.io.ObjectStreamField;
    38 import java.io.ObjectOutputStream;
    39 import java.io.ObjectOutputStream;
    39 import java.io.ObjectInputStream;
    40 import java.io.ObjectInputStream;
    40 import java.io.IOException;
    41 import java.io.IOException;
    83 {
    84 {
    84     /**
    85     /**
    85      * Key is permissions Class, value is PermissionCollection for that class.
    86      * Key is permissions Class, value is PermissionCollection for that class.
    86      * Not serialized; see serialization section at end of class.
    87      * Not serialized; see serialization section at end of class.
    87      */
    88      */
    88     private transient Map<Class<?>, PermissionCollection> permsMap;
    89     private transient ConcurrentHashMap<Class<?>, PermissionCollection> permsMap;
    89 
    90 
    90     // optimization. keep track of whether unresolved permissions need to be
    91     // optimization. keep track of whether unresolved permissions need to be
    91     // checked
    92     // checked
    92     private transient boolean hasUnresolved = false;
    93     private transient boolean hasUnresolved = false;
    93 
    94 
    97 
    98 
    98     /**
    99     /**
    99      * Creates a new Permissions object containing no PermissionCollections.
   100      * Creates a new Permissions object containing no PermissionCollections.
   100      */
   101      */
   101     public Permissions() {
   102     public Permissions() {
   102         permsMap = new HashMap<>(11);
   103         permsMap = new ConcurrentHashMap<>(11);
   103         allPermission = null;
   104         allPermission = null;
   104     }
   105     }
   105 
   106 
   106     /**
   107     /**
   107      * Adds a permission object to the PermissionCollection for the class the
   108      * Adds a permission object to the PermissionCollection for the class the
   118      * @exception SecurityException if this Permissions object is
   119      * @exception SecurityException if this Permissions object is
   119      * marked as readonly.
   120      * marked as readonly.
   120      *
   121      *
   121      * @see PermissionCollection#isReadOnly()
   122      * @see PermissionCollection#isReadOnly()
   122      */
   123      */
   123 
   124     @Override
   124     public void add(Permission permission) {
   125     public void add(Permission permission) {
   125         if (isReadOnly())
   126         if (isReadOnly())
   126             throw new SecurityException(
   127             throw new SecurityException(
   127               "attempt to add a Permission to a readonly Permissions object");
   128               "attempt to add a Permission to a readonly Permissions object");
   128 
   129 
   129         PermissionCollection pc;
   130         PermissionCollection pc = getPermissionCollection(permission, true);
   130 
   131         pc.add(permission);
   131         synchronized (this) {
       
   132             pc = getPermissionCollection(permission, true);
       
   133             pc.add(permission);
       
   134         }
       
   135 
   132 
   136         // No sync; staleness -> optimizations delayed, which is OK
   133         // No sync; staleness -> optimizations delayed, which is OK
   137         if (permission instanceof AllPermission) {
   134         if (permission instanceof AllPermission) {
   138             allPermission = pc;
   135             allPermission = pc;
   139         }
   136         }
   167      *
   164      *
   168      * @return true if "permission" is implied by the permissions in the
   165      * @return true if "permission" is implied by the permissions in the
   169      * PermissionCollection it
   166      * PermissionCollection it
   170      * belongs to, false if not.
   167      * belongs to, false if not.
   171      */
   168      */
   172 
   169     @Override
   173     public boolean implies(Permission permission) {
   170     public boolean implies(Permission permission) {
   174         // No sync; staleness -> skip optimization, which is OK
   171         // No sync; staleness -> skip optimization, which is OK
   175         if (allPermission != null) {
   172         if (allPermission != null) {
   176             return true; // AllPermission has already been added
   173             return true; // AllPermission has already been added
   177         } else {
   174         } else {
   178             synchronized (this) {
   175             PermissionCollection pc = getPermissionCollection(permission,
   179                 PermissionCollection pc = getPermissionCollection(permission,
   176                 false);
   180                     false);
   177             if (pc != null) {
   181                 if (pc != null) {
   178                 return pc.implies(permission);
   182                     return pc.implies(permission);
   179             } else {
   183                 } else {
   180                 // none found
   184                     // none found
   181                 return false;
   185                     return false;
       
   186                 }
       
   187             }
   182             }
   188         }
   183         }
   189     }
   184     }
   190 
   185 
   191     /**
   186     /**
   192      * Returns an enumeration of all the Permission objects in all the
   187      * Returns an enumeration of all the Permission objects in all the
   193      * PermissionCollections in this Permissions object.
   188      * PermissionCollections in this Permissions object.
   194      *
   189      *
   195      * @return an enumeration of all the Permissions.
   190      * @return an enumeration of all the Permissions.
   196      */
   191      */
   197 
   192     @Override
   198     public Enumeration<Permission> elements() {
   193     public Enumeration<Permission> elements() {
   199         // go through each Permissions in the hash table
   194         // go through each Permissions in the hash table
   200         // and call their elements() function.
   195         // and call their elements() function.
   201 
   196 
   202         synchronized (this) {
   197         return new PermissionsEnumerator(permsMap.values().iterator());
   203             return new PermissionsEnumerator(permsMap.values().iterator());
       
   204         }
       
   205     }
   198     }
   206 
   199 
   207     /**
   200     /**
   208      * Gets the PermissionCollection in this Permissions object for
   201      * Gets the PermissionCollection in this Permissions object for
   209      * permissions whose type is the same as that of <i>p</i>.
   202      * permissions whose type is the same as that of <i>p</i>.
   234      * implies() because it incurs the additional overhead of creating and
   227      * implies() because it incurs the additional overhead of creating and
   235      * adding an empty PermissionCollection that will just return false.
   228      * adding an empty PermissionCollection that will just return false.
   236      * It should be set to true when invoked from add().
   229      * It should be set to true when invoked from add().
   237      */
   230      */
   238     private PermissionCollection getPermissionCollection(Permission p,
   231     private PermissionCollection getPermissionCollection(Permission p,
   239         boolean createEmpty) {
   232                                                          boolean createEmpty) {
   240         Class<?> c = p.getClass();
   233         Class<?> c = p.getClass();
   241 
   234 
   242         PermissionCollection pc = permsMap.get(c);
       
   243 
       
   244         if (!hasUnresolved && !createEmpty) {
   235         if (!hasUnresolved && !createEmpty) {
   245             return pc;
   236             return permsMap.get(c);
   246         } else if (pc == null) {
   237         }
   247 
   238 
   248             // Check for unresolved permissions
   239         // Create and add permission collection to map if it is absent.
   249             pc = (hasUnresolved ? getUnresolvedPermissions(p) : null);
   240         // NOTE: cannot use lambda for mappingFunction parameter until
   250 
   241         // JDK-8076596 is fixed.
   251             // if still null, create a new collection
   242         return permsMap.computeIfAbsent(c,
   252             if (pc == null && createEmpty) {
   243             new java.util.function.Function<>() {
   253 
   244                 @Override
   254                 pc = p.newPermissionCollection();
   245                 public PermissionCollection apply(Class<?> k) {
   255 
   246                     // Check for unresolved permissions
   256                 // still no PermissionCollection?
   247                     PermissionCollection pc =
   257                 // We'll give them a PermissionsHash.
   248                         (hasUnresolved ? getUnresolvedPermissions(p) : null);
   258                 if (pc == null)
   249 
   259                     pc = new PermissionsHash();
   250                     // if still null, create a new collection
       
   251                     if (pc == null && createEmpty) {
       
   252 
       
   253                         pc = p.newPermissionCollection();
       
   254 
       
   255                         // still no PermissionCollection?
       
   256                         // We'll give them a PermissionsHash.
       
   257                         if (pc == null) {
       
   258                             pc = new PermissionsHash();
       
   259                         }
       
   260                     }
       
   261                     return pc;
       
   262                 }
   260             }
   263             }
   261 
   264         );
   262             if (pc != null) {
       
   263                 permsMap.put(c, pc);
       
   264             }
       
   265         }
       
   266         return pc;
       
   267     }
   265     }
   268 
   266 
   269     /**
   267     /**
   270      * Resolves any unresolved permissions of type p.
   268      * Resolves any unresolved permissions of type p.
   271      *
   269      *
   275      *  or null if there were no unresolved permissions of type p.
   273      *  or null if there were no unresolved permissions of type p.
   276      *
   274      *
   277      */
   275      */
   278     private PermissionCollection getUnresolvedPermissions(Permission p)
   276     private PermissionCollection getUnresolvedPermissions(Permission p)
   279     {
   277     {
   280         // Called from within synchronized method so permsMap doesn't need lock
       
   281 
       
   282         UnresolvedPermissionCollection uc =
   278         UnresolvedPermissionCollection uc =
   283         (UnresolvedPermissionCollection) permsMap.get(UnresolvedPermission.class);
   279         (UnresolvedPermissionCollection) permsMap.get(UnresolvedPermission.class);
   284 
   280 
   285         // we have no unresolved permissions if uc is null
   281         // we have no unresolved permissions if uc is null
   286         if (uc == null)
   282         if (uc == null)
   360         // Don't call out.defaultWriteObject()
   356         // Don't call out.defaultWriteObject()
   361 
   357 
   362         // Copy perms into a Hashtable
   358         // Copy perms into a Hashtable
   363         Hashtable<Class<?>, PermissionCollection> perms =
   359         Hashtable<Class<?>, PermissionCollection> perms =
   364             new Hashtable<>(permsMap.size()*2); // no sync; estimate
   360             new Hashtable<>(permsMap.size()*2); // no sync; estimate
   365         synchronized (this) {
   361         perms.putAll(permsMap);
   366             perms.putAll(permsMap);
       
   367         }
       
   368 
   362 
   369         // Write out serializable fields
   363         // Write out serializable fields
   370         ObjectOutputStream.PutField pfields = out.putFields();
   364         ObjectOutputStream.PutField pfields = out.putFields();
   371 
   365 
   372         pfields.put("allPermission", allPermission); // no sync; staleness OK
   366         pfields.put("allPermission", allPermission); // no sync; staleness OK
   392         // writeObject writes a Hashtable<Class<?>, PermissionCollection> for
   386         // writeObject writes a Hashtable<Class<?>, PermissionCollection> for
   393         // the perms key, so this cast is safe, unless the data is corrupt.
   387         // the perms key, so this cast is safe, unless the data is corrupt.
   394         @SuppressWarnings("unchecked")
   388         @SuppressWarnings("unchecked")
   395         Hashtable<Class<?>, PermissionCollection> perms =
   389         Hashtable<Class<?>, PermissionCollection> perms =
   396             (Hashtable<Class<?>, PermissionCollection>)gfields.get("perms", null);
   390             (Hashtable<Class<?>, PermissionCollection>)gfields.get("perms", null);
   397         permsMap = new HashMap<>(perms.size()*2);
   391         permsMap = new ConcurrentHashMap<>(perms.size()*2);
   398         permsMap.putAll(perms);
   392         permsMap.putAll(perms);
   399 
   393 
   400         // Set hasUnresolved
   394         // Set hasUnresolved
   401         UnresolvedPermissionCollection uc =
   395         UnresolvedPermissionCollection uc =
   402         (UnresolvedPermissionCollection) permsMap.get(UnresolvedPermission.class);
   396         (UnresolvedPermissionCollection) permsMap.get(UnresolvedPermission.class);
   479 {
   473 {
   480     /**
   474     /**
   481      * Key and value are (same) permissions objects.
   475      * Key and value are (same) permissions objects.
   482      * Not serialized; see serialization section at end of class.
   476      * Not serialized; see serialization section at end of class.
   483      */
   477      */
   484     private transient Map<Permission, Permission> permsMap;
   478     private transient ConcurrentHashMap<Permission, Permission> permsMap;
   485 
   479 
   486     /**
   480     /**
   487      * Create an empty PermissionsHash object.
   481      * Create an empty PermissionsHash object.
   488      */
   482      */
   489 
       
   490     PermissionsHash() {
   483     PermissionsHash() {
   491         permsMap = new HashMap<>(11);
   484         permsMap = new ConcurrentHashMap<>(11);
   492     }
   485     }
   493 
   486 
   494     /**
   487     /**
   495      * Adds a permission to the PermissionsHash.
   488      * Adds a permission to the PermissionsHash.
   496      *
   489      *
   497      * @param permission the Permission object to add.
   490      * @param permission the Permission object to add.
   498      */
   491      */
   499 
   492     @Override
   500     public void add(Permission permission) {
   493     public void add(Permission permission) {
   501         synchronized (this) {
   494         permsMap.put(permission, permission);
   502             permsMap.put(permission, permission);
       
   503         }
       
   504     }
   495     }
   505 
   496 
   506     /**
   497     /**
   507      * Check and see if this set of permissions implies the permissions
   498      * Check and see if this set of permissions implies the permissions
   508      * expressed in "permission".
   499      * expressed in "permission".
   510      * @param permission the Permission object to compare
   501      * @param permission the Permission object to compare
   511      *
   502      *
   512      * @return true if "permission" is a proper subset of a permission in
   503      * @return true if "permission" is a proper subset of a permission in
   513      * the set, false if not.
   504      * the set, false if not.
   514      */
   505      */
   515 
   506     @Override
   516     public boolean implies(Permission permission) {
   507     public boolean implies(Permission permission) {
   517         // attempt a fast lookup and implies. If that fails
   508         // attempt a fast lookup and implies. If that fails
   518         // then enumerate through all the permissions.
   509         // then enumerate through all the permissions.
   519         synchronized (this) {
   510         Permission p = permsMap.get(permission);
   520             Permission p = permsMap.get(permission);
   511 
   521 
   512         // If permission is found, then p.equals(permission)
   522             // If permission is found, then p.equals(permission)
   513         if (p == null) {
   523             if (p == null) {
   514             for (Permission p_ : permsMap.values()) {
   524                 for (Permission p_ : permsMap.values()) {
   515                 if (p_.implies(permission))
   525                     if (p_.implies(permission))
   516                     return true;
   526                         return true;
       
   527                 }
       
   528                 return false;
       
   529             } else {
       
   530                 return true;
       
   531             }
   517             }
       
   518             return false;
       
   519         } else {
       
   520             return true;
   532         }
   521         }
   533     }
   522     }
   534 
   523 
   535     /**
   524     /**
   536      * Returns an enumeration of all the Permission objects in the container.
   525      * Returns an enumeration of all the Permission objects in the container.
   537      *
   526      *
   538      * @return an enumeration of all the Permissions.
   527      * @return an enumeration of all the Permissions.
   539      */
   528      */
   540 
   529     @Override
   541     public Enumeration<Permission> elements() {
   530     public Enumeration<Permission> elements() {
   542         // Convert Iterator of Map values into an Enumeration
   531         return permsMap.elements();
   543         synchronized (this) {
       
   544             return Collections.enumeration(permsMap.values());
       
   545         }
       
   546     }
   532     }
   547 
   533 
   548     private static final long serialVersionUID = -8491988220802933440L;
   534     private static final long serialVersionUID = -8491988220802933440L;
   549     // Need to maintain serialization interoperability with earlier releases,
   535     // Need to maintain serialization interoperability with earlier releases,
   550     // which had the serializable field:
   536     // which had the serializable field:
   568         // Don't call out.defaultWriteObject()
   554         // Don't call out.defaultWriteObject()
   569 
   555 
   570         // Copy perms into a Hashtable
   556         // Copy perms into a Hashtable
   571         Hashtable<Permission, Permission> perms =
   557         Hashtable<Permission, Permission> perms =
   572                 new Hashtable<>(permsMap.size()*2);
   558                 new Hashtable<>(permsMap.size()*2);
   573         synchronized (this) {
   559         perms.putAll(permsMap);
   574             perms.putAll(permsMap);
       
   575         }
       
   576 
   560 
   577         // Write out serializable fields
   561         // Write out serializable fields
   578         ObjectOutputStream.PutField pfields = out.putFields();
   562         ObjectOutputStream.PutField pfields = out.putFields();
   579         pfields.put("perms", perms);
   563         pfields.put("perms", perms);
   580         out.writeFields();
   564         out.writeFields();
   595         // writeObject writes a Hashtable<Class<?>, PermissionCollection> for
   579         // writeObject writes a Hashtable<Class<?>, PermissionCollection> for
   596         // the perms key, so this cast is safe, unless the data is corrupt.
   580         // the perms key, so this cast is safe, unless the data is corrupt.
   597         @SuppressWarnings("unchecked")
   581         @SuppressWarnings("unchecked")
   598         Hashtable<Permission, Permission> perms =
   582         Hashtable<Permission, Permission> perms =
   599                 (Hashtable<Permission, Permission>)gfields.get("perms", null);
   583                 (Hashtable<Permission, Permission>)gfields.get("perms", null);
   600         permsMap = new HashMap<>(perms.size()*2);
   584         permsMap = new ConcurrentHashMap<>(perms.size()*2);
   601         permsMap.putAll(perms);
   585         permsMap.putAll(perms);
   602     }
   586     }
   603 }
   587 }