View Javadoc

1   /**
2    * This file Copyright (c) 2008-2011 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.module.cache.executor;
35  
36  import info.magnolia.cms.core.Content;
37  import info.magnolia.context.MgnlContext;
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.ContentCachedEntry;
46  import info.magnolia.module.cache.filter.CachedRedirect;
47  import info.magnolia.module.cache.filter.InMemoryCachedEntry;
48  import info.magnolia.module.cache.filter.DelegatingBlobCachedEntry;
49  
50  import java.io.IOException;
51  
52  import javax.servlet.FilterChain;
53  import javax.servlet.ServletException;
54  import javax.servlet.http.HttpServletRequest;
55  import javax.servlet.http.HttpServletResponse;
56  
57  /**
58   * Wraps the response and stores the content in a cache Entry.
59   *
60   * @author pbracher
61   * @version $Revision: $ ($Author: $)
62   */
63  public class Store extends AbstractExecutor {
64  
65      private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Store.class);
66  
67      public void processCacheRequest(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Cache cache, CachePolicyResult cachePolicyResult) throws IOException, ServletException {
68          CachedEntry cachedEntry = null;
69          final Object key = cachePolicyResult.getCacheKey();
70  
71          final CacheResponseWrapper responseWrapper = new CacheResponseWrapper(response, CacheResponseWrapper.DEFAULT_THRESHOLD, false);
72  
73          // setting Last-Modified to when this resource was stored in the cache. This value might get overridden by further filters or servlets.
74          final long cacheStorageDate = System.currentTimeMillis();
75          responseWrapper.setDateHeader("Last-Modified", cacheStorageDate);
76          chain.doFilter(request, responseWrapper);
77  
78          if (responseWrapper.getStatus() == HttpServletResponse.SC_NOT_MODIFIED) {
79              response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
80          }
81          else{
82              responseWrapper.flushBuffer();
83              cachedEntry = makeCachedEntry(request, responseWrapper);
84          }
85  
86          // also put null to unblock the cache
87          cache.put(key, cachedEntry);
88  
89          if(cachedEntry != null){
90              cachePolicyResult.setCachedEntry(cachedEntry);
91              // let policy know the uuid in case it wants to do something with it
92              final Content content = MgnlContext.getAggregationState().getCurrentContent();
93              if (content != null && content.isNodeType("mix:referenceable")) {
94                  final String uuid = content.getUUID();
95                  String repo = content.getHierarchyManager().getName();
96                  getCachePolicy(cache).persistCacheKey(repo, uuid, key);
97              }
98          }
99      }
100 
101     protected CachedEntry makeCachedEntry(HttpServletRequest request, CacheResponseWrapper cachedResponse) throws IOException {
102         // query params are handled by the cache key
103         final String originalUrl = request.getRequestURL().toString();
104         int status = cachedResponse.getStatus();
105         // TODO : handle more of the 30x codes - although CacheResponseWrapper currently only sets the 302 or 304.
106         if (cachedResponse.getRedirectionLocation() != null) {
107             return new CachedRedirect(cachedResponse.getStatus(), cachedResponse.getRedirectionLocation(), originalUrl);
108         }
109 
110         if (cachedResponse.isError()) {
111             return new CachedError(cachedResponse.getStatus(), originalUrl);
112         }
113 
114         final long modificationDate = cachedResponse.getLastModified();
115         final String contentType = cachedResponse.getContentType();
116 
117         ContentCachedEntry cacheEntry;
118         if(!cachedResponse.isThresholdExceeded()){
119             cacheEntry = new InMemoryCachedEntry(cachedResponse.getBufferedContent(),
120                     contentType,
121                     cachedResponse.getCharacterEncoding(),
122                     status,
123                     cachedResponse.getHeaders(),
124                     modificationDate,
125                     originalUrl);
126         }
127         else{
128             cacheEntry = new DelegatingBlobCachedEntry(cachedResponse.getContentLength(),
129                 contentType,
130                 cachedResponse.getCharacterEncoding(),
131                 status,
132                 cachedResponse.getHeaders(),
133                 modificationDate,
134                 originalUrl);
135 
136             // TODO remove this once we use a blob store
137             // the file will be deleted once served in this request
138             ((DelegatingBlobCachedEntry)cacheEntry).bindContentFileToCurrentRequest(request, cachedResponse.getContentFile());
139         }
140 
141         return cacheEntry;
142     }
143 
144     protected CachePolicy getCachePolicy(Cache cache) {
145         return getModule().getConfiguration(cache.getName()).getCachePolicy();
146     }
147 
148     protected CacheModule getModule() {
149         return CacheModule.getInstance();
150     }
151 }