1 /*
   2  * Copyright (c) 1996, 2016, 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.io.*;
  29 import java.util.*;
  30 import static java.util.Locale.ENGLISH;
  31 import java.lang.ref.*;
  32 import java.lang.reflect.*;
  33 import java.util.function.BiConsumer;
  34 import java.util.function.BiFunction;
  35 import java.util.function.Function;
  36 
  37 /**
  38  * This class represents a "provider" for the
  39  * Java Security API, where a provider implements some or all parts of
  40  * Java Security. Services that a provider may implement include:
  41  *
  42  * <ul>
  43  *
  44  * <li>Algorithms (such as DSA, RSA, or SHA-256).
  45  *
  46  * <li>Key generation, conversion, and management facilities (such as for
  47  * algorithm-specific keys).
  48  *
  49  * </ul>
  50  *
  51  * <p>Some provider implementations may encounter unrecoverable internal
  52  * errors during their operation, for example a failure to communicate with a
  53  * security token. A {@link ProviderException} should be used to indicate
  54  * such errors.
  55  *
  56  * <p>Please note that a provider can be used to implement any security
  57  * service in Java that uses a pluggable architecture with a choice
  58  * of implementations that fit underneath.
  59  *
  60  * <p>The service type {@code Provider} is reserved for use by the
  61  * security framework. Services of this type cannot be added, removed,
  62  * or modified by applications.
  63  * The following attributes are automatically placed in each Provider object:
  64  * <table cellspacing=4>
  65  * <caption><b>Attributes Automatically Placed in a Provider Object</b></caption>
  66  * <tr><th>Name</th><th>Value</th>
  67  * <tr><td>{@code Provider.id name}</td>
  68   *    <td>{@code String.valueOf(provider.getName())}</td>
  69  * <tr><td>{@code Provider.id version}</td>
  70  *     <td>{@code String.valueOf(provider.getVersionStr())}</td>
  71  * <tr><td>{@code Provider.id info}</td>
  72        <td>{@code String.valueOf(provider.getInfo())}</td>
  73  * <tr><td>{@code Provider.id className}</td>
  74  *     <td>{@code provider.getClass().getName()}</td>
  75  * </table>
  76  *
  77  * <p>Each provider has a name and a version string. A provider normally
  78  * identifies itself with a file named {@code java.security.Provider}
  79  * in the resource directory {@code META-INF/services}.
  80  * Security providers are looked up via the {@link ServiceLoader} mechanism
  81  * using the {@link ClassLoader#getSystemClassLoader application class loader}.
  82  *
  83  * <p>Providers may be configured such that they are automatically
  84  * installed and made available at runtime via the
  85  * {@link Security#getProviders() Security.getProviders()} method.
  86  * The mechanism for configuring and installing security providers is
  87  * implementation-specific.
  88  *
  89  * @implNote
  90  * The JDK implementation supports static registration of the security
  91  * providers via the {@code conf/security/java.security} file in the Java
  92  * installation directory. These providers are automatically installed by
  93  * the JDK runtime, see <a href =
  94  * "../../../technotes/guides/security/crypto/CryptoSpec.html#Provider">The Provider Class</a>
  95  * in the "Java Cryptography Architecture API Specification &amp; Reference"
  96  * for information about how a particular type of provider, the cryptographic
  97  * service provider, works and is installed.
  98  *
  99  * @author Benjamin Renaud
 100  * @author Andreas Sterbenz
 101  */
 102 public abstract class Provider extends Properties {
 103 
 104     // Declare serialVersionUID to be compatible with JDK1.1
 105     private static final long serialVersionUID = -4298000515446427739L;
 106 
 107     private static final sun.security.util.Debug debug =
 108         sun.security.util.Debug.getInstance("provider", "Provider");
 109 
 110     /**
 111      * The provider name.
 112      *
 113      * @serial
 114      */
 115     private String name;
 116 
 117     /**
 118      * A description of the provider and its services.
 119      *
 120      * @serial
 121      */
 122     private String info;
 123 
 124     /**
 125      * The provider version number.
 126      *
 127      * @serial
 128      */
 129     private double version;
 130 
 131     /**
 132      * The provider version string.
 133      *
 134      * @serial
 135      */
 136     private String versionStr;
 137 
 138     private transient Set<Map.Entry<Object,Object>> entrySet = null;
 139     private transient int entrySetCallCount = 0;
 140 
 141     private transient boolean initialized;
 142 
 143     private static Object newInstanceUtil(final Class<?> clazz,
 144         final Class<?> ctrParamClz, final Object ctorParamObj)
 145         throws Exception {
 146         if (ctrParamClz == null) {
 147             Constructor<?> con = clazz.getConstructor();
 148             return con.newInstance();
 149         } else {
 150             // Looking for the constructor with a params first and fallback
 151             // to one without if not found. This is to support the enhanced
 152             // SecureRandom where both styles of constructors are supported.
 153             // Before jdk9, there was no params support (only getInstance(alg))
 154             // and an impl only had the params-less constructor. Since jdk9,
 155             // there is getInstance(alg,params) and an impl can contain
 156             // an Impl(params) constructor.
 157             try {
 158                 Constructor<?> con = clazz.getConstructor(ctrParamClz);
 159                 return con.newInstance(ctorParamObj);
 160             } catch (NoSuchMethodException nsme) {
 161                 // For pre-jdk9 SecureRandom implementations, they only
 162                 // have params-less constructors which still works when
 163                 // the input ctorParamObj is null.
 164                 //
 165                 // For other primitives using params, ctorParamObj should not
 166                 // be null and nsme is thrown, just like before.
 167                 if (ctorParamObj == null) {
 168                     try {
 169                         Constructor<?> con = clazz.getConstructor();
 170                         return con.newInstance();
 171                     } catch (NoSuchMethodException nsme2) {
 172                         nsme.addSuppressed(nsme2);
 173                         throw nsme;
 174                     }
 175                 } else {
 176                     throw nsme;
 177                 }
 178             }
 179         }
 180     }
 181 
 182     private static double parseVersionStr(String s) {
 183         try {
 184             int firstDotIdx = s.indexOf('.');
 185             int nextDotIdx = s.indexOf('.', firstDotIdx + 1);
 186             if (nextDotIdx != -1) {
 187                 s = s.substring(0, nextDotIdx);
 188             }
 189             int endIdx = s.indexOf('-');
 190             if (endIdx > 0) {
 191                 s = s.substring(0, endIdx);
 192             }
 193             endIdx = s.indexOf('+');
 194             if (endIdx > 0) {
 195                 s = s.substring(0, endIdx);
 196             }
 197             return Double.parseDouble(s);
 198         } catch (NullPointerException | NumberFormatException e) {
 199             return 0d;
 200         }
 201     }
 202 
 203     /**
 204      * Constructs a provider with the specified name, version number,
 205      * and information. Calling this constructor is equivalent to call the
 206      * {@link #Provider(String, String, String)} with {@code name}
 207      * name, {@code Double.toString(version)}, and {@code info}.
 208      *
 209      * @param name the provider name.
 210      *
 211      * @param version the provider version number.
 212      *
 213      * @param info a description of the provider and its services.
 214      *
 215      * @deprecated use {@link #Provider(String, String, String)} instead.
 216      */
 217     @Deprecated(since="9")
 218     protected Provider(String name, double version, String info) {
 219         this.name = name;
 220         this.version = version;
 221         this.versionStr = Double.toString(version);
 222         this.info = info;
 223         putId();
 224         initialized = true;
 225     }
 226 
 227     /**
 228      * Constructs a provider with the specified name, version string,
 229      * and information.
 230      *
 231      * <p>The version string contains a version number optionally followed
 232      * by other information separated by one of the characters of '+', '-'.
 233      *
 234      * The format for the version number is:
 235      *
 236      * <blockquote><pre>
 237      *     ^[0-9]+(\.[0-9]+)*
 238      * </pre></blockquote>
 239      *
 240      * <p>In order to return the version number in a double, when there are
 241      * more than two components (separated by '.' as defined above), only
 242      * the first two components are retained. The resulting string is then
 243      * passed to {@link Double#valueOf(String)} to generate version number,
 244      * i.e. {@link #getVersion}.
 245      * <p>If the conversion failed, value 0 will be used.
 246      *
 247      * @param name the provider name.
 248      *
 249      * @param versionStr the provider version string.
 250      *
 251      * @param info a description of the provider and its services.
 252      *
 253      * @since 9
 254      */
 255     protected Provider(String name, String versionStr, String info) {
 256         this.name = name;
 257         this.versionStr = versionStr;
 258         this.version = parseVersionStr(versionStr);
 259         this.info = info;
 260         putId();
 261         initialized = true;
 262     }
 263 
 264     /**
 265      * Apply the supplied configuration argument to this provider instance
 266      * and return the configured provider. Note that if this provider cannot
 267      * be configured in-place, a new provider will be created and returned.
 268      * Therefore, callers should always use the returned provider.
 269      *
 270      * @implSpec
 271      * The default implementation throws {@code UnsupportedOperationException}.
 272      * Subclasses should override this method only if a configuration argument
 273      * is supported.
 274      *
 275      * @param configArg the configuration information for configuring this
 276      *         provider.
 277      *
 278      * @throws UnsupportedOperationException if a configuration argument is
 279      *         not supported.
 280      * @throws NullPointerException if the supplied configuration argument is
 281                null.
 282      * @throws InvalidParameterException if the supplied configuration argument
 283      *         is invalid.
 284      * @return a provider configured with the supplied configuration argument.
 285      *
 286      * @since 9
 287      */
 288     public Provider configure(String configArg) {
 289         throw new UnsupportedOperationException("configure is not supported");
 290     }
 291 
 292     /**
 293      * Check if this provider instance has been configured.
 294      *
 295      * @implSpec
 296      * The default implementation returns true.
 297      * Subclasses should override this method if the provider instance requires
 298      * an explicit {@code configure} call after being constructed.
 299      *
 300      * @return true if no further configuration is needed, false otherwise.
 301      *
 302      * @since 9
 303      */
 304     public boolean isConfigured() {
 305         return true;
 306     }
 307 
 308 
 309     /**
 310      * Returns the name of this provider.
 311      *
 312      * @return the name of this provider.
 313      */
 314     public String getName() {
 315         return name;
 316     }
 317 
 318     /**
 319      * Returns the version number for this provider.
 320      *
 321      * @return the version number for this provider.
 322      *
 323      * @deprecated use {@link #getVersionStr} instead.
 324      */
 325     @Deprecated(since="9")
 326     public double getVersion() {
 327         return version;
 328     }
 329 
 330     /**
 331      * Returns the version string for this provider.
 332      *
 333      * @return the version string for this provider.
 334      *
 335      * @since 9
 336      */
 337     public String getVersionStr() {
 338         return versionStr;
 339     }
 340 
 341     /**
 342      * Returns a human-readable description of the provider and its
 343      * services.  This may return an HTML page, with relevant links.
 344      *
 345      * @return a description of the provider and its services.
 346      */
 347     public String getInfo() {
 348         return info;
 349     }
 350 
 351     /**
 352      * Returns a string with the name and the version string
 353      * of this provider.
 354      *
 355      * @return the string with the name and the version string
 356      * for this provider.
 357      */
 358     public String toString() {
 359         return name + " version " + versionStr;
 360     }
 361 
 362     /*
 363      * override the following methods to ensure that provider
 364      * information can only be changed if the caller has the appropriate
 365      * permissions.
 366      */
 367 
 368     /**
 369      * Clears this provider so that it no longer contains the properties
 370      * used to look up facilities implemented by the provider.
 371      *
 372      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
 373      * method is called with the string {@code "clearProviderProperties."+name}
 374      * (where {@code name} is the provider name) to see if it's ok to clear
 375      * this provider.
 376      *
 377      * @throws  SecurityException
 378      *          if a security manager exists and its {@link
 379      *          java.lang.SecurityManager#checkSecurityAccess} method
 380      *          denies access to clear this provider
 381      *
 382      * @since 1.2
 383      */
 384     @Override
 385     public synchronized void clear() {
 386         check("clearProviderProperties."+name);
 387         if (debug != null) {
 388             debug.println("Remove " + name + " provider properties");
 389         }
 390         implClear();
 391     }
 392 
 393     /**
 394      * Reads a property list (key and element pairs) from the input stream.
 395      *
 396      * @param inStream the input stream.
 397      * @exception IOException if an error occurred when reading from the
 398      *               input stream.
 399      * @see java.util.Properties#load
 400      */
 401     @Override
 402     public synchronized void load(InputStream inStream) throws IOException {
 403         check("putProviderProperty."+name);
 404         if (debug != null) {
 405             debug.println("Load " + name + " provider properties");
 406         }
 407         Properties tempProperties = new Properties();
 408         tempProperties.load(inStream);
 409         implPutAll(tempProperties);
 410     }
 411 
 412     /**
 413      * Copies all of the mappings from the specified Map to this provider.
 414      * These mappings will replace any properties that this provider had
 415      * for any of the keys currently in the specified Map.
 416      *
 417      * @since 1.2
 418      */
 419     @Override
 420     public synchronized void putAll(Map<?,?> t) {
 421         check("putProviderProperty."+name);
 422         if (debug != null) {
 423             debug.println("Put all " + name + " provider properties");
 424         }
 425         implPutAll(t);
 426     }
 427 
 428     /**
 429      * Returns an unmodifiable Set view of the property entries contained
 430      * in this Provider.
 431      *
 432      * @see   java.util.Map.Entry
 433      * @since 1.2
 434      */
 435     @Override
 436     public synchronized Set<Map.Entry<Object,Object>> entrySet() {
 437         checkInitialized();
 438         if (entrySet == null) {
 439             if (entrySetCallCount++ == 0)  // Initial call
 440                 entrySet = Collections.unmodifiableMap(this).entrySet();
 441             else
 442                 return super.entrySet();   // Recursive call
 443         }
 444 
 445         // This exception will be thrown if the implementation of
 446         // Collections.unmodifiableMap.entrySet() is changed such that it
 447         // no longer calls entrySet() on the backing Map.  (Provider's
 448         // entrySet implementation depends on this "implementation detail",
 449         // which is unlikely to change.
 450         if (entrySetCallCount != 2)
 451             throw new RuntimeException("Internal error.");
 452 
 453         return entrySet;
 454     }
 455 
 456     /**
 457      * Returns an unmodifiable Set view of the property keys contained in
 458      * this provider.
 459      *
 460      * @since 1.2
 461      */
 462     @Override
 463     public Set<Object> keySet() {
 464         checkInitialized();
 465         return Collections.unmodifiableSet(super.keySet());
 466     }
 467 
 468     /**
 469      * Returns an unmodifiable Collection view of the property values
 470      * contained in this provider.
 471      *
 472      * @since 1.2
 473      */
 474     @Override
 475     public Collection<Object> values() {
 476         checkInitialized();
 477         return Collections.unmodifiableCollection(super.values());
 478     }
 479 
 480     /**
 481      * Sets the {@code key} property to have the specified
 482      * {@code value}.
 483      *
 484      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
 485      * method is called with the string {@code "putProviderProperty."+name},
 486      * where {@code name} is the provider name, to see if it's ok to set this
 487      * provider's property values.
 488      *
 489      * @throws  SecurityException
 490      *          if a security manager exists and its {@link
 491      *          java.lang.SecurityManager#checkSecurityAccess} method
 492      *          denies access to set property values.
 493      *
 494      * @since 1.2
 495      */
 496     @Override
 497     public synchronized Object put(Object key, Object value) {
 498         check("putProviderProperty."+name);
 499         if (debug != null) {
 500             debug.println("Set " + name + " provider property [" +
 501                           key + "/" + value +"]");
 502         }
 503         return implPut(key, value);
 504     }
 505 
 506     /**
 507      * If the specified key is not already associated with a value (or is mapped
 508      * to {@code null}) associates it with the given value and returns
 509      * {@code null}, else returns the current value.
 510      *
 511      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
 512      * method is called with the string {@code "putProviderProperty."+name},
 513      * where {@code name} is the provider name, to see if it's ok to set this
 514      * provider's property values.
 515      *
 516      * @throws  SecurityException
 517      *          if a security manager exists and its {@link
 518      *          java.lang.SecurityManager#checkSecurityAccess} method
 519      *          denies access to set property values.
 520      *
 521      * @since 1.8
 522      */
 523     @Override
 524     public synchronized Object putIfAbsent(Object key, Object value) {
 525         check("putProviderProperty."+name);
 526         if (debug != null) {
 527             debug.println("Set " + name + " provider property [" +
 528                           key + "/" + value +"]");
 529         }
 530         return implPutIfAbsent(key, value);
 531     }
 532 
 533     /**
 534      * Removes the {@code key} property (and its corresponding
 535      * {@code value}).
 536      *
 537      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
 538      * method is called with the string {@code "removeProviderProperty."+name},
 539      * where {@code name} is the provider name, to see if it's ok to remove this
 540      * provider's properties.
 541      *
 542      * @throws  SecurityException
 543      *          if a security manager exists and its {@link
 544      *          java.lang.SecurityManager#checkSecurityAccess} method
 545      *          denies access to remove this provider's properties.
 546      *
 547      * @since 1.2
 548      */
 549     @Override
 550     public synchronized Object remove(Object key) {
 551         check("removeProviderProperty."+name);
 552         if (debug != null) {
 553             debug.println("Remove " + name + " provider property " + key);
 554         }
 555         return implRemove(key);
 556     }
 557 
 558     /**
 559      * Removes the entry for the specified key only if it is currently
 560      * mapped to the specified value.
 561      *
 562      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
 563      * method is called with the string {@code "removeProviderProperty."+name},
 564      * where {@code name} is the provider name, to see if it's ok to remove this
 565      * provider's properties.
 566      *
 567      * @throws  SecurityException
 568      *          if a security manager exists and its {@link
 569      *          java.lang.SecurityManager#checkSecurityAccess} method
 570      *          denies access to remove this provider's properties.
 571      *
 572      * @since 1.8
 573      */
 574     @Override
 575     public synchronized boolean remove(Object key, Object value) {
 576         check("removeProviderProperty."+name);
 577         if (debug != null) {
 578             debug.println("Remove " + name + " provider property " + key);
 579         }
 580         return implRemove(key, value);
 581     }
 582 
 583     /**
 584      * Replaces the entry for the specified key only if currently
 585      * mapped to the specified value.
 586      *
 587      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
 588      * method is called with the string {@code "putProviderProperty."+name},
 589      * where {@code name} is the provider name, to see if it's ok to set this
 590      * provider's property values.
 591      *
 592      * @throws  SecurityException
 593      *          if a security manager exists and its {@link
 594      *          java.lang.SecurityManager#checkSecurityAccess} method
 595      *          denies access to set property values.
 596      *
 597      * @since 1.8
 598      */
 599     @Override
 600     public synchronized boolean replace(Object key, Object oldValue,
 601             Object newValue) {
 602         check("putProviderProperty." + name);
 603 
 604         if (debug != null) {
 605             debug.println("Replace " + name + " provider property " + key);
 606         }
 607         return implReplace(key, oldValue, newValue);
 608     }
 609 
 610     /**
 611      * Replaces the entry for the specified key only if it is
 612      * currently mapped to some value.
 613      *
 614      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
 615      * method is called with the string {@code "putProviderProperty."+name},
 616      * where {@code name} is the provider name, to see if it's ok to set this
 617      * provider's property values.
 618      *
 619      * @throws  SecurityException
 620      *          if a security manager exists and its {@link
 621      *          java.lang.SecurityManager#checkSecurityAccess} method
 622      *          denies access to set property values.
 623      *
 624      * @since 1.8
 625      */
 626     @Override
 627     public synchronized Object replace(Object key, Object value) {
 628         check("putProviderProperty." + name);
 629 
 630         if (debug != null) {
 631             debug.println("Replace " + name + " provider property " + key);
 632         }
 633         return implReplace(key, value);
 634     }
 635 
 636     /**
 637      * Replaces each entry's value with the result of invoking the given
 638      * function on that entry, in the order entries are returned by an entry
 639      * set iterator, until all entries have been processed or the function
 640      * throws an exception.
 641      *
 642      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
 643      * method is called with the string {@code "putProviderProperty."+name},
 644      * where {@code name} is the provider name, to see if it's ok to set this
 645      * provider's property values.
 646      *
 647      * @throws  SecurityException
 648      *          if a security manager exists and its {@link
 649      *          java.lang.SecurityManager#checkSecurityAccess} method
 650      *          denies access to set property values.
 651      *
 652      * @since 1.8
 653      */
 654     @Override
 655     public synchronized void replaceAll(BiFunction<? super Object,
 656             ? super Object, ? extends Object> function) {
 657         check("putProviderProperty." + name);
 658 
 659         if (debug != null) {
 660             debug.println("ReplaceAll " + name + " provider property ");
 661         }
 662         implReplaceAll(function);
 663     }
 664 
 665     /**
 666      * Attempts to compute a mapping for the specified key and its
 667      * current mapped value (or {@code null} if there is no current
 668      * mapping).
 669      *
 670      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
 671      * method is called with the strings {@code "putProviderProperty."+name}
 672      * and {@code "removeProviderProperty."+name}, where {@code name} is the
 673      * provider name, to see if it's ok to set this provider's property values
 674      * and remove this provider's properties.
 675      *
 676      * @throws  SecurityException
 677      *          if a security manager exists and its {@link
 678      *          java.lang.SecurityManager#checkSecurityAccess} method
 679      *          denies access to set property values or remove properties.
 680      *
 681      * @since 1.8
 682      */
 683     @Override
 684     public synchronized Object compute(Object key, BiFunction<? super Object,
 685             ? super Object, ? extends Object> remappingFunction) {
 686         check("putProviderProperty." + name);
 687         check("removeProviderProperty." + name);
 688 
 689         if (debug != null) {
 690             debug.println("Compute " + name + " provider property " + key);
 691         }
 692         return implCompute(key, remappingFunction);
 693     }
 694 
 695     /**
 696      * If the specified key is not already associated with a value (or
 697      * is mapped to {@code null}), attempts to compute its value using
 698      * the given mapping function and enters it into this map unless
 699      * {@code null}.
 700      *
 701      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
 702      * method is called with the strings {@code "putProviderProperty."+name}
 703      * and {@code "removeProviderProperty."+name}, where {@code name} is the
 704      * provider name, to see if it's ok to set this provider's property values
 705      * and remove this provider's properties.
 706      *
 707      * @throws  SecurityException
 708      *          if a security manager exists and its {@link
 709      *          java.lang.SecurityManager#checkSecurityAccess} method
 710      *          denies access to set property values and remove properties.
 711      *
 712      * @since 1.8
 713      */
 714     @Override
 715     public synchronized Object computeIfAbsent(Object key, Function<? super Object,
 716             ? extends Object> mappingFunction) {
 717         check("putProviderProperty." + name);
 718         check("removeProviderProperty." + name);
 719 
 720         if (debug != null) {
 721             debug.println("ComputeIfAbsent " + name + " provider property " +
 722                     key);
 723         }
 724         return implComputeIfAbsent(key, mappingFunction);
 725     }
 726 
 727     /**
 728      * If the value for the specified key is present and non-null, attempts to
 729      * compute a new mapping given the key and its current mapped value.
 730      *
 731      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
 732      * method is called with the strings {@code "putProviderProperty."+name}
 733      * and {@code "removeProviderProperty."+name}, where {@code name} is the
 734      * provider name, to see if it's ok to set this provider's property values
 735      * and remove this provider's properties.
 736      *
 737      * @throws  SecurityException
 738      *          if a security manager exists and its {@link
 739      *          java.lang.SecurityManager#checkSecurityAccess} method
 740      *          denies access to set property values or remove properties.
 741      *
 742      * @since 1.8
 743      */
 744     @Override
 745     public synchronized Object computeIfPresent(Object key, BiFunction<? super Object,
 746             ? super Object, ? extends Object> remappingFunction) {
 747         check("putProviderProperty." + name);
 748         check("removeProviderProperty." + name);
 749 
 750         if (debug != null) {
 751             debug.println("ComputeIfPresent " + name + " provider property " +
 752                     key);
 753         }
 754         return implComputeIfPresent(key, remappingFunction);
 755     }
 756 
 757     /**
 758      * If the specified key is not already associated with a value or is
 759      * associated with null, associates it with the given value. Otherwise,
 760      * replaces the value with the results of the given remapping function,
 761      * or removes if the result is null. This method may be of use when
 762      * combining multiple mapped values for a key.
 763      *
 764      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
 765      * method is called with the strings {@code "putProviderProperty."+name}
 766      * and {@code "removeProviderProperty."+name}, where {@code name} is the
 767      * provider name, to see if it's ok to set this provider's property values
 768      * and remove this provider's properties.
 769      *
 770      * @throws  SecurityException
 771      *          if a security manager exists and its {@link
 772      *          java.lang.SecurityManager#checkSecurityAccess} method
 773      *          denies access to set property values or remove properties.
 774      *
 775      * @since 1.8
 776      */
 777     @Override
 778     public synchronized Object merge(Object key, Object value,  BiFunction<? super Object,
 779             ? super Object, ? extends Object>  remappingFunction) {
 780         check("putProviderProperty." + name);
 781         check("removeProviderProperty." + name);
 782 
 783         if (debug != null) {
 784             debug.println("Merge " + name + " provider property " + key);
 785         }
 786         return implMerge(key, value, remappingFunction);
 787     }
 788 
 789     // let javadoc show doc from superclass
 790     @Override
 791     public Object get(Object key) {
 792         checkInitialized();
 793         return super.get(key);
 794     }
 795     /**
 796      * @since 1.8
 797      */
 798     @Override
 799     public synchronized Object getOrDefault(Object key, Object defaultValue) {
 800         checkInitialized();
 801         return super.getOrDefault(key, defaultValue);
 802     }
 803 
 804     /**
 805      * @since 1.8
 806      */
 807     @Override
 808     public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) {
 809         checkInitialized();
 810         super.forEach(action);
 811     }
 812 
 813     // let javadoc show doc from superclass
 814     @Override
 815     public Enumeration<Object> keys() {
 816         checkInitialized();
 817         return super.keys();
 818     }
 819 
 820     // let javadoc show doc from superclass
 821     @Override
 822     public Enumeration<Object> elements() {
 823         checkInitialized();
 824         return super.elements();
 825     }
 826 
 827     // let javadoc show doc from superclass
 828     public String getProperty(String key) {
 829         checkInitialized();
 830         return super.getProperty(key);
 831     }
 832 
 833     private void checkInitialized() {
 834         if (!initialized) {
 835             throw new IllegalStateException();
 836         }
 837     }
 838 
 839     private void check(String directive) {
 840         checkInitialized();
 841         SecurityManager security = System.getSecurityManager();
 842         if (security != null) {
 843             security.checkSecurityAccess(directive);
 844         }
 845     }
 846 
 847     // legacy properties changed since last call to any services method?
 848     private transient boolean legacyChanged;
 849     // serviceMap changed since last call to getServices()
 850     private transient boolean servicesChanged;
 851 
 852     // Map<String,String>
 853     private transient Map<String,String> legacyStrings;
 854 
 855     // Map<ServiceKey,Service>
 856     // used for services added via putService(), initialized on demand
 857     private transient Map<ServiceKey,Service> serviceMap;
 858 
 859     // Map<ServiceKey,Service>
 860     // used for services added via legacy methods, init on demand
 861     private transient Map<ServiceKey,Service> legacyMap;
 862 
 863     // Set<Service>
 864     // Unmodifiable set of all services. Initialized on demand.
 865     private transient Set<Service> serviceSet;
 866 
 867     // register the id attributes for this provider
 868     // this is to ensure that equals() and hashCode() do not incorrectly
 869     // report to different provider objects as the same
 870     private void putId() {
 871         // note: name and info may be null
 872         super.put("Provider.id name", String.valueOf(name));
 873         super.put("Provider.id version", String.valueOf(versionStr));
 874         super.put("Provider.id info", String.valueOf(info));
 875         super.put("Provider.id className", this.getClass().getName());
 876     }
 877 
 878    /**
 879     * Reads the {@code ObjectInputStream} for the default serializable fields.
 880     * If the serialized field {@code versionStr} is found in the STREAM FIELDS,
 881     * its String value will be used to populate both the version string and
 882     * version number. If {@code versionStr} is not found, but {@code version}
 883     * is, then its double value will be used to populate both fields.
 884     *
 885     * @param in the {@code ObjectInputStream} to read
 886     * @serial
 887     */
 888     private void readObject(ObjectInputStream in)
 889                 throws IOException, ClassNotFoundException {
 890         Map<Object,Object> copy = new HashMap<>();
 891         for (Map.Entry<Object,Object> entry : super.entrySet()) {
 892             copy.put(entry.getKey(), entry.getValue());
 893         }
 894         defaults = null;
 895         in.defaultReadObject();
 896         if (this.versionStr == null) {
 897             // set versionStr based on version when not found in serialized bytes
 898             this.versionStr = Double.toString(this.version);
 899         } else {
 900             // otherwise, set version based on versionStr
 901             this.version = parseVersionStr(this.versionStr);
 902         }
 903         implClear();
 904         initialized = true;
 905         putAll(copy);
 906     }
 907 
 908     private boolean checkLegacy(Object key) {
 909         String keyString = (String)key;
 910         if (keyString.startsWith("Provider.")) {
 911             return false;
 912         }
 913 
 914         legacyChanged = true;
 915         if (legacyStrings == null) {
 916             legacyStrings = new LinkedHashMap<>();
 917         }
 918         return true;
 919     }
 920 
 921     /**
 922      * Copies all of the mappings from the specified Map to this provider.
 923      * Internal method to be called AFTER the security check has been
 924      * performed.
 925      */
 926     private void implPutAll(Map<?,?> t) {
 927         for (Map.Entry<?,?> e : t.entrySet()) {
 928             implPut(e.getKey(), e.getValue());
 929         }
 930     }
 931 
 932     private Object implRemove(Object key) {
 933         if (key instanceof String) {
 934             if (!checkLegacy(key)) {
 935                 return null;
 936             }
 937             legacyStrings.remove((String)key);
 938         }
 939         return super.remove(key);
 940     }
 941 
 942     private boolean implRemove(Object key, Object value) {
 943         if (key instanceof String && value instanceof String) {
 944             if (!checkLegacy(key)) {
 945                 return false;
 946             }
 947             legacyStrings.remove((String)key, value);
 948         }
 949         return super.remove(key, value);
 950     }
 951 
 952     private boolean implReplace(Object key, Object oldValue, Object newValue) {
 953         if ((key instanceof String) && (oldValue instanceof String) &&
 954                 (newValue instanceof String)) {
 955             if (!checkLegacy(key)) {
 956                 return false;
 957             }
 958             legacyStrings.replace((String)key, (String)oldValue,
 959                     (String)newValue);
 960         }
 961         return super.replace(key, oldValue, newValue);
 962     }
 963 
 964     private Object implReplace(Object key, Object value) {
 965         if ((key instanceof String) && (value instanceof String)) {
 966             if (!checkLegacy(key)) {
 967                 return null;
 968             }
 969             legacyStrings.replace((String)key, (String)value);
 970         }
 971         return super.replace(key, value);
 972     }
 973 
 974     @SuppressWarnings("unchecked") // Function must actually operate over strings
 975     private void implReplaceAll(BiFunction<? super Object, ? super Object,
 976             ? extends Object> function) {
 977         legacyChanged = true;
 978         if (legacyStrings == null) {
 979             legacyStrings = new LinkedHashMap<>();
 980         } else {
 981             legacyStrings.replaceAll((BiFunction<? super String, ? super String,
 982                     ? extends String>) function);
 983         }
 984         super.replaceAll(function);
 985     }
 986 
 987     @SuppressWarnings("unchecked") // Function must actually operate over strings
 988     private Object implMerge(Object key, Object value, BiFunction<? super Object,
 989             ? super Object, ? extends Object> remappingFunction) {
 990         if ((key instanceof String) && (value instanceof String)) {
 991             if (!checkLegacy(key)) {
 992                 return null;
 993             }
 994             legacyStrings.merge((String)key, (String)value,
 995                     (BiFunction<? super String, ? super String, ? extends String>) remappingFunction);
 996         }
 997         return super.merge(key, value, remappingFunction);
 998     }
 999 
1000     @SuppressWarnings("unchecked") // Function must actually operate over strings
1001     private Object implCompute(Object key, BiFunction<? super Object,
1002             ? super Object, ? extends Object> remappingFunction) {
1003         if (key instanceof String) {
1004             if (!checkLegacy(key)) {
1005                 return null;
1006             }
1007             legacyStrings.compute((String) key,
1008                     (BiFunction<? super String,? super String, ? extends String>) remappingFunction);
1009         }
1010         return super.compute(key, remappingFunction);
1011     }
1012 
1013     @SuppressWarnings("unchecked") // Function must actually operate over strings
1014     private Object implComputeIfAbsent(Object key, Function<? super Object,
1015             ? extends Object> mappingFunction) {
1016         if (key instanceof String) {
1017             if (!checkLegacy(key)) {
1018                 return null;
1019             }
1020             legacyStrings.computeIfAbsent((String) key,
1021                     (Function<? super String, ? extends String>) mappingFunction);
1022         }
1023         return super.computeIfAbsent(key, mappingFunction);
1024     }
1025 
1026     @SuppressWarnings("unchecked") // Function must actually operate over strings
1027     private Object implComputeIfPresent(Object key, BiFunction<? super Object,
1028             ? super Object, ? extends Object> remappingFunction) {
1029         if (key instanceof String) {
1030             if (!checkLegacy(key)) {
1031                 return null;
1032             }
1033             legacyStrings.computeIfPresent((String) key,
1034                     (BiFunction<? super String, ? super String, ? extends String>) remappingFunction);
1035         }
1036         return super.computeIfPresent(key, remappingFunction);
1037     }
1038 
1039     private Object implPut(Object key, Object value) {
1040         if ((key instanceof String) && (value instanceof String)) {
1041             if (!checkLegacy(key)) {
1042                 return null;
1043             }
1044             legacyStrings.put((String)key, (String)value);
1045         }
1046         return super.put(key, value);
1047     }
1048 
1049     private Object implPutIfAbsent(Object key, Object value) {
1050         if ((key instanceof String) && (value instanceof String)) {
1051             if (!checkLegacy(key)) {
1052                 return null;
1053             }
1054             legacyStrings.putIfAbsent((String)key, (String)value);
1055         }
1056         return super.putIfAbsent(key, value);
1057     }
1058 
1059     private void implClear() {
1060         if (legacyStrings != null) {
1061             legacyStrings.clear();
1062         }
1063         if (legacyMap != null) {
1064             legacyMap.clear();
1065         }
1066         if (serviceMap != null) {
1067             serviceMap.clear();
1068         }
1069         legacyChanged = false;
1070         servicesChanged = false;
1071         serviceSet = null;
1072         super.clear();
1073         putId();
1074     }
1075 
1076     // used as key in the serviceMap and legacyMap HashMaps
1077     private static class ServiceKey {
1078         private final String type;
1079         private final String algorithm;
1080         private final String originalAlgorithm;
1081         private ServiceKey(String type, String algorithm, boolean intern) {
1082             this.type = type;
1083             this.originalAlgorithm = algorithm;
1084             algorithm = algorithm.toUpperCase(ENGLISH);
1085             this.algorithm = intern ? algorithm.intern() : algorithm;
1086         }
1087         public int hashCode() {
1088             return type.hashCode() + algorithm.hashCode();
1089         }
1090         public boolean equals(Object obj) {
1091             if (this == obj) {
1092                 return true;
1093             }
1094             if (obj instanceof ServiceKey == false) {
1095                 return false;
1096             }
1097             ServiceKey other = (ServiceKey)obj;
1098             return this.type.equals(other.type)
1099                 && this.algorithm.equals(other.algorithm);
1100         }
1101         boolean matches(String type, String algorithm) {
1102             return (this.type == type) && (this.originalAlgorithm == algorithm);
1103         }
1104     }
1105 
1106     /**
1107      * Ensure all the legacy String properties are fully parsed into
1108      * service objects.
1109      */
1110     private void ensureLegacyParsed() {
1111         if ((legacyChanged == false) || (legacyStrings == null)) {
1112             return;
1113         }
1114         serviceSet = null;
1115         if (legacyMap == null) {
1116             legacyMap = new LinkedHashMap<>();
1117         } else {
1118             legacyMap.clear();
1119         }
1120         for (Map.Entry<String,String> entry : legacyStrings.entrySet()) {
1121             parseLegacyPut(entry.getKey(), entry.getValue());
1122         }
1123         removeInvalidServices(legacyMap);
1124         legacyChanged = false;
1125     }
1126 
1127     /**
1128      * Remove all invalid services from the Map. Invalid services can only
1129      * occur if the legacy properties are inconsistent or incomplete.
1130      */
1131     private void removeInvalidServices(Map<ServiceKey,Service> map) {
1132         for (Iterator<Map.Entry<ServiceKey, Service>> t =
1133                 map.entrySet().iterator(); t.hasNext(); ) {
1134             Service s = t.next().getValue();
1135             if (s.isValid() == false) {
1136                 t.remove();
1137             }
1138         }
1139     }
1140 
1141     private String[] getTypeAndAlgorithm(String key) {
1142         int i = key.indexOf('.');
1143         if (i < 1) {
1144             if (debug != null) {
1145                 debug.println("Ignoring invalid entry in provider "
1146                         + name + ":" + key);
1147             }
1148             return null;
1149         }
1150         String type = key.substring(0, i);
1151         String alg = key.substring(i + 1);
1152         return new String[] {type, alg};
1153     }
1154 
1155     private static final String ALIAS_PREFIX = "Alg.Alias.";
1156     private static final String ALIAS_PREFIX_LOWER = "alg.alias.";
1157     private static final int ALIAS_LENGTH = ALIAS_PREFIX.length();
1158 
1159     private void parseLegacyPut(String name, String value) {
1160         if (name.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) {
1161             // e.g. put("Alg.Alias.MessageDigest.SHA", "SHA-1");
1162             // aliasKey ~ MessageDigest.SHA
1163             String stdAlg = value;
1164             String aliasKey = name.substring(ALIAS_LENGTH);
1165             String[] typeAndAlg = getTypeAndAlgorithm(aliasKey);
1166             if (typeAndAlg == null) {
1167                 return;
1168             }
1169             String type = getEngineName(typeAndAlg[0]);
1170             String aliasAlg = typeAndAlg[1].intern();
1171             ServiceKey key = new ServiceKey(type, stdAlg, true);
1172             Service s = legacyMap.get(key);
1173             if (s == null) {
1174                 s = new Service(this);
1175                 s.type = type;
1176                 s.algorithm = stdAlg;
1177                 legacyMap.put(key, s);
1178             }
1179             legacyMap.put(new ServiceKey(type, aliasAlg, true), s);
1180             s.addAlias(aliasAlg);
1181         } else {
1182             String[] typeAndAlg = getTypeAndAlgorithm(name);
1183             if (typeAndAlg == null) {
1184                 return;
1185             }
1186             int i = typeAndAlg[1].indexOf(' ');
1187             if (i == -1) {
1188                 // e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA");
1189                 String type = getEngineName(typeAndAlg[0]);
1190                 String stdAlg = typeAndAlg[1].intern();
1191                 String className = value;
1192                 ServiceKey key = new ServiceKey(type, stdAlg, true);
1193                 Service s = legacyMap.get(key);
1194                 if (s == null) {
1195                     s = new Service(this);
1196                     s.type = type;
1197                     s.algorithm = stdAlg;
1198                     legacyMap.put(key, s);
1199                 }
1200                 s.className = className;
1201             } else { // attribute
1202                 // e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software");
1203                 String attributeValue = value;
1204                 String type = getEngineName(typeAndAlg[0]);
1205                 String attributeString = typeAndAlg[1];
1206                 String stdAlg = attributeString.substring(0, i).intern();
1207                 String attributeName = attributeString.substring(i + 1);
1208                 // kill additional spaces
1209                 while (attributeName.startsWith(" ")) {
1210                     attributeName = attributeName.substring(1);
1211                 }
1212                 attributeName = attributeName.intern();
1213                 ServiceKey key = new ServiceKey(type, stdAlg, true);
1214                 Service s = legacyMap.get(key);
1215                 if (s == null) {
1216                     s = new Service(this);
1217                     s.type = type;
1218                     s.algorithm = stdAlg;
1219                     legacyMap.put(key, s);
1220                 }
1221                 s.addAttribute(attributeName, attributeValue);
1222             }
1223         }
1224     }
1225 
1226     /**
1227      * Get the service describing this Provider's implementation of the
1228      * specified type of this algorithm or alias. If no such
1229      * implementation exists, this method returns null. If there are two
1230      * matching services, one added to this provider using
1231      * {@link #putService putService()} and one added via {@link #put put()},
1232      * the service added via {@link #putService putService()} is returned.
1233      *
1234      * @param type the type of {@link Service service} requested
1235      * (for example, {@code MessageDigest})
1236      * @param algorithm the case insensitive algorithm name (or alternate
1237      * alias) of the service requested (for example, {@code SHA-1})
1238      *
1239      * @return the service describing this Provider's matching service
1240      * or null if no such service exists
1241      *
1242      * @throws NullPointerException if type or algorithm is null
1243      *
1244      * @since 1.5
1245      */
1246     public synchronized Service getService(String type, String algorithm) {
1247         checkInitialized();
1248         // avoid allocating a new key object if possible
1249         ServiceKey key = previousKey;
1250         if (key.matches(type, algorithm) == false) {
1251             key = new ServiceKey(type, algorithm, false);
1252             previousKey = key;
1253         }
1254         if (serviceMap != null) {
1255             Service service = serviceMap.get(key);
1256             if (service != null) {
1257                 return service;
1258             }
1259         }
1260         ensureLegacyParsed();
1261         return (legacyMap != null) ? legacyMap.get(key) : null;
1262     }
1263 
1264     // ServiceKey from previous getService() call
1265     // by re-using it if possible we avoid allocating a new object
1266     // and the toUpperCase() call.
1267     // re-use will occur e.g. as the framework traverses the provider
1268     // list and queries each provider with the same values until it finds
1269     // a matching service
1270     private static volatile ServiceKey previousKey =
1271                                             new ServiceKey("", "", false);
1272 
1273     /**
1274      * Get an unmodifiable Set of all services supported by
1275      * this Provider.
1276      *
1277      * @return an unmodifiable Set of all services supported by
1278      * this Provider
1279      *
1280      * @since 1.5
1281      */
1282     public synchronized Set<Service> getServices() {
1283         checkInitialized();
1284         if (legacyChanged || servicesChanged) {
1285             serviceSet = null;
1286         }
1287         if (serviceSet == null) {
1288             ensureLegacyParsed();
1289             Set<Service> set = new LinkedHashSet<>();
1290             if (serviceMap != null) {
1291                 set.addAll(serviceMap.values());
1292             }
1293             if (legacyMap != null) {
1294                 set.addAll(legacyMap.values());
1295             }
1296             serviceSet = Collections.unmodifiableSet(set);
1297             servicesChanged = false;
1298         }
1299         return serviceSet;
1300     }
1301 
1302     /**
1303      * Add a service. If a service of the same type with the same algorithm
1304      * name exists and it was added using {@link #putService putService()},
1305      * it is replaced by the new service.
1306      * This method also places information about this service
1307      * in the provider's Hashtable values in the format described in the
1308      * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
1309      * Java Cryptography Architecture API Specification &amp; Reference </a>.
1310      *
1311      * <p>Also, if there is a security manager, its
1312      * {@code checkSecurityAccess} method is called with the string
1313      * {@code "putProviderProperty."+name}, where {@code name} is
1314      * the provider name, to see if it's ok to set this provider's property
1315      * values. If the default implementation of {@code checkSecurityAccess}
1316      * is used (that is, that method is not overriden), then this results in
1317      * a call to the security manager's {@code checkPermission} method with
1318      * a {@code SecurityPermission("putProviderProperty."+name)}
1319      * permission.
1320      *
1321      * @param s the Service to add
1322      *
1323      * @throws SecurityException
1324      *      if a security manager exists and its {@link
1325      *      java.lang.SecurityManager#checkSecurityAccess} method denies
1326      *      access to set property values.
1327      * @throws NullPointerException if s is null
1328      *
1329      * @since 1.5
1330      */
1331     protected synchronized void putService(Service s) {
1332         check("putProviderProperty." + name);
1333         if (debug != null) {
1334             debug.println(name + ".putService(): " + s);
1335         }
1336         if (s == null) {
1337             throw new NullPointerException();
1338         }
1339         if (s.getProvider() != this) {
1340             throw new IllegalArgumentException
1341                     ("service.getProvider() must match this Provider object");
1342         }
1343         if (serviceMap == null) {
1344             serviceMap = new LinkedHashMap<>();
1345         }
1346         servicesChanged = true;
1347         String type = s.getType();
1348         String algorithm = s.getAlgorithm();
1349         ServiceKey key = new ServiceKey(type, algorithm, true);
1350         // remove existing service
1351         implRemoveService(serviceMap.get(key));
1352         serviceMap.put(key, s);
1353         for (String alias : s.getAliases()) {
1354             serviceMap.put(new ServiceKey(type, alias, true), s);
1355         }
1356         putPropertyStrings(s);
1357     }
1358 
1359     /**
1360      * Put the string properties for this Service in this Provider's
1361      * Hashtable.
1362      */
1363     private void putPropertyStrings(Service s) {
1364         String type = s.getType();
1365         String algorithm = s.getAlgorithm();
1366         // use super() to avoid permission check and other processing
1367         super.put(type + "." + algorithm, s.getClassName());
1368         for (String alias : s.getAliases()) {
1369             super.put(ALIAS_PREFIX + type + "." + alias, algorithm);
1370         }
1371         for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
1372             String key = type + "." + algorithm + " " + entry.getKey();
1373             super.put(key, entry.getValue());
1374         }
1375     }
1376 
1377     /**
1378      * Remove the string properties for this Service from this Provider's
1379      * Hashtable.
1380      */
1381     private void removePropertyStrings(Service s) {
1382         String type = s.getType();
1383         String algorithm = s.getAlgorithm();
1384         // use super() to avoid permission check and other processing
1385         super.remove(type + "." + algorithm);
1386         for (String alias : s.getAliases()) {
1387             super.remove(ALIAS_PREFIX + type + "." + alias);
1388         }
1389         for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
1390             String key = type + "." + algorithm + " " + entry.getKey();
1391             super.remove(key);
1392         }
1393     }
1394 
1395     /**
1396      * Remove a service previously added using
1397      * {@link #putService putService()}. The specified service is removed from
1398      * this provider. It will no longer be returned by
1399      * {@link #getService getService()} and its information will be removed
1400      * from this provider's Hashtable.
1401      *
1402      * <p>Also, if there is a security manager, its
1403      * {@code checkSecurityAccess} method is called with the string
1404      * {@code "removeProviderProperty."+name}, where {@code name} is
1405      * the provider name, to see if it's ok to remove this provider's
1406      * properties. If the default implementation of
1407      * {@code checkSecurityAccess} is used (that is, that method is not
1408      * overriden), then this results in a call to the security manager's
1409      * {@code checkPermission} method with a
1410      * {@code SecurityPermission("removeProviderProperty."+name)}
1411      * permission.
1412      *
1413      * @param s the Service to be removed
1414      *
1415      * @throws  SecurityException
1416      *          if a security manager exists and its {@link
1417      *          java.lang.SecurityManager#checkSecurityAccess} method denies
1418      *          access to remove this provider's properties.
1419      * @throws NullPointerException if s is null
1420      *
1421      * @since 1.5
1422      */
1423     protected synchronized void removeService(Service s) {
1424         check("removeProviderProperty." + name);
1425         if (debug != null) {
1426             debug.println(name + ".removeService(): " + s);
1427         }
1428         if (s == null) {
1429             throw new NullPointerException();
1430         }
1431         implRemoveService(s);
1432     }
1433 
1434     private void implRemoveService(Service s) {
1435         if ((s == null) || (serviceMap == null)) {
1436             return;
1437         }
1438         String type = s.getType();
1439         String algorithm = s.getAlgorithm();
1440         ServiceKey key = new ServiceKey(type, algorithm, false);
1441         Service oldService = serviceMap.get(key);
1442         if (s != oldService) {
1443             return;
1444         }
1445         servicesChanged = true;
1446         serviceMap.remove(key);
1447         for (String alias : s.getAliases()) {
1448             serviceMap.remove(new ServiceKey(type, alias, false));
1449         }
1450         removePropertyStrings(s);
1451     }
1452 
1453     // Wrapped String that behaves in a case insensitive way for equals/hashCode
1454     private static class UString {
1455         final String string;
1456         final String lowerString;
1457 
1458         UString(String s) {
1459             this.string = s;
1460             this.lowerString = s.toLowerCase(ENGLISH);
1461         }
1462 
1463         public int hashCode() {
1464             return lowerString.hashCode();
1465         }
1466 
1467         public boolean equals(Object obj) {
1468             if (this == obj) {
1469                 return true;
1470             }
1471             if (obj instanceof UString == false) {
1472                 return false;
1473             }
1474             UString other = (UString)obj;
1475             return lowerString.equals(other.lowerString);
1476         }
1477 
1478         public String toString() {
1479             return string;
1480         }
1481     }
1482 
1483     // describe relevant properties of a type of engine
1484     private static class EngineDescription {
1485         final String name;
1486         final boolean supportsParameter;
1487         final String constructorParameterClassName;
1488         private volatile Class<?> constructorParameterClass;
1489 
1490         EngineDescription(String name, boolean sp, String paramName) {
1491             this.name = name;
1492             this.supportsParameter = sp;
1493             this.constructorParameterClassName = paramName;
1494         }
1495         Class<?> getConstructorParameterClass() throws ClassNotFoundException {
1496             Class<?> clazz = constructorParameterClass;
1497             if (clazz == null) {
1498                 clazz = Class.forName(constructorParameterClassName);
1499                 constructorParameterClass = clazz;
1500             }
1501             return clazz;
1502         }
1503     }
1504 
1505     // built in knowledge of the engine types shipped as part of the JDK
1506     private static final Map<String,EngineDescription> knownEngines;
1507 
1508     private static void addEngine(String name, boolean sp, String paramName) {
1509         EngineDescription ed = new EngineDescription(name, sp, paramName);
1510         // also index by canonical name to avoid toLowerCase() for some lookups
1511         knownEngines.put(name.toLowerCase(ENGLISH), ed);
1512         knownEngines.put(name, ed);
1513     }
1514 
1515     static {
1516         knownEngines = new HashMap<>();
1517         // JCA
1518         addEngine("AlgorithmParameterGenerator",        false, null);
1519         addEngine("AlgorithmParameters",                false, null);
1520         addEngine("KeyFactory",                         false, null);
1521         addEngine("KeyPairGenerator",                   false, null);
1522         addEngine("KeyStore",                           false, null);
1523         addEngine("MessageDigest",                      false, null);
1524         addEngine("SecureRandom",                       false,
1525                 "java.security.SecureRandomParameters");
1526         addEngine("Signature",                          true,  null);
1527         addEngine("CertificateFactory",                 false, null);
1528         addEngine("CertPathBuilder",                    false, null);
1529         addEngine("CertPathValidator",                  false, null);
1530         addEngine("CertStore",                          false,
1531                             "java.security.cert.CertStoreParameters");
1532         // JCE
1533         addEngine("Cipher",                             true,  null);
1534         addEngine("ExemptionMechanism",                 false, null);
1535         addEngine("Mac",                                true,  null);
1536         addEngine("KeyAgreement",                       true,  null);
1537         addEngine("KeyGenerator",                       false, null);
1538         addEngine("SecretKeyFactory",                   false, null);
1539         // JSSE
1540         addEngine("KeyManagerFactory",                  false, null);
1541         addEngine("SSLContext",                         false, null);
1542         addEngine("TrustManagerFactory",                false, null);
1543         // JGSS
1544         addEngine("GssApiMechanism",                    false, null);
1545         // SASL
1546         addEngine("SaslClientFactory",                  false, null);
1547         addEngine("SaslServerFactory",                  false, null);
1548         // POLICY
1549         addEngine("Policy",                             false,
1550                             "java.security.Policy$Parameters");
1551         // CONFIGURATION
1552         addEngine("Configuration",                      false,
1553                             "javax.security.auth.login.Configuration$Parameters");
1554         // XML DSig
1555         addEngine("XMLSignatureFactory",                false, null);
1556         addEngine("KeyInfoFactory",                     false, null);
1557         addEngine("TransformService",                   false, null);
1558         // Smart Card I/O
1559         addEngine("TerminalFactory",                    false,
1560                             "java.lang.Object");
1561     }
1562 
1563     // get the "standard" (mixed-case) engine name for arbitary case engine name
1564     // if there is no known engine by that name, return s
1565     private static String getEngineName(String s) {
1566         // try original case first, usually correct
1567         EngineDescription e = knownEngines.get(s);
1568         if (e == null) {
1569             e = knownEngines.get(s.toLowerCase(ENGLISH));
1570         }
1571         return (e == null) ? s : e.name;
1572     }
1573 
1574     /**
1575      * The description of a security service. It encapsulates the properties
1576      * of a service and contains a factory method to obtain new implementation
1577      * instances of this service.
1578      *
1579      * <p>Each service has a provider that offers the service, a type,
1580      * an algorithm name, and the name of the class that implements the
1581      * service. Optionally, it also includes a list of alternate algorithm
1582      * names for this service (aliases) and attributes, which are a map of
1583      * (name, value) String pairs.
1584      *
1585      * <p>This class defines the methods {@link #supportsParameter
1586      * supportsParameter()} and {@link #newInstance newInstance()}
1587      * which are used by the Java security framework when it searches for
1588      * suitable services and instantiates them. The valid arguments to those
1589      * methods depend on the type of service. For the service types defined
1590      * within Java SE, see the
1591      * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
1592      * Java Cryptography Architecture API Specification &amp; Reference </a>
1593      * for the valid values.
1594      * Note that components outside of Java SE can define additional types of
1595      * services and their behavior.
1596      *
1597      * <p>Instances of this class are immutable.
1598      *
1599      * @since 1.5
1600      */
1601     public static class Service {
1602 
1603         private String type, algorithm, className;
1604         private final Provider provider;
1605         private List<String> aliases;
1606         private Map<UString,String> attributes;
1607 
1608         // Reference to the cached implementation Class object
1609         private volatile Reference<Class<?>> classRef;
1610 
1611         // flag indicating whether this service has its attributes for
1612         // supportedKeyFormats or supportedKeyClasses set
1613         // if null, the values have not been initialized
1614         // if TRUE, at least one of supportedFormats/Classes is non null
1615         private volatile Boolean hasKeyAttributes;
1616 
1617         // supported encoding formats
1618         private String[] supportedFormats;
1619 
1620         // names of the supported key (super) classes
1621         private Class<?>[] supportedClasses;
1622 
1623         // whether this service has been registered with the Provider
1624         private boolean registered;
1625 
1626         private static final Class<?>[] CLASS0 = new Class<?>[0];
1627 
1628         // this constructor and these methods are used for parsing
1629         // the legacy string properties.
1630 
1631         private Service(Provider provider) {
1632             this.provider = provider;
1633             aliases = Collections.<String>emptyList();
1634             attributes = Collections.<UString,String>emptyMap();
1635         }
1636 
1637         private boolean isValid() {
1638             return (type != null) && (algorithm != null) && (className != null);
1639         }
1640 
1641         private void addAlias(String alias) {
1642             if (aliases.isEmpty()) {
1643                 aliases = new ArrayList<>(2);
1644             }
1645             aliases.add(alias);
1646         }
1647 
1648         void addAttribute(String type, String value) {
1649             if (attributes.isEmpty()) {
1650                 attributes = new HashMap<>(8);
1651             }
1652             attributes.put(new UString(type), value);
1653         }
1654 
1655         /**
1656          * Construct a new service.
1657          *
1658          * @param provider the provider that offers this service
1659          * @param type the type of this service
1660          * @param algorithm the algorithm name
1661          * @param className the name of the class implementing this service
1662          * @param aliases List of aliases or null if algorithm has no aliases
1663          * @param attributes Map of attributes or null if this implementation
1664          *                   has no attributes
1665          *
1666          * @throws NullPointerException if provider, type, algorithm, or
1667          * className is null
1668          */
1669         public Service(Provider provider, String type, String algorithm,
1670                 String className, List<String> aliases,
1671                 Map<String,String> attributes) {
1672             if ((provider == null) || (type == null) ||
1673                     (algorithm == null) || (className == null)) {
1674                 throw new NullPointerException();
1675             }
1676             this.provider = provider;
1677             this.type = getEngineName(type);
1678             this.algorithm = algorithm;
1679             this.className = className;
1680             if (aliases == null) {
1681                 this.aliases = Collections.<String>emptyList();
1682             } else {
1683                 this.aliases = new ArrayList<>(aliases);
1684             }
1685             if (attributes == null) {
1686                 this.attributes = Collections.<UString,String>emptyMap();
1687             } else {
1688                 this.attributes = new HashMap<>();
1689                 for (Map.Entry<String,String> entry : attributes.entrySet()) {
1690                     this.attributes.put(new UString(entry.getKey()), entry.getValue());
1691                 }
1692             }
1693         }
1694 
1695         /**
1696          * Get the type of this service. For example, {@code MessageDigest}.
1697          *
1698          * @return the type of this service
1699          */
1700         public final String getType() {
1701             return type;
1702         }
1703 
1704         /**
1705          * Return the name of the algorithm of this service. For example,
1706          * {@code SHA-1}.
1707          *
1708          * @return the algorithm of this service
1709          */
1710         public final String getAlgorithm() {
1711             return algorithm;
1712         }
1713 
1714         /**
1715          * Return the Provider of this service.
1716          *
1717          * @return the Provider of this service
1718          */
1719         public final Provider getProvider() {
1720             return provider;
1721         }
1722 
1723         /**
1724          * Return the name of the class implementing this service.
1725          *
1726          * @return the name of the class implementing this service
1727          */
1728         public final String getClassName() {
1729             return className;
1730         }
1731 
1732         // internal only
1733         private final List<String> getAliases() {
1734             return aliases;
1735         }
1736 
1737         /**
1738          * Return the value of the specified attribute or null if this
1739          * attribute is not set for this Service.
1740          *
1741          * @param name the name of the requested attribute
1742          *
1743          * @return the value of the specified attribute or null if the
1744          *         attribute is not present
1745          *
1746          * @throws NullPointerException if name is null
1747          */
1748         public final String getAttribute(String name) {
1749             if (name == null) {
1750                 throw new NullPointerException();
1751             }
1752             return attributes.get(new UString(name));
1753         }
1754 
1755         /**
1756          * Return a new instance of the implementation described by this
1757          * service. The security provider framework uses this method to
1758          * construct implementations. Applications will typically not need
1759          * to call it.
1760          *
1761          * <p>The default implementation uses reflection to invoke the
1762          * standard constructor for this type of service.
1763          * Security providers can override this method to implement
1764          * instantiation in a different way.
1765          * For details and the values of constructorParameter that are
1766          * valid for the various types of services see the
1767          * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
1768          * Java Cryptography Architecture API Specification &amp;
1769          * Reference</a>.
1770          *
1771          * @param constructorParameter the value to pass to the constructor,
1772          * or null if this type of service does not use a constructorParameter.
1773          *
1774          * @return a new implementation of this service
1775          *
1776          * @throws InvalidParameterException if the value of
1777          * constructorParameter is invalid for this type of service.
1778          * @throws NoSuchAlgorithmException if instantiation failed for
1779          * any other reason.
1780          */
1781         public Object newInstance(Object constructorParameter)
1782                 throws NoSuchAlgorithmException {
1783             if (registered == false) {
1784                 if (provider.getService(type, algorithm) != this) {
1785                     throw new NoSuchAlgorithmException
1786                         ("Service not registered with Provider "
1787                         + provider.getName() + ": " + this);
1788                 }
1789                 registered = true;
1790             }
1791             Class<?> ctrParamClz;
1792             try {
1793                 EngineDescription cap = knownEngines.get(type);
1794                 if (cap == null) {
1795                     // unknown engine type, use generic code
1796                     // this is the code path future for non-core
1797                     // optional packages
1798                     ctrParamClz = constructorParameter == null?
1799                         null : constructorParameter.getClass();
1800                 } else {
1801                     ctrParamClz = cap.constructorParameterClassName == null?
1802                         null : Class.forName(cap.constructorParameterClassName);
1803                     if (constructorParameter != null) {
1804                         if (ctrParamClz == null) {
1805                             throw new InvalidParameterException
1806                                 ("constructorParameter not used with " + type
1807                                 + " engines");
1808                         } else {
1809                             Class<?> argClass = constructorParameter.getClass();
1810                             if (ctrParamClz.isAssignableFrom(argClass) == false) {
1811                                 throw new InvalidParameterException
1812                                     ("constructorParameter must be instanceof "
1813                                     + cap.constructorParameterClassName.replace('$', '.')
1814                                     + " for engine type " + type);
1815                             }
1816                         }
1817                     }
1818                 }
1819                 // constructorParameter can be null if not provided
1820                 return newInstanceUtil(getImplClass(), ctrParamClz, constructorParameter);
1821             } catch (NoSuchAlgorithmException e) {
1822                 throw e;
1823             } catch (InvocationTargetException e) {
1824                 throw new NoSuchAlgorithmException
1825                     ("Error constructing implementation (algorithm: "
1826                     + algorithm + ", provider: " + provider.getName()
1827                     + ", class: " + className + ")", e.getCause());
1828             } catch (Exception e) {
1829                 throw new NoSuchAlgorithmException
1830                     ("Error constructing implementation (algorithm: "
1831                     + algorithm + ", provider: " + provider.getName()
1832                     + ", class: " + className + ")", e);
1833             }
1834         }
1835 
1836         // return the implementation Class object for this service
1837         private Class<?> getImplClass() throws NoSuchAlgorithmException {
1838             try {
1839                 Reference<Class<?>> ref = classRef;
1840                 Class<?> clazz = (ref == null) ? null : ref.get();
1841                 if (clazz == null) {
1842                     ClassLoader cl = provider.getClass().getClassLoader();
1843                     if (cl == null) {
1844                         clazz = Class.forName(className);
1845                     } else {
1846                         clazz = cl.loadClass(className);
1847                     }
1848                     if (!Modifier.isPublic(clazz.getModifiers())) {
1849                         throw new NoSuchAlgorithmException
1850                             ("class configured for " + type + " (provider: " +
1851                             provider.getName() + ") is not public.");
1852                     }
1853                     classRef = new WeakReference<>(clazz);
1854                 }
1855                 return clazz;
1856             } catch (ClassNotFoundException e) {
1857                 throw new NoSuchAlgorithmException
1858                     ("class configured for " + type + " (provider: " +
1859                     provider.getName() + ") cannot be found.", e);
1860             }
1861         }
1862 
1863         /**
1864          * Test whether this Service can use the specified parameter.
1865          * Returns false if this service cannot use the parameter. Returns
1866          * true if this service can use the parameter, if a fast test is
1867          * infeasible, or if the status is unknown.
1868          *
1869          * <p>The security provider framework uses this method with
1870          * some types of services to quickly exclude non-matching
1871          * implementations for consideration.
1872          * Applications will typically not need to call it.
1873          *
1874          * <p>For details and the values of parameter that are valid for the
1875          * various types of services see the top of this class and the
1876          * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
1877          * Java Cryptography Architecture API Specification &amp;
1878          * Reference</a>.
1879          * Security providers can override it to implement their own test.
1880          *
1881          * @param parameter the parameter to test
1882          *
1883          * @return false if this service cannot use the specified
1884          * parameter; true if it can possibly use the parameter
1885          *
1886          * @throws InvalidParameterException if the value of parameter is
1887          * invalid for this type of service or if this method cannot be
1888          * used with this type of service
1889          */
1890         public boolean supportsParameter(Object parameter) {
1891             EngineDescription cap = knownEngines.get(type);
1892             if (cap == null) {
1893                 // unknown engine type, return true by default
1894                 return true;
1895             }
1896             if (cap.supportsParameter == false) {
1897                 throw new InvalidParameterException("supportsParameter() not "
1898                     + "used with " + type + " engines");
1899             }
1900             // allow null for keys without attributes for compatibility
1901             if ((parameter != null) && (parameter instanceof Key == false)) {
1902                 throw new InvalidParameterException
1903                     ("Parameter must be instanceof Key for engine " + type);
1904             }
1905             if (hasKeyAttributes() == false) {
1906                 return true;
1907             }
1908             if (parameter == null) {
1909                 return false;
1910             }
1911             Key key = (Key)parameter;
1912             if (supportsKeyFormat(key)) {
1913                 return true;
1914             }
1915             if (supportsKeyClass(key)) {
1916                 return true;
1917             }
1918             return false;
1919         }
1920 
1921         /**
1922          * Return whether this service has its supported properties for
1923          * keys defined. Parses the attributes if not yet initialized.
1924          */
1925         private boolean hasKeyAttributes() {
1926             Boolean b = hasKeyAttributes;
1927             if (b == null) {
1928                 synchronized (this) {
1929                     String s;
1930                     s = getAttribute("SupportedKeyFormats");
1931                     if (s != null) {
1932                         supportedFormats = s.split("\\|");
1933                     }
1934                     s = getAttribute("SupportedKeyClasses");
1935                     if (s != null) {
1936                         String[] classNames = s.split("\\|");
1937                         List<Class<?>> classList =
1938                             new ArrayList<>(classNames.length);
1939                         for (String className : classNames) {
1940                             Class<?> clazz = getKeyClass(className);
1941                             if (clazz != null) {
1942                                 classList.add(clazz);
1943                             }
1944                         }
1945                         supportedClasses = classList.toArray(CLASS0);
1946                     }
1947                     boolean bool = (supportedFormats != null)
1948                         || (supportedClasses != null);
1949                     b = Boolean.valueOf(bool);
1950                     hasKeyAttributes = b;
1951                 }
1952             }
1953             return b.booleanValue();
1954         }
1955 
1956         // get the key class object of the specified name
1957         private Class<?> getKeyClass(String name) {
1958             try {
1959                 return Class.forName(name);
1960             } catch (ClassNotFoundException e) {
1961                 // ignore
1962             }
1963             try {
1964                 ClassLoader cl = provider.getClass().getClassLoader();
1965                 if (cl != null) {
1966                     return cl.loadClass(name);
1967                 }
1968             } catch (ClassNotFoundException e) {
1969                 // ignore
1970             }
1971             return null;
1972         }
1973 
1974         private boolean supportsKeyFormat(Key key) {
1975             if (supportedFormats == null) {
1976                 return false;
1977             }
1978             String format = key.getFormat();
1979             if (format == null) {
1980                 return false;
1981             }
1982             for (String supportedFormat : supportedFormats) {
1983                 if (supportedFormat.equals(format)) {
1984                     return true;
1985                 }
1986             }
1987             return false;
1988         }
1989 
1990         private boolean supportsKeyClass(Key key) {
1991             if (supportedClasses == null) {
1992                 return false;
1993             }
1994             Class<?> keyClass = key.getClass();
1995             for (Class<?> clazz : supportedClasses) {
1996                 if (clazz.isAssignableFrom(keyClass)) {
1997                     return true;
1998                 }
1999             }
2000             return false;
2001         }
2002 
2003         /**
2004          * Return a String representation of this service.
2005          *
2006          * @return a String representation of this service.
2007          */
2008         public String toString() {
2009             String aString = aliases.isEmpty()
2010                 ? "" : "\r\n  aliases: " + aliases.toString();
2011             String attrs = attributes.isEmpty()
2012                 ? "" : "\r\n  attributes: " + attributes.toString();
2013             return provider.getName() + ": " + type + "." + algorithm
2014                 + " -> " + className + aString + attrs + "\r\n";
2015         }
2016     }
2017 }