dev@glassfish.java.net

Proposal for adding support for JSP cache taglib's 'scope' attribute

From: Jan Luehe <Jan.Luehe_at_Sun.COM>
Date: Tue, 02 Aug 2005 10:46:08 -0700

SUN's appserver and webserver products have shipped with a JSP
cache taglibrary, which allows caching of (potentially expensive) tag
body invocations. In the appserver, this taglib has been provided
by a JAR file named "appserv-tags.jar" in the installation's
lib directory.

The JSP cache taglib comes with two tags: "cache", which
supports caching the results of tag body invocations, and "flush", which
removes a previously cached entry from the cache and also allows the
entire cache to be cleared. Cache entries are identified by a
user-supplied key, passed as a tag attribute. It is also possible to
have the cache manager generate keys.

The cache taglib's underlying tag library descriptor (TLD) declares a
'scope' attribute for both tags, allowing page authors to reference
caches in different scopes.

However, the tags' implementations of the setScope() method have
ignored the specified scope (and there has been discussion about
deprecating the 'scope' attribute), and have defaulted to application
scope: The cache is initialized and cleared by the contextInitialized()
and contextDestroyed() methods, respectively, of the
com.sun.appserv.web.taglibs.cache.CacheContextListener (an instance of
javax.servlet.ServletContextListener) declared in the cache taglib's
TLD.

I'd like to fix the current limitation by adding support for caches in
request and session scopes. The setup and clearing of a cache in
request scope will be implemented by the requestInitialized() and
requestDestroyed() methods, respectively, of a new
CacheRequestListener, which is an instance of
javax.servlet.ServletRequestListener.

Likewise, the setup and clearing of a cache in session scope will be
performed by the sessionCreated() and sessionDestroyed() methods,
respectively, of a new CacheSessionListener, which is an instance of
javax.servlet.http.HttpSessionListener.

If a webapp utilizes the cache taglib and would like to cache tag body
invocations for the duration of a request and/or session, it will have
to declare the CacheRequestListener and/or CacheSessionListener,
respectively, in its deployment descriptor (using the <listener>
element).

Attached are the suggested fixes to the setScope() methods of
CacheTag.java and FlushTag.java, along with the new
CacheRequestListener.java and CacheSessionListener.java classes.

Please let me know if you have any comments.

Thanks,


Jan


Index: CacheTag.java
===================================================================
RCS file: /cvs/glassfish/webtier-extensions/src/java/com/sun/appserv/web/taglibs/cache/CacheTag.java,v
retrieving revision 1.2
diff -u -r1.2 CacheTag.java
--- CacheTag.java 27 Jun 2005 21:41:11 -0000 1.2
+++ CacheTag.java 2 Aug 2005 17:32:33 -0000
@@ -343,14 +343,14 @@
     }
 
     /**
- * This attribute is used to set the scope of the cache. It can be
- * either "session" or "application".
+ * Sets the scope of the cache.
+ *
+ * @param scope the scope of the cache
+ *
+ * @throws IllegalArgumentException if the specified scope is different
+ * from request, session, and application
      */
     public void setScope(String scope) {
- // scope not implemented yet
- // if (scope.equalsIgnoreCase("session"))
- // _scope = PageContext.SESSION_SCOPE;
- // else
- // _scope = PageContext.APPLICATION_SCOPE;
+ _scope = CacheUtil.convertScope(scope);
     }
 }


Index: CacheUtil.java
===================================================================
RCS file: /cvs/glassfish/webtier-extensions/src/java/com/sun/appserv/web/taglibs/cache/CacheUtil.java,v
retrieving revision 1.2
diff -u -r1.2 CacheUtil.java
--- CacheUtil.java 27 Jun 2005 21:41:11 -0000 1.2
+++ CacheUtil.java 2 Aug 2005 17:32:33 -0000
@@ -27,11 +27,15 @@
 
 package com.sun.appserv.web.taglibs.cache;
 
+import java.util.ResourceBundle;
+import java.text.MessageFormat;
+
 import javax.servlet.jsp.PageContext;
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 
 import com.sun.appserv.util.cache.Cache;
+import com.sun.enterprise.web.logging.pwc.LogDomains;
 
 /**
  * CacheUtil has utility methods used by the cache tag library.
@@ -39,6 +43,17 @@
 public class CacheUtil {
 
     /**
+ * The resource bundle containing the localized message strings.
+ */
+ private static ResourceBundle _rb =
+ LogDomains.getLogger(LogDomains.PWC_LOGGER).getResourceBundle();
+
+ private static final String PAGE_SCOPE = "page";
+ private static final String REQUEST_SCOPE = "request";
+ private static final String SESSION_SCOPE = "session";
+ private static final String APPLICATION_SCOPE = "application";
+
+ /**
      * This is used to get the cache itself. The cache is stored as an
      * attribute in the specified scope.
      * @return the cache object
@@ -75,5 +90,35 @@
         
         // concatenate the servlet path and the suffix to generate key
         return req.getServletPath() + '_' + suffix;
+ }
+
+
+ /*
+ * Converts the string representation of the given scope into an int.
+ *
+ * @param scope The string representation of the scope
+ *
+ * @return The corresponding int constant
+ *
+ * @throws IllegalArgumentException if the specified scope is different
+ * from request, session, and application
+ */
+ public static int convertScope(String scope) {
+
+ int ret;
+
+ if (REQUEST_SCOPE.equalsIgnoreCase(scope)) {
+ ret = PageContext.REQUEST_SCOPE;
+ } else if (SESSION_SCOPE.equalsIgnoreCase(scope)) {
+ ret = PageContext.SESSION_SCOPE;
+ } else if (APPLICATION_SCOPE.equalsIgnoreCase(scope)) {
+ ret = PageContext.APPLICATION_SCOPE;
+ } else {
+ String msg = _rb.getString("taglibs.cache.illegalScope");
+ msg = MessageFormat.format(msg, new Object[] { scope });
+ throw new IllegalArgumentException(msg);
+ }
+
+ return ret;
     }
 }


Index: FlushTag.java
===================================================================
RCS file: /cvs/glassfish/webtier-extensions/src/java/com/sun/appserv/web/taglibs/cache/FlushTag.java,v
retrieving revision 1.2
diff -u -r1.2 FlushTag.java
--- FlushTag.java 27 Jun 2005 21:41:11 -0000 1.2
+++ FlushTag.java 2 Aug 2005 17:32:33 -0000
@@ -154,14 +154,14 @@
     }
 
     /**
- * This attribute is used to set the scope of the cache. It can be
- * either "session" or "application".
+ * Sets the scope of the cache.
+ *
+ * @param scope the scope of the cache
+ *
+ * @throws IllegalArgumentException if the specified scope is different
+ * from request, session, and application
      */
     public void setScope(String scope) {
- // scope not implemented yet
- // if (scope.equalsIgnoreCase("session"))
- // _scope = PageContext.SESSION_SCOPE;
- // else
- // _scope = PageContext.APPLICATION_SCOPE;
+ _scope = CacheUtil.convertScope(scope);
     }
 }


Index: LogStrings.properties
===================================================================
RCS file: /cvs/glassfish/pwc-commons/src/java/com/sun/enterprise/web/logging/pwc/LogStrings.properties,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 LogStrings.properties
--- LogStrings.properties 27 May 2005 22:57:21 -0000 1.1.1.1
+++ LogStrings.properties 2 Aug 2005 17:34:59 -0000
@@ -38,6 +38,7 @@
 # com.sun.appserv.web.taglibs messages
 #
 taglibs.cache.nocache = PWC9001: cache not found in the specified scope
+taglibs.cache.illegalScope = PWC9002: Illegal value for scope attribute [{0}], must be one of request, session, or application
 
 #
 # com.sun.enterprise.web.monitor messages