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 18package org.apache.harmony.security.fortress; 19 20import java.security.Provider; 21import java.security.Security; 22import java.util.ArrayList; 23import java.util.HashMap; 24import java.util.List; 25import java.util.Locale; 26import java.util.Map; 27 28 29/** 30 * This class contains information about all registered providers and preferred 31 * implementations for all "serviceName.algName". 32 */ 33public 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); 81 providersNames.put(p.getName(), p); 82 initServiceInfo(p); 83 } catch (ClassNotFoundException ignored) { 84 } catch (IllegalAccessException ignored) { 85 } catch (InstantiationException ignored) { 86 } 87 } 88 Engine.door.renumProviders(); 89 } 90 91 /** 92 * Returns a copy of the registered providers as an array. 93 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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