View Javadoc

1   package com.atlassian.cache.hazelcast;
2   
3   import javax.annotation.Nonnull;
4   import javax.annotation.Nullable;
5   
6   import com.atlassian.cache.CacheException;
7   import com.atlassian.cache.CachedReference;
8   import com.atlassian.cache.CachedReferenceEvent;
9   import com.atlassian.cache.CachedReferenceListener;
10  import com.atlassian.cache.Supplier;
11  import com.atlassian.cache.impl.CachedReferenceListenerSupport;
12  import com.atlassian.cache.impl.DefaultCachedReferenceEvent;
13  import com.atlassian.cache.impl.ValueCachedReferenceListenerSupport;
14  import com.atlassian.hazelcast.serialization.OsgiSafe;
15  
16  import com.google.common.base.Objects;
17  import com.google.common.base.Throwables;
18  import com.hazelcast.core.EntryAdapter;
19  import com.hazelcast.core.EntryEvent;
20  import com.hazelcast.core.IMap;
21  
22  import static com.atlassian.cache.hazelcast.OsgiSafeUtils.unwrap;
23  import static com.atlassian.cache.hazelcast.OsgiSafeUtils.wrap;
24  import static com.google.common.base.Preconditions.checkNotNull;
25  
26  /**
27   * A {@link CachedReference} implementation to satisfy the requirements of {@link com.atlassian.cache.CacheFactory}.
28   *
29   * @since 2.4.0
30   */
31  public class HazelcastCachedReference<V> extends ManagedCacheSupport implements CachedReference<V>
32  {
33      private final IMap<String, OsgiSafe<V>> hazelcastMap;
34      private final Supplier<V> supplier;
35  
36      private final CachedReferenceListenerSupport<OsgiSafe<V>> listenerSupport = new ValueCachedReferenceListenerSupport<OsgiSafe<V>>()
37      {
38          @Override
39          protected void initValue(final CachedReferenceListenerSupport<OsgiSafe<V>> actualListenerSupport)
40          {
41              hazelcastMap.addEntryListener(new HazelcastCachedReferenceListener<OsgiSafe<V>>(actualListenerSupport), true);
42          }
43  
44          @Override
45          protected void initValueless(final CachedReferenceListenerSupport<OsgiSafe<V>> actualListenerSupport)
46          {
47              hazelcastMap.addEntryListener(new HazelcastCachedReferenceListener<OsgiSafe<V>>(actualListenerSupport), false);
48          }
49      };
50  
51      private static final String REFERENCE_KEY = "ReferenceKey";
52  
53      @SuppressWarnings ("AssignmentToCollectionOrArrayFieldFromParameter")
54          // The map is a delegate
55      HazelcastCachedReference(String name, IMap<String, OsgiSafe<V>> hazelcastMap, Supplier<V> supplier, HazelcastCacheManager cacheManager)
56      {
57          super(name, cacheManager);
58  
59          this.hazelcastMap = hazelcastMap;
60          this.supplier = supplier;
61      }
62  
63      @Override
64      public void clear()
65      {
66          hazelcastMap.remove(REFERENCE_KEY);
67      }
68  
69      @Nonnull
70      @SuppressWarnings ("unchecked")
71      @Override
72      public V get()
73      {
74          try
75          {
76              OsgiSafe<V> value = hazelcastMap.get(REFERENCE_KEY);
77              if (value == null)
78              {
79                  V newValue = supplier.get();
80                  if (newValue == null)
81                  {
82                      throw new CacheException("The provided supplier returned null. Null values are not supported.");
83                  }
84                  value = wrap(newValue);
85                  OsgiSafe<V> current = hazelcastMap.putIfAbsent(REFERENCE_KEY, value);
86                  return unwrap(Objects.firstNonNull(current, value));
87              }
88              return unwrap(value);
89          }
90          catch (RuntimeException e)
91          {
92              Throwables.propagateIfInstanceOf(e, CacheException.class);
93              throw new CacheException(e);
94          }
95      }
96  
97      @Override
98      public void reset()
99      {
100         try
101         {
102             hazelcastMap.remove(REFERENCE_KEY);
103         }
104         catch (RuntimeException e)
105         {
106             throw new CacheException(e);
107         }
108     }
109 
110     @Override
111     public boolean equals(@Nullable final Object o)
112     {
113         if (this == o)
114         {
115             return true;
116         }
117         if (o == null || getClass() != o.getClass())
118         {
119             return false;
120         }
121         HazelcastCachedReference<?> other = (HazelcastCachedReference<?>) o;
122         return hazelcastMap.equals(other.hazelcastMap);
123     }
124 
125     @Override
126     public int hashCode()
127     {
128         return 3 + hazelcastMap.hashCode();
129     }
130 
131     @Override
132     public void addListener(@Nonnull CachedReferenceListener<V> listener, boolean includeValues)
133     {
134         listenerSupport.add(new OsgiSafeCachedReferenceListener<V>(listener), includeValues);
135     }
136 
137     @Override
138     public void removeListener(@Nonnull CachedReferenceListener<V> listener)
139     {
140         listenerSupport.remove(new OsgiSafeCachedReferenceListener<V>(listener));
141     }
142 
143     @Override
144     protected String getHazelcastMapName()
145     {
146         return hazelcastMap.getName();
147     }
148 
149     private static class OsgiSafeCachedReferenceListener<V> implements CachedReferenceListener<OsgiSafe<V>>
150     {
151         private final CachedReferenceListener<V> delegate;
152 
153         private OsgiSafeCachedReferenceListener(CachedReferenceListener<V> listener)
154         {
155             this.delegate = checkNotNull(listener, "listener");
156         }
157 
158         @Override
159         public void onEvict(@Nonnull CachedReferenceEvent<OsgiSafe<V>> event)
160         {
161             delegate.onEvict(new DefaultCachedReferenceEvent<V>(unwrap(event.getValue())));
162         }
163 
164         @Override
165         public void onSet(@Nonnull CachedReferenceEvent<OsgiSafe<V>> event)
166         {
167             delegate.onSet(new DefaultCachedReferenceEvent<V>(unwrap(event.getValue())));
168         }
169 
170         @Override
171         public void onReset(@Nonnull CachedReferenceEvent<OsgiSafe<V>> event)
172         {
173             delegate.onReset(new DefaultCachedReferenceEvent<V>(unwrap(event.getValue())));
174         }
175 
176         @Override
177         public boolean equals(Object o)
178         {
179             if (this == o)
180             {
181                 return true;
182             }
183             if (o == null || getClass() != o.getClass())
184             {
185                 return false;
186             }
187 
188             OsgiSafeCachedReferenceListener that = (OsgiSafeCachedReferenceListener) o;
189             return delegate.equals(that.delegate);
190         }
191 
192         @Override
193         public int hashCode()
194         {
195             return delegate.hashCode();
196         }
197     }
198 
199     @SuppressWarnings ("unchecked")
200     private static class HazelcastCachedReferenceListener<V> extends EntryAdapter<String, V>
201     {
202         private final CachedReferenceListenerSupport listenerSupport;
203 
204         private HazelcastCachedReferenceListener(final CachedReferenceListenerSupport listenerSupport)
205         {
206             this.listenerSupport = listenerSupport;
207         }
208 
209         @Override
210         public void entryAdded(EntryEvent<String, V> event)
211         {
212             listenerSupport.notifySet(event.getValue());
213         }
214 
215         @Override
216         public void entryRemoved(EntryEvent<String, V> event)
217         {
218             listenerSupport.notifyReset(event.getOldValue());
219         }
220 
221         @Override
222         public void entryUpdated(EntryEvent<String, V> event)
223         {
224             listenerSupport.notifySet(event.getValue());
225         }
226 
227         @Override
228         public void entryEvicted(EntryEvent<String, V> event)
229         {
230             listenerSupport.notifyEvict(event.getOldValue());
231         }
232     }
233 }