1 package com.atlassian.cache.memory;
2
3 import javax.annotation.Nonnull;
4
5 import com.atlassian.cache.CacheLoader;
6 import com.atlassian.cache.CacheSettings;
7 import com.atlassian.cache.CacheSettingsBuilder;
8 import com.atlassian.cache.CachedReference;
9 import com.atlassian.cache.ManagedCache;
10 import com.atlassian.cache.impl.AbstractCacheManager;
11 import com.atlassian.cache.impl.ReferenceKey;
12 import com.atlassian.cache.impl.StrongSupplier;
13 import com.atlassian.cache.impl.WeakSupplier;
14 import com.atlassian.util.concurrent.Supplier;
15
16 import com.google.common.cache.Cache;
17 import com.google.common.cache.CacheBuilder;
18 import com.google.common.cache.LoadingCache;
19
20 import static java.util.concurrent.TimeUnit.MILLISECONDS;
21
22
23
24
25
26
27 public class MemoryCacheManager extends AbstractCacheManager
28 {
29 @Nonnull
30 public MemoryCacheManager()
31 {
32 super(null);
33 }
34
35 @Nonnull
36 @SuppressWarnings("unchecked")
37 @Override
38 public <V> CachedReference<V> getCachedReference(@Nonnull final String name,
39 @Nonnull final com.atlassian.cache.Supplier<V> supplier,
40 @Nonnull final CacheSettings settings)
41 {
42
43 final CacheSettings overridenSettings = settings.override(new CacheSettingsBuilder().flushable().build());
44
45 return (DelegatingCachedReference<V>) cacheCreationLocks.get(name).withLock(new com.atlassian.util.concurrent.Supplier<ManagedCache>()
46 {
47 @Override
48 public ManagedCache get()
49 {
50
51
52 final DelegatingCachedReference.DelegatingReferenceRemovalListener<V> listener = new DelegatingCachedReference.DelegatingReferenceRemovalListener<V>();
53
54 LoadingCache<ReferenceKey, V> computingCache = createCacheBuilder(overridenSettings)
55 .removalListener(listener)
56 .build(new com.google.common.cache.CacheLoader<ReferenceKey, V>()
57 {
58 @Override
59 public V load(@Nonnull final ReferenceKey key) throws Exception
60 {
61 V value = supplier.get();
62 listener.onSupply(value);
63 return value;
64 }
65 });
66
67 DelegatingCachedReference cache = DelegatingCachedReference.create(computingCache, name, overridenSettings);
68 listener.setCachedReference(cache);
69 caches.put(name, new WeakSupplier<ManagedCache>(cache));
70 return cache;
71 }
72 });
73 }
74
75 @SuppressWarnings("unchecked")
76 protected ManagedCache createSimpleCache(@Nonnull final String name, @Nonnull final CacheSettings settings)
77 {
78
79 Supplier<ManagedCache> cacheSupplier = caches.get(name);
80 if (cacheSupplier != null)
81 {
82 ManagedCache cache = cacheSupplier.get();
83 if (cache != null)
84 {
85 return cache;
86 }
87 }
88 return cacheCreationLocks.get(name).withLock(new com.atlassian.util.concurrent.Supplier<ManagedCache>()
89 {
90 @Override
91 public ManagedCache get()
92 {
93 if (!caches.containsKey(name))
94 {
95 DelegatingCache.DelegatingRemovalListener listener = new DelegatingCache.DelegatingRemovalListener();
96
97 final Cache<Object, Object> simpleCache = createCacheBuilder(settings)
98 .removalListener(listener)
99 .build();
100
101 DelegatingCache cache = DelegatingCache.create(simpleCache, name, settings);
102 listener.setCache(cache);
103
104 caches.put(name, new StrongSupplier<ManagedCache>(cache));
105 }
106 return caches.get(name).get();
107 }
108 });
109 }
110
111 @SuppressWarnings("unchecked")
112 protected <K, V> ManagedCache createComputingCache(@Nonnull final String name, @Nonnull final CacheSettings settings, final CacheLoader<K, V> loader)
113 {
114 return cacheCreationLocks.get(name).withLock(new com.atlassian.util.concurrent.Supplier<ManagedCache>()
115 {
116 @Override
117 public ManagedCache get()
118 {
119
120
121 final DelegatingCache.DelegatingRemovalListener listener = new DelegatingCache.DelegatingRemovalListener();
122
123 LoadingCache<K, V> computingCache = createCacheBuilder(settings)
124 .removalListener(listener)
125 .build(new com.google.common.cache.CacheLoader<K, V>()
126 {
127 @Override
128 public V load(@Nonnull final K key) throws Exception
129 {
130 V value = loader.load(key);
131 listener.onSupply(key, value);
132 return value;
133 }
134 });
135
136 DelegatingCache cache = DelegatingCache.create(computingCache, name, settings);
137 listener.setCache(cache);
138 caches.put(name, new WeakSupplier<ManagedCache>(cache));
139 return cache;
140 }
141 });
142 }
143
144 private CacheBuilder createCacheBuilder(CacheSettings settings)
145 {
146 final CacheBuilder cacheBuilder = CacheBuilder.newBuilder();
147 if (null != settings.getMaxEntries())
148 {
149 cacheBuilder.maximumSize(settings.getMaxEntries());
150 }
151
152 if (null != settings.getExpireAfterAccess())
153 {
154 cacheBuilder.expireAfterAccess(settings.getExpireAfterAccess(), MILLISECONDS);
155 }
156 else if (null != settings.getExpireAfterWrite())
157 {
158 cacheBuilder.expireAfterWrite(settings.getExpireAfterWrite(), MILLISECONDS);
159 }
160 return cacheBuilder;
161 }
162 }