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 /** 19 * @author Boris V. Kuznetsov 20 * @version $Revision$ 21 */ 22 23 package org.apache.harmony.security.fortress; 24 25 import java.security.Provider; 26 import java.security.Security; 27 import java.util.ArrayList; 28 import java.util.HashMap; 29 import java.util.List; 30 import java.util.Locale; 31 import java.util.Map; 32 33 34 /** 35 * This class contains information about all registered providers and preferred 36 * implementations for all "serviceName.algName". 37 * 38 */ 39 40 public class Services { 41 42 // The HashMap that contains information about preferred implementations for 43 // all serviceName.algName in the registered providers. 44 // Set the initial size to 600 so we don't grow to 1024 by default because 45 // initialization adds a few entries more than the growth threshold. 46 private static final Map<String, Provider.Service> services 47 = new HashMap<String, Provider.Service>(600); 48 // Save default SecureRandom service as well. 49 // Avoids similar provider/services iteration in SecureRandom constructor 50 private static Provider.Service secureRandom; 51 52 // Need refresh flag 53 private static boolean needRefresh; // = false; 54 55 /** 56 * Refresh number 57 */ 58 static int refreshNumber = 1; 59 60 // Registered providers 61 private static final List<Provider> providers = new ArrayList<Provider>(20); 62 63 // Hash for quick provider access by name 64 private static final Map<String, Provider> providersNames = new HashMap<String, Provider>(20); 65 static { 66 loadProviders(); 67 } 68 69 // Load statically registered providers and init Services Info 70 private static void loadProviders() { 71 String providerClassName = null; 72 int i = 1; 73 ClassLoader cl = ClassLoader.getSystemClassLoader(); 74 Provider p; 75 76 while ((providerClassName = Security.getProperty("security.provider." 77 + i++)) != null) { 78 try { 79 p = (Provider) Class 80 .forName(providerClassName.trim(), true, cl) 81 .newInstance(); 82 providers.add(p); 83 providersNames.put(p.getName(), p); 84 initServiceInfo(p); 85 } catch (ClassNotFoundException e) { // ignore Exceptions 86 } catch (IllegalAccessException e) { 87 } catch (InstantiationException e) { 88 } 89 } 90 Engine.door.renumProviders(); 91 } 92 93 /** 94 * Returns registered providers 95 * 96 * @return 97 */ 98 public static Provider[] getProviders() { 99 return providers.toArray(new Provider[providers.size()]); 100 } 101 102 /** 103 * Returns registered providers as List 104 * 105 * @return 106 */ 107 public static List<Provider> getProvidersList() { 108 return new ArrayList<Provider>(providers); 109 } 110 111 /** 112 * Returns the provider with the specified name 113 * 114 * @param name 115 * @return 116 */ 117 public static Provider getProvider(String name) { 118 if (name == null) { 119 return null; 120 } 121 return providersNames.get(name); 122 } 123 124 /** 125 * Inserts a provider at a specified position 126 * 127 * @param provider 128 * @param position 129 * @return 130 */ 131 public static int insertProviderAt(Provider provider, int position) { 132 int size = providers.size(); 133 if ((position < 1) || (position > size)) { 134 position = size + 1; 135 } 136 providers.add(position - 1, provider); 137 providersNames.put(provider.getName(), provider); 138 setNeedRefresh(); 139 return position; 140 } 141 142 /** 143 * Removes the provider 144 * 145 * @param providerNumber 146 */ 147 public static void removeProvider(int providerNumber) { 148 Provider p = providers.remove(providerNumber - 1); 149 providersNames.remove(p.getName()); 150 setNeedRefresh(); 151 } 152 153 /** 154 * 155 * Adds information about provider services into HashMap. 156 * 157 * @param p 158 */ 159 public static void initServiceInfo(Provider p) { 160 for (Provider.Service serv : p.getServices()) { 161 String type = serv.getType(); 162 if (secureRandom == null && type.equals("SecureRandom")) { 163 secureRandom = serv; 164 } 165 String key = type + "." + serv.getAlgorithm().toUpperCase(Locale.US); 166 if (!services.containsKey(key)) { 167 services.put(key, serv); 168 } 169 for (String alias : Engine.door.getAliases(serv)) { 170 key = type + "." + alias.toUpperCase(Locale.US); 171 if (!services.containsKey(key)) { 172 services.put(key, serv); 173 } 174 } 175 } 176 } 177 178 /** 179 * 180 * Updates services hashtable for all registered providers 181 * 182 */ 183 public static void updateServiceInfo() { 184 services.clear(); 185 secureRandom = null; 186 for (Provider p : providers) { 187 initServiceInfo(p); 188 } 189 needRefresh = false; 190 } 191 192 /** 193 * Returns true if services contain any provider information 194 * @return 195 */ 196 public static boolean isEmpty() { 197 return services.isEmpty(); 198 } 199 200 /** 201 * Returns service description. 202 * Call refresh() before. 203 * 204 * @param key in the format TYPE.ALGORITHM 205 * @return 206 */ 207 public static Provider.Service getService(String key) { 208 return services.get(key); 209 } 210 211 /** 212 * Returns the default SecureRandom service description. 213 * Call refresh() before. 214 */ 215 public static Provider.Service getSecureRandomService() { 216 return secureRandom; 217 } 218 219 /** 220 * Set flag needRefresh 221 * 222 */ 223 public static void setNeedRefresh() { 224 needRefresh = true; 225 } 226 227 /** 228 * Refresh services info 229 * 230 */ 231 public static void refresh() { 232 if (needRefresh) { 233 refreshNumber++; 234 updateServiceInfo(); 235 } 236 } 237 } 238