History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/security/Provider.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/security/Provider.java+1479−0
@@ -0,0 +1,1479 @@
1+/*
2+ * Copyright (c) 1996, 2011, 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+
34+import java.security.cert.CertStoreParameters;
35+import javax.security.auth.login.Configuration;
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</code> 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+ * <tr><th>Name</th><th>Value</th>
74+ * <tr><td><code>Provider.id name</code></td>
75+ * <td><code>String.valueOf(provider.getName())</code></td>
76+ * <tr><td><code>Provider.id version</code></td>
77+ * <td><code>String.valueOf(provider.getVersion())</code></td>
78+ * <tr><td><code>Provider.id info</code></td>
79+ <td><code>String.valueOf(provider.getInfo())</code></td>
80+ * <tr><td><code>Provider.id className</code></td>
81+ * <td><code>provider.getClass().getName()</code></td>
82+ * </table>
83+ *
84+ * @author Benjamin Renaud
85+ * @author Andreas Sterbenz
86+ */
87+public abstract class Provider extends Properties {
88+
89+ // Declare serialVersionUID to be compatible with JDK1.1
90+ static final long serialVersionUID = -4298000515446427739L;
91+
92+ private static final sun.security.util.Debug debug =
93+ sun.security.util.Debug.getInstance
94+ ("provider", "Provider");
95+
96+ /**
97+ * The provider name.
98+ *
99+ * @serial
100+ */
101+ private String name;
102+
103+ /**
104+ * A description of the provider and its services.
105+ *
106+ * @serial
107+ */
108+ private String info;
109+
110+ /**
111+ * The provider version number.
112+ *
113+ * @serial
114+ */
115+ private double version;
116+
117+
118+ private transient Set<Map.Entry<Object,Object>> entrySet = null;
119+ private transient int entrySetCallCount = 0;
120+
121+ private transient boolean initialized;
122+
123+ /**
124+ * Constructs a provider with the specified name, version number,
125+ * and information.
126+ *
127+ * @param name the provider name.
128+ *
129+ * @param version the provider version number.
130+ *
131+ * @param info a description of the provider and its services.
132+ */
133+ protected Provider(String name, double version, String info) {
134+ this.name = name;
135+ this.version = version;
136+ this.info = info;
137+ putId();
138+ initialized = true;
139+ }
140+
141+ /**
142+ * Returns the name of this provider.
143+ *
144+ * @return the name of this provider.
145+ */
146+ public String getName() {
147+ return name;
148+ }
149+
150+ /**
151+ * Returns the version number for this provider.
152+ *
153+ * @return the version number for this provider.
154+ */
155+ public double getVersion() {
156+ return version;
157+ }
158+
159+ /**
160+ * Returns a human-readable description of the provider and its
161+ * services. This may return an HTML page, with relevant links.
162+ *
163+ * @return a description of the provider and its services.
164+ */
165+ public String getInfo() {
166+ return info;
167+ }
168+
169+ /**
170+ * Returns a string with the name and the version number
171+ * of this provider.
172+ *
173+ * @return the string with the name and the version number
174+ * for this provider.
175+ */
176+ public String toString() {
177+ return name + " version " + version;
178+ }
179+
180+ /*
181+ * override the following methods to ensure that provider
182+ * information can only be changed if the caller has the appropriate
183+ * permissions.
184+ */
185+
186+ /**
187+ * Clears this provider so that it no longer contains the properties
188+ * used to look up facilities implemented by the provider.
189+ *
190+ * <p>First, if there is a security manager, its
191+ * <code>checkSecurityAccess</code> method is called with the string
192+ * <code>"clearProviderProperties."+name</code> (where <code>name</code>
193+ * is the provider name) to see if it's ok to clear this provider.
194+ * If the default implementation of <code>checkSecurityAccess</code>
195+ * is used (that is, that method is not overriden), then this results in
196+ * a call to the security manager's <code>checkPermission</code> method
197+ * with a <code>SecurityPermission("clearProviderProperties."+name)</code>
198+ * permission.
199+ *
200+ * @throws SecurityException
201+ * if a security manager exists and its <code>{@link
202+ * java.lang.SecurityManager#checkSecurityAccess}</code> method
203+ * denies access to clear this provider
204+ *
205+ * @since 1.2
206+ */
207+ public synchronized void clear() {
208+ check("clearProviderProperties."+name);
209+ if (debug != null) {
210+ debug.println("Remove " + name + " provider properties");
211+ }
212+ implClear();
213+ }
214+
215+ /**
216+ * Reads a property list (key and element pairs) from the input stream.
217+ *
218+ * @param inStream the input stream.
219+ * @exception IOException if an error occurred when reading from the
220+ * input stream.
221+ * @see java.util.Properties#load
222+ */
223+ public synchronized void load(InputStream inStream) throws IOException {
224+ check("putProviderProperty."+name);
225+ if (debug != null) {
226+ debug.println("Load " + name + " provider properties");
227+ }
228+ Properties tempProperties = new Properties();
229+ tempProperties.load(inStream);
230+ implPutAll(tempProperties);
231+ }
232+
233+ /**
234+ * Copies all of the mappings from the specified Map to this provider.
235+ * These mappings will replace any properties that this provider had
236+ * for any of the keys currently in the specified Map.
237+ *
238+ * @since 1.2
239+ */
240+ public synchronized void putAll(Map<?,?> t) {
241+ check("putProviderProperty."+name);
242+ if (debug != null) {
243+ debug.println("Put all " + name + " provider properties");
244+ }
245+ implPutAll(t);
246+ }
247+
248+ /**
249+ * Returns an unmodifiable Set view of the property entries contained
250+ * in this Provider.
251+ *
252+ * @see java.util.Map.Entry
253+ * @since 1.2
254+ */
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+ public Set<Object> keySet() {
282+ checkInitialized();
283+ return Collections.unmodifiableSet(super.keySet());
284+ }
285+
286+ /**
287+ * Returns an unmodifiable Collection view of the property values
288+ * contained in this provider.
289+ *
290+ * @since 1.2
291+ */
292+ public Collection<Object> values() {
293+ checkInitialized();
294+ return Collections.unmodifiableCollection(super.values());
295+ }
296+
297+ /**
298+ * Sets the <code>key</code> property to have the specified
299+ * <code>value</code>.
300+ *
301+ * <p>First, if there is a security manager, its
302+ * <code>checkSecurityAccess</code> method is called with the string
303+ * <code>"putProviderProperty."+name</code>, where <code>name</code> is the
304+ * provider name, to see if it's ok to set this provider's property values.
305+ * If the default implementation of <code>checkSecurityAccess</code>
306+ * is used (that is, that method is not overriden), then this results in
307+ * a call to the security manager's <code>checkPermission</code> method
308+ * with a <code>SecurityPermission("putProviderProperty."+name)</code>
309+ * permission.
310+ *
311+ * @param key the property key.
312+ *
313+ * @param value the property value.
314+ *
315+ * @return the previous value of the specified property
316+ * (<code>key</code>), or null if it did not have one.
317+ *
318+ * @throws SecurityException
319+ * if a security manager exists and its <code>{@link
320+ * java.lang.SecurityManager#checkSecurityAccess}</code> method
321+ * denies access to set property values.
322+ *
323+ * @since 1.2
324+ */
325+ public synchronized Object put(Object key, Object value) {
326+ check("putProviderProperty."+name);
327+ if (debug != null) {
328+ debug.println("Set " + name + " provider property [" +
329+ key + "/" + value +"]");
330+ }
331+ return implPut(key, value);
332+ }
333+
334+ /**
335+ * Removes the <code>key</code> property (and its corresponding
336+ * <code>value</code>).
337+ *
338+ * <p>First, if there is a security manager, its
339+ * <code>checkSecurityAccess</code> method is called with the string
340+ * <code>"removeProviderProperty."+name</code>, where <code>name</code> is
341+ * the provider name, to see if it's ok to remove this provider's
342+ * properties. If the default implementation of
343+ * <code>checkSecurityAccess</code> is used (that is, that method is not
344+ * overriden), then this results in a call to the security manager's
345+ * <code>checkPermission</code> method with a
346+ * <code>SecurityPermission("removeProviderProperty."+name)</code>
347+ * permission.
348+ *
349+ * @param key the key for the property to be removed.
350+ *
351+ * @return the value to which the key had been mapped,
352+ * or null if the key did not have a mapping.
353+ *
354+ * @throws SecurityException
355+ * if a security manager exists and its <code>{@link
356+ * java.lang.SecurityManager#checkSecurityAccess}</code> method
357+ * denies access to remove this provider's properties.
358+ *
359+ * @since 1.2
360+ */
361+ public synchronized Object remove(Object key) {
362+ check("removeProviderProperty."+name);
363+ if (debug != null) {
364+ debug.println("Remove " + name + " provider property " + key);
365+ }
366+ return implRemove(key);
367+ }
368+
369+ // let javadoc show doc from superclass
370+ public Object get(Object key) {
371+ checkInitialized();
372+ return super.get(key);
373+ }
374+
375+ // let javadoc show doc from superclass
376+ public Enumeration<Object> keys() {
377+ checkInitialized();
378+ return super.keys();
379+ }
380+
381+ // let javadoc show doc from superclass
382+ public Enumeration<Object> elements() {
383+ checkInitialized();
384+ return super.elements();
385+ }
386+
387+ // let javadoc show doc from superclass
388+ public String getProperty(String key) {
389+ checkInitialized();
390+ return super.getProperty(key);
391+ }
392+
393+ private void checkInitialized() {
394+ if (!initialized) {
395+ throw new IllegalStateException();
396+ }
397+ }
398+
399+ private void check(String directive) {
400+ checkInitialized();
401+ SecurityManager security = System.getSecurityManager();
402+ if (security != null) {
403+ security.checkSecurityAccess(directive);
404+ }
405+ }
406+
407+ // legacy properties changed since last call to any services method?
408+ private transient boolean legacyChanged;
409+ // serviceMap changed since last call to getServices()
410+ private transient boolean servicesChanged;
411+
412+ // Map<String,String>
413+ private transient Map<String,String> legacyStrings;
414+
415+ // Map<ServiceKey,Service>
416+ // used for services added via putService(), initialized on demand
417+ private transient Map<ServiceKey,Service> serviceMap;
418+
419+ // Map<ServiceKey,Service>
420+ // used for services added via legacy methods, init on demand
421+ private transient Map<ServiceKey,Service> legacyMap;
422+
423+ // Set<Service>
424+ // Unmodifiable set of all services. Initialized on demand.
425+ private transient Set<Service> serviceSet;
426+
427+ // register the id attributes for this provider
428+ // this is to ensure that equals() and hashCode() do not incorrectly
429+ // report to different provider objects as the same
430+ private void putId() {
431+ // note: name and info may be null
432+ super.put("Provider.id name", String.valueOf(name));
433+ super.put("Provider.id version", String.valueOf(version));
434+ super.put("Provider.id info", String.valueOf(info));
435+ super.put("Provider.id className", this.getClass().getName());
436+ }
437+
438+ private void readObject(ObjectInputStream in)
439+ throws IOException, ClassNotFoundException {
440+ Map<Object,Object> copy = new HashMap<>();
441+ for (Map.Entry<Object,Object> entry : super.entrySet()) {
442+ copy.put(entry.getKey(), entry.getValue());
443+ }
444+ defaults = null;
445+ in.defaultReadObject();
446+ implClear();
447+ initialized = true;
448+ putAll(copy);
449+ }
450+
451+ /**
452+ * Copies all of the mappings from the specified Map to this provider.
453+ * Internal method to be called AFTER the security check has been
454+ * performed.
455+ */
456+ private void implPutAll(Map t) {
457+ for (Map.Entry e : ((Map<?,?>)t).entrySet()) {
458+ implPut(e.getKey(), e.getValue());
459+ }
460+ }
461+
462+ private Object implRemove(Object key) {
463+ if (key instanceof String) {
464+ String keyString = (String)key;
465+ if (keyString.startsWith("Provider.")) {
466+ return null;
467+ }
468+ legacyChanged = true;
469+ if (legacyStrings == null) {
470+ legacyStrings = new LinkedHashMap<String,String>();
471+ }
472+ legacyStrings.remove(keyString);
473+ }
474+ return super.remove(key);
475+ }
476+
477+ private Object implPut(Object key, Object value) {
478+ if ((key instanceof String) && (value instanceof String)) {
479+ String keyString = (String)key;
480+ if (keyString.startsWith("Provider.")) {
481+ return null;
482+ }
483+ legacyChanged = true;
484+ if (legacyStrings == null) {
485+ legacyStrings = new LinkedHashMap<String,String>();
486+ }
487+ legacyStrings.put(keyString, (String)value);
488+ }
489+ return super.put(key, value);
490+ }
491+
492+ private void implClear() {
493+ if (legacyStrings != null) {
494+ legacyStrings.clear();
495+ }
496+ if (legacyMap != null) {
497+ legacyMap.clear();
498+ }
499+ if (serviceMap != null) {
500+ serviceMap.clear();
501+ }
502+ legacyChanged = false;
503+ servicesChanged = false;
504+ serviceSet = null;
505+ super.clear();
506+ putId();
507+ }
508+
509+ // used as key in the serviceMap and legacyMap HashMaps
510+ private static class ServiceKey {
511+ private final String type;
512+ private final String algorithm;
513+ private final String originalAlgorithm;
514+ private ServiceKey(String type, String algorithm, boolean intern) {
515+ this.type = type;
516+ this.originalAlgorithm = algorithm;
517+ algorithm = algorithm.toUpperCase(ENGLISH);
518+ this.algorithm = intern ? algorithm.intern() : algorithm;
519+ }
520+ public int hashCode() {
521+ return type.hashCode() + algorithm.hashCode();
522+ }
523+ public boolean equals(Object obj) {
524+ if (this == obj) {
525+ return true;
526+ }
527+ if (obj instanceof ServiceKey == false) {
528+ return false;
529+ }
530+ ServiceKey other = (ServiceKey)obj;
531+ return this.type.equals(other.type)
532+ && this.algorithm.equals(other.algorithm);
533+ }
534+ boolean matches(String type, String algorithm) {
535+ return (this.type == type) && (this.originalAlgorithm == algorithm);
536+ }
537+ }
538+
539+ /**
540+ * Ensure all the legacy String properties are fully parsed into
541+ * service objects.
542+ */
543+ private void ensureLegacyParsed() {
544+ if ((legacyChanged == false) || (legacyStrings == null)) {
545+ return;
546+ }
547+ serviceSet = null;
548+ if (legacyMap == null) {
549+ legacyMap = new LinkedHashMap<ServiceKey,Service>();
550+ } else {
551+ legacyMap.clear();
552+ }
553+ for (Map.Entry<String,String> entry : legacyStrings.entrySet()) {
554+ parseLegacyPut(entry.getKey(), entry.getValue());
555+ }
556+ removeInvalidServices(legacyMap);
557+ legacyChanged = false;
558+ }
559+
560+ /**
561+ * Remove all invalid services from the Map. Invalid services can only
562+ * occur if the legacy properties are inconsistent or incomplete.
563+ */
564+ private void removeInvalidServices(Map<ServiceKey,Service> map) {
565+ for (Iterator t = map.entrySet().iterator(); t.hasNext(); ) {
566+ Map.Entry entry = (Map.Entry)t.next();
567+ Service s = (Service)entry.getValue();
568+ if (s.isValid() == false) {
569+ t.remove();
570+ }
571+ }
572+ }
573+
574+ private String[] getTypeAndAlgorithm(String key) {
575+ int i = key.indexOf(".");
576+ if (i < 1) {
577+ if (debug != null) {
578+ debug.println("Ignoring invalid entry in provider "
579+ + name + ":" + key);
580+ }
581+ return null;
582+ }
583+ String type = key.substring(0, i);
584+ String alg = key.substring(i + 1);
585+ return new String[] {type, alg};
586+ }
587+
588+ private final static String ALIAS_PREFIX = "Alg.Alias.";
589+ private final static String ALIAS_PREFIX_LOWER = "alg.alias.";
590+ private final static int ALIAS_LENGTH = ALIAS_PREFIX.length();
591+
592+ private void parseLegacyPut(String name, String value) {
593+ if (name.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) {
594+ // e.g. put("Alg.Alias.MessageDigest.SHA", "SHA-1");
595+ // aliasKey ~ MessageDigest.SHA
596+ String stdAlg = value;
597+ String aliasKey = name.substring(ALIAS_LENGTH);
598+ String[] typeAndAlg = getTypeAndAlgorithm(aliasKey);
599+ if (typeAndAlg == null) {
600+ return;
601+ }
602+ String type = getEngineName(typeAndAlg[0]);
603+ String aliasAlg = typeAndAlg[1].intern();
604+ ServiceKey key = new ServiceKey(type, stdAlg, true);
605+ Service s = legacyMap.get(key);
606+ if (s == null) {
607+ s = new Service(this);
608+ s.type = type;
609+ s.algorithm = stdAlg;
610+ legacyMap.put(key, s);
611+ }
612+ legacyMap.put(new ServiceKey(type, aliasAlg, true), s);
613+ s.addAlias(aliasAlg);
614+ } else {
615+ String[] typeAndAlg = getTypeAndAlgorithm(name);
616+ if (typeAndAlg == null) {
617+ return;
618+ }
619+ int i = typeAndAlg[1].indexOf(' ');
620+ if (i == -1) {
621+ // e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA");
622+ String type = getEngineName(typeAndAlg[0]);
623+ String stdAlg = typeAndAlg[1].intern();
624+ String className = value;
625+ ServiceKey key = new ServiceKey(type, stdAlg, true);
626+ Service s = legacyMap.get(key);
627+ if (s == null) {
628+ s = new Service(this);
629+ s.type = type;
630+ s.algorithm = stdAlg;
631+ legacyMap.put(key, s);
632+ }
633+ s.className = className;
634+ } else { // attribute
635+ // e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software");
636+ String attributeValue = value;
637+ String type = getEngineName(typeAndAlg[0]);
638+ String attributeString = typeAndAlg[1];
639+ String stdAlg = attributeString.substring(0, i).intern();
640+ String attributeName = attributeString.substring(i + 1);
641+ // kill additional spaces
642+ while (attributeName.startsWith(" ")) {
643+ attributeName = attributeName.substring(1);
644+ }
645+ attributeName = attributeName.intern();
646+ ServiceKey key = new ServiceKey(type, stdAlg, true);
647+ Service s = legacyMap.get(key);
648+ if (s == null) {
649+ s = new Service(this);
650+ s.type = type;
651+ s.algorithm = stdAlg;
652+ legacyMap.put(key, s);
653+ }
654+ s.addAttribute(attributeName, attributeValue);
655+ }
656+ }
657+ }
658+
659+ /**
660+ * Get the service describing this Provider's implementation of the
661+ * specified type of this algorithm or alias. If no such
662+ * implementation exists, this method returns null. If there are two
663+ * matching services, one added to this provider using
664+ * {@link #putService putService()} and one added via {@link #put put()},
665+ * the service added via {@link #putService putService()} is returned.
666+ *
667+ * @param type the type of {@link Service service} requested
668+ * (for example, <code>MessageDigest</code>)
669+ * @param algorithm the case insensitive algorithm name (or alternate
670+ * alias) of the service requested (for example, <code>SHA-1</code>)
671+ *
672+ * @return the service describing this Provider's matching service
673+ * or null if no such service exists
674+ *
675+ * @throws NullPointerException if type or algorithm is null
676+ *
677+ * @since 1.5
678+ */
679+ public synchronized Service getService(String type, String algorithm) {
680+ checkInitialized();
681+ // avoid allocating a new key object if possible
682+ ServiceKey key = previousKey;
683+ if (key.matches(type, algorithm) == false) {
684+ key = new ServiceKey(type, algorithm, false);
685+ previousKey = key;
686+ }
687+ if (serviceMap != null) {
688+ Service service = serviceMap.get(key);
689+ if (service != null) {
690+ return service;
691+ }
692+ }
693+ ensureLegacyParsed();
694+ return (legacyMap != null) ? legacyMap.get(key) : null;
695+ }
696+
697+ // ServiceKey from previous getService() call
698+ // by re-using it if possible we avoid allocating a new object
699+ // and the toUpperCase() call.
700+ // re-use will occur e.g. as the framework traverses the provider
701+ // list and queries each provider with the same values until it finds
702+ // a matching service
703+ private static volatile ServiceKey previousKey =
704+ new ServiceKey("", "", false);
705+
706+ /**
707+ * Get an unmodifiable Set of all services supported by
708+ * this Provider.
709+ *
710+ * @return an unmodifiable Set of all services supported by
711+ * this Provider
712+ *
713+ * @since 1.5
714+ */
715+ public synchronized Set<Service> getServices() {
716+ checkInitialized();
717+ if (legacyChanged || servicesChanged) {
718+ serviceSet = null;
719+ }
720+ if (serviceSet == null) {
721+ ensureLegacyParsed();
722+ Set<Service> set = new LinkedHashSet<>();
723+ if (serviceMap != null) {
724+ set.addAll(serviceMap.values());
725+ }
726+ if (legacyMap != null) {
727+ set.addAll(legacyMap.values());
728+ }
729+ serviceSet = Collections.unmodifiableSet(set);
730+ servicesChanged = false;
731+ }
732+ return serviceSet;
733+ }
734+
735+ /**
736+ * Add a service. If a service of the same type with the same algorithm
737+ * name exists and it was added using {@link #putService putService()},
738+ * it is replaced by the new service.
739+ * This method also places information about this service
740+ * in the provider's Hashtable values in the format described in the
741+ * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
742+ * Java Cryptography Architecture API Specification &amp; Reference </a>.
743+ *
744+ * <p>Also, if there is a security manager, its
745+ * <code>checkSecurityAccess</code> method is called with the string
746+ * <code>"putProviderProperty."+name</code>, where <code>name</code> is
747+ * the provider name, to see if it's ok to set this provider's property
748+ * values. If the default implementation of <code>checkSecurityAccess</code>
749+ * is used (that is, that method is not overriden), then this results in
750+ * a call to the security manager's <code>checkPermission</code> method with
751+ * a <code>SecurityPermission("putProviderProperty."+name)</code>
752+ * permission.
753+ *
754+ * @param s the Service to add
755+ *
756+ * @throws SecurityException
757+ * if a security manager exists and its <code>{@link
758+ * java.lang.SecurityManager#checkSecurityAccess}</code> method denies
759+ * access to set property values.
760+ * @throws NullPointerException if s is null
761+ *
762+ * @since 1.5
763+ */
764+ protected synchronized void putService(Service s) {
765+ check("putProviderProperty." + name);
766+ if (debug != null) {
767+ debug.println(name + ".putService(): " + s);
768+ }
769+ if (s == null) {
770+ throw new NullPointerException();
771+ }
772+ if (s.getProvider() != this) {
773+ throw new IllegalArgumentException
774+ ("service.getProvider() must match this Provider object");
775+ }
776+ if (serviceMap == null) {
777+ serviceMap = new LinkedHashMap<ServiceKey,Service>();
778+ }
779+ servicesChanged = true;
780+ String type = s.getType();
781+ String algorithm = s.getAlgorithm();
782+ ServiceKey key = new ServiceKey(type, algorithm, true);
783+ // remove existing service
784+ implRemoveService(serviceMap.get(key));
785+ serviceMap.put(key, s);
786+ for (String alias : s.getAliases()) {
787+ serviceMap.put(new ServiceKey(type, alias, true), s);
788+ }
789+ putPropertyStrings(s);
790+ }
791+
792+ /**
793+ * Put the string properties for this Service in this Provider's
794+ * Hashtable.
795+ */
796+ private void putPropertyStrings(Service s) {
797+ String type = s.getType();
798+ String algorithm = s.getAlgorithm();
799+ // use super() to avoid permission check and other processing
800+ super.put(type + "." + algorithm, s.getClassName());
801+ for (String alias : s.getAliases()) {
802+ super.put(ALIAS_PREFIX + type + "." + alias, algorithm);
803+ }
804+ for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
805+ String key = type + "." + algorithm + " " + entry.getKey();
806+ super.put(key, entry.getValue());
807+ }
808+ }
809+
810+ /**
811+ * Remove the string properties for this Service from this Provider's
812+ * Hashtable.
813+ */
814+ private void removePropertyStrings(Service s) {
815+ String type = s.getType();
816+ String algorithm = s.getAlgorithm();
817+ // use super() to avoid permission check and other processing
818+ super.remove(type + "." + algorithm);
819+ for (String alias : s.getAliases()) {
820+ super.remove(ALIAS_PREFIX + type + "." + alias);
821+ }
822+ for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
823+ String key = type + "." + algorithm + " " + entry.getKey();
824+ super.remove(key);
825+ }
826+ }
827+
828+ /**
829+ * Remove a service previously added using
830+ * {@link #putService putService()}. The specified service is removed from
831+ * this provider. It will no longer be returned by
832+ * {@link #getService getService()} and its information will be removed
833+ * from this provider's Hashtable.
834+ *
835+ * <p>Also, if there is a security manager, its
836+ * <code>checkSecurityAccess</code> method is called with the string
837+ * <code>"removeProviderProperty."+name</code>, where <code>name</code> is
838+ * the provider name, to see if it's ok to remove this provider's
839+ * properties. If the default implementation of
840+ * <code>checkSecurityAccess</code> is used (that is, that method is not
841+ * overriden), then this results in a call to the security manager's
842+ * <code>checkPermission</code> method with a
843+ * <code>SecurityPermission("removeProviderProperty."+name)</code>
844+ * permission.
845+ *
846+ * @param s the Service to be removed
847+ *
848+ * @throws SecurityException
849+ * if a security manager exists and its <code>{@link
850+ * java.lang.SecurityManager#checkSecurityAccess}</code> method denies
851+ * access to remove this provider's properties.
852+ * @throws NullPointerException if s is null
853+ *
854+ * @since 1.5
855+ */
856+ protected synchronized void removeService(Service s) {
857+ check("removeProviderProperty." + name);
858+ if (debug != null) {
859+ debug.println(name + ".removeService(): " + s);
860+ }
861+ if (s == null) {
862+ throw new NullPointerException();
863+ }
864+ implRemoveService(s);
865+ }
866+
867+ private void implRemoveService(Service s) {
868+ if ((s == null) || (serviceMap == null)) {
869+ return;
870+ }
871+ String type = s.getType();
872+ String algorithm = s.getAlgorithm();
873+ ServiceKey key = new ServiceKey(type, algorithm, false);
874+ Service oldService = serviceMap.get(key);
875+ if (s != oldService) {
876+ return;
877+ }
878+ servicesChanged = true;
879+ serviceMap.remove(key);
880+ for (String alias : s.getAliases()) {
881+ serviceMap.remove(new ServiceKey(type, alias, false));
882+ }
883+ removePropertyStrings(s);
884+ }
885+
886+ // Wrapped String that behaves in a case insensitive way for equals/hashCode
887+ private static class UString {
888+ final String string;
889+ final String lowerString;
890+
891+ UString(String s) {
892+ this.string = s;
893+ this.lowerString = s.toLowerCase(ENGLISH);
894+ }
895+
896+ public int hashCode() {
897+ return lowerString.hashCode();
898+ }
899+
900+ public boolean equals(Object obj) {
901+ if (this == obj) {
902+ return true;
903+ }
904+ if (obj instanceof UString == false) {
905+ return false;
906+ }
907+ UString other = (UString)obj;
908+ return lowerString.equals(other.lowerString);
909+ }
910+
911+ public String toString() {
912+ return string;
913+ }
914+ }
915+
916+ // describe relevant properties of a type of engine
917+ private static class EngineDescription {
918+ final String name;
919+ final boolean supportsParameter;
920+ final String constructorParameterClassName;
921+ private volatile Class constructorParameterClass;
922+
923+ EngineDescription(String name, boolean sp, String paramName) {
924+ this.name = name;
925+ this.supportsParameter = sp;
926+ this.constructorParameterClassName = paramName;
927+ }
928+ Class getConstructorParameterClass() throws ClassNotFoundException {
929+ Class clazz = constructorParameterClass;
930+ if (clazz == null) {
931+ clazz = Class.forName(constructorParameterClassName);
932+ constructorParameterClass = clazz;
933+ }
934+ return clazz;
935+ }
936+ }
937+
938+ // built in knowledge of the engine types shipped as part of the JDK
939+ private static final Map<String,EngineDescription> knownEngines;
940+
941+ private static void addEngine(String name, boolean sp, String paramName) {
942+ EngineDescription ed = new EngineDescription(name, sp, paramName);
943+ // also index by canonical name to avoid toLowerCase() for some lookups
944+ knownEngines.put(name.toLowerCase(ENGLISH), ed);
945+ knownEngines.put(name, ed);
946+ }
947+
948+ static {
949+ knownEngines = new HashMap<String,EngineDescription>();
950+ // JCA
951+ addEngine("AlgorithmParameterGenerator", false, null);
952+ addEngine("AlgorithmParameters", false, null);
953+ addEngine("KeyFactory", false, null);
954+ addEngine("KeyPairGenerator", false, null);
955+ addEngine("KeyStore", false, null);
956+ addEngine("MessageDigest", false, null);
957+ addEngine("SecureRandom", false, null);
958+ addEngine("Signature", true, null);
959+ addEngine("CertificateFactory", false, null);
960+ addEngine("CertPathBuilder", false, null);
961+ addEngine("CertPathValidator", false, null);
962+ addEngine("CertStore", false,
963+ "java.security.cert.CertStoreParameters");
964+ // JCE
965+ addEngine("Cipher", true, null);
966+ addEngine("ExemptionMechanism", false, null);
967+ addEngine("Mac", true, null);
968+ addEngine("KeyAgreement", true, null);
969+ addEngine("KeyGenerator", false, null);
970+ addEngine("SecretKeyFactory", false, null);
971+ // JSSE
972+ addEngine("KeyManagerFactory", false, null);
973+ addEngine("SSLContext", false, null);
974+ addEngine("TrustManagerFactory", false, null);
975+ // JGSS
976+ addEngine("GssApiMechanism", false, null);
977+ // SASL
978+ addEngine("SaslClientFactory", false, null);
979+ addEngine("SaslServerFactory", false, null);
980+ // POLICY
981+ addEngine("Policy", false,
982+ "java.security.Policy$Parameters");
983+ // CONFIGURATION
984+ addEngine("Configuration", false,
985+ "javax.security.auth.login.Configuration$Parameters");
986+ // XML DSig
987+ addEngine("XMLSignatureFactory", false, null);
988+ addEngine("KeyInfoFactory", false, null);
989+ addEngine("TransformService", false, null);
990+ // Smart Card I/O
991+ addEngine("TerminalFactory", false,
992+ "java.lang.Object");
993+ }
994+
995+ // get the "standard" (mixed-case) engine name for arbitary case engine name
996+ // if there is no known engine by that name, return s
997+ private static String getEngineName(String s) {
998+ // try original case first, usually correct
999+ EngineDescription e = knownEngines.get(s);
1000+ if (e == null) {
1001+ e = knownEngines.get(s.toLowerCase(ENGLISH));
1002+ }
1003+ return (e == null) ? s : e.name;
1004+ }
1005+
1006+ /**
1007+ * The description of a security service. It encapsulates the properties
1008+ * of a service and contains a factory method to obtain new implementation
1009+ * instances of this service.
1010+ *
1011+ * <p>Each service has a provider that offers the service, a type,
1012+ * an algorithm name, and the name of the class that implements the
1013+ * service. Optionally, it also includes a list of alternate algorithm
1014+ * names for this service (aliases) and attributes, which are a map of
1015+ * (name, value) String pairs.
1016+ *
1017+ * <p>This class defines the methods {@link #supportsParameter
1018+ * supportsParameter()} and {@link #newInstance newInstance()}
1019+ * which are used by the Java security framework when it searches for
1020+ * suitable services and instantes them. The valid arguments to those
1021+ * methods depend on the type of service. For the service types defined
1022+ * within Java SE, see the
1023+ * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
1024+ * Java Cryptography Architecture API Specification &amp; Reference </a>
1025+ * for the valid values.
1026+ * Note that components outside of Java SE can define additional types of
1027+ * services and their behavior.
1028+ *
1029+ * <p>Instances of this class are immutable.
1030+ *
1031+ * @since 1.5
1032+ */
1033+ public static class Service {
1034+
1035+ private String type, algorithm, className;
1036+ private final Provider provider;
1037+ private List<String> aliases;
1038+ private Map<UString,String> attributes;
1039+
1040+ // Reference to the cached implementation Class object
1041+ private volatile Reference<Class> classRef;
1042+
1043+ // flag indicating whether this service has its attributes for
1044+ // supportedKeyFormats or supportedKeyClasses set
1045+ // if null, the values have not been initialized
1046+ // if TRUE, at least one of supportedFormats/Classes is non null
1047+ private volatile Boolean hasKeyAttributes;
1048+
1049+ // supported encoding formats
1050+ private String[] supportedFormats;
1051+
1052+ // names of the supported key (super) classes
1053+ private Class[] supportedClasses;
1054+
1055+ // whether this service has been registered with the Provider
1056+ private boolean registered;
1057+
1058+ private static final Class[] CLASS0 = new Class[0];
1059+
1060+ // this constructor and these methods are used for parsing
1061+ // the legacy string properties.
1062+
1063+ private Service(Provider provider) {
1064+ this.provider = provider;
1065+ aliases = Collections.<String>emptyList();
1066+ attributes = Collections.<UString,String>emptyMap();
1067+ }
1068+
1069+ private boolean isValid() {
1070+ return (type != null) && (algorithm != null) && (className != null);
1071+ }
1072+
1073+ private void addAlias(String alias) {
1074+ if (aliases.isEmpty()) {
1075+ aliases = new ArrayList<String>(2);
1076+ }
1077+ aliases.add(alias);
1078+ }
1079+
1080+ void addAttribute(String type, String value) {
1081+ if (attributes.isEmpty()) {
1082+ attributes = new HashMap<UString,String>(8);
1083+ }
1084+ attributes.put(new UString(type), value);
1085+ }
1086+
1087+ /**
1088+ * Construct a new service.
1089+ *
1090+ * @param provider the provider that offers this service
1091+ * @param type the type of this service
1092+ * @param algorithm the algorithm name
1093+ * @param className the name of the class implementing this service
1094+ * @param aliases List of aliases or null if algorithm has no aliases
1095+ * @param attributes Map of attributes or null if this implementation
1096+ * has no attributes
1097+ *
1098+ * @throws NullPointerException if provider, type, algorithm, or
1099+ * className is null
1100+ */
1101+ public Service(Provider provider, String type, String algorithm,
1102+ String className, List<String> aliases,
1103+ Map<String,String> attributes) {
1104+ if ((provider == null) || (type == null) ||
1105+ (algorithm == null) || (className == null)) {
1106+ throw new NullPointerException();
1107+ }
1108+ this.provider = provider;
1109+ this.type = getEngineName(type);
1110+ this.algorithm = algorithm;
1111+ this.className = className;
1112+ if (aliases == null) {
1113+ this.aliases = Collections.<String>emptyList();
1114+ } else {
1115+ this.aliases = new ArrayList<String>(aliases);
1116+ }
1117+ if (attributes == null) {
1118+ this.attributes = Collections.<UString,String>emptyMap();
1119+ } else {
1120+ this.attributes = new HashMap<UString,String>();
1121+ for (Map.Entry<String,String> entry : attributes.entrySet()) {
1122+ this.attributes.put(new UString(entry.getKey()), entry.getValue());
1123+ }
1124+ }
1125+ }
1126+
1127+ /**
1128+ * Get the type of this service. For example, <code>MessageDigest</code>.
1129+ *
1130+ * @return the type of this service
1131+ */
1132+ public final String getType() {
1133+ return type;
1134+ }
1135+
1136+ /**
1137+ * Return the name of the algorithm of this service. For example,
1138+ * <code>SHA-1</code>.
1139+ *
1140+ * @return the algorithm of this service
1141+ */
1142+ public final String getAlgorithm() {
1143+ return algorithm;
1144+ }
1145+
1146+ /**
1147+ * Return the Provider of this service.
1148+ *
1149+ * @return the Provider of this service
1150+ */
1151+ public final Provider getProvider() {
1152+ return provider;
1153+ }
1154+
1155+ /**
1156+ * Return the name of the class implementing this service.
1157+ *
1158+ * @return the name of the class implementing this service
1159+ */
1160+ public final String getClassName() {
1161+ return className;
1162+ }
1163+
1164+ // internal only
1165+ private final List<String> getAliases() {
1166+ return aliases;
1167+ }
1168+
1169+ /**
1170+ * Return the value of the specified attribute or null if this
1171+ * attribute is not set for this Service.
1172+ *
1173+ * @param name the name of the requested attribute
1174+ *
1175+ * @return the value of the specified attribute or null if the
1176+ * attribute is not present
1177+ *
1178+ * @throws NullPointerException if name is null
1179+ */
1180+ public final String getAttribute(String name) {
1181+ if (name == null) {
1182+ throw new NullPointerException();
1183+ }
1184+ return attributes.get(new UString(name));
1185+ }
1186+
1187+ /**
1188+ * Return a new instance of the implementation described by this
1189+ * service. The security provider framework uses this method to
1190+ * construct implementations. Applications will typically not need
1191+ * to call it.
1192+ *
1193+ * <p>The default implementation uses reflection to invoke the
1194+ * standard constructor for this type of service.
1195+ * Security providers can override this method to implement
1196+ * instantiation in a different way.
1197+ * For details and the values of constructorParameter that are
1198+ * valid for the various types of services see the
1199+ * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
1200+ * Java Cryptography Architecture API Specification &amp;
1201+ * Reference</a>.
1202+ *
1203+ * @param constructorParameter the value to pass to the constructor,
1204+ * or null if this type of service does not use a constructorParameter.
1205+ *
1206+ * @return a new implementation of this service
1207+ *
1208+ * @throws InvalidParameterException if the value of
1209+ * constructorParameter is invalid for this type of service.
1210+ * @throws NoSuchAlgorithmException if instantation failed for
1211+ * any other reason.
1212+ */
1213+ public Object newInstance(Object constructorParameter)
1214+ throws NoSuchAlgorithmException {
1215+ if (registered == false) {
1216+ if (provider.getService(type, algorithm) != this) {
1217+ throw new NoSuchAlgorithmException
1218+ ("Service not registered with Provider "
1219+ + provider.getName() + ": " + this);
1220+ }
1221+ registered = true;
1222+ }
1223+ try {
1224+ EngineDescription cap = knownEngines.get(type);
1225+ if (cap == null) {
1226+ // unknown engine type, use generic code
1227+ // this is the code path future for non-core
1228+ // optional packages
1229+ return newInstanceGeneric(constructorParameter);
1230+ }
1231+ if (cap.constructorParameterClassName == null) {
1232+ if (constructorParameter != null) {
1233+ throw new InvalidParameterException
1234+ ("constructorParameter not used with " + type
1235+ + " engines");
1236+ }
1237+ Class clazz = getImplClass();
1238+ return clazz.newInstance();
1239+ } else {
1240+ Class paramClass = cap.getConstructorParameterClass();
1241+ if (constructorParameter != null) {
1242+ Class argClass = constructorParameter.getClass();
1243+ if (paramClass.isAssignableFrom(argClass) == false) {
1244+ throw new InvalidParameterException
1245+ ("constructorParameter must be instanceof "
1246+ + cap.constructorParameterClassName.replace('$', '.')
1247+ + " for engine type " + type);
1248+ }
1249+ }
1250+ Class clazz = getImplClass();
1251+ Constructor cons = clazz.getConstructor(paramClass);
1252+ return cons.newInstance(constructorParameter);
1253+ }
1254+ } catch (NoSuchAlgorithmException e) {
1255+ throw e;
1256+ } catch (InvocationTargetException e) {
1257+ throw new NoSuchAlgorithmException
1258+ ("Error constructing implementation (algorithm: "
1259+ + algorithm + ", provider: " + provider.getName()
1260+ + ", class: " + className + ")", e.getCause());
1261+ } catch (Exception e) {
1262+ throw new NoSuchAlgorithmException
1263+ ("Error constructing implementation (algorithm: "
1264+ + algorithm + ", provider: " + provider.getName()
1265+ + ", class: " + className + ")", e);
1266+ }
1267+ }
1268+
1269+ // return the implementation Class object for this service
1270+ private Class getImplClass() throws NoSuchAlgorithmException {
1271+ try {
1272+ Reference<Class> ref = classRef;
1273+ Class clazz = (ref == null) ? null : ref.get();
1274+ if (clazz == null) {
1275+ ClassLoader cl = provider.getClass().getClassLoader();
1276+ if (cl == null) {
1277+ clazz = Class.forName(className);
1278+ } else {
1279+ clazz = cl.loadClass(className);
1280+ }
1281+ classRef = new WeakReference<Class>(clazz);
1282+ }
1283+ return clazz;
1284+ } catch (ClassNotFoundException e) {
1285+ throw new NoSuchAlgorithmException
1286+ ("class configured for " + type + "(provider: " +
1287+ provider.getName() + ")" + "cannot be found.", e);
1288+ }
1289+ }
1290+
1291+ /**
1292+ * Generic code path for unknown engine types. Call the
1293+ * no-args constructor if constructorParameter is null, otherwise
1294+ * use the first matching constructor.
1295+ */
1296+ private Object newInstanceGeneric(Object constructorParameter)
1297+ throws Exception {
1298+ Class clazz = getImplClass();
1299+ if (constructorParameter == null) {
1300+ Object o = clazz.newInstance();
1301+ return o;
1302+ }
1303+ Class argClass = constructorParameter.getClass();
1304+ Constructor[] cons = clazz.getConstructors();
1305+ // find first public constructor that can take the
1306+ // argument as parameter
1307+ for (int i = 0; i < cons.length; i++) {
1308+ Constructor con = cons[i];
1309+ Class[] paramTypes = con.getParameterTypes();
1310+ if (paramTypes.length != 1) {
1311+ continue;
1312+ }
1313+ if (paramTypes[0].isAssignableFrom(argClass) == false) {
1314+ continue;
1315+ }
1316+ Object o = con.newInstance(new Object[] {constructorParameter});
1317+ return o;
1318+ }
1319+ throw new NoSuchAlgorithmException("No constructor matching "
1320+ + argClass.getName() + " found in class " + className);
1321+ }
1322+
1323+ /**
1324+ * Test whether this Service can use the specified parameter.
1325+ * Returns false if this service cannot use the parameter. Returns
1326+ * true if this service can use the parameter, if a fast test is
1327+ * infeasible, or if the status is unknown.
1328+ *
1329+ * <p>The security provider framework uses this method with
1330+ * some types of services to quickly exclude non-matching
1331+ * implementations for consideration.
1332+ * Applications will typically not need to call it.
1333+ *
1334+ * <p>For details and the values of parameter that are valid for the
1335+ * various types of services see the top of this class and the
1336+ * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
1337+ * Java Cryptography Architecture API Specification &amp;
1338+ * Reference</a>.
1339+ * Security providers can override it to implement their own test.
1340+ *
1341+ * @param parameter the parameter to test
1342+ *
1343+ * @return false if this this service cannot use the specified
1344+ * parameter; true if it can possibly use the parameter
1345+ *
1346+ * @throws InvalidParameterException if the value of parameter is
1347+ * invalid for this type of service or if this method cannot be
1348+ * used with this type of service
1349+ */
1350+ public boolean supportsParameter(Object parameter) {
1351+ EngineDescription cap = knownEngines.get(type);
1352+ if (cap == null) {
1353+ // unknown engine type, return true by default
1354+ return true;
1355+ }
1356+ if (cap.supportsParameter == false) {
1357+ throw new InvalidParameterException("supportsParameter() not "
1358+ + "used with " + type + " engines");
1359+ }
1360+ // allow null for keys without attributes for compatibility
1361+ if ((parameter != null) && (parameter instanceof Key == false)) {
1362+ throw new InvalidParameterException
1363+ ("Parameter must be instanceof Key for engine " + type);
1364+ }
1365+ if (hasKeyAttributes() == false) {
1366+ return true;
1367+ }
1368+ if (parameter == null) {
1369+ return false;
1370+ }
1371+ Key key = (Key)parameter;
1372+ if (supportsKeyFormat(key)) {
1373+ return true;
1374+ }
1375+ if (supportsKeyClass(key)) {
1376+ return true;
1377+ }
1378+ return false;
1379+ }
1380+
1381+ /**
1382+ * Return whether this service has its Supported* properties for
1383+ * keys defined. Parses the attributes if not yet initialized.
1384+ */
1385+ private boolean hasKeyAttributes() {
1386+ Boolean b = hasKeyAttributes;
1387+ if (b == null) {
1388+ synchronized (this) {
1389+ String s;
1390+ s = getAttribute("SupportedKeyFormats");
1391+ if (s != null) {
1392+ supportedFormats = s.split("\\|");
1393+ }
1394+ s = getAttribute("SupportedKeyClasses");
1395+ if (s != null) {
1396+ String[] classNames = s.split("\\|");
1397+ List<Class> classList =
1398+ new ArrayList<>(classNames.length);
1399+ for (String className : classNames) {
1400+ Class clazz = getKeyClass(className);
1401+ if (clazz != null) {
1402+ classList.add(clazz);
1403+ }
1404+ }
1405+ supportedClasses = classList.toArray(CLASS0);
1406+ }
1407+ boolean bool = (supportedFormats != null)
1408+ || (supportedClasses != null);
1409+ b = Boolean.valueOf(bool);
1410+ hasKeyAttributes = b;
1411+ }
1412+ }
1413+ return b.booleanValue();
1414+ }
1415+
1416+ // get the key class object of the specified name
1417+ private Class getKeyClass(String name) {
1418+ try {
1419+ return Class.forName(name);
1420+ } catch (ClassNotFoundException e) {
1421+ // ignore
1422+ }
1423+ try {
1424+ ClassLoader cl = provider.getClass().getClassLoader();
1425+ if (cl != null) {
1426+ return cl.loadClass(name);
1427+ }
1428+ } catch (ClassNotFoundException e) {
1429+ // ignore
1430+ }
1431+ return null;
1432+ }
1433+
1434+ private boolean supportsKeyFormat(Key key) {
1435+ if (supportedFormats == null) {
1436+ return false;
1437+ }
1438+ String format = key.getFormat();
1439+ if (format == null) {
1440+ return false;
1441+ }
1442+ for (String supportedFormat : supportedFormats) {
1443+ if (supportedFormat.equals(format)) {
1444+ return true;
1445+ }
1446+ }
1447+ return false;
1448+ }
1449+
1450+ private boolean supportsKeyClass(Key key) {
1451+ if (supportedClasses == null) {
1452+ return false;
1453+ }
1454+ Class keyClass = key.getClass();
1455+ for (Class clazz : supportedClasses) {
1456+ if (clazz.isAssignableFrom(keyClass)) {
1457+ return true;
1458+ }
1459+ }
1460+ return false;
1461+ }
1462+
1463+ /**
1464+ * Return a String representation of this service.
1465+ *
1466+ * @return a String representation of this service.
1467+ */
1468+ public String toString() {
1469+ String aString = aliases.isEmpty()
1470+ ? "" : "\r\n aliases: " + aliases.toString();
1471+ String attrs = attributes.isEmpty()
1472+ ? "" : "\r\n attributes: " + attributes.toString();
1473+ return provider.getName() + ": " + type + "." + algorithm
1474+ + " -> " + className + aString + attrs + "\r\n";
1475+ }
1476+
1477+ }
1478+
1479+}