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="striped">
65  * <caption><b>Attributes Automatically Placed in a Provider Object</b></caption>
66  * <thead>
67  * <tr><th scope="col">Name</th><th scope="col">Value</th>
68  * </thead>
69  * <tbody style="text-align:left">
70  * <tr><th scope="row">{@code Provider.id name}</th>
71  *     <td>{@code String.valueOf(provider.getName())}</td>
72  * <tr><th scope="row">{@code Provider.id version}</th>
73  *     <td>{@code String.valueOf(provider.getVersionStr())}</td>
74  * <tr><th scope="row">{@code Provider.id info}</th>
75  *     <td>{@code String.valueOf(provider.getInfo())}</td>
76  * <tr><th scope="row">{@code Provider.id className}</th>
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 {@extLink security_guide_jca_provider
98  * The Provider Class}
99  * in the Java Cryptography Architecture (JCA) Reference Guide
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 nullif 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      * {@extLink security_guide_jca
1314      * Java Cryptography Architecture (JCA) Reference Guide}.
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",        falsenull);
1524         addEngine("AlgorithmParameters",                falsenull);
1525         addEngine("KeyFactory",                         falsenull);
1526         addEngine("KeyPairGenerator",                   falsenull);
1527         addEngine("KeyStore",                           falsenull);
1528         addEngine("MessageDigest",                      falsenull);
1529         addEngine("SecureRandom",                       false,
1530                 "java.security.SecureRandomParameters");
1531         addEngine("Signature",                          true,  null);
1532         addEngine("CertificateFactory",                 falsenull);
1533         addEngine("CertPathBuilder",                    falsenull);
1534         addEngine("CertPathValidator",                  falsenull);
1535         addEngine("CertStore",                          false,
1536                             "java.security.cert.CertStoreParameters");
1537         // JCE
1538         addEngine("Cipher",                             true,  null);
1539         addEngine("ExemptionMechanism",                 falsenull);
1540         addEngine("Mac",                                true,  null);
1541         addEngine("KeyAgreement",                       true,  null);
1542         addEngine("KeyGenerator",                       falsenull);
1543         addEngine("SecretKeyFactory",                   falsenull);
1544         // JSSE
1545         addEngine("KeyManagerFactory",                  falsenull);
1546         addEngine("SSLContext",                         falsenull);
1547         addEngine("TrustManagerFactory",                falsenull);
1548         // JGSS
1549         addEngine("GssApiMechanism",                    falsenull);
1550         // SASL
1551         addEngine("SaslClientFactory",                  falsenull);
1552         addEngine("SaslServerFactory",                  falsenull);
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",                falsenull);
1561         addEngine("KeyInfoFactory",                     falsenull);
1562         addEngine("TransformService",                   falsenull);
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      * {@extLink security_guide_jca
1597      * Java Cryptography Architecture (JCA) Reference Guide}
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          * {@extLink security_guide_jca
1773          * Java Cryptography Architecture (JCA) Reference Guide}.
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          * {@extLink security_guide_jca
1881          * Java Cryptography Architecture (JCA) Reference Guide}.
1882          * Security providers can override it to implement their own test.
1883          *
1884          * @param parameter the parameter to test
1885          *
1886          * @return false if this service cannot use the specified
1887          * parameter; true if it can possibly use the parameter
1888          *
1889          * @throws InvalidParameterException if the value of parameter is
1890          * invalid for this type of service or if this method cannot be
1891          * used with this type of service
1892          */

1893         public boolean supportsParameter(Object parameter) {
1894             EngineDescription cap = knownEngines.get(type);
1895             if (cap == null) {
1896                 // unknown engine type, return true by default
1897                 return true;
1898             }
1899             if (cap.supportsParameter == false) {
1900                 throw new InvalidParameterException("supportsParameter() not "
1901                     + "used with " + type + " engines");
1902             }
1903             // allow null for keys without attributes for compatibility
1904             if ((parameter != null) && (parameter instanceof Key == false)) {
1905                 throw new InvalidParameterException
1906                     ("Parameter must be instanceof Key for engine " + type);
1907             }
1908             if (hasKeyAttributes() == false) {
1909                 return true;
1910             }
1911             if (parameter == null) {
1912                 return false;
1913             }
1914             Key key = (Key)parameter;
1915             if (supportsKeyFormat(key)) {
1916                 return true;
1917             }
1918             if (supportsKeyClass(key)) {
1919                 return true;
1920             }
1921             return false;
1922         }
1923
1924         /**
1925          * Return whether this service has its supported properties for
1926          * keys defined. Parses the attributes if not yet initialized.
1927          */

1928         private boolean hasKeyAttributes() {
1929             Boolean b = hasKeyAttributes;
1930             if (b == null) {
1931                 synchronized (this) {
1932                     String s;
1933                     s = getAttribute("SupportedKeyFormats");
1934                     if (s != null) {
1935                         supportedFormats = s.split("\\|");
1936                     }
1937                     s = getAttribute("SupportedKeyClasses");
1938                     if (s != null) {
1939                         String[] classNames = s.split("\\|");
1940                         List<Class<?>> classList =
1941                             new ArrayList<>(classNames.length);
1942                         for (String className : classNames) {
1943                             Class<?> clazz = getKeyClass(className);
1944                             if (clazz != null) {
1945                                 classList.add(clazz);
1946                             }
1947                         }
1948                         supportedClasses = classList.toArray(CLASS0);
1949                     }
1950                     boolean bool = (supportedFormats != null)
1951                         || (supportedClasses != null);
1952                     b = Boolean.valueOf(bool);
1953                     hasKeyAttributes = b;
1954                 }
1955             }
1956             return b.booleanValue();
1957         }
1958
1959         // get the key class object of the specified name
1960         private Class<?> getKeyClass(String name) {
1961             try {
1962                 return Class.forName(name);
1963             } catch (ClassNotFoundException e) {
1964                 // ignore
1965             }
1966             try {
1967                 ClassLoader cl = provider.getClass().getClassLoader();
1968                 if (cl != null) {
1969                     return cl.loadClass(name);
1970                 }
1971             } catch (ClassNotFoundException e) {
1972                 // ignore
1973             }
1974             return null;
1975         }
1976
1977         private boolean supportsKeyFormat(Key key) {
1978             if (supportedFormats == null) {
1979                 return false;
1980             }
1981             String format = key.getFormat();
1982             if (format == null) {
1983                 return false;
1984             }
1985             for (String supportedFormat : supportedFormats) {
1986                 if (supportedFormat.equals(format)) {
1987                     return true;
1988                 }
1989             }
1990             return false;
1991         }
1992
1993         private boolean supportsKeyClass(Key key) {
1994             if (supportedClasses == null) {
1995                 return false;
1996             }
1997             Class<?> keyClass = key.getClass();
1998             for (Class<?> clazz : supportedClasses) {
1999                 if (clazz.isAssignableFrom(keyClass)) {
2000                     return true;
2001                 }
2002             }
2003             return false;
2004         }
2005
2006         /**
2007          * Return a String representation of this service.
2008          *
2009          * @return a String representation of this service.
2010          */

2011         public String toString() {
2012             String aString = aliases.isEmpty()
2013                 ? "" : "\r\n  aliases: " + aliases.toString();
2014             String attrs = attributes.isEmpty()
2015                 ? "" : "\r\n  attributes: " + attributes.toString();
2016             return provider.getName() + ": " + type + "." + algorithm
2017                 + " -> " + className + aString + attrs + "\r\n";
2018         }
2019     }
2020 }
2021