KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > appserv > web > taglibs > cache > CacheTag


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.appserv.web.taglibs.cache;
25
26 import java.util.ResourceBundle JavaDoc;
27 import java.util.logging.Logger JavaDoc;
28 import java.util.logging.Level JavaDoc;
29
30 import javax.servlet.jsp.*;
31 import javax.servlet.jsp.tagext.*;
32
33 import com.sun.enterprise.web.logging.pwc.LogDomains;
34
35 import com.sun.appserv.util.cache.Cache;
36
37 /**
38  * CacheTag is a JSP tag that allows server-side caching of JSP page
39  * fragments. It lets you specify a timeout for how long the cached data
40  * is valid. It also gives you programmatic control over key generation,
41  * refreshing of the cache and whether the cached content should be served
42  * or not.
43  *
44  * Usage Example:
45  * <%@ taglib prefix="ias" uri="Sun ONE Application Server Tags" %>
46  * <ias:cache key="<%= cacheKey %>" usecached="<%= useCached %>"
47  * refresh="<%= reload %>" timeout="3600">
48  * ... expensive operation ...
49  * </ias:cache>
50  */

51 public class CacheTag extends BodyTagSupport
52 {
53     /**
54      * Constants used to calculate the timeout
55      */

56     private static final int SECOND = 1;
57     private static final int MINUTE = 60 * SECOND;
58     private static final int HOUR = 60 * MINUTE;
59     private static final int DAY = 24 * HOUR;
60
61     /**
62      * User specified key
63      */

64     private String JavaDoc _keyExpr;
65
66     /**
67      * The key into the cache. This is generated by suffixing the servlet
68      * path with the key if one is specified or by a generated suffix.
69      */

70     private String JavaDoc _key;
71
72     /**
73      * Timeout for the cache entry.
74      */

75     private int _timeout = Constants.DEFAULT_JSP_CACHE_TIMEOUT;
76
77     /**
78      * This boolean specifies whether the cache should be forcibly refreshed
79      * after the current request or not.
80      */

81     private boolean _refreshCache = false;
82
83     /**
84      * This boolean specifies whether the cached response must be sent
85      * or the body should be evaluated. The cache is not refreshed.
86      */

87     private boolean _useCachedResponse = true;
88
89     /**
90      * This specifies the scope of the cache.
91      */

92     private int _scope = PageContext.APPLICATION_SCOPE;
93
94     /**
95      * The actual cache itself.
96      */

97     private Cache _cache;
98
99     /**
100      * The logger to use for logging ALL web container related messages.
101      */

102     private static Logger JavaDoc _logger = null;
103
104     /**
105      * This indicates whether debug logging is on or not
106      */

107     private static boolean _debugLog;
108
109     /**
110      * The resource bundle containing the localized message strings.
111      */

112     private static ResourceBundle JavaDoc _rb = null;
113
114     // ---------------------------------------------------------------------
115
// Constructor and initialization
116

117     /**
118      * Default constructor that simply gets a handle to the web container
119      * subsystem's logger.
120      */

121     public CacheTag() {
122         super();
123         if (_logger == null) {
124             _logger = LogDomains.getLogger(LogDomains.PWC_LOGGER);
125             _rb = _logger.getResourceBundle();
126             _debugLog = _logger.isLoggable(Level.FINE);
127         }
128     }
129
130     // ---------------------------------------------------------------------
131
// Tag logic
132

133     /**
134      * doStartTag is called every time the cache tag is encountered. By
135      * the time this is called, the tag attributes are already set, but
136      * the tag body has not been evaluated.
137      * The cache key is generated here and the cache is obtained as well
138      *
139      * @throws JspException the standard exception thrown
140      * @return EVAL_BODY_INCLUDE when nocache is specified so that the
141      * tag body is just evaluated into the output stream
142      * SKIP_BODY if the cached response is valid in which case
143      * it is just written to the output stream, hence there is
144      * nothing more to be done.
145      * EVAL_BODY_BUFFERED is the default return value which
146      * ensures that the BodyContent is created and the tag body
147      * is evaluated into it.
148      */

149     public int doStartTag()
150         throws JspException
151     {
152         // default is EVAL_BODY_BUFFERED to ensure that BodyContent is created
153
int ret = EVAL_BODY_BUFFERED;
154
155         // generate the cache key using the user specified key. If no
156
// key is specified, a position specific key suffix is used
157
_key = CacheUtil.generateKey(_keyExpr, pageContext);
158
159         if (_debugLog)
160             _logger.fine("CacheTag["+ _key +"]: Timeout = "+ _timeout);
161
162         // if useCachedResponse is false, we do not check for any
163
// cached response and just evaluate the tag body
164
if (_useCachedResponse) {
165
166             _cache = CacheUtil.getCache(pageContext, _scope);
167             if (_cache == null)
168                 throw new JspException(_rb.getString("taglibs.cache.nocache"));
169
170             // if refreshCache is true, we want to re-evaluate the
171
// tag body and refresh the cached entry
172
if (_refreshCache == false) {
173
174                 // check if an entry is present for the given key
175
// if it is, check if it has expired or not
176
CacheEntry entry = (CacheEntry)_cache.get(_key);
177
178                 if (entry != null && entry.isValid()) {
179
180                     // valid cached entry, get cached response and
181
// write it to the output stream
182
String JavaDoc content = entry.getContent();
183
184                     try {
185                         pageContext.getOut().write(content);
186                     } catch (java.io.IOException JavaDoc ex) {
187                         throw new JspException(ex);
188                     }
189                          
190                     // since cached response is already written, skip
191
// evaluation of the tag body. This also means that
192
// doAfterBody wont get called
193
ret = SKIP_BODY;
194                 }
195             }
196         } else {
197             // since we dont want to use the cached response, just
198
// return EVAL_BODY_INCLUDE which will evaluate the body
199
// into the output stream. This will mean that this tag
200
// will be treated as an IterationTag and BodyContent is
201
// not created
202
ret = EVAL_BODY_INCLUDE;
203         }
204
205         return ret;
206     }
207
208     /**
209      * doAfterBody is called only if the body was evaluated. This would happen
210      * if nocache is specified in which case this should do nothing
211      * if there was no cached response in which case the response data
212      * is obtained from the bodyContent and cached
213      * if the response has expired in which case the cache is refreshed
214      *
215      * @throws JspException the standard exception thrown
216      * @return always returns SKIP_BODY since we dont do any iteration
217      */

218     public int doAfterBody()
219         throws JspException
220     {
221         // if useCachedResponse, update the cache with the new response
222
// data. If it is false, the body has already been evaluated and
223
// sent out, nothing more to be done.
224
if (_useCachedResponse) {
225             if (bodyContent != null) {
226
227                 // get the response as a string from bodyContent
228
// and cache it for the specified timeout period
229
String JavaDoc content = bodyContent.getString().trim();
230
231                 CacheEntry entry = new CacheEntry(content, _timeout);
232                 _cache.put(_key, entry);
233
234                 // write to body content to the enclosing writer as well
235
try {
236                     bodyContent.writeOut(bodyContent.getEnclosingWriter());
237                 } catch (java.io.IOException JavaDoc ex) {
238                     throw new JspException(ex);
239                 }
240             }
241         }
242         return SKIP_BODY;
243     }
244
245     /**
246      * doEndTag just resets all the valiables in case the tag is reused
247      *
248      * @throws JspException the standard exception thrown
249      * @return always returns EVAL_PAGE since we want the entire jsp evaluated
250      */

251     public int doEndTag()
252         throws JspException
253     {
254         _key = null;
255         _keyExpr = null;
256         _timeout = Constants.DEFAULT_JSP_CACHE_TIMEOUT;
257         _refreshCache = false;
258         _useCachedResponse = true;
259         _scope = PageContext.APPLICATION_SCOPE;
260         _cache = null;
261
262         return EVAL_PAGE;
263     }
264
265     // ---------------------------------------------------------------------
266
// Attribute setters
267

268     /**
269      * This is used to set a user-defined key to store the response in
270      * the cache.
271      */

272     public void setKey(String JavaDoc key) {
273         if (key != null && key.length() > 0)
274             _keyExpr = key;
275     }
276
277     /**
278      * This sets the time for which the cached response is valid. The
279      * cached entry is invalid after this time is past. If no unit is
280      * specified, then the timeout is assumed to be in seconds. A
281      * different unit can be specified by postfixing the timeout
282      * value with the desired unit:
283      * s=seconds, m=minutes, h=hours, d=days
284      */

285     public void setTimeout(String JavaDoc timeout) {
286         if (timeout != null) {
287             try {
288                 _timeout = Integer.parseInt(timeout);
289             } catch (NumberFormatException JavaDoc nfe) {
290                 // nfe indicated that the timeout has non-integers in it
291
// try to parse it as 1sec, 1min, 1 hour and 1day formats
292
int i = 0;
293                 while (i < timeout.length() &&
294                        Character.isDigit(timeout.charAt(i)))
295                     i++;
296
297                 if (i > 0) {
298                     _timeout = Integer.parseInt(timeout.substring(0, i));
299
300                     // mutiply timeout by the specified unit of time
301
char multiplier = timeout.charAt(i);
302                     switch (multiplier) {
303                         case 's' : _timeout *= SECOND;
304                                    break;
305                         case 'm' : _timeout *= MINUTE;
306                                    break;
307                         case 'h' : _timeout *= HOUR;
308                                    break;
309                         case 'd' : _timeout *= DAY;
310                                    break;
311                         default : break;
312                     }
313                 }
314             }
315         }
316     }
317
318     /**
319      * This attribute is used to programmatically enable or disable the use
320      * of the cached response.
321      * If noCache is true, then the cached response is not sent, instead
322      * the tag body is evaluated and sent out, the cache is not refreshed
323      * either.
324      */

325     public void setNocache(boolean noCache) {
326         if (noCache)
327             _useCachedResponse = false;
328     }
329
330     /**
331      * This attribute is used to programmatically refresh the cached
332      * response.
333      * If refresh is true, the cached response is not sent, instead the
334      * tag body is evaluated and sent and the cache is refreshed with the
335      * new response.
336      */

337     public void setRefresh(boolean refresh) {
338         _refreshCache = refresh;
339     }
340
341     /**
342      * Sets the scope of the cache.
343      *
344      * @param scope the scope of the cache
345      *
346      * @throws IllegalArgumentException if the specified scope is different
347      * from request, session, and application
348      */

349     public void setScope(String JavaDoc scope) {
350         _scope = CacheUtil.convertScope(scope);
351     }
352 }
353
Popular Tags