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.filter;
35
36 import info.magnolia.cms.core.AggregationState;
37 import info.magnolia.cms.filters.OncePerRequestAbstractMgnlFilter;
38 import info.magnolia.context.MgnlContext;
39 import info.magnolia.module.cache.BlockingCache;
40 import info.magnolia.module.cache.Cache;
41 import info.magnolia.module.cache.CacheConfiguration;
42 import info.magnolia.module.cache.CacheModule;
43 import info.magnolia.module.cache.CacheModuleLifecycleListener;
44 import info.magnolia.module.cache.CachePolicyExecutor;
45 import info.magnolia.module.cache.CachePolicyResult;
46 import info.magnolia.module.cache.mbean.CacheMonitor;
47
48 import javax.servlet.FilterChain;
49 import javax.servlet.FilterConfig;
50 import javax.servlet.ServletException;
51 import javax.servlet.http.HttpServletRequest;
52 import javax.servlet.http.HttpServletResponse;
53
54 import org.apache.commons.lang.StringUtils;
55 import org.apache.commons.lang.exception.ExceptionUtils;
56
57 import net.sf.ehcache.constructs.blocking.LockTimeoutException;
58
59 import java.io.IOException;
60
61
62
63
64
65
66
67
68 public class CacheFilter extends OncePerRequestAbstractMgnlFilter implements CacheModuleLifecycleListener {
69 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CacheFilter.class);
70
71 private static final String DEFAULT_CACHE_CONFIG = "default";
72
73 private final CacheModule cacheModule;
74 private final CacheMonitor monitor;
75 private String cacheConfigurationName;
76 private CacheConfiguration cacheConfig;
77 private Cache cache;
78
79
80 private int blockingTimeout = -1;
81
82 public CacheFilter(CacheModule cacheModule, CacheMonitor cacheMonitor) {
83 this.cacheModule = cacheModule;
84 this.monitor = cacheMonitor;
85 }
86
87 public String getCacheConfigurationName() {
88 return cacheConfigurationName;
89 }
90
91 public void setCacheConfigurationName(String cacheConfigurationName) {
92 this.cacheConfigurationName = cacheConfigurationName;
93 }
94
95 @Override
96 public void init(FilterConfig filterConfig) throws ServletException {
97 super.init(filterConfig);
98 cacheModule.register(this);
99
100 onCacheModuleStart();
101 }
102
103 @Override
104 public void onCacheModuleStart() {
105 if (cacheConfigurationName == null) {
106 log.warn("The cacheConfigurationName property is not set for the {} CacheFilter, falling back to {}.", getName(), DEFAULT_CACHE_CONFIG);
107 this.cacheConfigurationName = DEFAULT_CACHE_CONFIG;
108 }
109
110 this.cacheConfig = cacheModule.getConfiguration(cacheConfigurationName);
111 this.cache = cacheModule.getCacheFactory().getCache(cacheConfigurationName);
112
113 if(cache instanceof BlockingCache){
114 blockingTimeout = ((BlockingCache)cache).getBlockingTimeout();
115 }
116
117 if (cacheConfig == null || cache == null) {
118 log.error("The " + getName() + " CacheFilter is not properly configured, either cacheConfig(" + cacheConfig + ") or cache(" + cache + ") is null. Check if " + cacheConfigurationName + " is a valid cache configuration name. Will disable temporarily.");
119 setEnabled(false);
120 }
121 }
122
123 protected CacheModule getModule() {
124 return cacheModule;
125 }
126
127 @Override
128 public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
129
130 final AggregationState aggregationState = MgnlContext.getAggregationState();
131 final CachePolicyResult cachePolicyResult;
132 try{
133 cachePolicyResult = cacheConfig.getCachePolicy().shouldCache(cache, aggregationState, cacheConfig.getFlushPolicy());
134 CachePolicyResult.setCurrent(cachePolicyResult);
135 }
136 catch(LockTimeoutException timeout){
137 log.warn("The following URL was blocked for longer than {} seconds and has timed-out. The request has been blocked as another request is already processing the same resource. [url={}]", new Object[]{blockingTimeout/1000, request.getRequestURL()} );
138 throw timeout;
139 }
140
141 log.debug("Cache policy result: {}", cachePolicyResult);
142
143 final CachePolicyResult.CachePolicyBehaviour behaviour = cachePolicyResult.getBehaviour();
144 monitor.logBehavior(behaviour.getName());
145 monitor.logAccess(cachePolicyResult.getCacheKey());
146 final CachePolicyExecutor executor = cacheConfig.getExecutor(behaviour);
147 if (executor == null) {
148 throw new IllegalStateException("Unexpected cache policy result: " + cachePolicyResult);
149 }
150
151 try{
152 final long start = System.currentTimeMillis();
153 executor.processCacheRequest(request, response, chain, cache, cachePolicyResult);
154 final long end = System.currentTimeMillis();
155
156 if(blockingTimeout != -1 && (end-start) >= blockingTimeout){
157 log.warn("The following URL took longer than {} seconds ({} ms) to render. This might cause timeout exceptions on other requests to the same URI. [url={}], [key={}]", new Object[]{blockingTimeout/1000, (end-start), request.getRequestURL(), stripPasswordFromCacheLog(cachePolicyResult.getCacheKey().toString())});
158 }
159 }
160 catch (Throwable th) {
161 if(cachePolicyResult.getBehaviour() == CachePolicyResult.store && cache instanceof BlockingCache){
162 log.error("A request started to cache but failed with an exception ({}). [url={}], [key={}]", new Object[]{ExceptionUtils.getRootCauseMessage(th), request.getRequestURL(), stripPasswordFromCacheLog(cachePolicyResult.getCacheKey().toString())});
163 ((BlockingCache) cache).unlock(cachePolicyResult.getCacheKey());
164 }
165 throw new RuntimeException(th);
166 }
167 }
168
169 public String stripPasswordFromCacheLog(String log){
170 String value = null;
171 if(log != null){
172 value = StringUtils.substringBefore(log, "mgnlUserPSWD");
173 String afterString = StringUtils.substringAfter(log, "mgnlUserPSWD");
174 if(afterString.indexOf(" ") < afterString.indexOf("}")){
175 value = value + StringUtils.substringAfter(afterString, " ");
176 }else{
177 value = value + "}" + StringUtils.substringAfter(afterString, "}");
178 }
179 }
180 return value;
181 }
182 }