Home | History | Annotate | Download | only in io
      1 /*
      2  * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 /*
     27  */
     28 
     29 package java.io;
     30 
     31 import java.util.Iterator;
     32 import java.util.Map;
     33 import java.util.LinkedHashMap;
     34 import java.util.Set;
     35 
     36 class ExpiringCache {
     37     private long millisUntilExpiration;
     38     private Map<String,Entry> map;
     39     // Clear out old entries every few queries
     40     private int queryCount;
     41     private int queryOverflow = 300;
     42     private int MAX_ENTRIES = 200;
     43 
     44     static class Entry {
     45         private long   timestamp;
     46         private String val;
     47 
     48         Entry(long timestamp, String val) {
     49             this.timestamp = timestamp;
     50             this.val = val;
     51         }
     52 
     53         long   timestamp()                  { return timestamp;           }
     54         void   setTimestamp(long timestamp) { this.timestamp = timestamp; }
     55 
     56         String val()                        { return val;                 }
     57         void   setVal(String val)           { this.val = val;             }
     58     }
     59 
     60     ExpiringCache() {
     61         this(30000);
     62     }
     63 
     64     @SuppressWarnings("serial")
     65     ExpiringCache(long millisUntilExpiration) {
     66         this.millisUntilExpiration = millisUntilExpiration;
     67         map = new LinkedHashMap<String,Entry>() {
     68             @Override
     69             protected boolean removeEldestEntry(Map.Entry eldest) {
     70               return size() > MAX_ENTRIES;
     71             }
     72           };
     73     }
     74 
     75     synchronized String get(String key) {
     76         if (++queryCount >= queryOverflow) {
     77             cleanup();
     78         }
     79         Entry entry = entryFor(key);
     80         if (entry != null) {
     81             return entry.val();
     82         }
     83         return null;
     84     }
     85 
     86     synchronized void put(String key, String val) {
     87         if (++queryCount >= queryOverflow) {
     88             cleanup();
     89         }
     90         Entry entry = entryFor(key);
     91         if (entry != null) {
     92             entry.setTimestamp(System.currentTimeMillis());
     93             entry.setVal(val);
     94         } else {
     95             map.put(key, new Entry(System.currentTimeMillis(), val));
     96         }
     97     }
     98 
     99     synchronized void clear() {
    100         map.clear();
    101     }
    102 
    103     private Entry entryFor(String key) {
    104         Entry entry = map.get(key);
    105         if (entry != null) {
    106             long delta = System.currentTimeMillis() - entry.timestamp();
    107             if (delta < 0 || delta >= millisUntilExpiration) {
    108                 map.remove(key);
    109                 entry = null;
    110             }
    111         }
    112         return entry;
    113     }
    114 
    115     private void cleanup() {
    116         Set<String> keySet = map.keySet();
    117         // Avoid ConcurrentModificationExceptions
    118         String[] keys = new String[keySet.size()];
    119         int i = 0;
    120         for (String key: keySet) {
    121             keys[i++] = key;
    122         }
    123         for (int j = 0; j < keys.length; j++) {
    124             entryFor(keys[j]);
    125         }
    126         queryCount = 0;
    127     }
    128 }
    129