1 24 package org.riotfamily.cachius.spring; 25 26 import javax.servlet.http.HttpServletRequest ; 27 import javax.servlet.http.HttpServletResponse ; 28 29 import org.apache.commons.logging.Log; 30 import org.apache.commons.logging.LogFactory; 31 import org.riotfamily.cachius.Cache; 32 import org.riotfamily.cachius.CacheItem; 33 import org.riotfamily.cachius.CachiusResponseWrapper; 34 import org.riotfamily.cachius.ItemUpdater; 35 import org.riotfamily.cachius.support.SessionUtils; 36 import org.riotfamily.common.web.view.ViewResolverHelper; 37 import org.springframework.beans.factory.DisposableBean; 38 import org.springframework.context.ApplicationContext; 39 import org.springframework.context.ApplicationContextAware; 40 import org.springframework.core.Ordered; 41 import org.springframework.web.servlet.HandlerAdapter; 42 import org.springframework.web.servlet.ModelAndView; 43 import org.springframework.web.servlet.View; 44 import org.springframework.web.servlet.mvc.LastModified; 45 46 62 public class CacheableControllerHandlerAdapter implements HandlerAdapter, 63 DisposableBean, ApplicationContextAware, Ordered { 64 65 private Log log = LogFactory.getLog(CacheableControllerHandlerAdapter.class); 66 67 private Cache cache; 68 69 private ViewResolverHelper viewResolverHelper; 70 71 private int order = 0; 72 73 private boolean enabled = true; 74 75 public CacheableControllerHandlerAdapter(Cache cache) { 76 this.cache = cache; 77 } 78 79 85 public void setEnabled(boolean enabled) { 86 this.enabled = enabled; 87 } 88 89 92 public int getOrder() { 93 return this.order; 94 } 95 96 99 public void setOrder(int order) { 100 this.order = order; 101 } 102 103 public void setApplicationContext(ApplicationContext context) { 104 viewResolverHelper = new ViewResolverHelper(context); 105 } 106 107 111 public void destroy() { 112 cache.persist(); 113 } 114 115 119 public boolean supports(Object handler) { 120 return enabled && handler instanceof CacheableController; 121 } 122 123 129 public ModelAndView handle(HttpServletRequest request, 130 HttpServletResponse response, Object handler) throws Exception { 131 132 CacheableController controller = (CacheableController) handler; 133 String cacheKey = controller.getCacheKey(request); 134 CacheItem cacheItem = getCacheItem(cacheKey, request); 135 if (cacheItem == null) { 136 log.debug("No cacheItem - Response won't be cached"); 137 return controller.handleRequest(request, response); 138 } 139 140 if (isUpToDate(cacheItem, controller, request)) { 141 cacheItem.writeTo(request, response); 142 return null; 143 } 144 else { 145 return handleRequestAndUpdateCacheItem(request, response, 146 controller, cacheItem); 147 } 148 } 149 150 protected ModelAndView handleRequestAndUpdateCacheItem( 151 HttpServletRequest request, HttpServletResponse response, 152 CacheableController controller, CacheItem cacheItem) 153 throws Exception { 154 155 ItemUpdater update = new ItemUpdater(cacheItem, request); 156 CachiusResponseWrapper wrapper = new CachiusResponseWrapper( 157 response, update); 158 159 ModelAndView mv = controller.handleRequest(request, wrapper); 160 if (mv == null) { 161 wrapper.flushBuffer(); 162 update.updateCacheItem(); 163 return null; 164 } 165 else { 166 View view = viewResolverHelper.resolveView(request, mv); 167 View cachingView = new CachingView(view, wrapper, update); 168 return new ModelAndView(cachingView, mv.getModel()); 169 } 170 } 171 172 protected CacheItem getCacheItem(String cacheKey, 173 HttpServletRequest request) { 174 175 if (cacheKey == null) { 176 log.debug("Cache key is null - Response won't be cached."); 177 return null; 178 } 179 180 boolean encodedUrls = SessionUtils.urlsNeedEncoding(request); 181 if (encodedUrls) { 182 cacheKey += ";jsessionid"; 183 } 184 185 log.debug("Getting cache item for key " + cacheKey); 186 CacheItem cacheItem = cache.getItem(cacheKey); 187 if (cacheItem == null) { 188 log.warn("Failed to create cache item"); 189 } 190 else if (cacheItem.isNew() || !cacheItem.exists()) { 191 cacheItem.setFilterSessionId(encodedUrls); 192 } 193 return cacheItem; 194 } 195 196 207 protected boolean isUpToDate(CacheItem cacheItem, 208 CacheableController controller, HttpServletRequest request) 209 throws Exception { 210 211 if (cacheItem.isNew() || !cacheItem.exists()) { 214 log.debug("Item is new or has been invalidated"); 215 return false; 216 } 217 218 long now = System.currentTimeMillis(); 219 long ttl = controller.getTimeToLive(); 220 if (ttl == CacheableController.CACHE_ETERNALLY) { 221 log.debug("Item is cached eternally"); 222 return true; 223 } 224 if (cacheItem.getLastCheck() + ttl < now) { 225 long mtime = controller.getLastModified(request); 226 log.debug("Last modified: " + mtime); 227 cacheItem.setLastCheck(now); 228 if (mtime > cacheItem.getLastModified()) { 229 cacheItem.setLastModified(now); 233 return false; 234 } 235 } 236 else if (log.isDebugEnabled()) { 237 log.debug("Item not expired yet, will live for another " + 238 (ttl - (now - cacheItem.getLastCheck())) + " ms."); 239 } 240 return true; 241 } 242 243 246 public long getLastModified(HttpServletRequest request, Object handler) { 247 if (handler instanceof LastModified) { 248 CacheableController controller = (CacheableController) handler; 249 String cacheKey = controller.getCacheKey(request); 250 CacheItem cacheItem = getCacheItem(cacheKey, request); 251 if (cacheItem != null) { 252 if (!cacheItem.isNew()) { 253 long now = System.currentTimeMillis(); 254 long ttl = controller.getTimeToLive(); 255 if (ttl == CacheableController.CACHE_ETERNALLY 256 || cacheItem.getLastCheck() + ttl <= now) { 257 258 return cacheItem.getLastModified(); 259 } 260 } 261 try { 262 return controller.getLastModified(request); 263 } 264 catch (Exception e) { 265 log.error("Error invoking the last-modified method", e); 266 } 267 } 268 } 269 return -1L; 270 } 271 272 } | Popular Tags |