##### Coverage Report - org.webmacro.resource.ReloadingCacheManager

Classes in this File | Line Coverage | Branch Coverage | Complexity
ReloadingCacheManager |
65% | 41/63
50% | 16/32
| 1.9523809523809523;1.952
ReloadingCacheManager$1 |
100% | 5/5
N/A | N/A
| 1.9523809523809523;1.952
ReloadingCacheManager$2 |
100% | 4/4
N/A | N/A
| 1.9523809523809523;1.952
ReloadingCacheManager$DirectScmCacheElement |
0% | 0/4
N/A | N/A
| 1.9523809523809523;1.952
ReloadingCacheManager$MyCacheElement |
83% | 5/6
25% | 1/4
| 1.9523809523809523;1.952
ReloadingCacheManager$SoftScmCacheElement |
100% | 4/4
N/A | N/A
| 1.9523809523809523;1.952

1 |  |
     package org.webmacro.resource;
2 |  |
3 |  |
     import java.lang.ref.SoftReference;
4 |  |
     import java.util.concurrent.ConcurrentHashMap;
5 |  |
     import java.util.concurrent.Executors;
6 |  |
     import java.util.concurrent.ScheduledExecutorService;
7 |  |
     import java.util.concurrent.ThreadFactory;
8 |  |
     import java.util.concurrent.TimeUnit;
9 |  |
10 |  |
     import org.slf4j.Logger;
11 |  |
     import org.slf4j.LoggerFactory;
12 |  |
13 |  |
     import org.webmacro.Broker;
14 |  |
     import org.webmacro.InitException;
15 |  |
     import org.webmacro.ResourceException;
16 |  |
     import org.webmacro.util.Settings;
17 |  |
     import org.webmacro.util.SubSettings;
18 |  |
19 |  |
20 |  |
     /**
21 |  |
      * ReloadingCacheManager -- a cache manager which supports reloading and expiration, backed
22 |  |
      * by a ConcurrentHashMap.  Derived from the old SMapCacheManager, but simplified.
23 |  |
      *
24 |  |
      * @author Brian Goetz
25 |  |
      */
26 | 409 |
     public class ReloadingCacheManager implements CacheManager {
27 |  |
28 | 2 |
         static Logger _log =  LoggerFactory.getLogger(ReloadDelayDecorator.class);
29 |  |
30 |  |
         private static final String NAME = "ReloadingCacheManager";
31 |  |
32 | 12 |
         private final ConcurrentHashMap _cache = new ConcurrentHashMap();
33 |  |
         private int _cacheDurationMilliseconds;
34 |  |
         private String _resourceType;
35 | 12 |
         private boolean _reloadOnChange = true, _useSoftReferences = true;
36 | 12 |
         private boolean _delayReloadChecks = false;
37 |  |
         private long _checkForReloadDelay;
38 |  |
39 |  |
         // Used ClockDaemon instead of the original TimeLoop -- more efficient priority-queue based implementation
40 |  |
         // Then renamed in move to java.util.concurrent
41 |  |
         private ScheduledExecutorService _clockDaemon;
42 |  |
43 |  |
44 | 3084 |
         private abstract class MyCacheElement extends CacheElement implements Cloneable
45 |  |
         {
46 |  |
47 | 544 |
             private CacheReloadContext reloadContext = null;
48 |  |
49 |  |
             public void setReloadContext (CacheReloadContext rc)
50 |  |
             {
51 | 224 |
                 if (_delayReloadChecks && rc != null)
52 | 0 |
                     this.reloadContext = new TimedReloadContext(rc, _checkForReloadDelay);
53 |  |
                 else
54 | 224 |
                     this.reloadContext = rc;
55 | 224 |
             }
56 |  |
57 |  |
             public abstract Object getObject ();
58 |  |
59 |  |
             public abstract void setObject (Object o);
60 |  |
         }
61 |  |
62 | 1088 |
         private final class SoftScmCacheElement extends MyCacheElement
63 |  |
         {
64 |  |
65 |  |
             private SoftReference reference;
66 |  |
67 |  |
             public Object getObject ()
68 |  |
             {
69 | 998 |
                 return reference.get();
70 |  |
             }
71 |  |
72 |  |
             public void setObject (Object o)
73 |  |
             {
74 | 224 |
                 reference = new SoftReference(o);
75 | 224 |
             }
76 |  |
         }
77 |  |
78 | 0 |
         private final class DirectScmCacheElement extends MyCacheElement
79 |  |
         {
80 |  |
81 |  |
             private Object object;
82 |  |
83 |  |
             public Object getObject ()
84 |  |
             {
85 | 0 |
                 return object;
86 |  |
             }
87 |  |
88 |  |
             public void setObject (Object o)
89 |  |
             {
90 | 0 |
                 object = o;
91 | 0 |
             }
92 |  |
         }
93 |  |
94 |  |
         public ReloadingCacheManager()
95 | 12 |
         {
96 | 12 |
         }
97 |  |
98 |  |
         public void init (Broker b, Settings config, String resourceType)
99 |  |
                 throws InitException
100 |  |
         {
101 |  |
             Settings ourSettings, defaultSettings;
102 |  |
103 | 12 |
             _clockDaemon = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
104 |  |
                 public Thread newThread(Runnable runnable) {
105 | 6 |
                     _log.info("Creating new ClockDaemon thread");
106 | 6 |
                     Thread t = new Thread(runnable);
107 | 6 |
                     t.setDaemon(true);
108 | 6 |
                     return t;
109 |  |
                 }
110 |  |
             });
111 |  |
112 | 12 |
             _resourceType = resourceType;
113 |  |
114 | 12 |
             ourSettings = new SubSettings(config, NAME + "." + _resourceType);
115 | 12 |
             defaultSettings = new SubSettings(config, NAME + ".*");
116 |  |
117 | 12 |
             _cacheDurationMilliseconds =
118 |  |
                     ourSettings.getIntegerSetting("ExpireTime",
119 |  |
                             defaultSettings.getIntegerSetting("ExpireTime",
120 |  |
                                     config.getIntegerSetting("TemplateExpireTime", 0)));
121 | 12 |
             _useSoftReferences =
122 |  |
                     (ourSettings.containsKey("UseSoftReferences"))
123 |  |
                     ? ourSettings.getBooleanSetting("UseSoftReferences")
124 |  |
                     : ((defaultSettings.containsKey("UseSoftReferences"))
125 |  |
                     ? defaultSettings.getBooleanSetting("UseSoftReferences") : true);
126 | 12 |
             _reloadOnChange =
127 |  |
                     (ourSettings.containsKey("ReloadOnChange"))
128 |  |
                     ? ourSettings.getBooleanSetting("ReloadOnChange")
129 |  |
                     : ((defaultSettings.containsKey("ReloadOnChange"))
130 |  |
                     ? defaultSettings.getBooleanSetting("ReloadOnChange") : true);
131 |  |
132 | 12 |
             _checkForReloadDelay =
133 |  |
                     (ourSettings.getIntegerSetting("CheckForReloadDelay",
134 |  |
                             defaultSettings.getIntegerSetting("CheckForReloadDelay", -1)));
135 | 12 |
             _delayReloadChecks = _checkForReloadDelay > 0;
136 |  |
137 | 12 |
             _log.info(NAME + "." + _resourceType + ": "
138 |  |
                     + "; expireTime=" + _cacheDurationMilliseconds
139 |  |
                     + "; reload=" + _reloadOnChange
140 |  |
                     + "; softReference=" + _useSoftReferences
141 |  |
                     + "; checkForReloadDelay=" + _checkForReloadDelay);
142 | 12 |
         }
143 |  |
144 |  |
         private MyCacheElement newCacheElement() {
145 | 544 |
             if (_useSoftReferences)
146 | 544 |
                 return new SoftScmCacheElement();
147 |  |
             else
148 | 0 |
                 return new DirectScmCacheElement();
149 |  |
         }
150 |  |
151 |  |
         /**
152 |  |
          * Clear the cache.
153 |  |
          */
154 |  |
         public void flush ()
155 |  |
         {
156 | 0 |
             _cache.clear();
157 | 0 |
         }
158 |  |
159 |  |
         /**
160 |  |
          * Close down the provider.
161 |  |
          */
162 |  |
         public void destroy ()
163 |  |
         {
164 | 0 |
             _cache.clear();
165 | 0 |
             _clockDaemon.shutdown();
166 | 0 |
         }
167 |  |
168 |  |
         public boolean supportsReload ()
169 |  |
         {
170 | 12 |
             return _reloadOnChange;
171 |  |
         }
172 |  |
173 |  |
         private final void scheduleRemoval(final Object key) {
174 | 224 |
             _clockDaemon.schedule(
175 |  |
                     new Runnable()
176 | 224 |
                     {
177 |  |
                         public void run ()
178 |  |
                         {
179 | 185 |
                             _cache.remove(key);
180 | 185 |
                             _log.debug("cache expired: " + key);
181 | 185 |
                         }
182 |  |
                     },
183 |  |
                     _cacheDurationMilliseconds,
184 |  |
                     TimeUnit.MILLISECONDS);
185 | 224 |
         }
186 |  |
187 |  |
         /**
188 |  |
          * Get the object associated with the specific query, first
189 |  |
          * trying to look it up in a cache. If it's not there, then
190 |  |
          * call load(String) to load it into the cache.
191 |  |
          */
192 |  |
         public Object get (final Object query, ResourceLoader helper)
193 |  |
                 throws ResourceException
194 |  |
         {
195 |  |
             MyCacheElement r;
196 | 1542 |
             Object o = null;
197 | 1542 |
             boolean reload = false;
198 |  |
199 | 1542 |
             r = (MyCacheElement) _cache.get(query);
200 | 1542 |
             if (r != null) {
201 | 998 |
                 o = r.getObject();
202 |  |
203 |  |
                 // should the template be reloaded, regardless of cached status?
204 | 998 |
                 if (o != null && r.reloadContext != null && _reloadOnChange)
205 | 998 |
                     reload = r.reloadContext.shouldReload();
206 |  |
             }
207 | 1542 |
             if (o == null || reload)
208 |  |
             {
209 | 544 |
                 r = newCacheElement();
210 | 544 |
                 o = helper.load(query, r);
211 | 224 |
                 if (o != null)
212 |  |
                 {
213 | 224 |
                     r.setObject(o);
214 | 224 |
                     _cache.put(query, r);
215 | 224 |
                     _log.debug("cached: " + query + " for " + _cacheDurationMilliseconds);
216 |  |
                     try
217 |  |
                     {
218 |  |
                         // if timeout is < 0,
219 |  |
                         // then don't schedule a removal from cache
220 | 224 |
                         if (_cacheDurationMilliseconds >= 0)
221 | 224 |
                             scheduleRemoval(query);
222 |  |
                     }
223 | 0 |
                     catch (Exception e)
224 |  |
                     {
225 | 0 |
                         _log.error("CachingProvider caught an exception", e);
226 | 224 |
                     }
227 |  |
                 }
228 |  |
             }
229 | 1222 |
             return o;
230 |  |
         }
231 |  |
232 |  |
         /**
233 |  |
          * Get the object associated with the specific query,
234 |  |
          * trying to look it up in a cache. If it's not there, return null.
235 |  |
          */
236 |  |
         public Object get (final Object query)
237 |  |
         {
238 | 0 |
             MyCacheElement r = (MyCacheElement) _cache.get(query);
239 | 0 |
             if (r != null)
240 | 0 |
                 return r.getObject();
241 |  |
             else
242 | 0 |
                 return null;
243 |  |
         }
244 |  |
245 |  |
         /**
246 |  |
          * Put an object in the cache
247 |  |
          */
248 |  |
         public void put (final Object query, Object resource)
249 |  |
         {
250 | 0 |
             MyCacheElement r = newCacheElement();
251 | 0 |
             r.setObject(resource);
252 |  |
253 | 0 |
             _cache.put(query, r);
254 | 0 |
             if (_cacheDurationMilliseconds >= 0)
255 |  |
             {
256 | 0 |
                 _log.debug("cached: " + query + " for " + _cacheDurationMilliseconds);
257 | 0 |
                 scheduleRemoval(query);
258 |  |
             }
259 | 0 |
         }
260 |  |
261 |  |
         /** Removes a specific entry from the cache. */
262 |  |
         public void invalidate (final Object query)
263 |  |
         {
264 | 0 |
             _cache.remove(query);
265 | 0 |
         }
266 |  |
267 |  |
         public String toString ()
268 |  |
         {
269 | 0 |
             return NAME + "(type = " + _resourceType + ")";
270 |  |
         }
271 |  |
     }