package com.atom.util; import j2ee.core.utils.TextUtils; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; import com.atom.memcache.CacheOperate; public class AtsHashtable<K, V> extends Hashtable<K, V>{ private String TABLE_FLAG = TextUtils.getUUID(); private Hashtable<K,V> outsideMap; private static List<Class> SINGLE_OBJECT = new ArrayList<Class>(); static{ SINGLE_OBJECT.add(String.class); } { initOutsideMap(); } private void initOutsideMap(){ outsideMap = (Hashtable<K,V>)getFromOutSide(TABLE_FLAG); if(outsideMap==null){ outsideMap = new Hashtable<K,V>(); } } public void initOutsideData(String id){ Hashtable<K,V> outsideData = (Hashtable<K,V>)getFromOutSide(id); if(outsideData!=null){ TABLE_FLAG = id; outsideMap = outsideData; } } @Override public synchronized void clear() { removeFromOutSide(TABLE_FLAG); super.clear(); } @Override public synchronized boolean contains(Object value) { return super.contains(value) || this.outsideMap.contains(value); } @Override public synchronized boolean containsKey(Object key) { return super.containsKey(key) || this.outsideMap.containsKey(key); } @Override public boolean containsValue(Object value) { return super.containsValue(value) || this.outsideMap.containsValue(value); } @Override public synchronized Enumeration elements() { return getUniteTable().elements(); } @Override public Set entrySet() { return getUniteTable().entrySet(); } @Override public synchronized V get(Object key) { V result = super.get(key); result = result==null?outsideMap.get(key):result; return result; } @Override public synchronized boolean isEmpty() { return super.isEmpty() && outsideMap.isEmpty(); } @Override public synchronized Enumeration keys() { return getUniteTable().keys(); } @Override public Set keySet() { return getUniteTable().keySet(); } @Override public synchronized V put(K key, V value) { if(isOutsideObject(value.getClass())){ Object o = super.get(TABLE_FLAG); //判断TABLE_FLAG这个key是否放入过自身 if(o==null){ super.put((K)TABLE_FLAG, (V)outsideMap); } //old memcached好像会直接拷贝对象数据,所以不能像往常session那样操作 // putToOutSide(); // return outsideMap.put(key, value); //new 将outsideMap填充新数据后再更新memcached V rtn = outsideMap.put(key,value); putToOutSide(); return rtn; }else{ return super.put(key, value); } } @Override public synchronized void putAll(Map t) { super.putAll(t); } @Override public synchronized V remove(Object key) { if(this.containsKey(key)){ return super.remove(key); }else{ //这么删好像会出问题,因为memcached上保存的是TABLE_FLAG这个key //不是要删除的对象的key //old // removeFromOutSide(key); // return outsideMap.remove(key); //new V o = outsideMap.remove(key); //如果没有对象放缓存里了,那么清除缓存 if(outsideMap.size()==0){ removeFromOutSide(TABLE_FLAG); }else{ //否则把删除后的outsideMap放到缓存 putToOutSide(); } return o; } } @Override public Collection values() { return getUniteTable().values(); } private void putToOutSide(){ CacheOperate.addByUser(TABLE_FLAG, outsideMap); } private Object getFromOutSide(String key){ return CacheOperate.getByUser(key); } private void removeFromOutSide(Object key){ CacheOperate.deleteByUser(String.valueOf(key)); } private Hashtable<K,V> getUniteTable(){ Hashtable<K,V> _ht = new Hashtable<K, V>(); //old 会出现死循环错误 //_ht.putAll(this); //new 自己手动的模仿putAll放置 Set<Map.Entry<K,V>> entrySet = super.entrySet(); for (Map.Entry<? extends K, ? extends V> e : entrySet) _ht.put(e.getKey(), e.getValue()); _ht.putAll(outsideMap); return _ht; } private boolean isOutsideObject(Object o){ return !SINGLE_OBJECT.contains(o); } public String getTableFlag(){ return this.TABLE_FLAG; } }