View Javadoc

1   package com.atlassian.cache.memory;
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.impl.CachedReferenceListenerSupport;
14  import com.atlassian.cache.impl.DefaultCachedReferenceListenerSupport;
15  import com.atlassian.cache.impl.ReferenceKey;
16  import com.atlassian.util.concurrent.Supplier;
17  
18  import com.google.common.cache.LoadingCache;
19  import com.google.common.cache.RemovalListener;
20  import com.google.common.cache.RemovalNotification;
21  import com.google.common.util.concurrent.UncheckedExecutionException;
22  
23  import static com.atlassian.cache.memory.DelegatingCacheStatistics.toStatistics;
24  
25  /**
26   * A Lazy Reference that delegates Concurrent Map.
27   *
28   * @since 2.0
29   */
30  class DelegatingCachedReference<V> extends ManagedCacheSupport implements CachedReference<V>
31  {
32      private final LoadingCache<ReferenceKey, V> internalCache;
33      private final CachedReferenceListenerSupport<V> listenerSupport;
34  
35      private DelegatingCachedReference(final LoadingCache<ReferenceKey, V> internalCache,
36              String name, CacheSettings settings)
37      {
38          super(name, settings);
39          this.internalCache = internalCache;
40  
41          this.listenerSupport = new DefaultCachedReferenceListenerSupport<V>();
42      }
43  
44      static <V> DelegatingCachedReference<V> create(final LoadingCache<ReferenceKey, V> internalCache,
45              String name, CacheSettings settings)
46      {
47          return new DelegatingCachedReference<V>(internalCache, name, settings);
48      }
49  
50      @Nonnull
51      @Override
52      public V get()
53      {
54          try
55          {
56              return internalCache.get(ReferenceKey.KEY);
57          }
58          catch (UncheckedExecutionException e)
59          {
60              throw new CacheException(e.getCause());
61          }
62          catch (Exception e)
63          {
64              throw new CacheException(e);
65          }
66      }
67  
68      @Override
69      public void reset()
70      {
71          try
72          {
73              try
74              {
75                  internalCache.getUnchecked(ReferenceKey.KEY);
76              }
77              catch (UncheckedExecutionException e)
78              {
79                  //Even if the get fails we still want to remove and report only if the remove fails.
80              }
81              finally
82              {
83                  internalCache.invalidate(ReferenceKey.KEY);
84              }
85          }
86          catch (Exception e)
87          {
88              throw new CacheException(e);
89          }
90      }
91  
92      @Override
93      public void clear()
94      {
95          reset();
96      }
97  
98      @Override
99      public boolean equals(@Nullable final Object other)
100     {
101         if (other instanceof DelegatingCachedReference)
102         {
103             DelegatingCachedReference<?> otherDelegatingReference = (DelegatingCachedReference<?>) other;
104             if (internalCache.equals(otherDelegatingReference.internalCache))
105             {
106                 return true;
107             }
108         }
109         return false;
110     }
111 
112     @Override
113     public int hashCode()
114     {
115         return 3 + internalCache.hashCode();
116     }
117 
118     @Nonnull
119     @Override
120     public SortedMap<CacheStatisticsKey,Supplier<Long>> getStatistics()
121     {
122         return toStatistics(internalCache);
123     }
124 
125     @Override
126     public void addListener(@Nonnull CachedReferenceListener<V> listener, boolean includeValues)
127     {
128         listenerSupport.add(listener, includeValues);
129     }
130 
131     @Override
132     public void removeListener(@Nonnull CachedReferenceListener<V> listener)
133     {
134         listenerSupport.remove(listener);
135     }
136 
137     protected static class DelegatingReferenceRemovalListener<V> implements RemovalListener<ReferenceKey, V>
138     {
139         private DelegatingCachedReference<V> cachedReference;
140 
141         protected void onSupply(V value)
142         {
143             cachedReference.listenerSupport.notifySet(value);
144         }
145 
146         @Override
147         public void onRemoval(RemovalNotification<ReferenceKey, V> notification)
148         {
149             switch (notification.getCause())
150             {
151                 case COLLECTED:
152                 case EXPIRED:
153                     cachedReference.listenerSupport.notifyEvict(notification.getValue());
154                     break;
155                 case EXPLICIT:
156                     cachedReference.listenerSupport.notifyReset(notification.getValue());
157                     break;
158                 case REPLACED:
159                     V value = cachedReference.internalCache.getIfPresent(ReferenceKey.KEY);
160                     cachedReference.listenerSupport.notifySet(value);
161                     break;
162             }
163         }
164 
165         public void setCachedReference(DelegatingCachedReference<V> cachedReference)
166         {
167             this.cachedReference = cachedReference;
168         }
169     }
170 }