|
|||||||||||||||||||
| Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
| CacheTag.java | 0% | 0% | 0% | 0% |
|
||||||||||||||
| 1 |
/*
|
|
| 2 |
* Copyright (c) 2002-2003 by OpenSymphony
|
|
| 3 |
* All rights reserved.
|
|
| 4 |
*/
|
|
| 5 |
package com.opensymphony.oscache.web.tag;
|
|
| 6 |
|
|
| 7 |
import com.opensymphony.oscache.base.Cache;
|
|
| 8 |
import com.opensymphony.oscache.base.NeedsRefreshException;
|
|
| 9 |
import com.opensymphony.oscache.util.StringUtil;
|
|
| 10 |
import com.opensymphony.oscache.web.ServletCacheAdministrator;
|
|
| 11 |
import com.opensymphony.oscache.web.WebEntryRefreshPolicy;
|
|
| 12 |
|
|
| 13 |
import org.apache.commons.logging.Log;
|
|
| 14 |
import org.apache.commons.logging.LogFactory;
|
|
| 15 |
|
|
| 16 |
import java.io.IOException;
|
|
| 17 |
|
|
| 18 |
import java.util.ArrayList;
|
|
| 19 |
import java.util.List;
|
|
| 20 |
|
|
| 21 |
import javax.servlet.http.HttpServletRequest;
|
|
| 22 |
import javax.servlet.jsp.JspTagException;
|
|
| 23 |
import javax.servlet.jsp.PageContext;
|
|
| 24 |
import javax.servlet.jsp.tagext.BodyTagSupport;
|
|
| 25 |
import javax.servlet.jsp.tagext.TryCatchFinally;
|
|
| 26 |
|
|
| 27 |
/**
|
|
| 28 |
* CacheTag is a tag that allows for server-side caching of post-processed JSP content.<p>
|
|
| 29 |
*
|
|
| 30 |
* It also gives great programatic control over refreshing, flushing and updating the cache.<p>
|
|
| 31 |
*
|
|
| 32 |
* Usage Example:
|
|
| 33 |
* <pre><code>
|
|
| 34 |
* <%@ taglib uri="oscache" prefix="cache" %>
|
|
| 35 |
* <cache:cache key="mycache"
|
|
| 36 |
* scope="application"
|
|
| 37 |
* refresh="false"
|
|
| 38 |
* time="30">
|
|
| 39 |
* jsp content here... refreshed every 30 seconds
|
|
| 40 |
* </cache:cache>
|
|
| 41 |
* </code></pre>
|
|
| 42 |
*
|
|
| 43 |
* @author <a href="mailto:mike@atlassian.com">Mike Cannon-Brookes</a>
|
|
| 44 |
* @author <a href="mailto:tgochenour@peregrine.com">Todd Gochenour</a>
|
|
| 45 |
* @author <a href="mailto:fbeauregard@pyxis-tech.com">Francois Beauregard</a>
|
|
| 46 |
* @author <a href="mailto:abergevin@pyxis-tech.com">Alain Bergevin</a>
|
|
| 47 |
* @version $Revision: 1.4 $
|
|
| 48 |
*/
|
|
| 49 |
public class CacheTag extends BodyTagSupport implements TryCatchFinally { |
|
| 50 |
/**
|
|
| 51 |
* Constants for time computation
|
|
| 52 |
*/
|
|
| 53 |
private final static int SECOND = 1; |
|
| 54 |
private final static int MINUTE = 60 * SECOND; |
|
| 55 |
private final static int HOUR = 60 * MINUTE; |
|
| 56 |
private final static int DAY = 24 * HOUR; |
|
| 57 |
private final static int WEEK = 7 * DAY; |
|
| 58 |
private final static int MONTH = 30 * DAY; |
|
| 59 |
private final static int YEAR = 365 * DAY; |
|
| 60 |
|
|
| 61 |
/**
|
|
| 62 |
* The key under which the tag counter will be stored in the request
|
|
| 63 |
*/
|
|
| 64 |
private final static String CACHE_TAG_COUNTER_KEY = "__oscache_tag_counter"; |
|
| 65 |
|
|
| 66 |
/**
|
|
| 67 |
* Constants for refresh time
|
|
| 68 |
*/
|
|
| 69 |
final static private int ONE_MINUTE = 60; |
|
| 70 |
final static private int ONE_HOUR = 60 * ONE_MINUTE; |
|
| 71 |
final static private int DEFAULT_TIMEOUT = ONE_HOUR; |
|
| 72 |
private static transient Log log = LogFactory.getLog(CacheTag.class); |
|
| 73 |
|
|
| 74 |
/**
|
|
| 75 |
* Cache modes
|
|
| 76 |
*/
|
|
| 77 |
final static private int SILENT_MODE = 1; |
|
| 78 |
|
|
| 79 |
/**
|
|
| 80 |
* A flag to indicate whether a NeedsRefreshException was thrown and
|
|
| 81 |
* the update needs to be cancelled
|
|
| 82 |
*/
|
|
| 83 |
boolean cancelUpdateRequired = false; |
|
| 84 |
private Cache cache = null; |
|
| 85 |
|
|
| 86 |
/**
|
|
| 87 |
* If no groups are specified, the cached content does not get put into any groups
|
|
| 88 |
*/
|
|
| 89 |
private List groups = null; |
|
| 90 |
private ServletCacheAdministrator admin = null; |
|
| 91 |
|
|
| 92 |
/**
|
|
| 93 |
* The actual key to use. This is generated based on the supplied key, scope etc.
|
|
| 94 |
*/
|
|
| 95 |
private String actualKey = null; |
|
| 96 |
|
|
| 97 |
/**
|
|
| 98 |
* The content that was retrieved from cache
|
|
| 99 |
*/
|
|
| 100 |
private String content = null; |
|
| 101 |
|
|
| 102 |
/**
|
|
| 103 |
* The cron expression that is used to expire cache entries at specific dates and/or times.
|
|
| 104 |
*/
|
|
| 105 |
private String cron = null; |
|
| 106 |
|
|
| 107 |
/**
|
|
| 108 |
* if cache key is null, the request URI is used
|
|
| 109 |
*/
|
|
| 110 |
private String key = null; |
|
| 111 |
|
|
| 112 |
/**
|
|
| 113 |
* The ISO-639 language code to distinguish different pages in application scope
|
|
| 114 |
*/
|
|
| 115 |
private String language = null; |
|
| 116 |
|
|
| 117 |
/**
|
|
| 118 |
* Class used to handle the refresh policy logic
|
|
| 119 |
*/
|
|
| 120 |
private String refreshPolicyClass = null; |
|
| 121 |
|
|
| 122 |
/**
|
|
| 123 |
* Parameters that will be passed to the init method of the
|
|
| 124 |
* refresh policy instance.
|
|
| 125 |
*/
|
|
| 126 |
private String refreshPolicyParam = null; |
|
| 127 |
|
|
| 128 |
/**
|
|
| 129 |
* Whether the cache should be refreshed instantly
|
|
| 130 |
*/
|
|
| 131 |
private boolean refresh = false; |
|
| 132 |
|
|
| 133 |
/**
|
|
| 134 |
* used for subtags to tell this tag that we should use the cached version
|
|
| 135 |
*/
|
|
| 136 |
private boolean useBody = true; |
|
| 137 |
|
|
| 138 |
/**
|
|
| 139 |
* The cache mode. Valid values are SILENT_MODE
|
|
| 140 |
*/
|
|
| 141 |
private int mode = 0; |
|
| 142 |
|
|
| 143 |
/**
|
|
| 144 |
* The cache scope to use
|
|
| 145 |
*/
|
|
| 146 |
private int scope = PageContext.APPLICATION_SCOPE; |
|
| 147 |
|
|
| 148 |
/**
|
|
| 149 |
* time (in seconds) before cache should be refreshed
|
|
| 150 |
*/
|
|
| 151 |
private int time = DEFAULT_TIMEOUT; |
|
| 152 |
|
|
| 153 |
/**
|
|
| 154 |
* Set the time this cache entry will be cached for. A date and/or time in
|
|
| 155 |
* either ISO-8601 format or a simple format can be specified. The acceptable
|
|
| 156 |
* syntax for the simple format can be any one of the following:
|
|
| 157 |
*
|
|
| 158 |
* <ul>
|
|
| 159 |
* <li>0 (seconds)
|
|
| 160 |
* <li>0s (seconds)
|
|
| 161 |
* <li>0m (minutes)
|
|
| 162 |
* <li>0h (hours)
|
|
| 163 |
* <li>0d (days)
|
|
| 164 |
* <li>0w (weeks)
|
|
| 165 |
* </ul>
|
|
| 166 |
*
|
|
| 167 |
* @param duration The duration to cache this content (using either the simple
|
|
| 168 |
* or the ISO-8601 format). Passing in a duration of zero will turn off the
|
|
| 169 |
* caching, while a negative value will result in the cached content never
|
|
| 170 |
* expiring (ie, the cached content will always be served as long as it is
|
|
| 171 |
* present).
|
|
| 172 |
*/
|
|
| 173 | 0 |
public void setDuration(String duration) { |
| 174 | 0 |
try {
|
| 175 |
// Try Simple Date Format Duration first because it's faster
|
|
| 176 | 0 |
this.time = parseDuration(duration);
|
| 177 |
} catch (Exception ex) {
|
|
| 178 | 0 |
if (log.isDebugEnabled()) {
|
| 179 | 0 |
log.debug("Failed parsing simple duration format '" + duration + "' (" + ex.getMessage() + "). Trying ISO-8601 format..."); |
| 180 |
} |
|
| 181 |
|
|
| 182 | 0 |
try {
|
| 183 |
// Try ISO-8601 Duration
|
|
| 184 | 0 |
this.time = parseISO_8601_Duration(duration);
|
| 185 |
} catch (Exception ex1) {
|
|
| 186 |
// An invalid duration entered, not much impact.
|
|
| 187 |
// The default timeout will be used
|
|
| 188 | 0 |
log.warn("The requested cache duration '" + duration + "' is invalid (" + ex1.getMessage() + "). Reverting to the default timeout"); |
| 189 | 0 |
this.time = DEFAULT_TIMEOUT;
|
| 190 |
} |
|
| 191 |
} |
|
| 192 |
} |
|
| 193 |
|
|
| 194 |
/**
|
|
| 195 |
* Sets the cron expression that should be used to expire content at specific
|
|
| 196 |
* dates and/or times.
|
|
| 197 |
*/
|
|
| 198 | 0 |
public void setCron(String cron) { |
| 199 | 0 |
this.cron = cron;
|
| 200 |
} |
|
| 201 |
|
|
| 202 |
/**
|
|
| 203 |
* Sets the groups for this cache entry. Any existing groups will
|
|
| 204 |
* be replaced.
|
|
| 205 |
*
|
|
| 206 |
* @param groups A comma-delimited list of groups that the cache entry belongs to.
|
|
| 207 |
*/
|
|
| 208 | 0 |
public void setGroups(String groups) { |
| 209 | 0 |
this.groups = StringUtil.split(groups, ',');
|
| 210 |
} |
|
| 211 |
|
|
| 212 |
/**
|
|
| 213 |
* Adds to the groups for this cache entry.
|
|
| 214 |
*
|
|
| 215 |
* @param group A group to which the cache entry should belong.
|
|
| 216 |
*/
|
|
| 217 | 0 |
void addGroup(String group) {
|
| 218 | 0 |
if (groups == null) { |
| 219 | 0 |
groups = new ArrayList();
|
| 220 |
} |
|
| 221 |
|
|
| 222 | 0 |
groups.add(group); |
| 223 |
} |
|
| 224 |
|
|
| 225 |
/**
|
|
| 226 |
* Set the key for this cache entry.
|
|
| 227 |
*
|
|
| 228 |
* @param key The key for this cache entry.
|
|
| 229 |
*/
|
|
| 230 | 0 |
public void setKey(String key) { |
| 231 | 0 |
this.key = key;
|
| 232 |
} |
|
| 233 |
|
|
| 234 |
/**
|
|
| 235 |
* Set the ISO-639 language code to distinguish different pages in application scope
|
|
| 236 |
*
|
|
| 237 |
* @param language The language code for this cache entry.
|
|
| 238 |
*/
|
|
| 239 | 0 |
public void setLanguage(String language) { |
| 240 | 0 |
this.language = language;
|
| 241 |
} |
|
| 242 |
|
|
| 243 |
/**
|
|
| 244 |
* This method allows the user to programatically decide whether the cached
|
|
| 245 |
* content should be refreshed immediately.
|
|
| 246 |
*
|
|
| 247 |
* @param refresh Whether or not to refresh this cache entry immediately.
|
|
| 248 |
*/
|
|
| 249 | 0 |
public void setRefresh(boolean refresh) { |
| 250 | 0 |
this.refresh = refresh;
|
| 251 |
} |
|
| 252 |
|
|
| 253 |
/**
|
|
| 254 |
* Setting this to <code>true</code> prevents the cache from writing any output
|
|
| 255 |
* to the response, however the JSP content is still cached as normal.
|
|
| 256 |
* @param mode The cache mode to use.
|
|
| 257 |
*/
|
|
| 258 | 0 |
public void setMode(String mode) { |
| 259 | 0 |
if ("silent".equalsIgnoreCase(mode)) { |
| 260 | 0 |
this.mode = SILENT_MODE;
|
| 261 |
} else {
|
|
| 262 | 0 |
this.mode = 0;
|
| 263 |
} |
|
| 264 |
} |
|
| 265 |
|
|
| 266 |
/**
|
|
| 267 |
* Class used to handle the refresh policy logic
|
|
| 268 |
*/
|
|
| 269 | 0 |
public void setRefreshpolicyclass(String refreshPolicyClass) { |
| 270 | 0 |
this.refreshPolicyClass = refreshPolicyClass;
|
| 271 |
} |
|
| 272 |
|
|
| 273 |
/**
|
|
| 274 |
* Parameters that will be passed to the init method of the
|
|
| 275 |
* refresh policy instance.
|
|
| 276 |
*/
|
|
| 277 | 0 |
public void setRefreshpolicyparam(String refreshPolicyParam) { |
| 278 | 0 |
this.refreshPolicyParam = refreshPolicyParam;
|
| 279 |
} |
|
| 280 |
|
|
| 281 |
// ----------- setMethods ------------------------------------------------------
|
|
| 282 |
|
|
| 283 |
/**
|
|
| 284 |
* Set the scope of this cache.
|
|
| 285 |
* <p>
|
|
| 286 |
* @param scope The scope of this cache. Either "application" (default) or "session".
|
|
| 287 |
*/
|
|
| 288 | 0 |
public void setScope(String scope) { |
| 289 | 0 |
if (scope.equalsIgnoreCase(ServletCacheAdministrator.SESSION_SCOPE_NAME)) {
|
| 290 | 0 |
this.scope = PageContext.SESSION_SCOPE;
|
| 291 |
} else {
|
|
| 292 | 0 |
this.scope = PageContext.APPLICATION_SCOPE;
|
| 293 |
} |
|
| 294 |
} |
|
| 295 |
|
|
| 296 |
/**
|
|
| 297 |
* Set the time this cache entry will be cached for (in seconds)
|
|
| 298 |
*
|
|
| 299 |
* @param time The time to cache this content (in seconds). Passing in
|
|
| 300 |
* a time of zero will turn off the caching. A negative value for the
|
|
| 301 |
* time will result in the cached content never expiring (ie, the cached
|
|
| 302 |
* content will always be served if it is present)
|
|
| 303 |
*/
|
|
| 304 | 0 |
public void setTime(int time) { |
| 305 | 0 |
this.time = time;
|
| 306 |
} |
|
| 307 |
|
|
| 308 |
/**
|
|
| 309 |
* This controls whether or not the body of the tag is evaluated or used.<p>
|
|
| 310 |
*
|
|
| 311 |
* It is most often called by the <UseCached /> tag to tell this tag to
|
|
| 312 |
* use the cached content.
|
|
| 313 |
*
|
|
| 314 |
* @see UseCachedTag
|
|
| 315 |
* @param useBody Whether or not to use the cached content.
|
|
| 316 |
*/
|
|
| 317 | 0 |
public void setUseBody(boolean useBody) { |
| 318 | 0 |
if (log.isInfoEnabled()) {
|
| 319 | 0 |
log.info("<cache>: Set useBody to " + useBody);
|
| 320 |
} |
|
| 321 |
|
|
| 322 | 0 |
this.useBody = useBody;
|
| 323 |
} |
|
| 324 |
|
|
| 325 |
/**
|
|
| 326 |
* After the cache body, either update the cache, serve new cached content or
|
|
| 327 |
* indicate an error.
|
|
| 328 |
*
|
|
| 329 |
* @throws JspTagException The standard exception thrown.
|
|
| 330 |
* @return The standard BodyTag return.
|
|
| 331 |
*/
|
|
| 332 | 0 |
public int doAfterBody() throws JspTagException { |
| 333 | 0 |
String body = null;
|
| 334 |
|
|
| 335 | 0 |
try {
|
| 336 |
// if we have a body, and we have not been told to use the cached version
|
|
| 337 | 0 |
if ((bodyContent != null) && (useBody || (time == 0)) && ((body = bodyContent.getString()) != null)) { |
| 338 | 0 |
if ((time != 0) || (refreshPolicyClass != null)) { |
| 339 |
// Instantiate custom refresh policy if needed
|
|
| 340 | 0 |
WebEntryRefreshPolicy policy = null;
|
| 341 |
|
|
| 342 | 0 |
if (refreshPolicyClass != null) { |
| 343 | 0 |
try {
|
| 344 | 0 |
policy = (WebEntryRefreshPolicy) Class.forName(refreshPolicyClass).newInstance(); |
| 345 | 0 |
policy.init(actualKey, refreshPolicyParam); |
| 346 |
} catch (Exception e) {
|
|
| 347 | 0 |
if (log.isInfoEnabled()) {
|
| 348 | 0 |
log.info("<cache>: Problem instantiating or initializing refresh policy : " + refreshPolicyClass);
|
| 349 |
} |
|
| 350 |
} |
|
| 351 |
} |
|
| 352 |
|
|
| 353 | 0 |
if (log.isInfoEnabled()) {
|
| 354 | 0 |
log.info("<cache>: Updating cache entry with new content : " + actualKey);
|
| 355 |
} |
|
| 356 |
|
|
| 357 | 0 |
cancelUpdateRequired = false;
|
| 358 |
|
|
| 359 | 0 |
if ((groups == null) || groups.isEmpty()) { |
| 360 | 0 |
cache.putInCache(actualKey, body, policy); |
| 361 |
} else {
|
|
| 362 | 0 |
String[] groupArray = new String[groups.size()];
|
| 363 | 0 |
groups.toArray(groupArray); |
| 364 | 0 |
cache.putInCache(actualKey, body, groupArray, policy, null);
|
| 365 |
} |
|
| 366 |
} |
|
| 367 |
} |
|
| 368 |
// otherwise if we have been told to use the cached content and we have cached content
|
|
| 369 |
else {
|
|
| 370 | 0 |
if (!useBody && (content != null)) { |
| 371 | 0 |
if (log.isInfoEnabled()) {
|
| 372 | 0 |
log.info("<cache>: Using cached version as instructed, useBody = false : " + actualKey);
|
| 373 |
} |
|
| 374 |
|
|
| 375 | 0 |
body = content; |
| 376 |
} |
|
| 377 |
// either the cached entry is blank and a subtag has said don't useBody, or body is null
|
|
| 378 |
else {
|
|
| 379 | 0 |
if (log.isInfoEnabled()) {
|
| 380 | 0 |
log.info("<cache>: Missing cached content : " + actualKey);
|
| 381 |
} |
|
| 382 |
|
|
| 383 | 0 |
body = "Missing cached content";
|
| 384 |
} |
|
| 385 |
} |
|
| 386 |
|
|
| 387 |
// Only display anything if we're not running in silent mode
|
|
| 388 | 0 |
if (mode != SILENT_MODE) {
|
| 389 | 0 |
bodyContent.clearBody(); |
| 390 | 0 |
bodyContent.write(body); |
| 391 | 0 |
bodyContent.writeOut(bodyContent.getEnclosingWriter()); |
| 392 |
} |
|
| 393 |
} catch (java.io.IOException e) {
|
|
| 394 | 0 |
throw new JspTagException("IO Error: " + e.getMessage()); |
| 395 |
} |
|
| 396 |
|
|
| 397 | 0 |
return SKIP_BODY;
|
| 398 |
} |
|
| 399 |
|
|
| 400 | 0 |
public void doCatch(Throwable throwable) throws Throwable { |
| 401 | 0 |
throw throwable;
|
| 402 |
} |
|
| 403 |
|
|
| 404 |
/**
|
|
| 405 |
* The end tag - clean up variables used.
|
|
| 406 |
*
|
|
| 407 |
* @throws JspTagException The standard exception thrown.
|
|
| 408 |
* @return The standard BodyTag return.
|
|
| 409 |
*/
|
|
| 410 | 0 |
public int doEndTag() throws JspTagException { |
| 411 | 0 |
return EVAL_PAGE;
|
| 412 |
} |
|
| 413 |
|
|
| 414 | 0 |
public void doFinally() { |
| 415 | 0 |
if (cancelUpdateRequired && (actualKey != null)) { |
| 416 | 0 |
cache.cancelUpdate(actualKey); |
| 417 |
} |
|
| 418 |
} |
|
| 419 |
|
|
| 420 |
/**
|
|
| 421 |
* The start of the tag.
|
|
| 422 |
* <p>
|
|
| 423 |
* Grabs the administrator, the cache, the specific cache entry, then decides
|
|
| 424 |
* whether to refresh.
|
|
| 425 |
* <p>
|
|
| 426 |
* If no refresh is needed, this serves the cached content directly.
|
|
| 427 |
*
|
|
| 428 |
* @throws JspTagException The standard exception thrown.
|
|
| 429 |
* @return The standard doStartTag() return.
|
|
| 430 |
*/
|
|
| 431 | 0 |
public int doStartTag() throws JspTagException { |
| 432 | 0 |
cancelUpdateRequired = false;
|
| 433 | 0 |
useBody = true;
|
| 434 | 0 |
content = null;
|
| 435 |
|
|
| 436 |
// We can only skip the body if the cache has the data
|
|
| 437 | 0 |
int returnCode = EVAL_BODY_BUFFERED;
|
| 438 |
|
|
| 439 | 0 |
if (admin == null) { |
| 440 | 0 |
admin = ServletCacheAdministrator.getInstance(pageContext.getServletContext()); |
| 441 |
} |
|
| 442 |
|
|
| 443 |
// Retrieve the cache
|
|
| 444 | 0 |
cache = admin.getCache((HttpServletRequest) pageContext.getRequest(), scope); |
| 445 |
|
|
| 446 |
// This allows to have multiple cache tags on a single page without
|
|
| 447 |
// having to specify keys. However, nested cache tags are not supported.
|
|
| 448 |
// In that case you would have to supply a key.
|
|
| 449 | 0 |
String suffix = null;
|
| 450 |
|
|
| 451 | 0 |
if (key == null) { |
| 452 | 0 |
synchronized (pageContext.getRequest()) {
|
| 453 | 0 |
Object o = pageContext.getRequest().getAttribute(CACHE_TAG_COUNTER_KEY); |
| 454 |
|
|
| 455 | 0 |
if (o == null) { |
| 456 | 0 |
suffix = "1";
|
| 457 |
} else {
|
|
| 458 | 0 |
suffix = Integer.toString(Integer.parseInt((String) o) + 1); |
| 459 |
} |
|
| 460 |
} |
|
| 461 |
|
|
| 462 | 0 |
pageContext.getRequest().setAttribute(CACHE_TAG_COUNTER_KEY, suffix); |
| 463 |
} |
|
| 464 |
|
|
| 465 |
// Generate the actual cache key
|
|
| 466 | 0 |
actualKey = admin.generateEntryKey(key, (HttpServletRequest) pageContext.getRequest(), scope, language, suffix); |
| 467 |
|
|
| 468 |
/*
|
|
| 469 |
if
|
|
| 470 |
- refresh is not set,
|
|
| 471 |
- the cacheEntry itself does not need to be refreshed before 'time' and
|
|
| 472 |
- the administrator has not had the cache entry's scope flushed
|
|
| 473 |
|
|
| 474 |
send out the cached version!
|
|
| 475 |
*/
|
|
| 476 | 0 |
try {
|
| 477 | 0 |
if (refresh) {
|
| 478 |
// Force a refresh
|
|
| 479 | 0 |
content = (String) cache.getFromCache(actualKey, 0, cron); |
| 480 |
} else {
|
|
| 481 |
// Use the specified refresh period
|
|
| 482 | 0 |
content = (String) cache.getFromCache(actualKey, time, cron); |
| 483 |
} |
|
| 484 |
|
|
| 485 | 0 |
try {
|
| 486 | 0 |
if (log.isDebugEnabled()) {
|
| 487 | 0 |
log.debug("<cache>: Using cached entry : " + actualKey);
|
| 488 |
} |
|
| 489 |
|
|
| 490 |
// Ensure that the cache returns the data correctly. Else re-evaluate the body
|
|
| 491 | 0 |
if ((content != null)) { |
| 492 | 0 |
if (mode != SILENT_MODE) {
|
| 493 | 0 |
pageContext.getOut().write(content); |
| 494 |
} |
|
| 495 |
|
|
| 496 | 0 |
returnCode = SKIP_BODY; |
| 497 |
} |
|
| 498 |
} catch (IOException e) {
|
|
| 499 | 0 |
throw new JspTagException("IO Exception: " + e.getMessage()); |
| 500 |
} |
|
| 501 |
} catch (NeedsRefreshException nre) {
|
|
| 502 | 0 |
cancelUpdateRequired = true;
|
| 503 | 0 |
content = (String) nre.getCacheContent(); |
| 504 |
} |
|
| 505 |
|
|
| 506 | 0 |
if (returnCode == EVAL_BODY_BUFFERED) {
|
| 507 | 0 |
if (log.isInfoEnabled()) {
|
| 508 | 0 |
log.info("<cache>: Cached content not used: New cache entry, cache stale or scope flushed : " + actualKey);
|
| 509 |
} |
|
| 510 |
} |
|
| 511 |
|
|
| 512 | 0 |
return returnCode;
|
| 513 |
} |
|
| 514 |
|
|
| 515 |
/**
|
|
| 516 |
* Convert a SimpleDateFormat string to seconds
|
|
| 517 |
* Acceptable format are :
|
|
| 518 |
* <ul>
|
|
| 519 |
* <li>0s (seconds)
|
|
| 520 |
* <li>0m (minute)
|
|
| 521 |
* <li>0h (hour)
|
|
| 522 |
* <li>0d (day)
|
|
| 523 |
* <li>0w (week)
|
|
| 524 |
* </ul>
|
|
| 525 |
* @param duration The simple date time to parse
|
|
| 526 |
* @return The value in seconds
|
|
| 527 |
*/
|
|
| 528 | 0 |
private int parseDuration(String duration) { |
| 529 | 0 |
int time = 0;
|
| 530 |
|
|
| 531 |
//Detect if the factor is specified
|
|
| 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 | 0 |
try {
|
| 533 | 0 |
time = Integer.parseInt(duration); |
| 534 |
} catch (Exception ex) {
|
|
| 535 |
//Extract number and ajust this number with the time factor
|
|
| 536 | 0 |
for (int i = 0; i < duration.length(); i++) { |
| 537 | 0 |
if (!Character.isDigit(duration.charAt(i))) {
|
| 538 | 0 |
time = Integer.parseInt(duration.substring(0, i)); |
| 539 |
|
|
| 540ht"> 532 |