1 /*
2  * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
3  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4  *
5  *
6  *
7  *
8  *
9  *
10  *
11  *
12  *
13  *
14  *
15  *
16  *
17  *
18  *
19  *
20  *
21  *
22  *
23  *
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, MD5 or SHA-1).
45  *
46  * <li>Key generation, conversion, and management facilities (such as for
47  * algorithm-specific keys).
48  *
49  *</ul>
50  *
51  * <p>Each provider has a name and a version number, and is configured
52  * in each runtime it is installed in.
53  *
54  * <p>See <a href =
55  * "../../../technotes/guides/security/crypto/CryptoSpec.html#Provider">The Provider Class</a>
56  * in the "Java Cryptography Architecture API Specification &amp; Reference"
57  * for information about how a particular type of provider, the
58  * cryptographic service provider, works and is installed. However,
59  * please note that a provider can be used to implement any security
60  * service in Java that uses a pluggable architecture with a choice
61  * of implementations that fit underneath.
62  *
63  * <p>Some provider implementations may encounter unrecoverable internal
64  * errors during their operation, for example a failure to communicate with a
65  * security token. A {@link ProviderException} should be used to indicate
66  * such errors.
67  *
68  * <p>The service type {@code Provider} is reserved for use by the
69  * security framework. Services of this type cannot be added, removed,
70  * or modified by applications.
71  * The following attributes are automatically placed in each Provider object:
72  * <table cellspacing=4>
73  * <caption><b>Attributes Automatically Placed in a Provider Object</b></caption>
74  * <tr><th>Name</th><th>Value</th>
75  * <tr><td>{@code Provider.id name}</td>
76   *    <td>{@code String.valueOf(provider.getName())}</td>
77  * <tr><td>{@code Provider.id version}</td>
78  *     <td>{@code String.valueOf(provider.getVersion())}</td>
79  * <tr><td>{@code Provider.id info}</td>
80        <td>{@code String.valueOf(provider.getInfo())}</td>
81  * <tr><td>{@code Provider.id className}</td>
82  *     <td>{@code provider.getClass().getName()}</td>
83  * </table>
84  *
85  * @author Benjamin Renaud
86  * @author Andreas Sterbenz
87  */

88 public abstract class Provider extends Properties {
89
90     // Declare serialVersionUID to be compatible with JDK1.1
91     static final long serialVersionUID = -4298000515446427739L;
92
93     private static final sun.security.util.Debug debug =
94         sun.security.util.Debug.getInstance
95         ("provider""Provider");
96
97     /**
98      * The provider name.
99      *
100      * @serial
101      */

102     private String name;
103
104     /**
105      * A description of the provider and its services.
106      *
107      * @serial
108      */

109     private String info;
110
111     /**
112      * The provider version number.
113      *
114      * @serial
115      */

116     private double version;
117
118
119     private transient Set<Map.Entry<Object,Object>> entrySet = null;
120     private transient int entrySetCallCount = 0;
121
122     private transient boolean initialized;
123
124     /**
125      * Constructs a provider with the specified name, version number,
126      * and information.
127      *
128      * @param name the provider name.
129      *
130      * @param version the provider version number.
131      *
132      * @param info a description of the provider and its services.
133      */

134     protected Provider(String name, double version, String info) {
135         this.name = name;
136         this.version = version;
137         this.info = info;
138         putId();
139         initialized = true;
140     }
141
142     /**
143      * Returns the name of this provider.
144      *
145      * @return the name of this provider.
146      */

147     public String getName() {
148         return name;
149     }
150
151     /**
152      * Returns the version number for this provider.
153      *
154      * @return the version number for this provider.
155      */

156     public double getVersion() {
157         return version;
158     }
159
160     /**
161      * Returns a human-readable description of the provider and its
162      * services.  This may return an HTML page, with relevant links.
163      *
164      * @return a description of the provider and its services.
165      */

166     public String getInfo() {
167         return info;
168     }
169
170     /**
171      * Returns a string with the name and the version number
172      * of this provider.
173      *
174      * @return the string with the name and the version number
175      * for this provider.
176      */

177     public String toString() {
178         return name + " version " + version;
179     }
180
181     /*
182      * override the following methods to ensure that provider
183      * information can only be changed if the caller has the appropriate
184      * permissions.
185      */

186
187     /**
188      * Clears this provider so that it no longer contains the properties
189      * used to look up facilities implemented by the provider.
190      *
191      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
192      * method is called with the string {@code "clearProviderProperties."+name}
193      * (where {@code name} is the provider name) to see if it's ok to clear
194      * this provider.
195      *
196      * @throws  SecurityException
197      *          if a security manager exists and its {@link
198      *          java.lang.SecurityManager#checkSecurityAccess} method
199      *          denies access to clear this provider
200      *
201      * @since 1.2
202      */

203     @Override
204     public synchronized void clear() {
205         check("clearProviderProperties."+name);
206         if (debug != null) {
207             debug.println("Remove " + name + " provider properties");
208         }
209         implClear();
210     }
211
212     /**
213      * Reads a property list (key and element pairs) from the input stream.
214      *
215      * @param inStream   the input stream.
216      * @exception  IOException  if an error occurred when reading from the
217      *               input stream.
218      * @see java.util.Properties#load
219      */

220     @Override
221     public synchronized void load(InputStream inStream) throws IOException {
222         check("putProviderProperty."+name);
223         if (debug != null) {
224             debug.println("Load " + name + " provider properties");
225         }
226         Properties tempProperties = new Properties();
227         tempProperties.load(inStream);
228         implPutAll(tempProperties);
229     }
230
231     /**
232      * Copies all of the mappings from the specified Map to this provider.
233      * These mappings will replace any properties that this provider had
234      * for any of the keys currently in the specified Map.
235      *
236      * @since 1.2
237      */

238     @Override
239     public synchronized void putAll(Map<?,?> t) {
240         check("putProviderProperty."+name);
241         if (debug != null) {
242             debug.println("Put all " + name + " provider properties");
243         }
244         implPutAll(t);
245     }
246
247     /**
248      * Returns an unmodifiable Set view of the property entries contained
249      * in this Provider.
250      *
251      * @see   java.util.Map.Entry
252      * @since 1.2
253      */

254     @Override
255     public synchronized Set<Map.Entry<Object,Object>> entrySet() {
256         checkInitialized();
257         if (entrySet == null) {
258             if (entrySetCallCount++ == 0)  // Initial call
259                 entrySet = Collections.unmodifiableMap(this).entrySet();
260             else
261                 return super.entrySet();   // Recursive call
262         }
263
264         // This exception will be thrown if the implementation of
265         // Collections.unmodifiableMap.entrySet() is changed such that it
266         // no longer calls entrySet() on the backing Map.  (Provider's
267         // entrySet implementation depends on this "implementation detail",
268         // which is unlikely to change.
269         if (entrySetCallCount != 2)
270             throw new RuntimeException("Internal error.");
271
272         return entrySet;
273     }
274
275     /**
276      * Returns an unmodifiable Set view of the property keys contained in
277      * this provider.
278      *
279      * @since 1.2
280      */

281     @Override
282     public Set<Object> keySet() {
283         checkInitialized();
284         return Collections.unmodifiableSet(super.keySet());
285     }
286
287     /**
288      * Returns an unmodifiable Collection view of the property values
289      * contained in this provider.
290      *
291      * @since 1.2
292      */

293     @Override
294     public Collection<Object> values() {
295         checkInitialized();
296         return Collections.unmodifiableCollection(super.values());
297     }
298
299     /**
300      * Sets the {@code key} property to have the specified
301      * {@code value}.
302      *
303      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
304      * method is called with the string {@code "putProviderProperty."+name},
305      * where {@code name} is the provider name, to see if it's ok to set this
306      * provider's property values.
307      *
308      * @throws  SecurityException
309      *          if a security manager exists and its {@link
310      *          java.lang.SecurityManager#checkSecurityAccess} method
311      *          denies access to set property values.
312      *
313      * @since 1.2
314      */

315     @Override
316     public synchronized Object put(Object key, Object value) {
317         check("putProviderProperty."+name);
318         if (debug != null) {
319             debug.println("Set " + name + " provider property [" +
320                           key + "/" + value +"]");
321         }
322         return implPut(key, value);
323     }
324
325     /**
326      * If the specified key is not already associated with a value (or is mapped
327      * to {@code null}) associates it with the given value and returns
328      * {@code null}, else returns the current value.
329      *
330      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
331      * method is called with the string {@code "putProviderProperty."+name},
332      * where {@code name} is the provider name, to see if it's ok to set this
333      * provider's property values.
334      *
335      * @throws  SecurityException
336      *          if a security manager exists and its {@link
337      *          java.lang.SecurityManager#checkSecurityAccess} method
338      *          denies access to set property values.
339      *
340      * @since 1.8
341      */

342     @Override
343     public synchronized Object putIfAbsent(Object key, Object value) {
344         check("putProviderProperty."+name);
345         if (debug != null) {
346             debug.println("Set " + name + " provider property [" +
347                           key + "/" + value +"]");
348         }
349         return implPutIfAbsent(key, value);
350     }
351
352     /**
353      * Removes the {@code key} property (and its corresponding
354      * {@code value}).
355      *
356      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
357      * method is called with the string {@code "removeProviderProperty."+name},
358      * where {@code name} is the provider name, to see if it's ok to remove this
359      * provider's properties.
360      *
361      * @throws  SecurityException
362      *          if a security manager exists and its {@link
363      *          java.lang.SecurityManager#checkSecurityAccess} method
364      *          denies access to remove this provider's properties.
365      *
366      * @since 1.2
367      */

368     @Override
369     public synchronized Object remove(Object key) {
370         check("removeProviderProperty."+name);
371         if (debug != null) {
372             debug.println("Remove " + name + " provider property " + key);
373         }
374         return implRemove(key);
375     }
376
377     /**
378      * Removes the entry for the specified key only if it is currently
379      * mapped to the specified value.
380      *
381      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
382      * method is called with the string {@code "removeProviderProperty."+name},
383      * where {@code name} is the provider name, to see if it's ok to remove this
384      * provider's properties.
385      *
386      * @throws  SecurityException
387      *          if a security manager exists and its {@link
388      *          java.lang.SecurityManager#checkSecurityAccess} method
389      *          denies access to remove this provider's properties.
390      *
391      * @since 1.8
392      */

393     @Override
394     public synchronized boolean remove(Object key, Object value) {
395         check("removeProviderProperty."+name);
396         if (debug != null) {
397             debug.println("Remove " + name + " provider property " + key);
398         }
399         return implRemove(key, value);
400     }
401
402     /**
403      * Replaces the entry for the specified key only if currently
404      * mapped to the specified value.
405      *
406      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
407      * method is called with the string {@code "putProviderProperty."+name},
408      * where {@code name} is the provider name, to see if it's ok to set this
409      * provider's property values.
410      *
411      * @throws  SecurityException
412      *          if a security manager exists and its {@link
413      *          java.lang.SecurityManager#checkSecurityAccess} method
414      *          denies access to set property values.
415      *
416      * @since 1.8
417      */

418     @Override
419     public synchronized boolean replace(Object key, Object oldValue,
420             Object newValue) {
421         check("putProviderProperty." + name);
422
423         if (debug != null) {
424             debug.println("Replace " + name + " provider property " + key);
425         }
426         return implReplace(key, oldValue, newValue);
427     }
428
429     /**
430      * Replaces the entry for the specified key only if it is
431      * currently mapped to some value.
432      *
433      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
434      * method is called with the string {@code "putProviderProperty."+name},
435      * where {@code name} is the provider name, to see if it's ok to set this
436      * provider's property values.
437      *
438      * @throws  SecurityException
439      *          if a security manager exists and its {@link
440      *          java.lang.SecurityManager#checkSecurityAccess} method
441      *          denies access to set property values.
442      *
443      * @since 1.8
444      */

445     @Override
446     public synchronized Object replace(Object key, Object value) {
447         check("putProviderProperty." + name);
448
449         if (debug != null) {
450             debug.println("Replace " + name + " provider property " + key);
451         }
452         return implReplace(key, value);
453     }
454
455     /**
456      * Replaces each entry's value with the result of invoking the given
457      * function on that entry, in the order entries are returned by an entry
458      * set iterator, until all entries have been processed or the function
459      * throws an exception.
460      *
461      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
462      * method is called with the string {@code "putProviderProperty."+name},
463      * where {@code name} is the provider name, to see if it's ok to set this
464      * provider's property values.
465      *
466      * @throws  SecurityException
467      *          if a security manager exists and its {@link
468      *          java.lang.SecurityManager#checkSecurityAccess} method
469      *          denies access to set property values.
470      *
471      * @since 1.8
472      */

473     @Override
474     public synchronized void replaceAll(BiFunction<? super Object, ? super Object, ? extends Object> function) {
475         check("putProviderProperty." + name);
476
477         if (debug != null) {
478             debug.println("ReplaceAll " + name + " provider property ");
479         }
480         implReplaceAll(function);
481     }
482
483     /**
484      * Attempts to compute a mapping for the specified key and its
485      * current mapped value (or {@code nullif there is no current
486      * mapping).
487      *
488      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
489      * method is called with the strings {@code "putProviderProperty."+name}
490      * and {@code "removeProviderProperty."+name}, where {@code name} is the
491      * provider name, to see if it's ok to set this provider's property values
492      * and remove this provider's properties.
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 or remove properties.
498      *
499      * @since 1.8
500      */

501     @Override
502     public synchronized Object compute(Object key,
503         BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
504         check("putProviderProperty." + name);
505         check("removeProviderProperty" + name);
506
507         if (debug != null) {
508             debug.println("Compute " + name + " provider property " + key);
509         }
510         return implCompute(key, remappingFunction);
511     }
512
513     /**
514      * If the specified key is not already associated with a value (or
515      * is mapped to {@code null}), attempts to compute its value using
516      * the given mapping function and enters it into this map unless
517      * {@code null}.
518      *
519      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
520      * method is called with the strings {@code "putProviderProperty."+name}
521      * and {@code "removeProviderProperty."+name}, where {@code name} is the
522      * provider name, to see if it's ok to set this provider's property values
523      * and remove this provider's properties.
524      *
525      * @throws  SecurityException
526      *          if a security manager exists and its {@link
527      *          java.lang.SecurityManager#checkSecurityAccess} method
528      *          denies access to set property values and remove properties.
529      *
530      * @since 1.8
531      */

532     @Override
533     public synchronized Object computeIfAbsent(Object key, Function<? super Object, ? extends Object> mappingFunction) {
534         check("putProviderProperty." + name);
535         check("removeProviderProperty" + name);
536
537         if (debug != null) {
538             debug.println("ComputeIfAbsent " + name + " provider property " +
539                     key);
540         }
541         return implComputeIfAbsent(key, mappingFunction);
542     }
543
544     /**
545      * If the value for the specified key is present and non-null, attempts to
546      * compute a new mapping given the key and its current mapped value.
547      *
548      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
549      * method is called with the strings {@code "putProviderProperty."+name}
550      * and {@code "removeProviderProperty."+name}, where {@code name} is the
551      * provider name, to see if it's ok to set this provider's property values
552      * and remove this provider's properties.
553      *
554      * @throws  SecurityException
555      *          if a security manager exists and its {@link
556      *          java.lang.SecurityManager#checkSecurityAccess} method
557      *          denies access to set property values or remove properties.
558      *
559      * @since 1.8
560      */

561     @Override
562     public synchronized Object computeIfPresent(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
563         check("putProviderProperty." + name);
564         check("removeProviderProperty" + name);
565
566         if (debug != null) {
567             debug.println("ComputeIfPresent " + name + " provider property " +
568                     key);
569         }
570         return implComputeIfPresent(key, remappingFunction);
571     }
572
573     /**
574      * If the specified key is not already associated with a value or is
575      * associated with null, associates it with the given value. Otherwise,
576      * replaces the value with the results of the given remapping function,
577      * or removes if the result is null. This method may be of use when
578      * combining multiple mapped values for a key.
579      *
580      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
581      * method is called with the strings {@code "putProviderProperty."+name}
582      * and {@code "removeProviderProperty."+name}, where {@code name} is the
583      * provider name, to see if it's ok to set this provider's property values
584      * and remove this provider's properties.
585      *
586      * @throws  SecurityException
587      *          if a security manager exists and its {@link
588      *          java.lang.SecurityManager#checkSecurityAccess} method
589      *          denies access to set property values or remove properties.
590      *
591      * @since 1.8
592      */

593     @Override
594     public synchronized Object merge(Object key, Object value,  BiFunction<? super Object, ? super Object, ? extends Object>  remappingFunction) {
595         check("putProviderProperty." + name);
596         check("removeProviderProperty" + name);
597
598         if (debug != null) {
599             debug.println("Merge " + name + " provider property " + key);
600         }
601         return implMerge(key, value, remappingFunction);
602     }
603
604     // let javadoc show doc from superclass
605     @Override
606     public Object get(Object key) {
607         checkInitialized();
608         return super.get(key);
609     }
610     /**
611      * @since 1.8
612      */

613     @Override
614     public synchronized Object getOrDefault(Object key, Object defaultValue) {
615         checkInitialized();
616         return super.getOrDefault(key, defaultValue);
617     }
618
619     /**
620      * @since 1.8
621      */

622     @Override
623     public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) {
624         checkInitialized();
625         super.forEach(action);
626     }
627
628     // let javadoc show doc from superclass
629     @Override
630     public Enumeration<Object> keys() {
631         checkInitialized();
632         return super.keys();
633     }
634
635     // let javadoc show doc from superclass
636     @Override
637     public Enumeration<Object> elements() {
638         checkInitialized();
639         return super.elements();
640     }
641
642     // let javadoc show doc from superclass
643     public String getProperty(String key) {
644         checkInitialized();
645         return super.getProperty(key);
646     }
647
648     private void checkInitialized() {
649         if (!initialized) {
650             throw new IllegalStateException();
651         }
652     }
653
654     private void check(String directive) {
655         checkInitialized();
656         SecurityManager security = System.getSecurityManager();
657         if (security != null) {
658             security.checkSecurityAccess(directive);
659         }
660     }
661
662     // legacy properties changed since last call to any services method?
663     private transient boolean legacyChanged;
664     // serviceMap changed since last call to getServices()
665     private transient boolean servicesChanged;
666
667     // Map<String,String>
668     private transient Map<String,String> legacyStrings;
669
670     // Map<ServiceKey,Service>
671     // used for services added via putService(), initialized on demand
672     private transient Map<ServiceKey,Service> serviceMap;
673
674     // Map<ServiceKey,Service>
675     // used for services added via legacy methods, init on demand
676     private transient Map<ServiceKey,Service> legacyMap;
677
678     // Set<Service>
679     // Unmodifiable set of all services. Initialized on demand.
680     private transient Set<Service> serviceSet;
681
682     // register the id attributes for this provider
683     // this is to ensure that equals() and hashCode() do not incorrectly
684     // report to different provider objects as the same
685     private void putId() {
686         // note: name and info may be null
687         super.put("Provider.id name", String.valueOf(name));
688         super.put("Provider.id version", String.valueOf(version));
689         super.put("Provider.id info", String.valueOf(info));
690         super.put("Provider.id className"this.getClass().getName());
691     }
692
693     private void readObject(ObjectInputStream in)
694                 throws IOException, ClassNotFoundException {
695         Map<Object,Object> copy = new HashMap<>();
696         for (Map.Entry<Object,Object> entry : super.entrySet()) {
697             copy.put(entry.getKey(), entry.getValue());
698         }
699         defaults = null;
700         in.defaultReadObject();
701         implClear();
702         initialized = true;
703         putAll(copy);
704     }
705
706     private boolean checkLegacy(Object key) {
707         String keyString = (String)key;
708         if (keyString.startsWith("Provider.")) {
709             return false;
710         }
711
712         legacyChanged = true;
713         if (legacyStrings == null) {
714             legacyStrings = new LinkedHashMap<String,String>();
715         }
716         return true;
717     }
718
719     /**
720      * Copies all of the mappings from the specified Map to this provider.
721      * Internal method to be called AFTER the security check has been
722      * performed.
723      */

724     private void implPutAll(Map<?,?> t) {
725         for (Map.Entry<?,?> e : t.entrySet()) {
726             implPut(e.getKey(), e.getValue());
727         }
728     }
729
730     private Object implRemove(Object key) {
731         if (key instanceof String) {
732             if (!checkLegacy(key)) {
733                 return null;
734             }
735             legacyStrings.remove((String)key);
736         }
737         return super.remove(key);
738     }
739
740     private boolean implRemove(Object key, Object value) {
741         if (key instanceof String && value instanceof String) {
742             if (!checkLegacy(key)) {
743                 return false;
744             }
745             legacyStrings.remove((String)key, value);
746         }
747         return super.remove(key, value);
748     }
749
750     private boolean implReplace(Object key, Object oldValue, Object newValue) {
751         if ((key instanceof String) && (oldValue instanceof String) &&
752                 (newValue instanceof String)) {
753             if (!checkLegacy(key)) {
754                 return false;
755             }
756             legacyStrings.replace((String)key, (String)oldValue,
757                     (String)newValue);
758         }
759         return super.replace(key, oldValue, newValue);
760     }
761
762     private Object implReplace(Object key, Object value) {
763         if ((key instanceof String) && (value instanceof String)) {
764             if (!checkLegacy(key)) {
765                 return null;
766             }
767             legacyStrings.replace((String)key, (String)value);
768         }
769         return super.replace(key, value);
770     }
771
772     private void implReplaceAll(BiFunction<? super Object, ? super Object, ? extends Object> function) {
773         legacyChanged = true;
774         if (legacyStrings == null) {
775             legacyStrings = new LinkedHashMap<String,String>();
776         } else {
777             legacyStrings.replaceAll((BiFunction<? super String, ? super String, ? extends String>) function);
778         }
779         super.replaceAll(function);
780     }
781
782
783     private Object implMerge(Object key, Object value, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
784         if ((key instanceof String) && (value instanceof String)) {
785             if (!checkLegacy(key)) {
786                 return null;
787             }
788             legacyStrings.merge((String)key, (String)value,
789                     (BiFunction<? super String, ? super String, ? extends String>) remappingFunction);
790         }
791         return super.merge(key, value, remappingFunction);
792     }
793
794     private Object implCompute(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
795         if (key instanceof String) {
796             if (!checkLegacy(key)) {
797                 return null;
798             }
799             legacyStrings.computeIfAbsent((String) key,
800                     (Function<? super String, ? extends String>) remappingFunction);
801         }
802         return super.compute(key, remappingFunction);
803     }
804
805     private Object implComputeIfAbsent(Object key, Function<? super Object, ? extends Object> mappingFunction) {
806         if (key instanceof String) {
807             if (!checkLegacy(key)) {
808                 return null;
809             }
810             legacyStrings.computeIfAbsent((String) key,
811                     (Function<? super String, ? extends String>) mappingFunction);
812         }
813         return super.computeIfAbsent(key, mappingFunction);
814     }
815
816     private Object implComputeIfPresent(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
817         if (key instanceof String) {
818             if (!checkLegacy(key)) {
819                 return null;
820             }
821             legacyStrings.computeIfPresent((String) key,
822                     (BiFunction<? super String, ? super String, ? extends String>) remappingFunction);
823         }
824         return super.computeIfPresent(key, remappingFunction);
825     }
826
827     private Object implPut(Object key, Object value) {
828         if ((key instanceof String) && (value instanceof String)) {
829             if (!checkLegacy(key)) {
830                 return null;
831             }
832             legacyStrings.put((String)key, (String)value);
833         }
834         return super.put(key, value);
835     }
836
837     private Object implPutIfAbsent(Object key, Object value) {
838         if ((key instanceof String) && (value instanceof String)) {
839             if (!checkLegacy(key)) {
840                 return null;
841             }
842             legacyStrings.putIfAbsent((String)key, (String)value);
843         }
844         return super.putIfAbsent(key, value);
845     }
846
847     private void implClear() {
848         if (legacyStrings != null) {
849             legacyStrings.clear();
850         }
851         if (legacyMap != null) {
852             legacyMap.clear();
853         }
854         if (serviceMap != null) {
855             serviceMap.clear();
856         }
857         legacyChanged = false;
858         servicesChanged = false;
859         serviceSet = null;
860         super.clear();
861         putId();
862     }
863
864     // used as key in the serviceMap and legacyMap HashMaps
865     private static class ServiceKey {
866         private final String type;
867         private final String algorithm;
868         private final String originalAlgorithm;
869         private ServiceKey(String type, String algorithm, boolean intern) {
870             this.type = type;
871             this.originalAlgorithm = algorithm;
872             algorithm = algorithm.toUpperCase(ENGLISH);
873             this.algorithm = intern ? algorithm.intern() : algorithm;
874         }
875         public int hashCode() {
876             return type.hashCode() + algorithm.hashCode();
877         }
878         public boolean equals(Object obj) {
879             if (this == obj) {
880                 return true;
881             }
882             if (obj instanceof ServiceKey == false) {
883                 return false;
884             }
885             ServiceKey other = (ServiceKey)obj;
886             return this.type.equals(other.type)
887                 && this.algorithm.equals(other.algorithm);
888         }
889         boolean matches(String type, String algorithm) {
890             return (this.type == type) && (this.originalAlgorithm == algorithm);
891         }
892     }
893
894     /**
895      * Ensure all the legacy String properties are fully parsed into
896      * service objects.
897      */

898     private void ensureLegacyParsed() {
899         if ((legacyChanged == false) || (legacyStrings == null)) {
900             return;
901         }
902         serviceSet = null;
903         if (legacyMap == null) {
904             legacyMap = new LinkedHashMap<ServiceKey,Service>();
905         } else {
906             legacyMap.clear();
907         }
908         for (Map.Entry<String,String> entry : legacyStrings.entrySet()) {
909             parseLegacyPut(entry.getKey(), entry.getValue());
910         }
911         removeInvalidServices(legacyMap);
912         legacyChanged = false;
913     }
914
915     /**
916      * Remove all invalid services from the Map. Invalid services can only
917      * occur if the legacy properties are inconsistent or incomplete.
918      */

919     private void removeInvalidServices(Map<ServiceKey,Service> map) {
920         for (Iterator<Map.Entry<ServiceKey, Service>> t =
921                 map.entrySet().iterator(); t.hasNext(); ) {
922             Service s = t.next().getValue();
923             if (s.isValid() == false) {
924                 t.remove();
925             }
926         }
927     }
928
929     private String[] getTypeAndAlgorithm(String key) {
930         int i = key.indexOf(".");
931         if (i < 1) {
932             if (debug != null) {
933                 debug.println("Ignoring invalid entry in provider "
934                         + name + ":" + key);
935             }
936             return null;
937         }
938         String type = key.substring(0, i);
939         String alg = key.substring(i + 1);
940         return new String[] {type, alg};
941     }
942
943     private final static String ALIAS_PREFIX = "Alg.Alias.";
944     private final static String ALIAS_PREFIX_LOWER = "alg.alias.";
945     private final static int ALIAS_LENGTH = ALIAS_PREFIX.length();
946
947     private void parseLegacyPut(String name, String value) {
948         if (name.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) {
949             // e.g. put("Alg.Alias.MessageDigest.SHA""SHA-1");
950             // aliasKey ~ MessageDigest.SHA
951             String stdAlg = value;
952             String aliasKey = name.substring(ALIAS_LENGTH);
953             String[] typeAndAlg = getTypeAndAlgorithm(aliasKey);
954             if (typeAndAlg == null) {
955                 return;
956             }
957             String type = getEngineName(typeAndAlg[0]);
958             String aliasAlg = typeAndAlg[1].intern();
959             ServiceKey key = new ServiceKey(type, stdAlg, true);
960             Service s = legacyMap.get(key);
961             if (s == null) {
962                 s = new Service(this);
963                 s.type = type;
964                 s.algorithm = stdAlg;
965                 legacyMap.put(key, s);
966             }
967             legacyMap.put(new ServiceKey(type, aliasAlg, true), s);
968             s.addAlias(aliasAlg);
969         } else {
970             String[] typeAndAlg = getTypeAndAlgorithm(name);
971             if (typeAndAlg == null) {
972                 return;
973             }
974             int i = typeAndAlg[1].indexOf(' ');
975             if (i == -1) {
976                 // e.g. put("MessageDigest.SHA-1""sun.security.provider.SHA");
977                 String type = getEngineName(typeAndAlg[0]);
978                 String stdAlg = typeAndAlg[1].intern();
979                 String className = value;
980                 ServiceKey key = new ServiceKey(type, stdAlg, true);
981                 Service s = legacyMap.get(key);
982                 if (s == null) {
983                     s = new Service(this);
984                     s.type = type;
985                     s.algorithm = stdAlg;
986                     legacyMap.put(key, s);
987                 }
988                 s.className = className;
989             } else { // attribute
990                 // e.g. put("MessageDigest.SHA-1 ImplementedIn""Software");
991                 String attributeValue = value;
992                 String type = getEngineName(typeAndAlg[0]);
993                 String attributeString = typeAndAlg[1];
994                 String stdAlg = attributeString.substring(0, i).intern();
995                 String attributeName = attributeString.substring(i + 1);
996                 // kill additional spaces
997                 while (attributeName.startsWith(" ")) {
998                     attributeName = attributeName.substring(1);
999                 }
1000                 attributeName = attributeName.intern();
1001                 ServiceKey key = new ServiceKey(type, stdAlg, true);
1002                 Service s = legacyMap.get(key);
1003                 if (s == null) {
1004                     s = new Service(this);
1005                     s.type = type;
1006                     s.algorithm = stdAlg;
1007                     legacyMap.put(key, s);
1008                 }
1009                 s.addAttribute(attributeName, attributeValue);
1010             }
1011         }
1012     }
1013
1014     /**
1015      * Get the service describing this Provider's implementation of the
1016      * specified type of this algorithm or alias. If no such
1017      * implementation exists, this method returns null. If there are two
1018      * matching services, one added to this provider using
1019      * {@link #putService putService()} and one added via {@link #put put()},
1020      * the service added via {@link #putService putService()} is returned.
1021      *
1022      * @param type the type of {@link Service service} requested
1023      * (for example, {@code MessageDigest})
1024      * @param algorithm the case insensitive algorithm name (or alternate
1025      * alias) of the service requested (for example, {@code SHA-1})
1026      *
1027      * @return the service describing this Provider's matching service
1028      * or null if no such service exists
1029      *
1030      * @throws NullPointerException if type or algorithm is null
1031      *
1032      * @since 1.5
1033      */

1034     public synchronized Service getService(String type, String algorithm) {
1035         checkInitialized();
1036         // avoid allocating a new key object if possible
1037         ServiceKey key = previousKey;
1038         if (key.matches(type, algorithm) == false) {
1039             key = new ServiceKey(type, algorithm, false);
1040             previousKey = key;
1041         }
1042         if (serviceMap != null) {
1043             Service service = serviceMap.get(key);
1044             if (service != null) {
1045                 return service;
1046             }
1047         }
1048         ensureLegacyParsed();
1049         return (legacyMap != null) ? legacyMap.get(key) : null;
1050     }
1051
1052     // ServiceKey from previous getService() call
1053     // by re-using it if possible we avoid allocating a new object
1054     // and the toUpperCase() call.
1055     // re-use will occur e.g. as the framework traverses the provider
1056     // list and queries each provider with the same values until it finds
1057     // a matching service
1058     private static volatile ServiceKey previousKey =
1059                                             new ServiceKey(""""false);
1060
1061     /**
1062      * Get an unmodifiable Set of all services supported by
1063      * this Provider.
1064      *
1065      * @return an unmodifiable Set of all services supported by
1066      * this Provider
1067      *
1068      * @since 1.5
1069      */

1070     public synchronized Set<Service> getServices() {
1071         checkInitialized();
1072         if (legacyChanged || servicesChanged) {
1073             serviceSet = null;
1074         }
1075         if (serviceSet == null) {
1076             ensureLegacyParsed();
1077             Set<Service> set = new LinkedHashSet<>();
1078             if (serviceMap != null) {
1079                 set.addAll(serviceMap.values());
1080             }
1081             if (legacyMap != null) {
1082                 set.addAll(legacyMap.values());
1083             }
1084             serviceSet = Collections.unmodifiableSet(set);
1085             servicesChanged = false;
1086         }
1087         return serviceSet;
1088     }
1089
1090     /**
1091      * Add a service. If a service of the same type with the same algorithm
1092      * name exists and it was added using {@link #putService putService()},
1093      * it is replaced by the new service.
1094      * This method also places information about this service
1095      * in the provider's Hashtable values in the format described in the
1096      * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
1097      * Java Cryptography Architecture API Specification &amp; Reference </a>.
1098      *
1099      * <p>Also, if there is a security manager, its
1100      * {@code checkSecurityAccess} method is called with the string
1101      * {@code "putProviderProperty."+name}, where {@code name} is
1102      * the provider name, to see if it's ok to set this provider's property
1103      * values. If the default implementation of {@code checkSecurityAccess}
1104      * is used (that is, that method is not overriden), then this results in
1105      * a call to the security manager's {@code checkPermission} method with
1106      * a {@code SecurityPermission("putProviderProperty."+name)}
1107      * permission.
1108      *
1109      * @param s the Service to add
1110      *
1111      * @throws SecurityException
1112      *      if a security manager exists and its {@link
1113      *      java.lang.SecurityManager#checkSecurityAccess} method denies
1114      *      access to set property values.
1115      * @throws NullPointerException if s is null
1116      *
1117      * @since 1.5
1118      */

1119     protected synchronized void putService(Service s) {
1120         check("putProviderProperty." + name);
1121         if (debug != null) {
1122             debug.println(name + ".putService(): " + s);
1123         }
1124         if (s == null) {
1125             throw new NullPointerException();
1126         }
1127         if (s.getProvider() != this) {
1128             throw new IllegalArgumentException
1129                     ("service.getProvider() must match this Provider object");
1130         }
1131         if (serviceMap == null) {
1132             serviceMap = new LinkedHashMap<ServiceKey,Service>();
1133         }
1134         servicesChanged = true;
1135         String type = s.getType();
1136         String algorithm = s.getAlgorithm();
1137         ServiceKey key = new ServiceKey(type, algorithm, true);
1138         // remove existing service
1139         implRemoveService(serviceMap.get(key));
1140         serviceMap.put(key, s);
1141         for (String alias : s.getAliases()) {
1142             serviceMap.put(new ServiceKey(type, alias, true), s);
1143         }
1144         putPropertyStrings(s);
1145     }
1146
1147     /**
1148      * Put the string properties for this Service in this Provider's
1149      * Hashtable.
1150      */

1151     private void putPropertyStrings(Service s) {
1152         String type = s.getType();
1153         String algorithm = s.getAlgorithm();
1154         // use super() to avoid permission check and other processing
1155         super.put(type + "." + algorithm, s.getClassName());
1156         for (String alias : s.getAliases()) {
1157             super.put(ALIAS_PREFIX + type + "." + alias, algorithm);
1158         }
1159         for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
1160             String key = type + "." + algorithm + " " + entry.getKey();
1161             super.put(key, entry.getValue());
1162         }
1163     }
1164
1165     /**
1166      * Remove the string properties for this Service from this Provider's
1167      * Hashtable.
1168      */

1169     private void removePropertyStrings(Service s) {
1170         String type = s.getType();
1171         String algorithm = s.getAlgorithm();
1172         // use super() to avoid permission check and other processing
1173         super.remove(type + "." + algorithm);
1174         for (String alias : s.getAliases()) {
1175             super.remove(ALIAS_PREFIX + type + "." + alias);
1176         }
1177         for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
1178             String key = type + "." + algorithm + " " + entry.getKey();
1179             super.remove(key);
1180         }
1181     }
1182
1183     /**
1184      * Remove a service previously added using
1185      * {@link #putService putService()}. The specified service is removed from
1186      * this provider. It will no longer be returned by
1187      * {@link #getService getService()} and its information will be removed
1188      * from this provider's Hashtable.
1189      *
1190      * <p>Also, if there is a security manager, its
1191      * {@code checkSecurityAccess} method is called with the string
1192      * {@code "removeProviderProperty."+name}, where {@code name} is
1193      * the provider name, to see if it's ok to remove this provider's
1194      * properties. If the default implementation of
1195      * {@code checkSecurityAccess} is used (that is, that method is not
1196      * overriden), then this results in a call to the security manager's
1197      * {@code checkPermission} method with a
1198      * {@code SecurityPermission("removeProviderProperty."+name)}
1199      * permission.
1200      *
1201      * @param s the Service to be removed
1202      *
1203      * @throws  SecurityException
1204      *          if a security manager exists and its {@link
1205      *          java.lang.SecurityManager#checkSecurityAccess} method denies
1206      *          access to remove this provider's properties.
1207      * @throws NullPointerException if s is null
1208      *
1209      * @since 1.5
1210      */

1211     protected synchronized void removeService(Service s) {
1212         check("removeProviderProperty." + name);
1213         if (debug != null) {
1214             debug.println(name + ".removeService(): " + s);
1215         }
1216         if (s == null) {
1217             throw new NullPointerException();
1218         }
1219         implRemoveService(s);
1220     }
1221
1222     private void implRemoveService(Service s) {
1223         if ((s == null) || (serviceMap == null)) {
1224             return;
1225         }
1226         String type = s.getType();
1227         String algorithm = s.getAlgorithm();
1228         ServiceKey key = new ServiceKey(type, algorithm, false);
1229         Service oldService = serviceMap.get(key);
1230         if (s != oldService) {
1231             return;
1232         }
1233         servicesChanged = true;
1234         serviceMap.remove(key);
1235         for (String alias : s.getAliases()) {
1236             serviceMap.remove(new ServiceKey(type, alias, false));
1237         }
1238         removePropertyStrings(s);
1239     }
1240
1241     // Wrapped String that behaves in a case insensitive way for equals/hashCode
1242     private static class UString {
1243         final String string;
1244         final String lowerString;
1245
1246         UString(String s) {
1247             this.string = s;
1248             this.lowerString = s.toLowerCase(ENGLISH);
1249         }
1250
1251         public int hashCode() {
1252             return lowerString.hashCode();
1253         }
1254
1255         public boolean equals(Object obj) {
1256             if (this == obj) {
1257                 return true;
1258             }
1259             if (obj instanceof UString == false) {
1260                 return false;
1261             }
1262             UString other = (UString)obj;
1263             return lowerString.equals(other.lowerString);
1264         }
1265
1266         public String toString() {
1267             return string;
1268         }
1269     }
1270
1271     // describe relevant properties of a type of engine
1272     private static class EngineDescription {
1273         final String name;
1274         final boolean supportsParameter;
1275         final String constructorParameterClassName;
1276         private volatile Class<?> constructorParameterClass;
1277
1278         EngineDescription(String name, boolean sp, String paramName) {
1279             this.name = name;
1280             this.supportsParameter = sp;
1281             this.constructorParameterClassName = paramName;
1282         }
1283         Class<?> getConstructorParameterClass() throws ClassNotFoundException {
1284             Class<?> clazz = constructorParameterClass;
1285             if (clazz == null) {
1286                 clazz = Class.forName(constructorParameterClassName);
1287                 constructorParameterClass = clazz;
1288             }
1289             return clazz;
1290         }
1291     }
1292
1293     // built in knowledge of the engine types shipped as part of the JDK
1294     private static final Map<String,EngineDescription> knownEngines;
1295
1296     private static void addEngine(String name, boolean sp, String paramName) {
1297         EngineDescription ed = new EngineDescription(name, sp, paramName);
1298         // also index by canonical name to avoid toLowerCase() for some lookups
1299         knownEngines.put(name.toLowerCase(ENGLISH), ed);
1300         knownEngines.put(name, ed);
1301     }
1302
1303     static {
1304         knownEngines = new HashMap<String,EngineDescription>();
1305         // JCA
1306         addEngine("AlgorithmParameterGenerator",        falsenull);
1307         addEngine("AlgorithmParameters",                falsenull);
1308         addEngine("KeyFactory",                         falsenull);
1309         addEngine("KeyPairGenerator",                   falsenull);
1310         addEngine("KeyStore",                           falsenull);
1311         addEngine("MessageDigest",                      falsenull);
1312         addEngine("SecureRandom",                       falsenull);
1313         addEngine("Signature",                          true,  null);
1314         addEngine("CertificateFactory",                 falsenull);
1315         addEngine("CertPathBuilder",                    falsenull);
1316         addEngine("CertPathValidator",                  falsenull);
1317         addEngine("CertStore",                          false,
1318                             "java.security.cert.CertStoreParameters");
1319         // JCE
1320         addEngine("Cipher",                             true,  null);
1321         addEngine("ExemptionMechanism",                 falsenull);
1322         addEngine("Mac",                                true,  null);
1323         addEngine("KeyAgreement",                       true,  null);
1324         addEngine("KeyGenerator",                       falsenull);
1325         addEngine("SecretKeyFactory",                   falsenull);
1326         // JSSE
1327         addEngine("KeyManagerFactory",                  falsenull);
1328         addEngine("SSLContext",                         falsenull);
1329         addEngine("TrustManagerFactory",                falsenull);
1330         // JGSS
1331         addEngine("GssApiMechanism",                    falsenull);
1332         // SASL
1333         addEngine("SaslClientFactory",                  falsenull);
1334         addEngine("SaslServerFactory",                  falsenull);
1335         // POLICY
1336         addEngine("Policy",                             false,
1337                             "java.security.Policy$Parameters");
1338         // CONFIGURATION
1339         addEngine("Configuration",                      false,
1340                             "javax.security.auth.login.Configuration$Parameters");
1341         // XML DSig
1342         addEngine("XMLSignatureFactory",                falsenull);
1343         addEngine("KeyInfoFactory",                     falsenull);
1344         addEngine("TransformService",                   falsenull);
1345         // Smart Card I/O
1346         addEngine("TerminalFactory",                    false,
1347                             "java.lang.Object");
1348     }
1349
1350     // get the "standard" (mixed-case) engine name for arbitary case engine name
1351     // if there is no known engine by that name, return s
1352     private static String getEngineName(String s) {
1353         // try original case first, usually correct
1354         EngineDescription e = knownEngines.get(s);
1355         if (e == null) {
1356             e = knownEngines.get(s.toLowerCase(ENGLISH));
1357         }
1358         return (e == null) ? s : e.name;
1359     }
1360
1361     /**
1362      * The description of a security service. It encapsulates the properties
1363      * of a service and contains a factory method to obtain new implementation
1364      * instances of this service.
1365      *
1366      * <p>Each service has a provider that offers the service, a type,
1367      * an algorithm name, and the name of the class that implements the
1368      * service. Optionally, it also includes a list of alternate algorithm
1369      * names for this service (aliases) and attributes, which are a map of
1370      * (name, value) String pairs.
1371      *
1372      * <p>This class defines the methods {@link #supportsParameter
1373      * supportsParameter()} and {@link #newInstance newInstance()}
1374      * which are used by the Java security framework when it searches for
1375      * suitable services and instantiates them. The valid arguments to those
1376      * methods depend on the type of service. For the service types defined
1377      * within Java SE, see the
1378      * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
1379      * Java Cryptography Architecture API Specification &amp; Reference </a>
1380      * for the valid values.
1381      * Note that components outside of Java SE can define additional types of
1382      * services and their behavior.
1383      *
1384      * <p>Instances of this class are immutable.
1385      *
1386      * @since 1.5
1387      */

1388     public static class Service {
1389
1390         private String type, algorithm, className;
1391         private final Provider provider;
1392         private List<String> aliases;
1393         private Map<UString,String> attributes;
1394
1395         // Reference to the cached implementation Class object
1396         private volatile Reference<Class<?>> classRef;
1397
1398         // flag indicating whether this service has its attributes for
1399         // supportedKeyFormats or supportedKeyClasses set
1400         // if null, the values have not been initialized
1401         // if TRUE, at least one of supportedFormats/Classes is non null
1402         private volatile Boolean hasKeyAttributes;
1403
1404         // supported encoding formats
1405         private String[] supportedFormats;
1406
1407         // names of the supported key (super) classes
1408         private Class[] supportedClasses;
1409
1410         // whether this service has been registered with the Provider
1411         private boolean registered;
1412
1413         private static final Class<?>[] CLASS0 = new Class<?>[0];
1414
1415         // this constructor and these methods are used for parsing
1416         // the legacy string properties.
1417
1418         private Service(Provider provider) {
1419             this.provider = provider;
1420             aliases = Collections.<String>emptyList();
1421             attributes = Collections.<UString,String>emptyMap();
1422         }
1423
1424         private boolean isValid() {
1425             return (type != null) && (algorithm != null) && (className != null);
1426         }
1427
1428         private void addAlias(String alias) {
1429             if (aliases.isEmpty()) {
1430                 aliases = new ArrayList<String>(2);
1431             }
1432             aliases.add(alias);
1433         }
1434
1435         void addAttribute(String type, String value) {
1436             if (attributes.isEmpty()) {
1437                 attributes = new HashMap<UString,String>(8);
1438             }
1439             attributes.put(new UString(type), value);
1440         }
1441
1442         /**
1443          * Construct a new service.
1444          *
1445          * @param provider the provider that offers this service
1446          * @param type the type of this service
1447          * @param algorithm the algorithm name
1448          * @param className the name of the class implementing this service
1449          * @param aliases List of aliases or null if algorithm has no aliases
1450          * @param attributes Map of attributes or null if this implementation
1451          *                   has no attributes
1452          *
1453          * @throws NullPointerException if provider, type, algorithm, or
1454          * className is null
1455          */

1456         public Service(Provider provider, String type, String algorithm,
1457                 String className, List<String> aliases,
1458                 Map<String,String> attributes) {
1459             if ((provider == null) || (type == null) ||
1460                     (algorithm == null) || (className == null)) {
1461                 throw new NullPointerException();
1462             }
1463             this.provider = provider;
1464             this.type = getEngineName(type);
1465             this.algorithm = algorithm;
1466             this.className = className;
1467             if (aliases == null) {
1468                 this.aliases = Collections.<String>emptyList();
1469             } else {
1470                 this.aliases = new ArrayList<String>(aliases);
1471             }
1472             if (attributes == null) {
1473                 this.attributes = Collections.<UString,String>emptyMap();
1474             } else {
1475                 this.attributes = new HashMap<UString,String>();
1476                 for (Map.Entry<String,String> entry : attributes.entrySet()) {
1477                     this.attributes.put(new UString(entry.getKey()), entry.getValue());
1478                 }
1479             }
1480         }
1481
1482         /**
1483          * Get the type of this service. For example, {@code MessageDigest}.
1484          *
1485          * @return the type of this service
1486          */

1487         public final String getType() {
1488             return type;
1489         }
1490
1491         /**
1492          * Return the name of the algorithm of this service. For example,
1493          * {@code SHA-1}.
1494          *
1495          * @return the algorithm of this service
1496          */

1497         public final String getAlgorithm() {
1498             return algorithm;
1499         }
1500
1501         /**
1502          * Return the Provider of this service.
1503          *
1504          * @return the Provider of this service
1505          */

1506         public final Provider getProvider() {
1507             return provider;
1508         }
1509
1510         /**
1511          * Return the name of the class implementing this service.
1512          *
1513          * @return the name of the class implementing this service
1514          */

1515         public final String getClassName() {
1516             return className;
1517         }
1518
1519         // internal only
1520         private final List<String> getAliases() {
1521             return aliases;
1522         }
1523
1524         /**
1525          * Return the value of the specified attribute or null if this
1526          * attribute is not set for this Service.
1527          *
1528          * @param name the name of the requested attribute
1529          *
1530          * @return the value of the specified attribute or null if the
1531          *         attribute is not present
1532          *
1533          * @throws NullPointerException if name is null
1534          */

1535         public final String getAttribute(String name) {
1536             if (name == null) {
1537                 throw new NullPointerException();
1538             }
1539             return attributes.get(new UString(name));
1540         }
1541
1542         /**
1543          * Return a new instance of the implementation described by this
1544          * service. The security provider framework uses this method to
1545          * construct implementations. Applications will typically not need
1546          * to call it.
1547          *
1548          * <p>The default implementation uses reflection to invoke the
1549          * standard constructor for this type of service.
1550          * Security providers can override this method to implement
1551          * instantiation in a different way.
1552          * For details and the values of constructorParameter that are
1553          * valid for the various types of services see the
1554          * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
1555          * Java Cryptography Architecture API Specification &amp;
1556          * Reference</a>.
1557          *
1558          * @param constructorParameter the value to pass to the constructor,
1559          * or null if this type of service does not use a constructorParameter.
1560          *
1561          * @return a new implementation of this service
1562          *
1563          * @throws InvalidParameterException if the value of
1564          * constructorParameter is invalid for this type of service.
1565          * @throws NoSuchAlgorithmException if instantiation failed for
1566          * any other reason.
1567          */

1568         public Object newInstance(Object constructorParameter)
1569                 throws NoSuchAlgorithmException {
1570             if (registered == false) {
1571                 if (provider.getService(type, algorithm) != this) {
1572                     throw new NoSuchAlgorithmException
1573                         ("Service not registered with Provider "
1574                         + provider.getName() + ": " + this);
1575                 }
1576                 registered = true;
1577             }
1578             try {
1579                 EngineDescription cap = knownEngines.get(type);
1580                 if (cap == null) {
1581                     // unknown engine type, use generic code
1582                     // this is the code path future for non-core
1583                     // optional packages
1584                     return newInstanceGeneric(constructorParameter);
1585                 }
1586                 if (cap.constructorParameterClassName == null) {
1587                     if (constructorParameter != null) {
1588                         throw new InvalidParameterException
1589                             ("constructorParameter not used with " + type
1590                             + " engines");
1591                     }
1592                     Class<?> clazz = getImplClass();
1593                     Class<?>[] empty = {};
1594                     Constructor<?> con = clazz.getConstructor(empty);
1595                     return con.newInstance();
1596                 } else {
1597                     Class<?> paramClass = cap.getConstructorParameterClass();
1598                     if (constructorParameter != null) {
1599                         Class<?> argClass = constructorParameter.getClass();
1600                         if (paramClass.isAssignableFrom(argClass) == false) {
1601                             throw new InvalidParameterException
1602                             ("constructorParameter must be instanceof "
1603                             + cap.constructorParameterClassName.replace('$', '.')
1604                             + for engine type " + type);
1605                         }
1606                     }
1607                     Class<?> clazz = getImplClass();
1608                     Constructor<?> cons = clazz.getConstructor(paramClass);
1609                     return cons.newInstance(constructorParameter);
1610                 }
1611             } catch (NoSuchAlgorithmException e) {
1612                 throw e;
1613             } catch (InvocationTargetException e) {
1614                 throw new NoSuchAlgorithmException
1615                     ("Error constructing implementation (algorithm: "
1616                     + algorithm + ", provider: " + provider.getName()
1617                     + ", class: " + className + ")", e.getCause());
1618             } catch (Exception e) {
1619                 throw new NoSuchAlgorithmException
1620                     ("Error constructing implementation (algorithm: "
1621                     + algorithm + ", provider: " + provider.getName()
1622                     + ", class: " + className + ")", e);
1623             }
1624         }
1625
1626         // return the implementation Class object for this service
1627         private Class<?> getImplClass() throws NoSuchAlgorithmException {
1628             try {
1629                 Reference<Class<?>> ref = classRef;
1630                 Class<?> clazz = (ref == null) ? null : ref.get();
1631                 if (clazz == null) {
1632                     ClassLoader cl = provider.getClass().getClassLoader();
1633                     if (cl == null) {
1634                         clazz = Class.forName(className);
1635                     } else {
1636                         clazz = cl.loadClass(className);
1637                     }
1638                     if (!Modifier.isPublic(clazz.getModifiers())) {
1639                         throw new NoSuchAlgorithmException
1640                             ("class configured for " + type + " (provider: " +
1641                             provider.getName() + ") is not public.");
1642                     }
1643                     classRef = new WeakReference<Class<?>>(clazz);
1644                 }
1645                 return clazz;
1646             } catch (ClassNotFoundException e) {
1647                 throw new NoSuchAlgorithmException
1648                     ("class configured for " + type + " (provider: " +
1649                     provider.getName() + ") cannot be found.", e);
1650             }
1651         }
1652
1653         /**
1654          * Generic code path for unknown engine types. Call the
1655          * no-args constructor if constructorParameter is null, otherwise
1656          * use the first matching constructor.
1657          */

1658         private Object newInstanceGeneric(Object constructorParameter)
1659                 throws Exception {
1660             Class<?> clazz = getImplClass();
1661             if (constructorParameter == null) {
1662                 // create instance with public no-arg constructor if it exists
1663                 try {
1664                     Class<?>[] empty = {};
1665                     Constructor<?> con = clazz.getConstructor(empty);
1666                     return con.newInstance();
1667                 } catch (NoSuchMethodException e) {
1668                     throw new NoSuchAlgorithmException("No public no-arg "
1669                         + "constructor found in class " + className);
1670                 }
1671             }
1672             Class<?> argClass = constructorParameter.getClass();
1673             Constructor[] cons = clazz.getConstructors();
1674             // find first public constructor that can take the
1675             // argument as parameter
1676             for (Constructor<?> con : cons) {
1677                 Class<?>[] paramTypes = con.getParameterTypes();
1678                 if (paramTypes.length != 1) {
1679                     continue;
1680                 }
1681                 if (paramTypes[0].isAssignableFrom(argClass) == false) {
1682                     continue;
1683                 }
1684                 return con.newInstance(constructorParameter);
1685             }
1686             throw new NoSuchAlgorithmException("No public constructor matching "
1687                 + argClass.getName() + " found in class " + className);
1688         }
1689
1690         /**
1691          * Test whether this Service can use the specified parameter.
1692          * Returns false if this service cannot use the parameter. Returns
1693          * true if this service can use the parameter, if a fast test is
1694          * infeasible, or if the status is unknown.
1695          *
1696          * <p>The security provider framework uses this method with
1697          * some types of services to quickly exclude non-matching
1698          * implementations for consideration.
1699          * Applications will typically not need to call it.
1700          *
1701          * <p>For details and the values of parameter that are valid for the
1702          * various types of services see the top of this class and the
1703          * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
1704          * Java Cryptography Architecture API Specification &amp;
1705          * Reference</a>.
1706          * Security providers can override it to implement their own test.
1707          *
1708          * @param parameter the parameter to test
1709          *
1710          * @return false if this this service cannot use the specified
1711          * parameter; true if it can possibly use the parameter
1712          *
1713          * @throws InvalidParameterException if the value of parameter is
1714          * invalid for this type of service or if this method cannot be
1715          * used with this type of service
1716          */

1717         public boolean supportsParameter(Object parameter) {
1718             EngineDescription cap = knownEngines.get(type);
1719             if (cap == null) {
1720                 // unknown engine type, return true by default
1721                 return true;
1722             }
1723             if (cap.supportsParameter == false) {
1724                 throw new InvalidParameterException("supportsParameter() not "
1725                     + "used with " + type + " engines");
1726             }
1727             // allow null for keys without attributes for compatibility
1728             if ((parameter != null) && (parameter instanceof Key == false)) {
1729                 throw new InvalidParameterException
1730                     ("Parameter must be instanceof Key for engine " + type);
1731             }
1732             if (hasKeyAttributes() == false) {
1733                 return true;
1734             }
1735             if (parameter == null) {
1736                 return false;
1737             }
1738             Key key = (Key)parameter;
1739             if (supportsKeyFormat(key)) {
1740                 return true;
1741             }
1742             if (supportsKeyClass(key)) {
1743                 return true;
1744             }
1745             return false;
1746         }
1747
1748         /**
1749          * Return whether this service has its Supported* properties for
1750          * keys defined. Parses the attributes if not yet initialized.
1751          */

1752         private boolean hasKeyAttributes() {
1753             Boolean b = hasKeyAttributes;
1754             if (b == null) {
1755                 synchronized (this) {
1756                     String s;
1757                     s = getAttribute("SupportedKeyFormats");
1758                     if (s != null) {
1759                         supportedFormats = s.split("\\|");
1760                     }
1761                     s = getAttribute("SupportedKeyClasses");
1762                     if (s != null) {
1763                         String[] classNames = s.split("\\|");
1764                         List<Class<?>> classList =
1765                             new ArrayList<>(classNames.length);
1766                         for (String className : classNames) {
1767                             Class<?> clazz = getKeyClass(className);
1768                             if (clazz != null) {
1769                                 classList.add(clazz);
1770                             }
1771                         }
1772                         supportedClasses = classList.toArray(CLASS0);
1773                     }
1774                     boolean bool = (supportedFormats != null)
1775                         || (supportedClasses != null);
1776                     b = Boolean.valueOf(bool);
1777                     hasKeyAttributes = b;
1778                 }
1779             }
1780             return b.booleanValue();
1781         }
1782
1783         // get the key class object of the specified name
1784         private Class<?> getKeyClass(String name) {
1785             try {
1786                 return Class.forName(name);
1787             } catch (ClassNotFoundException e) {
1788                 // ignore
1789             }
1790             try {
1791                 ClassLoader cl = provider.getClass().getClassLoader();
1792                 if (cl != null) {
1793                     return cl.loadClass(name);
1794                 }
1795             } catch (ClassNotFoundException e) {
1796                 // ignore
1797             }
1798             return null;
1799         }
1800
1801         private boolean supportsKeyFormat(Key key) {
1802             if (supportedFormats == null) {
1803                 return false;
1804             }
1805             String format = key.getFormat();
1806             if (format == null) {
1807                 return false;
1808             }
1809             for (String supportedFormat : supportedFormats) {
1810                 if (supportedFormat.equals(format)) {
1811                     return true;
1812                 }
1813             }
1814             return false;
1815         }
1816
1817         private boolean supportsKeyClass(Key key) {
1818             if (supportedClasses == null) {
1819                 return false;
1820             }
1821             Class<?> keyClass = key.getClass();
1822             for (Class<?> clazz : supportedClasses) {
1823                 if (clazz.isAssignableFrom(keyClass)) {
1824                     return true;
1825                 }
1826             }
1827             return false;
1828         }
1829
1830         /**
1831          * Return a String representation of this service.
1832          *
1833          * @return a String representation of this service.
1834          */

1835         public String toString() {
1836             String aString = aliases.isEmpty()
1837                 ? "" : "\r\n  aliases: " + aliases.toString();
1838             String attrs = attributes.isEmpty()
1839                 ? "" : "\r\n  attributes: " + attributes.toString();
1840             return provider.getName() + ": " + type + "." + algorithm
1841                 + " -> " + className + aString + attrs + "\r\n";
1842         }
1843
1844     }
1845
1846 }
1847
Powered by JavaMelody