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