You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by te...@apache.org on 2006/07/11 11:04:39 UTC

svn commit: r420770 [1/2] - in /incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common: java/security/Provider.java org/apache/harmony/security/utils/TwoKeyHashMap.java

Author: tellison
Date: Tue Jul 11 02:04:38 2006
New Revision: 420770

URL: http://svn.apache.org/viewvc?rev=420770&view=rev
Log:
Apply patch HARMONY-825 ([classlib][security] TwoKeyHashMap: restricted key types)

Modified:
    incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/java/security/Provider.java
    incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/utils/TwoKeyHashMap.java

Modified: incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/java/security/Provider.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/java/security/Provider.java?rev=420770&r1=420769&r2=420770&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/java/security/Provider.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/java/security/Provider.java Tue Jul 11 02:04:38 2006
@@ -1,896 +1,896 @@
-/*
- *  Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-/**
-* @author Boris V. Kuznetsov
-* @version $Revision$
-*/
-
-package java.security;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-
-import org.apache.harmony.security.fortress.Services;
-import org.apache.harmony.security.utils.TwoKeyHashMap;
-
-public abstract class Provider extends Properties {
-    private static final long serialVersionUID = -4298000515446427739L;
-
-    private String name;
-
-    private double version;
-
-    // String representation of the provider version number.
-    private transient String versionString;
-
-    private String info;
-
-    //The provider preference order number. 
-    // Equals -1 for non registered provider.
-    private transient int providerNumber = -1;
-
-    // Contains "Service.Algorithm" and Provider.Service classes added using
-    // putService()
-    private transient TwoKeyHashMap<Service> serviceTable;
-
-    // Contains "Service.Alias" and Provider.Service classes added using
-    // putService()
-    private transient TwoKeyHashMap<Service> aliasTable;
-
-    // Contains "Service.Algorithm" and Provider.Service classes added using
-    // put()
-    private transient TwoKeyHashMap<Service> propertyServiceTable;
-
-    // Contains "Service.Alias" and Provider.Service classes added using put()
-    private transient TwoKeyHashMap<Service> propertyAliasTable;
-
-    // The properties changed via put()
-    private transient Properties changedProperties;
-
-    // For getService(String type, String algorithm) optimization:
-    // previous result
-    private transient Provider.Service returnedService;
-    // previous parameters
-    private transient String lastAlgorithm;
-    // last name
-    private transient String lastServiceName;
-
-    // For getServices() optimization:
-    private transient Set<Service> lastServicesSet;
-
-    // For getService(String type) optimization:
-    private transient String lastType;
-    // last Service found by type
-    private transient Provider.Service lastServicesByType;
-
-    protected Provider(String name, double version, String info) {
-        this.name = name;
-        this.version = version;
-        this.info = info;
-        versionString = String.valueOf(version);
-        putProviderInfo();
-    }
-
-	/**
-	 * Returns the name of this provider.
-	 * 
-	 * 
-	 * 
-	 * @return String name of the provider
-	 */
-    public String getName() {
-        return name;
-    }
-
-	/**
-	 * Returns the version number for the services being provided
-	 * 
-	 * 
-	 * 
-	 * @return double version number for the services being provided
-	 */
-    public double getVersion() {
-        return version;
-    }
-
-	/**
-	 * Returns the generic information about the services being provided.
-	 * 
-	 * 
-	 * 
-	 * @return String generic description of the services being provided
-	 */
-    public String getInfo() {
-        return info;
-    }
-
-	/**
-	 * Answers a string containing a concise, human-readable description of the
-	 * receiver.
-	 * 
-	 * 
-	 * @return a printable representation for the receiver.
-	 */
-    public String toString() {
-        return name + " provider, Ver. " + version + " " + info;
-    }
-
-    public synchronized void clear() {
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            sm.checkSecurityAccess("clearProviderProperties." + name);
-        }
-        super.clear();
-        if (serviceTable != null) {
-            serviceTable.clear();
-        }
-        if (propertyServiceTable != null) {
-            propertyServiceTable.clear();
-        }
-        if (aliasTable != null) {
-            aliasTable.clear();
-        }
-        if (propertyAliasTable != null) {
-            propertyAliasTable.clear();
-        }
-        if (changedProperties != null) {
-            changedProperties.clear();
-        }
-        putProviderInfo();
-        if (providerNumber != -1) {
-            // if registered then refresh Services
-            Services.setNeedRefresh();
-        }
-        servicesChanged();
-    }
-
-    public synchronized void load(InputStream inStream) throws IOException {
-        Properties tmp = new Properties();
-        tmp.load(inStream);
-        myPutAll(tmp);
-    }
-
-    public synchronized void putAll(Map<?,?> t) {
-
-        // Implementation note:
-        // checkSecurityAccess method call is NOT specified
-        // Do it as in put(Object key, Object value).
-
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            sm.checkSecurityAccess("putProviderProperty." + name);
-        }
-        myPutAll(t);
-    }
-
-    private void myPutAll(Map<?,?> t) {
-        if (changedProperties == null) {
-            changedProperties = new Properties();
-        }
-        Iterator<? extends Map.Entry<?, ?>> it = t.entrySet().iterator();
-        Object key;
-        Object value;
-        while (it.hasNext()) {
-            Map.Entry<?, ?> entry = it.next();
-            key = entry.getKey();
-            if (key instanceof String && ((String) key).startsWith("Provider.")) {
-                // Provider service type is reserved
-                continue;
-            }
-            value = entry.getValue();
-            super.put(key, value);
-            if (changedProperties.remove(key) == null) {
-                removeFromPropertyServiceTable(key);
-            }
-            changedProperties.put(key, value);
-        }
-        if (providerNumber != -1) {
-            // if registered then refresh Services
-            Services.setNeedRefresh();
-        }
-    }
-
-    public synchronized Set<Map.Entry<Object,Object>> entrySet() {
-        return Collections.unmodifiableSet(super.entrySet());
-    }
-
-    public Set<Object> keySet() {
-        return Collections.unmodifiableSet(super.keySet());
-    }
-
-    public Collection<Object> values() {
-        return Collections.unmodifiableCollection(super.values());
-    }
-
-    public synchronized Object put(Object key, Object value) {
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            sm.checkSecurityAccess("putProviderProperty." + name);
-        }
-        if (key instanceof String && ((String) key).startsWith("Provider.")) {
-            // Provider service type is reserved
-            return null;
-        }
-        if (providerNumber != -1) {
-            // if registered then refresh Services
-            Services.setNeedRefresh();
-        }
-        if (changedProperties != null && changedProperties.remove(key) == null) {
-            removeFromPropertyServiceTable(key);
-        }
-        if (changedProperties == null) {
-            changedProperties = new Properties();
-        }
-        changedProperties.put(key, value);
-        return super.put(key, value);
-    }
-
-    public synchronized Object remove(Object key) {
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            sm.checkSecurityAccess("removeProviderProperty." + name);
-        }
-        if (key instanceof String && ((String) key).startsWith("Provider.")) {
-            // Provider service type is reserved
-            return null;
-        }
-        if (providerNumber != -1) {
-            // if registered then refresh Services
-            Services.setNeedRefresh();
-        }
-        if (changedProperties != null && changedProperties.remove(key) == null) {
-            removeFromPropertyServiceTable(key);
-        }
-        return super.remove(key);
-    }
-
-    /**
-     * 
-     * returns true if the provider implements the specified algorithm.  Caller must
-     * specify the cryptographic service and specify constraints via the
-     * attribute name the attribute value
-     * 
-     * @param serv
-     *            Crypto service
-     * @param alg
-     *            Algorithm or type
-     * @param attribute
-     *            The attribute name or null
-     * @param val
-     *            The attribute value
-     * @return
-     */
-    boolean implementsAlg(String serv, String alg, String attribute, String val) {
-        String servAlg = serv + "." + alg;
-        String prop = getPropertyIgnoreCase(servAlg);
-        if (prop == null) {
-            alg = getPropertyIgnoreCase("Alg.Alias." + servAlg);
-            if (alg != null) {
-                servAlg = serv + "." + alg;
-                prop = getPropertyIgnoreCase(serv + "." + alg);
-            }
-        }
-        if (prop != null) {
-            if (attribute == null) {
-                return true;
-            } else {
-                return checkAttribute(serv + "." + alg, attribute, val);
-            }
-        }
-        return false;
-    }
-
-    // returns true if the implementation meets the constraint expressed by the
-    // specified attribute name/value pair.
-    private boolean checkAttribute(String servAlg, String attribute, String val) {
-        if (attribute.equalsIgnoreCase("KeySize")) {
-            if (Integer.valueOf(getProperty(servAlg + " KeySize")).compareTo(
-                    Integer.valueOf(val)) < 0) {
-                return false;
-            } else {
-                return true;
-            }
-        } else if (attribute.equalsIgnoreCase("ImplementedId")) {
-            if (!getProperty(servAlg + " ImplementedId").equals(val)) {
-                return false;
-            } else {
-                return true;
-            }
-        } else { // other attributes
-            if (!getProperty(servAlg + " " + attribute).equals(val)) {
-                return false;
-            } else {
-                return true;
-            }
-        }
-    }
-
-    /**
-     * 
-     * Set the provider preference order number.
-     * 
-     * @param n
-     */
-    void setProviderNumber(int n) {
-        providerNumber = n;
-    }
-
-    /**
-     * 
-     * Get the provider preference order number.
-     * 
-     * @return
-     */
-    int getProviderNumber() {
-        return providerNumber;
-    }
-
-    /**
-     * Get the service of the specified type
-     *  
-     */
-    synchronized Provider.Service getService(String type) {
-        updatePropertyServiceTable();
-        if (lastServicesByType != null && type.equals(lastType)) {
-            return lastServicesByType;
-        }
-        Provider.Service service;
-        for (Iterator<Service> it = getServices().iterator(); it.hasNext();) {
-            service = it.next();
-            if (type.equals(service.type)) {
-                lastType = type;
-                lastServicesByType = service;
-                return service;
-            }
-        }
-        return null;
-    }
-
-    public synchronized Provider.Service getService(String type,
-            String algorithm) {
-        if (type == null || algorithm == null) {
-            throw new NullPointerException();
-        }
-
-        if (type.equals(lastServiceName)
-                && algorithm.equalsIgnoreCase(lastAlgorithm)) {
-            return returnedService;
-        }
-
-        String alg = algorithm.toUpperCase();
-        Object o = null;
-        if (serviceTable != null) {
-            o = serviceTable.get(type, alg);
-        }
-        if (o == null && aliasTable != null) {
-            o = aliasTable.get(type, alg);
-        }
-        if (o == null) {
-            updatePropertyServiceTable();
-        }
-        if (o == null && propertyServiceTable != null) {
-            o = propertyServiceTable.get(type, alg);
-        }
-        if (o == null && propertyAliasTable != null) {
-            o = propertyAliasTable.get(type, alg);
-        }
-
-        if (o != null) {
-            lastServiceName = type;
-            lastAlgorithm = algorithm;
-            returnedService = (Provider.Service) o;
-            return returnedService;
-        }
-        return null;
-    }
-
-    public synchronized Set<Provider.Service> getServices() {
-        updatePropertyServiceTable();
-        if (lastServicesSet != null) {
-            return lastServicesSet;
-        }
-        if (serviceTable != null) {
-            lastServicesSet = new HashSet<Service>(serviceTable.values());
-        } else {
-            lastServicesSet = new HashSet<Service>();
-        }
-        if (propertyServiceTable != null) {
-            lastServicesSet.addAll(propertyServiceTable.values());
-        }
-        lastServicesSet = Collections.unmodifiableSet(lastServicesSet);
-        return lastServicesSet;
-    }
-
-    protected synchronized void putService(Provider.Service s) {
-        if (s == null) {
-            throw new NullPointerException();
-        }
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            sm.checkSecurityAccess("putProviderProperty." + name);
-        }
-        if ("Provider".equals(s.getType())) { // Provider service type cannot be
-                                              // added
-            return;
-        }
-        servicesChanged();
-        if (serviceTable == null) {
-            serviceTable = new TwoKeyHashMap<Service>(128);
-        }
-        serviceTable.put(s.type, s.algorithm.toUpperCase(), s);
-        if (s.aliases != null) {
-            if (aliasTable == null) {
-                aliasTable = new TwoKeyHashMap<Service>(256);
-            }
-            for (Iterator<String> it = s.getAliases(); it.hasNext();) {
-                aliasTable.put(s.type, (it.next()).toUpperCase(), s);
-            }
-        }
-        serviceInfoToProperties(s);
-    }
-
-    protected synchronized void removeService(Provider.Service s) {
-        if (s == null) {
-            throw new NullPointerException();
-        }
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            sm.checkSecurityAccess("removeProviderProperty." + name);
-        }
-        servicesChanged();
-        if (serviceTable != null) {
-            serviceTable.remove(s.type, s.algorithm.toUpperCase());
-        }
-        if (aliasTable != null && s.aliases != null) {
-            for (Iterator<String> it = s.getAliases(); it.hasNext();) {
-                aliasTable.remove(s.type, (it.next()).toUpperCase());
-            }
-        }
-        serviceInfoFromProperties(s);
-    }
-
-    // Add Service information to the provider's properties.
-    private void serviceInfoToProperties(Provider.Service s) {
-        super.put(s.type + "." + s.algorithm, s.className);
-        if (s.aliases != null) {
-            for (Iterator<String> i = s.aliases.iterator(); i.hasNext();) {
-                super.put("Alg.Alias." + s.type + "." + i.next(), s.algorithm);
-            }
-        }
-        if (s.attributes != null) {
-            for (Iterator<Map.Entry<String, String>> i = s.attributes.entrySet().iterator(); i.hasNext();) {
-                Map.Entry<String, String> entry = i.next();
-                super.put(s.type + "." + s.algorithm + " " + entry.getKey(),
-                        entry.getValue());
-            }
-        }
-        if (providerNumber != -1) {
-            // if registered then refresh Services
-            Services.setNeedRefresh();
-        }
-    }
-
-    // Remove Service information from the provider's properties.
-    private void serviceInfoFromProperties(Provider.Service s) {
-        super.remove(s.type + "." + s.algorithm);
-        if (s.aliases != null) {
-            for (Iterator<String> i = s.aliases.iterator(); i.hasNext();) {
-                super.remove("Alg.Alias." + s.type + "." + i.next());
-            }
-        }
-        if (s.attributes != null) {
-            for (Iterator<Map.Entry<String, String>> i = s.attributes.entrySet().iterator(); i.hasNext();) {
-                Map.Entry<String, String> entry = i.next();
-                super.remove(s.type + "." + s.algorithm + " " + entry.getKey());
-            }
-        }
-        if (providerNumber != -1) {
-            // if registered then refresh Services
-            Services.setNeedRefresh();
-        }
-    }
-
-    // Remove property information from provider Services
-    private void removeFromPropertyServiceTable(Object key) {
-        if (key == null || !(key instanceof String)) {
-            return;
-        }
-        String k = (String) key;
-        if (k.startsWith("Provider.")) { // Provider service type is reserved
-            return;
-        }
-        Provider.Service s;
-        String serviceName;
-        String algorithm = null;
-        String attribute = null;
-        int i;
-        if (k.startsWith("Alg.Alias.")) { // Alg.Alias.<crypto_service>.<aliasName>=<stanbdardName>
-            String aliasName;
-            String service_alias = k.substring(10);
-            i = service_alias.indexOf(".");
-            serviceName = service_alias.substring(0, i);
-            aliasName = service_alias.substring(i + 1);
-            if (propertyAliasTable != null) {
-                propertyAliasTable.remove(serviceName, aliasName.toUpperCase());
-            }
-            if (propertyServiceTable != null) {
-                for (Iterator<Service> it = propertyServiceTable.values().iterator(); it
-                        .hasNext();) {
-                    s = it.next();
-                    if (s.aliases.contains(aliasName)) {
-                        s.aliases.remove(aliasName);
-                        return;
-                    }
-                }
-            }
-            return;
-        }
-        int j = k.indexOf(".");
-        if (j == -1) { // unknown format
-            return;
-        }
-
-        i = k.indexOf(" ");
-        if (i == -1) { // <crypto_service>.<algorithm_or_type>=<className>
-            serviceName = k.substring(0, j);
-            algorithm = k.substring(j + 1);
-            if (propertyServiceTable != null) {
-                Provider.Service ser = propertyServiceTable.remove(serviceName, algorithm.toUpperCase());
-                if (ser != null && propertyAliasTable != null
-                        && ser.aliases != null) {
-                    for (Iterator<String> it = ser.aliases.iterator(); it.hasNext();) {
-                        propertyAliasTable.remove(serviceName, (it
-                                .next()).toUpperCase());
-                    }
-                }
-            }
-        } else { // <crypto_service>.<algorithm_or_type>
-                 // <attribute_name>=<attrValue>
-            attribute = k.substring(i + 1);
-            serviceName = k.substring(0, j);
-            algorithm = k.substring(j + 1, i);
-            if (propertyServiceTable != null) {
-                Object o = propertyServiceTable.get(serviceName, algorithm
-                        .toUpperCase());
-                if (o != null) {
-                    s = (Provider.Service) o;
-                    s.attributes.remove(attribute);
-                }
-            }
-        }
-    }
-
-    // Update provider Services if the properties was changed
-    private void updatePropertyServiceTable() {
-        Object _key;
-        Object _value;
-        Provider.Service s;
-        String serviceName;
-        String algorithm;
-        if (changedProperties == null || changedProperties.isEmpty()) {
-            return;
-        }
-        for (Iterator<Map.Entry<Object, Object>> it = changedProperties.entrySet().iterator(); it
-                .hasNext();) {
-            Map.Entry<Object, Object> entry = it.next();
-            _key = entry.getKey();
-            _value = entry.getValue();
-            if (_key == null || _value == null || !(_key instanceof String)
-                    || !(_value instanceof String)) {
-                continue;
-            }
-            String key = (String) _key;
-            String value = (String) _value;
-            if (key.startsWith("Provider")) { // Provider service type is reserved
-                continue;
-            }
-            int i;
-            if (key.startsWith("Alg.Alias.")) { // Alg.Alias.<crypto_service>.<aliasName>=<stanbdardName>
-                String aliasName;
-                String service_alias = key.substring(10);
-                i = service_alias.indexOf(".");
-                serviceName = service_alias.substring(0, i);
-                aliasName = service_alias.substring(i + 1);
-                algorithm = value;
-                String algUp = algorithm.toUpperCase();
-                Object o = null;
-                if (propertyServiceTable == null) {
-                    propertyServiceTable = new TwoKeyHashMap<Service>(128);
-                } else {
-                    o = propertyServiceTable.get(serviceName, algUp);
-                }
-                if (o != null) {
-                    s = (Provider.Service) o;
-                    s.aliases.add(aliasName);
-                    if (propertyAliasTable == null) {
-                        propertyAliasTable = new TwoKeyHashMap<Service>(256);
-                    }
-                    propertyAliasTable.put(serviceName,
-                            aliasName.toUpperCase(), s);
-                } else {
-                    String className = (String) changedProperties
-                            .get(serviceName + "." + algorithm);
-                    if (className != null) {
-                        List<String> l = new ArrayList<String>();
-                        l.add(aliasName);
-                        s = new Provider.Service(this, serviceName, algorithm,
-                                className, l, new HashMap<String, String>());
-                        propertyServiceTable.put(serviceName, algUp, s);
-                        if (propertyAliasTable == null) {
-                            propertyAliasTable = new TwoKeyHashMap<Service>(256);
-                        }
-                        propertyAliasTable.put(serviceName, aliasName
-                                .toUpperCase(), s);
-                    }
-                }
-                continue;
-            }
-            int j = key.indexOf(".");
-            if (j == -1) { // unknown format
-                continue;
-            }
-            i = key.indexOf(" ");
-            if (i == -1) { // <crypto_service>.<algorithm_or_type>=<className>
-                serviceName = key.substring(0, j);
-                algorithm = key.substring(j + 1);
-                String alg = algorithm.toUpperCase();
-                Object o = null;
-                if (propertyServiceTable != null) {
-                    o = propertyServiceTable.get(serviceName, alg);
-                }
-                if (o != null) {
-                    s = (Provider.Service) o;
-                    s.className = value;
-                } else {
-                    s = new Provider.Service(this, serviceName, algorithm,
-                            value, new ArrayList<String>(), new HashMap<String, String>());
-                    if (propertyServiceTable == null) {
-                        propertyServiceTable = new TwoKeyHashMap<Service>(128);
-                    }
-                    propertyServiceTable.put(serviceName, alg, s);
-
-                }
-            } else { // <crypto_service>.<algorithm_or_type>
-                     // <attribute_name>=<attrValue>
-                serviceName = key.substring(0, j);
-                algorithm = key.substring(j + 1, i);
-                String attribute = key.substring(i + 1);
-                String alg = algorithm.toUpperCase();
-                Object o = null;
-                if (propertyServiceTable != null) {
-                    o = propertyServiceTable.get(serviceName, alg);
-                }
-                if (o != null) {
-                    s = (Provider.Service) o;
-                    s.attributes.put(attribute, value);
-                } else {
-                    String className = (String) changedProperties
-                            .get(serviceName + "." + algorithm);
-                    if (className != null) {
-                        Map<String, String> m = new HashMap<String, String>();
-                        m.put(attribute, value);
-                        s = new Provider.Service(this, serviceName, algorithm,
-                                className, new ArrayList<String>(), m);
-                        if (propertyServiceTable == null) {
-                            propertyServiceTable = new TwoKeyHashMap<Service>(128);
-                        }
-                        propertyServiceTable.put(serviceName, alg, s);
-                    }
-                }
-            }
-        }
-        servicesChanged();
-        changedProperties.clear();
-    }
-
-    private void servicesChanged() {
-        lastServicesByType = null;
-        lastServiceName = null;
-        lastServicesSet = null;
-    }
-
-    // These attributes should be placed in each Provider object: 
-    // Provider.id name, Provider.id version, Provider.id info, 
-    // Provider.id className
-    private void putProviderInfo() {
-        super.put("Provider.id name", name);
-        super.put("Provider.id version", versionString);
-        super.put("Provider.id info", info);
-        super.put("Provider.id className", this.getClass().getName());
-    }
-
-    // Searches for the property with the specified key in the provider
-    // properties. Key is not case-sensitive.
-    // 
-    // @param prop
-    // @return the property value with the specified key value.
-    private String getPropertyIgnoreCase(String key) {
-        String res = getProperty(key);
-        if (res != null) {
-            return res;
-        }
-        for (Enumeration<?> e = propertyNames(); e.hasMoreElements();) {
-            String pname = (String) e.nextElement();
-            if (key.equalsIgnoreCase(pname)) {
-                return getProperty(pname);
-            }
-        }
-        return null;
-    }
-
-    public static class Service {
-        // The provider
-        private Provider provider;
-
-        // The type of this service
-        private String type;
-
-        // The algorithm name
-        private String algorithm;
-
-        // The class implementing this service
-        private String className;
-
-        // The aliases
-        private List<String> aliases;
-
-        // The attributes
-        private Map<String,String> attributes;
-
-        // Service implementation
-        private Class<?> implementation;
-
-        // For newInstance() optimization
-        private String lastClassName;
-
-        public Service(Provider provider, String type, String algorithm,
-                String className, List<String> aliases, Map<String, String> attributes) {
-            if (provider == null || type == null || algorithm == null
-                    || className == null) {
-                throw new NullPointerException();
-            }
-            this.provider = provider;
-            this.type = type;
-            this.algorithm = algorithm;
-            this.className = className;
-            this.aliases = aliases;
-            this.attributes = attributes;
-        }
-
-        public final String getType() {
-            return type;
-        }
-
-        public final String getAlgorithm() {
-            return algorithm;
-        }
-
-        public final Provider getProvider() {
-            return provider;
-        }
-
-        public final String getClassName() {
-            return className;
-        }
-
-        public final String getAttribute(String name) {
-            if (name == null) {
-                throw new NullPointerException();
-            }
-            if (attributes == null) {
-                return null;
-            }
-            return attributes.get(name);
-        }
-
-        Iterator<String> getAliases() {
-            return aliases.iterator();
-        }
-
-        public Object newInstance(Object constructorParameter)
-                throws NoSuchAlgorithmException {
-            if (implementation == null || !className.equals(lastClassName)) {
-                NoSuchAlgorithmException result = AccessController
-                        .doPrivileged(new PrivilegedAction<NoSuchAlgorithmException>() {
-                            public NoSuchAlgorithmException run() {
-                                ClassLoader cl = provider.getClass()
-                                        .getClassLoader();
-                                if (cl == null) {
-                                    cl = ClassLoader.getSystemClassLoader();
-                                }
-                                try {
-                                    implementation = Class.forName(className,
-                                            true, cl);
-                                } catch (Exception e) {
-                                    return new NoSuchAlgorithmException(type
-                                            + " " + algorithm
-                                            + " implementation not found: " + e);
-                                }
-                                lastClassName = className;
-                                return null;
-                            }
-                        });
-                if (result != null) {
-                    throw result;
-                }
-            }
-            if (constructorParameter == null) {
-                try {
-                    return implementation.newInstance();
-                } catch (Exception e) {
-                    throw new NoSuchAlgorithmException(type + " " + algorithm
-                            + " implementation not found", e);
-                }
-            } else {
-                if (!supportsParameter(constructorParameter)) {
-                    throw new InvalidParameterException(type
-                            + ": service cannot use the parameter");
-                }
-
-                Class[] parameterTypes = new Class[1];
-                Object[] initargs = { constructorParameter };
-                try {
-                    if (type.equalsIgnoreCase("CertStore")) {
-                        parameterTypes[0] = Class
-                                .forName("java.security.cert.CertStoreParameters");
-                    } else {
-                        parameterTypes[0] = constructorParameter.getClass();
-                    }
-                    return implementation.getConstructor(parameterTypes)
-                            .newInstance(initargs);
-                } catch (Exception e) {
-                    throw new NoSuchAlgorithmException(type + " " + algorithm
-                            + " implementation not found", e);
-                }
-            }
-        }
-
-        public boolean supportsParameter(Object parameter) {
-            return true;
-        }
-
-	/**
-	 * Answers a string containing a concise, human-readable
-	 * description of the receiver.
-	 * 
-	 * 
-	 * @return a printable representation for the receiver.
-	 */
-        public String toString() {
-            String result = "Provider " + provider.getName() + " Service "
-                    + type + "." + algorithm + " " + className;
-            if (aliases != null) {
-                result = result + "\nAliases " + aliases.toString();
-            }
-            if (attributes != null) {
-                result = result + "\nAttributes " + attributes.toString();
-            }
-            return result;
-        }
-    }
-}
+/*
+ *  Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.harmony.security.fortress.Services;
+import org.apache.harmony.security.utils.TwoKeyHashMap;
+
+public abstract class Provider extends Properties {
+    private static final long serialVersionUID = -4298000515446427739L;
+
+    private String name;
+
+    private double version;
+
+    // String representation of the provider version number.
+    private transient String versionString;
+
+    private String info;
+
+    //The provider preference order number. 
+    // Equals -1 for non registered provider.
+    private transient int providerNumber = -1;
+
+    // Contains "Service.Algorithm" and Provider.Service classes added using
+    // putService()
+    private transient TwoKeyHashMap<String, String, Service> serviceTable;
+
+    // Contains "Service.Alias" and Provider.Service classes added using
+    // putService()
+    private transient TwoKeyHashMap<String, String, Service> aliasTable;
+
+    // Contains "Service.Algorithm" and Provider.Service classes added using
+    // put()
+    private transient TwoKeyHashMap<String, String, Service> propertyServiceTable;
+
+    // Contains "Service.Alias" and Provider.Service classes added using put()
+    private transient TwoKeyHashMap<String, String, Service> propertyAliasTable;
+
+    // The properties changed via put()
+    private transient Properties changedProperties;
+
+    // For getService(String type, String algorithm) optimization:
+    // previous result
+    private transient Provider.Service returnedService;
+    // previous parameters
+    private transient String lastAlgorithm;
+    // last name
+    private transient String lastServiceName;
+
+    // For getServices() optimization:
+    private transient Set<Service> lastServicesSet;
+
+    // For getService(String type) optimization:
+    private transient String lastType;
+    // last Service found by type
+    private transient Provider.Service lastServicesByType;
+
+    protected Provider(String name, double version, String info) {
+        this.name = name;
+        this.version = version;
+        this.info = info;
+        versionString = String.valueOf(version);
+        putProviderInfo();
+    }
+
+	/**
+	 * Returns the name of this provider.
+	 * 
+	 * 
+	 * 
+	 * @return String name of the provider
+	 */
+    public String getName() {
+        return name;
+    }
+
+	/**
+	 * Returns the version number for the services being provided
+	 * 
+	 * 
+	 * 
+	 * @return double version number for the services being provided
+	 */
+    public double getVersion() {
+        return version;
+    }
+
+	/**
+	 * Returns the generic information about the services being provided.
+	 * 
+	 * 
+	 * 
+	 * @return String generic description of the services being provided
+	 */
+    public String getInfo() {
+        return info;
+    }
+
+	/**
+	 * Answers a string containing a concise, human-readable description of the
+	 * receiver.
+	 * 
+	 * 
+	 * @return a printable representation for the receiver.
+	 */
+    public String toString() {
+        return name + " provider, Ver. " + version + " " + info;
+    }
+
+    public synchronized void clear() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("clearProviderProperties." + name);
+        }
+        super.clear();
+        if (serviceTable != null) {
+            serviceTable.clear();
+        }
+        if (propertyServiceTable != null) {
+            propertyServiceTable.clear();
+        }
+        if (aliasTable != null) {
+            aliasTable.clear();
+        }
+        if (propertyAliasTable != null) {
+            propertyAliasTable.clear();
+        }
+        if (changedProperties != null) {
+            changedProperties.clear();
+        }
+        putProviderInfo();
+        if (providerNumber != -1) {
+            // if registered then refresh Services
+            Services.setNeedRefresh();
+        }
+        servicesChanged();
+    }
+
+    public synchronized void load(InputStream inStream) throws IOException {
+        Properties tmp = new Properties();
+        tmp.load(inStream);
+        myPutAll(tmp);
+    }
+
+    public synchronized void putAll(Map<?,?> t) {
+
+        // Implementation note:
+        // checkSecurityAccess method call is NOT specified
+        // Do it as in put(Object key, Object value).
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("putProviderProperty." + name);
+        }
+        myPutAll(t);
+    }
+
+    private void myPutAll(Map<?,?> t) {
+        if (changedProperties == null) {
+            changedProperties = new Properties();
+        }
+        Iterator<? extends Map.Entry<?, ?>> it = t.entrySet().iterator();
+        Object key;
+        Object value;
+        while (it.hasNext()) {
+            Map.Entry<?, ?> entry = it.next();
+            key = entry.getKey();
+            if (key instanceof String && ((String) key).startsWith("Provider.")) {
+                // Provider service type is reserved
+                continue;
+            }
+            value = entry.getValue();
+            super.put(key, value);
+            if (changedProperties.remove(key) == null) {
+                removeFromPropertyServiceTable(key);
+            }
+            changedProperties.put(key, value);
+        }
+        if (providerNumber != -1) {
+            // if registered then refresh Services
+            Services.setNeedRefresh();
+        }
+    }
+
+    public synchronized Set<Map.Entry<Object,Object>> entrySet() {
+        return Collections.unmodifiableSet(super.entrySet());
+    }
+
+    public Set<Object> keySet() {
+        return Collections.unmodifiableSet(super.keySet());
+    }
+
+    public Collection<Object> values() {
+        return Collections.unmodifiableCollection(super.values());
+    }
+
+    public synchronized Object put(Object key, Object value) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("putProviderProperty." + name);
+        }
+        if (key instanceof String && ((String) key).startsWith("Provider.")) {
+            // Provider service type is reserved
+            return null;
+        }
+        if (providerNumber != -1) {
+            // if registered then refresh Services
+            Services.setNeedRefresh();
+        }
+        if (changedProperties != null && changedProperties.remove(key) == null) {
+            removeFromPropertyServiceTable(key);
+        }
+        if (changedProperties == null) {
+            changedProperties = new Properties();
+        }
+        changedProperties.put(key, value);
+        return super.put(key, value);
+    }
+
+    public synchronized Object remove(Object key) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("removeProviderProperty." + name);
+        }
+        if (key instanceof String && ((String) key).startsWith("Provider.")) {
+            // Provider service type is reserved
+            return null;
+        }
+        if (providerNumber != -1) {
+            // if registered then refresh Services
+            Services.setNeedRefresh();
+        }
+        if (changedProperties != null && changedProperties.remove(key) == null) {
+            removeFromPropertyServiceTable(key);
+        }
+        return super.remove(key);
+    }
+
+    /**
+     * 
+     * returns true if the provider implements the specified algorithm.  Caller must
+     * specify the cryptographic service and specify constraints via the
+     * attribute name the attribute value
+     * 
+     * @param serv
+     *            Crypto service
+     * @param alg
+     *            Algorithm or type
+     * @param attribute
+     *            The attribute name or null
+     * @param val
+     *            The attribute value
+     * @return
+     */
+    boolean implementsAlg(String serv, String alg, String attribute, String val) {
+        String servAlg = serv + "." + alg;
+        String prop = getPropertyIgnoreCase(servAlg);
+        if (prop == null) {
+            alg = getPropertyIgnoreCase("Alg.Alias." + servAlg);
+            if (alg != null) {
+                servAlg = serv + "." + alg;
+                prop = getPropertyIgnoreCase(serv + "." + alg);
+            }
+        }
+        if (prop != null) {
+            if (attribute == null) {
+                return true;
+            } else {
+                return checkAttribute(serv + "." + alg, attribute, val);
+            }
+        }
+        return false;
+    }
+
+    // returns true if the implementation meets the constraint expressed by the
+    // specified attribute name/value pair.
+    private boolean checkAttribute(String servAlg, String attribute, String val) {
+        if (attribute.equalsIgnoreCase("KeySize")) {
+            if (Integer.valueOf(getProperty(servAlg + " KeySize")).compareTo(
+                    Integer.valueOf(val)) < 0) {
+                return false;
+            } else {
+                return true;
+            }
+        } else if (attribute.equalsIgnoreCase("ImplementedId")) {
+            if (!getProperty(servAlg + " ImplementedId").equals(val)) {
+                return false;
+            } else {
+                return true;
+            }
+        } else { // other attributes
+            if (!getProperty(servAlg + " " + attribute).equals(val)) {
+                return false;
+            } else {
+                return true;
+            }
+        }
+    }
+
+    /**
+     * 
+     * Set the provider preference order number.
+     * 
+     * @param n
+     */
+    void setProviderNumber(int n) {
+        providerNumber = n;
+    }
+
+    /**
+     * 
+     * Get the provider preference order number.
+     * 
+     * @return
+     */
+    int getProviderNumber() {
+        return providerNumber;
+    }
+
+    /**
+     * Get the service of the specified type
+     *  
+     */
+    synchronized Provider.Service getService(String type) {
+        updatePropertyServiceTable();
+        if (lastServicesByType != null && type.equals(lastType)) {
+            return lastServicesByType;
+        }
+        Provider.Service service;
+        for (Iterator<Service> it = getServices().iterator(); it.hasNext();) {
+            service = it.next();
+            if (type.equals(service.type)) {
+                lastType = type;
+                lastServicesByType = service;
+                return service;
+            }
+        }
+        return null;
+    }
+
+    public synchronized Provider.Service getService(String type,
+            String algorithm) {
+        if (type == null || algorithm == null) {
+            throw new NullPointerException();
+        }
+
+        if (type.equals(lastServiceName)
+                && algorithm.equalsIgnoreCase(lastAlgorithm)) {
+            return returnedService;
+        }
+
+        String alg = algorithm.toUpperCase();
+        Object o = null;
+        if (serviceTable != null) {
+            o = serviceTable.get(type, alg);
+        }
+        if (o == null && aliasTable != null) {
+            o = aliasTable.get(type, alg);
+        }
+        if (o == null) {
+            updatePropertyServiceTable();
+        }
+        if (o == null && propertyServiceTable != null) {
+            o = propertyServiceTable.get(type, alg);
+        }
+        if (o == null && propertyAliasTable != null) {
+            o = propertyAliasTable.get(type, alg);
+        }
+
+        if (o != null) {
+            lastServiceName = type;
+            lastAlgorithm = algorithm;
+            returnedService = (Provider.Service) o;
+            return returnedService;
+        }
+        return null;
+    }
+
+    public synchronized Set<Provider.Service> getServices() {
+        updatePropertyServiceTable();
+        if (lastServicesSet != null) {
+            return lastServicesSet;
+        }
+        if (serviceTable != null) {
+            lastServicesSet = new HashSet<Service>(serviceTable.values());
+        } else {
+            lastServicesSet = new HashSet<Service>();
+        }
+        if (propertyServiceTable != null) {
+            lastServicesSet.addAll(propertyServiceTable.values());
+        }
+        lastServicesSet = Collections.unmodifiableSet(lastServicesSet);
+        return lastServicesSet;
+    }
+
+    protected synchronized void putService(Provider.Service s) {
+        if (s == null) {
+            throw new NullPointerException();
+        }
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("putProviderProperty." + name);
+        }
+        if ("Provider".equals(s.getType())) { // Provider service type cannot be
+                                              // added
+            return;
+        }
+        servicesChanged();
+        if (serviceTable == null) {
+            serviceTable = new TwoKeyHashMap<String, String, Service>(128);
+        }
+        serviceTable.put(s.type, s.algorithm.toUpperCase(), s);
+        if (s.aliases != null) {
+            if (aliasTable == null) {
+                aliasTable = new TwoKeyHashMap<String, String, Service>(256);
+            }
+            for (Iterator<String> it = s.getAliases(); it.hasNext();) {
+                aliasTable.put(s.type, (it.next()).toUpperCase(), s);
+            }
+        }
+        serviceInfoToProperties(s);
+    }
+
+    protected synchronized void removeService(Provider.Service s) {
+        if (s == null) {
+            throw new NullPointerException();
+        }
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("removeProviderProperty." + name);
+        }
+        servicesChanged();
+        if (serviceTable != null) {
+            serviceTable.remove(s.type, s.algorithm.toUpperCase());
+        }
+        if (aliasTable != null && s.aliases != null) {
+            for (Iterator<String> it = s.getAliases(); it.hasNext();) {
+                aliasTable.remove(s.type, (it.next()).toUpperCase());
+            }
+        }
+        serviceInfoFromProperties(s);
+    }
+
+    // Add Service information to the provider's properties.
+    private void serviceInfoToProperties(Provider.Service s) {
+        super.put(s.type + "." + s.algorithm, s.className);
+        if (s.aliases != null) {
+            for (Iterator<String> i = s.aliases.iterator(); i.hasNext();) {
+                super.put("Alg.Alias." + s.type + "." + i.next(), s.algorithm);
+            }
+        }
+        if (s.attributes != null) {
+            for (Iterator<Map.Entry<String, String>> i = s.attributes.entrySet().iterator(); i.hasNext();) {
+                Map.Entry<String, String> entry = i.next();
+                super.put(s.type + "." + s.algorithm + " " + entry.getKey(),
+                        entry.getValue());
+            }
+        }
+        if (providerNumber != -1) {
+            // if registered then refresh Services
+            Services.setNeedRefresh();
+        }
+    }
+
+    // Remove Service information from the provider's properties.
+    private void serviceInfoFromProperties(Provider.Service s) {
+        super.remove(s.type + "." + s.algorithm);
+        if (s.aliases != null) {
+            for (Iterator<String> i = s.aliases.iterator(); i.hasNext();) {
+                super.remove("Alg.Alias." + s.type + "." + i.next());
+            }
+        }
+        if (s.attributes != null) {
+            for (Iterator<Map.Entry<String, String>> i = s.attributes.entrySet().iterator(); i.hasNext();) {
+                Map.Entry<String, String> entry = i.next();
+                super.remove(s.type + "." + s.algorithm + " " + entry.getKey());
+            }
+        }
+        if (providerNumber != -1) {
+            // if registered then refresh Services
+            Services.setNeedRefresh();
+        }
+    }
+
+    // Remove property information from provider Services
+    private void removeFromPropertyServiceTable(Object key) {
+        if (key == null || !(key instanceof String)) {
+            return;
+        }
+        String k = (String) key;
+        if (k.startsWith("Provider.")) { // Provider service type is reserved
+            return;
+        }
+        Provider.Service s;
+        String serviceName;
+        String algorithm = null;
+        String attribute = null;
+        int i;
+        if (k.startsWith("Alg.Alias.")) { // Alg.Alias.<crypto_service>.<aliasName>=<stanbdardName>
+            String aliasName;
+            String service_alias = k.substring(10);
+            i = service_alias.indexOf(".");
+            serviceName = service_alias.substring(0, i);
+            aliasName = service_alias.substring(i + 1);
+            if (propertyAliasTable != null) {
+                propertyAliasTable.remove(serviceName, aliasName.toUpperCase());
+            }
+            if (propertyServiceTable != null) {
+                for (Iterator<Service> it = propertyServiceTable.values().iterator(); it
+                        .hasNext();) {
+                    s = it.next();
+                    if (s.aliases.contains(aliasName)) {
+                        s.aliases.remove(aliasName);
+                        return;
+                    }
+                }
+            }
+            return;
+        }
+        int j = k.indexOf(".");
+        if (j == -1) { // unknown format
+            return;
+        }
+
+        i = k.indexOf(" ");
+        if (i == -1) { // <crypto_service>.<algorithm_or_type>=<className>
+            serviceName = k.substring(0, j);
+            algorithm = k.substring(j + 1);
+            if (propertyServiceTable != null) {
+                Provider.Service ser = propertyServiceTable.remove(serviceName, algorithm.toUpperCase());
+                if (ser != null && propertyAliasTable != null
+                        && ser.aliases != null) {
+                    for (Iterator<String> it = ser.aliases.iterator(); it.hasNext();) {
+                        propertyAliasTable.remove(serviceName, (it
+                                .next()).toUpperCase());
+                    }
+                }
+            }
+        } else { // <crypto_service>.<algorithm_or_type>
+                 // <attribute_name>=<attrValue>
+            attribute = k.substring(i + 1);
+            serviceName = k.substring(0, j);
+            algorithm = k.substring(j + 1, i);
+            if (propertyServiceTable != null) {
+                Object o = propertyServiceTable.get(serviceName, algorithm
+                        .toUpperCase());
+                if (o != null) {
+                    s = (Provider.Service) o;
+                    s.attributes.remove(attribute);
+                }
+            }
+        }
+    }
+
+    // Update provider Services if the properties was changed
+    private void updatePropertyServiceTable() {
+        Object _key;
+        Object _value;
+        Provider.Service s;
+        String serviceName;
+        String algorithm;
+        if (changedProperties == null || changedProperties.isEmpty()) {
+            return;
+        }
+        for (Iterator<Map.Entry<Object, Object>> it = changedProperties.entrySet().iterator(); it
+                .hasNext();) {
+            Map.Entry<Object, Object> entry = it.next();
+            _key = entry.getKey();
+            _value = entry.getValue();
+            if (_key == null || _value == null || !(_key instanceof String)
+                    || !(_value instanceof String)) {
+                continue;
+            }
+            String key = (String) _key;
+            String value = (String) _value;
+            if (key.startsWith("Provider")) { // Provider service type is reserved
+                continue;
+            }
+            int i;
+            if (key.startsWith("Alg.Alias.")) { // Alg.Alias.<crypto_service>.<aliasName>=<stanbdardName>
+                String aliasName;
+                String service_alias = key.substring(10);
+                i = service_alias.indexOf(".");
+                serviceName = service_alias.substring(0, i);
+                aliasName = service_alias.substring(i + 1);
+                algorithm = value;
+                String algUp = algorithm.toUpperCase();
+                Object o = null;
+                if (propertyServiceTable == null) {
+                    propertyServiceTable = new TwoKeyHashMap<String, String, Service>(128);
+                } else {
+                    o = propertyServiceTable.get(serviceName, algUp);
+                }
+                if (o != null) {
+                    s = (Provider.Service) o;
+                    s.aliases.add(aliasName);
+                    if (propertyAliasTable == null) {
+                        propertyAliasTable = new TwoKeyHashMap<String, String, Service>(256);
+                    }
+                    propertyAliasTable.put(serviceName,
+                            aliasName.toUpperCase(), s);
+                } else {
+                    String className = (String) changedProperties
+                            .get(serviceName + "." + algorithm);
+                    if (className != null) {
+                        List<String> l = new ArrayList<String>();
+                        l.add(aliasName);
+                        s = new Provider.Service(this, serviceName, algorithm,
+                                className, l, new HashMap<String, String>());
+                        propertyServiceTable.put(serviceName, algUp, s);
+                        if (propertyAliasTable == null) {
+                            propertyAliasTable = new TwoKeyHashMap<String, String, Service>(256);
+                        }
+                        propertyAliasTable.put(serviceName, aliasName
+                                .toUpperCase(), s);
+                    }
+                }
+                continue;
+            }
+            int j = key.indexOf(".");
+            if (j == -1) { // unknown format
+                continue;
+            }
+            i = key.indexOf(" ");
+            if (i == -1) { // <crypto_service>.<algorithm_or_type>=<className>
+                serviceName = key.substring(0, j);
+                algorithm = key.substring(j + 1);
+                String alg = algorithm.toUpperCase();
+                Object o = null;
+                if (propertyServiceTable != null) {
+                    o = propertyServiceTable.get(serviceName, alg);
+                }
+                if (o != null) {
+                    s = (Provider.Service) o;
+                    s.className = value;
+                } else {
+                    s = new Provider.Service(this, serviceName, algorithm,
+                            value, new ArrayList<String>(), new HashMap<String, String>());
+                    if (propertyServiceTable == null) {
+                        propertyServiceTable = new TwoKeyHashMap<String, String, Service>(128);
+                    }
+                    propertyServiceTable.put(serviceName, alg, s);
+
+                }
+            } else { // <crypto_service>.<algorithm_or_type>
+                     // <attribute_name>=<attrValue>
+                serviceName = key.substring(0, j);
+                algorithm = key.substring(j + 1, i);
+                String attribute = key.substring(i + 1);
+                String alg = algorithm.toUpperCase();
+                Object o = null;
+                if (propertyServiceTable != null) {
+                    o = propertyServiceTable.get(serviceName, alg);
+                }
+                if (o != null) {
+                    s = (Provider.Service) o;
+                    s.attributes.put(attribute, value);
+                } else {
+                    String className = (String) changedProperties
+                            .get(serviceName + "." + algorithm);
+                    if (className != null) {
+                        Map<String, String> m = new HashMap<String, String>();
+                        m.put(attribute, value);
+                        s = new Provider.Service(this, serviceName, algorithm,
+                                className, new ArrayList<String>(), m);
+                        if (propertyServiceTable == null) {
+                            propertyServiceTable = new TwoKeyHashMap<String, String, Service>(128);
+                        }
+                        propertyServiceTable.put(serviceName, alg, s);
+                    }
+                }
+            }
+        }
+        servicesChanged();
+        changedProperties.clear();
+    }
+
+    private void servicesChanged() {
+        lastServicesByType = null;
+        lastServiceName = null;
+        lastServicesSet = null;
+    }
+
+    // These attributes should be placed in each Provider object: 
+    // Provider.id name, Provider.id version, Provider.id info, 
+    // Provider.id className
+    private void putProviderInfo() {
+        super.put("Provider.id name", name);
+        super.put("Provider.id version", versionString);
+        super.put("Provider.id info", info);
+        super.put("Provider.id className", this.getClass().getName());
+    }
+
+    // Searches for the property with the specified key in the provider
+    // properties. Key is not case-sensitive.
+    // 
+    // @param prop
+    // @return the property value with the specified key value.
+    private String getPropertyIgnoreCase(String key) {
+        String res = getProperty(key);
+        if (res != null) {
+            return res;
+        }
+        for (Enumeration<?> e = propertyNames(); e.hasMoreElements();) {
+            String pname = (String) e.nextElement();
+            if (key.equalsIgnoreCase(pname)) {
+                return getProperty(pname);
+            }
+        }
+        return null;
+    }
+
+    public static class Service {
+        // The provider
+        private Provider provider;
+
+        // The type of this service
+        private String type;
+
+        // The algorithm name
+        private String algorithm;
+
+        // The class implementing this service
+        private String className;
+
+        // The aliases
+        private List<String> aliases;
+
+        // The attributes
+        private Map<String,String> attributes;
+
+        // Service implementation
+        private Class<?> implementation;
+
+        // For newInstance() optimization
+        private String lastClassName;
+
+        public Service(Provider provider, String type, String algorithm,
+                String className, List<String> aliases, Map<String, String> attributes) {
+            if (provider == null || type == null || algorithm == null
+                    || className == null) {
+                throw new NullPointerException();
+            }
+            this.provider = provider;
+            this.type = type;
+            this.algorithm = algorithm;
+            this.className = className;
+            this.aliases = aliases;
+            this.attributes = attributes;
+        }
+
+        public final String getType() {
+            return type;
+        }
+
+        public final String getAlgorithm() {
+            return algorithm;
+        }
+
+        public final Provider getProvider() {
+            return provider;
+        }
+
+        public final String getClassName() {
+            return className;
+        }
+
+        public final String getAttribute(String name) {
+            if (name == null) {
+                throw new NullPointerException();
+            }
+            if (attributes == null) {
+                return null;
+            }
+            return attributes.get(name);
+        }
+
+        Iterator<String> getAliases() {
+            return aliases.iterator();
+        }
+
+        public Object newInstance(Object constructorParameter)
+                throws NoSuchAlgorithmException {
+            if (implementation == null || !className.equals(lastClassName)) {
+                NoSuchAlgorithmException result = AccessController
+                        .doPrivileged(new PrivilegedAction<NoSuchAlgorithmException>() {
+                            public NoSuchAlgorithmException run() {
+                                ClassLoader cl = provider.getClass()
+                                        .getClassLoader();
+                                if (cl == null) {
+                                    cl = ClassLoader.getSystemClassLoader();
+                                }
+                                try {
+                                    implementation = Class.forName(className,
+                                            true, cl);
+                                } catch (Exception e) {
+                                    return new NoSuchAlgorithmException(type
+                                            + " " + algorithm
+                                            + " implementation not found: " + e);
+                                }
+                                lastClassName = className;
+                                return null;
+                            }
+                        });
+                if (result != null) {
+                    throw result;
+                }
+            }
+            if (constructorParameter == null) {
+                try {
+                    return implementation.newInstance();
+                } catch (Exception e) {
+                    throw new NoSuchAlgorithmException(type + " " + algorithm
+                            + " implementation not found", e);
+                }
+            } else {
+                if (!supportsParameter(constructorParameter)) {
+                    throw new InvalidParameterException(type
+                            + ": service cannot use the parameter");
+                }
+
+                Class[] parameterTypes = new Class[1];
+                Object[] initargs = { constructorParameter };
+                try {
+                    if (type.equalsIgnoreCase("CertStore")) {
+                        parameterTypes[0] = Class
+                                .forName("java.security.cert.CertStoreParameters");
+                    } else {
+                        parameterTypes[0] = constructorParameter.getClass();
+                    }
+                    return implementation.getConstructor(parameterTypes)
+                            .newInstance(initargs);
+                } catch (Exception e) {
+                    throw new NoSuchAlgorithmException(type + " " + algorithm
+                            + " implementation not found", e);
+                }
+            }
+        }
+
+        public boolean supportsParameter(Object parameter) {
+            return true;
+        }
+
+	/**
+	 * Answers a string containing a concise, human-readable
+	 * description of the receiver.
+	 * 
+	 * 
+	 * @return a printable representation for the receiver.
+	 */
+        public String toString() {
+            String result = "Provider " + provider.getName() + " Service "
+                    + type + "." + algorithm + " " + className;
+            if (aliases != null) {
+                result = result + "\nAliases " + aliases.toString();
+            }
+            if (attributes != null) {
+                result = result + "\nAttributes " + attributes.toString();
+            }
+            return result;
+        }
+    }
+}