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