/**
   * Load the policies from the specified file. Also checks that the policies are correctly signed.
   */
  private static void loadPolicies(
      File jarPathName, CryptoPermissions defaultPolicy, CryptoPermissions exemptPolicy)
      throws Exception {

    JarFile jf = new JarFile(jarPathName);

    Enumeration<JarEntry> entries = jf.entries();
    while (entries.hasMoreElements()) {
      JarEntry je = entries.nextElement();
      InputStream is = null;
      try {
        if (je.getName().startsWith("default_")) {
          is = jf.getInputStream(je);
          defaultPolicy.load(is);
        } else if (je.getName().startsWith("exempt_")) {
          is = jf.getInputStream(je);
          exemptPolicy.load(is);
        } else {
          continue;
        }
      } finally {
        if (is != null) {
          is.close();
        }
      }

      // Enforce the signer restraint, i.e. signer of JCE framework
      // jar should also be the signer of the two jurisdiction policy
      // jar files.
      JarVerifier.verifyPolicySigned(je.getCertificates());
    }
    // Close and nullify the JarFile reference to help GC.
    jf.close();
    jf = null;
  }
  /**
   * Returns a Set of Strings containing the names of all available algorithms or types for the
   * specified Java cryptographic service (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore).
   * Returns an empty Set if there is no provider that supports the specified service or if
   * serviceName is null. For a complete list of Java cryptographic services, please see the <a
   * href="../../../guide/security/CryptoSpec.html">Java Cryptography Architecture API Specification
   * &amp; Reference</a>. Note: the returned set is immutable.
   *
   * @param serviceName the name of the Java cryptographic service (e.g., Signature, MessageDigest,
   *     Cipher, Mac, KeyStore). Note: this parameter is case-insensitive.
   * @return a Set of Strings containing the names of all available algorithms or types for the
   *     specified Java cryptographic service or an empty set if no provider supports the specified
   *     service.
   * @since 1.4
   */
  public static Set<String> getAlgorithms(String serviceName) {

    if ((serviceName == null) || (serviceName.length() == 0) || (serviceName.endsWith("."))) {
      return Collections.EMPTY_SET;
    }

    HashSet result = new HashSet();
    Provider[] providers = Security.getProviders();

    for (int i = 0; i < providers.length; i++) {
      // Check the keys for each provider.
      for (Enumeration e = providers[i].keys(); e.hasMoreElements(); ) {
        String currentKey = ((String) e.nextElement()).toUpperCase();
        if (currentKey.startsWith(serviceName.toUpperCase())) {
          // We should skip the currentKey if it contains a
          // whitespace. The reason is: such an entry in the
          // provider property contains attributes for the
          // implementation of an algorithm. We are only interested
          // in entries which lead to the implementation
          // classes.
          if (currentKey.indexOf(" ") < 0) {
            result.add(currentKey.substring(serviceName.length() + 1));
          }
        }
      }
    }
    return Collections.unmodifiableSet(result);
  }
  /**
   * Looks up providers, and returns the property (and its associated provider) mapping the key, if
   * any. The order in which the providers are looked up is the provider-preference order, as
   * specificed in the security properties file.
   */
  private static ProviderProperty getProviderProperty(String key) {
    ProviderProperty entry = null;

    List providers = Providers.getProviderList().providers();
    for (int i = 0; i < providers.size(); i++) {

      String matchKey = null;
      Provider prov = (Provider) providers.get(i);
      String prop = prov.getProperty(key);

      if (prop == null) {
        // Is there a match if we do a case-insensitive property name
        // comparison? Let's try ...
        for (Enumeration e = prov.keys(); e.hasMoreElements() && prop == null; ) {
          matchKey = (String) e.nextElement();
          if (key.equalsIgnoreCase(matchKey)) {
            prop = prov.getProperty(matchKey);
            break;
          }
        }
      }

      if (prop != null) {
        ProviderProperty newEntry = new ProviderProperty();
        newEntry.className = prop;
        newEntry.provider = prov;
        return newEntry;
      }
    }

    return entry;
  }
 /** Returns the property (if any) mapping the key for the given provider. */
 private static String getProviderProperty(String key, Provider provider) {
   String prop = provider.getProperty(key);
   if (prop == null) {
     // Is there a match if we do a case-insensitive property name
     // comparison? Let's try ...
     for (Enumeration e = provider.keys(); e.hasMoreElements() && prop == null; ) {
       String matchKey = (String) e.nextElement();
       if (key.equalsIgnoreCase(matchKey)) {
         prop = provider.getProperty(matchKey);
         break;
       }
     }
   }
   return prop;
 }