• 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.Locale;
25 
26 
27 /**
28  * This class contains information about all registered providers and preferred
29  * implementations for all "serviceName.algName".
30  */
31 public class Services {
32     /**
33      * Save default SecureRandom service as well.
34      * Avoids similar provider/services iteration in SecureRandom constructor.
35      */
36     private static Provider.Service cachedSecureRandomService;
37 
38     /**
39      * Need refresh flag.
40      */
41     private static boolean needRefresh;
42 
43     /**
44      * The cacheVersion is changed on every update of service
45      * information. It is used by external callers to validate their
46      * own caches of Service information.
47      */
48     private static int cacheVersion = 1;
49 
50     /**
51      * Registered providers.
52      */
53     private static final ArrayList<Provider> providers = new ArrayList<Provider>(20);
54 
55     /**
56      * Try to load and register a provider by name from the given class-loader.
57      */
initProvider(String providerClassName, ClassLoader classLoader)58     private static boolean initProvider(String providerClassName, ClassLoader classLoader) {
59         try {
60             Class<?> providerClass = Class.forName(providerClassName.trim(), true, classLoader);
61             Provider p = (Provider) providerClass.newInstance();
62             providers.add(p);
63             providersNames.put(p.getName(), p);
64             return true;
65         } catch (ClassNotFoundException ignored) {
66         } catch (IllegalAccessException ignored) {
67         } catch (InstantiationException ignored) {
68         }
69         return false;
70     }
71 
72     /**
73      * Hash for quick provider access by name.
74      */
75     private static final HashMap<String, Provider> providersNames
76             = new HashMap<String, Provider>(20);
77     static {
78         String providerClassName = null;
79         int i = 1;
80         ClassLoader cl = Services.class.getClassLoader();
81 
82         while ((providerClassName = Security.getProperty("security.provider." + i++)) != null) {
83             if (!initProvider(providerClassName, cl)) {
84                 // Not on the boot classpath. Try the system class-loader.
85                 // Note: DO NOT USE A LOCAL FOR GETSYSTEMCLASSLOADER! This will break compile-time
86                 //       initialization.
87                 if (!initProvider(providerClassName, ClassLoader.getSystemClassLoader())) {
88                     // TODO: Logging?
89                 }
90             }
91         }
Engine.door.renumProviders()92         Engine.door.renumProviders();
setNeedRefresh()93         setNeedRefresh();
94     }
95 
96     /**
97      * Returns the actual registered providers.
98      */
getProviders()99     public static synchronized ArrayList<Provider> getProviders() {
100         return providers;
101     }
102 
103     /**
104      * Returns the provider with the specified name.
105      */
getProvider(String name)106     public static synchronized Provider getProvider(String name) {
107         if (name == null) {
108             return null;
109         }
110         return providersNames.get(name);
111     }
112 
113     /**
114      * Inserts a provider at a specified 1-based position.
115      */
insertProviderAt(Provider provider, int position)116     public static synchronized int insertProviderAt(Provider provider, int position) {
117         int size = providers.size();
118         if ((position < 1) || (position > size)) {
119             position = size + 1;
120         }
121         providers.add(position - 1, provider);
122         providersNames.put(provider.getName(), provider);
123         setNeedRefresh();
124         return position;
125     }
126 
127     /**
128      * Removes the provider at the specified 1-based position.
129      */
removeProvider(int providerNumber)130     public static synchronized void removeProvider(int providerNumber) {
131         Provider p = providers.remove(providerNumber - 1);
132         providersNames.remove(p.getName());
133         setNeedRefresh();
134     }
135 
136     /**
137      * Looks up the requested service by type and algorithm. The service
138      * {@code type} and should be provided in the same format used when
139      * registering a service with a provider, for example, "KeyFactory.RSA".
140      * Callers can cache the returned service information but such caches should
141      * be validated against the result of Service.getCacheVersion() before use.
142      * Returns {@code null} if there are no services found.
143      */
getServices(String type, String algorithm)144     public static synchronized ArrayList<Provider.Service> getServices(String type,
145             String algorithm) {
146         ArrayList<Provider.Service> services = null;
147         for (Provider p : providers) {
148             Provider.Service s = p.getService(type, algorithm);
149             if (s != null) {
150                 if (services == null) {
151                     services = new ArrayList<>(providers.size());
152                 }
153                 services.add(s);
154             }
155         }
156         return services;
157     }
158 
159     /**
160      * Finds the first service offered of {@code type} and returns it.
161      */
getFirstServiceOfType(String type)162     private static synchronized Provider.Service getFirstServiceOfType(String type) {
163         for (Provider p : providers) {
164             Provider.Service s = Engine.door.getService(p, type);
165             if (s != null) {
166                 return s;
167             }
168         }
169         return null;
170     }
171 
172     /**
173      * Returns the default SecureRandom service description.
174      */
getSecureRandomService()175     public static synchronized Provider.Service getSecureRandomService() {
176         getCacheVersion();  // used for side effect of updating cache if needed
177         return cachedSecureRandomService;
178     }
179 
180     /**
181      * In addition to being used here when the list of providers
182      * changes, this method is also used by the Provider
183      * implementation to indicate that a provides list of services has
184      * changed.
185      */
setNeedRefresh()186     public static synchronized void setNeedRefresh() {
187         needRefresh = true;
188     }
189 
190     /**
191      * Returns the current cache version. This has the possible side
192      * effect of updating the cache if needed.
193      */
getCacheVersion()194     public static synchronized int getCacheVersion() {
195         if (needRefresh) {
196             cacheVersion++;
197             cachedSecureRandomService = getFirstServiceOfType("SecureRandom");
198             needRefresh = false;
199         }
200         return cacheVersion;
201     }
202 }
203