View Javadoc

1   /*
2    * Copyright (C) 2004 TiongHiang Lee
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   * Lesser General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this library; if not,  write to the Free Software
16   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17   *
18   * Email: thlee@onemindsoft.org
19   */
20  
21  package org.onemind.commons.java.datastructure;
22  
23  import java.util.*;
24  import java.util.logging.Level;
25  import java.util.logging.Logger;
26  /***
27   * A lookup cache implements simple lookup caching algorithm for looking up things. The derived class simply implement the
28   * produce(Object key) method which is assumed an expensive operation and the results will be cached by the lookup cache
29   * implementation. There's no public method on lookup cache, the developer should provide application specific lookup interface.
30   * @author TiongHiang Lee (thlee@onemindsoft.org)
31   * @version $Id: LookupCache.java,v 1.4 2004/09/30 13:26:26 thlee Exp $ $Name:  $
32   */
33  public abstract class LookupCache
34  {
35  
36      /*** the logger * */
37      private static final Logger _logger = Logger.getLogger(LookupCache.class.getName());
38  
39      /*** the hit cache * */
40      private Map _cache = new HashMap();
41  
42      /*** the negative cache * */
43      private Set _negCache;
44  
45      /*** indicate whether to do negative caching * */
46      private boolean _doNegCache = true;
47  
48      /***
49       * {@inheritDoc}
50       */
51      public LookupCache()
52      {
53          this(true);
54      }
55  
56      /***
57       * {@inheritDoc}
58       * @param doNegCache whether to do negative caching
59       */
60      public LookupCache(boolean doNegCache)
61      {
62          setDoNegativeCache(doNegCache);
63      }
64  
65      /***
66       * The main lookup method. The developer should provide another application specific method that call this method to return what
67       * the application wants
68       * @param key the key
69       * @return the object or null
70       * @todo add synchronization when lookup the same key to avoid double loading
71       */
72      protected final Object lookup(Object key)
73      {
74          if (_doNegCache)
75          {
76              if (_negCache.contains(key))
77              {
78                  if (_logger.isLoggable(Level.FINEST))
79                  {
80                      _logger.finest("Returning negative cache hit");
81                  }
82                  return null;
83              }
84          }
85          Object o = _cache.get(key);
86          if (o == null)
87          {
88              //TODO: synchronization for looking up same key
89              o = produce(key);
90              if (o != null)
91              {
92                  if (_logger.isLoggable(Level.FINEST))
93                  {
94                      _logger.finest("Put hit of " + key + " to cache");
95                  }
96                  _cache.put(key, o);
97              } else
98              {
99                  if (_doNegCache)
100                 {
101                     _logger.finest("Put negative hit of " + key + " to cache");
102                     _negCache.add(key);
103                 }
104             }
105         } else
106         {
107             if (_logger.isLoggable(Level.FINEST))
108             {
109                 _logger.finest("Returning positive cache hit of " + key);
110             }
111         }
112         return o;
113     }
114 
115     /***
116      * Produce the object given the key. This is assumed to be an expensive operation and it will be called by the lookup method.
117      * The result will be cached by the lookup method and negative result also will be cached to if the doNegCache is turned on.
118      * @param key the key
119      * @return the result or null if no result
120      */
121     protected abstract Object produce(Object key);
122 
123     /***
124      * Turn on/off the negative cache
125      * @param b true to turn on the neg cache
126      */
127     protected void setDoNegativeCache(boolean b)
128     {
129         _doNegCache = b;
130         if (b && (_negCache == null))
131         {
132             _negCache = new HashSet();
133         }
134     }
135 
136     /***
137      * Get whether the object is in negative cache
138      * @param o the object
139      * @return true if is in negative cache
140      */
141     protected boolean isInNegCache(Object o)
142     {
143         return _negCache.contains(o);
144     }
145 
146     /***
147      * Test if the key is in cache
148      * @param o the object
149      * @return true if is in cache
150      */
151     protected boolean isInCache(Object o)
152     {
153         return _cache.containsKey(o);
154     }
155 
156     /***
157      * Clear all the negative cache
158      */
159     protected void clearNegCache()
160     {
161         if (_negCache != null)
162         {
163             _negCache.clear();
164         }
165     }
166 }