Return-Path: Mailing-List: contact cocoon-dev-help@xml.apache.org; run by ezmlm Delivered-To: mailing list cocoon-dev@xml.apache.org Received: (qmail 76569 invoked from network); 3 Jan 2001 01:09:02 -0000 Received: from mournblade.netural.com (HELO mail.netural.com) (qmailr@206.54.248.2) by h31.sny.collab.net with SMTP; 3 Jan 2001 01:09:02 -0000 Received: (qmail 4650 invoked from network); 3 Jan 2001 01:09:08 -0000 Received: from arnold.closerlook.com (208.177.75.10) by mournblade.netural.com with SMTP; 3 Jan 2001 01:09:08 -0000 Received: by arnold.closerlook.com(Lotus SMTP MTA v4.6.1 (569.2 2-6-1998)) id 862569C9.000528D8 ; Tue, 2 Jan 2001 18:56:21 -0600 X-Lotus-FromDomain: CLOSER_LOOK From: wbayever@closerlook.com To: cocoon-dev@xml.apache.org Message-ID: <862569C8.007F676B.00@arnold.closerlook.com> Date: Tue, 2 Jan 2001 18:56:18 -0600 Subject: Cache fix for SSI and jsp:include Mime-Version: 1.0 Content-type: text/plain; charset=us-ascii Content-Disposition: inline X-Spam-Rating: h31.sny.collab.net 1.6.2 0/1000/N 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: ----- 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: ----- 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