KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > security > Provider


1 /*
2  * @(#)Provider.java 1.64 05/04/08
3  *
4  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.security;
9
10 import java.io.*;
11 import java.util.*;
12 import static java.util.Locale.ENGLISH JavaDoc;
13 import java.lang.ref.*;
14 import java.lang.reflect.*;
15
16 import java.security.cert.CertStoreParameters JavaDoc;
17
18 /**
19  * This class represents a "provider" for the
20  * Java Security API, where a provider implements some or all parts of
21  * Java Security. Services that a provider may implement include:
22  *
23  * <ul>
24  *
25  * <li>Algorithms (such as DSA, RSA, MD5 or SHA-1).
26  *
27  * <li>Key generation, conversion, and management facilities (such as for
28  * algorithm-specific keys).
29  *
30  *</ul>
31  *
32  * <p>Each provider has a name and a version number, and is configured
33  * in each runtime it is installed in.
34  *
35  * <p>See <a href =
36  * "../../../guide/security/CryptoSpec.html#Provider">The Provider Class</a>
37  * in the "Java Cryptography Architecture API Specification &amp; Reference"
38  * for information about how a particular type of provider, the
39  * cryptographic service provider, works and is installed. However,
40  * please note that a provider can be used to implement any security
41  * service in Java that uses a pluggable architecture with a choice
42  * of implementations that fit underneath.
43  *
44  * <p>Some provider implementations may encounter unrecoverable internal
45  * errors during their operation, for example a failure to communicate with a
46  * security token. A {@link ProviderException} should be used to indicate
47  * such errors.
48  *
49  * <p>The service type <code>Provider</code> is reserved for use by the
50  * security framework. Services of this type cannot be added, removed,
51  * or modified by applications.
52  * The following attributes are automatically placed in each Provider object:
53  * <table cellspacing=4>
54  * <tr><th>Name</th><th>Value</th>
55  * <tr><td><code>Provider.id name</code></td>
56   * <td><code>String.valueOf(provider.getName())</code></td>
57  * <tr><td><code>Provider.id version</code></td>
58  * <td><code>String.valueOf(provider.getVersion())</code></td>
59  * <tr><td><code>Provider.id info</code></td>
60        <td><code>String.valueOf(provider.getInfo())</code></td>
61  * <tr><td><code>Provider.id className</code></td>
62  * <td><code>provider.getClass().getName()</code></td>
63  * </table>
64  *
65  * @version 1.64, 04/08/05
66  * @author Benjamin Renaud
67  * @author Andreas Sterbenz
68  */

69 public abstract class Provider extends Properties {
70
71     // Declare serialVersionUID to be compatible with JDK1.1
72
static final long serialVersionUID = -4298000515446427739L;
73
74     private static final sun.security.util.Debug debug =
75         sun.security.util.Debug.getInstance
76         ("provider", "Provider");
77
78     /**
79      * The provider name.
80      *
81      * @serial
82      */

83     private String JavaDoc name;
84
85     /**
86      * A description of the provider and its services.
87      *
88      * @serial
89      */

90     private String JavaDoc info;
91
92     /**
93      * The provider version number.
94      *
95      * @serial
96      */

97     private double version;
98
99
100     private transient Set entrySet = null;
101     private transient int entrySetCallCount = 0;
102
103
104     /**
105      * Constructs a provider with the specified name, version number,
106      * and information.
107      *
108      * @param name the provider name.
109      *
110      * @param version the provider version number.
111      *
112      * @param info a description of the provider and its services.
113      */

114     protected Provider(String JavaDoc name, double version, String JavaDoc info) {
115     this.name = name;
116     this.version = version;
117     this.info = info;
118     putId();
119     }
120
121     /**
122      * Returns the name of this provider.
123      *
124      * @return the name of this provider.
125      */

126     public String JavaDoc getName() {
127     return name;
128     }
129
130     /**
131      * Returns the version number for this provider.
132      *
133      * @return the version number for this provider.
134      */

135     public double getVersion() {
136     return version;
137     }
138
139     /**
140      * Returns a human-readable description of the provider and its
141      * services. This may return an HTML page, with relevant links.
142      *
143      * @return a description of the provider and its services.
144      */

145     public String JavaDoc getInfo() {
146     return info;
147     }
148
149     /**
150      * Returns a string with the name and the version number
151      * of this provider.
152      *
153      * @return the string with the name and the version number
154      * for this provider.
155      */

156     public String JavaDoc toString() {
157     return name + " version " + version;
158     }
159
160     /*
161      * override the following methods to ensure that provider
162      * information can only be changed if the caller has the appropriate
163      * permissions.
164      */

165
166     /**
167      * Clears this provider so that it no longer contains the properties
168      * used to look up facilities implemented by the provider.
169      *
170      * <p>First, if there is a security manager, its
171      * <code>checkSecurityAccess</code> method is called with the string
172      * <code>"clearProviderProperties."+name</code> (where <code>name</code>
173      * is the provider name) to see if it's ok to clear this provider.
174      * If the default implementation of <code>checkSecurityAccess</code>
175      * is used (that is, that method is not overriden), then this results in
176      * a call to the security manager's <code>checkPermission</code> method
177      * with a <code>SecurityPermission("clearProviderProperties."+name)</code>
178      * permission.
179      *
180      * @throws SecurityException
181      * if a security manager exists and its <code>{@link
182      * java.lang.SecurityManager#checkSecurityAccess}</code> method
183      * denies access to clear this provider
184      *
185      * @since 1.2
186      */

187     public synchronized void clear() {
188     check("clearProviderProperties."+name);
189     if (debug != null) {
190         debug.println("Remove " + name + " provider properties");
191     }
192     implClear();
193     }
194
195     /**
196      * Reads a property list (key and element pairs) from the input stream.
197      *
198      * @param inStream the input stream.
199      * @exception IOException if an error occurred when reading from the
200      * input stream.
201      * @see java.util.Properties#load
202      */

203     public synchronized void load(InputStream inStream) throws IOException {
204     check("putProviderProperty."+name);
205         if (debug != null) {
206             debug.println("Load " + name + " provider properties");
207         }
208     Properties tempProperties = new Properties();
209     tempProperties.load(inStream);
210     implPutAll(tempProperties);
211     }
212
213     /**
214      * Copies all of the mappings from the specified Map to this provider.
215      * These mappings will replace any properties that this provider had
216      * for any of the keys currently in the specified Map.
217      *
218      * @since 1.2
219      */

220     public synchronized void putAll(Map<?,?> t) {
221     check("putProviderProperty."+name);
222         if (debug != null) {
223             debug.println("Put all " + name + " provider properties");
224         }
225     implPutAll(t);
226     }
227     
228     /**
229      * Returns an unmodifiable Set view of the property entries contained
230      * in this Provider.
231      *
232      * @see java.util.Map.Entry
233      * @since 1.2
234      */

235     public synchronized Set<Map.Entry<Object JavaDoc,Object JavaDoc>> entrySet() {
236     if (entrySet == null) {
237         if (entrySetCallCount++ == 0) // Initial call
238
entrySet = Collections.unmodifiableMap(this).entrySet();
239         else
240         return super.entrySet(); // Recursive call
241
}
242     
243     // This exception will be thrown if the implementation of
244
// Collections.unmodifiableMap.entrySet() is changed such that it
245
// no longer calls entrySet() on the backing Map. (Provider's
246
// entrySet implementation depends on this "implementation detail",
247
// which is unlikely to change.
248
if (entrySetCallCount != 2)
249         throw new RuntimeException JavaDoc("Internal error.");
250     
251     return entrySet;
252     }
253     
254     /**
255      * Returns an unmodifiable Set view of the property keys contained in
256      * this provider.
257      *
258      * @since 1.2
259      */

260     public Set<Object JavaDoc> keySet() {
261     return Collections.unmodifiableSet(super.keySet());
262     }
263
264     /**
265      * Returns an unmodifiable Collection view of the property values
266      * contained in this provider.
267      *
268      * @since 1.2
269      */

270     public Collection<Object JavaDoc> values() {
271     return Collections.unmodifiableCollection(super.values());
272     }
273
274     /**
275      * Sets the <code>key</code> property to have the specified
276      * <code>value</code>.
277      *
278      * <p>First, if there is a security manager, its
279      * <code>checkSecurityAccess</code> method is called with the string
280      * <code>"putProviderProperty."+name</code>, where <code>name</code> is the
281      * provider name, to see if it's ok to set this provider's property values.
282      * If the default implementation of <code>checkSecurityAccess</code>
283      * is used (that is, that method is not overriden), then this results in
284      * a call to the security manager's <code>checkPermission</code> method
285      * with a <code>SecurityPermission("putProviderProperty."+name)</code>
286      * permission.
287      *
288      * @param key the property key.
289      *
290      * @param value the property value.
291      *
292      * @return the previous value of the specified property
293      * (<code>key</code>), or null if it did not have one.
294      *
295      * @throws SecurityException
296      * if a security manager exists and its <code>{@link
297      * java.lang.SecurityManager#checkSecurityAccess}</code> method
298      * denies access to set property values.
299      *
300      * @since 1.2
301      */

302     public synchronized Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
303     check("putProviderProperty."+name);
304         if (debug != null) {
305             debug.println("Set " + name + " provider property [" +
306               key + "/" + value +"]");
307         }
308     return implPut(key, value);
309     }
310
311     /**
312      * Removes the <code>key</code> property (and its corresponding
313      * <code>value</code>).
314      *
315      * <p>First, if there is a security manager, its
316      * <code>checkSecurityAccess</code> method is called with the string
317      * <code>"removeProviderProperty."+name</code>, where <code>name</code> is
318      * the provider name, to see if it's ok to remove this provider's
319      * properties. If the default implementation of
320      * <code>checkSecurityAccess</code> is used (that is, that method is not
321      * overriden), then this results in a call to the security manager's
322      * <code>checkPermission</code> method with a
323      * <code>SecurityPermission("removeProviderProperty."+name)</code>
324      * permission.
325      *
326      * @param key the key for the property to be removed.
327      *
328      * @return the value to which the key had been mapped,
329      * or null if the key did not have a mapping.
330      *
331      * @throws SecurityException
332      * if a security manager exists and its <code>{@link
333      * java.lang.SecurityManager#checkSecurityAccess}</code> method
334      * denies access to remove this provider's properties.
335      *
336      * @since 1.2
337      */

338     public synchronized Object JavaDoc remove(Object JavaDoc key) {
339     check("removeProviderProperty."+name);
340         if (debug != null) {
341             debug.println("Remove " + name + " provider property " + key);
342         }
343     return implRemove(key);
344     }
345
346     private static void check(String JavaDoc directive) {
347         SecurityManager JavaDoc security = System.getSecurityManager();
348         if (security != null) {
349             security.checkSecurityAccess(directive);
350         }
351     }
352     
353     // legacy properties changed since last call to any services method?
354
private transient boolean legacyChanged;
355     // serviceMap changed since last call to getServices()
356
private transient boolean servicesChanged;
357     
358     // Map<String,String>
359
private transient Map<String JavaDoc,String JavaDoc> legacyStrings;
360     
361     // Map<ServiceKey,Service>
362
// used for services added via putService(), initialized on demand
363
private transient Map<ServiceKey,Service> serviceMap;
364
365     // Map<ServiceKey,Service>
366
// used for services added via legacy methods, init on demand
367
private transient Map<ServiceKey,Service> legacyMap;
368     
369     // Set<Service>
370
// set of all services. initialized on demand, cleared on modification
371
private transient Set<Service> serviceSet;
372     
373     // register the id attributes for this provider
374
// this is to ensure that equals() and hashCode() do not incorrectly
375
// report to different provider objects as the same
376
private void putId() {
377     // note: name and info may be null
378
super.put("Provider.id name", String.valueOf(name));
379     super.put("Provider.id version", String.valueOf(version));
380     super.put("Provider.id info", String.valueOf(info));
381     super.put("Provider.id className", this.getClass().getName());
382     }
383
384     /**
385      * Copies all of the mappings from the specified Map to this provider.
386      * Internal method to be called AFTER the security check has been
387      * performed.
388      */

389     private void implPutAll(Map t) {
390     for (Map.Entry e : ((Map<?,?>)t).entrySet()) {
391         implPut(e.getKey(), e.getValue());
392     }
393     }
394     
395     private Object JavaDoc implRemove(Object JavaDoc key) {
396     if (key instanceof String JavaDoc) {
397         String JavaDoc keyString = (String JavaDoc)key;
398         if (keyString.startsWith("Provider.")) {
399         return null;
400         }
401         legacyChanged = true;
402         if (legacyStrings == null) {
403         legacyStrings = new LinkedHashMap<String JavaDoc,String JavaDoc>();
404         }
405         legacyStrings.remove(keyString);
406     }
407     return super.remove(key);
408     }
409     
410     private Object JavaDoc implPut(Object JavaDoc key, Object JavaDoc value) {
411     if ((key instanceof String JavaDoc) && (value instanceof String JavaDoc)) {
412         String JavaDoc keyString = (String JavaDoc)key;
413         if (keyString.startsWith("Provider.")) {
414         return null;
415         }
416         legacyChanged = true;
417         if (legacyStrings == null) {
418         legacyStrings = new LinkedHashMap<String JavaDoc,String JavaDoc>();
419         }
420         legacyStrings.put(keyString, (String JavaDoc)value);
421     }
422     return super.put(key, value);
423     }
424     
425     private void implClear() {
426     super.clear();
427     putId();
428     if (legacyStrings != null) {
429         legacyStrings.clear();
430     }
431     if (legacyMap != null) {
432         legacyMap.clear();
433     }
434     if (serviceMap != null) {
435         serviceMap.clear();
436     }
437     legacyChanged = false;
438     servicesChanged = false;
439     serviceSet = null;
440     }
441     
442     // used as key in the serviceMap and legacyMap HashMaps
443
private static class ServiceKey {
444     private final String JavaDoc type;
445     private final String JavaDoc algorithm;
446     private final String JavaDoc originalAlgorithm;
447     private ServiceKey(String JavaDoc type, String JavaDoc algorithm, boolean intern) {
448         this.type = type;
449         this.originalAlgorithm = algorithm;
450         algorithm = algorithm.toUpperCase(ENGLISH);
451         this.algorithm = intern ? algorithm.intern() : algorithm;
452     }
453     public int hashCode() {
454         return type.hashCode() + algorithm.hashCode();
455     }
456     public boolean equals(Object JavaDoc obj) {
457         if (this == obj) {
458         return true;
459         }
460         if (obj instanceof ServiceKey == false) {
461         return false;
462         }
463         ServiceKey other = (ServiceKey)obj;
464         return this.type.equals(other.type)
465             && this.algorithm.equals(other.algorithm);
466     }
467     boolean matches(String JavaDoc type, String JavaDoc algorithm) {
468         return (this.type == type) && (this.originalAlgorithm == algorithm);
469     }
470     }
471
472     /**
473      * Ensure all the legacy String properties are fully parsed into
474      * service objects.
475      */

476     private void ensureLegacyParsed() {
477     if ((legacyChanged == false) || (legacyStrings == null)) {
478         return;
479     }
480     serviceSet = null;
481     if (legacyMap == null) {
482         legacyMap = new LinkedHashMap<ServiceKey,Service>();
483     } else {
484         legacyMap.clear();
485     }
486     for (Map.Entry<String JavaDoc,String JavaDoc> entry : legacyStrings.entrySet()) {
487         parseLegacyPut(entry.getKey(), entry.getValue());
488     }
489     removeInvalidServices(legacyMap);
490     legacyChanged = false;
491     }
492     
493     /**
494      * Remove all invalid services from the Map. Invalid services can only
495      * occur if the legacy properties are inconsistent or incomplete.
496      */

497     private void removeInvalidServices(Map<ServiceKey,Service> map) {
498     for (Iterator t = map.entrySet().iterator(); t.hasNext(); ) {
499         Map.Entry entry = (Map.Entry)t.next();
500         Service s = (Service)entry.getValue();
501         if (s.isValid() == false) {
502         t.remove();
503         }
504     }
505     }
506     
507     private String JavaDoc[] getTypeAndAlgorithm(String JavaDoc key) {
508     int i = key.indexOf(".");
509     if (i < 1) {
510         if (debug != null) {
511         debug.println("Ignoring invalid entry in provider "
512             + name + ":" + key);
513         }
514         return null;
515     }
516     String JavaDoc type = key.substring(0, i);
517     String JavaDoc alg = key.substring(i + 1);
518     return new String JavaDoc[] {type, alg};
519     }
520     
521     private final static String JavaDoc ALIAS_PREFIX = "Alg.Alias.";
522     private final static String JavaDoc ALIAS_PREFIX_LOWER = "alg.alias.";
523     private final static int ALIAS_LENGTH = ALIAS_PREFIX.length();
524     
525     private void parseLegacyPut(String JavaDoc name, String JavaDoc value) {
526     if (name.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) {
527         // e.g. put("Alg.Alias.MessageDigest.SHA", "SHA-1");
528
// aliasKey ~ MessageDigest.SHA
529
String JavaDoc stdAlg = value;
530         String JavaDoc aliasKey = name.substring(ALIAS_LENGTH);
531         String JavaDoc[] typeAndAlg = getTypeAndAlgorithm(aliasKey);
532         if (typeAndAlg == null) {
533         return;
534         }
535         String JavaDoc type = getEngineName(typeAndAlg[0]);
536         String JavaDoc aliasAlg = typeAndAlg[1].intern();
537         ServiceKey key = new ServiceKey(type, stdAlg, true);
538         Service s = (Service)legacyMap.get(key);
539         if (s == null) {
540         s = new Service(this);
541         s.type = type;
542         s.algorithm = stdAlg;
543         legacyMap.put(key, s);
544         }
545         legacyMap.put(new ServiceKey(type, aliasAlg, true), s);
546         s.addAlias(aliasAlg);
547     } else {
548         String JavaDoc[] typeAndAlg = getTypeAndAlgorithm(name);
549         if (typeAndAlg == null) {
550         return;
551         }
552         int i = typeAndAlg[1].indexOf(' ');
553         if (i == -1) {
554         // e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA");
555
String JavaDoc type = getEngineName(typeAndAlg[0]);
556         String JavaDoc stdAlg = typeAndAlg[1].intern();
557         String JavaDoc className = value;
558         ServiceKey key = new ServiceKey(type, stdAlg, true);
559         Service s = (Service)legacyMap.get(key);
560         if (s == null) {
561             s = new Service(this);
562             s.type = type;
563             s.algorithm = stdAlg;
564             legacyMap.put(key, s);
565         }
566         s.className = className;
567         } else { // attribute
568
// e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software");
569
String JavaDoc attributeValue = value;
570         String JavaDoc type = getEngineName(typeAndAlg[0]);
571         String JavaDoc attributeString = typeAndAlg[1];
572         String JavaDoc stdAlg = attributeString.substring(0, i).intern();
573         String JavaDoc attributeName = attributeString.substring(i + 1);
574         // kill additional spaces
575
while (attributeName.startsWith(" ")) {
576             attributeName = attributeName.substring(1);
577         }
578         attributeName = attributeName.intern();
579         ServiceKey key = new ServiceKey(type, stdAlg, true);
580         Service s = (Service)legacyMap.get(key);
581         if (s == null) {
582             s = new Service(this);
583             s.type = type;
584             s.algorithm = stdAlg;
585             legacyMap.put(key, s);
586         }
587         s.addAttribute(attributeName, attributeValue);
588         }
589     }
590     }
591     
592     /**
593      * Get the service describing this Provider's implementation of the
594      * specified type of this algorithm or alias. If no such
595      * implementation exists, this method returns null. If there are two
596      * matching services, one added to this provider using
597      * {@link #putService putService()} and one added via {@link #put put()},
598      * the service added via {@link #putService putService()} is returned.
599      *
600      * @param type the type of {@link Service service} requested
601      * (for example, <code>MessageDigest</code>)
602      * @param algorithm the case insensitive algorithm name (or alternate
603      * alias) of the service requested (for example, <code>SHA-1</code>)
604      *
605      * @return the service describing this Provider's matching service
606      * or null if no such service exists
607      *
608      * @throws NullPointerException if type or algorithm is null
609      *
610      * @since 1.5
611      */

612     public synchronized Service getService(String JavaDoc type, String JavaDoc algorithm) {
613     // avoid allocating a new key object if possible
614
ServiceKey key = previousKey;
615     if (key.matches(type, algorithm) == false) {
616         key = new ServiceKey(type, algorithm, false);
617         previousKey = key;
618     }
619     if (serviceMap != null) {
620         Service service = serviceMap.get(key);
621         if (service != null) {
622         return service;
623         }
624     }
625     ensureLegacyParsed();
626     return (legacyMap != null) ? legacyMap.get(key) : null;
627     }
628     
629     // ServiceKey from previous getService() call
630
// by re-using it if possible we avoid allocating a new object
631
// and the toUpperCase() call.
632
// re-use will occur e.g. as the framework traverses the provider
633
// list and queries each provider with the same values until it finds
634
// a matching service
635
private static volatile ServiceKey previousKey =
636                         new ServiceKey("", "", false);
637     
638     /**
639      * Get an unmodifiable Set of all services supported by
640      * this Provider.
641      *
642      * @return an unmodifiable Set of all services supported by
643      * this Provider
644      *
645      * @since 1.5
646      */

647     public synchronized Set<Service> getServices() {
648     if (legacyChanged || servicesChanged) {
649         serviceSet = null;
650     } else if (serviceSet != null) {
651         return serviceSet;
652     }
653     ensureLegacyParsed();
654     serviceSet = new LinkedHashSet<Service>();
655     if (serviceMap != null) {
656         serviceSet.addAll(serviceMap.values());
657     }
658     if (legacyMap != null) {
659         serviceSet.addAll(legacyMap.values());
660     }
661     servicesChanged = false;
662     return serviceSet;
663     }
664
665     /**
666      * Add a service. If a service of the same type with the same algorithm
667      * name exists and it was added using {@link #putService putService()},
668      * it is replaced by the new service.
669      * This method also places information about this service
670      * in the provider's Hashtable values in the format described in the
671      * <a HREF="../../../guide/security/CryptoSpec.html">
672      * Java Cryptography Architecture API Specification &amp; Reference </a>.
673      *
674      * <p>Also, if there is a security manager, its
675      * <code>checkSecurityAccess</code> method is called with the string
676      * <code>"putProviderProperty."+name</code>, where <code>name</code> is
677      * the provider name, to see if it's ok to set this provider's property
678      * values. If the default implementation of <code>checkSecurityAccess</code>
679      * is used (that is, that method is not overriden), then this results in
680      * a call to the security manager's <code>checkPermission</code> method with
681      * a <code>SecurityPermission("putProviderProperty."+name)</code>
682      * permission.
683      *
684      * @param s the Service to add
685      *
686      * @throws SecurityException
687      * if a security manager exists and its <code>{@link
688      * java.lang.SecurityManager#checkSecurityAccess}</code> method denies
689      * access to set property values.
690      * @throws NullPointerException if s is null
691      *
692      * @since 1.5
693      */

694     protected synchronized void putService(Service s) {
695     check("putProviderProperty." + name);
696     if (debug != null) {
697             debug.println(name + ".putService(): " + s);
698     }
699     if (s == null) {
700         throw new NullPointerException JavaDoc();
701     }
702     if (serviceMap == null) {
703         serviceMap = new LinkedHashMap<ServiceKey,Service>();
704     }
705     servicesChanged = true;
706     String JavaDoc type = s.getType();
707     String JavaDoc algorithm = s.getAlgorithm();
708     ServiceKey key = new ServiceKey(type, algorithm, true);
709     // remove existing service
710
implRemoveService(serviceMap.get(key));
711     serviceMap.put(key, s);
712     for (String JavaDoc alias : s.getAliases()) {
713         serviceMap.put(new ServiceKey(type, alias, true), s);
714     }
715     putPropertyStrings(s);
716     }
717     
718     /**
719      * Put the string properties for this Service in this Provider's
720      * Hashtable.
721      */

722     private void putPropertyStrings(Service s) {
723     String JavaDoc type = s.getType();
724     String JavaDoc algorithm = s.getAlgorithm();
725     // use super() to avoid permission check and other processing
726
super.put(type + "." + algorithm, s.getClassName());
727     for (String JavaDoc alias : s.getAliases()) {
728         super.put(ALIAS_PREFIX + type + "." + alias, algorithm);
729     }
730     for (Map.Entry<UString,String JavaDoc> entry : s.attributes.entrySet()) {
731         String JavaDoc key = type + "." + algorithm + " " + entry.getKey();
732         super.put(key, entry.getValue());
733     }
734     }
735
736     /**
737      * Remove the string properties for this Service from this Provider's
738      * Hashtable.
739      */

740     private void removePropertyStrings(Service s) {
741     String JavaDoc type = s.getType();
742     String JavaDoc algorithm = s.getAlgorithm();
743     // use super() to avoid permission check and other processing
744
super.remove(type + "." + algorithm);
745     for (String JavaDoc alias : s.getAliases()) {
746         super.remove(ALIAS_PREFIX + type + "." + alias);
747     }
748     for (Map.Entry<UString,String JavaDoc> entry : s.attributes.entrySet()) {
749         String JavaDoc key = type + "." + algorithm + " " + entry.getKey();
750         super.remove(key);
751     }
752     }
753
754     /**
755      * Remove a service previously added using
756      * {@link #putService putService()}. The specified service is removed from
757      * this provider. It will no longer be returned by
758      * {@link #getService getService()} and its information will be removed
759      * from this provider's Hashtable.
760      *
761      * <p>Also, if there is a security manager, its
762      * <code>checkSecurityAccess</code> method is called with the string
763      * <code>"removeProviderProperty."+name</code>, where <code>name</code> is
764      * the provider name, to see if it's ok to remove this provider's
765      * properties. If the default implementation of
766      * <code>checkSecurityAccess</code> is used (that is, that method is not
767      * overriden), then this results in a call to the security manager's
768      * <code>checkPermission</code> method with a
769      * <code>SecurityPermission("removeProviderProperty."+name)</code>
770      * permission.
771      *
772      * @param s the Service to be removed
773      *
774      * @throws SecurityException
775      * if a security manager exists and its <code>{@link
776      * java.lang.SecurityManager#checkSecurityAccess}</code> method denies
777      * access to remove this provider's properties.
778      * @throws NullPointerException if s is null
779      *
780      * @since 1.5
781      */

782     protected synchronized void removeService(Service s) {
783     check("removeProviderProperty." + name);
784         if (debug != null) {
785             debug.println(name + ".removeService(): " + s);
786         }
787     if (s == null) {
788         throw new NullPointerException JavaDoc();
789     }
790     implRemoveService(s);
791     }
792     
793     private void implRemoveService(Service s) {
794     if ((s == null) || (serviceMap == null)) {
795         return;
796     }
797     String JavaDoc type = s.getType();
798     String JavaDoc algorithm = s.getAlgorithm();
799     ServiceKey key = new ServiceKey(type, algorithm, false);
800     Service oldService = serviceMap.get(key);
801     if (s != oldService) {
802         return;
803     }
804     servicesChanged = true;
805     serviceMap.remove(key);
806     for (String JavaDoc alias : s.getAliases()) {
807         serviceMap.remove(new ServiceKey(type, alias, false));
808     }
809     removePropertyStrings(s);
810     }
811
812     // Wrapped String that behaves in a case insensitive way for equals/hashCode
813
private static class UString {
814     final String JavaDoc string;
815     final String JavaDoc lowerString;
816     
817     UString(String JavaDoc s) {
818         this.string = s;
819         this.lowerString = s.toLowerCase(ENGLISH);
820     }
821     
822     public int hashCode() {
823         return lowerString.hashCode();
824     }
825     
826     public boolean equals(Object JavaDoc obj) {
827         if (this == obj) {
828         return true;
829         }
830         if (obj instanceof UString == false) {
831         return false;
832         }
833         UString other = (UString)obj;
834         return lowerString.equals(other.lowerString);
835     }
836     
837     public String JavaDoc toString() {
838         return string;
839     }
840     }
841
842     // describe relevant properties of a type of engine
843
private static class EngineDescription {
844     final String JavaDoc name;
845     final boolean constructor;
846     final boolean supportsParameter;
847     
848     EngineDescription(String JavaDoc name, boolean constructor, boolean sp) {
849         this.name = name;
850         this.constructor = constructor;
851         this.supportsParameter = sp;
852     }
853     }
854     
855     // built in knowledge of the engine types shipped as part of the JDK
856
private static final Map<String JavaDoc,EngineDescription> knownEngines;
857     
858     private static void addEngine(String JavaDoc name, boolean cons, boolean sp) {
859     EngineDescription ed = new EngineDescription(name, cons, sp);
860     // also index by canonical name to avoid toLowerCase() for some lookups
861
knownEngines.put(name.toLowerCase(ENGLISH), ed);
862     knownEngines.put(name, ed);
863     }
864     
865     static {
866     knownEngines = new HashMap<String JavaDoc,EngineDescription>();
867     // JCA
868
addEngine("AlgorithmParameterGenerator", false, false);
869     addEngine("AlgorithmParameters", false, false);
870     addEngine("KeyFactory", false, false);
871     addEngine("KeyPairGenerator", false, false);
872     addEngine("KeyStore", false, false);
873     addEngine("MessageDigest", false, false);
874     addEngine("SecureRandom", false, false);
875     addEngine("Signature", false, true);
876     addEngine("CertificateFactory", false, false);
877     addEngine("CertPathBuilder", false, false);
878     addEngine("CertPathValidator", false, false);
879     addEngine("CertStore", true, false);
880     // JCE
881
addEngine("Cipher", false, true);
882     addEngine("ExemptionMechanism", false, false);
883     addEngine("Mac", false, true);
884     addEngine("KeyAgreement", false, true);
885     addEngine("KeyGenerator", false, false);
886     addEngine("SecretKeyFactory", false, false);
887     // JSSE
888
addEngine("KeyManagerFactory", false, false);
889     addEngine("SSLContext", false, false);
890     addEngine("TrustManagerFactory", false, false);
891     // JGSS
892
addEngine("GssApiMechanism", false, false);
893     // SASL
894
addEngine("SaslClientFactory", false, false);
895     addEngine("SaslServerFactory", false, false);
896     }
897     
898     // get the "standard" (mixed-case) engine name for arbitary case engine name
899
// if there is no known engine by that name, return s
900
private static String JavaDoc getEngineName(String JavaDoc s) {
901     // try original case first, usually correct
902
EngineDescription e = knownEngines.get(s);
903     if (e == null) {
904         e = knownEngines.get(s.toLowerCase(ENGLISH));
905     }
906     return (e == null) ? s : e.name;
907     }
908     
909     /**
910      * The description of a security service. It encapsulates the properties
911      * of a service and contains a factory method to obtain new implementation
912      * instances of this service.
913      *
914      * <p>Each service has a provider that offers the service, a type,
915      * an algorithm name, and the name of the class that implements the
916      * service. Optionally, it also includes a list of alternate algorithm
917      * names for this service (aliases) and attributes, which are a map of
918      * (name, value) String pairs.
919      *
920      * <p>This class defines the methods {@link #supportsParameter
921      * supportsParameter()} and {@link #newInstance newInstance()}
922      * which are used by the Java security framework when it searches for
923      * suitable services and instantes them. The valid arguments to those
924      * methods depend on the type of service. For the service types defined
925      * within J2SE, see the
926      * <a HREF="../../../guide/security/CryptoSpec.html">
927      * Java Cryptography Architecture API Specification &amp; Reference </a>
928      * for the valid values.
929      * Note that components outside of J2SE can define additional types of
930      * services and their behavior.
931      *
932      * <p>Instances of this class are immutable.
933      *
934      * @since 1.5
935      */

936     public static class Service {
937     
938     private String JavaDoc type, algorithm, className;
939     private final Provider JavaDoc provider;
940     private List<String JavaDoc> aliases;
941     private Map<UString,String JavaDoc> attributes;
942
943     // Reference to the cached implementation Class object
944
private volatile Reference<Class JavaDoc> classRef;
945     
946     // flag indicating whether this service has its attributes for
947
// supportedKeyFormats or supportedKeyClasses set
948
// if null, the values have not been initialized
949
// if TRUE, at least one of supportedFormats/Classes is non null
950
private volatile Boolean JavaDoc hasKeyAttributes;
951     
952     // supported encoding formats
953
private String JavaDoc[] supportedFormats;
954     
955     // names of the supported key (super) classes
956
private Class JavaDoc[] supportedClasses;
957     
958     private static final Class JavaDoc[] CLASS0 = new Class JavaDoc[0];
959     
960     // this constructor and these methods are used for parsing
961
// the legacy string properties.
962

963     private Service(Provider JavaDoc provider) {
964         this.provider = provider;
965         aliases = Collections.<String JavaDoc>emptyList();
966         attributes = Collections.<UString,String JavaDoc>emptyMap();
967     }
968
969     private boolean isValid() {
970         return (type != null) && (algorithm != null) && (className != null);
971     }
972     
973     private void addAlias(String JavaDoc alias) {
974         if (aliases.isEmpty()) {
975         aliases = new ArrayList<String JavaDoc>(2);
976         }
977         aliases.add(alias);
978     }
979     
980     void addAttribute(String JavaDoc type, String JavaDoc value) {
981         if (attributes.isEmpty()) {
982         attributes = new HashMap<UString,String JavaDoc>(8);
983         }
984         attributes.put(new UString(type), value);
985     }
986     
987     /**
988      * Construct a new service.
989      *
990      * @param provider the provider that offers this service
991      * @param type the type of this service
992      * @param algorithm the algorithm name
993      * @param className the name of the class implementing this service
994      * @param aliases List of aliases or null if algorithm has no aliases
995      * @param attributes Map of attributes or null if this implementation
996      * has no attributes
997      *
998      * @throws NullPointerException if provider, type, algorithm, or
999      * className is null
1000     */

1001    public Service(Provider JavaDoc provider, String JavaDoc type, String JavaDoc algorithm,
1002        String JavaDoc className, List<String JavaDoc> aliases,
1003        Map<String JavaDoc,String JavaDoc> attributes) {
1004        if ((provider == null) || (type == null) ||
1005            (algorithm == null) || (className == null)) {
1006        throw new NullPointerException JavaDoc();
1007        }
1008        this.provider = provider;
1009        this.type = getEngineName(type);
1010        this.algorithm = algorithm;
1011        this.className = className;
1012        if (aliases == null) {
1013        this.aliases = Collections.<String JavaDoc>emptyList();
1014        } else {
1015        this.aliases = new ArrayList<String JavaDoc>(aliases);
1016        }
1017        if (attributes == null) {
1018        this.attributes = Collections.<UString,String JavaDoc>emptyMap();
1019        } else {
1020        this.attributes = new HashMap<UString,String JavaDoc>();
1021        for (Map.Entry<String JavaDoc,String JavaDoc> entry : attributes.entrySet()) {
1022            this.attributes.put(new UString(entry.getKey()), entry.getValue());
1023        }
1024        }
1025    }
1026    
1027    /**
1028     * Get the type of this service. For example, <code>MessageDigest</code>.
1029     *
1030     * @return the type of this service
1031     */

1032    public final String JavaDoc getType() {
1033        return type;
1034    }
1035    
1036    /**
1037     * Return the name of the algorithm of this service. For example,
1038     * <code>SHA-1</code>.
1039     *
1040     * @return the algorithm of this service
1041     */

1042    public final String JavaDoc getAlgorithm() {
1043        return algorithm;
1044    }
1045    
1046    /**
1047     * Return the Provider of this service.
1048     *
1049     * @return the Provider of this service
1050     */

1051    public final Provider JavaDoc getProvider() {
1052        return provider;
1053    }
1054    
1055    /**
1056     * Return the name of the class implementing this service.
1057     *
1058     * @return the name of the class implementing this service
1059     */

1060    public final String JavaDoc getClassName() {
1061        return className;
1062    }
1063    
1064    // internal only
1065
private final List<String JavaDoc> getAliases() {
1066        return aliases;
1067    }
1068    
1069    /**
1070     * Return the value of the specified attribute or null if this
1071     * attribute is not set for this Service.
1072     *
1073     * @param name the name of the requested attribute
1074     *
1075     * @return the value of the specified attribute or null if the
1076     * attribute is not present
1077     *
1078     * @throws NullPointerException if name is null
1079     */

1080    public final String JavaDoc getAttribute(String JavaDoc name) {
1081        if (name == null) {
1082        throw new NullPointerException JavaDoc();
1083        }
1084        return attributes.get(new UString(name));
1085    }
1086    
1087    /**
1088     * Return a new instance of the implementation described by this
1089     * service. The security provider framework uses this method to
1090     * construct implementations. Applications will typically not need
1091     * to call it.
1092     *
1093     * <p>The default implementation uses reflection to invoke the
1094     * standard constructor for this type of service.
1095     * Security providers can override this method to implement
1096     * instantiation in a different way.
1097     * For details and the values of constructorParameter that are
1098     * valid for the various types of services see the
1099     * <a HREF="../../../guide/security/CryptoSpec.html">
1100     * Java Cryptography Architecture API Specification &amp;
1101     * Reference</a>.
1102     *
1103     * @param constructorParameter the value to pass to the constructor,
1104     * or null if this type of service does not use a constructorParameter.
1105     *
1106     * @return a new implementation of this service
1107     *
1108     * @throws InvalidParameterException if the value of
1109     * constructorParameter is invalid for this type of service.
1110     * @throws NoSuchAlgorithmException if instantation failed for
1111     * any other reason.
1112     */

1113    public Object JavaDoc newInstance(Object JavaDoc constructorParameter)
1114        throws NoSuchAlgorithmException JavaDoc {
1115        try {
1116        EngineDescription cap = knownEngines.get(type);
1117        if (cap == null) {
1118            // unknown engine type, use generic code
1119
// this is the code path future for non-core
1120
// optional packages
1121
return newInstanceGeneric(constructorParameter);
1122        }
1123        if (cap.constructor == false) {
1124            if (constructorParameter != null) {
1125            throw new InvalidParameterException JavaDoc
1126                ("constructorParameter not used with " + type
1127                + " engines");
1128            }
1129            Class JavaDoc clazz = getImplClass();
1130            return clazz.newInstance();
1131        }
1132        if (type.equals("CertStore") == false) {
1133            throw new AssertionError JavaDoc("Unknown engine: " + type);
1134        }
1135        if (constructorParameter != null &&
1136            !(constructorParameter instanceof CertStoreParameters JavaDoc)) {
1137            throw new InvalidParameterException JavaDoc
1138                ("constructorParameter must be instanceof "
1139            + "CertStoreParameters for CertStores");
1140        }
1141        Class JavaDoc clazz = getImplClass();
1142        // use Class.forName() rather than .class to delay
1143
// class loading
1144
Constructor cons = clazz.getConstructor(new Class JavaDoc[]
1145           { Class.forName("java.security.cert.CertStoreParameters") });
1146        return cons.newInstance(new Object JavaDoc[] {constructorParameter});
1147        } catch (NoSuchAlgorithmException JavaDoc e) {
1148        throw e;
1149        } catch (InvocationTargetException e) {
1150        throw new NoSuchAlgorithmException JavaDoc
1151            ("Error constructing implementation (algorithm: "
1152            + algorithm + ", provider: " + provider.getName()
1153            + ", class: " + className + ")", e.getCause());
1154        } catch (Exception JavaDoc e) {
1155        throw new NoSuchAlgorithmException JavaDoc
1156            ("Error constructing implementation (algorithm: "
1157            + algorithm + ", provider: " + provider.getName()
1158            + ", class: " + className + ")", e);
1159        }
1160    }
1161    
1162    // return the implementation Class object for this service
1163
private Class JavaDoc getImplClass() throws NoSuchAlgorithmException JavaDoc {
1164        try {
1165        Reference<Class JavaDoc> ref = classRef;
1166        Class JavaDoc clazz = (ref == null) ? null : ref.get();
1167        if (clazz == null) {
1168            ClassLoader JavaDoc cl = provider.getClass().getClassLoader();
1169            if (cl == null) {
1170            clazz = Class.forName(className);
1171            } else {
1172            clazz = cl.loadClass(className);
1173            }
1174            classRef = new WeakReference<Class JavaDoc>(clazz);
1175        }
1176        return clazz;
1177        } catch (ClassNotFoundException JavaDoc e) {
1178        throw new NoSuchAlgorithmException JavaDoc
1179                ("class configured for " + type + "(provider: " +
1180            provider.getName() + ")" + "cannot be found.", e);
1181        }
1182    }
1183    
1184    /**
1185     * Generic code path for unknown engine types. Call the
1186     * no-args constructor if constructorParameter is null, otherwise
1187     * use the first matching constructor.
1188     */

1189    private Object JavaDoc newInstanceGeneric(Object JavaDoc constructorParameter)
1190        throws Exception JavaDoc {
1191        Class JavaDoc clazz = getImplClass();
1192        if (constructorParameter == null) {
1193        Object JavaDoc o = clazz.newInstance();
1194        return o;
1195        }
1196        Class JavaDoc argClass = constructorParameter.getClass();
1197        Constructor[] cons = clazz.getConstructors();
1198        // find first public constructor that can take the
1199
// argument as parameter
1200
for (int i = 0; i < cons.length; i++) {
1201        Constructor con = cons[i];
1202        Class JavaDoc[] paramTypes = con.getParameterTypes();
1203        if (paramTypes.length != 1) {
1204            continue;
1205        }
1206        if (paramTypes[0].isAssignableFrom(argClass) == false) {
1207            continue;
1208        }
1209        Object JavaDoc o = con.newInstance(new Object JavaDoc[] {constructorParameter});
1210        return o;
1211        }
1212        throw new NoSuchAlgorithmException JavaDoc("No constructor matching "
1213            + argClass.getName() + " found in class " + className);
1214    }
1215    
1216    /**
1217     * Test whether this Service can use the specified parameter.
1218     * Returns false if this service cannot use the parameter. Returns
1219     * true if this service can use the parameter, if a fast test is
1220     * infeasible, or if the status is unknown.
1221     *
1222     * <p>The security provider framework uses this method with
1223     * some types of services to quickly exclude non-matching
1224     * implementations for consideration.
1225     * Applications will typically not need to call it.
1226     *
1227     * <p>For details and the values of parameter that are valid for the
1228     * various types of services see the top of this class and the
1229     * <a HREF="../../../guide/security/CryptoSpec.html">
1230     * Java Cryptography Architecture API Specification &amp;
1231     * Reference</a>.
1232     * Security providers can override it to implement their own test.
1233     *
1234     * @param parameter the parameter to test
1235     *
1236     * @return false if this this service cannot use the specified
1237     * parameter; true if it can possibly use the parameter
1238     *
1239     * @throws InvalidParameterException if the value of parameter is
1240     * invalid for this type of service or if this method cannot be
1241     * used with this type of service
1242     */

1243    public boolean supportsParameter(Object JavaDoc parameter) {
1244        EngineDescription cap = knownEngines.get(type);
1245        if (cap == null) {
1246        // unknown engine type, return true by default
1247
return true;
1248        }
1249        if (cap.supportsParameter == false) {
1250        throw new InvalidParameterException JavaDoc("supportsParameter() not "
1251            + "used with " + type + " engines");
1252        }
1253        // allow null for keys without attributes for compatibility
1254
if ((parameter != null) && (parameter instanceof Key JavaDoc == false)) {
1255        throw new InvalidParameterException JavaDoc
1256            ("Parameter must be instanceof Key for engine " + type);
1257        }
1258        if (hasKeyAttributes() == false) {
1259        return true;
1260        }
1261        if (parameter == null) {
1262        return false;
1263        }
1264        Key JavaDoc key = (Key JavaDoc)parameter;
1265        if (supportsKeyFormat(key)) {
1266        return true;
1267        }
1268        if (supportsKeyClass(key)) {
1269        return true;
1270        }
1271        return false;
1272    }
1273    
1274    /**
1275     * Return whether this service has its Supported* properties for
1276     * keys defined. Parses the attributes if not yet initialized.
1277     */

1278    private boolean hasKeyAttributes() {
1279        Boolean JavaDoc b = hasKeyAttributes;
1280        if (b == null) {
1281        synchronized (this) {
1282            String JavaDoc s;
1283            s = getAttribute("SupportedKeyFormats");
1284            if (s != null) {
1285            supportedFormats = s.split("\\|");
1286            }
1287            s = getAttribute("SupportedKeyClasses");
1288            if (s != null) {
1289            String JavaDoc[] classNames = s.split("\\|");
1290            List<Class JavaDoc> classList =
1291                new ArrayList<Class JavaDoc>(classNames.length);
1292            for (String JavaDoc className : classNames) {
1293                Class JavaDoc clazz = getKeyClass(className);
1294                if (clazz != null) {
1295                classList.add(clazz);
1296                }
1297            }
1298            supportedClasses = classList.toArray(CLASS0);
1299            }
1300            boolean bool = (supportedFormats != null)
1301                || (supportedClasses != null);
1302            b = Boolean.valueOf(bool);
1303            hasKeyAttributes = b;
1304        }
1305        }
1306        return b.booleanValue();
1307    }
1308    
1309    // get the key class object of the specified name
1310
private Class JavaDoc getKeyClass(String JavaDoc name) {
1311        try {
1312        return Class.forName(name);
1313        } catch (ClassNotFoundException JavaDoc e) {
1314        // ignore
1315
}
1316        try {
1317        ClassLoader JavaDoc cl = provider.getClass().getClassLoader();
1318        if (cl != null) {
1319            return cl.loadClass(name);
1320        }
1321        } catch (ClassNotFoundException JavaDoc e) {
1322        // ignore
1323
}
1324        return null;
1325    }
1326    
1327    private boolean supportsKeyFormat(Key JavaDoc key) {
1328        if (supportedFormats == null) {
1329        return false;
1330        }
1331        String JavaDoc format = key.getFormat();
1332        if (format == null) {
1333        return false;
1334        }
1335        for (String JavaDoc supportedFormat : supportedFormats) {
1336        if (supportedFormat.equals(format)) {
1337            return true;
1338        }
1339        }
1340        return false;
1341    }
1342    
1343    private boolean supportsKeyClass(Key JavaDoc key) {
1344        if (supportedClasses == null) {
1345        return false;
1346        }
1347        Class JavaDoc keyClass = key.getClass();
1348        for (Class JavaDoc clazz : supportedClasses) {
1349        if (clazz.isAssignableFrom(keyClass)) {
1350            return true;
1351        }
1352        }
1353        return false;
1354    }
1355    
1356    /**
1357     * Return a String representation of this service.
1358     *
1359     * @return a String representation of this service.
1360     */

1361    public String JavaDoc toString() {
1362        String JavaDoc aString = aliases.isEmpty()
1363        ? "" : "\r\n aliases: " + aliases.toString();
1364        String JavaDoc attrs = attributes.isEmpty()
1365        ? "" : "\r\n attributes: " + attributes.toString();
1366        return provider.getName() + ": " + type + "." + algorithm
1367            + " -> " + className + aString + attrs + "\r\n";
1368    }
1369    
1370    }
1371
1372}
1373
1374
Popular Tags