001    /*
002     * Copyright 2001-2004 The Apache Software Foundation
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.apache.commons.cache;
017    
018    import java.io.ByteArrayOutputStream;
019    import java.io.FileOutputStream;
020    import java.io.FileInputStream;
021    import java.io.ObjectOutputStream;
022    import java.io.ObjectInputStream;
023    import java.io.BufferedOutputStream;
024    import java.io.BufferedInputStream;
025    import java.io.Serializable;
026    import java.io.IOException;
027    import java.io.File;
028    
029    /**
030     * tk.
031     * @version $Id: SimpleCache.java 155435 2005-02-26 13:17:27Z dirkv $
032     * @author Rodney Waldhoff
033     */
034    public class SimpleCache extends BaseCache implements Cache {
035      protected GroupMap _gm = null;
036      protected EvictionPolicy _ep = null;
037      protected StashPolicy _sp = null;
038      protected Stash _stash = null;
039      protected boolean _wantsSerialized = false;
040      protected File _persistFile = null;
041    
042      protected long _numRetrieveRequested = 0;
043      protected long _numRetrieveFound = 0;
044      protected long _numStoreRequested = 0;
045      protected long _numStoreStored = 0;
046      protected long _numCleared = 0;
047    
048      public SimpleCache(Stash stash) {
049        this(stash,null,null,null);
050      }
051    
052      public SimpleCache(Stash stash, EvictionPolicy ep) {
053        this(stash,ep,null,null);
054      }
055    
056      public SimpleCache(Stash stash, EvictionPolicy ep, StashPolicy sp) {
057        this(stash,ep,sp,null,null);
058      }
059    
060      public SimpleCache(Stash stash, EvictionPolicy ep, StashPolicy sp, GroupMap tm) {
061        this(stash,ep,sp,tm,null);
062      }
063    
064      public SimpleCache(Stash stash, EvictionPolicy ep, StashPolicy sp, GroupMap tm, File persistFile) {
065        _gm = tm;
066        if(null != _gm) { tm.setCache(this); }
067        _stash = stash;
068        _stash.setCache(this); // stash cannot be null
069        _ep = ep;
070        if(null != _ep) { _ep.setCache(this); }
071        _sp = sp;
072        if(null != _sp) { _sp.setCache(this); }
073        _wantsSerialized = _stash.wantsSerializedForm() || ((null == _sp) ? false : _sp.wantsSerializedForm());
074        _persistFile = persistFile;
075      }
076    
077      public synchronized long getStat(CacheStat stat) throws UnsupportedOperationException {
078        if(stat.equals(CacheStat.CUR_CAPACITY)) {
079          try {
080            return (long)(1000F * _stash.capacity());
081          } catch(Exception e) {
082            throw new UnsupportedOperationException();
083          }
084        } else if(stat.equals(CacheStat.NUM_CLEARED)) {
085          throw new UnsupportedOperationException();
086        } else if(stat.equals(CacheStat.NUM_RETRIEVE_FOUND)) {
087          return _numRetrieveFound;
088        } else if(stat.equals(CacheStat.NUM_RETRIEVE_NOT_FOUND)) {
089          return (_numRetrieveRequested - _numRetrieveFound);
090        } else if(stat.equals(CacheStat.NUM_RETRIEVE_REQUESTED)) {
091          return _numRetrieveRequested;
092        } else if(stat.equals(CacheStat.NUM_STORE_NOT_STORED)) {
093          return (_numStoreRequested - _numStoreStored);
094        } else if(stat.equals(CacheStat.NUM_STORE_REQUESTED)) {
095          return _numStoreRequested;
096        } else if(stat.equals(CacheStat.NUM_STORE_STORED)) {
097          return _numStoreStored;
098        } else {
099          throw new UnsupportedOperationException("CacheStat \"" + stat.toString() + "\" not recoginzed.");
100        }
101      }
102    
103      public static SimpleCache readFromFile(String f) throws IOException, ClassNotFoundException {
104        return SimpleCache.readFromFile(new File(f));
105      }
106    
107      public static SimpleCache readFromFile(File f) throws IOException, ClassNotFoundException {
108        ObjectInputStream in = null;
109        try {
110          in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(f)));
111          return (SimpleCache)(in.readObject());
112        } catch(ClassNotFoundException e) {
113          e.fillInStackTrace();
114          throw e;
115        } catch(IOException e) {
116          e.fillInStackTrace();
117          throw e;
118        } finally {
119          try { in.close(); } catch(Exception e) { }
120        }
121      }
122    
123      protected synchronized void writeToFile() {
124        if(null == _persistFile) {
125          return;
126        } else {
127          ObjectOutputStream out = null;
128          try {
129            out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(_persistFile)));
130            out.writeObject(this);
131            out.flush();
132          } catch(Exception e) {
133            e.printStackTrace();
134          } finally {
135            try { out.close(); } catch(Exception e) { }
136          }
137        }
138      }
139    
140      public Serializable[] getKeysForGroup(Serializable group) {
141        if(null == _gm) {
142          throw new IllegalStateException("no group map right now");
143        } else {
144          return _gm.getKeysForGroup(group);
145        }
146      }
147    
148      public synchronized boolean store(Serializable key, Serializable val, Long expiry, Long cost, Serializable group) {
149        if(contains(key)) {
150          clear(key);
151        }
152        _numStoreRequested++;
153        if(null != expiry) {
154          if(expiry.longValue() <= System.currentTimeMillis()) {
155            return false;
156          }
157        }
158    
159        broadcastStoreRequested(key,val,expiry,cost,group);
160        byte[] serform = null;
161        if(_wantsSerialized) {
162          ByteArrayOutputStream byout = null;
163          ObjectOutputStream out = null;
164          try {
165            byout = new ByteArrayOutputStream();
166            out = new ObjectOutputStream(byout);
167            out.writeObject(val);
168            out.flush();
169            serform = byout.toByteArray();
170          } catch(IOException e) {
171            serform = null;
172          } finally {
173            try { byout.close(); } catch(Exception e) { }
174            try { out.close(); } catch(Exception e) { }
175          }
176        }
177        if(_sp == null || _sp.shouldStore(key,val,expiry,cost,serform)) {
178          switch(_stash.canStore(key,val,expiry,cost,group,serform)) {
179            case Stash.YES:
180              _stash.store(key,val,expiry,cost,group,serform);
181              broadcastStored(key,val,expiry,cost,group);
182              _numStoreStored++;
183              writeToFile();
184              return true;
185            case Stash.NO_FULL:
186              if(tryToEvict()) {
187                return store(key,val,expiry,cost,group);
188              } else {
189                broadcastNotStored(key,val,expiry,cost,group);
190                return false;
191              }
192            case Stash.NO_NOT_STORABLE:
193            case Stash.NO:
194            default:
195              broadcastNotStored(key,val,expiry,cost,group);
196              return false;
197          }
198        } else {
199          broadcastNotStored(key,val,expiry,cost,group);
200          return false;
201        }
202      }
203    
204      public synchronized Serializable retrieve(Serializable key) {
205        _numRetrieveRequested++;
206        broadcastRetrieveRequested(key);
207        Serializable obj = _stash.retrieve(key);
208        if(null == obj) {
209          broadcastNotRetrieved(key);
210          return null;
211        } else {
212          broadcastRetrieved(key);
213          _numRetrieveFound++;
214          return obj;
215        }
216      }
217    
218      public synchronized boolean contains(Serializable key) {
219        return _stash.contains(key);
220      }
221    
222      public synchronized void clear(Serializable key) {
223        _numCleared++;
224        _stash.clear(key);
225        broadcastCleared(key);
226        writeToFile();
227      }
228    
229      public synchronized void clear() {
230        _stash.clear();
231        broadcastCleared();
232        writeToFile();
233      }
234    
235      protected synchronized boolean tryToEvict() {
236        if(null == _ep) {
237          return false;
238        } else {
239          Serializable key = _ep.getEvictionCandidate();
240          if(null == key) {
241            return false;
242          } else {
243            clear(key);
244            return true;
245          }
246        }
247      }
248    
249      public static void main(String[] args) throws Exception {
250        File cfile = null;
251        SimpleCache cache = null;
252        if(args.length > 0) {
253          ObjectInputStream in = null;
254          try {
255            in = new ObjectInputStream(new FileInputStream(new File(args[0])));
256            cache = (SimpleCache)(in.readObject());
257          } catch(Exception e) {
258            cache = null;
259            e.printStackTrace();
260          } finally {
261            try { in.close(); } catch(Exception e) { }
262          }
263        }
264    
265        if(null == cache) {
266          LRUEvictionPolicy ep = new LRUEvictionPolicy();
267          Stash s = new FileStash(10000L);
268          cache = new SimpleCache(s,ep,null,null,new File("persitent.ser"));
269    
270          System.out.println(cache.store("Key1","Value1",null,null));
271          System.out.println(cache.store("Key2","Value2",new Long(System.currentTimeMillis() + 10000),null));
272          System.out.println(cache.store("Key3","Value3",new Long(System.currentTimeMillis() + 9000),null));
273          System.out.println(cache.store("Key4","Value4",new Long(System.currentTimeMillis() + 8000),null));
274          System.out.println(cache.store("Key5","Value5",new Long(System.currentTimeMillis() + 7000),null));
275          System.out.println(cache.store("Key6","Value6",new Long(System.currentTimeMillis() + 6000),null));
276          System.out.println(cache.store("Key7","Value7",new Long(System.currentTimeMillis() + 5000),null));
277          System.out.println(cache.store("Key8","Value8",new Long(System.currentTimeMillis() + 4000),null));
278          System.out.println(cache.store("Key9","Value9",new Long(System.currentTimeMillis() + 3000),null));
279          System.out.println(cache.store("Key10","Value10",new Long(System.currentTimeMillis() + 40000),null));
280          System.out.println(cache.store("Key11","Value11",new Long(System.currentTimeMillis() + 30000),null));
281          System.out.println(cache.store("Key12","Value12",new Long(System.currentTimeMillis() + 20000),null));
282    
283          if(args.length > 0) {
284            ObjectOutputStream out = null;
285            try {
286              out = new ObjectOutputStream(new FileOutputStream(new File(args[0])));
287              out.writeObject(cache);
288            } catch(Exception e) {
289              e.printStackTrace();
290            } finally {
291              try { out.close(); } catch(Exception e) { }
292            }
293          }
294        }
295    
296        for(int i=0;i<12;i++) {
297          System.out.println("Key1\t" + cache.retrieve("Key1"));
298          System.out.println("Key2\t" + cache.retrieve("Key2"));
299          System.out.println("Key3\t" + cache.retrieve("Key3"));
300          System.out.println("Key4\t" + cache.retrieve("Key4"));
301          System.out.println("Key5\t" + cache.retrieve("Key5"));
302          System.out.println("Key6\t" + cache.retrieve("Key6"));
303          System.out.println("Key7\t" + cache.retrieve("Key7"));
304          System.out.println("Key8\t" + cache.retrieve("Key8"));
305          System.out.println("Key9\t" + cache.retrieve("Key9"));
306          System.out.println("Key10\t" + cache.retrieve("Key10"));
307          System.out.println("Key11\t" + cache.retrieve("Key11"));
308          System.out.println("Key12\t" + cache.retrieve("Key12"));
309    
310          System.out.println();
311          Thread.sleep(1000L);
312        }
313      }
314    }