Improve Entity Capabilities code

Most importantly, rename reload() method of persistent cache to
"DiscoverInfo lookup(String nodeVer)" and lazily load the data from the
persistent cache to the memory cache.
This commit is contained in:
Florian Schmaus 2014-05-25 17:49:17 +02:00
parent 47d9146c76
commit 6dd180e9d3
4 changed files with 67 additions and 57 deletions

View File

@ -62,7 +62,6 @@ import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@ -97,7 +96,7 @@ public class EntityCapsManager extends Manager {
/**
* Map of (node + '#" + hash algorithm) to DiscoverInfo data
*/
protected static Map<String, DiscoverInfo> caps = new Cache<String, DiscoverInfo>(1000, -1);
private static final Cache<String, DiscoverInfo> CAPS_CACHE = new Cache<String, DiscoverInfo>(1000, -1);
/**
* Map of Full JID -&gt; DiscoverInfo/null. In case of c2s connection the
@ -105,7 +104,7 @@ public class EntityCapsManager extends Manager {
* link-local connection the key is formed as user@host (no resource) In
* case of a server or component the key is formed as domain
*/
protected static Map<String, NodeVerHash> jidCaps = new Cache<String, NodeVerHash>(10000, -1);
private static final Cache<String, NodeVerHash> JID_TO_NODEVER_CACHE = new Cache<String, NodeVerHash>(10000, -1);
static {
XMPPConnection.addConnectionCreationListener(new ConnectionCreationListener() {
@ -141,7 +140,7 @@ public class EntityCapsManager extends Manager {
* DiscoverInfo for the specified node.
*/
public static void addDiscoverInfoByNode(String nodeVer, DiscoverInfo info) {
caps.put(nodeVer, info);
CAPS_CACHE.put(nodeVer, info);
if (persistentCache != null)
persistentCache.addDiscoverInfoByNodePersistent(nodeVer, info);
@ -156,7 +155,7 @@ public class EntityCapsManager extends Manager {
* @return the node version (node#ver) or null
*/
public static String getNodeVersionByJid(String jid) {
NodeVerHash nvh = jidCaps.get(jid);
NodeVerHash nvh = JID_TO_NODEVER_CACHE.get(jid);
if (nvh != null) {
return nvh.nodeVer;
} else {
@ -165,7 +164,7 @@ public class EntityCapsManager extends Manager {
}
public static NodeVerHash getNodeVerHashByJid(String jid) {
return jidCaps.get(jid);
return JID_TO_NODEVER_CACHE.get(jid);
}
/**
@ -178,7 +177,7 @@ public class EntityCapsManager extends Manager {
* @return the discovered info
*/
public static DiscoverInfo getDiscoverInfoByUser(String user) {
NodeVerHash nvh = jidCaps.get(user);
NodeVerHash nvh = JID_TO_NODEVER_CACHE.get(user);
if (nvh == null)
return null;
@ -194,7 +193,18 @@ public class EntityCapsManager extends Manager {
* @return The corresponding DiscoverInfo or null if none is known.
*/
public static DiscoverInfo getDiscoveryInfoByNodeVer(String nodeVer) {
DiscoverInfo info = caps.get(nodeVer);
DiscoverInfo info = CAPS_CACHE.get(nodeVer);
// If it was not in CAPS_CACHE, try to retrieve the information from persistentCache
if (info == null) {
info = persistentCache.lookup(nodeVer);
// Promote the information to CAPS_CACHE if one was found
if (info != null) {
CAPS_CACHE.put(nodeVer, info);
}
}
// If we were able to retrieve information from one of the caches, copy it before returning
if (info != null)
info = new DiscoverInfo(info);
@ -205,40 +215,37 @@ public class EntityCapsManager extends Manager {
* Set the persistent cache implementation
*
* @param cache
* @throws IOException
*/
public static void setPersistentCache(EntityCapsPersistentCache cache) throws IOException {
if (persistentCache != null)
throw new IllegalStateException("Entity Caps Persistent Cache was already set");
public static void setPersistentCache(EntityCapsPersistentCache cache) {
persistentCache = cache;
persistentCache.replay();
}
/**
* Sets the maximum Cache size for the JID to nodeVer Cache
*
* @param maxCacheSize
* Sets the maximum cache sizes
*
* @param maxJidToNodeVerSize
* @param maxCapsCacheSize
*/
@SuppressWarnings("rawtypes")
public static void setJidCapsMaxCacheSize(int maxCacheSize) {
((Cache) jidCaps).setMaxCacheSize(maxCacheSize);
public static void setMaxsCacheSizes(int maxJidToNodeVerSize, int maxCapsCacheSize) {
JID_TO_NODEVER_CACHE.setMaxCacheSize(maxJidToNodeVerSize);
CAPS_CACHE.setMaxCacheSize(maxCapsCacheSize);
}
/**
* Sets the maximum Cache size for the nodeVer to DiscoverInfo Cache
*
* @param maxCacheSize
* Clears the memory cache.
*/
@SuppressWarnings("rawtypes")
public static void setCapsMaxCacheSize(int maxCacheSize) {
((Cache) caps).setMaxCacheSize(maxCacheSize);
public static void clearMemoryCache() {
JID_TO_NODEVER_CACHE.clear();
CAPS_CACHE.clear();
}
private ServiceDiscoveryManager sdm;
private final Queue<String> lastLocalCapsVersions = new ConcurrentLinkedQueue<String>();
private final ServiceDiscoveryManager sdm;
private boolean entityCapsEnabled;
private String currentCapsVersion;
private boolean presenceSend = false;
private Queue<String> lastLocalCapsVersions = new ConcurrentLinkedQueue<String>();
/**
* The entity node String used by this EntityCapsManager instance.
@ -286,7 +293,7 @@ public class EntityCapsManager extends Manager {
String node = ext.getNode();
String ver = ext.getVer();
jidCaps.put(from, new NodeVerHash(node, ver, hash));
JID_TO_NODEVER_CACHE.put(from, new NodeVerHash(node, ver, hash));
}
}, PRESENCES_WITH_CAPS);
@ -297,7 +304,7 @@ public class EntityCapsManager extends Manager {
// always remove the JID from the map, even if entityCaps are
// disabled
String from = packet.getFrom();
jidCaps.remove(from);
JID_TO_NODEVER_CACHE.remove(from);
}
}, PRESENCES_WITHOUT_CAPS);
@ -367,7 +374,7 @@ public class EntityCapsManager extends Manager {
* the user (Full JID)
*/
public void removeUserCapsNode(String user) {
jidCaps.remove(user);
JID_TO_NODEVER_CACHE.remove(user);
}
/**
@ -441,9 +448,9 @@ public class EntityCapsManager extends Manager {
}
lastLocalCapsVersions.add(currentCapsVersion);
caps.put(currentCapsVersion, discoverInfo);
CAPS_CACHE.put(currentCapsVersion, discoverInfo);
if (connection != null)
jidCaps.put(connection.getUser(), new NodeVerHash(entityNode, currentCapsVersion, "sha-1"));
JID_TO_NODEVER_CACHE.put(connection.getUser(), new NodeVerHash(entityNode, currentCapsVersion, "sha-1"));
final List<Identity> identities = new LinkedList<Identity>(ServiceDiscoveryManager.getInstanceFor(connection).getIdentities());
sdm.setNodeInformationProvider(entityNode + '#' + currentCapsVersion, new NodeInformationProvider() {

View File

@ -1,6 +1,6 @@
/**
*
* Copyright © 2011-2013 Florian Schmaus
* Copyright © 2011-2014 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,23 +16,21 @@
*/
package org.jivesoftware.smackx.caps.cache;
import java.io.IOException;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
public interface EntityCapsPersistentCache {
/**
* Add an DiscoverInfo to the persistent Cache
*
* @param node
* @param nodeVer
* @param info
*/
void addDiscoverInfoByNodePersistent(String node, DiscoverInfo info);
void addDiscoverInfoByNodePersistent(String nodeVer, DiscoverInfo info);
/**
* Replay the Caches data into EntityCapsManager
* Lookup DiscoverInfo by a Node string
*/
void replay() throws IOException;
DiscoverInfo lookup(String nodeVer);
/**
* Empty the Cache

View File

@ -1,6 +1,6 @@
/**
*
* Copyright © 2011 Florian Schmaus
* Copyright © 2011-2014 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -31,7 +31,6 @@ import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smack.util.Base32Encoder;
import org.jivesoftware.smack.util.StringEncoder;
import org.jivesoftware.smackx.caps.EntityCapsManager;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.disco.provider.DiscoverInfoProvider;
import org.xmlpull.v1.XmlPullParserFactory;
@ -87,9 +86,8 @@ public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache
}
@Override
public void addDiscoverInfoByNodePersistent(String node, DiscoverInfo info) {
String filename = filenameEncoder.encode(node);
File nodeFile = new File(cacheDir, filename);
public void addDiscoverInfoByNodePersistent(String nodeVer, DiscoverInfo info) {
File nodeFile = getFileFor(nodeVer);
try {
if (nodeFile.createNewFile())
writeInfoToFile(nodeFile, info);
@ -99,18 +97,28 @@ public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache
}
@Override
public void replay() throws IOException {
File[] files = cacheDir.listFiles();
for (File f : files) {
String node = filenameEncoder.decode(f.getName());
DiscoverInfo info = restoreInfoFromFile(f);
if (info == null)
continue;
EntityCapsManager.addDiscoverInfoByNode(node, info);
public DiscoverInfo lookup(String nodeVer) {
File nodeFile = getFileFor(nodeVer);
if (!nodeFile.isFile()) {
return null;
}
DiscoverInfo info = null;
try {
info = restoreInfoFromFile(nodeFile);
}
catch (IOException e) {
LOGGER.log(Level.WARNING, "Coud not restore info from file", e);
}
return info;
}
private File getFileFor(String nodeVer) {
String filename = filenameEncoder.encode(nodeVer);
File nodeFile = new File(cacheDir, filename);
return nodeFile;
}
@Override
public void emptyCache() {
File[] files = cacheDir.listFiles();
for (File f : files) {

View File

@ -94,10 +94,7 @@ public class EntityCapsManagerTest {
EntityCapsManager.addDiscoverInfoByNode(nodeVer, di);
// Lose all the data
EntityCapsManager.caps.clear();
// Restore the data from the persistent Cache
cache.replay();
EntityCapsManager.clearMemoryCache();
DiscoverInfo restored_di = EntityCapsManager.getDiscoveryInfoByNodeVer(nodeVer);
assertNotNull(restored_di);