View Javadoc
1   package com.atlassian.cache.ehcache;
2   
3   import java.util.SortedMap;
4   
5   import javax.annotation.Nonnull;
6   import javax.annotation.Nullable;
7   
8   import com.atlassian.cache.CacheException;
9   import com.atlassian.cache.CacheSettings;
10  import com.atlassian.cache.CacheStatisticsKey;
11  import com.atlassian.cache.CachedReference;
12  import com.atlassian.cache.CachedReferenceListener;
13  import com.atlassian.cache.ehcache.wrapper.ValueProcessor;
14  import com.atlassian.cache.impl.CachedReferenceListenerSupport;
15  import com.atlassian.cache.impl.LazyCachedReferenceListenerSupport;
16  import com.atlassian.cache.impl.ReferenceKey;
17  import java.util.function.Supplier;
18  
19  import com.google.common.collect.ImmutableSortedMap;
20  
21  import net.sf.ehcache.Ehcache;
22  import net.sf.ehcache.Element;
23  import net.sf.ehcache.event.CacheEventListener;
24  import org.slf4j.Logger;
25  import org.slf4j.LoggerFactory;
26  
27  import static com.atlassian.cache.ehcache.DelegatingCacheStatistics.toStatistics;
28  import static com.atlassian.cache.ehcache.wrapper.WrapperUtils.unwrapElement;
29  
30  /**
31   * A Lazy Reference that delegates to EhCache.
32   *
33   * @since 2.0
34   */
35  class DelegatingCachedReference<V> extends ManagedCacheSupport implements CachedReference<V>
36  {
37      private final Ehcache delegate;
38      private final CachedReferenceListenerSupport<V> listenerSupport = new LazyCachedReferenceListenerSupport<V>()
39      {
40          @Override
41          protected void init()
42          {
43              delegate.getCacheEventNotificationService().registerListener(new DelegatingReferenceCacheEventListener());
44          }
45      };
46  
47      private final Logger eventLogger;
48      private final Logger stacktraceLogger;
49  
50      private final ValueProcessor valueProcessor;
51  
52      private DelegatingCachedReference(final Ehcache delegate, CacheSettings settings, final ValueProcessor valueProcessor)
53      {
54          super(delegate, settings);
55          this.delegate = delegate;
56          this.eventLogger = LoggerFactory.getLogger("com.atlassian.cache.event." + delegate.getName());
57          this.stacktraceLogger = LoggerFactory.getLogger("com.atlassian.cache.stacktrace." + delegate.getName());
58          this.valueProcessor = valueProcessor;
59      }
60  
61      static <V> DelegatingCachedReference<V> create(final Ehcache delegate, CacheSettings settings, final ValueProcessor valueProcessor)
62      {
63          return new DelegatingCachedReference<V>(delegate, settings, valueProcessor);
64      }
65  
66      @Nonnull
67      @SuppressWarnings("unchecked")
68      @Override
69      public V get()
70      {
71          try
72          {
73              return (V) unwrap(delegate.get(wrap(ReferenceKey.KEY))).getObjectValue();
74          }
75          catch (net.sf.ehcache.CacheException e)
76          {
77              throw new CacheException(e.getCause());
78          }
79          catch (Exception e)
80          {
81              throw new CacheException(e);
82          }
83      }
84  
85      @Override
86      public void reset()
87      {
88          try
89          {
90              delegate.remove(wrap(ReferenceKey.KEY));
91              eventLogger.info("Cache {} was flushed", delegate.getName());
92              if (stacktraceLogger.isInfoEnabled()) {
93                  stacktraceLogger.info("Cache {} was flushed. Stacktrace:", delegate.getName(), new Exception());
94              }
95          }
96          catch (Exception e)
97          {
98              throw new CacheException(e);
99          }
100     }
101 
102     @Override
103     public void clear()
104     {
105         reset();
106     }
107 
108     public boolean equals(@Nullable final Object other)
109     {
110         if (other instanceof DelegatingCachedReference)
111         {
112             DelegatingCachedReference<?> otherDelegatingReference = (DelegatingCachedReference<?>) other;
113             if (delegate.equals(otherDelegatingReference.delegate))
114             {
115                 return true;
116             }
117         }
118         return false;
119     }
120 
121     @Override
122     public int hashCode()
123     {
124         return 3 + delegate.hashCode();
125     }
126 
127     @Nonnull
128     @Override
129     public SortedMap<CacheStatisticsKey,Supplier<Long>> getStatistics()
130     {
131         if (isStatisticsEnabled())
132         {
133             return toStatistics(delegate.getStatistics());
134         }
135         else
136         {
137             return ImmutableSortedMap.of();
138         }
139     }
140 
141     @Override
142     public void addListener(@Nonnull CachedReferenceListener<V> listener, boolean includeValues)
143     {
144         listenerSupport.add(listener, includeValues);
145     }
146 
147     private Object wrap(Object o) {
148         return valueProcessor.wrap(o);
149     }
150 
151     private Object unwrap(Object o) {
152         return valueProcessor.unwrap(o);
153     }
154 
155     private Element unwrap(Element element) {
156         return unwrapElement(element, valueProcessor);
157     }
158 
159     @Override
160     public void removeListener(@Nonnull CachedReferenceListener<V> listener)
161     {
162         listenerSupport.remove(listener);
163     }
164 
165     private class DelegatingReferenceCacheEventListener implements CacheEventListener
166     {
167         @Override
168         public void notifyElementRemoved(Ehcache ehcache, Element element) throws net.sf.ehcache.CacheException
169         {
170             listenerSupport.notifyReset((V) unwrap(element.getObjectValue()));
171         }
172 
173         @Override
174         public void notifyElementPut(Ehcache ehcache, Element element) throws net.sf.ehcache.CacheException
175         {
176             listenerSupport.notifySet((V) unwrap(element.getObjectValue()));
177         }
178 
179         @Override
180         public void notifyElementUpdated(Ehcache ehcache, Element element) throws net.sf.ehcache.CacheException
181         {
182             listenerSupport.notifySet((V) unwrap(element.getObjectValue()));
183         }
184 
185         @Override
186         public void notifyElementExpired(Ehcache ehcache, Element element)
187         {
188             listenerSupport.notifyEvict((V) unwrap(element.getObjectValue()));
189         }
190 
191         @Override
192         public void notifyElementEvicted(Ehcache ehcache, Element element)
193         {
194             listenerSupport.notifyEvict((V) unwrap(element.getObjectValue()));
195         }
196 
197         @Override
198         public void notifyRemoveAll(Ehcache ehcache)
199         {
200             listenerSupport.notifyReset((V) null);
201         }
202 
203         @Override
204         public void dispose()
205         {
206             // We don't hold onto any resources so there is nothing to be done.
207         }
208 
209         public Object clone() throws CloneNotSupportedException
210         {
211             throw new CloneNotSupportedException();
212         }
213     }
214 }