0001 /*
0002 * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package java.security;
0027
0028 import java.io.*;
0029 import java.util.*;
0030 import static java.util.Locale.ENGLISH;
0031 import java.lang.ref.*;
0032 import java.lang.reflect.*;
0033
0034 import java.security.cert.CertStoreParameters;
0035 import javax.security.auth.login.Configuration;
0036
0037 /**
0038 * This class represents a "provider" for the
0039 * Java Security API, where a provider implements some or all parts of
0040 * Java Security. Services that a provider may implement include:
0041 *
0042 * <ul>
0043 *
0044 * <li>Algorithms (such as DSA, RSA, MD5 or SHA-1).
0045 *
0046 * <li>Key generation, conversion, and management facilities (such as for
0047 * algorithm-specific keys).
0048 *
0049 *</ul>
0050 *
0051 * <p>Each provider has a name and a version number, and is configured
0052 * in each runtime it is installed in.
0053 *
0054 * <p>See <a href =
0055 * "../../../technotes/guides/security/crypto/CryptoSpec.html#Provider">The Provider Class</a>
0056 * in the "Java Cryptography Architecture API Specification & Reference"
0057 * for information about how a particular type of provider, the
0058 * cryptographic service provider, works and is installed. However,
0059 * please note that a provider can be used to implement any security
0060 * service in Java that uses a pluggable architecture with a choice
0061 * of implementations that fit underneath.
0062 *
0063 * <p>Some provider implementations may encounter unrecoverable internal
0064 * errors during their operation, for example a failure to communicate with a
0065 * security token. A {@link ProviderException} should be used to indicate
0066 * such errors.
0067 *
0068 * <p>The service type <code>Provider</code> is reserved for use by the
0069 * security framework. Services of this type cannot be added, removed,
0070 * or modified by applications.
0071 * The following attributes are automatically placed in each Provider object:
0072 * <table cellspacing=4>
0073 * <tr><th>Name</th><th>Value</th>
0074 * <tr><td><code>Provider.id name</code></td>
0075 * <td><code>String.valueOf(provider.getName())</code></td>
0076 * <tr><td><code>Provider.id version</code></td>
0077 * <td><code>String.valueOf(provider.getVersion())</code></td>
0078 * <tr><td><code>Provider.id info</code></td>
0079 <td><code>String.valueOf(provider.getInfo())</code></td>
0080 * <tr><td><code>Provider.id className</code></td>
0081 * <td><code>provider.getClass().getName()</code></td>
0082 * </table>
0083 *
0084 * @version 1.84, 05/05/07
0085 * @author Benjamin Renaud
0086 * @author Andreas Sterbenz
0087 */
0088 public abstract class Provider extends Properties {
0089
0090 // Declare serialVersionUID to be compatible with JDK1.1
0091 static final long serialVersionUID = -4298000515446427739L;
0092
0093 private static final sun.security.util.Debug debug = sun.security.util.Debug
0094 .getInstance("provider", "Provider");
0095
0096 /**
0097 * The provider name.
0098 *
0099 * @serial
0100 */
0101 private String name;
0102
0103 /**
0104 * A description of the provider and its services.
0105 *
0106 * @serial
0107 */
0108 private String info;
0109
0110 /**
0111 * The provider version number.
0112 *
0113 * @serial
0114 */
0115 private double version;
0116
0117 private transient Set<Map.Entry<Object, Object>> entrySet = null;
0118 private transient int entrySetCallCount = 0;
0119
0120 private transient boolean initialized;
0121
0122 /**
0123 * Constructs a provider with the specified name, version number,
0124 * and information.
0125 *
0126 * @param name the provider name.
0127 *
0128 * @param version the provider version number.
0129 *
0130 * @param info a description of the provider and its services.
0131 */
0132 protected Provider(String name, double version, String info) {
0133 this .name = name;
0134 this .version = version;
0135 this .info = info;
0136 putId();
0137 initialized = true;
0138 }
0139
0140 /**
0141 * Returns the name of this provider.
0142 *
0143 * @return the name of this provider.
0144 */
0145 public String getName() {
0146 return name;
0147 }
0148
0149 /**
0150 * Returns the version number for this provider.
0151 *
0152 * @return the version number for this provider.
0153 */
0154 public double getVersion() {
0155 return version;
0156 }
0157
0158 /**
0159 * Returns a human-readable description of the provider and its
0160 * services. This may return an HTML page, with relevant links.
0161 *
0162 * @return a description of the provider and its services.
0163 */
0164 public String getInfo() {
0165 return info;
0166 }
0167
0168 /**
0169 * Returns a string with the name and the version number
0170 * of this provider.
0171 *
0172 * @return the string with the name and the version number
0173 * for this provider.
0174 */
0175 public String toString() {
0176 return name + " version " + version;
0177 }
0178
0179 /*
0180 * override the following methods to ensure that provider
0181 * information can only be changed if the caller has the appropriate
0182 * permissions.
0183 */
0184
0185 /**
0186 * Clears this provider so that it no longer contains the properties
0187 * used to look up facilities implemented by the provider.
0188 *
0189 * <p>First, if there is a security manager, its
0190 * <code>checkSecurityAccess</code> method is called with the string
0191 * <code>"clearProviderProperties."+name</code> (where <code>name</code>
0192 * is the provider name) to see if it's ok to clear this provider.
0193 * If the default implementation of <code>checkSecurityAccess</code>
0194 * is used (that is, that method is not overriden), then this results in
0195 * a call to the security manager's <code>checkPermission</code> method
0196 * with a <code>SecurityPermission("clearProviderProperties."+name)</code>
0197 * permission.
0198 *
0199 * @throws SecurityException
0200 * if a security manager exists and its <code>{@link
0201 * java.lang.SecurityManager#checkSecurityAccess}</code> method
0202 * denies access to clear this provider
0203 *
0204 * @since 1.2
0205 */
0206 public synchronized void clear() {
0207 check("clearProviderProperties." + name);
0208 if (debug != null) {
0209 debug.println("Remove " + name + " provider properties");
0210 }
0211 implClear();
0212 }
0213
0214 /**
0215 * Reads a property list (key and element pairs) from the input stream.
0216 *
0217 * @param inStream the input stream.
0218 * @exception IOException if an error occurred when reading from the
0219 * input stream.
0220 * @see java.util.Properties#load
0221 */
0222 public synchronized void load(InputStream inStream)
0223 throws IOException {
0224 check("putProviderProperty." + name);
0225 if (debug != null) {
0226 debug.println("Load " + name + " provider properties");
0227 }
0228 Properties tempProperties = new Properties();
0229 tempProperties.load(inStream);
0230 implPutAll(tempProperties);
0231 }
0232
0233 /**
0234 * Copies all of the mappings from the specified Map to this provider.
0235 * These mappings will replace any properties that this provider had
0236 * for any of the keys currently in the specified Map.
0237 *
0238 * @since 1.2
0239 */
0240 public synchronized void putAll(Map<?, ?> t) {
0241 check("putProviderProperty." + name);
0242 if (debug != null) {
0243 debug.println("Put all " + name + " provider properties");
0244 }
0245 implPutAll(t);
0246 }
0247
0248 /**
0249 * Returns an unmodifiable Set view of the property entries contained
0250 * in this Provider.
0251 *
0252 * @see java.util.Map.Entry
0253 * @since 1.2
0254 */
0255 public synchronized Set<Map.Entry<Object, Object>> entrySet() {
0256 checkInitialized();
0257 if (entrySet == null) {
0258 if (entrySetCallCount++ == 0) // Initial call
0259 entrySet = Collections.unmodifiableMap(this ).entrySet();
0260 else
0261 return super .entrySet(); // Recursive call
0262 }
0263
0264 // This exception will be thrown if the implementation of
0265 // Collections.unmodifiableMap.entrySet() is changed such that it
0266 // no longer calls entrySet() on the backing Map. (Provider's
0267 // entrySet implementation depends on this "implementation detail",
0268 // which is unlikely to change.
0269 if (entrySetCallCount != 2)
0270 throw new RuntimeException("Internal error.");
0271
0272 return entrySet;
0273 }
0274
0275 /**
0276 * Returns an unmodifiable Set view of the property keys contained in
0277 * this provider.
0278 *
0279 * @since 1.2
0280 */
0281 public Set<Object> keySet() {
0282 checkInitialized();
0283 return Collections.unmodifiableSet(super .keySet());
0284 }
0285
0286 /**
0287 * Returns an unmodifiable Collection view of the property values
0288 * contained in this provider.
0289 *
0290 * @since 1.2
0291 */
0292 public Collection<Object> values() {
0293 checkInitialized();
0294 return Collections.unmodifiableCollection(super .values());
0295 }
0296
0297 /**
0298 * Sets the <code>key</code> property to have the specified
0299 * <code>value</code>.
0300 *
0301 * <p>First, if there is a security manager, its
0302 * <code>checkSecurityAccess</code> method is called with the string
0303 * <code>"putProviderProperty."+name</code>, where <code>name</code> is the
0304 * provider name, to see if it's ok to set this provider's property values.
0305 * If the default implementation of <code>checkSecurityAccess</code>
0306 * is used (that is, that method is not overriden), then this results in
0307 * a call to the security manager's <code>checkPermission</code> method
0308 * with a <code>SecurityPermission("putProviderProperty."+name)</code>
0309 * permission.
0310 *
0311 * @param key the property key.
0312 *
0313 * @param value the property value.
0314 *
0315 * @return the previous value of the specified property
0316 * (<code>key</code>), or null if it did not have one.
0317 *
0318 * @throws SecurityException
0319 * if a security manager exists and its <code>{@link
0320 * java.lang.SecurityManager#checkSecurityAccess}</code> method
0321 * denies access to set property values.
0322 *
0323 * @since 1.2
0324 */
0325 public synchronized Object put(Object key, Object value) {
0326 check("putProviderProperty." + name);
0327 if (debug != null) {
0328 debug.println("Set " + name + " provider property [" + key
0329 + "/" + value + "]");
0330 }
0331 return implPut(key, value);
0332 }
0333
0334 /**
0335 * Removes the <code>key</code> property (and its corresponding
0336 * <code>value</code>).
0337 *
0338 * <p>First, if there is a security manager, its
0339 * <code>checkSecurityAccess</code> method is called with the string
0340 * <code>"removeProviderProperty."+name</code>, where <code>name</code> is
0341 * the provider name, to see if it's ok to remove this provider's
0342 * properties. If the default implementation of
0343 * <code>checkSecurityAccess</code> is used (that is, that method is not
0344 * overriden), then this results in a call to the security manager's
0345 * <code>checkPermission</code> method with a
0346 * <code>SecurityPermission("removeProviderProperty."+name)</code>
0347 * permission.
0348 *
0349 * @param key the key for the property to be removed.
0350 *
0351 * @return the value to which the key had been mapped,
0352 * or null if the key did not have a mapping.
0353 *
0354 * @throws SecurityException
0355 * if a security manager exists and its <code>{@link
0356 * java.lang.SecurityManager#checkSecurityAccess}</code> method
0357 * denies access to remove this provider's properties.
0358 *
0359 * @since 1.2
0360 */
0361 public synchronized Object remove(Object key) {
0362 check("removeProviderProperty." + name);
0363 if (debug != null) {
0364 debug.println("Remove " + name + " provider property "
0365 + key);
0366 }
0367 return implRemove(key);
0368 }
0369
0370 // let javadoc show doc from superclass
0371 public Object get(Object key) {
0372 checkInitialized();
0373 return super .get(key);
0374 }
0375
0376 // let javadoc show doc from superclass
0377 public Enumeration<Object> keys() {
0378 checkInitialized();
0379 return super .keys();
0380 }
0381
0382 // let javadoc show doc from superclass
0383 public Enumeration<Object> elements() {
0384 checkInitialized();
0385 return super .elements();
0386 }
0387
0388 // let javadoc show doc from superclass
0389 public String getProperty(String key) {
0390 checkInitialized();
0391 return super .getProperty(key);
0392 }
0393
0394 private void checkInitialized() {
0395 if (!initialized) {
0396 throw new IllegalStateException();
0397 }
0398 }
0399
0400 private void check(String directive) {
0401 checkInitialized();
0402 SecurityManager security = System.getSecurityManager();
0403 if (security != null) {
0404 security.checkSecurityAccess(directive);
0405 }
0406 }
0407
0408 // legacy properties changed since last call to any services method?
0409 private transient boolean legacyChanged;
0410 // serviceMap changed since last call to getServices()
0411 private transient boolean servicesChanged;
0412
0413 // Map<String,String>
0414 private transient Map<String, String> legacyStrings;
0415
0416 // Map<ServiceKey,Service>
0417 // used for services added via putService(), initialized on demand
0418 private transient Map<ServiceKey, Service> serviceMap;
0419
0420 // Map<ServiceKey,Service>
0421 // used for services added via legacy methods, init on demand
0422 private transient Map<ServiceKey, Service> legacyMap;
0423
0424 // Set<Service>
0425 // Unmodifiable set of all services. Initialized on demand.
0426 private transient Set<Service> serviceSet;
0427
0428 // register the id attributes for this provider
0429 // this is to ensure that equals() and hashCode() do not incorrectly
0430 // report to different provider objects as the same
0431 private void putId() {
0432 // note: name and info may be null
0433 super .put("Provider.id name", String.valueOf(name));
0434 super .put("Provider.id version", String.valueOf(version));
0435 super .put("Provider.id info", String.valueOf(info));
0436 super .put("Provider.id className", this .getClass().getName());
0437 }
0438
0439 private void readObject(ObjectInputStream in) throws IOException,
0440 ClassNotFoundException {
0441 Map<Object, Object> copy = new HashMap<Object, Object>();
0442 for (Map.Entry<Object, Object> entry : super .entrySet()) {
0443 copy.put(entry.getKey(), entry.getValue());
0444 }
0445 defaults = null;
0446 in.defaultReadObject();
0447 implClear();
0448 initialized = true;
0449 putAll(copy);
0450 }
0451
0452 /**
0453 * Copies all of the mappings from the specified Map to this provider.
0454 * Internal method to be called AFTER the security check has been
0455 * performed.
0456 */
0457 private void implPutAll(Map t) {
0458 for (Map.Entry e : ((Map<?, ?>) t).entrySet()) {
0459 implPut(e.getKey(), e.getValue());
0460 }
0461 }
0462
0463 private Object implRemove(Object key) {
0464 if (key instanceof String) {
0465 String keyString = (String) key;
0466 if (keyString.startsWith("Provider.")) {
0467 return null;
0468 }
0469 legacyChanged = true;
0470 if (legacyStrings == null) {
0471 legacyStrings = new LinkedHashMap<String, String>();
0472 }
0473 legacyStrings.remove(keyString);
0474 }
0475 return super .remove(key);
0476 }
0477
0478 private Object implPut(Object key, Object value) {
0479 if ((key instanceof String) && (value instanceof String)) {
0480 String keyString = (String) key;
0481 if (keyString.startsWith("Provider.")) {
0482 return null;
0483 }
0484 legacyChanged = true;
0485 if (legacyStrings == null) {
0486 legacyStrings = new LinkedHashMap<String, String>();
0487 }
0488 legacyStrings.put(keyString, (String) value);
0489 }
0490 return super .put(key, value);
0491 }
0492
0493 private void implClear() {
0494 if (legacyStrings != null) {
0495 legacyStrings.clear();
0496 }
0497 if (legacyMap != null) {
0498 legacyMap.clear();
0499 }
0500 if (serviceMap != null) {
0501 serviceMap.clear();
0502 }
0503 legacyChanged = false;
0504 servicesChanged = false;
0505 serviceSet = null;
0506 super .clear();
0507 putId();
0508 }
0509
0510 // used as key in the serviceMap and legacyMap HashMaps
0511 private static class ServiceKey {
0512 private final String type;
0513 private final String algorithm;
0514 private final String originalAlgorithm;
0515
0516 private ServiceKey(String type, String algorithm, boolean intern) {
0517 this .type = type;
0518 this .originalAlgorithm = algorithm;
0519 algorithm = algorithm.toUpperCase(ENGLISH);
0520 this .algorithm = intern ? algorithm.intern() : algorithm;
0521 }
0522
0523 public int hashCode() {
0524 return type.hashCode() + algorithm.hashCode();
0525 }
0526
0527 public boolean equals(Object obj) {
0528 if (this == obj) {
0529 return true;
0530 }
0531 if (obj instanceof ServiceKey == false) {
0532 return false;
0533 }
0534 ServiceKey other = (ServiceKey) obj;
0535 return this .type.equals(other.type)
0536 && this .algorithm.equals(other.algorithm);
0537 }
0538
0539 boolean matches(String type, String algorithm) {
0540 return (this .type == type)
0541 && (this .originalAlgorithm == algorithm);
0542 }
0543 }
0544
0545 /**
0546 * Ensure all the legacy String properties are fully parsed into
0547 * service objects.
0548 */
0549 private void ensureLegacyParsed() {
0550 if ((legacyChanged == false) || (legacyStrings == null)) {
0551 return;
0552 }
0553 serviceSet = null;
0554 if (legacyMap == null) {
0555 legacyMap = new LinkedHashMap<ServiceKey, Service>();
0556 } else {
0557 legacyMap.clear();
0558 }
0559 for (Map.Entry<String, String> entry : legacyStrings.entrySet()) {
0560 parseLegacyPut(entry.getKey(), entry.getValue());
0561 }
0562 removeInvalidServices(legacyMap);
0563 legacyChanged = false;
0564 }
0565
0566 /**
0567 * Remove all invalid services from the Map. Invalid services can only
0568 * occur if the legacy properties are inconsistent or incomplete.
0569 */
0570 private void removeInvalidServices(Map<ServiceKey, Service> map) {
0571 for (Iterator t = map.entrySet().iterator(); t.hasNext();) {
0572 Map.Entry entry = (Map.Entry) t.next();
0573 Service s = (Service) entry.getValue();
0574 if (s.isValid() == false) {
0575 t.remove();
0576 }
0577 }
0578 }
0579
0580 private String[] getTypeAndAlgorithm(String key) {
0581 int i = key.indexOf(".");
0582 if (i < 1) {
0583 if (debug != null) {
0584 debug.println("Ignoring invalid entry in provider "
0585 + name + ":" + key);
0586 }
0587 return null;
0588 }
0589 String type = key.substring(0, i);
0590 String alg = key.substring(i + 1);
0591 return new String[] { type, alg };
0592 }
0593
0594 private final static String ALIAS_PREFIX = "Alg.Alias.";
0595 private final static String ALIAS_PREFIX_LOWER = "alg.alias.";
0596 private final static int ALIAS_LENGTH = ALIAS_PREFIX.length();
0597
0598 private void parseLegacyPut(String name, String value) {
0599 if (name.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) {
0600 // e.g. put("Alg.Alias.MessageDigest.SHA", "SHA-1");
0601 // aliasKey ~ MessageDigest.SHA
0602 String stdAlg = value;
0603 String aliasKey = name.substring(ALIAS_LENGTH);
0604 String[] typeAndAlg = getTypeAndAlgorithm(aliasKey);
0605 if (typeAndAlg == null) {
0606 return;
0607 }
0608 String type = getEngineName(typeAndAlg[0]);
0609 String aliasAlg = typeAndAlg[1].intern();
0610 ServiceKey key = new ServiceKey(type, stdAlg, true);
0611 Service s = (Service) legacyMap.get(key);
0612 if (s == null) {
0613 s = new Service(this );
0614 s.type = type;
0615 s.algorithm = stdAlg;
0616 legacyMap.put(key, s);
0617 }
0618 legacyMap.put(new ServiceKey(type, aliasAlg, true), s);
0619 s.addAlias(aliasAlg);
0620 } else {
0621 String[] typeAndAlg = getTypeAndAlgorithm(name);
0622 if (typeAndAlg == null) {
0623 return;
0624 }
0625 int i = typeAndAlg[1].indexOf(' ');
0626 if (i == -1) {
0627 // e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA");
0628 String type = getEngineName(typeAndAlg[0]);
0629 String stdAlg = typeAndAlg[1].intern();
0630 String className = value;
0631 ServiceKey key = new ServiceKey(type, stdAlg, true);
0632 Service s = (Service) legacyMap.get(key);
0633 if (s == null) {
0634 s = new Service(this );
0635 s.type = type;
0636 s.algorithm = stdAlg;
0637 legacyMap.put(key, s);
0638 }
0639 s.className = className;
0640 } else { // attribute
0641 // e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software");
0642 String attributeValue = value;
0643 String type = getEngineName(typeAndAlg[0]);
0644 String attributeString = typeAndAlg[1];
0645 String stdAlg = attributeString.substring(0, i)
0646 .intern();
0647 String attributeName = attributeString.substring(i + 1);
0648 // kill additional spaces
0649 while (attributeName.startsWith(" ")) {
0650 attributeName = attributeName.substring(1);
0651 }
0652 attributeName = attributeName.intern();
0653 ServiceKey key = new ServiceKey(type, stdAlg, true);
0654 Service s = (Service) legacyMap.get(key);
0655 if (s == null) {
0656 s = new Service(this );
0657 s.type = type;
0658 s.algorithm = stdAlg;
0659 legacyMap.put(key, s);
0660 }
0661 s.addAttribute(attributeName, attributeValue);
0662 }
0663 }
0664 }
0665
0666 /**
0667 * Get the service describing this Provider's implementation of the
0668 * specified type of this algorithm or alias. If no such
0669 * implementation exists, this method returns null. If there are two
0670 * matching services, one added to this provider using
0671 * {@link #putService putService()} and one added via {@link #put put()},
0672 * the service added via {@link #putService putService()} is returned.
0673 *
0674 * @param type the type of {@link Service service} requested
0675 * (for example, <code>MessageDigest</code>)
0676 * @param algorithm the case insensitive algorithm name (or alternate
0677 * alias) of the service requested (for example, <code>SHA-1</code>)
0678 *
0679 * @return the service describing this Provider's matching service
0680 * or null if no such service exists
0681 *
0682 * @throws NullPointerException if type or algorithm is null
0683 *
0684 * @since 1.5
0685 */
0686 public synchronized Service getService(String type, String algorithm) {
0687 checkInitialized();
0688 // avoid allocating a new key object if possible
0689 ServiceKey key = previousKey;
0690 if (key.matches(type, algorithm) == false) {
0691 key = new ServiceKey(type, algorithm, false);
0692 previousKey = key;
0693 }
0694 if (serviceMap != null) {
0695 Service service = serviceMap.get(key);
0696 if (service != null) {
0697 return service;
0698 }
0699 }
0700 ensureLegacyParsed();
0701 return (legacyMap != null) ? legacyMap.get(key) : null;
0702 }
0703
0704 // ServiceKey from previous getService() call
0705 // by re-using it if possible we avoid allocating a new object
0706 // and the toUpperCase() call.
0707 // re-use will occur e.g. as the framework traverses the provider
0708 // list and queries each provider with the same values until it finds
0709 // a matching service
0710 private static volatile ServiceKey previousKey = new ServiceKey("",
0711 "", false);
0712
0713 /**
0714 * Get an unmodifiable Set of all services supported by
0715 * this Provider.
0716 *
0717 * @return an unmodifiable Set of all services supported by
0718 * this Provider
0719 *
0720 * @since 1.5
0721 */
0722 public synchronized Set<Service> getServices() {
0723 checkInitialized();
0724 if (legacyChanged || servicesChanged) {
0725 serviceSet = null;
0726 }
0727 if (serviceSet == null) {
0728 ensureLegacyParsed();
0729 Set<Service> set = new LinkedHashSet<Service>();
0730 if (serviceMap != null) {
0731 set.addAll(serviceMap.values());
0732 }
0733 if (legacyMap != null) {
0734 set.addAll(legacyMap.values());
0735 }
0736 serviceSet = Collections.unmodifiableSet(set);
0737 servicesChanged = false;
0738 }
0739 return serviceSet;
0740 }
0741
0742 /**
0743 * Add a service. If a service of the same type with the same algorithm
0744 * name exists and it was added using {@link #putService putService()},
0745 * it is replaced by the new service.
0746 * This method also places information about this service
0747 * in the provider's Hashtable values in the format described in the
0748 * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
0749 * Java Cryptography Architecture API Specification & Reference </a>.
0750 *
0751 * <p>Also, if there is a security manager, its
0752 * <code>checkSecurityAccess</code> method is called with the string
0753 * <code>"putProviderProperty."+name</code>, where <code>name</code> is
0754 * the provider name, to see if it's ok to set this provider's property
0755 * values. If the default implementation of <code>checkSecurityAccess</code>
0756 * is used (that is, that method is not overriden), then this results in
0757 * a call to the security manager's <code>checkPermission</code> method with
0758 * a <code>SecurityPermission("putProviderProperty."+name)</code>
0759 * permission.
0760 *
0761 * @param s the Service to add
0762 *
0763 * @throws SecurityException
0764 * if a security manager exists and its <code>{@link
0765 * java.lang.SecurityManager#checkSecurityAccess}</code> method denies
0766 * access to set property values.
0767 * @throws NullPointerException if s is null
0768 *
0769 * @since 1.5
0770 */
0771 protected synchronized void putService(Service s) {
0772 check("putProviderProperty." + name);
0773 if (debug != null) {
0774 debug.println(name + ".putService(): " + s);
0775 }
0776 if (s == null) {
0777 throw new NullPointerException();
0778 }
0779 if (s.getProvider() != this ) {
0780 throw new IllegalArgumentException(
0781 "service.getProvider() must match this Provider object");
0782 }
0783 if (serviceMap == null) {
0784 serviceMap = new LinkedHashMap<ServiceKey, Service>();
0785 }
0786 servicesChanged = true;
0787 String type = s.getType();
0788 String algorithm = s.getAlgorithm();
0789 ServiceKey key = new ServiceKey(type, algorithm, true);
0790 // remove existing service
0791 implRemoveService(serviceMap.get(key));
0792 serviceMap.put(key, s);
0793 for (String alias : s.getAliases()) {
0794 serviceMap.put(new ServiceKey(type, alias, true), s);
0795 }
0796 putPropertyStrings(s);
0797 }
0798
0799 /**
0800 * Put the string properties for this Service in this Provider's
0801 * Hashtable.
0802 */
0803 private void putPropertyStrings(Service s) {
0804 String type = s.getType();
0805 String algorithm = s.getAlgorithm();
0806 // use super() to avoid permission check and other processing
0807 super .put(type + "." + algorithm, s.getClassName());
0808 for (String alias : s.getAliases()) {
0809 super .put(ALIAS_PREFIX + type + "." + alias, algorithm);
0810 }
0811 for (Map.Entry<UString, String> entry : s.attributes.entrySet()) {
0812 String key = type + "." + algorithm + " " + entry.getKey();
0813 super .put(key, entry.getValue());
0814 }
0815 }
0816
0817 /**
0818 * Remove the string properties for this Service from this Provider's
0819 * Hashtable.
0820 */
0821 private void removePropertyStrings(Service s) {
0822 String type = s.getType();
0823 String algorithm = s.getAlgorithm();
0824 // use super() to avoid permission check and other processing
0825 super .remove(type + "." + algorithm);
0826 for (String alias : s.getAliases()) {
0827 super .remove(ALIAS_PREFIX + type + "." + alias);
0828 }
0829 for (Map.Entry<UString, String> entry : s.attributes.entrySet()) {
0830 String key = type + "." + algorithm + " " + entry.getKey();
0831 super .remove(key);
0832 }
0833 }
0834
0835 /**
0836 * Remove a service previously added using
0837 * {@link #putService putService()}. The specified service is removed from
0838 * this provider. It will no longer be returned by
0839 * {@link #getService getService()} and its information will be removed
0840 * from this provider's Hashtable.
0841 *
0842 * <p>Also, if there is a security manager, its
0843 * <code>checkSecurityAccess</code> method is called with the string
0844 * <code>"removeProviderProperty."+name</code>, where <code>name</code> is
0845 * the provider name, to see if it's ok to remove this provider's
0846 * properties. If the default implementation of
0847 * <code>checkSecurityAccess</code> is used (that is, that method is not
0848 * overriden), then this results in a call to the security manager's
0849 * <code>checkPermission</code> method with a
0850 * <code>SecurityPermission("removeProviderProperty."+name)</code>
0851 * permission.
0852 *
0853 * @param s the Service to be removed
0854 *
0855 * @throws SecurityException
0856 * if a security manager exists and its <code>{@link
0857 * java.lang.SecurityManager#checkSecurityAccess}</code> method denies
0858 * access to remove this provider's properties.
0859 * @throws NullPointerException if s is null
0860 *
0861 * @since 1.5
0862 */
0863 protected synchronized void removeService(Service s) {
0864 check("removeProviderProperty." + name);
0865 if (debug != null) {
0866 debug.println(name + ".removeService(): " + s);
0867 }
0868 if (s == null) {
0869 throw new NullPointerException();
0870 }
0871 implRemoveService(s);
0872 }
0873
0874 private void implRemoveService(Service s) {
0875 if ((s == null) || (serviceMap == null)) {
0876 return;
0877 }
0878 String type = s.getType();
0879 String algorithm = s.getAlgorithm();
0880 ServiceKey key = new ServiceKey(type, algorithm, false);
0881 Service oldService = serviceMap.get(key);
0882 if (s != oldService) {
0883 return;
0884 }
0885 servicesChanged = true;
0886 serviceMap.remove(key);
0887 for (String alias : s.getAliases()) {
0888 serviceMap.remove(new ServiceKey(type, alias, false));
0889 }
0890 removePropertyStrings(s);
0891 }
0892
0893 // Wrapped String that behaves in a case insensitive way for equals/hashCode
0894 private static class UString {
0895 final String string;
0896 final String lowerString;
0897
0898 UString(String s) {
0899 this .string = s;
0900 this .lowerString = s.toLowerCase(ENGLISH);
0901 }
0902
0903 public int hashCode() {
0904 return lowerString.hashCode();
0905 }
0906
0907 public boolean equals(Object obj) {
0908 if (this == obj) {
0909 return true;
0910 }
0911 if (obj instanceof UString == false) {
0912 return false;
0913 }
0914 UString other = (UString) obj;
0915 return lowerString.equals(other.lowerString);
0916 }
0917
0918 public String toString() {
0919 return string;
0920 }
0921 }
0922
0923 // describe relevant properties of a type of engine
0924 private static class EngineDescription {
0925 final String name;
0926 final boolean supportsParameter;
0927 final String constructorParameterClassName;
0928 private volatile Class constructorParameterClass;
0929
0930 EngineDescription(String name, boolean sp, String paramName) {
0931 this .name = name;
0932 this .supportsParameter = sp;
0933 this .constructorParameterClassName = paramName;
0934 }
0935
0936 Class getConstructorParameterClass()
0937 throws ClassNotFoundException {
0938 Class clazz = constructorParameterClass;
0939 if (clazz == null) {
0940 clazz = Class.forName(constructorParameterClassName);
0941 constructorParameterClass = clazz;
0942 }
0943 return clazz;
0944 }
0945 }
0946
0947 // built in knowledge of the engine types shipped as part of the JDK
0948 private static final Map<String, EngineDescription> knownEngines;
0949
0950 private static void addEngine(String name, boolean sp,
0951 String paramName) {
0952 EngineDescription ed = new EngineDescription(name, sp,
0953 paramName);
0954 // also index by canonical name to avoid toLowerCase() for some lookups
0955 knownEngines.put(name.toLowerCase(ENGLISH), ed);
0956 knownEngines.put(name, ed);
0957 }
0958
0959 static {
0960 knownEngines = new HashMap<String, EngineDescription>();
0961 // JCA
0962 addEngine("AlgorithmParameterGenerator", false, null);
0963 addEngine("AlgorithmParameters", false, null);
0964 addEngine("KeyFactory", false, null);
0965 addEngine("KeyPairGenerator", false, null);
0966 addEngine("KeyStore", false, null);
0967 addEngine("MessageDigest", false, null);
0968 addEngine("SecureRandom", false, null);
0969 addEngine("Signature", true, null);
0970 addEngine("CertificateFactory", false, null);
0971 addEngine("CertPathBuilder", false, null);
0972 addEngine("CertPathValidator", false, null);
0973 addEngine("CertStore", false,
0974 "java.security.cert.CertStoreParameters");
0975 // JCE
0976 addEngine("Cipher", true, null);
0977 addEngine("ExemptionMechanism", false, null);
0978 addEngine("Mac", true, null);
0979 addEngine("KeyAgreement", true, null);
0980 addEngine("KeyGenerator", false, null);
0981 addEngine("SecretKeyFactory", false, null);
0982 // JSSE
0983 addEngine("KeyManagerFactory", false, null);
0984 addEngine("SSLContext", false, null);
0985 addEngine("TrustManagerFactory", false, null);
0986 // JGSS
0987 addEngine("GssApiMechanism", false, null);
0988 // SASL
0989 addEngine("SaslClientFactory", false, null);
0990 addEngine("SaslServerFactory", false, null);
0991 // POLICY
0992 addEngine("Policy", false, "java.security.Policy$Parameters");
0993 // CONFIGURATION
0994 addEngine("Configuration", false,
0995 "javax.security.auth.login.Configuration$Parameters");
0996 // XML DSig
0997 addEngine("XMLSignatureFactory", false, null);
0998 addEngine("KeyInfoFactory", false, null);
0999 addEngine("TransformService", false, null);
1000 // Smart Card I/O
1001 addEngine("TerminalFactory", false, "java.lang.Object");
1002 }
1003
1004 // get the "standard" (mixed-case) engine name for arbitary case engine name
1005 // if there is no known engine by that name, return s
1006 private static String getEngineName(String s) {
1007 // try original case first, usually correct
1008 EngineDescription e = knownEngines.get(s);
1009 if (e == null) {
1010 e = knownEngines.get(s.toLowerCase(ENGLISH));
1011 }
1012 return (e == null) ? s : e.name;
1013 }
1014
1015 /**
1016 * The description of a security service. It encapsulates the properties
1017 * of a service and contains a factory method to obtain new implementation
1018 * instances of this service.
1019 *
1020 * <p>Each service has a provider that offers the service, a type,
1021 * an algorithm name, and the name of the class that implements the
1022 * service. Optionally, it also includes a list of alternate algorithm
1023 * names for this service (aliases) and attributes, which are a map of
1024 * (name, value) String pairs.
1025 *
1026 * <p>This class defines the methods {@link #supportsParameter
1027 * supportsParameter()} and {@link #newInstance newInstance()}
1028 * which are used by the Java security framework when it searches for
1029 * suitable services and instantes them. The valid arguments to those
1030 * methods depend on the type of service. For the service types defined
1031 * within Java SE, see the
1032 * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
1033 * Java Cryptography Architecture API Specification & Reference </a>
1034 * for the valid values.
1035 * Note that components outside of Java SE can define additional types of
1036 * services and their behavior.
1037 *
1038 * <p>Instances of this class are immutable.
1039 *
1040 * @since 1.5
1041 */
1042 public static class Service {
1043
1044 private String type, algorithm, className;
1045 private final Provider provider;
1046 private List<String> aliases;
1047 private Map<UString, String> attributes;
1048
1049 // Reference to the cached implementation Class object
1050 private volatile Reference<Class> classRef;
1051
1052 // flag indicating whether this service has its attributes for
1053 // supportedKeyFormats or supportedKeyClasses set
1054 // if null, the values have not been initialized
1055 // if TRUE, at least one of supportedFormats/Classes is non null
1056 private volatile Boolean hasKeyAttributes;
1057
1058 // supported encoding formats
1059 private String[] supportedFormats;
1060
1061 // names of the supported key (super) classes
1062 private Class[] supportedClasses;
1063
1064 // whether this service has been registered with the Provider
1065 private boolean registered;
1066
1067 private static final Class[] CLASS0 = new Class[0];
1068
1069 // this constructor and these methods are used for parsing
1070 // the legacy string properties.
1071
1072 private Service(Provider provider) {
1073 this .provider = provider;
1074 aliases = Collections.<String> emptyList();
1075 attributes = Collections.<UString, String> emptyMap();
1076 }
1077
1078 private boolean isValid() {
1079 return (type != null) && (algorithm != null)
1080 && (className != null);
1081 }
1082
1083 private void addAlias(String alias) {
1084 if (aliases.isEmpty()) {
1085 aliases = new ArrayList<String>(2);
1086 }
1087 aliases.add(alias);
1088 }
1089
1090 void addAttribute(String type, String value) {
1091 if (attributes.isEmpty()) {
1092 attributes = new HashMap<UString, String>(8);
1093 }
1094 attributes.put(new UString(type), value);
1095 }
1096
1097 /**
1098 * Construct a new service.
1099 *
1100 * @param provider the provider that offers this service
1101 * @param type the type of this service
1102 * @param algorithm the algorithm name
1103 * @param className the name of the class implementing this service
1104 * @param aliases List of aliases or null if algorithm has no aliases
1105 * @param attributes Map of attributes or null if this implementation
1106 * has no attributes
1107 *
1108 * @throws NullPointerException if provider, type, algorithm, or
1109 * className is null
1110 */
1111 public Service(Provider provider, String type,
1112 String algorithm, String className,
1113 List<String> aliases, Map<String, String> attributes) {
1114 if ((provider == null) || (type == null)
1115 || (algorithm == null) || (className == null)) {
1116 throw new NullPointerException();
1117 }
1118 this .provider = provider;
1119 this .type = getEngineName(type);
1120 this .algorithm = algorithm;
1121 this .className = className;
1122 if (aliases == null) {
1123 this .aliases = Collections.<String> emptyList();
1124 } else {
1125 this .aliases = new ArrayList<String>(aliases);
1126 }
1127 if (attributes == null) {
1128 this .attributes = Collections
1129 .<UString, String> emptyMap();
1130 } else {
1131 this .attributes = new HashMap<UString, String>();
1132 for (Map.Entry<String, String> entry : attributes
1133 .entrySet()) {
1134 this .attributes.put(new UString(entry.getKey()),
1135 entry.getValue());
1136 }
1137 }
1138 }
1139
1140 /**
1141 * Get the type of this service. For example, <code>MessageDigest</code>.
1142 *
1143 * @return the type of this service
1144 */
1145 public final String getType() {
1146 return type;
1147 }
1148
1149 /**
1150 * Return the name of the algorithm of this service. For example,
1151 * <code>SHA-1</code>.
1152 *
1153 * @return the algorithm of this service
1154 */
1155 public final String getAlgorithm() {
1156 return algorithm;
1157 }
1158
1159 /**
1160 * Return the Provider of this service.
1161 *
1162 * @return the Provider of this service
1163 */
1164 public final Provider getProvider() {
1165 return provider;
1166 }
1167
1168 /**
1169 * Return the name of the class implementing this service.
1170 *
1171 * @return the name of the class implementing this service
1172 */
1173 public final String getClassName() {
1174 return className;
1175 }
1176
1177 // internal only
1178 private final List<String> getAliases() {
1179 return aliases;
1180 }
1181
1182 /**
1183 * Return the value of the specified attribute or null if this
1184 * attribute is not set for this Service.
1185 *
1186 * @param name the name of the requested attribute
1187 *
1188 * @return the value of the specified attribute or null if the
1189 * attribute is not present
1190 *
1191 * @throws NullPointerException if name is null
1192 */
1193 public final String getAttribute(String name) {
1194 if (name == null) {
1195 throw new NullPointerException();
1196 }
1197 return attributes.get(new UString(name));
1198 }
1199
1200 /**
1201 * Return a new instance of the implementation described by this
1202 * service. The security provider framework uses this method to
1203 * construct implementations. Applications will typically not need
1204 * to call it.
1205 *
1206 * <p>The default implementation uses reflection to invoke the
1207 * standard constructor for this type of service.
1208 * Security providers can override this method to implement
1209 * instantiation in a different way.
1210 * For details and the values of constructorParameter that are
1211 * valid for the various types of services see the
1212 * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
1213 * Java Cryptography Architecture API Specification &
1214 * Reference</a>.
1215 *
1216 * @param constructorParameter the value to pass to the constructor,
1217 * or null if this type of service does not use a constructorParameter.
1218 *
1219 * @return a new implementation of this service
1220 *
1221 * @throws InvalidParameterException if the value of
1222 * constructorParameter is invalid for this type of service.
1223 * @throws NoSuchAlgorithmException if instantation failed for
1224 * any other reason.
1225 */
1226 public Object newInstance(Object constructorParameter)
1227 throws NoSuchAlgorithmException {
1228 if (registered == false) {
1229 if (provider.getService(type, algorithm) != this ) {
1230 throw new NoSuchAlgorithmException(
1231 "Service not registered with Provider "
1232 + provider.getName() + ": " + this );
1233 }
1234 registered = true;
1235 }
1236 try {
1237 EngineDescription cap = knownEngines.get(type);
1238 if (cap == null) {
1239 // unknown engine type, use generic code
1240 // this is the code path future for non-core
1241 // optional packages
1242 return newInstanceGeneric(constructorParameter);
1243 }
1244 if (cap.constructorParameterClassName == null) {
1245 if (constructorParameter != null) {
1246 throw new InvalidParameterException(
1247 "constructorParameter not used with "
1248 + type + " engines");
1249 }
1250 Class clazz = getImplClass();
1251 return clazz.newInstance();
1252 } else {
1253 Class paramClass = cap
1254 .getConstructorParameterClass();
1255 if (constructorParameter != null) {
1256 Class argClass = constructorParameter
1257 .getClass();
1258 if (paramClass.isAssignableFrom(argClass) == false) {
1259 throw new InvalidParameterException(
1260 "constructorParameter must be instanceof "
1261 + cap.constructorParameterClassName
1262 .replace('$', '.')
1263 + " for engine type "
1264 + type);
1265 }
1266 }
1267 Class clazz = getImplClass();
1268 Constructor cons = clazz.getConstructor(paramClass);
1269 return cons.newInstance(constructorParameter);
1270 }
1271 } catch (NoSuchAlgorithmException e) {
1272 throw e;
1273 } catch (InvocationTargetException e) {
1274 throw new NoSuchAlgorithmException(
1275 "Error constructing implementation (algorithm: "
1276 + algorithm + ", provider: "
1277 + provider.getName() + ", class: "
1278 + className + ")", e.getCause());
1279 } catch (Exception e) {
1280 throw new NoSuchAlgorithmException(
1281 "Error constructing implementation (algorithm: "
1282 + algorithm + ", provider: "
1283 + provider.getName() + ", class: "
1284 + className + ")", e);
1285 }
1286 }
1287
1288 // return the implementation Class object for this service
1289 private Class getImplClass() throws NoSuchAlgorithmException {
1290 try {
1291 Reference<Class> ref = classRef;
1292 Class clazz = (ref == null) ? null : ref.get();
1293 if (clazz == null) {
1294 ClassLoader cl = provider.getClass()
1295 .getClassLoader();
1296 if (cl == null) {
1297 clazz = Class.forName(className);
1298 } else {
1299 clazz = cl.loadClass(className);
1300 }
1301 classRef = new WeakReference<Class>(clazz);
1302 }
1303 return clazz;
1304 } catch (ClassNotFoundException e) {
1305 throw new NoSuchAlgorithmException(
1306 "class configured for " + type + "(provider: "
1307 + provider.getName() + ")"
1308 + "cannot be found.", e);
1309 }
1310 }
1311
1312 /**
1313 * Generic code path for unknown engine types. Call the
1314 * no-args constructor if constructorParameter is null, otherwise
1315 * use the first matching constructor.
1316 */
1317 private Object newInstanceGeneric(Object constructorParameter)
1318 throws Exception {
1319 Class clazz = getImplClass();
1320 if (constructorParameter == null) {
1321 Object o = clazz.newInstance();
1322 return o;
1323 }
1324 Class argClass = constructorParameter.getClass();
1325 Constructor[] cons = clazz.getConstructors();
1326 // find first public constructor that can take the
1327 // argument as parameter
1328 for (int i = 0; i < cons.length; i++) {
1329 Constructor con = cons[i];
1330 Class[] paramTypes = con.getParameterTypes();
1331 if (paramTypes.length != 1) {
1332 continue;
1333 }
1334 if (paramTypes[0].isAssignableFrom(argClass) == false) {
1335 continue;
1336 }
1337 Object o = con
1338 .newInstance(new Object[] { constructorParameter });
1339 return o;
1340 }
1341 throw new NoSuchAlgorithmException(
1342 "No constructor matching " + argClass.getName()
1343 + " found in class " + className);
1344 }
1345
1346 /**
1347 * Test whether this Service can use the specified parameter.
1348 * Returns false if this service cannot use the parameter. Returns
1349 * true if this service can use the parameter, if a fast test is
1350 * infeasible, or if the status is unknown.
1351 *
1352 * <p>The security provider framework uses this method with
1353 * some types of services to quickly exclude non-matching
1354 * implementations for consideration.
1355 * Applications will typically not need to call it.
1356 *
1357 * <p>For details and the values of parameter that are valid for the
1358 * various types of services see the top of this class and the
1359 * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
1360 * Java Cryptography Architecture API Specification &
1361 * Reference</a>.
1362 * Security providers can override it to implement their own test.
1363 *
1364 * @param parameter the parameter to test
1365 *
1366 * @return false if this this service cannot use the specified
1367 * parameter; true if it can possibly use the parameter
1368 *
1369 * @throws InvalidParameterException if the value of parameter is
1370 * invalid for this type of service or if this method cannot be
1371 * used with this type of service
1372 */
1373 public boolean supportsParameter(Object parameter) {
1374 EngineDescription cap = knownEngines.get(type);
1375 if (cap == null) {
1376 // unknown engine type, return true by default
1377 return true;
1378 }
1379 if (cap.supportsParameter == false) {
1380 throw new InvalidParameterException(
1381 "supportsParameter() not " + "used with "
1382 + type + " engines");
1383 }
1384 // allow null for keys without attributes for compatibility
1385 if ((parameter != null)
1386 && (parameter instanceof Key == false)) {
1387 throw new InvalidParameterException(
1388 "Parameter must be instanceof Key for engine "
1389 + type);
1390 }
1391 if (hasKeyAttributes() == false) {
1392 return true;
1393 }
1394 if (parameter == null) {
1395 return false;
1396 }
1397 Key key = (Key) parameter;
1398 if (supportsKeyFormat(key)) {
1399 return true;
1400 }
1401 if (supportsKeyClass(key)) {
1402 return true;
1403 }
1404 return false;
1405 }
1406
1407 /**
1408 * Return whether this service has its Supported* properties for
1409 * keys defined. Parses the attributes if not yet initialized.
1410 */
1411 private boolean hasKeyAttributes() {
1412 Boolean b = hasKeyAttributes;
1413 if (b == null) {
1414 synchronized (this ) {
1415 String s;
1416 s = getAttribute("SupportedKeyFormats");
1417 if (s != null) {
1418 supportedFormats = s.split("\\|");
1419 }
1420 s = getAttribute("SupportedKeyClasses");
1421 if (s != null) {
1422 String[] classNames = s.split("\\|");
1423 List<Class> classList = new ArrayList<Class>(
1424 classNames.length);
1425 for (String className : classNames) {
1426 Class clazz = getKeyClass(className);
1427 if (clazz != null) {
1428 classList.add(clazz);
1429 }
1430 }
1431 supportedClasses = classList.toArray(CLASS0);
1432 }
1433 boolean bool = (supportedFormats != null)
1434 || (supportedClasses != null);
1435 b = Boolean.valueOf(bool);
1436 hasKeyAttributes = b;
1437 }
1438 }
1439 return b.booleanValue();
1440 }
1441
1442 // get the key class object of the specified name
1443 private Class getKeyClass(String name) {
1444 try {
1445 return Class.forName(name);
1446 } catch (ClassNotFoundException e) {
1447 // ignore
1448 }
1449 try {
1450 ClassLoader cl = provider.getClass().getClassLoader();
1451 if (cl != null) {
1452 return cl.loadClass(name);
1453 }
1454 } catch (ClassNotFoundException e) {
1455 // ignore
1456 }
1457 return null;
1458 }
1459
1460 private boolean supportsKeyFormat(Key key) {
1461 if (supportedFormats == null) {
1462 return false;
1463 }
1464 String format = key.getFormat();
1465 if (format == null) {
1466 return false;
1467 }
1468 for (String supportedFormat : supportedFormats) {
1469 if (supportedFormat.equals(format)) {
1470 return true;
1471 }
1472 }
1473 return false;
1474 }
1475
1476 private boolean supportsKeyClass(Key key) {
1477 if (supportedClasses == null) {
1478 return false;
1479 }
1480 Class keyClass = key.getClass();
1481 for (Class clazz : supportedClasses) {
1482 if (clazz.isAssignableFrom(keyClass)) {
1483 return true;
1484 }
1485 }
1486 return false;
1487 }
1488
1489 /**
1490 * Return a String representation of this service.
1491 *
1492 * @return a String representation of this service.
1493 */
1494 public String toString() {
1495 String aString = aliases.isEmpty() ? "" : "\r\n aliases: "
1496 + aliases.toString();
1497 String attrs = attributes.isEmpty() ? ""
1498 : "\r\n attributes: " + attributes.toString();
1499 return provider.getName() + ": " + type + "." + algorithm
1500 + " -> " + className + aString + attrs + "\r\n";
1501 }
1502
1503 }
1504
1505 }
|