• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 
18 package org.apache.harmony.security.fortress;
19 
20 import java.security.Provider;
21 import java.security.Security;
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Locale;
26 import java.util.Map;
27 
28 
29 /**
30  * This class contains information about all registered providers and preferred
31  * implementations for all "serviceName.algName".
32  */
33 public class Services {
34 
35     /**
36      * The HashMap that contains information about preferred implementations for
37      * all serviceName.algName in the registered providers.
38      * Set the initial size to 600 so we don't grow to 1024 by default because
39      * initialization adds a few entries more than the growth threshold.
40      */
41     private static final Map<String, Provider.Service> services
42             = new HashMap<String, Provider.Service>(600);
43 
44     /**
45      * Save default SecureRandom service as well.
46      * Avoids similar provider/services iteration in SecureRandom constructor.
47      */
48     private static Provider.Service cachedSecureRandomService;
49 
50     /**
51      * Need refresh flag.
52      */
53     private static boolean needRefresh;
54 
55     /**
56      * The cacheVersion is changed on every update of service
57      * information. It is used by external callers to validate their
58      * own caches of Service information.
59      */
60     private static int cacheVersion = 1;
61 
62     /**
63      * Registered providers.
64      */
65     private static final List<Provider> providers = new ArrayList<Provider>(20);
66 
67     /**
68      * Hash for quick provider access by name.
69      */
70     private static final Map<String, Provider> providersNames = new HashMap<String, Provider>(20);
71     static {
72         String providerClassName = null;
73         int i = 1;
74         ClassLoader cl = ClassLoader.getSystemClassLoader();
75 
76         while ((providerClassName = Security.getProperty("security.provider." + i++)) != null) {
77             try {
78                 Class providerClass = Class.forName(providerClassName.trim(), true, cl);
79                 Provider p = (Provider) providerClass.newInstance();
80                 providers.add(p);
p.getName()81                 providersNames.put(p.getName(), p);
82                 initServiceInfo(p);
83             } catch (ClassNotFoundException ignored) {
84             } catch (IllegalAccessException ignored) {
85             } catch (InstantiationException ignored) {
86             }
87         }
Engine.door.renumProviders()88         Engine.door.renumProviders();
89     }
90 
91     /**
92      * Returns a copy of the registered providers as an array.
93      */
getProviders()94     public static synchronized Provider[] getProviders() {
95         return providers.toArray(new Provider[providers.size()]);
96     }
97 
98     /**
99      * Returns a copy of the registered providers as a list.
100      */
getProvidersList()101     public static synchronized List<Provider> getProvidersList() {
102         return new ArrayList<Provider>(providers);
103     }
104 
105     /**
106      * Returns the provider with the specified name.
107      */
getProvider(String name)108     public static synchronized Provider getProvider(String name) {
109         if (name == null) {
110             return null;
111         }
112         return providersNames.get(name);
113     }
114 
115     /**
116      * Inserts a provider at a specified 1-based position.
117      */
insertProviderAt(Provider provider, int position)118     public static synchronized int insertProviderAt(Provider provider, int position) {
119         int size = providers.size();
120         if ((position < 1) || (position > size)) {
121             position = size + 1;
122         }
123         providers.add(position - 1, provider);
124         providersNames.put(provider.getName(), provider);
125         setNeedRefresh();
126         return position;
127     }
128 
129     /**
130      * Removes the provider at the specified 1-based position.
131      */
removeProvider(int providerNumber)132     public static synchronized void removeProvider(int providerNumber) {
133         Provider p = providers.remove(providerNumber - 1);
134         providersNames.remove(p.getName());
135         setNeedRefresh();
136     }
137 
138     /**
139      * Adds information about provider services into HashMap.
140      */
initServiceInfo(Provider p)141     public static synchronized void initServiceInfo(Provider p) {
142         for (Provider.Service service : p.getServices()) {
143             String type = service.getType();
144             if (cachedSecureRandomService == null && type.equals("SecureRandom")) {
145                 cachedSecureRandomService = service;
146             }
147             String key = type + "." + service.getAlgorithm().toUpperCase(Locale.US);
148             if (!services.containsKey(key)) {
149                 services.put(key, service);
150             }
151             for (String alias : Engine.door.getAliases(service)) {
152                 key = type + "." + alias.toUpperCase(Locale.US);
153                 if (!services.containsKey(key)) {
154                     services.put(key, service);
155                 }
156             }
157         }
158     }
159 
160     /**
161      * Returns true if services contain any provider information.
162      */
isEmpty()163     public static synchronized boolean isEmpty() {
164         return services.isEmpty();
165     }
166 
167     /**
168      * Looks up the requested service by type and algorithm. The
169      * service key should be provided in the same format used when
170      * registering a service with a provider, for example,
171      * "KeyFactory.RSA".
172      *
173      * Callers can cache the returned service information but such
174      * caches should be validated against the result of
175      * Service.getCacheVersion() before use.
176      */
getService(String key)177     public static synchronized Provider.Service getService(String key) {
178         return services.get(key);
179     }
180 
181     /**
182      * Returns the default SecureRandom service description.
183      */
getSecureRandomService()184     public static synchronized Provider.Service getSecureRandomService() {
185         getCacheVersion();  // used for side effect of updating cache if needed
186         return cachedSecureRandomService;
187     }
188 
189     /**
190      * In addition to being used here when the list of providers
191      * changes, this method is also used by the Provider
192      * implementation to indicate that a provides list of services has
193      * changed.
194      */
setNeedRefresh()195     public static synchronized void setNeedRefresh() {
196         needRefresh = true;
197     }
198 
199     /**
200      * Returns the current cache version. This has the possible side
201      * effect of updating the cache if needed.
202      */
getCacheVersion()203     public static synchronized int getCacheVersion() {
204         if (needRefresh) {
205             cacheVersion++;
206             synchronized (services) {
207                 services.clear();
208             }
209             cachedSecureRandomService = null;
210             for (Provider p : providers) {
211                 initServiceInfo(p);
212             }
213             needRefresh = false;
214         }
215         return cacheVersion;
216     }
217 }
218