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 /** 34 * The HashMap that contains information about preferred implementations for 35 * all serviceName.algName in the registered providers. 36 * Set the initial size to 600 so we don't grow to 1024 by default because 37 * initialization adds a few entries more than the growth threshold. 38 */ 39 private static final HashMap<String, ArrayList<Provider.Service>> services 40 = new HashMap<String, ArrayList<Provider.Service>>(600); 41 42 /** 43 * Save default SecureRandom service as well. 44 * Avoids similar provider/services iteration in SecureRandom constructor. 45 */ 46 private static Provider.Service cachedSecureRandomService; 47 48 /** 49 * Need refresh flag. 50 */ 51 private static boolean needRefresh; 52 53 /** 54 * The cacheVersion is changed on every update of service 55 * information. It is used by external callers to validate their 56 * own caches of Service information. 57 */ 58 private static int cacheVersion = 1; 59 60 /** 61 * Registered providers. 62 */ 63 private static final ArrayList<Provider> providers = new ArrayList<Provider>(20); 64 65 /** 66 * Hash for quick provider access by name. 67 */ 68 private static final HashMap<String, Provider> providersNames 69 = new HashMap<String, Provider>(20); 70 static { 71 String providerClassName = null; 72 int i = 1; 73 ClassLoader cl = ClassLoader.getSystemClassLoader(); 74 75 while ((providerClassName = Security.getProperty("security.provider." + i++)) != null) { 76 try { 77 Class<?> providerClass = Class.forName(providerClassName.trim(), true, cl); 78 Provider p = (Provider) providerClass.newInstance(); 79 providers.add(p); p.getName()80 providersNames.put(p.getName(), p); 81 initServiceInfo(p); 82 } catch (ClassNotFoundException ignored) { 83 } catch (IllegalAccessException ignored) { 84 } catch (InstantiationException ignored) { 85 } 86 } Engine.door.renumProviders()87 Engine.door.renumProviders(); 88 } 89 90 /** 91 * Returns a copy of the registered providers as an array. 92 */ getProviders()93 public static synchronized ArrayList<Provider> getProviders() { 94 return providers; 95 } 96 97 /** 98 * Returns the provider with the specified name. 99 */ getProvider(String name)100 public static synchronized Provider getProvider(String name) { 101 if (name == null) { 102 return null; 103 } 104 return providersNames.get(name); 105 } 106 107 /** 108 * Inserts a provider at a specified 1-based position. 109 */ insertProviderAt(Provider provider, int position)110 public static synchronized int insertProviderAt(Provider provider, int position) { 111 int size = providers.size(); 112 if ((position < 1) || (position > size)) { 113 position = size + 1; 114 } 115 providers.add(position - 1, provider); 116 providersNames.put(provider.getName(), provider); 117 setNeedRefresh(); 118 return position; 119 } 120 121 /** 122 * Removes the provider at the specified 1-based position. 123 */ removeProvider(int providerNumber)124 public static synchronized void removeProvider(int providerNumber) { 125 Provider p = providers.remove(providerNumber - 1); 126 providersNames.remove(p.getName()); 127 setNeedRefresh(); 128 } 129 130 /** 131 * Adds information about provider services into HashMap. 132 */ initServiceInfo(Provider p)133 public static synchronized void initServiceInfo(Provider p) { 134 for (Provider.Service service : p.getServices()) { 135 String type = service.getType(); 136 if (cachedSecureRandomService == null && type.equals("SecureRandom")) { 137 cachedSecureRandomService = service; 138 } 139 String key = type + "." + service.getAlgorithm().toUpperCase(Locale.US); 140 appendServiceLocked(key, service); 141 for (String alias : Engine.door.getAliases(service)) { 142 key = type + "." + alias.toUpperCase(Locale.US); 143 appendServiceLocked(key, service); 144 } 145 } 146 } 147 148 /** 149 * Add or append the service to the key. 150 */ appendServiceLocked(String key, Provider.Service service)151 private static void appendServiceLocked(String key, Provider.Service service) { 152 ArrayList<Provider.Service> serviceList = services.get(key); 153 if (serviceList == null) { 154 serviceList = new ArrayList<Provider.Service>(1); 155 services.put(key, serviceList); 156 } 157 serviceList.add(service); 158 } 159 160 /** 161 * Returns true if services does not 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 */ getServices(String key)177 public static synchronized ArrayList<Provider.Service> getServices(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