001 
002 /*
003  *  JScripter Standard 1.0 - To Script In Java
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.jscripter.org>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package jsx.http.rpc.server;
021 
022 import java.util.Collection;
023 import java.util.Date;
024 import java.util.HashMap;
025 import java.util.IdentityHashMap;
026 import java.util.Map;
027 import java.util.Timer;
028 import java.util.TimerTask;
029 
030 class IdentityMap extends HashMap<String, Object>
031 {
032     private static final long serialVersionUID = 1L;
033 
034     private final IdentityHashMap<Object, String> idMap =
035               new IdentityHashMap<Object, String>();
036 
037     private final Map<String, Long> refMap = new HashMap<String, Long>();
038     private final Map<String, Long> useMap = new HashMap<String, Long>();
039     private final Timer timer = new Timer();
040 
041     public IdentityMap() {
042         super();
043         final long ttl = 30000L;
044         timer.schedule(new TimerTask() {
045             @Override
046             public void run() {
047                 purge(ttl);
048             }
049         }, ttl, ttl);
050     }
051 
052     protected synchronized void purge(long ttl) {
053         long now = new Date().getTime();
054         Object[] keys = keySet().toArray();
055         for (Object k : keys) {
056             String key = (String)k;
057             if (ref(key) < 1L) {
058                 if (now - usage(key) > ttl) {
059                     remove(key);
060                 }
061             }
062         }
063     }
064 
065     protected synchronized long usage(String key) {
066         if (key == null) return 0L;
067         Long r = useMap.get(key);
068         return r == null ? 0L : r.longValue();
069     }
070 
071     protected synchronized String use(String key) {
072         if (key == null) return key;
073         useMap.put(key, new Date().getTime());
074         return key;
075     }
076 
077     public String getString(String key) {
078         Object o = get(key);
079         return o == null ? "NULL" : o.toString();
080     }
081 
082     protected synchronized long idle(String key) {
083         return new Date().getTime() - usage(key);
084     }
085 
086     public synchronized long ref(String key) {
087         Long r = refMap.get(key);
088         return r == null ? 0L : r.longValue();
089     }
090 
091     public synchronized void increase(String key) {
092         if (key != null) {
093             refMap.put(use(key), ref(key) + 1L);
094         }
095     }
096 
097     public synchronized void decrease(String key) {
098         if (key != null) {
099             refMap.put(use(key), ref(key) - 1L);
100         }
101     }
102 
103     @Override
104     public synchronized void clear() {
105         super.clear();
106         idMap.clear();
107         refMap.clear();
108         useMap.clear();
109     }
110 
111     @Override
112     public synchronized boolean containsValue(Object value) {
113         return idMap.containsKey(value);
114     }
115 
116     public synchronized String getKey(Object value) {
117         return use(idMap.get(value));
118     }
119 
120     @Override
121     public synchronized Object put(String key, Object value) {
122         Object prev = super.put(use(key), value);
123         if (prev != value) {
124             idMap.put(value, key);
125         }
126         return prev;
127     }
128 
129     @Override
130     public synchronized Object remove(Object key) {
131         Object value = super.remove(key);
132         idMap.remove(value);
133         refMap.remove(key);
134         useMap.remove(key);
135         return value;
136     }
137 
138     public synchronized String removeValue(Object value) {
139         String key = idMap.remove(value);
140         super.remove(key);
141         refMap.remove(key);
142         useMap.remove(key);
143         return key;
144     }
145 
146     @Override
147     public synchronized Collection<Object> values() {
148         return idMap.keySet();
149     }
150 }