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