1 /*
   2  * Copyright (c) 1997, 2009, 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 
  27 package java.security;
  28 
  29 import java.io.*;
  30 import java.lang.RuntimePermission;
  31 import java.lang.reflect.*;
  32 import java.net.MalformedURLException;
  33 import java.net.URL;
  34 import java.util.Enumeration;
  35 import java.util.Hashtable;
  36 import java.util.PropertyPermission;
  37 import java.util.StringTokenizer;
  38 import java.util.Vector;
  39 import java.util.WeakHashMap;
  40 import sun.security.jca.GetInstance;
  41 import sun.security.util.Debug;
  42 import sun.security.util.SecurityConstants;
  43 
  44 /**
  45  * A Policy object is responsible for determining whether code executing
  46  * in the Java runtime environment has permission to perform a
  47  * security-sensitive operation.
  48  *
  49  * <p> There is only one Policy object installed in the runtime at any
  50  * given time.  A Policy object can be installed by calling the
  51  * <code>setPolicy</code> method.  The installed Policy object can be
  52  * obtained by calling the <code>getPolicy</code> method.
  53  *
  54  * <p> If no Policy object has been installed in the runtime, a call to
  55  * <code>getPolicy</code> installs an instance of the default Policy
  56  * implementation (a default subclass implementation of this abstract class).
  57  * The default Policy implementation can be changed by setting the value
  58  * of the "policy.provider" security property (in the Java security properties
  59  * file) to the fully qualified name of the desired Policy subclass
  60  * implementation.  The Java security properties file is located in the
  61  * file named &lt;JAVA_HOME&gt;/lib/security/java.security.
  62  * &lt;JAVA_HOME&gt; refers to the value of the java.home system property,
  63  * and specifies the directory where the JRE is installed.
  64  *
  65  * <p> Application code can directly subclass Policy to provide a custom
  66  * implementation.  In addition, an instance of a Policy object can be
  67  * constructed by invoking one of the <code>getInstance</code> factory methods
  68  * with a standard type.  The default policy type is "JavaPolicy".
  69  * See Appendix A in the <a href="../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
  70  * Java Cryptography Architecture API Specification &amp; Reference </a>
  71  * for a list of standard Policy types.
  72  *
  73  * <p> Once a Policy instance has been installed (either by default, or by
  74  * calling <code>setPolicy</code>),
  75  * the Java runtime invokes its <code>implies</code> when it needs to
  76  * determine whether executing code (encapsulated in a ProtectionDomain)
  77  * can perform SecurityManager-protected operations.  How a Policy object
  78  * retrieves its policy data is up to the Policy implementation itself.
  79  * The policy data may be stored, for example, in a flat ASCII file,
  80  * in a serialized binary file of the Policy class, or in a database.
  81  *
  82  * <p> The <code>refresh</code> method causes the policy object to
  83  * refresh/reload its data.  This operation is implementation-dependent.
  84  * For example, if the policy object stores its data in configuration files,
  85  * calling <code>refresh</code> will cause it to re-read the configuration
  86  * policy files.  If a refresh operation is not supported, this method does
  87  * nothing.  Note that refreshed policy may not have an effect on classes
  88  * in a particular ProtectionDomain. This is dependent on the Policy
  89  * provider's implementation of the <code>implies</code>
  90  * method and its PermissionCollection caching strategy.
  91  *
  92  * @author Roland Schemers
  93  * @author Gary Ellison
  94  * @see java.security.Provider
  95  * @see java.security.ProtectionDomain
  96  * @see java.security.Permission
  97  */
  98 
  99 public abstract class Policy {
 100 
 101     /**
 102      * A read-only empty PermissionCollection instance.
 103      * @since 1.6
 104      */
 105     public static final PermissionCollection UNSUPPORTED_EMPTY_COLLECTION =
 106                         new UnsupportedEmptyCollection();
 107 
 108     /** the system-wide policy. */
 109     private static Policy policy; // package private for AccessControlContext
 110 
 111     private static final Debug debug = Debug.getInstance("policy");
 112 
 113     // Cache mapping ProtectionDomain.Key to PermissionCollection
 114     private WeakHashMap<ProtectionDomain.Key, PermissionCollection> pdMapping;
 115 
 116     /** package private for AccessControlContext */
 117     static boolean isSet()
 118     {
 119         return policy != null;
 120     }
 121 
 122     private static void checkPermission(String type) {
 123         SecurityManager sm = System.getSecurityManager();
 124         if (sm != null) {
 125             sm.checkPermission(new SecurityPermission("createPolicy." + type));
 126         }
 127     }
 128 
 129     /**
 130      * Returns the installed Policy object. This value should not be cached,
 131      * as it may be changed by a call to <code>setPolicy</code>.
 132      * This method first calls
 133      * <code>SecurityManager.checkPermission</code> with a
 134      * <code>SecurityPermission("getPolicy")</code> permission
 135      * to ensure it's ok to get the Policy object..
 136      *
 137      * @return the installed Policy.
 138      *
 139      * @throws SecurityException
 140      *        if a security manager exists and its
 141      *        <code>checkPermission</code> method doesn't allow
 142      *        getting the Policy object.
 143      *
 144      * @see SecurityManager#checkPermission(Permission)
 145      * @see #setPolicy(java.security.Policy)
 146      */
 147     public static Policy getPolicy()
 148     {
 149         SecurityManager sm = System.getSecurityManager();
 150         if (sm != null)
 151             sm.checkPermission(SecurityConstants.GET_POLICY_PERMISSION);
 152         return getPolicyNoCheck();
 153     }
 154 
 155     /**
 156      * Returns the installed Policy object, skipping the security check.
 157      * Used by SecureClassLoader and getPolicy.
 158      *
 159      * @return the installed Policy.
 160      *
 161      */
 162     static synchronized Policy getPolicyNoCheck()
 163     {
 164         if (policy == null) {
 165             String policy_class = null;
 166             policy_class = AccessController.doPrivileged(
 167                 new PrivilegedAction<String>() {
 168                     public String run() {
 169                         return Security.getProperty("policy.provider");
 170                     }
 171                 });
 172             if (policy_class == null) {
 173                 policy_class = "sun.security.provider.PolicyFile";
 174             }
 175 
 176             try {
 177                 policy = (Policy)
 178                     Class.forName(policy_class).newInstance();
 179             } catch (Exception e) {
 180                 /*
 181                  * The policy_class seems to be an extension
 182                  * so we have to bootstrap loading it via a policy
 183                  * provider that is on the bootclasspath
 184                  * If it loads then shift gears to using the configured
 185                  * provider.
 186                  */
 187 
 188                 // install the bootstrap provider to avoid recursion
 189                 policy = new sun.security.provider.PolicyFile();
 190 
 191                 final String pc = policy_class;
 192                 Policy p = AccessController.doPrivileged(
 193                     new PrivilegedAction<Policy>() {
 194                         public Policy run() {
 195                             try {
 196                                 ClassLoader cl =
 197                                         ClassLoader.getSystemClassLoader();
 198                                 // we want the extension loader
 199                                 ClassLoader extcl = null;
 200                                 while (cl != null) {
 201                                     extcl = cl;
 202                                     cl = cl.getParent();
 203                                 }
 204                                 return (extcl != null ? (Policy)Class.forName(
 205                                         pc, true, extcl).newInstance() : null);
 206                             } catch (Exception e) {
 207                                 if (debug != null) {
 208                                     debug.println("policy provider " +
 209                                                 pc +
 210                                                 " not available");
 211                                     e.printStackTrace();
 212                                 }
 213                                 return null;
 214                             }
 215                         }
 216                     });
 217                 /*
 218                  * if it loaded install it as the policy provider. Otherwise
 219                  * continue to use the system default implementation
 220                  */
 221                 if (p != null) {
 222                     policy = p;
 223                 } else {
 224                     if (debug != null) {
 225                         debug.println("using sun.security.provider.PolicyFile");
 226                     }
 227                 }
 228             }
 229         }
 230         return policy;
 231     }
 232 
 233     /**
 234      * Sets the system-wide Policy object. This method first calls
 235      * <code>SecurityManager.checkPermission</code> with a
 236      * <code>SecurityPermission("setPolicy")</code>
 237      * permission to ensure it's ok to set the Policy.
 238      *
 239      * @param p the new system Policy object.
 240      *
 241      * @throws SecurityException
 242      *        if a security manager exists and its
 243      *        <code>checkPermission</code> method doesn't allow
 244      *        setting the Policy.
 245      *
 246      * @see SecurityManager#checkPermission(Permission)
 247      * @see #getPolicy()
 248      *
 249      */
 250     public static void setPolicy(Policy p)
 251     {
 252         SecurityManager sm = System.getSecurityManager();
 253         if (sm != null) sm.checkPermission(
 254                                  new SecurityPermission("setPolicy"));
 255         if (p != null) {
 256             initPolicy(p);
 257         }
 258         synchronized (Policy.class) {
 259             Policy.policy = p;
 260         }
 261     }
 262 
 263     /**
 264      * Initialize superclass state such that a legacy provider can
 265      * handle queries for itself.
 266      *
 267      * @since 1.4
 268      */
 269     private static void initPolicy (final Policy p) {
 270         /*
 271          * A policy provider not on the bootclasspath could trigger
 272          * security checks fulfilling a call to either Policy.implies
 273          * or Policy.getPermissions. If this does occur the provider
 274          * must be able to answer for it's own ProtectionDomain
 275          * without triggering additional security checks, otherwise
 276          * the policy implementation will end up in an infinite
 277          * recursion.
 278          *
 279          * To mitigate this, the provider can collect it's own
 280          * ProtectionDomain and associate a PermissionCollection while
 281          * it is being installed. The currently installed policy
 282          * provider (if there is one) will handle calls to
 283          * Policy.implies or Policy.getPermissions during this
 284          * process.
 285          *
 286          * This Policy superclass caches away the ProtectionDomain and
 287          * statically binds permissions so that legacy Policy
 288          * implementations will continue to function.
 289          */
 290 
 291         ProtectionDomain policyDomain =
 292         AccessController.doPrivileged(new PrivilegedAction<ProtectionDomain>() {
 293             public ProtectionDomain run() {
 294                 return p.getClass().getProtectionDomain();
 295             }
 296         });
 297 
 298         /*
 299          * Collect the permissions granted to this protection domain
 300          * so that the provider can be security checked while processing
 301          * calls to Policy.implies or Policy.getPermissions.
 302          */
 303         PermissionCollection policyPerms = null;
 304         synchronized (p) {
 305             if (p.pdMapping == null) {
 306                 p.pdMapping =
 307                     new WeakHashMap<ProtectionDomain.Key, PermissionCollection>();
 308            }
 309         }
 310 
 311         if (policyDomain.getCodeSource() != null) {
 312             if (Policy.isSet()) {
 313                 policyPerms = policy.getPermissions(policyDomain);
 314             }
 315 
 316             if (policyPerms == null) { // assume it has all
 317                 policyPerms = new Permissions();
 318                 policyPerms.add(SecurityConstants.ALL_PERMISSION);
 319             }
 320 
 321             synchronized (p.pdMapping) {
 322                 // cache of pd to permissions
 323                 p.pdMapping.put(policyDomain.key, policyPerms);
 324             }
 325         }
 326         return;
 327     }
 328 
 329 
 330     /**
 331      * Returns a Policy object of the specified type.
 332      *
 333      * <p> This method traverses the list of registered security providers,
 334      * starting with the most preferred Provider.
 335      * A new Policy object encapsulating the
 336      * PolicySpi implementation from the first
 337      * Provider that supports the specified type is returned.
 338      *
 339      * <p> Note that the list of registered providers may be retrieved via
 340      * the {@link Security#getProviders() Security.getProviders()} method.
 341      *
 342      * @param type the specified Policy type.  See Appendix A in the
 343      *    <a href="../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
 344      *    Java Cryptography Architecture API Specification &amp; Reference </a>
 345      *    for a list of standard Policy types.
 346      *
 347      * @param params parameters for the Policy, which may be null.
 348      *
 349      * @return the new Policy object.
 350      *
 351      * @exception SecurityException if the caller does not have permission
 352      *          to get a Policy instance for the specified type.
 353      *
 354      * @exception NullPointerException if the specified type is null.
 355      *
 356      * @exception IllegalArgumentException if the specified parameters
 357      *          are not understood by the PolicySpi implementation
 358      *          from the selected Provider.
 359      *
 360      * @exception NoSuchAlgorithmException if no Provider supports a PolicySpi
 361      *          implementation for the specified type.
 362      *
 363      * @see Provider
 364      * @since 1.6
 365      */
 366     public static Policy getInstance(String type, Policy.Parameters params)
 367                 throws NoSuchAlgorithmException {
 368 
 369         checkPermission(type);
 370         try {
 371             GetInstance.Instance instance = GetInstance.getInstance("Policy",
 372                                                         PolicySpi.class,
 373                                                         type,
 374                                                         params);
 375             return new PolicyDelegate((PolicySpi)instance.impl,
 376                                                         instance.provider,
 377                                                         type,
 378                                                         params);
 379         } catch (NoSuchAlgorithmException nsae) {
 380             return handleException(nsae);
 381         }
 382     }
 383 
 384     /**
 385      * Returns a Policy object of the specified type.
 386      *
 387      * <p> A new Policy object encapsulating the
 388      * PolicySpi implementation from the specified provider
 389      * is returned.   The specified provider must be registered
 390      * in the provider list.
 391      *
 392      * <p> Note that the list of registered providers may be retrieved via
 393      * the {@link Security#getProviders() Security.getProviders()} method.
 394      *
 395      * @param type the specified Policy type.  See Appendix A in the
 396      *    <a href="../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
 397      *    Java Cryptography Architecture API Specification &amp; Reference </a>
 398      *    for a list of standard Policy types.
 399      *
 400      * @param params parameters for the Policy, which may be null.
 401      *
 402      * @param provider the provider.
 403      *
 404      * @return the new Policy object.
 405      *
 406      * @exception SecurityException if the caller does not have permission
 407      *          to get a Policy instance for the specified type.
 408      *
 409      * @exception NullPointerException if the specified type is null.
 410      *
 411      * @exception IllegalArgumentException if the specified provider
 412      *          is null or empty,
 413      *          or if the specified parameters are not understood by
 414      *          the PolicySpi implementation from the specified provider.
 415      *
 416      * @exception NoSuchProviderException if the specified provider is not
 417      *          registered in the security provider list.
 418      *
 419      * @exception NoSuchAlgorithmException if the specified provider does not
 420      *          support a PolicySpi implementation for the specified type.
 421      *
 422      * @see Provider
 423      * @since 1.6
 424      */
 425     public static Policy getInstance(String type,
 426                                 Policy.Parameters params,
 427                                 String provider)
 428                 throws NoSuchProviderException, NoSuchAlgorithmException {
 429 
 430         if (provider == null || provider.length() == 0) {
 431             throw new IllegalArgumentException("missing provider");
 432         }
 433 
 434         checkPermission(type);
 435         try {
 436             GetInstance.Instance instance = GetInstance.getInstance("Policy",
 437                                                         PolicySpi.class,
 438                                                         type,
 439                                                         params,
 440                                                         provider);
 441             return new PolicyDelegate((PolicySpi)instance.impl,
 442                                                         instance.provider,
 443                                                         type,
 444                                                         params);
 445         } catch (NoSuchAlgorithmException nsae) {
 446             return handleException (nsae);
 447         }
 448     }
 449 
 450     /**
 451      * Returns a Policy object of the specified type.
 452      *
 453      * <p> A new Policy object encapsulating the
 454      * PolicySpi implementation from the specified Provider
 455      * object is returned.  Note that the specified Provider object
 456      * does not have to be registered in the provider list.
 457      *
 458      * @param type the specified Policy type.  See Appendix A in the
 459      *    <a href="../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
 460      *    Java Cryptography Architecture API Specification &amp; Reference </a>
 461      *    for a list of standard Policy types.
 462      *
 463      * @param params parameters for the Policy, which may be null.
 464      *
 465      * @param provider the Provider.
 466      *
 467      * @return the new Policy object.
 468      *
 469      * @exception SecurityException if the caller does not have permission
 470      *          to get a Policy instance for the specified type.
 471      *
 472      * @exception NullPointerException if the specified type is null.
 473      *
 474      * @exception IllegalArgumentException if the specified Provider is null,
 475      *          or if the specified parameters are not understood by
 476      *          the PolicySpi implementation from the specified Provider.
 477      *
 478      * @exception NoSuchAlgorithmException if the specified Provider does not
 479      *          support a PolicySpi implementation for the specified type.
 480      *
 481      * @see Provider
 482      * @since 1.6
 483      */
 484     public static Policy getInstance(String type,
 485                                 Policy.Parameters params,
 486                                 Provider provider)
 487                 throws NoSuchAlgorithmException {
 488 
 489         if (provider == null) {
 490             throw new IllegalArgumentException("missing provider");
 491         }
 492 
 493         checkPermission(type);
 494         try {
 495             GetInstance.Instance instance = GetInstance.getInstance("Policy",
 496                                                         PolicySpi.class,
 497                                                         type,
 498                                                         params,
 499                                                         provider);
 500             return new PolicyDelegate((PolicySpi)instance.impl,
 501                                                         instance.provider,
 502                                                         type,
 503                                                         params);
 504         } catch (NoSuchAlgorithmException nsae) {
 505             return handleException (nsae);
 506         }
 507     }
 508 
 509     private static Policy handleException(NoSuchAlgorithmException nsae)
 510                 throws NoSuchAlgorithmException {
 511         Throwable cause = nsae.getCause();
 512         if (cause instanceof IllegalArgumentException) {
 513             throw (IllegalArgumentException)cause;
 514         }
 515         throw nsae;
 516     }
 517 
 518     /**
 519      * Return the Provider of this Policy.
 520      *
 521      * <p> This Policy instance will only have a Provider if it
 522      * was obtained via a call to <code>Policy.getInstance</code>.
 523      * Otherwise this method returns null.
 524      *
 525      * @return the Provider of this Policy, or null.
 526      *
 527      * @since 1.6
 528      */
 529     public Provider getProvider() {
 530         return null;
 531     }
 532 
 533     /**
 534      * Return the type of this Policy.
 535      *
 536      * <p> This Policy instance will only have a type if it
 537      * was obtained via a call to <code>Policy.getInstance</code>.
 538      * Otherwise this method returns null.
 539      *
 540      * @return the type of this Policy, or null.
 541      *
 542      * @since 1.6
 543      */
 544     public String getType() {
 545         return null;
 546     }
 547 
 548     /**
 549      * Return Policy parameters.
 550      *
 551      * <p> This Policy instance will only have parameters if it
 552      * was obtained via a call to <code>Policy.getInstance</code>.
 553      * Otherwise this method returns null.
 554      *
 555      * @return Policy parameters, or null.
 556      *
 557      * @since 1.6
 558      */
 559     public Policy.Parameters getParameters() {
 560         return null;
 561     }
 562 
 563     /**
 564      * Return a PermissionCollection object containing the set of
 565      * permissions granted to the specified CodeSource.
 566      *
 567      * <p> Applications are discouraged from calling this method
 568      * since this operation may not be supported by all policy implementations.
 569      * Applications should solely rely on the <code>implies</code> method
 570      * to perform policy checks.  If an application absolutely must call
 571      * a getPermissions method, it should call
 572      * <code>getPermissions(ProtectionDomain)</code>.
 573      *
 574      * <p> The default implementation of this method returns
 575      * Policy.UNSUPPORTED_EMPTY_COLLECTION.  This method can be
 576      * overridden if the policy implementation can return a set of
 577      * permissions granted to a CodeSource.
 578      *
 579      * @param codesource the CodeSource to which the returned
 580      *          PermissionCollection has been granted.
 581      *
 582      * @return a set of permissions granted to the specified CodeSource.
 583      *          If this operation is supported, the returned
 584      *          set of permissions must be a new mutable instance
 585      *          and it must support heterogeneous Permission types.
 586      *          If this operation is not supported,
 587      *          Policy.UNSUPPORTED_EMPTY_COLLECTION is returned.
 588      */
 589     public PermissionCollection getPermissions(CodeSource codesource) {
 590         return Policy.UNSUPPORTED_EMPTY_COLLECTION;
 591     }
 592 
 593     /**
 594      * Return a PermissionCollection object containing the set of
 595      * permissions granted to the specified ProtectionDomain.
 596      *
 597      * <p> Applications are discouraged from calling this method
 598      * since this operation may not be supported by all policy implementations.
 599      * Applications should rely on the <code>implies</code> method
 600      * to perform policy checks.
 601      *
 602      * <p> The default implementation of this method first retrieves
 603      * the permissions returned via <code>getPermissions(CodeSource)</code>
 604      * (the CodeSource is taken from the specified ProtectionDomain),
 605      * as well as the permissions located inside the specified ProtectionDomain.
 606      * All of these permissions are then combined and returned in a new
 607      * PermissionCollection object.  If <code>getPermissions(CodeSource)</code>
 608      * returns Policy.UNSUPPORTED_EMPTY_COLLECTION, then this method
 609      * returns the permissions contained inside the specified ProtectionDomain
 610      * in a new PermissionCollection object.
 611      *
 612      * <p> This method can be overridden if the policy implementation
 613      * supports returning a set of permissions granted to a ProtectionDomain.
 614      *
 615      * @param domain the ProtectionDomain to which the returned
 616      *          PermissionCollection has been granted.
 617      *
 618      * @return a set of permissions granted to the specified ProtectionDomain.
 619      *          If this operation is supported, the returned
 620      *          set of permissions must be a new mutable instance
 621      *          and it must support heterogeneous Permission types.
 622      *          If this operation is not supported,
 623      *          Policy.UNSUPPORTED_EMPTY_COLLECTION is returned.
 624      *
 625      * @since 1.4
 626      */
 627     public PermissionCollection getPermissions(ProtectionDomain domain) {
 628         PermissionCollection pc = null;
 629 
 630         if (domain == null)
 631             return new Permissions();
 632 
 633         if (pdMapping == null) {
 634             initPolicy(this);
 635         }
 636 
 637         synchronized (pdMapping) {
 638             pc = pdMapping.get(domain.key);
 639         }
 640 
 641         if (pc != null) {
 642             Permissions perms = new Permissions();
 643             synchronized (pc) {
 644                 for (Enumeration<Permission> e = pc.elements() ; e.hasMoreElements() ;) {
 645                     perms.add(e.nextElement());
 646                 }
 647             }
 648             return perms;
 649         }
 650 
 651         pc = getPermissions(domain.getCodeSource());
 652         if (pc == null || pc == UNSUPPORTED_EMPTY_COLLECTION) {
 653             pc = new Permissions();
 654         }
 655 
 656         addStaticPerms(pc, domain.getPermissions());
 657         return pc;
 658     }
 659 
 660     /**
 661      * add static permissions to provided permission collection
 662      */
 663     private void addStaticPerms(PermissionCollection perms,
 664                                 PermissionCollection statics) {
 665         if (statics != null) {
 666             synchronized (statics) {
 667                 Enumeration<Permission> e = statics.elements();
 668                 while (e.hasMoreElements()) {
 669                     perms.add(e.nextElement());
 670                 }
 671             }
 672         }
 673     }
 674 
 675     /**
 676      * Evaluates the global policy for the permissions granted to
 677      * the ProtectionDomain and tests whether the permission is
 678      * granted.
 679      *
 680      * @param domain the ProtectionDomain to test
 681      * @param permission the Permission object to be tested for implication.
 682      *
 683      * @return true if "permission" is a proper subset of a permission
 684      * granted to this ProtectionDomain.
 685      *
 686      * @see java.security.ProtectionDomain
 687      * @since 1.4
 688      */
 689     public boolean implies(ProtectionDomain domain, Permission permission) {
 690         PermissionCollection pc;
 691 
 692         if (pdMapping == null) {
 693             initPolicy(this);
 694         }
 695 
 696         synchronized (pdMapping) {
 697             pc = pdMapping.get(domain.key);
 698         }
 699 
 700         if (pc != null) {
 701             return pc.implies(permission);
 702         }
 703 
 704         pc = getPermissions(domain);
 705         if (pc == null) {
 706             return false;
 707         }
 708 
 709         synchronized (pdMapping) {
 710             // cache it
 711             pdMapping.put(domain.key, pc);
 712         }
 713 
 714         return pc.implies(permission);
 715     }
 716 
 717     /**
 718      * Refreshes/reloads the policy configuration. The behavior of this method
 719      * depends on the implementation. For example, calling <code>refresh</code>
 720      * on a file-based policy will cause the file to be re-read.
 721      *
 722      * <p> The default implementation of this method does nothing.
 723      * This method should be overridden if a refresh operation is supported
 724      * by the policy implementation.
 725      */
 726     public void refresh() { }
 727 
 728     /**
 729      * This subclass is returned by the getInstance calls.  All Policy calls
 730      * are delegated to the underlying PolicySpi.
 731      */
 732     private static class PolicyDelegate extends Policy {
 733 
 734         private PolicySpi spi;
 735         private Provider p;
 736         private String type;
 737         private Policy.Parameters params;
 738 
 739         private PolicyDelegate(PolicySpi spi, Provider p,
 740                         String type, Policy.Parameters params) {
 741             this.spi = spi;
 742             this.p = p;
 743             this.type = type;
 744             this.params = params;
 745         }
 746 
 747         @Override public String getType() { return type; }
 748 
 749         @Override public Policy.Parameters getParameters() { return params; }
 750 
 751         @Override public Provider getProvider() { return p; }
 752 
 753         @Override
 754         public PermissionCollection getPermissions(CodeSource codesource) {
 755             return spi.engineGetPermissions(codesource);
 756         }
 757         @Override
 758         public PermissionCollection getPermissions(ProtectionDomain domain) {
 759             return spi.engineGetPermissions(domain);
 760         }
 761         @Override
 762         public boolean implies(ProtectionDomain domain, Permission perm) {
 763             return spi.engineImplies(domain, perm);
 764         }
 765         @Override
 766         public void refresh() {
 767             spi.engineRefresh();
 768         }
 769     }
 770 
 771     /**
 772      * This represents a marker interface for Policy parameters.
 773      *
 774      * @since 1.6
 775      */
 776     public static interface Parameters { }
 777 
 778     /**
 779      * This class represents a read-only empty PermissionCollection object that
 780      * is returned from the <code>getPermissions(CodeSource)</code> and
 781      * <code>getPermissions(ProtectionDomain)</code>
 782      * methods in the Policy class when those operations are not
 783      * supported by the Policy implementation.
 784      */
 785     private static class UnsupportedEmptyCollection
 786         extends PermissionCollection {
 787 
 788         private Permissions perms;
 789 
 790         /**
 791          * Create a read-only empty PermissionCollection object.
 792          */
 793         public UnsupportedEmptyCollection() {
 794             this.perms = new Permissions();
 795             perms.setReadOnly();
 796         }
 797 
 798         /**
 799          * Adds a permission object to the current collection of permission
 800          * objects.
 801          *
 802          * @param permission the Permission object to add.
 803          *
 804          * @exception SecurityException - if this PermissionCollection object
 805          *                                has been marked readonly
 806          */
 807         @Override public void add(Permission permission) {
 808             perms.add(permission);
 809         }
 810 
 811         /**
 812          * Checks to see if the specified permission is implied by the
 813          * collection of Permission objects held in this PermissionCollection.
 814          *
 815          * @param permission the Permission object to compare.
 816          *
 817          * @return true if "permission" is implied by the  permissions in
 818          * the collection, false if not.
 819          */
 820         @Override public boolean implies(Permission permission) {
 821             return perms.implies(permission);
 822         }
 823 
 824         /**
 825          * Returns an enumeration of all the Permission objects in the
 826          * collection.
 827          *
 828          * @return an enumeration of all the Permissions.
 829          */
 830         @Override public Enumeration<Permission> elements() {
 831             return perms.elements();
 832         }
 833     }
 834 }