View Javadoc

1   /*
2    * Copyright 2012-2013 smartics, Kronseder & Reiner GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package de.smartics.properties.spi.config.cache.guava;
17  
18  import java.util.HashSet;
19  import java.util.Iterator;
20  import java.util.Map.Entry;
21  import java.util.Set;
22  import java.util.concurrent.ExecutionException;
23  import java.util.concurrent.TimeUnit;
24  import java.util.concurrent.locks.Lock;
25  import java.util.concurrent.locks.ReentrantReadWriteLock;
26  import java.util.logging.Logger;
27  
28  import com.google.common.cache.Cache;
29  import com.google.common.cache.CacheBuilder;
30  import com.google.common.cache.CacheLoader;
31  import com.google.common.cache.LoadingCache;
32  import com.google.common.cache.RemovalListener;
33  import com.google.common.cache.RemovalNotification;
34  
35  import de.smartics.properties.api.config.domain.Property;
36  import de.smartics.properties.api.config.domain.PropertyCollection;
37  import de.smartics.properties.impl.config.cache.CacheConfigurationPropertiesManagement;
38  import de.smartics.properties.spi.config.cache.infinispan.InfinispanCompoundKeyDelegatingCache;
39  import de.smartics.util.lang.StaticAnalysis;
40  
41  /**
42   * The cache manager implementation using
43   * <code>com.google.common.cache.Cache</code> provided by <a
44   * href="http://code.google.com/p/guava-libraries/">guava-libraries</a>.
45   */
46  public final class GuavaCacheManager
47  { // NOPMD
48    // ********************************* Fields *********************************
49  
50    // --- constants ------------------------------------------------------------
51  
52    /**
53     * The logger for this class.
54     */
55    private static final Logger LOGGER = Logger.getLogger(GuavaCacheManager.class
56        .getName());
57  
58    /**
59     * The name of the key to retrieve the cache names.
60     */
61    public static final String INFINISPAN_DELEGATING_CACHE_CACHE_NAME =
62        "INFINISPAN_DELEGATING_CACHE_CACHE";
63  
64    /**
65     * The lock for synchronized access.
66     *
67     * @serial
68     */
69    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
70  
71    /**
72     * The read lock for synchronized access.
73     *
74     * @serial
75     */
76    private final Lock readLock = lock.readLock();
77  
78    /**
79     * The write lock for synchronized access.
80     *
81     * @serial
82     */
83    private final Lock writeLock = lock.writeLock();
84  
85    /**
86     * Removal listener for configurations.
87     */
88    // CHECKSTYLE:OFF
89    @SuppressWarnings(StaticAnalysis.RAWTYPES)
90    private final RemovalListener<Object, Object> configurationCacheCacheEntryRemovalListener =
91        new RemovalListener<Object, Object>()
92        {
93          public void onRemoval(final RemovalNotification<Object, Object> removal)
94          {
95            final String key = removal.getKey().toString();
96            LOGGER.fine("REMOVED: Confiurations cache removed cache with key: "
97                        + key);
98            final Object value = removal.getValue();
99            if (value instanceof CacheConfigurationPropertiesManagement)
100           {
101             removeFromInfinispanCache((CacheConfigurationPropertiesManagement) value);
102           }
103         }
104 
105         private void removeFromInfinispanCache(
106             final CacheConfigurationPropertiesManagement management)
107         {
108           final PropertyCollection collection =
109               management.getPropertyStoreAccessor()
110                   .getPropertyCollectionFromStore();
111           final String configurationKeyString = management.getKey().toString();
112           final InfinispanCompoundKeyDelegatingCache ic =
113               fetchInfinispanCompuondKeyDelegatingCache(configurationKeyString);
114 
115           for (final Iterator iterator = collection.iterator(); iterator
116               .hasNext();)
117           {
118             final Property property = (Property) iterator.next();
119             final String propertyKey = property.getName();
120             ic.remove(propertyKey);
121             LOGGER.finest("REMOVED from infinispan cache: key:" + propertyKey);
122           }
123         }
124 
125         @SuppressWarnings("unchecked")
126         private InfinispanCompoundKeyDelegatingCache fetchInfinispanCompuondKeyDelegatingCache(
127             final String configurationKeyString)
128         {
129           final de.smartics.properties.spi.config.cache.Cache infinispanDelegatingCache =
130               getInfinispanDelegatingCache();
131           final InfinispanCompoundKeyDelegatingCache ic =
132               (InfinispanCompoundKeyDelegatingCache) infinispanDelegatingCache
133                   .get(configurationKeyString);
134           return ic;
135         }
136       };
137 
138   // CHECKSTYLE:ON
139 
140   /**
141    * Removal listener for configurations.
142    */
143   @SuppressWarnings(StaticAnalysis.RAWTYPES)
144   private final RemovalListener<Object, Cache> infinispanCacheCacheEntryRemovalListener =
145       new RemovalListener<Object, Cache>()
146       {
147         public void onRemoval(final RemovalNotification<Object, Cache> removal)
148         {
149           final String key = removal.getKey().toString();
150           LOGGER.fine("REMOVED: Infinispan cache removed cache with key: "
151                       + key);
152         }
153       };
154 
155   /**
156    * Removal listener for infinispan caches.
157    */
158   @SuppressWarnings(StaticAnalysis.RAWTYPES)
159   private final RemovalListener<Object, Cache> mainCacheCacheEntryRemovalListener =
160       new RemovalListener<Object, Cache>()
161       {
162         public void onRemoval(final RemovalNotification<Object, Cache> removal)
163         {
164           final Object key = removal.getKey().toString();
165           LOGGER.fine("REMOVED: Main cache removed cache with key: " + key);
166         }
167       };
168 
169   /**
170    * The cache builder to build the caches on the fly.
171    */
172   // TODO configure eviction
173   @SuppressWarnings(StaticAnalysis.RAWTYPES)
174   private final CacheBuilder configurationsCacheCacheBuilder = CacheBuilder
175       .newBuilder().expireAfterWrite(30, TimeUnit.MINUTES)
176       .removalListener(configurationCacheCacheEntryRemovalListener);
177 
178   /**
179    * The cache builder to build the caches on the fly.
180    */
181   // TODO configure eviction
182   @SuppressWarnings(StaticAnalysis.RAWTYPES)
183   private final CacheBuilder infinispanCacheCacheBuilder = CacheBuilder
184       .newBuilder().expireAfterWrite(30, TimeUnit.MINUTES)
185       .removalListener(infinispanCacheCacheEntryRemovalListener);
186 
187   /**
188    * The cache builder to build the main cache (the one that stores the other
189    * caches).
190    */
191   // TODO configure eviction
192   @SuppressWarnings(StaticAnalysis.RAWTYPES)
193   private final CacheBuilder mainCacheBuilder = CacheBuilder.newBuilder()
194       .removalListener(mainCacheCacheEntryRemovalListener);
195 
196   /**
197    * The cache to store the caches.
198    */
199   @SuppressWarnings({ StaticAnalysis.RAWTYPES, StaticAnalysis.UNCHECKED })
200   private final LoadingCache<String, Cache> configurationCacheCache =
201       mainCacheBuilder.build(new CacheLoader<String, Cache>()
202       {
203         public Cache load(final String key)
204         {
205           LOGGER.fine("BUILDING: Building config cache cache for key: " + key);
206           return configurationsCacheCacheBuilder.build();
207         }
208       });
209 
210   /**
211    * The cache to store the caches.
212    */
213   @SuppressWarnings({ StaticAnalysis.RAWTYPES, StaticAnalysis.UNCHECKED })
214   private final LoadingCache<String, Cache> infinispanCacheCache =
215       mainCacheBuilder.build(new CacheLoader<String, Cache>()
216       {
217         public Cache load(final String key)
218         {
219           LOGGER
220               .fine("BUILDING: Building guava (infinispanCacheCache) cache for key: "
221                     + key);
222           return infinispanCacheCacheBuilder.build();
223         }
224       });
225 
226   /**
227    * The cache to store the caches wrapped in a guava delegating cache.
228    */
229   @SuppressWarnings({ StaticAnalysis.RAWTYPES, StaticAnalysis.UNCHECKED })
230   private final GuavaDelegatingCache guavaBasedInfinispanCacheCache =
231       new GuavaDelegatingCache(infinispanCacheCache);
232 
233   // --- members --------------------------------------------------------------
234 
235   // ****************************** Initializer *******************************
236 
237   // ****************************** Constructors ******************************
238 
239   /**
240    * Default constructor.
241    */
242   public GuavaCacheManager()
243   {
244   }
245 
246   // ****************************** Inner Classes *****************************
247 
248   // ********************************* Methods ********************************
249 
250   // --- init -----------------------------------------------------------------
251 
252   // --- get&set --------------------------------------------------------------
253 
254   // --- business -------------------------------------------------------------
255 
256   /**
257    * Removes all keys from all caches.
258    */
259   public void clearAll()
260   {
261     writeLock.lock();
262     try
263     {
264       internalClearAll(configurationCacheCache);
265       internalClearAll(infinispanCacheCache);
266     }
267     finally
268     {
269       writeLock.unlock();
270     }
271 
272   }
273 
274   @SuppressWarnings("rawtypes")
275   private void internalClearAll(final LoadingCache<String, Cache> cache)
276   {
277     for (final Entry<String, Cache> entry : cache.asMap().entrySet())
278     {
279       entry.getValue().cleanUp();
280     }
281     cache.cleanUp();
282   }
283 
284   /**
285    * Clears the cache with the given name.
286    *
287    * @param cacheName the name of the cache to be cleared.
288    */
289   @SuppressWarnings(StaticAnalysis.RAWTYPES)
290   public void clear(final String cacheName)
291   {
292     writeLock.lock();
293     try
294     {
295       final Cache current = findCache(cacheName);
296       if (current != null)
297       {
298         current.cleanUp();
299       }
300     }
301     finally
302     {
303       writeLock.unlock();
304     }
305   }
306 
307   @SuppressWarnings("rawtypes")
308   private Cache findCache(final String cacheName)
309   {
310     Cache current = configurationCacheCache.getIfPresent(cacheName);
311     if (current == null)
312     {
313       current = infinispanCacheCache.getIfPresent(cacheName);
314     }
315     return current;
316   }
317 
318   /**
319    * Clears and stops the cache.
320    *
321    * @param cacheName the name of the cache to be cleared and stopped.
322    */
323   public void discard(final String cacheName)
324   {
325     clear(cacheName);
326   }
327 
328   /**
329    * Stops all caches, rendering the manager in a stopped state.
330    */
331   public void stopAll()
332   {
333     clearAll();
334   }
335 
336   /**
337    * Stops the cache with the given name.
338    *
339    * @param cacheName the name of the cache to stop.
340    */
341   public void stop(final String cacheName)
342   {
343     clear(cacheName);
344   }
345 
346   /**
347    * Returns the cache with the given name. The cache is already started.
348    *
349    * @param cacheName the name of the cache to fetch.
350    * @return the requested cache already started.
351    */
352   @SuppressWarnings({ StaticAnalysis.RAWTYPES, StaticAnalysis.UNCHECKED })
353   public de.smartics.properties.spi.config.cache.Cache getConfigurationsCache(
354       final String cacheName)
355   {
356     writeLock.lock();
357     try
358     {
359       LOGGER.finest("GETTING: gCC: " + cacheName);
360       final Cache currentCache = configurationCacheCache.get(cacheName);
361       return new GuavaDelegatingCache(currentCache);
362     }
363     catch (final ExecutionException e)
364     {
365       // TODO Smartics exception
366       return null;
367     }
368     finally
369     {
370       writeLock.unlock();
371     }
372   }
373 
374   /**
375    * Returns the infinispan delegating cache.
376    *
377    * @return the requested cache.
378    */
379   @SuppressWarnings(StaticAnalysis.RAWTYPES)
380   public de.smartics.properties.spi.config.cache.Cache getInfinispanDelegatingCache()
381   {
382     LOGGER.finest("GETTING: idc");
383     return guavaBasedInfinispanCacheCache;
384   }
385 
386   /**
387    * Returns the set of cache names.
388    *
389    * @return the set of cache names.
390    */
391   public Set<String> getCacheNames()
392   {
393     readLock.lock();
394     try
395     {
396       final Set<String> cacheNames = new HashSet<String>();
397       cacheNames.addAll(configurationCacheCache.asMap().keySet());
398       cacheNames.addAll(infinispanCacheCache.asMap().keySet());
399       return cacheNames;
400     }
401     finally
402     {
403       readLock.unlock();
404     }
405   }
406   // --- object basics --------------------------------------------------------
407 
408 }