8055753: Use ConcurrentHashMap to map ProtectionDomain to PermissionCollection

Reviewed-by: weijun
This commit is contained in:
Sean Mullan 2015-05-21 07:17:36 -04:00
parent c7c5826bb2
commit d29a80d711

View File

@ -25,23 +25,24 @@
package java.security; package java.security;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import sun.misc.JavaSecurityAccess;
import sun.misc.JavaSecurityProtectionDomainAccess; import sun.misc.JavaSecurityProtectionDomainAccess;
import static sun.misc.JavaSecurityProtectionDomainAccess.ProtectionDomainCache; import static sun.misc.JavaSecurityProtectionDomainAccess.ProtectionDomainCache;
import sun.misc.SharedSecrets;
import sun.security.util.Debug; import sun.security.util.Debug;
import sun.security.util.SecurityConstants; import sun.security.util.SecurityConstants;
import sun.misc.JavaSecurityAccess;
import sun.misc.SharedSecrets;
/** /**
* * The ProtectionDomain class encapsulates the characteristics of a domain,
*<p>
* This ProtectionDomain class encapsulates the characteristics of a domain,
* which encloses a set of classes whose instances are granted a set * which encloses a set of classes whose instances are granted a set
* of permissions when being executed on behalf of a given set of Principals. * of permissions when being executed on behalf of a given set of Principals.
* <p> * <p>
@ -58,6 +59,7 @@ import sun.misc.SharedSecrets;
*/ */
public class ProtectionDomain { public class ProtectionDomain {
private static class JavaSecurityAccessImpl implements JavaSecurityAccess { private static class JavaSecurityAccessImpl implements JavaSecurityAccess {
private JavaSecurityAccessImpl() { private JavaSecurityAccessImpl() {
@ -86,18 +88,33 @@ public class ProtectionDomain {
AccessController.getContext(), context); AccessController.getContext(), context);
} }
private static AccessControlContext getCombinedACC(AccessControlContext context, AccessControlContext stack) { private static AccessControlContext getCombinedACC(
AccessControlContext acc = new AccessControlContext(context, stack.getCombiner(), true); AccessControlContext context, AccessControlContext stack) {
AccessControlContext acc =
new AccessControlContext(context, stack.getCombiner(), true);
return new AccessControlContext(stack.getContext(), acc).optimize(); return new AccessControlContext(stack.getContext(), acc).optimize();
} }
} }
static { static {
// Set up JavaSecurityAccess in SharedSecrets // setup SharedSecrets to allow access to doIntersectionPrivilege
// methods and ProtectionDomain cache
SharedSecrets.setJavaSecurityAccess(new JavaSecurityAccessImpl()); SharedSecrets.setJavaSecurityAccess(new JavaSecurityAccessImpl());
SharedSecrets.setJavaSecurityProtectionDomainAccess(
new JavaSecurityProtectionDomainAccess() {
@Override
public ProtectionDomainCache getProtectionDomainCache() {
return new PDCache();
}
});
} }
/**
* Used for storing ProtectionDomains as keys in a Map.
*/
static final class Key {}
/* CodeSource */ /* CodeSource */
private CodeSource codesource ; private CodeSource codesource ;
@ -451,40 +468,104 @@ public class ProtectionDomain {
} }
/** /**
* Used for storing ProtectionDomains as keys in a Map. * A cache of ProtectionDomains and their Permissions.
*
* This class stores ProtectionDomains as weak keys in a ConcurrentHashMap
* with additional support for checking and removing weak keys that are no
* longer in use.
*/ */
final static class Key {}
// A cache of ProtectionDomains and their Permissions
private static class PDCache implements ProtectionDomainCache { private static class PDCache implements ProtectionDomainCache {
// We must wrap the PermissionCollection in a WeakReference as there private final ConcurrentHashMap<WeakProtectionDomainKey,
// are some PermissionCollections which contain strong references PermissionCollection>
// back to a ProtectionDomain and otherwise would never be removed pdMap = new ConcurrentHashMap<>();
// from the WeakHashMap private final ReferenceQueue<Key> queue = new ReferenceQueue<>();
private final Map<Key, WeakReference<PermissionCollection>>
map = new WeakHashMap<>();
@Override @Override
public synchronized void put(ProtectionDomain pd, public void put(ProtectionDomain pd, PermissionCollection pc) {
PermissionCollection pc) { processQueue(queue, pdMap);
map.put(pd == null ? null : pd.key, new WeakReference<>(pc)); WeakProtectionDomainKey weakPd =
new WeakProtectionDomainKey(pd, queue);
pdMap.putIfAbsent(weakPd, pc);
} }
@Override @Override
public synchronized PermissionCollection get(ProtectionDomain pd) { public PermissionCollection get(ProtectionDomain pd) {
WeakReference<PermissionCollection> ref = processQueue(queue, pdMap);
map.get(pd == null ? null : pd.key); WeakProtectionDomainKey weakPd =
return ref == null ? null : ref.get(); new WeakProtectionDomainKey(pd, queue);
return pdMap.get(weakPd);
}
/**
* Removes weak keys from the map that have been enqueued
* on the reference queue and are no longer in use.
*/
private static void processQueue(ReferenceQueue<Key> queue,
ConcurrentHashMap<? extends
WeakReference<Key>, ?> pdMap) {
Reference<? extends Key> ref;
while ((ref = queue.poll()) != null) {
pdMap.remove(ref);
}
} }
} }
static { /**
SharedSecrets.setJavaSecurityProtectionDomainAccess( * A weak key for a ProtectionDomain.
new JavaSecurityProtectionDomainAccess() { */
@Override private static class WeakProtectionDomainKey extends WeakReference<Key> {
public ProtectionDomainCache getProtectionDomainCache() { /**
return new PDCache(); * Saved value of the referent's identity hash code, to maintain
} * a consistent hash code after the referent has been cleared
}); */
private final int hash;
/**
* A key representing a null ProtectionDomain.
*/
private static final Key NULL_KEY = new Key();
/**
* Create a new WeakProtectionDomain with the specified domain and
* registered with a queue.
*/
WeakProtectionDomainKey(ProtectionDomain pd, ReferenceQueue<Key> rq) {
this((pd == null ? NULL_KEY : pd.key), rq);
}
private WeakProtectionDomainKey(Key key, ReferenceQueue<Key> rq) {
super(key, rq);
hash = key.hashCode();
}
/**
* Returns the identity hash code of the original referent.
*/
@Override
public int hashCode() {
return hash;
}
/**
* Returns true if the given object is an identical
* WeakProtectionDomainKey instance, or, if this object's referent
* has not been cleared and the given object is another
* WeakProtectionDomainKey instance with an identical non-null
* referent as this one.
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof WeakProtectionDomainKey) {
Object referent = get();
return (referent != null) &&
(referent == ((WeakProtectionDomainKey)obj).get());
} else {
return false;
}
}
} }
} }