cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From wbaye...@closerlook.com
Subject Cache fix for SSI and jsp:include
Date Wed, 03 Jan 2001 00:56:18 GMT
Hi,

I am working on a project that needs to include the output of an XML file
inside a JSP.  In the JSP, I get the current date and pass it in as a
parameter to XSL.  Here is a sample of the code:
-----
<%
GregorianCalendar c = new GregorianCalendar();
int y = c.get(Calendar.YEAR);
%>
Event listings:
<jsp:include page="Events.xml" flush="true">
     <jsp:param name="YR" value='<%=y%>'/>
</jsp:include>
-----

The XSL will filter the events based on the year passed in as the parameter
YR.

In order to test the page I changed the code to the following:
-----
<%
GregorianCalendar c = new GregorianCalendar();
int y = c.get(Calendar.MINUTE)%3 + 2000;
out.print(y);
%>
Event listings:
<jsp:include page="Events.xml" flush="true">
     <jsp:param name="YR" value='<%=y%>'/>
</jsp:include>
-----

The output from the XML should change every minute based on the "fake" year
that is passed in.  However, when tested, the "out.print(y)" was printing
the correct "fake" year, but the output from the XML file didn't change.
If I "touched" the XML file and then refreshed the browser, I got the
correct output.

So, somehow the page was getting cached and not recognizing that the
parameter that was passed in had changed.

I traced this problem to the following code:
-- org/apache/cocoon/Utils.java----------
    public static final String encode(...) {
        StringBuffer url = new StringBuffer();
        if (agent) {
            url.append(req.getHeader("user-Agent"));
            url.append(':');
        }
          url.append(req.getMethod());
          url.append(':');
        url.append(req.getScheme());
        url.append("://");
        url.append(req.getServerName());
        url.append(':');
        url.append(req.getServerPort());
----->  url.append(req.getRequestURI());
----->  if (query) {
----->      url.append('?');
----->      url.append(req.getQueryString());
----->  }
        return url.toString();
    }
--------------------
When the XML page is included inside a JSP or via Apache's SSI,
req.getRequestURI() and req.getQueryString() return the URI and QueryString
of the "including" JSP or SHTML page NOT the included XML page.
Since the "including" page URI and QueryString does not change from one
minute to the next, Cocoon was retrieving the old page from the cache.

(About a year ago someone else posted a similar problem, where he was
including 2 XML pages in one SHTML page and Cocoon was returning the same
page twice.  This can be traced to the same problem)

Here is the solution that I implemented.  I stole the code from two places.
1.  To correct the URI problem, the following code could be used (stolen
from Utils.getBaseName()):
-----
        //  Get the path of the real file
        String path = (String)
req.getAttribute("javax.servlet.include.servlet_path");
        // otherwise, we find it out ourselves
        if (path == null)
            path = req.getServletPath();

        url.append(path);
-----
2. To correct the QueryString problem, the following code could be
used(stolen from XSLTProcessor.filterParameters()):
-----
        if (query) {
            url.append('?');
            url.append(buildQueryString(req));
        }
 .
 .
 .
  public static String buildQueryString(HttpServletRequest request) {
    StringBuffer queryString = new StringBuffer();
    Enumeration parameters = request.getParameterNames();

    if (parameters != null) {
      while (parameters.hasMoreElements()) {
        String name = (String) parameters.nextElement();
        StringCharacterIterator iter = new StringCharacterIterator(name);
        boolean valid_name = true;
        char c = iter.first();

        if (!(Character.isLetter(c) || c == '_')) {
          valid_name = false;
        } else {
          c = iter.next();
        }

        while (valid_name && c != iter.DONE) {
          if (!(Character.isLetterOrDigit(c) ||
            c == '-' ||
            c == '_' ||
            c == '.')) {
              valid_name = false;
            } else {
              c = iter.next();
            }
          }

          if (valid_name) {();se;rOrDigit(c)
            queryString.append(URLEncoder.encode(name)
+ "=" + URLEncoder.encode(request.getParameter(name)) + "&");
          }
        }
      }
      if(queryString.length() > 0)
      {
        queryString.setLength(queryString.length()-1);
      }
      return queryString.toString();
    }
-----

This fix solves the problem, since now the URI and QueryString of the XML
file gets used in the key in the caching scheme.  Also, if the same XML
file is included in multiple JSPs or SHTML files, the correct cached page
will be served.

Obviously, duplicating the code in XSLTProcessor.filterParameters() and
Utils.buildQueryString() is not optimal, so there is more work to be done.

Please let me know if you have any comments.  Is this the correct approach?
If so, can this change be included in the next version of Cocoon 1?
If so, should I become an active developer and make the changes myself?

Regards,

Wayne Bayever
closerlook, inc.
wbayever@closerlook.com



Mime
View raw message