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.executor;
35
36 import info.magnolia.context.MgnlContext;
37 import info.magnolia.jcr.util.NodeUtil;
38 import info.magnolia.module.cache.Cache;
39 import info.magnolia.module.cache.CacheModule;
40 import info.magnolia.module.cache.CachePolicy;
41 import info.magnolia.module.cache.CachePolicyResult;
42 import info.magnolia.module.cache.filter.CacheResponseWrapper;
43 import info.magnolia.module.cache.filter.CachedEntry;
44 import info.magnolia.module.cache.filter.CachedError;
45 import info.magnolia.module.cache.filter.CachedRedirect;
46 import info.magnolia.module.cache.filter.ContentCachedEntry;
47 import info.magnolia.module.cache.filter.DelegatingBlobCachedEntry;
48 import info.magnolia.module.cache.filter.InMemoryCachedEntry;
49 import info.magnolia.module.cache.filter.UncacheableEntry;
50
51 import java.io.IOException;
52
53 import javax.inject.Inject;
54 import javax.jcr.Node;
55 import javax.jcr.RepositoryException;
56 import javax.servlet.FilterChain;
57 import javax.servlet.ServletException;
58 import javax.servlet.http.HttpServletRequest;
59 import javax.servlet.http.HttpServletResponse;
60
61
62
63
64 public class Store extends AbstractExecutor {
65
66 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Store.class);
67 private final CacheModule cacheModule;
68
69 @Inject
70 public Store(CacheModule cacheModule) {
71 this.cacheModule = cacheModule;
72 }
73
74 @Override
75 public void processCacheRequest(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Cache cache, CachePolicyResult cachePolicyResult) throws IOException, ServletException {
76
77 CachedEntry cachedEntry = null;
78 final Object key = cachePolicyResult.getCacheKey();
79
80 final CacheResponseWrapperrapper.html#CacheResponseWrapper">CacheResponseWrapper responseWrapper = new CacheResponseWrapper(response, CacheResponseWrapper.DEFAULT_THRESHOLD, false);
81 responseWrapper.setResponseExpirationDetectionEnabled();
82
83
84 final long cacheStorageDate = System.currentTimeMillis();
85 responseWrapper.setDateHeader("Last-Modified", cacheStorageDate);
86
87 try {
88 chain.doFilter(request, responseWrapper);
89 if (responseWrapper.getStatus() == HttpServletResponse.SC_NOT_MODIFIED) {
90 response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
91 } else {
92 responseWrapper.flushBuffer();
93 cachedEntry = makeCachedEntry(request, responseWrapper, cache, cachePolicyResult);
94 if (cachedEntry.getTimeToLiveInSeconds() == 0) {
95 cachedEntry = new UncacheableEntry(cachedEntry);
96 }
97 }
98
99 } catch (IOException e) {
100 responseWrapper.cleanUp();
101 throw e;
102 } catch (ServletException e) {
103 responseWrapper.cleanUp();
104 throw e;
105 } catch (Throwable e) {
106 responseWrapper.cleanUp();
107 throw new RuntimeException("Failed to process request with: " + e.getMessage(), e);
108 }
109
110 if (cachedEntry == null) {
111
112 cache.put(key, null);
113 return;
114 }
115
116 int timeToLiveInSeconds = cachedEntry.getTimeToLiveInSeconds();
117 cachePolicyResult.setCachedEntry(cachedEntry);
118
119 if (timeToLiveInSeconds == -1) {
120 cache.put(key, cachedEntry);
121 } else {
122 cache.put(key, cachedEntry, timeToLiveInSeconds);
123 }
124
125
126 final Node content = MgnlContext.getAggregationState().getMainContentNode();
127 try {
128 if (content != null && NodeUtil.isNodeType(content, "mix:referenceable")) {
129 final String uuid = content.getIdentifier();
130 String repo = content.getSession().getWorkspace().getName();
131 getCachePolicy(cache).persistCacheKey(repo, uuid, key);
132 }
133 } catch (RepositoryException e) {
134
135 responseWrapper.cleanUp();
136 throw new RuntimeException(e);
137 }
138 }
139
140 protected CachedEntry makeCachedEntry(HttpServletRequest request, CacheResponseWrapper cachedResponse, Cache cache, CachePolicyResult cachePolicyResult) throws IOException {
141
142 final String originalUrl = request.getRequestURL().toString();
143 int status = cachedResponse.getStatus();
144 int timeToLiveInSeconds = this.getTimeToLive(cachedResponse, cache);
145
146
147 if (cachedResponse.getRedirectionLocation() != null) {
148 return new CachedRedirect(cachedResponse.getStatus(), cachedResponse.getRedirectionLocation(), originalUrl, timeToLiveInSeconds);
149 }
150
151 if (cachedResponse.isError()) {
152 return new CachedError(cachedResponse.getStatus(), originalUrl, timeToLiveInSeconds);
153 }
154
155 final long modificationDate = cachedResponse.getLastModified();
156 final String contentType = cachedResponse.getContentType();
157
158 ContentCachedEntry cacheEntry;
159 if (!cachedResponse.isThresholdExceeded()) {
160 cacheEntry = new InMemoryCachedEntry(cachedResponse.getBufferedContent(),
161 contentType,
162 cachedResponse.getCharacterEncoding(),
163 status,
164 cachedResponse.getHeaders(),
165 modificationDate,
166 originalUrl,
167 timeToLiveInSeconds);
168 } else {
169 cacheEntry = new DelegatingBlobCachedEntry(cachedResponse.getContentLength(),
170 contentType,
171 cachedResponse.getCharacterEncoding(),
172 status,
173 cachedResponse.getHeaders(),
174 modificationDate,
175 originalUrl,
176 timeToLiveInSeconds);
177
178
179
180 ((DelegatingBlobCachedEntry) cacheEntry).bindContentFileToCurrentRequest(request, cachedResponse.getContentFile());
181 cachedResponse.getThresholdingOutputStream().close();
182 }
183 return cacheEntry;
184 }
185
186 protected int getTimeToLive(CacheResponseWrapper cachedResponse, Cache cache) {
187 return this.getCachePolicy(cache).getTtlVoters().vote(cachedResponse);
188 }
189
190 protected CachePolicy getCachePolicy(Cache cache) {
191 return cacheModule.getContentCaching(cache.getName()).getCachePolicy();
192 }
193 }