1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.module.cache.cachepolicy;
35
36 import java.util.Collections;
37 import java.util.HashSet;
38 import java.util.Locale;
39 import java.util.Map;
40 import java.util.Set;
41
42 import info.magnolia.cms.core.AggregationState;
43 import info.magnolia.context.MgnlContext;
44 import info.magnolia.context.WebContext;
45 import info.magnolia.module.ModuleRegistry;
46 import info.magnolia.module.cache.Cache;
47 import info.magnolia.module.cache.CacheFactory;
48 import info.magnolia.module.cache.CacheModule;
49 import info.magnolia.module.cache.CachePolicy;
50 import info.magnolia.module.cache.CachePolicyResult;
51 import info.magnolia.module.cache.DefaultCacheKey;
52 import info.magnolia.module.cache.FlushPolicy;
53 import info.magnolia.voting.voters.VoterSet;
54
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58
59
60
61
62
63
64
65 public class Default implements CachePolicy {
66
67 public static final String UUID_KEY_MAP_KEY = "uuid-key-mapping";
68 private static final Logger log = LoggerFactory.getLogger(Default.class);
69
70 private VoterSet voters;
71
72 private boolean refreshOnNoCacheRequests = false;
73
74 public CachePolicyResult shouldCache(final Cache cache, final AggregationState aggregationState, final FlushPolicy flushPolicy) {
75 final Object key = retrieveCacheKey(aggregationState);
76
77 if (shouldBypass(aggregationState, key)) {
78 return new CachePolicyResult(CachePolicyResult.bypass, key, null);
79 }
80
81 if (shouldRefresh(aggregationState, key)) {
82 log.debug("Cache refresh requested for {}", key);
83 return new CachePolicyResult(CachePolicyResult.store, key, null);
84 }
85
86
87
88
89
90
91
92
93
94
95
96 final Object cachedEntry = cache.get(key);
97
98
99 if (cachedEntry != null) {
100 return new CachePolicyResult(CachePolicyResult.useCache, key, cachedEntry);
101 } else {
102 return new CachePolicyResult(CachePolicyResult.store, key, null);
103 }
104 }
105
106
107
108
109
110 protected boolean shouldRefresh(AggregationState aggregationState, Object key) {
111 if(isRefreshOnNoCacheRequests()){
112 String cacheControl = ((WebContext) MgnlContext.getInstance()).getRequest().getHeader("Cache-Control");
113
114
115 return cacheControl != null && cacheControl.equals("no-cache");
116 }
117 return false;
118 }
119
120 protected boolean shouldBypass(AggregationState aggregationState, Object key) {
121 final String uri;
122 if (key instanceof DefaultCacheKey) {
123 uri = ((DefaultCacheKey) key).getUri();
124 } else {
125 uri = key.toString();
126 }
127
128 return voters.vote(uri) <= 0;
129 }
130
131 public Object retrieveCacheKey(final AggregationState aggregationState) {
132
133 final String uri = aggregationState.getOriginalURI();
134
135
136 final String serverName;
137 final Map<String, String> params;
138 if (MgnlContext.isWebContext()) {
139 serverName = MgnlContext.getWebContext().getRequest().getServerName();
140 params = MgnlContext.getWebContext().getParameters();
141 } else {
142 serverName = null;
143 params = null;
144 }
145
146
147 final String localeStr;
148 final Locale locale = aggregationState.getLocale();
149 if(locale != null){
150 localeStr = locale.toString();
151 } else {
152 localeStr = null;
153 }
154
155
156 return new DefaultCacheKey(uri, serverName, localeStr, params);
157 }
158
159 public Object[] retrieveCacheKeys(final String uuid, final String repository) {
160 final String uuidKey = repository + ":" + uuid;
161 final Set<Object> keys = getUUIDKeySetFromCacheSafely(uuidKey);
162 return keys.toArray();
163 }
164
165 public void persistCacheKey(final String repo, final String uuid, final Object key) {
166 final String uuidKey = repo + ":" + uuid;
167 final Set<Object> uuidToCacheKeyMapping = getUUIDKeySetFromCacheSafely(uuidKey);
168 uuidToCacheKeyMapping.add(key);
169 }
170
171 public VoterSet getVoters() {
172 return voters;
173 }
174
175 public void setVoters(VoterSet voters) {
176 this.voters = voters;
177 }
178
179 public Object[] removeCacheKeys(final String uuid, final String repository) {
180 final String uuidKey = repository + ":" + uuid;
181 final Set keys = getUUIDKeySetFromCacheSafely(uuidKey);
182 getUuidKeyCache().remove(uuidKey);
183 return keys.toArray();
184 }
185
186 private Cache getUuidKeyCache() {
187 final CacheFactory factory = ModuleRegistry.Factory.getInstance().getModuleInstance(CacheModule.class).getCacheFactory();
188 return factory.getCache(UUID_KEY_MAP_KEY);
189 }
190
191
192
193
194 private synchronized Set<Object> getUUIDKeySetFromCacheSafely(String uuidKey) {
195 final Cache cache = getUuidKeyCache();
196 synchronized (cache) {
197 Set<Object> keys = (Set<Object>) cache.get(uuidKey);
198 if (keys == null) {
199 keys = Collections.synchronizedSet(new HashSet<Object>());
200 cache.put(uuidKey, keys);
201 }
202 return keys;
203 }
204 }
205
206 public boolean isRefreshOnNoCacheRequests() {
207 return this.refreshOnNoCacheRequests;
208 }
209
210 public void setRefreshOnNoCacheRequests(boolean allowNoCacheHeader) {
211 this.refreshOnNoCacheRequests = allowNoCacheHeader;
212 }
213 }