📄 synchronouscache.java
字号:
/*------------------------------------------------------------------------------Name: BlasterCache.javaProject: xmlBlaster.orgCopyright: xmlBlaster.org, see xmlBlaster-LICENSE file------------------------------------------------------------------------------*/package org.xmlBlaster.client;import org.xmlBlaster.util.Global;import org.xmlBlaster.util.XmlBlasterException;import org.xmlBlaster.util.MsgUnit;import org.xmlBlaster.util.def.Constants;import org.xmlBlaster.client.key.UpdateKey;import org.xmlBlaster.client.qos.UpdateQos;import org.xmlBlaster.client.key.GetKey;import org.xmlBlaster.client.qos.GetQos;import java.util.*;/** * Caches the messages updated from xmlBlaster. * <p /> * It is used to allow local (client side) cached messages * which you can access with the <strong>synchronous</strong> * getCached() method. * <p /> * If XmlBlasterAccess has switched this cache on, * a getCached() automatically makes a subscribe() behind the scenes as well * and subsequent getCached() are high performing local calls. * @author konrad.krafft@doubleslash.de * @author xmlblaster@marcelruff.info * @see org.xmlBlaster.client.XmlBlasterAccess#getCached(GetKey, GetQos) * @see org.xmlBlaster.test.client.TestSynchronousCache * @see <a href="http://www.xmlBlaster.org/xmlBlaster/doc/requirements/client.cache.html">client.cache requirement</a> */public final class SynchronousCache{ private static final String ME = "SynchronousCache"; private final Global glob; /** key==getQueryString(GetKey getKey), value=subscriptionId */ private Hashtable query2SubId = null; /** * key==subscriptionId, value=dataHashtable<br /> * And dataHashtable key=keyOid, value=MsgUnit */ private Hashtable subscriptions = null; private int maxQueriesCached = 0; /** * Create a cache instance. */ public SynchronousCache(Global glob, int maxQueriesCached) { this.glob = glob; this.query2SubId = new Hashtable(); this.subscriptions = new Hashtable(); this.maxQueriesCached = maxQueriesCached; } /** * Remove a cache entry with the given subscriptionId. * <p> * This is usually called by the update() ERASE event * </p> */ public void removeEntry(String subId) { Hashtable dataHashtable = (Hashtable)this.subscriptions.remove(subId); if (dataHashtable == null) { System.err.println("Expected to remove subId=" + subId + " " + toXml("")); return; } synchronized (dataHashtable) { dataHashtable.clear(); } String query = getQueryString(subId); if (query != null) { this.query2SubId.remove(query); } else { System.err.println("Expected to remove subId=" + subId + " from query2SubId: " + toXml("")); } } /** * Remove a MsgUnit from cache with the given query key string and keyOid. * <p> * This is usually called by the update() ERASE event for XPATH queries, * when the last oid disappears the cache entry is removed * </p> */ public void removeEntryByQueryString(String query, String keyOid) { String subId = (String)this.query2SubId.get(query); if (subId != null) { Hashtable dataHashtable = (Hashtable)this.subscriptions.get(subId); if (dataHashtable != null) { synchronized (dataHashtable) { dataHashtable.remove(keyOid); if (dataHashtable.size() < 1) { this.subscriptions.remove(subId); this.query2SubId.remove(query); } } } } } /** * Remove a cache entry with the given query key string. * <p> * This is usually called by the update() ERASE event for EXACT queries. * </p> */ public void removeEntryByQueryString(String query) { String subId = (String)this.query2SubId.remove(query); if (subId != null) { Hashtable dataHashtable = (Hashtable)this.subscriptions.remove(subId); if (dataHashtable != null) { synchronized (dataHashtable) { dataHashtable.clear(); } } } } /** * Access the query key for a given subscriptionId. * * Slow linear lookup ... * @return null if not found */ private String getQueryString(String subscriptionId) { Enumeration queryEnum = this.query2SubId.keys(); while (queryEnum.hasMoreElements()) { String query = (String)queryEnum.nextElement(); String tmpSubscriptionId = (String)this.query2SubId.get(query); if (tmpSubscriptionId.equals(subscriptionId)) { return query; } } return null; } /** * Updated the cache (add a new entry or replaces an existing or removes one). * @return true if message was for cache, false if we are not interested in such a message. */ public boolean update(String subId, UpdateKey updateKey, byte[] content, UpdateQos updateQos) throws XmlBlasterException { Object obj = this.subscriptions.get(subId); if(obj == null) { return false; } if (updateQos.isErased()) { String query = getQueryString(subId); if (query != null) { if (query.startsWith(Constants.EXACT)) { removeEntryByQueryString(query); return true; } else { removeEntryByQueryString(query, updateKey.getOid()); return true; } } else return true; } Hashtable dataHashtable = (Hashtable)obj; synchronized (dataHashtable) { dataHashtable.put(updateKey.getOid(), new MsgUnit(updateKey.getData(), content, updateQos.getData())); } return true; } /** * Access messages from cache * @return null if no messages are found in cache */ public MsgUnit[] get(GetKey getKey, GetQos getQos) throws XmlBlasterException { MsgUnit[] messageUnits = null; //Look into cache if xmlKey is already there String subId = (String)this.query2SubId.get(getQueryString(getKey)); //if yes, return the content of the cache entry if(subId != null) { Hashtable dataHashtable = (Hashtable)this.subscriptions.get(subId); if (dataHashtable != null) { synchronized (dataHashtable) { messageUnits = new MsgUnit[dataHashtable.size()]; int i = 0; Enumeration values = dataHashtable.elements(); while (values.hasMoreElements()) { messageUnits[i] = (MsgUnit)values.nextElement(); i++; } } } } return messageUnits; } /** * Create a unique key for our Hashtable from a GetKey */ public String getQueryString(GetKey getKey) { if (getKey.getData().isExact()) { return Constants.EXACT+getKey.getOid(); } else { return getKey.getData().getQueryType()+getKey.getData().getQueryString().trim(); } } /** * Creates an new entry in the cache * <p /> * @return true - entry has been created * false- cache is full */ public boolean newEntry(String subId, GetKey getKey, MsgUnit[] units) throws XmlBlasterException { String query = getQueryString(getKey); if (this.query2SubId.get(query) != null) return true; // Existed already if(this.query2SubId.size() < this.maxQueriesCached) { this.query2SubId.put(query, subId); Hashtable dataHashtable = new Hashtable(); for( int i = 0; i < units.length; i++ ) dataHashtable.put(units[i].getKeyOid(), units[i]); this.subscriptions.put(subId, dataHashtable); return true; } else return false; } /** * Destroy all entries in the cash */ public synchronized void clear() { this.query2SubId.clear(); this.subscriptions.clear(); } /** * Return how full is this cache. */ public int getNumQueriesCached() { return this.subscriptions.size(); } /** * Return the registered subscriptions, for internal use only (to check cache). * @return key==getQueryString(GetKey getKey), value=subscriptionId */ public Hashtable getSubscriptions() { return this.subscriptions; } /** * Dump state of this object into a XML ASCII string. * <br> * @param extraOffset indenting of tags for nice output * @return internal state of SynchronousCache as a XML ASCII string */ public final String toXml(String extraOffset) { StringBuffer sb = new StringBuffer(1024); if (extraOffset == null) extraOffset = ""; String offset = Constants.OFFSET + extraOffset; sb.append(offset).append("<SynchronousCache maxQueriesCached='").append(this.maxQueriesCached).append("'>"); Enumeration subIdEnum = this.subscriptions.keys(); while (subIdEnum.hasMoreElements()) { String subscriptionId = (String)subIdEnum.nextElement(); Hashtable hash = (Hashtable)this.subscriptions.get(subscriptionId); sb.append(offset).append(" <subscribe id='").append(subscriptionId).append("'/>"); } Enumeration queryEnum = this.query2SubId.keys(); while (queryEnum.hasMoreElements()) { String query = (String)queryEnum.nextElement(); String subscriptionId = (String)this.query2SubId.get(query); sb.append(offset).append(" <query id='").append(query); sb.append("' subscriptionId='").append(subscriptionId).append("'/>"); } sb.append(offset).append("</SynchronousCache>"); return sb.toString(); }} // SynchronousCache
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -