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
32
33
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
207 }
208
209 public Object clone() throws CloneNotSupportedException
210 {
211 throw new CloneNotSupportedException();
212 }
213 }
214 }