mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8276660: Scalability bottleneck in java.security.Provider.getService()
Reviewed-by: weijun
This commit is contained in:
parent
2478158815
commit
9b747491de
1 changed files with 276 additions and 227 deletions
|
@ -191,6 +191,8 @@ public abstract class Provider extends Properties {
|
|||
this.versionStr = Double.toString(version);
|
||||
this.info = info;
|
||||
this.serviceMap = new ConcurrentHashMap<>();
|
||||
this.legacyMap = new ConcurrentHashMap<>();
|
||||
this.prngAlgos = new LinkedHashSet<String>(6);
|
||||
putId();
|
||||
initialized = true;
|
||||
}
|
||||
|
@ -229,6 +231,8 @@ public abstract class Provider extends Properties {
|
|||
this.version = parseVersionStr(versionStr);
|
||||
this.info = info;
|
||||
this.serviceMap = new ConcurrentHashMap<>();
|
||||
this.legacyMap = new ConcurrentHashMap<>();
|
||||
this.prngAlgos = new LinkedHashSet<String>(6);
|
||||
putId();
|
||||
initialized = true;
|
||||
}
|
||||
|
@ -572,7 +576,6 @@ public abstract class Provider extends Properties {
|
|||
public synchronized boolean replace(Object key, Object oldValue,
|
||||
Object newValue) {
|
||||
check("putProviderProperty." + name);
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("Replace " + name + " provider property " + key);
|
||||
}
|
||||
|
@ -598,7 +601,6 @@ public abstract class Provider extends Properties {
|
|||
@Override
|
||||
public synchronized Object replace(Object key, Object value) {
|
||||
check("putProviderProperty." + name);
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("Replace " + name + " provider property " + key);
|
||||
}
|
||||
|
@ -627,7 +629,6 @@ public abstract class Provider extends Properties {
|
|||
public synchronized void replaceAll(BiFunction<? super Object,
|
||||
? super Object, ? extends Object> function) {
|
||||
check("putProviderProperty." + name);
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("ReplaceAll " + name + " provider property ");
|
||||
}
|
||||
|
@ -657,7 +658,6 @@ public abstract class Provider extends Properties {
|
|||
? super Object, ? extends Object> remappingFunction) {
|
||||
check("putProviderProperty." + name);
|
||||
check("removeProviderProperty." + name);
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("Compute " + name + " provider property " + key);
|
||||
}
|
||||
|
@ -684,11 +684,10 @@ public abstract class Provider extends Properties {
|
|||
* @since 1.8
|
||||
*/
|
||||
@Override
|
||||
public synchronized Object computeIfAbsent(Object key, Function<? super Object,
|
||||
? extends Object> mappingFunction) {
|
||||
public synchronized Object computeIfAbsent(Object key,
|
||||
Function<? super Object, ? extends Object> mappingFunction) {
|
||||
check("putProviderProperty." + name);
|
||||
check("removeProviderProperty." + name);
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("ComputeIfAbsent " + name + " provider property " +
|
||||
key);
|
||||
|
@ -714,11 +713,11 @@ public abstract class Provider extends Properties {
|
|||
* @since 1.8
|
||||
*/
|
||||
@Override
|
||||
public synchronized Object computeIfPresent(Object key, BiFunction<? super Object,
|
||||
? super Object, ? extends Object> remappingFunction) {
|
||||
public synchronized Object computeIfPresent(Object key,
|
||||
BiFunction<? super Object, ? super Object, ? extends Object>
|
||||
remappingFunction) {
|
||||
check("putProviderProperty." + name);
|
||||
check("removeProviderProperty." + name);
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("ComputeIfPresent " + name + " provider property " +
|
||||
key);
|
||||
|
@ -747,11 +746,11 @@ public abstract class Provider extends Properties {
|
|||
* @since 1.8
|
||||
*/
|
||||
@Override
|
||||
public synchronized Object merge(Object key, Object value, BiFunction<? super Object,
|
||||
? super Object, ? extends Object> remappingFunction) {
|
||||
public synchronized Object merge(Object key, Object value,
|
||||
BiFunction<? super Object, ? super Object, ? extends Object>
|
||||
remappingFunction) {
|
||||
check("putProviderProperty." + name);
|
||||
check("removeProviderProperty." + name);
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("Merge " + name + " provider property " + key);
|
||||
}
|
||||
|
@ -777,7 +776,8 @@ public abstract class Provider extends Properties {
|
|||
* @since 1.8
|
||||
*/
|
||||
@Override
|
||||
public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) {
|
||||
public synchronized void forEach(BiConsumer<? super Object, ? super Object>
|
||||
action) {
|
||||
checkInitialized();
|
||||
super.forEach(action);
|
||||
}
|
||||
|
@ -817,14 +817,11 @@ public abstract class Provider extends Properties {
|
|||
}
|
||||
}
|
||||
|
||||
// legacy properties changed since last call to any services method?
|
||||
private transient boolean legacyChanged;
|
||||
// legacyMap changed since last call to getServices()
|
||||
private transient volatile boolean legacyChanged;
|
||||
// serviceMap changed since last call to getServices()
|
||||
private transient volatile boolean servicesChanged;
|
||||
|
||||
// Map<String,String> used to keep track of legacy registration
|
||||
private transient Map<String,String> legacyStrings;
|
||||
|
||||
// Map<ServiceKey,Service>
|
||||
// used for services added via putService(), initialized on demand
|
||||
private transient Map<ServiceKey,Service> serviceMap;
|
||||
|
@ -832,6 +829,9 @@ public abstract class Provider extends Properties {
|
|||
// For backward compatibility, the registration ordering of
|
||||
// SecureRandom (RNG) algorithms needs to be preserved for
|
||||
// "new SecureRandom()" calls when this provider is used
|
||||
// NOTE: may need extra mechanism for providers to indicate their
|
||||
// preferred ordering of SecureRandom algorithms since registration
|
||||
// ordering info is lost once serialized
|
||||
private transient Set<String> prngAlgos;
|
||||
|
||||
// Map<ServiceKey,Service>
|
||||
|
@ -840,7 +840,7 @@ public abstract class Provider extends Properties {
|
|||
|
||||
// Set<Service>
|
||||
// Unmodifiable set of all services. Initialized on demand.
|
||||
private transient Set<Service> serviceSet;
|
||||
private transient volatile Set<Service> serviceSet;
|
||||
|
||||
// register the id attributes for this provider
|
||||
// this is to ensure that equals() and hashCode() do not incorrectly
|
||||
|
@ -872,6 +872,7 @@ public abstract class Provider extends Properties {
|
|||
for (Map.Entry<Object,Object> entry : super.entrySet()) {
|
||||
copy.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
defaults = null;
|
||||
in.defaultReadObject();
|
||||
if (this.versionStr == null) {
|
||||
|
@ -882,23 +883,22 @@ public abstract class Provider extends Properties {
|
|||
this.version = parseVersionStr(this.versionStr);
|
||||
}
|
||||
this.serviceMap = new ConcurrentHashMap<>();
|
||||
this.legacyMap = new ConcurrentHashMap<>();
|
||||
this.prngAlgos = new LinkedHashSet<String>(6);
|
||||
implClear();
|
||||
initialized = true;
|
||||
putAll(copy);
|
||||
}
|
||||
|
||||
// check whether to update 'legacyString' with the specified key
|
||||
private boolean checkLegacy(Object key) {
|
||||
String keyString = (String)key;
|
||||
if (keyString.startsWith("Provider.")) {
|
||||
// returns false if no update necessary, i.e. key isn't String or
|
||||
// is String but it's provider-related (name/version/info/className)
|
||||
private static boolean checkLegacy(Object key) {
|
||||
if (key instanceof String && ((String)key).startsWith("Provider.")) {
|
||||
// ignore provider related updates
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
legacyChanged = true;
|
||||
if (legacyStrings == null) {
|
||||
legacyStrings = new LinkedHashMap<>();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -913,149 +913,161 @@ public abstract class Provider extends Properties {
|
|||
}
|
||||
|
||||
private Object implRemove(Object key) {
|
||||
if (key instanceof String) {
|
||||
if (!checkLegacy(key)) {
|
||||
return null;
|
||||
}
|
||||
legacyStrings.remove((String)key);
|
||||
if (!checkLegacy(key)) return null;
|
||||
|
||||
Object o = super.remove(key);
|
||||
if (o instanceof String so && key instanceof String sk) {
|
||||
parseLegacy(sk, so, OPType.REMOVE);
|
||||
}
|
||||
return super.remove(key);
|
||||
return o;
|
||||
}
|
||||
|
||||
private boolean implRemove(Object key, Object value) {
|
||||
if (key instanceof String && value instanceof String) {
|
||||
if (!checkLegacy(key)) {
|
||||
return false;
|
||||
}
|
||||
legacyStrings.remove((String)key, (String)value);
|
||||
if (!checkLegacy(key)) return false;
|
||||
|
||||
boolean result = super.remove(key, value);
|
||||
if (result && key instanceof String sk && value instanceof String sv) {
|
||||
parseLegacy(sk, sv, OPType.REMOVE);
|
||||
}
|
||||
return super.remove(key, value);
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean implReplace(Object key, Object oldValue, Object newValue) {
|
||||
if ((key instanceof String) && (oldValue instanceof String) &&
|
||||
(newValue instanceof String)) {
|
||||
if (!checkLegacy(key)) {
|
||||
return false;
|
||||
if (!checkLegacy(key)) return false;
|
||||
|
||||
boolean result = super.replace(key, oldValue, newValue);
|
||||
if (result && key instanceof String sk) {
|
||||
if (newValue instanceof String sv) {
|
||||
parseLegacy(sk, sv, OPType.ADD);
|
||||
} else if (oldValue instanceof String sv) {
|
||||
parseLegacy(sk, sv, OPType.REMOVE);
|
||||
}
|
||||
legacyStrings.replace((String)key, (String)oldValue,
|
||||
(String)newValue);
|
||||
}
|
||||
return super.replace(key, oldValue, newValue);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Object implReplace(Object key, Object value) {
|
||||
if ((key instanceof String) && (value instanceof String)) {
|
||||
if (!checkLegacy(key)) {
|
||||
return null;
|
||||
if (!checkLegacy(key)) return null;
|
||||
|
||||
Object o = super.replace(key, value);
|
||||
if (key instanceof String sk) {
|
||||
if (o instanceof String so) {
|
||||
if (value instanceof String sv) {
|
||||
parseLegacy(sk, sv, OPType.ADD);
|
||||
} else {
|
||||
parseLegacy(sk, so, OPType.REMOVE);
|
||||
}
|
||||
}
|
||||
legacyStrings.replace((String)key, (String)value);
|
||||
}
|
||||
return super.replace(key, value);
|
||||
return o;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // Function must actually operate over strings
|
||||
private void implReplaceAll(BiFunction<? super Object, ? super Object,
|
||||
? extends Object> function) {
|
||||
legacyChanged = true;
|
||||
if (legacyStrings == null) {
|
||||
legacyStrings = new LinkedHashMap<>();
|
||||
} else {
|
||||
legacyStrings.replaceAll((BiFunction<? super String, ? super String,
|
||||
? extends String>) function);
|
||||
}
|
||||
|
||||
super.replaceAll(function);
|
||||
// clear out all existing mappings and start fresh
|
||||
legacyMap.clear();
|
||||
legacyChanged = true;
|
||||
for (Map.Entry<Object, Object> entry : super.entrySet()) {
|
||||
Object key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
if ((key instanceof String sk) && (value instanceof String sv)) {
|
||||
if (!checkLegacy(sk)) {
|
||||
continue;
|
||||
}
|
||||
parseLegacy(sk, sv, OPType.ADD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // Function must actually operate over strings
|
||||
private Object implMerge(Object key, Object value,
|
||||
BiFunction<? super Object, ? super Object, ? extends Object>
|
||||
remappingFunction) {
|
||||
if ((key instanceof String) && (value instanceof String)) {
|
||||
if (!checkLegacy(key)) {
|
||||
return null;
|
||||
if (!checkLegacy(key)) return null;
|
||||
|
||||
Object o = super.merge(key, value, remappingFunction);
|
||||
if (key instanceof String sk) {
|
||||
if (o == null) {
|
||||
parseLegacy(sk, null, OPType.REMOVE);
|
||||
} else if (o instanceof String so) {
|
||||
parseLegacy(sk, so, OPType.ADD);
|
||||
}
|
||||
legacyStrings.merge((String)key, (String)value,
|
||||
(BiFunction<? super String, ? super String,
|
||||
? extends String>) remappingFunction);
|
||||
}
|
||||
return super.merge(key, value, remappingFunction);
|
||||
return o;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // Function must actually operate over strings
|
||||
private Object implCompute(Object key, BiFunction<? super Object,
|
||||
? super Object, ? extends Object> remappingFunction) {
|
||||
if (key instanceof String) {
|
||||
if (!checkLegacy(key)) {
|
||||
return null;
|
||||
|
||||
if (!checkLegacy(key)) return null;
|
||||
|
||||
Object o = super.compute(key, remappingFunction);
|
||||
if (key instanceof String sk) {
|
||||
if (o == null) {
|
||||
parseLegacy(sk, null, OPType.REMOVE);
|
||||
} else if (o instanceof String so) {
|
||||
parseLegacy(sk, so, OPType.ADD);
|
||||
}
|
||||
legacyStrings.compute((String) key,
|
||||
(BiFunction<? super String,? super String,
|
||||
? extends String>) remappingFunction);
|
||||
}
|
||||
return super.compute(key, remappingFunction);
|
||||
return o;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // Function must actually operate over strings
|
||||
private Object implComputeIfAbsent(Object key, Function<? super Object,
|
||||
? extends Object> mappingFunction) {
|
||||
if (key instanceof String) {
|
||||
if (!checkLegacy(key)) {
|
||||
return null;
|
||||
}
|
||||
legacyStrings.computeIfAbsent((String) key,
|
||||
(Function<? super String, ? extends String>)
|
||||
mappingFunction);
|
||||
if (!checkLegacy(key)) return null;
|
||||
|
||||
Object o = super.computeIfAbsent(key, mappingFunction);
|
||||
if (o instanceof String so && key instanceof String sk) {
|
||||
parseLegacy(sk, so, OPType.ADD);
|
||||
}
|
||||
return super.computeIfAbsent(key, mappingFunction);
|
||||
return o;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // Function must actually operate over strings
|
||||
private Object implComputeIfPresent(Object key, BiFunction<? super Object,
|
||||
? super Object, ? extends Object> remappingFunction) {
|
||||
if (key instanceof String) {
|
||||
if (!checkLegacy(key)) {
|
||||
return null;
|
||||
}
|
||||
legacyStrings.computeIfPresent((String) key,
|
||||
(BiFunction<? super String, ? super String,
|
||||
? extends String>) remappingFunction);
|
||||
if (!checkLegacy(key)) return null;
|
||||
|
||||
Object o = super.computeIfPresent(key, remappingFunction);
|
||||
if (o instanceof String so && key instanceof String sk) {
|
||||
parseLegacy(sk, so, OPType.ADD);
|
||||
}
|
||||
return super.computeIfPresent(key, remappingFunction);
|
||||
return o;
|
||||
}
|
||||
|
||||
private Object implPut(Object key, Object value) {
|
||||
if ((key instanceof String) && (value instanceof String)) {
|
||||
if (!checkLegacy(key)) {
|
||||
return null;
|
||||
}
|
||||
legacyStrings.put((String)key, (String)value);
|
||||
if (!checkLegacy(key)) return null;
|
||||
|
||||
Object o = super.put(key, value);
|
||||
if (key instanceof String sk && value instanceof String sv) {
|
||||
parseLegacy(sk, sv, OPType.ADD);
|
||||
}
|
||||
return super.put(key, value);
|
||||
return o;
|
||||
}
|
||||
|
||||
private Object implPutIfAbsent(Object key, Object value) {
|
||||
if ((key instanceof String) && (value instanceof String)) {
|
||||
if (!checkLegacy(key)) {
|
||||
return null;
|
||||
}
|
||||
legacyStrings.putIfAbsent((String)key, (String)value);
|
||||
if (!checkLegacy(key)) return null;
|
||||
|
||||
Object o = super.putIfAbsent(key, value);
|
||||
if (o == null && key instanceof String sk &&
|
||||
value instanceof String sv) {
|
||||
parseLegacy(sk, sv, OPType.ADD);
|
||||
}
|
||||
return super.putIfAbsent(key, value);
|
||||
return o;
|
||||
}
|
||||
|
||||
private void implClear() {
|
||||
if (legacyStrings != null) {
|
||||
legacyStrings.clear();
|
||||
}
|
||||
if (legacyMap != null) {
|
||||
legacyMap.clear();
|
||||
}
|
||||
legacyMap.clear();
|
||||
serviceMap.clear();
|
||||
legacyChanged = false;
|
||||
servicesChanged = false;
|
||||
serviceSet = null;
|
||||
prngAlgos = null;
|
||||
prngAlgos.clear();
|
||||
super.clear();
|
||||
putId();
|
||||
}
|
||||
|
@ -1085,40 +1097,8 @@ public abstract class Provider extends Properties {
|
|||
boolean matches(String type, String algorithm) {
|
||||
return (this.type == type) && (this.originalAlgorithm == algorithm);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure all the legacy String properties are fully parsed into
|
||||
* service objects.
|
||||
*/
|
||||
private void ensureLegacyParsed() {
|
||||
if (legacyChanged == false || (legacyStrings == null)) {
|
||||
return;
|
||||
}
|
||||
serviceSet = null;
|
||||
if (legacyMap == null) {
|
||||
legacyMap = new ConcurrentHashMap<>();
|
||||
} else {
|
||||
legacyMap.clear();
|
||||
}
|
||||
for (Map.Entry<String,String> entry : legacyStrings.entrySet()) {
|
||||
parseLegacyPut(entry.getKey(), entry.getValue());
|
||||
}
|
||||
removeInvalidServices(legacyMap);
|
||||
legacyChanged = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all invalid services from the Map. Invalid services can only
|
||||
* occur if the legacy properties are inconsistent or incomplete.
|
||||
*/
|
||||
private void removeInvalidServices(Map<ServiceKey,Service> map) {
|
||||
for (Iterator<Map.Entry<ServiceKey, Service>> t =
|
||||
map.entrySet().iterator(); t.hasNext(); ) {
|
||||
Service s = t.next().getValue();
|
||||
if (s.isValid() == false) {
|
||||
t.remove();
|
||||
}
|
||||
public String toString() {
|
||||
return type + "." + algorithm;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1136,71 +1116,136 @@ public abstract class Provider extends Properties {
|
|||
return new String[] {type, alg};
|
||||
}
|
||||
|
||||
// utility method for getting a String with service type and algorithm
|
||||
private static String getKey(Service s) {
|
||||
return s.getType() + "." + s.getAlgorithm();
|
||||
}
|
||||
|
||||
private static final String ALIAS_PREFIX = "Alg.Alias.";
|
||||
private static final String ALIAS_PREFIX_LOWER = "alg.alias.";
|
||||
private static final int ALIAS_LENGTH = ALIAS_PREFIX.length();
|
||||
|
||||
private void parseLegacyPut(String name, String value) {
|
||||
private static enum OPType {
|
||||
ADD, REMOVE;
|
||||
}
|
||||
|
||||
private void parseLegacy(String name, String value, OPType opType) {
|
||||
// alias
|
||||
if (name.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) {
|
||||
// e.g. put("Alg.Alias.MessageDigest.SHA", "SHA-1");
|
||||
// aliasKey ~ MessageDigest.SHA
|
||||
String stdAlg = value;
|
||||
String aliasKey = name.substring(ALIAS_LENGTH);
|
||||
String[] typeAndAlg = getTypeAndAlgorithm(aliasKey);
|
||||
String aliasKeyStr = name.substring(ALIAS_LENGTH);
|
||||
String[] typeAndAlg = getTypeAndAlgorithm(aliasKeyStr);
|
||||
if (typeAndAlg == null) {
|
||||
return;
|
||||
}
|
||||
legacyChanged = true;
|
||||
Objects.requireNonNull(value, "alias value should map to an alg");
|
||||
String type = getEngineName(typeAndAlg[0]);
|
||||
String aliasAlg = typeAndAlg[1].intern();
|
||||
ServiceKey key = new ServiceKey(type, stdAlg, true);
|
||||
Service s = legacyMap.get(key);
|
||||
if (s == null) {
|
||||
s = new Service(this, type, stdAlg);
|
||||
legacyMap.put(key, s);
|
||||
ServiceKey stdKey = new ServiceKey(type, value, true);
|
||||
Service stdService = legacyMap.get(stdKey);
|
||||
ServiceKey aliasKey = new ServiceKey(type, aliasAlg, true);
|
||||
switch (opType) {
|
||||
case ADD:
|
||||
// clean up old alias if present
|
||||
Service prevAliasService = legacyMap.get(aliasAlg);
|
||||
if (prevAliasService != null) {
|
||||
prevAliasService.removeAlias(aliasAlg);
|
||||
}
|
||||
if (stdService == null) {
|
||||
// add standard mapping in order to add alias
|
||||
stdService = new Service(this, type, value);
|
||||
legacyMap.put(stdKey, stdService);
|
||||
}
|
||||
stdService.addAlias(aliasAlg);
|
||||
legacyMap.put(aliasKey, stdService);
|
||||
break;
|
||||
case REMOVE:
|
||||
if (stdService != null) {
|
||||
stdService.removeAlias(aliasAlg);
|
||||
}
|
||||
legacyMap.remove(aliasKey);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
legacyMap.put(new ServiceKey(type, aliasAlg, true), s);
|
||||
s.addAlias(aliasAlg);
|
||||
} else {
|
||||
String[] typeAndAlg = getTypeAndAlgorithm(name);
|
||||
if (typeAndAlg == null) {
|
||||
return;
|
||||
}
|
||||
legacyChanged = true;
|
||||
int i = typeAndAlg[1].indexOf(' ');
|
||||
// regular registration
|
||||
if (i == -1) {
|
||||
// e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA");
|
||||
String type = getEngineName(typeAndAlg[0]);
|
||||
String stdAlg = typeAndAlg[1].intern();
|
||||
String className = value;
|
||||
ServiceKey key = new ServiceKey(type, stdAlg, true);
|
||||
Service s = legacyMap.get(key);
|
||||
if (s == null) {
|
||||
s = new Service(this, type, stdAlg);
|
||||
legacyMap.put(key, s);
|
||||
}
|
||||
s.className = className;
|
||||
|
||||
if (type.equals("SecureRandom")) {
|
||||
updateSecureRandomEntries(true, s.algorithm);
|
||||
ServiceKey stdKey = new ServiceKey(type, stdAlg, true);
|
||||
Service stdService = legacyMap.get(stdKey);
|
||||
switch (opType) {
|
||||
case ADD:
|
||||
Objects.requireNonNull(value,
|
||||
"className can't be null");
|
||||
if (stdService == null) {
|
||||
stdService = new Service(this, type, stdAlg);
|
||||
legacyMap.put(stdKey, stdService);
|
||||
}
|
||||
stdService.className = value;
|
||||
break;
|
||||
case REMOVE:
|
||||
// only remove if value also matches when non-null
|
||||
if (stdService != null) {
|
||||
if (value == null) {
|
||||
legacyMap.remove(stdKey);
|
||||
} else if (stdService.className.equals(value)) {
|
||||
legacyMap.remove(stdKey, stdService);
|
||||
}
|
||||
// remove all corresponding alias mappings
|
||||
for (String alias : stdService.getAliases()) {
|
||||
legacyMap.remove(new ServiceKey(type, alias,
|
||||
true), stdService);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
checkAndUpdateSecureRandom(type, stdAlg,
|
||||
(opType != OPType.REMOVE));
|
||||
} else { // attribute
|
||||
// e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software");
|
||||
String attributeValue = value;
|
||||
String type = getEngineName(typeAndAlg[0]);
|
||||
String attributeString = typeAndAlg[1];
|
||||
String stdAlg = attributeString.substring(0, i).intern();
|
||||
String attributeName = attributeString.substring(i + 1);
|
||||
String attrString = typeAndAlg[1];
|
||||
String stdAlg = attrString.substring(0, i).intern();
|
||||
String attrName = attrString.substring(i + 1);
|
||||
// kill additional spaces
|
||||
while (attributeName.startsWith(" ")) {
|
||||
attributeName = attributeName.substring(1);
|
||||
while (attrName.startsWith(" ")) {
|
||||
attrName = attrName.substring(1);
|
||||
}
|
||||
attributeName = attributeName.intern();
|
||||
ServiceKey key = new ServiceKey(type, stdAlg, true);
|
||||
Service s = legacyMap.get(key);
|
||||
if (s == null) {
|
||||
s = new Service(this, type, stdAlg);
|
||||
legacyMap.put(key, s);
|
||||
attrName = attrName.intern();
|
||||
ServiceKey stdKey = new ServiceKey(type, stdAlg, true);
|
||||
Service stdService = legacyMap.get(stdKey);
|
||||
switch (opType) {
|
||||
case ADD:
|
||||
Objects.requireNonNull(value,
|
||||
"attribute value should not be null");
|
||||
|
||||
if (stdService == null) {
|
||||
stdService = new Service(this, type, stdAlg);
|
||||
legacyMap.put(stdKey, stdService);
|
||||
}
|
||||
stdService.addAttribute(attrName, value);
|
||||
break;
|
||||
case REMOVE:
|
||||
if (stdService != null) {
|
||||
stdService.removeAttribute(attrName, value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
s.addAttribute(attributeName, attributeValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1227,25 +1272,25 @@ public abstract class Provider extends Properties {
|
|||
*/
|
||||
public Service getService(String type, String algorithm) {
|
||||
checkInitialized();
|
||||
|
||||
// avoid allocating a new ServiceKey object if possible
|
||||
ServiceKey key = previousKey;
|
||||
if (key.matches(type, algorithm) == false) {
|
||||
key = new ServiceKey(type, algorithm, false);
|
||||
previousKey = key;
|
||||
}
|
||||
if (!serviceMap.isEmpty()) {
|
||||
Service s = serviceMap.get(key);
|
||||
if (s != null) {
|
||||
return s;
|
||||
}
|
||||
|
||||
Service s = serviceMap.get(key);
|
||||
if (s != null) {
|
||||
return s;
|
||||
}
|
||||
synchronized (this) {
|
||||
ensureLegacyParsed();
|
||||
if (legacyMap != null && !legacyMap.isEmpty()) {
|
||||
return legacyMap.get(key);
|
||||
}
|
||||
|
||||
s = legacyMap.get(key);
|
||||
if (s != null && !s.isValid()) {
|
||||
legacyMap.remove(key, s);
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1267,22 +1312,19 @@ public abstract class Provider extends Properties {
|
|||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public synchronized Set<Service> getServices() {
|
||||
public Set<Service> getServices() {
|
||||
checkInitialized();
|
||||
if (legacyChanged || servicesChanged) {
|
||||
serviceSet = null;
|
||||
}
|
||||
if (serviceSet == null) {
|
||||
ensureLegacyParsed();
|
||||
if (serviceSet == null || legacyChanged || servicesChanged) {
|
||||
Set<Service> set = new LinkedHashSet<>();
|
||||
if (!serviceMap.isEmpty()) {
|
||||
set.addAll(serviceMap.values());
|
||||
}
|
||||
if (legacyMap != null && !legacyMap.isEmpty()) {
|
||||
if (!legacyMap.isEmpty()) {
|
||||
set.addAll(legacyMap.values());
|
||||
}
|
||||
serviceSet = Collections.unmodifiableSet(set);
|
||||
servicesChanged = false;
|
||||
legacyChanged = false;
|
||||
}
|
||||
return serviceSet;
|
||||
}
|
||||
|
@ -1339,44 +1381,36 @@ public abstract class Provider extends Properties {
|
|||
servicesChanged = true;
|
||||
synchronized (this) {
|
||||
putPropertyStrings(s);
|
||||
if (type.equals("SecureRandom")) {
|
||||
updateSecureRandomEntries(true, s.algorithm);
|
||||
}
|
||||
checkAndUpdateSecureRandom(type, algorithm, true);
|
||||
}
|
||||
}
|
||||
|
||||
// keep tracks of the registered secure random algos and store them in order
|
||||
private void updateSecureRandomEntries(boolean doAdd, String s) {
|
||||
Objects.requireNonNull(s);
|
||||
if (doAdd) {
|
||||
if (prngAlgos == null) {
|
||||
prngAlgos = new LinkedHashSet<String>();
|
||||
private void checkAndUpdateSecureRandom(String type, String algo,
|
||||
boolean doAdd) {
|
||||
if (type.equalsIgnoreCase("SecureRandom")) {
|
||||
if (doAdd) {
|
||||
prngAlgos.add(algo);
|
||||
} else {
|
||||
prngAlgos.remove(algo);
|
||||
}
|
||||
if (debug != null) {
|
||||
debug.println((doAdd? "Add":"Remove") +
|
||||
" SecureRandom algo " + algo);
|
||||
}
|
||||
prngAlgos.add(s);
|
||||
} else {
|
||||
prngAlgos.remove(s);
|
||||
}
|
||||
|
||||
if (debug != null) {
|
||||
debug.println((doAdd? "Add":"Remove") + " SecureRandom algo " + s);
|
||||
}
|
||||
}
|
||||
|
||||
// used by new SecureRandom() to find out the default SecureRandom
|
||||
// service for this provider
|
||||
synchronized Service getDefaultSecureRandomService() {
|
||||
Service getDefaultSecureRandomService() {
|
||||
checkInitialized();
|
||||
|
||||
if (legacyChanged) {
|
||||
prngAlgos = null;
|
||||
ensureLegacyParsed();
|
||||
}
|
||||
|
||||
if (prngAlgos != null && !prngAlgos.isEmpty()) {
|
||||
if (!prngAlgos.isEmpty()) {
|
||||
String algo = prngAlgos.iterator().next();
|
||||
// IMPORTANT: use the Service obj returned by getService(...) call
|
||||
// as providers may override putService(...)/getService(...) and
|
||||
// return their own Service objects
|
||||
return getService("SecureRandom", prngAlgos.iterator().next());
|
||||
return getService("SecureRandom", algo);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -1473,12 +1507,9 @@ public abstract class Provider extends Properties {
|
|||
for (String alias : s.getAliases()) {
|
||||
serviceMap.remove(new ServiceKey(type, alias, false));
|
||||
}
|
||||
synchronized (this) {
|
||||
removePropertyStrings(s);
|
||||
if (type.equals("SecureRandom")) {
|
||||
updateSecureRandomEntries(false, s.algorithm);
|
||||
}
|
||||
}
|
||||
|
||||
removePropertyStrings(s);
|
||||
checkAndUpdateSecureRandom(type, algorithm, false);
|
||||
}
|
||||
|
||||
// Wrapped String that behaves in a case insensitive way for equals/hashCode
|
||||
|
@ -1686,6 +1717,13 @@ public abstract class Provider extends Properties {
|
|||
aliases.add(alias);
|
||||
}
|
||||
|
||||
private void removeAlias(String alias) {
|
||||
if (aliases.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
aliases.remove(alias);
|
||||
}
|
||||
|
||||
void addAttribute(String type, String value) {
|
||||
if (attributes.isEmpty()) {
|
||||
attributes = new HashMap<>(8);
|
||||
|
@ -1693,6 +1731,17 @@ public abstract class Provider extends Properties {
|
|||
attributes.put(new UString(type), value);
|
||||
}
|
||||
|
||||
void removeAttribute(String type, String value) {
|
||||
if (attributes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (value == null) {
|
||||
attributes.remove(new UString(type));
|
||||
} else {
|
||||
attributes.remove(new UString(type), value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new service.
|
||||
*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue