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