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