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