View Javadoc

1   package com.atlassian.cache.ehcache;
2   
3   import javax.annotation.Nonnull;
4   import javax.annotation.Nullable;
5   import javax.management.MBeanServer;
6   
7   import com.atlassian.cache.CacheLoader;
8   import com.atlassian.cache.CacheSettings;
9   import com.atlassian.cache.CacheSettingsBuilder;
10  import com.atlassian.cache.CacheSettingsDefaultsProvider;
11  import com.atlassian.cache.CachedReference;
12  import com.atlassian.cache.ManagedCache;
13  import com.atlassian.cache.impl.AbstractCacheManager;
14  import com.atlassian.cache.impl.ReferenceKey;
15  import com.atlassian.cache.impl.StrongSupplier;
16  import com.atlassian.cache.impl.WeakSupplier;
17  import com.atlassian.cache.impl.jmx.MBeanRegistrar;
18  import com.atlassian.util.concurrent.Supplier;
19  
20  import net.sf.ehcache.Ehcache;
21  import net.sf.ehcache.management.ManagementService;
22  
23  /**
24   * Maintains a mapping of name -> Cache and provides factory methods for creating ad getting caches.
25   *
26   * @since 2.0
27   */
28  public class EhCacheManager extends AbstractCacheManager implements MBeanRegistrar
29  {
30      private final net.sf.ehcache.CacheManager delegate;
31  
32      private boolean statisticsEnabled = true;
33  
34      /**
35       * Creates an instance backed by a new instance of {@link net.sf.ehcache.CacheManager}.
36       */
37      public EhCacheManager()
38      {
39          this(net.sf.ehcache.CacheManager.create(), null);
40      }
41  
42      /**
43       * Creates an instance backed by the provided instance of {@link net.sf.ehcache.CacheManager}.
44       *
45       * @param delegate an Ehcache's cache manager
46       */
47      public EhCacheManager(net.sf.ehcache.CacheManager delegate, CacheSettingsDefaultsProvider cacheSettingsDefaultsProvider)
48      {
49          super(cacheSettingsDefaultsProvider);
50  
51          this.delegate = delegate;
52      }
53  
54      net.sf.ehcache.CacheManager getEh()
55      {
56          return delegate;
57      }
58  
59      public boolean isStatisticsEnabled()
60      {
61          return statisticsEnabled;
62      }
63  
64      public void setStatisticsEnabled(final boolean statisticsEnabled)
65      {
66          this.statisticsEnabled = statisticsEnabled;
67      }
68  
69      @Nonnull
70      @SuppressWarnings("unchecked")
71      @Override
72      public <V> CachedReference<V> getCachedReference(@Nonnull final String name,
73                                                       @Nonnull final com.atlassian.cache.Supplier<V> supplier,
74                                                       @Nonnull final CacheSettings settings)
75      {
76          // Force the cache settings to be flushable and a maximum size of one.
77          final CacheSettings overridenSettings = settings.override(
78                  new CacheSettingsBuilder().flushable().maxEntries(1).build());
79  
80          return cacheCreationLocks.get(name).withLock(new com.atlassian.util.concurrent.Supplier<DelegatingCachedReference<V>>()
81              {
82                  @Override
83                  public DelegatingCachedReference<V> get()
84                  {
85                      Ehcache ehCache = getCleanCache(name, overridenSettings);
86                      final Ehcache spCache = new LoadingCache<ReferenceKey,V>(ehCache, new SupplierAdapter<V>(supplier));
87                      final DelegatingCachedReference<V> cache = DelegatingCachedReference.create(spCache, overridenSettings);
88                      caches.put(name, new WeakSupplier<ManagedCache>(cache));
89                      return cache;
90                  }
91              });
92      }
93  
94      @Override
95      protected ManagedCache createSimpleCache(@Nonnull final String name, @Nonnull final CacheSettings settings)
96      {
97          final Supplier<ManagedCache> cacheSupplier = caches.get(name);
98          if (cacheSupplier != null)
99          {
100             ManagedCache cache = cacheSupplier.get();
101             if (cache != null)
102             {
103                 return cache;
104             }
105         }
106         return cacheCreationLocks.get(name).withLock(new com.atlassian.util.concurrent.Supplier<ManagedCache>()
107             {
108                 @Override
109                 public ManagedCache get()
110                 {
111                     if (!caches.containsKey(name))
112                     {
113                         final Ehcache simpleCache = createCache(name, settings, false);
114                         DelegatingCache<?,?> cache = DelegatingCache.create(simpleCache, settings);
115                         caches.put(name,  new StrongSupplier<ManagedCache>(cache));
116                     }
117                     return caches.get(name).get();
118                 }
119             });
120 
121     }
122 
123     @SuppressWarnings("unchecked")
124     protected <K, V> ManagedCache createComputingCache(@Nonnull final String name, @Nonnull final CacheSettings settings, final CacheLoader<K, V> loader)
125     {
126         return cacheCreationLocks.get(name).withLock(new com.atlassian.util.concurrent.Supplier<ManagedCache>()
127         {
128             @Override
129             public ManagedCache get()
130             {
131                 Ehcache ehCache = getCleanCache(name, settings);
132 
133                 Ehcache spCache = new LoadingCache(ehCache, loader);
134                 DelegatingCache<K,V> cache = DelegatingCache.create(spCache, settings);
135                 caches.put(name,  new WeakSupplier<ManagedCache>(cache));
136                 return cache;
137             }
138         });
139     }
140 
141     private Ehcache getCleanCache(final String name, final CacheSettings settings)
142     {
143         // Particularly for plugins that are reloaded the cache may already exist from earlier times.
144         // Because actually removing the old cache and recreating it breaks RMI replication we get the old one,
145         // but to avoid any class loading issues with the old plugin class loader which would be unavailable
146         // we remove all entries from the local version of the cache
147 
148         Ehcache ehCache = delegate.getCache(name);
149         if (ehCache != null)
150         {
151             // Remove all entries but do not notify replication listeners.
152             ehCache.removeAll(true);
153         }
154         else
155         {
156             ehCache = createCache(name, settings, true);
157         }
158         return ehCache;
159     }
160 
161     private Ehcache createCache(String name, CacheSettings settings, boolean selfLoading)
162     {
163         return new EhCacheHelper().getEhcache(name, delegate, settings, selfLoading, statisticsEnabled);
164     }
165 
166     @Override
167     public void shutdown()
168     {
169 
170         delegate.shutdown();
171     }
172 
173     @Override
174     public void registerMBeans(@Nullable final MBeanServer mBeanServer)
175     {
176         if (mBeanServer != null)
177         {
178             ManagementService.registerMBeans(delegate, mBeanServer, true, true, true, true);
179         }
180     }
181 
182     @Override
183     public void unregisterMBeans(@Nullable final MBeanServer mBeanServer)
184     {
185         if (mBeanServer != null)
186         {
187             final ManagementService managementService = new ManagementService(delegate, mBeanServer, true, true, true, true);
188             managementService.dispose();
189         }
190     }
191 
192     static class SupplierAdapter<V> implements CacheLoader<ReferenceKey, V>
193     {
194         private final com.atlassian.cache.Supplier<V> supplier;
195 
196         SupplierAdapter(com.atlassian.cache.Supplier<V> supplier)
197         {
198             this.supplier = supplier;
199         }
200 
201         @Nonnull
202         @Override
203         public V load(@Nonnull ReferenceKey key)
204         {
205             return supplier.get();
206         }
207     }
208 }