pier 2004/06/30 09:38:41
Added: src/java/org/apache/cocoon/acting HttpCacheAction.java Log: Added simple action generating HTTP caching headers to be used in conjunction with mod_proxy Revision Changes Path 1.1 cocoon-2.1/src/java/org/apache/cocoon/acting/HttpCacheAction.java Index: HttpCacheAction.java =================================================================== /* * Copyright 1999-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cocoon.acting; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.parameters.Parameters; import org.apache.avalon.framework.thread.ThreadSafe; import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.Redirector; import org.apache.cocoon.environment.Response; import org.apache.cocoon.environment.SourceResolver; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.TimeZone; /** * This action adds the <code>Last-Modified</code>, <code>Expires</code> and * <code>Cache-Control</code> HTTP headers to the response. * * <p> * This action will add the <code>Last-Modified</code> header to the response * with the time in which the request was executed, and an <code>Expires</code> * header at a specified time difference. Additionally, it will provide an * extra <code>Cache-Control</code> indicating the maximum age of the request * as a delta between the expiration and last modification dates. * </p> * <p> * This is useful (for example) when Cocoon is proxyied by a Web Server such * as Apache HTTPD running mod_cache, to indicate for each request how long * the output should be cached for. * </p> * <p> * To configure the difference between <code>Last-Modified</code> and * <code>Expires</code> this <code>Action</code> can be configured specifying * days, hours, minutes, and seconds in this way: * </p> * <pre> * <map:action>s * <map:action name="xyz" src="org.apache.cocoon.acting.HttpCacheAction>" * <days>1</day>s * <hours>2</hour>s * <minutes>3</minute>s * <seconds>4</second>s * </map:actio>n * </map:action>s * </pre> * <p> * Using this example configuration, the <code>Expires</code> header will * specify a date one day, two hours, three minutes and four seconds after * the time of the request (which will be in <code>Last-Modified</code>). * </p> * <p> * Note that if any of the parameters mentioned above is <b>zero</b> or * <b>less than zero</b> this action will modify the behaviour of the * resulting <code>Cache-Control</code> header to emit the keyword * <code>no-cache</code>. * </p> * <p> * This action will also return the three headers it added as sitemap * parameters called <code>last-modified</code>, <code>expires</code> and * <code>cache-control</code> (all lowercase). * </p> * * @author <a href="mailto:[EMAIL PROTECTED]">Pier Fumagalli</a> * @version CVS $Id: HttpCacheAction.java,v 1.1 2004/06/30 16:38:41 pier Exp $ */ public class HttpCacheAction extends AbstractConfigurableAction implements ThreadSafe { private TimeZone timezone = null; private SimpleDateFormat formatter = null; int days = 0; int hours = 0; int minutes = 0; int seconds = 0; public void configure(Configuration configuration) throws ConfigurationException { super.configure(configuration); /* RFC-822 Date with a GMT based time zone */ this.timezone = TimeZone.getTimeZone("GMT"); this.formatter = new SimpleDateFormat("EEE, dd MMM yyyy kk:mm:ss zzz"); this.formatter.setTimeZone(this.timezone); this.days = configuration.getChild("days").getValueAsInteger(0); this.hours = configuration.getChild("hours").getValueAsInteger(0); this.minutes = configuration.getChild("minutes").getValueAsInteger(0); this.seconds = configuration.getChild("seconds").getValueAsInteger(0); } public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception { Response response = ObjectModelHelper.getResponse(objectModel); Calendar calendar = Calendar.getInstance(timezone); Map values = new HashMap(3); /* Get the current time and output as the last modified header */ String value = this.formatter.format(calendar.getTime()); long maxage = calendar.getTimeInMillis(); response.setHeader("Last-Modified", value); values.put("last-modified", value); /* Advance the time as much as required */ calendar.add(Calendar.DATE, this.days); calendar.add(Calendar.HOUR, this.hours); calendar.add(Calendar.MINUTE, this.minutes); calendar.add(Calendar.SECOND, this.seconds); /* Recalculate time and age to see what changed */ maxage = calendar.getTimeInMillis() - maxage; /* If we got more than one second everything is quite normal */ if (maxage > 1000) { value = this.formatter.format(calendar.getTime()); response.setHeader("Expires", value); values.put("expires", value); value = "max-age=" + Long.toString(maxage / 1000l); response.setHeader("Cache-Control", value); values.put("cache-control", value); /* If we got less than one second (even negatives) no cache */ } else { /* We still hold the old value from Last-Modified here */ response.setHeader("Expires", value); values.put("expires", value); response.setHeader("Cache-Control", "no-cache"); values.put("cache-control", "no-cache"); } /* Return the headers */ return(Collections.unmodifiableMap(values)); } }
