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