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.exception.ExceptionUtils;
55
56 import net.sf.ehcache.constructs.blocking.LockTimeoutException;
57
58 import java.io.IOException;
59
60
61
62
63
64
65
66
67 public class CacheFilter extends OncePerRequestAbstractMgnlFilter implements CacheModuleLifecycleListener {
68 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CacheFilter.class);
69
70 private static final String DEFAULT_CACHE_CONFIG = "default";
71
72 private final CacheModule cacheModule;
73 private final CacheMonitor monitor;
74 private String cacheConfigurationName;
75 private CacheConfiguration cacheConfig;
76 private Cache cache;
77
78
79 private int blockingTimeout = -1;
80
81 public CacheFilter(CacheModule cacheModule, CacheMonitor cacheMonitor) {
82 this.cacheModule = cacheModule;
83 this.monitor = cacheMonitor;
84 }
85
86 public String getCacheConfigurationName() {
87 return cacheConfigurationName;
88 }
89
90 public void setCacheConfigurationName(String cacheConfigurationName) {
91 this.cacheConfigurationName = cacheConfigurationName;
92 }
93
94 @Override
95 public void init(FilterConfig filterConfig) throws ServletException {
96 super.init(filterConfig);
97 cacheModule.register(this);
98
99 onCacheModuleStart();
100 }
101
102 @Override
103 public void onCacheModuleStart() {
104 if (cacheConfigurationName == null) {
105 log.warn("The cacheConfigurationName property is not set for the {} CacheFilter, falling back to {}.", getName(), DEFAULT_CACHE_CONFIG);
106 this.cacheConfigurationName = DEFAULT_CACHE_CONFIG;
107 }
108
109 this.cacheConfig = cacheModule.getConfiguration(cacheConfigurationName);
110 this.cache = cacheModule.getCacheFactory().getCache(cacheConfigurationName);
111
112 if(cache instanceof BlockingCache){
113 blockingTimeout = ((BlockingCache)cache).getBlockingTimeout();
114 }
115
116 if (cacheConfig == null || cache == null) {
117 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.");
118 setEnabled(false);
119 }
120 }
121
122 protected CacheModule getModule() {
123 return cacheModule;
124 }
125
126 @Override
127 public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
128
129 final AggregationState aggregationState = MgnlContext.getAggregationState();
130 final CachePolicyResult cachePolicyResult;
131 try{
132 cachePolicyResult = cacheConfig.getCachePolicy().shouldCache(cache, aggregationState, cacheConfig.getFlushPolicy());
133 CachePolicyResult.setCurrent(cachePolicyResult);
134 }
135 catch(LockTimeoutException timeout){
136 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()} );
137 throw timeout;
138 }
139
140 log.debug("Cache policy result: {}", cachePolicyResult);
141
142 final CachePolicyResult.CachePolicyBehaviour behaviour = cachePolicyResult.getBehaviour();
143 monitor.logBehavior(behaviour.getName());
144 monitor.logAccess(cachePolicyResult.getCacheKey());
145 final CachePolicyExecutor executor = cacheConfig.getExecutor(behaviour);
146 if (executor == null) {
147 throw new IllegalStateException("Unexpected cache policy result: " + cachePolicyResult);
148 }
149
150 try{
151 final long start = System.currentTimeMillis();
152 executor.processCacheRequest(request, response, chain, cache, cachePolicyResult);
153 final long end = System.currentTimeMillis();
154
155 if(blockingTimeout != -1 && (end-start) >= blockingTimeout){
156 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(), cachePolicyResult.getCacheKey()});
157 }
158 }
159 catch (Throwable th) {
160 if(cachePolicyResult.getBehaviour() == CachePolicyResult.store && cache instanceof BlockingCache){
161 log.error("A request started to cache but failed with an exception ({}). [url={}], [key={}]", new Object[]{ExceptionUtils.getRootCauseMessage(th), request.getRequestURL(), cachePolicyResult.getCacheKey()});
162 ((BlockingCache) cache).unlock(cachePolicyResult.getCacheKey());
163 }
164 throw new RuntimeException(th);
165 }
166 }
167
168 }