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

Save This Page
Home » openjdk-7 » java » security » [javadoc | source]