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
27
28
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
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 }