1 /*
2 * Copyright (c) 2002-2007 by OpenSymphony
3 * All rights reserved.
4 */
5 package com.opensymphony.oscache.web.filter;
6
7 import com.opensymphony.oscache.base.Cache;
8 import com.opensymphony.oscache.base.Config;
9 import com.opensymphony.oscache.base.EntryRefreshPolicy;
10 import com.opensymphony.oscache.base.NeedsRefreshException;
11 import com.opensymphony.oscache.util.ClassLoaderUtil;
12 import com.opensymphony.oscache.util.StringUtil;
13 import com.opensymphony.oscache.web.ServletCacheAdministrator;
14
15 import org.apache.commons.logging.Log;
16 import org.apache.commons.logging.LogFactory;
17
18 import java.io.IOException;
19 import java.util.List;
20 import java.util.Properties;
21
22 import javax.servlet;
23 import javax.servlet.http.HttpServletRequest;
24 import javax.servlet.http.HttpServletResponse;
25 import javax.servlet.jsp.PageContext;
26
27 /**
28 * CacheFilter is a filter that allows for server-side caching of post-processed servlet content.<p>
29 *
30 * It also gives great programatic control over refreshing, flushing and updating the cache.<p>
31 *
32 * @author <a href="mailto:sergek [ AT ] lokitech.com">Serge Knystautas</a>
33 * @author <a href="mailto:mike [ AT ] atlassian.com">Mike Cannon-Brookes</a>
34 * @author <a href="mailto:ltorunski [ AT ] t-online.de">Lars Torunski</a>
35 * @version $Revision: 434 $
36 */
37 public class CacheFilter implements Filter, ICacheKeyProvider, ICacheGroupsProvider {
38 // Header
39 public static final String HEADER_LAST_MODIFIED = "Last-Modified";
40 public static final String HEADER_CONTENT_TYPE = "Content-Type";
41 public static final String HEADER_CONTENT_ENCODING = "Content-Encoding";
42 public static final String HEADER_EXPIRES = "Expires";
43 public static final String HEADER_IF_MODIFIED_SINCE = "If-Modified-Since";
44 public static final String HEADER_CACHE_CONTROL = "Cache-Control";
45 public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
46
47 // Fragment parameter
48 public static final int FRAGMENT_AUTODETECT = -1;
49 public static final int FRAGMENT_NO = 0;
50 public static final int FRAGMENT_YES = 1;
51
52 // No cache parameter
53 public static final int NOCACHE_OFF = 0;
54 public static final int NOCACHE_SESSION_ID_IN_URL = 1;
55
56 // Last Modified parameter
57 public static final long LAST_MODIFIED_OFF = 0;
58 public static final long LAST_MODIFIED_ON = 1;
59 public static final long LAST_MODIFIED_INITIAL = -1;
60
61 // Expires parameter
62 public static final long EXPIRES_OFF = 0;
63 public static final long EXPIRES_ON = 1;
64 public static final long EXPIRES_TIME = -1;
65
66 // Cache Control
67 public static final long MAX_AGE_NO_INIT = Long.MIN_VALUE;
68 public static final long MAX_AGE_TIME = Long.MAX_VALUE;
69
70 // request attribute to avoid reentrance
71 private final static String REQUEST_FILTERED = "__oscache_filtered__";
72 private String requestFiltered;
73
74 // the policy for the expires header
75 private EntryRefreshPolicy expiresRefreshPolicy;
76
77 // the logger
78 private final Log log = LogFactory.getLog(this.getClass());
79
80 // filter variables
81 private FilterConfig config;
82 private ServletCacheAdministrator admin = null;
83 private int cacheScope = PageContext.APPLICATION_SCOPE; // filter scope - default is APPLICATION
84 private int fragment = FRAGMENT_AUTODETECT; // defines if this filter handles fragments of a page - default is auto detect
85 private int time = 60 * 60; // time before cache should be refreshed - default one hour (in seconds)
86 private String cron = null; // A cron expression that determines when this cached content will expire - default is null
87 private int nocache = NOCACHE_OFF; // defines special no cache option for the requests - default is off
88 private long lastModified = LAST_MODIFIED_INITIAL; // defines if the last-modified-header will be sent - default is intial setting
89 private long expires = EXPIRES_ON; // defines if the expires-header will be sent - default is on
90 private long cacheControlMaxAge = -60; // defines which max-age in Cache-Control to be set - default is 60 seconds for max-age
91 private ICacheKeyProvider cacheKeyProvider = this; // the provider of the cache key - default is the CacheFilter itselfs
92 private ICacheGroupsProvider cacheGroupsProvider = this; // the provider of the cache groups - default is the CacheFilter itselfs
93 private List disableCacheOnMethods = null; // caching can be disabled by defining the http methods - default is off
94
95 /**
96 * Filter clean-up
97 */
98 public void destroy() {
99 //Not much to do...
100 }
101
102 /**
103 * The doFilter call caches the response by wrapping the <code>HttpServletResponse</code>
104 * object so that the output stream can be caught. This works by splitting off the output
105 * stream into two with the {@link SplitServletOutputStream} class. One stream gets written
106 * out to the response as normal, the other is fed into a byte array inside a {@link ResponseContent}
107 * object.
108 *
109 * @param request The servlet request
110 * @param response The servlet response
111 * @param chain The filter chain
112 * @throws ServletException IOException
113 */
114 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
115 if (log.isInfoEnabled()) {
116 log.info("OSCache: filter in scope " + cacheScope);
117 }
118
119 // avoid reentrance (CACHE-128) and check if request is cacheable
120 if (isFilteredBefore(request) || !isCacheableInternal(request)) {
121 chain.doFilter(request, response);
122 return;
123 }
124 request.setAttribute(requestFiltered, Boolean.TRUE);
125
126 HttpServletRequest httpRequest = (HttpServletRequest) request;
127
128 // checks if the response will be a fragment of a page
129 boolean fragmentRequest = isFragment(httpRequest);
130
131 // avoid useless session creation for application scope pages (CACHE-129)
132 Cache cache;
133 if (cacheScope == PageContext.SESSION_SCOPE) {
134 cache = admin.getSessionScopeCache(httpRequest.getSession(true));
135 } else {
136 cache = admin.getAppScopeCache(config.getServletContext());
137 }
138
139 // generate the cache entry key
140 String key = cacheKeyProvider.createCacheKey(httpRequest, admin, cache);
141
142 try {
143 ResponseContent respContent = (ResponseContent) cache.getFromCache(key, time, cron);
144
145 if (log.isInfoEnabled()) {
146 log.info("OSCache: Using cached entry for " + key);
147 }
148
149 boolean acceptsGZip = false;
150 if ((!fragmentRequest) && (lastModified != LAST_MODIFIED_OFF)) {
151 long clientLastModified = httpRequest.getDateHeader(HEADER_IF_MODIFIED_SINCE); // will return -1 if no header...
152
153 // only reply with SC_NOT_MODIFIED
154 // if the client has already the newest page and the response isn't a fragment in a page
155 if ((clientLastModified != -1) && (clientLastModified >= respContent.getLastModified())) {
156 ((HttpServletResponse) response).setStatus(HttpServletResponse.SC_NOT_MODIFIED);
157 return;
158 }
159
160 acceptsGZip = respContent.isContentGZiped() && acceptsGZipEncoding(httpRequest);
161 }
162
163 respContent.writeTo(response, fragmentRequest, acceptsGZip);
164 // acceptsGZip is used for performance reasons above; use the following line for CACHE-49
165 // respContent.writeTo(response, fragmentRequest, acceptsGZipEncoding(httpRequest));
166 } catch (NeedsRefreshException nre) {
167 boolean updateSucceeded = false;
168
169 try {
170 if (log.isInfoEnabled()) {
171 log.info("OSCache: New cache entry, cache stale or cache scope flushed for " + key);
172 }
173
174 CacheHttpServletResponseWrapper cacheResponse = new CacheHttpServletResponseWrapper((HttpServletResponse) response, fragmentRequest, time * 1000L, lastModified, expires, cacheControlMaxAge);
175 chain.doFilter(request, cacheResponse);
176 cacheResponse.flushBuffer();
177
178 // Only cache if the response is cacheable
179 if (isCacheableInternal(cacheResponse)) {
180 // get the cache groups of the content
181 String[] groups = cacheGroupsProvider.createCacheGroups(httpRequest, admin, cache);
182 // Store as the cache content the result of the response
183 cache.putInCache(key, cacheResponse.getContent(), groups, expiresRefreshPolicy, null);
184 updateSucceeded = true;
185 if (log.isInfoEnabled()) {
186 log.info("OSCache: New entry added to the cache with key " + key);
187 }
188 }
189 } finally {
190 if (!updateSucceeded) {
191 cache.cancelUpdate(key);
192 }
193 }
194 }
195 }
196
197 /**
198 * Initialize the filter. This retrieves a {@link ServletCacheAdministrator}
199 * instance and configures the filter based on any initialization parameters.<p>
200 * The supported initialization parameters are:
201 * <ul>
202 *
203 * <li><b>oscache-properties-file</b> - the properties file that contains the OSCache configuration
204 * options to be used by the Cache that this Filter should use.</li>
205 *
206 * @param filterConfig The filter configuration
207 */
208 public void init(FilterConfig filterConfig) {
209 // Get whatever settings we want...
210 config = filterConfig;
211
212 log.info("OSCache: Initializing CacheFilter with filter name " + config.getFilterName());
213
214 // setting the request filter to avoid reentrance with the same filter
215 requestFiltered = REQUEST_FILTERED + config.getFilterName();
216 log.info("Request filter attribute is " + requestFiltered);
217
218 // filter Properties file
219 Properties props = null;
220 try {
221 String propertiesfile = config.getInitParameter("oscache-properties-file");
222
223 if (propertiesfile != null && propertiesfile.length() > 0) {
224 props = Config.loadProperties(propertiesfile, "CacheFilter with filter name '" + config.getFilterName()+ "'");
225 }
226 } catch (Exception e) {
227 log.info("OSCache: Init parameter 'oscache-properties-file' not set, using default.");
228 }
229 admin = ServletCacheAdministrator.getInstance(config.getServletContext(), props);
230
231 // filter parameter time
232 String timeParam = config.getInitParameter("time");
233 if (timeParam != null) {
234 try {
235 setTime(Integer.parseInt(timeParam));
236 } catch (NumberFormatException nfe) {
237 log.error("OSCache: Unexpected value for the init parameter 'time', defaulting to one hour. Message=" + nfe.getMessage());
238 }
239 }
240
241 // filter parameter scope
242 String scopeParam = config.getInitParameter("scope");
243 if (scopeParam != null) {
244 if ("session".equalsIgnoreCase(scopeParam)) {
245 setCacheScope(PageContext.SESSION_SCOPE);
246 } else if ("application".equalsIgnoreCase(scopeParam)) {
247 setCacheScope(PageContext.APPLICATION_SCOPE);
248 } else {
249 log.error("OSCache: Wrong value '" + scopeParam + "' for init parameter 'scope', defaulting to 'application'.");
250 }
251
252 }
253
254 // filter parameter cron
255 setCron(config.getInitParameter("cron"));
256
257 // filter parameter fragment
258 String fragmentParam = config.getInitParameter("fragment");
259 if (fragmentParam != null) {
260 if ("no".equalsIgnoreCase(fragmentParam)) {
261 setFragment(FRAGMENT_NO);
262 } else if ("yes".equalsIgnoreCase(fragmentParam)) {
263 setFragment(FRAGMENT_YES);
264 } else if ("auto".equalsIgnoreCase(fragmentParam)) {
265 setFragment(FRAGMENT_AUTODETECT);
266 } else {
267 log.error("OSCache: Wrong value '" + fragmentParam + "' for init parameter 'fragment', defaulting to 'auto detect'.");
268 }
269 }
270
271 // filter parameter nocache
272 String nocacheParam = config.getInitParameter("nocache");
273 if (nocacheParam != null) {
274 if ("off".equalsIgnoreCase(nocacheParam)) {
275 nocache = NOCACHE_OFF;
276 } else if ("sessionIdInURL".equalsIgnoreCase(nocacheParam)) {
277 nocache = NOCACHE_SESSION_ID_IN_URL;
278 } else {
279 log.error("OSCache: Wrong value '" + nocacheParam + "' for init parameter 'nocache', defaulting to 'off'.");
280 }
281 }
282
283 // filter parameter last modified
284 String lastModifiedParam = config.getInitParameter("lastModified");
285 if (lastModifiedParam != null) {
286 if ("off".equalsIgnoreCase(lastModifiedParam)) {
287 lastModified = LAST_MODIFIED_OFF;
288 } else if ("on".equalsIgnoreCase(lastModifiedParam)) {
289 lastModified = LAST_MODIFIED_ON;
290 } else if ("initial".equalsIgnoreCase(lastModifiedParam)) {
291 lastModified = LAST_MODIFIED_INITIAL;
292 } else {
293 log.error("OSCache: Wrong value '" + lastModifiedParam + "' for init parameter 'lastModified', defaulting to 'initial'.");
294 }
295 }
296
297 // filter parameter expires
298 String expiresParam = config.getInitParameter("expires");
299 if (expiresParam != null) {
300 if ("off".equalsIgnoreCase(expiresParam)) {
301 setExpires(EXPIRES_OFF);
302 } else if ("on".equalsIgnoreCase(expiresParam)) {
303 setExpires(EXPIRES_ON);
304 } else if ("time".equalsIgnoreCase(expiresParam)) {
305 setExpires(EXPIRES_TIME);
306 } else {
307 log.error("OSCache: Wrong value '" + expiresParam + "' for init parameter 'expires', defaulting to 'on'.");
308 }
309 }
310
311 // filter parameter Cache-Control
312 String cacheControlMaxAgeParam = config.getInitParameter("max-age");
313 if (cacheControlMaxAgeParam != null) {
314 if (cacheControlMaxAgeParam.equalsIgnoreCase("no init")) {
315 setCacheControlMaxAge(MAX_AGE_NO_INIT);
316 } else if (cacheControlMaxAgeParam.equalsIgnoreCase("time")) {
317 setCacheControlMaxAge(MAX_AGE_TIME);
318 } else {
319 try {
320 setCacheControlMaxAge(Long.parseLong(cacheControlMaxAgeParam));
321 } catch (NumberFormatException nfe) {
322 log.error("OSCache: Unexpected value for the init parameter 'max-age', defaulting to '60'. Message=" + nfe.getMessage());
323 }
324 }
325 }
326
327 // filter parameter ICacheKeyProvider
328 ICacheKeyProvider cacheKeyProviderParam = (ICacheKeyProvider)instantiateFromInitParam("ICacheKeyProvider", ICacheKeyProvider.class, this.getClass().getName());
329 if (cacheKeyProviderParam != null) {
330 setCacheKeyProvider(cacheKeyProviderParam);
331 }
332
333 // filter parameter ICacheGroupsProvider
334 ICacheGroupsProvider cacheGroupsProviderParam = (ICacheGroupsProvider)instantiateFromInitParam("ICacheGroupsProvider", ICacheGroupsProvider.class, this.getClass().getName());
335 if (cacheGroupsProviderParam != null) {
336 setCacheGroupsProvider(cacheGroupsProviderParam);
337 }
338
339 // filter parameter EntryRefreshPolicy
340 EntryRefreshPolicy expiresRefreshPolicyParam = (EntryRefreshPolicy)instantiateFromInitParam("EntryRefreshPolicy", EntryRefreshPolicy.class, ExpiresRefreshPolicy.class.getName());
341 if (expiresRefreshPolicyParam != null) {
342 setExpiresRefreshPolicy(expiresRefreshPolicyParam);
343 } else {
344 // setting the refresh period for this cache filter
345 setExpiresRefreshPolicy(new ExpiresRefreshPolicy(time));
346 }
347
348 // filter parameter scope
349 String disableCacheOnMethodsParam = config.getInitParameter("disableCacheOnMethods");
350 if (StringUtil.hasLength(disableCacheOnMethodsParam)) {
351 disableCacheOnMethods = StringUtil.split(disableCacheOnMethodsParam, ',');
352 // log.error("OSCache: Wrong value '" + disableCacheOnMethodsParam + "' for init parameter 'disableCacheOnMethods', defaulting to 'null'.");
353 }
354
355 }
356
357 private Object instantiateFromInitParam(String classInitParam, Class interfaceClass, String defaultObjectName) {
358 String className = config.getInitParameter(classInitParam);
359 if (className != null) {
360 try {
361 Class clazz = ClassLoaderUtil.loadClass(className, this.getClass());
362 if (!interfaceClass.isAssignableFrom(clazz)) {
363 log.error("OSCache: Specified class '" + className + "' does not implement" + interfaceClass.getName() + ". Using default " + defaultObjectName + ".");
364 return null;
365 } else {
366 return clazz.newInstance();
367 }
368 } catch (ClassNotFoundException e) {
369 log.error("OSCache: Class '" + className + "' not found. Defaulting to " + defaultObjectName + ".", e);
370 } catch (InstantiationException e) {
371 log.error("OSCache: Class '" + className + "' could not be instantiated because it is not a concrete class. Using default object " + defaultObjectName + ".", e);
372 } catch (IllegalAccessException e) {
373 log.error("OSCache: Class '"+ className+ "' could not be instantiated because it is not public. Using default object " + defaultObjectName + ".", e);
374 }
375 }
376 return null;
377 }
378
379 /**
380 * {@link ICacheKeyProvider}
381 * @see com.opensymphony.oscache.web.filter.ICacheKeyProvider#createCacheKey(javax.servlet.http.HttpServletRequest, ServletCacheAdministrator, Cache)
382 */
383 public String createCacheKey(HttpServletRequest httpRequest, ServletCacheAdministrator scAdmin, Cache cache) {
384 return scAdmin.generateEntryKey(null, httpRequest, cacheScope);
385 }
386
387 /**
388 * {@link ICacheGroupsProvider}
389 * @see com.opensymphony.oscache.web.filter.ICacheGroupsProvider#createCacheGroups(javax.servlet.http.HttpServletRequest, ServletCacheAdministrator, Cache)
390 */
391 public String[] createCacheGroups(HttpServletRequest httpRequest, ServletCacheAdministrator scAdmin, Cache cache) {
392 return null;
393 }
394
395 /**
396 * Checks if the request is a fragment in a page.
397 *
398 * According to Java Servlet API 2.2 (8.2.1 Dispatching Requests, Included
399 * Request Parameters), when a servlet is being used from within an include,
400 * the attribute <code>javax.servlet.include.request_uri</code> is set.
401 * According to Java Servlet API 2.3 this is excepted for servlets obtained
402 * by using the getNamedDispatcher method.
403 *
404 * @param request the to be handled request
405 * @return true if the request is a fragment in a page
406 */
407 public boolean isFragment(HttpServletRequest request) {
408 if (fragment == FRAGMENT_AUTODETECT) {
409 return request.getAttribute("javax.servlet.include.request_uri") != null;
410 } else {
411 return (fragment == FRAGMENT_NO) ? false : true;
412 }
413 }
414
415 /**
416 * Checks if the request was filtered before, so
417 * guarantees to be executed once per request. You
418 * can override this methods to define a more specific
419 * behaviour.
420 *
421 * @param request checks if the request was filtered before.
422 * @return true if it is the first execution
423 */
424 public boolean isFilteredBefore(ServletRequest request) {
425 return request.getAttribute(requestFiltered) != null;
426 }
427
428 /*
429 * isCacheableInternal gurarantees that the log information is correct.
430 *
431 * @param request The servlet request
432 * @return Returns a boolean indicating if the request can be cached or not.
433 */
434 private final boolean isCacheableInternal(ServletRequest request) {
435 final boolean cacheable = isCacheable(request);
436
437 if (log.isDebugEnabled()) {
438 log.debug("OSCache: the request " + ((cacheable) ? "is" : "is not") + " cachable.");
439 }
440
441 return cacheable;
442 }
443
444 /**
445 * isCacheable is a method allowing a subclass to decide if a request is
446 * cachable or not.
447 *
448 * @param request The servlet request
449 * @return Returns a boolean indicating if the request can be cached or not.
450 */
451 public boolean isCacheable(ServletRequest request) {
452 boolean cacheable = request instanceof HttpServletRequest;
453
454 if (cacheable) {
455 HttpServletRequest requestHttp = (HttpServletRequest) request;
456 // CACHE-272 don't cache special http request methods
457 if ((disableCacheOnMethods != null) && (disableCacheOnMethods.contains(requestHttp.getMethod()))) {
458 return false;
459 }
460 if (nocache == NOCACHE_SESSION_ID_IN_URL) { // don't cache requests if session id is in the URL
461 cacheable = !requestHttp.isRequestedSessionIdFromURL();
462 }
463 }
464
465 return cacheable;
466 }
467
468 /*
469 * isCacheableInternal gurarantees that the log information is correct.
470 *
471 * @param cacheResponse the HTTP servlet response
472 * @return Returns a boolean indicating if the response can be cached or not.
473 */
474 private final boolean isCacheableInternal(CacheHttpServletResponseWrapper cacheResponse) {
475 final boolean cacheable = isCacheable(cacheResponse);
476
477 if (log.isDebugEnabled()) {
478 log.debug("OSCache: the response " + ((cacheable) ? "is" : "is not") + " cachable.");
479 }
480
481 return cacheable;
482 }
483
484 /**
485 * isCacheable is a method allowing subclass to decide if a response is
486 * cachable or not.
487 *
488 * @param cacheResponse the HTTP servlet response
489 * @return Returns a boolean indicating if the response can be cached or not.
490 */
491 public boolean isCacheable(CacheHttpServletResponseWrapper cacheResponse) {
492 // TODO implement CACHE-137 here
493 // Only cache if the response was 200
494 return cacheResponse.getStatus() == HttpServletResponse.SC_OK;
495 }
496
497 /**
498 * Check if the client browser support gzip compression.
499 *
500 * @param request the http request
501 * @return true if client browser supports GZIP
502 */
503 public boolean acceptsGZipEncoding(HttpServletRequest request) {
504 String acceptEncoding = request.getHeader(HEADER_ACCEPT_ENCODING);
505 return (acceptEncoding != null) && (acceptEncoding.indexOf("gzip") != -1);
506 }
507
508 // ---------------------------------
509 // --- getter and setter methods ---
510 // ---------------------------------
511
512 /**
513 * @return the max-age of the cache control
514 * @since 2.4
515 */
516 public long getCacheControlMaxAge() {
517 if ((cacheControlMaxAge == MAX_AGE_NO_INIT) || (cacheControlMaxAge == MAX_AGE_TIME)) {
518 return cacheControlMaxAge;
519 }
520 return - cacheControlMaxAge;
521 }
522
523 /**
524 * <b>max-age</b> - defines the cache control response header max-age. Acceptable values are
525 * <code>MAX_AGE_NO_INIT</code> for don't initializing the max-age cache control,
526 * <code>MAX_AGE_TIME</code> the max-age information will be based on the time parameter and creation time of the content (expiration timestamp minus current timestamp), and
527 * <code>[positive integer]</code> value constant in seconds to be set in every response, the default value is 60.
528 *
529 * @param cacheControlMaxAge the cacheControlMaxAge to set
530 * @since 2.4
531 */
532 public void setCacheControlMaxAge(long cacheControlMaxAge) {
533 if ((cacheControlMaxAge == MAX_AGE_NO_INIT) || (cacheControlMaxAge == MAX_AGE_TIME)) {
534 this.cacheControlMaxAge = cacheControlMaxAge;
535 } else if (cacheControlMaxAge >= 0) {
536 // declare the cache control as a constant
537 // TODO check if this value can be stored as a positive long without changing it
538 this.cacheControlMaxAge = - cacheControlMaxAge;
539 } else {
540 log.warn("OSCache: 'max-age' must be at least a positive integer, defaulting to '60'. ");
541 this.cacheControlMaxAge = -60;
542 }
543 }
544
545 /**
546 * @return the cacheGroupsProvider
547 * @since 2.4
548 */
549 public ICacheGroupsProvider getCacheGroupsProvider() {
550 return cacheGroupsProvider;
551 }
552
553 /**
554 * <b>ICacheGroupsProvider</b> - Class implementing the interface <code>ICacheGroupsProvider</code>.
555 * A developer can implement a method which provides cache groups based on the request,
556 * the servlect cache administrator and cache. The parameter has to be not <code>null</code>.
557 *
558 * @param cacheGroupsProvider the cacheGroupsProvider to set
559 * @since 2.4
560 */
561 public void setCacheGroupsProvider(ICacheGroupsProvider cacheGroupsProvider) {
562 if (cacheGroupsProvider == null) throw new IllegalArgumentException("The ICacheGroupsProvider is null.");
563 this.cacheGroupsProvider = cacheGroupsProvider;
564 }
565
566 /**
567 * @return the cacheKeyProvider
568 * @since 2.4
569 */
570 public ICacheKeyProvider getCacheKeyProvider() {
571 return cacheKeyProvider;
572 }
573
574 /**
575 * <b>ICacheKeyProvider</b> - Class implementing the interface <code>ICacheKeyProvider</code>.
576 * A developer can implement a method which provides cache keys based on the request,
577 * the servlect cache administrator and cache. The parameter has to be not <code>null</code>.
578 *
579 * @param cacheKeyProvider the cacheKeyProvider to set
580 * @since 2.4
581 */
582 public void setCacheKeyProvider(ICacheKeyProvider cacheKeyProvider) {
583 if (cacheKeyProvider == null) throw new IllegalArgumentException("The ICacheKeyProvider is null.");
584 this.cacheKeyProvider = cacheKeyProvider;
585 }
586
587 /**
588 * Returns PageContext.APPLICATION_SCOPE or PageContext.SESSION_SCOPE.
589 * @return the cache scope
590 * @since 2.4
591 */
592 public int getCacheScope() {
593 return cacheScope;
594 }
595
596 /**
597 * <b>scope</b> - the default scope to cache content. Acceptable values
598 * are <code>PageContext.APPLICATION_SCOPE</code> (default) and <code>PageContext.SESSION_SCOPE</code>.
599 *
600 * @param cacheScope the cacheScope to set
601 * @since 2.4
602 */
603 public void setCacheScope(int cacheScope) {
604 if ((cacheScope != PageContext.APPLICATION_SCOPE) && (cacheScope != PageContext.SESSION_SCOPE))
605 throw new IllegalArgumentException("Acceptable values for cache scope are PageContext.APPLICATION_SCOPE or PageContext.SESSION_SCOPE");
606 this.cacheScope = cacheScope;
607 }
608
609 /**
610 * @return the cron
611 * @since 2.4
612 */
613 public String getCron() {
614 return cron;
615 }
616
617 /**
618 * <b>cron</b> - defines an expression that determines when the page content will expire.
619 * This allows content to be expired at particular dates and/or times, rather than once
620 * a cache entry reaches a certain age.
621 *
622 * @param cron the cron to set
623 * @since 2.4
624 */
625 public void setCron(String cron) {
626 this.cron = cron;
627 }
628
629 /**
630 * @return the expires header
631 * @since 2.4
632 */
633 public long getExpires() {
634 return expires;
635 }
636
637 /**
638 * <b>expires</b> - defines if the expires header will be sent in the response. Acceptable values are
639 * <code>EXPIRES_OFF</code> for don't sending the header, even it is set in the filter chain,
640 * <code>EXPIRES_ON</code> (default) for sending it if it is set in the filter chain and
641 * <code>EXPIRES_TIME</code> the expires information will be intialized based on the time parameter and creation time of the content.
642 *
643 * @param expires the expires to set
644 * @since 2.4
645 */
646 public void setExpires(long expires) {
647 if ((expires < EXPIRES_TIME) || (expires > EXPIRES_ON)) throw new IllegalArgumentException("Expires value out of range.");
648 this.expires = expires;
649 }
650
651 /**
652 * @return the expiresRefreshPolicy
653 * @since 2.4
654 */
655 public EntryRefreshPolicy getExpiresRefreshPolicy() {
656 return expiresRefreshPolicy;
657 }
658
659 /**
660 * <b>EntryRefreshPolicy</b> - Class implementing the interface <code>EntryRefreshPolicy</code>.
661 * A developer can implement a class which provides a different custom cache invalidation policy for a specific cache entry.
662 * If not specified, the default policy is timed entry expiry as specified with the <b>time</b> parameter described above.
663 *
664 * @param expiresRefreshPolicy the expiresRefreshPolicy to set
665 * @since 2.4
666 */
667 public void setExpiresRefreshPolicy(EntryRefreshPolicy expiresRefreshPolicy) {
668 if (expiresRefreshPolicy == null) throw new IllegalArgumentException("The EntryRefreshPolicy is null.");
669 this.expiresRefreshPolicy = expiresRefreshPolicy;
670 }
671
672 /**
673 * @return the fragment
674 * @since 2.4
675 */
676 public int getFragment() {
677 return fragment;
678 }
679
680 /**
681 * <b>fragment</b> - defines if this filter handles fragments of a page. Acceptable values
682 * are <code>FRAGMENT_AUTODETECT</code> (default) for auto detect, <code>FRAGMENT_NO</code> and <code>FRAGMENT_YES</code>.
683 *
684 * @param fragment the fragment to set
685 * @since 2.4
686 */
687 public void setFragment(int fragment) {
688 if ((fragment < FRAGMENT_AUTODETECT) || (fragment > FRAGMENT_YES)) throw new IllegalArgumentException("Fragment value out of range.");
689 this.fragment = fragment;
690 }
691
692 /**
693 * @return the lastModified
694 * @since 2.4
695 */
696 public long getLastModified() {
697 return lastModified;
698 }
699
700 /**
701 * <b>lastModified</b> - defines if the last modified header will be sent in the response. Acceptable values are
702 * <code>LAST_MODIFIED_OFF</code> for don't sending the header, even it is set in the filter chain,
703 * <code>LAST_MODIFIED_ON</code> for sending it if it is set in the filter chain and
704 * <code>LAST_MODIFIED_INITIAL</code> (default) the last modified information will be set based on the current time and changes are allowed.
705 *
706 * @param lastModified the lastModified to set
707 * @since 2.4
708 */
709 public void setLastModified(long lastModified) {
710 if ((lastModified < LAST_MODIFIED_INITIAL) || (lastModified > LAST_MODIFIED_ON)) throw new IllegalArgumentException("LastModified value out of range.");
711 this.lastModified = lastModified;
712 }
713
714 /**
715 * @return the nocache
716 * @since 2.4
717 */
718 public int getNocache() {
719 return nocache;
720 }
721
722 /**
723 * <b>nocache</b> - defines which objects shouldn't be cached. Acceptable values
724 * are <code>NOCACHE_OFF</code> (default) and <code>NOCACHE_SESSION_ID_IN_URL</code> if the session id is
725 * contained in the URL.
726 *
727 * @param nocache the nocache to set
728 * @since 2.4
729 */
730 public void setNocache(int nocache) {
731 if ((nocache < NOCACHE_OFF) || (nocache > NOCACHE_SESSION_ID_IN_URL)) throw new IllegalArgumentException("Nocache value out of range.");
732 this.nocache = nocache;
733 }
734
735 /**
736 * @return the time
737 * @since 2.4
738 */
739 public int getTime() {
740 return time;
741 }
742
743 /**
744 * <b>time</b> - the default time (in seconds) to cache content for. The default
745 * value is 3600 seconds (one hour). Specifying -1 (indefinite expiry) as the cache
746 * time will ensure a content does not become stale until it is either explicitly
747 * flushed or the expires refresh policy causes the entry to expire.
748 *
749 * @param time the time to set
750 * @since 2.4
751 */
752 public void setTime(int time) {
753 this.time = time;
754 // check if ExpiresRefreshPolicy has to be reset
755 if (expiresRefreshPolicy instanceof ExpiresRefreshPolicy) {
756 ((ExpiresRefreshPolicy) expiresRefreshPolicy).setRefreshPeriod(time);
757 }
758 }
759
760 /**
761 * @link http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/http/HttpServletRequest.html#getMethod()
762 * @return the list of http method names for which cacheing should be disabled
763 * @since 2.4
764 */
765 public List getDisableCacheOnMethods() {
766 return disableCacheOnMethods;
767 }
768
769 /**
770 * <b>disableCacheOnMethods</b> - Defines the http method name for which cacheing should be disabled.
771 * The default value is <code>null</code> for cacheing all requests without regarding the method name.
772 * @link http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/http/HttpServletRequest.html#getMethod()
773 * @param disableCacheOnMethods the list of http method names for which cacheing should be disabled
774 * @since 2.4
775 */
776 public void setDisableCacheOnMethods(List disableCacheOnMethods) {
777 this.disableCacheOnMethods = disableCacheOnMethods;
778 }
779
780 // TODO: check if getter/setter for oscache-properties-file is possible
781
782 }