mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-09 22:48:41 +00:00
7092897: sun.security.util.Cache should be generified
Reviewed-by: xuelei
This commit is contained in:
parent
8dd8726505
commit
9852219b7e
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -48,7 +48,7 @@ import sun.security.util.Cache;
|
||||
*/
|
||||
final class KeyCache {
|
||||
|
||||
private final Cache strongCache;
|
||||
private final Cache<IdentityWrapper, P11Key> strongCache;
|
||||
|
||||
private WeakReference<Map<Key,P11Key>> cacheReference;
|
||||
|
||||
@ -77,7 +77,7 @@ final class KeyCache {
|
||||
}
|
||||
|
||||
synchronized P11Key get(Key key) {
|
||||
P11Key p11Key = (P11Key)strongCache.get(new IdentityWrapper(key));
|
||||
P11Key p11Key = strongCache.get(new IdentityWrapper(key));
|
||||
if (p11Key != null) {
|
||||
return p11Key;
|
||||
}
|
||||
@ -94,8 +94,8 @@ final class KeyCache {
|
||||
Map<Key,P11Key> map =
|
||||
(cacheReference == null) ? null : cacheReference.get();
|
||||
if (map == null) {
|
||||
map = new IdentityHashMap<Key,P11Key>();
|
||||
cacheReference = new WeakReference<Map<Key,P11Key>>(map);
|
||||
map = new IdentityHashMap<>();
|
||||
cacheReference = new WeakReference<>(map);
|
||||
}
|
||||
map.put(key, p11Key);
|
||||
}
|
||||
|
||||
@ -64,8 +64,10 @@ public class X509Factory extends CertificateFactorySpi {
|
||||
|
||||
private static final int ENC_MAX_LENGTH = 4096 * 1024; // 4 MB MAX
|
||||
|
||||
private static final Cache certCache = Cache.newSoftMemoryCache(750);
|
||||
private static final Cache crlCache = Cache.newSoftMemoryCache(750);
|
||||
private static final Cache<Object, X509CertImpl> certCache
|
||||
= Cache.newSoftMemoryCache(750);
|
||||
private static final Cache<Object, X509CRLImpl> crlCache
|
||||
= Cache.newSoftMemoryCache(750);
|
||||
|
||||
/**
|
||||
* Generates an X.509 certificate object and initializes it with
|
||||
@ -90,7 +92,7 @@ public class X509Factory extends CertificateFactorySpi {
|
||||
try {
|
||||
byte[] encoding = readOneBlock(is);
|
||||
if (encoding != null) {
|
||||
X509CertImpl cert = (X509CertImpl)getFromCache(certCache, encoding);
|
||||
X509CertImpl cert = getFromCache(certCache, encoding);
|
||||
if (cert != null) {
|
||||
return cert;
|
||||
}
|
||||
@ -151,7 +153,7 @@ public class X509Factory extends CertificateFactorySpi {
|
||||
} else {
|
||||
encoding = c.getEncoded();
|
||||
}
|
||||
X509CertImpl newC = (X509CertImpl)getFromCache(certCache, encoding);
|
||||
X509CertImpl newC = getFromCache(certCache, encoding);
|
||||
if (newC != null) {
|
||||
return newC;
|
||||
}
|
||||
@ -181,7 +183,7 @@ public class X509Factory extends CertificateFactorySpi {
|
||||
} else {
|
||||
encoding = c.getEncoded();
|
||||
}
|
||||
X509CRLImpl newC = (X509CRLImpl)getFromCache(crlCache, encoding);
|
||||
X509CRLImpl newC = getFromCache(crlCache, encoding);
|
||||
if (newC != null) {
|
||||
return newC;
|
||||
}
|
||||
@ -198,18 +200,17 @@ public class X509Factory extends CertificateFactorySpi {
|
||||
/**
|
||||
* Get the X509CertImpl or X509CRLImpl from the cache.
|
||||
*/
|
||||
private static synchronized Object getFromCache(Cache cache,
|
||||
private static synchronized <K,V> V getFromCache(Cache<K,V> cache,
|
||||
byte[] encoding) {
|
||||
Object key = new Cache.EqualByteArray(encoding);
|
||||
Object value = cache.get(key);
|
||||
return value;
|
||||
return cache.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the X509CertImpl or X509CRLImpl to the cache.
|
||||
*/
|
||||
private static synchronized void addToCache(Cache cache, byte[] encoding,
|
||||
Object value) {
|
||||
private static synchronized <V> void addToCache(Cache<Object, V> cache,
|
||||
byte[] encoding, V value) {
|
||||
if (encoding.length > ENC_MAX_LENGTH) {
|
||||
return;
|
||||
}
|
||||
@ -361,7 +362,7 @@ public class X509Factory extends CertificateFactorySpi {
|
||||
try {
|
||||
byte[] encoding = readOneBlock(is);
|
||||
if (encoding != null) {
|
||||
X509CRLImpl crl = (X509CRLImpl)getFromCache(crlCache, encoding);
|
||||
X509CRLImpl crl = getFromCache(crlCache, encoding);
|
||||
if (crl != null) {
|
||||
return crl;
|
||||
}
|
||||
|
||||
@ -59,12 +59,13 @@ public abstract class CertStoreHelper {
|
||||
"SSLServer",
|
||||
"sun.security.provider.certpath.ssl.SSLServerCertStoreHelper");
|
||||
};
|
||||
private static Cache cache = Cache.newSoftMemoryCache(NUM_TYPES);
|
||||
private static Cache<String, CertStoreHelper> cache
|
||||
= Cache.newSoftMemoryCache(NUM_TYPES);
|
||||
|
||||
public static CertStoreHelper getInstance(final String type)
|
||||
throws NoSuchAlgorithmException
|
||||
{
|
||||
CertStoreHelper helper = (CertStoreHelper)cache.get(type);
|
||||
CertStoreHelper helper = cache.get(type);
|
||||
if (helper != null) {
|
||||
return helper;
|
||||
}
|
||||
|
||||
@ -100,8 +100,7 @@ class URICertStore extends CertStoreSpi {
|
||||
private final CertificateFactory factory;
|
||||
|
||||
// cached Collection of X509Certificates (may be empty, never null)
|
||||
private Collection<X509Certificate> certs =
|
||||
Collections.<X509Certificate>emptySet();
|
||||
private Collection<X509Certificate> certs = Collections.emptySet();
|
||||
|
||||
// cached X509CRL (may be null)
|
||||
private X509CRL crl;
|
||||
@ -157,14 +156,14 @@ class URICertStore extends CertStoreSpi {
|
||||
* Returns a URI CertStore. This method consults a cache of
|
||||
* CertStores (shared per JVM) using the URI as a key.
|
||||
*/
|
||||
private static final Cache certStoreCache =
|
||||
Cache.newSoftMemoryCache(CACHE_SIZE);
|
||||
private static final Cache<URICertStoreParameters, CertStore>
|
||||
certStoreCache = Cache.newSoftMemoryCache(CACHE_SIZE);
|
||||
static synchronized CertStore getInstance(URICertStoreParameters params)
|
||||
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
|
||||
if (debug != null) {
|
||||
debug.println("CertStore URI:" + params.uri);
|
||||
}
|
||||
CertStore ucs = (CertStore) certStoreCache.get(params);
|
||||
CertStore ucs = certStoreCache.get(params);
|
||||
if (ucs == null) {
|
||||
ucs = new UCS(new URICertStore(params), null, "URI", params);
|
||||
certStoreCache.put(params, ucs);
|
||||
@ -287,7 +286,7 @@ class URICertStore extends CertStoreSpi {
|
||||
}
|
||||
// exception, forget previous values
|
||||
lastModified = 0;
|
||||
certs = Collections.<X509Certificate>emptySet();
|
||||
certs = Collections.emptySet();
|
||||
return certs;
|
||||
}
|
||||
|
||||
@ -394,7 +393,7 @@ class URICertStore extends CertStoreSpi {
|
||||
// exception, forget previous values
|
||||
lastModified = 0;
|
||||
crl = null;
|
||||
return Collections.<X509CRL>emptyList();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -404,9 +403,9 @@ class URICertStore extends CertStoreSpi {
|
||||
private static Collection<X509CRL> getMatchingCRLs
|
||||
(X509CRL crl, CRLSelector selector) {
|
||||
if (selector == null || (crl != null && selector.match(crl))) {
|
||||
return Collections.<X509CRL>singletonList(crl);
|
||||
return Collections.singletonList(crl);
|
||||
} else {
|
||||
return Collections.<X509CRL>emptyList();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -79,7 +79,8 @@ public class X509CertificatePair {
|
||||
private X509Certificate reverse;
|
||||
private byte[] encoded;
|
||||
|
||||
private static final Cache cache = Cache.newSoftMemoryCache(750);
|
||||
private static final Cache<Object, X509CertificatePair> cache
|
||||
= Cache.newSoftMemoryCache(750);
|
||||
|
||||
/**
|
||||
* Creates an empty instance of X509CertificatePair.
|
||||
@ -114,7 +115,7 @@ public class X509CertificatePair {
|
||||
*
|
||||
* For internal use only, external code should use generateCertificatePair.
|
||||
*/
|
||||
private X509CertificatePair(byte[] encoded)throws CertificateException {
|
||||
private X509CertificatePair(byte[] encoded) throws CertificateException {
|
||||
try {
|
||||
parse(new DerValue(encoded));
|
||||
this.encoded = encoded;
|
||||
@ -138,7 +139,7 @@ public class X509CertificatePair {
|
||||
public static synchronized X509CertificatePair generateCertificatePair
|
||||
(byte[] encoded) throws CertificateException {
|
||||
Object key = new Cache.EqualByteArray(encoded);
|
||||
X509CertificatePair pair = (X509CertificatePair)cache.get(key);
|
||||
X509CertificatePair pair = cache.get(key);
|
||||
if (pair != null) {
|
||||
return pair;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -160,7 +160,7 @@ public final class LDAPCertStore extends CertStoreSpi {
|
||||
*/
|
||||
private boolean prefetchCRLs = false;
|
||||
|
||||
private final Cache valueCache;
|
||||
private final Cache<String, byte[][]> valueCache;
|
||||
|
||||
private int cacheHits = 0;
|
||||
private int cacheMisses = 0;
|
||||
@ -207,10 +207,11 @@ public final class LDAPCertStore extends CertStoreSpi {
|
||||
* Returns an LDAP CertStore. This method consults a cache of
|
||||
* CertStores (shared per JVM) using the LDAP server/port as a key.
|
||||
*/
|
||||
private static final Cache certStoreCache = Cache.newSoftMemoryCache(185);
|
||||
private static final Cache<LDAPCertStoreParameters, CertStore>
|
||||
certStoreCache = Cache.newSoftMemoryCache(185);
|
||||
static synchronized CertStore getInstance(LDAPCertStoreParameters params)
|
||||
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
|
||||
CertStore lcs = (CertStore) certStoreCache.get(params);
|
||||
CertStore lcs = certStoreCache.get(params);
|
||||
if (lcs == null) {
|
||||
lcs = CertStore.getInstance("LDAP", params);
|
||||
certStoreCache.put(params, lcs);
|
||||
@ -232,7 +233,7 @@ public final class LDAPCertStore extends CertStoreSpi {
|
||||
private void createInitialDirContext(String server, int port)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
String url = "ldap://" + server + ":" + port;
|
||||
Hashtable<String,Object> env = new Hashtable<String,Object>();
|
||||
Hashtable<String,Object> env = new Hashtable<>();
|
||||
env.put(Context.INITIAL_CONTEXT_FACTORY,
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
env.put(Context.PROVIDER_URL, url);
|
||||
@ -283,7 +284,7 @@ public final class LDAPCertStore extends CertStoreSpi {
|
||||
|
||||
LDAPRequest(String name) {
|
||||
this.name = name;
|
||||
requestedAttributes = new ArrayList<String>(5);
|
||||
requestedAttributes = new ArrayList<>(5);
|
||||
}
|
||||
|
||||
String getName() {
|
||||
@ -311,7 +312,7 @@ public final class LDAPCertStore extends CertStoreSpi {
|
||||
+ cacheMisses);
|
||||
}
|
||||
String cacheKey = name + "|" + attrId;
|
||||
byte[][] values = (byte[][])valueCache.get(cacheKey);
|
||||
byte[][] values = valueCache.get(cacheKey);
|
||||
if (values != null) {
|
||||
cacheHits++;
|
||||
return values;
|
||||
@ -347,7 +348,7 @@ public final class LDAPCertStore extends CertStoreSpi {
|
||||
System.out.println("LDAP requests: " + requests);
|
||||
}
|
||||
}
|
||||
valueMap = new HashMap<String, byte[][]>(8);
|
||||
valueMap = new HashMap<>(8);
|
||||
String[] attrIds = requestedAttributes.toArray(STRING0);
|
||||
Attributes attrs;
|
||||
try {
|
||||
@ -429,10 +430,10 @@ public final class LDAPCertStore extends CertStoreSpi {
|
||||
|
||||
int n = encodedCert.length;
|
||||
if (n == 0) {
|
||||
return Collections.<X509Certificate>emptySet();
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
List<X509Certificate> certs = new ArrayList<X509Certificate>(n);
|
||||
List<X509Certificate> certs = new ArrayList<>(n);
|
||||
/* decode certs and check if they satisfy selector */
|
||||
for (int i = 0; i < n; i++) {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert[i]);
|
||||
@ -477,11 +478,10 @@ public final class LDAPCertStore extends CertStoreSpi {
|
||||
|
||||
int n = encodedCertPair.length;
|
||||
if (n == 0) {
|
||||
return Collections.<X509CertificatePair>emptySet();
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
List<X509CertificatePair> certPairs =
|
||||
new ArrayList<X509CertificatePair>(n);
|
||||
List<X509CertificatePair> certPairs = new ArrayList<>(n);
|
||||
/* decode each cert pair and add it to the Collection */
|
||||
for (int i = 0; i < n; i++) {
|
||||
try {
|
||||
@ -528,8 +528,7 @@ public final class LDAPCertStore extends CertStoreSpi {
|
||||
getCertPairs(request, CROSS_CERT);
|
||||
|
||||
// Find Certificates that match and put them in a list
|
||||
ArrayList<X509Certificate> matchingCerts =
|
||||
new ArrayList<X509Certificate>();
|
||||
ArrayList<X509Certificate> matchingCerts = new ArrayList<>();
|
||||
for (X509CertificatePair certPair : certPairs) {
|
||||
X509Certificate cert;
|
||||
if (forward != null) {
|
||||
@ -587,7 +586,7 @@ public final class LDAPCertStore extends CertStoreSpi {
|
||||
int basicConstraints = xsel.getBasicConstraints();
|
||||
String subject = xsel.getSubjectAsString();
|
||||
String issuer = xsel.getIssuerAsString();
|
||||
HashSet<X509Certificate> certs = new HashSet<X509Certificate>();
|
||||
HashSet<X509Certificate> certs = new HashSet<>();
|
||||
if (debug != null) {
|
||||
debug.println("LDAPCertStore.engineGetCertificates() basicConstraints: "
|
||||
+ basicConstraints);
|
||||
@ -706,10 +705,10 @@ public final class LDAPCertStore extends CertStoreSpi {
|
||||
|
||||
int n = encodedCRL.length;
|
||||
if (n == 0) {
|
||||
return Collections.<X509CRL>emptySet();
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
List<X509CRL> crls = new ArrayList<X509CRL>(n);
|
||||
List<X509CRL> crls = new ArrayList<>(n);
|
||||
/* decode each crl and check if it matches selector */
|
||||
for (int i = 0; i < n; i++) {
|
||||
try {
|
||||
@ -765,13 +764,13 @@ public final class LDAPCertStore extends CertStoreSpi {
|
||||
throw new CertStoreException("need X509CRLSelector to find CRLs");
|
||||
}
|
||||
X509CRLSelector xsel = (X509CRLSelector) selector;
|
||||
HashSet<X509CRL> crls = new HashSet<X509CRL>();
|
||||
HashSet<X509CRL> crls = new HashSet<>();
|
||||
|
||||
// Look in directory entry for issuer of cert we're checking.
|
||||
Collection<Object> issuerNames;
|
||||
X509Certificate certChecking = xsel.getCertificateChecking();
|
||||
if (certChecking != null) {
|
||||
issuerNames = new HashSet<Object>();
|
||||
issuerNames = new HashSet<>();
|
||||
X500Principal issuer = certChecking.getIssuerX500Principal();
|
||||
issuerNames.add(issuer.getName(X500Principal.RFC2253));
|
||||
} else {
|
||||
@ -796,7 +795,7 @@ public final class LDAPCertStore extends CertStoreSpi {
|
||||
issuerName = (String)nameObject;
|
||||
}
|
||||
// If all we want is CA certs, try to get the (probably shorter) ARL
|
||||
Collection<X509CRL> entryCRLs = Collections.<X509CRL>emptySet();
|
||||
Collection<X509CRL> entryCRLs = Collections.emptySet();
|
||||
if (certChecking == null || certChecking.getBasicConstraints() != -1) {
|
||||
LDAPRequest request = new LDAPRequest(issuerName);
|
||||
request.addRequestedAttribute(CROSS_CERT);
|
||||
@ -1028,9 +1027,9 @@ public final class LDAPCertStore extends CertStoreSpi {
|
||||
throws IOException {
|
||||
this.selector = selector == null ? new X509CRLSelector() : selector;
|
||||
this.certIssuers = certIssuers;
|
||||
issuerNames = new HashSet<Object>();
|
||||
issuerNames = new HashSet<>();
|
||||
issuerNames.add(ldapDN);
|
||||
issuers = new HashSet<X500Principal>();
|
||||
issuers = new HashSet<>();
|
||||
issuers.add(new X500Name(ldapDN).asX500Principal());
|
||||
}
|
||||
// we only override the get (accessor methods) since the set methods
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -43,11 +43,14 @@ import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import sun.security.util.Cache;
|
||||
import sun.security.util.Cache.CacheVisitor;
|
||||
|
||||
|
||||
final class SSLSessionContextImpl implements SSLSessionContext {
|
||||
private Cache sessionCache; // session cache, session id as key
|
||||
private Cache sessionHostPortCache; // session cache, "host:port" as key
|
||||
private Cache<SessionId, SSLSessionImpl> sessionCache;
|
||||
// session cache, session id as key
|
||||
private Cache<String, SSLSessionImpl> sessionHostPortCache;
|
||||
// session cache, "host:port" as key
|
||||
private int cacheLimit; // the max cache size
|
||||
private int timeout; // timeout in seconds
|
||||
|
||||
@ -71,8 +74,7 @@ final class SSLSessionContextImpl implements SSLSessionContext {
|
||||
throw new NullPointerException("session id cannot be null");
|
||||
}
|
||||
|
||||
SSLSessionImpl sess =
|
||||
(SSLSessionImpl)sessionCache.get(new SessionId(sessionId));
|
||||
SSLSessionImpl sess = sessionCache.get(new SessionId(sessionId));
|
||||
if (!isTimedout(sess)) {
|
||||
return sess;
|
||||
}
|
||||
@ -157,8 +159,7 @@ final class SSLSessionContextImpl implements SSLSessionContext {
|
||||
return null;
|
||||
}
|
||||
|
||||
SSLSessionImpl sess =
|
||||
(SSLSessionImpl)sessionHostPortCache.get(getKey(hostname, port));
|
||||
SSLSessionImpl sess = sessionHostPortCache.get(getKey(hostname, port));
|
||||
if (!isTimedout(sess)) {
|
||||
return sess;
|
||||
}
|
||||
@ -193,7 +194,7 @@ final class SSLSessionContextImpl implements SSLSessionContext {
|
||||
|
||||
// package-private method, remove a cached SSLSession
|
||||
void remove(SessionId key) {
|
||||
SSLSessionImpl s = (SSLSessionImpl)sessionCache.get(key);
|
||||
SSLSessionImpl s = sessionCache.get(key);
|
||||
if (s != null) {
|
||||
sessionCache.remove(key);
|
||||
sessionHostPortCache.remove(
|
||||
@ -233,17 +234,17 @@ final class SSLSessionContextImpl implements SSLSessionContext {
|
||||
}
|
||||
|
||||
final class SessionCacheVisitor
|
||||
implements sun.security.util.Cache.CacheVisitor {
|
||||
implements Cache.CacheVisitor<SessionId, SSLSessionImpl> {
|
||||
Vector<byte[]> ids = null;
|
||||
|
||||
// public void visit(java.util.Map<Object, Object> map) {}
|
||||
public void visit(java.util.Map<Object, Object> map) {
|
||||
ids = new Vector<byte[]>(map.size());
|
||||
// public void visit(java.util.Map<K,V> map) {}
|
||||
public void visit(java.util.Map<SessionId, SSLSessionImpl> map) {
|
||||
ids = new Vector<>(map.size());
|
||||
|
||||
for (Object key : map.keySet()) {
|
||||
SSLSessionImpl value = (SSLSessionImpl)map.get(key);
|
||||
for (SessionId key : map.keySet()) {
|
||||
SSLSessionImpl value = map.get(key);
|
||||
if (!isTimedout(value)) {
|
||||
ids.addElement(((SessionId)key).getId());
|
||||
ids.addElement(key.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ import java.lang.ref.*;
|
||||
*
|
||||
* . optional lifetime, specified in seconds.
|
||||
*
|
||||
* . save for concurrent use by multiple threads
|
||||
* . safe for concurrent use by multiple threads
|
||||
*
|
||||
* . values are held by either standard references or via SoftReferences.
|
||||
* SoftReferences have the advantage that they are automatically cleared
|
||||
@ -69,7 +69,7 @@ import java.lang.ref.*;
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public abstract class Cache {
|
||||
public abstract class Cache<K,V> {
|
||||
|
||||
protected Cache() {
|
||||
// empty
|
||||
@ -88,12 +88,12 @@ public abstract class Cache {
|
||||
/**
|
||||
* Add an entry to the cache.
|
||||
*/
|
||||
public abstract void put(Object key, Object value);
|
||||
public abstract void put(K key, V value);
|
||||
|
||||
/**
|
||||
* Get a value from the cache.
|
||||
*/
|
||||
public abstract Object get(Object key);
|
||||
public abstract V get(Object key);
|
||||
|
||||
/**
|
||||
* Remove an entry from the cache.
|
||||
@ -113,14 +113,14 @@ public abstract class Cache {
|
||||
/**
|
||||
* accept a visitor
|
||||
*/
|
||||
public abstract void accept(CacheVisitor visitor);
|
||||
public abstract void accept(CacheVisitor<K,V> visitor);
|
||||
|
||||
/**
|
||||
* Return a new memory cache with the specified maximum size, unlimited
|
||||
* lifetime for entries, with the values held by SoftReferences.
|
||||
*/
|
||||
public static Cache newSoftMemoryCache(int size) {
|
||||
return new MemoryCache(true, size);
|
||||
public static <K,V> Cache<K,V> newSoftMemoryCache(int size) {
|
||||
return new MemoryCache<>(true, size);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,23 +128,24 @@ public abstract class Cache {
|
||||
* specified maximum lifetime (in seconds), with the values held
|
||||
* by SoftReferences.
|
||||
*/
|
||||
public static Cache newSoftMemoryCache(int size, int timeout) {
|
||||
return new MemoryCache(true, size, timeout);
|
||||
public static <K,V> Cache<K,V> newSoftMemoryCache(int size, int timeout) {
|
||||
return new MemoryCache<>(true, size, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new memory cache with the specified maximum size, unlimited
|
||||
* lifetime for entries, with the values held by standard references.
|
||||
*/
|
||||
public static Cache newHardMemoryCache(int size) {
|
||||
return new MemoryCache(false, size);
|
||||
public static <K,V> Cache<K,V> newHardMemoryCache(int size) {
|
||||
return new MemoryCache<>(false, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a dummy cache that does nothing.
|
||||
*/
|
||||
public static Cache newNullCache() {
|
||||
return NullCache.INSTANCE;
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <K,V> Cache<K,V> newNullCache() {
|
||||
return (Cache<K,V>) NullCache.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -152,8 +153,8 @@ public abstract class Cache {
|
||||
* specified maximum lifetime (in seconds), with the values held
|
||||
* by standard references.
|
||||
*/
|
||||
public static Cache newHardMemoryCache(int size, int timeout) {
|
||||
return new MemoryCache(false, size, timeout);
|
||||
public static <K,V> Cache<K,V> newHardMemoryCache(int size, int timeout) {
|
||||
return new MemoryCache<>(false, size, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -193,15 +194,15 @@ public abstract class Cache {
|
||||
}
|
||||
}
|
||||
|
||||
public interface CacheVisitor {
|
||||
public void visit(Map<Object, Object> map);
|
||||
public interface CacheVisitor<K,V> {
|
||||
public void visit(Map<K,V> map);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class NullCache extends Cache {
|
||||
class NullCache<K,V> extends Cache<K,V> {
|
||||
|
||||
final static Cache INSTANCE = new NullCache();
|
||||
final static Cache<Object,Object> INSTANCE = new NullCache<>();
|
||||
|
||||
private NullCache() {
|
||||
// empty
|
||||
@ -215,11 +216,11 @@ class NullCache extends Cache {
|
||||
// empty
|
||||
}
|
||||
|
||||
public void put(Object key, Object value) {
|
||||
public void put(K key, V value) {
|
||||
// empty
|
||||
}
|
||||
|
||||
public Object get(Object key) {
|
||||
public V get(Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -235,23 +236,26 @@ class NullCache extends Cache {
|
||||
// empty
|
||||
}
|
||||
|
||||
public void accept(CacheVisitor visitor) {
|
||||
public void accept(CacheVisitor<K,V> visitor) {
|
||||
// empty
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MemoryCache extends Cache {
|
||||
class MemoryCache<K,V> extends Cache<K,V> {
|
||||
|
||||
private final static float LOAD_FACTOR = 0.75f;
|
||||
|
||||
// XXXX
|
||||
private final static boolean DEBUG = false;
|
||||
|
||||
private final Map<Object, CacheEntry> cacheMap;
|
||||
private final Map<K, CacheEntry<K,V>> cacheMap;
|
||||
private int maxSize;
|
||||
private long lifetime;
|
||||
private final ReferenceQueue<Object> queue;
|
||||
|
||||
// ReferenceQueue is of type V instead of Cache<K,V>
|
||||
// to allow SoftCacheEntry to extend SoftReference<V>
|
||||
private final ReferenceQueue<V> queue;
|
||||
|
||||
public MemoryCache(boolean soft, int maxSize) {
|
||||
this(soft, maxSize, 0);
|
||||
@ -260,10 +264,13 @@ class MemoryCache extends Cache {
|
||||
public MemoryCache(boolean soft, int maxSize, int lifetime) {
|
||||
this.maxSize = maxSize;
|
||||
this.lifetime = lifetime * 1000;
|
||||
this.queue = soft ? new ReferenceQueue<Object>() : null;
|
||||
if (soft)
|
||||
this.queue = new ReferenceQueue<>();
|
||||
else
|
||||
this.queue = null;
|
||||
|
||||
int buckets = (int)(maxSize / LOAD_FACTOR) + 1;
|
||||
cacheMap = new LinkedHashMap<Object, CacheEntry>(buckets,
|
||||
LOAD_FACTOR, true);
|
||||
cacheMap = new LinkedHashMap<>(buckets, LOAD_FACTOR, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -279,16 +286,17 @@ class MemoryCache extends Cache {
|
||||
}
|
||||
int startSize = cacheMap.size();
|
||||
while (true) {
|
||||
CacheEntry entry = (CacheEntry)queue.poll();
|
||||
@SuppressWarnings("unchecked")
|
||||
CacheEntry<K,V> entry = (CacheEntry<K,V>)queue.poll();
|
||||
if (entry == null) {
|
||||
break;
|
||||
}
|
||||
Object key = entry.getKey();
|
||||
K key = entry.getKey();
|
||||
if (key == null) {
|
||||
// key is null, entry has already been removed
|
||||
continue;
|
||||
}
|
||||
CacheEntry currentEntry = cacheMap.remove(key);
|
||||
CacheEntry<K,V> currentEntry = cacheMap.remove(key);
|
||||
// check if the entry in the map corresponds to the expired
|
||||
// entry. If not, readd the entry
|
||||
if ((currentEntry != null) && (entry != currentEntry)) {
|
||||
@ -314,9 +322,9 @@ class MemoryCache extends Cache {
|
||||
}
|
||||
int cnt = 0;
|
||||
long time = System.currentTimeMillis();
|
||||
for (Iterator<CacheEntry> t = cacheMap.values().iterator();
|
||||
for (Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
|
||||
t.hasNext(); ) {
|
||||
CacheEntry entry = t.next();
|
||||
CacheEntry<K,V> entry = t.next();
|
||||
if (entry.isValid(time) == false) {
|
||||
t.remove();
|
||||
cnt++;
|
||||
@ -339,7 +347,7 @@ class MemoryCache extends Cache {
|
||||
if (queue != null) {
|
||||
// if this is a SoftReference cache, first invalidate() all
|
||||
// entries so that GC does not have to enqueue them
|
||||
for (CacheEntry entry : cacheMap.values()) {
|
||||
for (CacheEntry<K,V> entry : cacheMap.values()) {
|
||||
entry.invalidate();
|
||||
}
|
||||
while (queue.poll() != null) {
|
||||
@ -349,12 +357,12 @@ class MemoryCache extends Cache {
|
||||
cacheMap.clear();
|
||||
}
|
||||
|
||||
public synchronized void put(Object key, Object value) {
|
||||
public synchronized void put(K key, V value) {
|
||||
emptyQueue();
|
||||
long expirationTime = (lifetime == 0) ? 0 :
|
||||
System.currentTimeMillis() + lifetime;
|
||||
CacheEntry newEntry = newEntry(key, value, expirationTime, queue);
|
||||
CacheEntry oldEntry = cacheMap.put(key, newEntry);
|
||||
CacheEntry<K,V> newEntry = newEntry(key, value, expirationTime, queue);
|
||||
CacheEntry<K,V> oldEntry = cacheMap.put(key, newEntry);
|
||||
if (oldEntry != null) {
|
||||
oldEntry.invalidate();
|
||||
return;
|
||||
@ -362,8 +370,8 @@ class MemoryCache extends Cache {
|
||||
if (maxSize > 0 && cacheMap.size() > maxSize) {
|
||||
expungeExpiredEntries();
|
||||
if (cacheMap.size() > maxSize) { // still too large?
|
||||
Iterator<CacheEntry> t = cacheMap.values().iterator();
|
||||
CacheEntry lruEntry = t.next();
|
||||
Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
|
||||
CacheEntry<K,V> lruEntry = t.next();
|
||||
if (DEBUG) {
|
||||
System.out.println("** Overflow removal "
|
||||
+ lruEntry.getKey() + " | " + lruEntry.getValue());
|
||||
@ -374,9 +382,9 @@ class MemoryCache extends Cache {
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized Object get(Object key) {
|
||||
public synchronized V get(Object key) {
|
||||
emptyQueue();
|
||||
CacheEntry entry = cacheMap.get(key);
|
||||
CacheEntry<K,V> entry = cacheMap.get(key);
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
@ -393,7 +401,7 @@ class MemoryCache extends Cache {
|
||||
|
||||
public synchronized void remove(Object key) {
|
||||
emptyQueue();
|
||||
CacheEntry entry = cacheMap.remove(key);
|
||||
CacheEntry<K,V> entry = cacheMap.remove(key);
|
||||
if (entry != null) {
|
||||
entry.invalidate();
|
||||
}
|
||||
@ -402,9 +410,9 @@ class MemoryCache extends Cache {
|
||||
public synchronized void setCapacity(int size) {
|
||||
expungeExpiredEntries();
|
||||
if (size > 0 && cacheMap.size() > size) {
|
||||
Iterator<CacheEntry> t = cacheMap.values().iterator();
|
||||
Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
|
||||
for (int i = cacheMap.size() - size; i > 0; i--) {
|
||||
CacheEntry lruEntry = t.next();
|
||||
CacheEntry<K,V> lruEntry = t.next();
|
||||
if (DEBUG) {
|
||||
System.out.println("** capacity reset removal "
|
||||
+ lruEntry.getKey() + " | " + lruEntry.getValue());
|
||||
@ -431,60 +439,61 @@ class MemoryCache extends Cache {
|
||||
}
|
||||
|
||||
// it is a heavyweight method.
|
||||
public synchronized void accept(CacheVisitor visitor) {
|
||||
public synchronized void accept(CacheVisitor<K,V> visitor) {
|
||||
expungeExpiredEntries();
|
||||
Map<Object, Object> cached = getCachedEntries();
|
||||
Map<K,V> cached = getCachedEntries();
|
||||
|
||||
visitor.visit(cached);
|
||||
}
|
||||
|
||||
private Map<Object, Object> getCachedEntries() {
|
||||
Map<Object,Object> kvmap = new HashMap<Object,Object>(cacheMap.size());
|
||||
private Map<K,V> getCachedEntries() {
|
||||
Map<K,V> kvmap = new HashMap<>(cacheMap.size());
|
||||
|
||||
for (CacheEntry entry : cacheMap.values()) {
|
||||
for (CacheEntry<K,V> entry : cacheMap.values()) {
|
||||
kvmap.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
return kvmap;
|
||||
}
|
||||
|
||||
protected CacheEntry newEntry(Object key, Object value,
|
||||
long expirationTime, ReferenceQueue<Object> queue) {
|
||||
protected CacheEntry<K,V> newEntry(K key, V value,
|
||||
long expirationTime, ReferenceQueue<V> queue) {
|
||||
if (queue != null) {
|
||||
return new SoftCacheEntry(key, value, expirationTime, queue);
|
||||
return new SoftCacheEntry<>(key, value, expirationTime, queue);
|
||||
} else {
|
||||
return new HardCacheEntry(key, value, expirationTime);
|
||||
return new HardCacheEntry<>(key, value, expirationTime);
|
||||
}
|
||||
}
|
||||
|
||||
private static interface CacheEntry {
|
||||
private static interface CacheEntry<K,V> {
|
||||
|
||||
boolean isValid(long currentTime);
|
||||
|
||||
void invalidate();
|
||||
|
||||
Object getKey();
|
||||
K getKey();
|
||||
|
||||
Object getValue();
|
||||
V getValue();
|
||||
|
||||
}
|
||||
|
||||
private static class HardCacheEntry implements CacheEntry {
|
||||
private static class HardCacheEntry<K,V> implements CacheEntry<K,V> {
|
||||
|
||||
private Object key, value;
|
||||
private K key;
|
||||
private V value;
|
||||
private long expirationTime;
|
||||
|
||||
HardCacheEntry(Object key, Object value, long expirationTime) {
|
||||
HardCacheEntry(K key, V value, long expirationTime) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.expirationTime = expirationTime;
|
||||
}
|
||||
|
||||
public Object getKey() {
|
||||
public K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -503,24 +512,25 @@ class MemoryCache extends Cache {
|
||||
}
|
||||
}
|
||||
|
||||
private static class SoftCacheEntry
|
||||
extends SoftReference<Object> implements CacheEntry {
|
||||
private static class SoftCacheEntry<K,V>
|
||||
extends SoftReference<V>
|
||||
implements CacheEntry<K,V> {
|
||||
|
||||
private Object key;
|
||||
private K key;
|
||||
private long expirationTime;
|
||||
|
||||
SoftCacheEntry(Object key, Object value, long expirationTime,
|
||||
ReferenceQueue<Object> queue) {
|
||||
SoftCacheEntry(K key, V value, long expirationTime,
|
||||
ReferenceQueue<V> queue) {
|
||||
super(value, queue);
|
||||
this.key = key;
|
||||
this.expirationTime = expirationTime;
|
||||
}
|
||||
|
||||
public Object getKey() {
|
||||
public K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
public V getValue() {
|
||||
return get();
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user