You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@roller.apache.org by sn...@apache.org on 2006/05/02 00:23:34 UTC
svn commit: r398712 [15/32] - in /incubator/roller/trunk/src/org/apache: ./
roller/ roller/business/ roller/business/hibernate/
roller/business/referrers/ roller/business/runnable/
roller/business/search/ roller/business/search/operations/ roller/busin...
Added: incubator/roller/trunk/src/org/apache/roller/presentation/cache/LRUCacheImpl.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/cache/LRUCacheImpl.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/cache/LRUCacheImpl.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/cache/LRUCacheImpl.java Mon May 1 15:23:02 2006
@@ -0,0 +1,122 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. The ASF licenses this file to You
+* 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+/*
+ * LRUCacheImpl.java
+ *
+ * Created on November 6, 2005, 10:33 AM
+ */
+package org.apache.roller.presentation.cache;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * A simple LRU Cache.
+ *
+ * @author Allen Gilliland
+ */
+public class LRUCacheImpl implements Cache {
+
+ private static Log mLogger = LogFactory.getLog(LRUCacheImpl.class);
+
+ private Map cache = null;
+
+
+ protected LRUCacheImpl() {
+
+ this.cache = Collections.synchronizedMap(new LRULinkedHashMap(100));
+ }
+
+
+ protected LRUCacheImpl(int maxsize) {
+
+ this.cache = Collections.synchronizedMap(new LRULinkedHashMap(maxsize));
+ }
+
+
+ /**
+ * Store an entry in the cache.
+ */
+ public synchronized void put(String key, Object value) {
+
+ this.cache.put(key, value);
+ }
+
+
+ /**
+ * Retrieve an entry from the cache.
+ */
+ public synchronized Object get(String key) {
+
+ return this.cache.get(key);
+ }
+
+
+ public synchronized void remove(String key) {
+
+ this.cache.remove(key);
+ }
+
+
+ public synchronized void remove(Set keys) {
+
+ Iterator it = keys.iterator();
+ while(it.hasNext())
+ this.cache.remove((String) it.next());
+ }
+
+
+ public synchronized void clear() {
+
+ this.cache.clear();
+ }
+
+
+ public synchronized Set keySet() {
+ return this.cache.keySet();
+ }
+
+
+ public Map stats() {
+
+ return new HashMap();
+ }
+
+
+ // David Flanaghan: http://www.davidflanagan.com/blog/000014.html
+ private static class LRULinkedHashMap extends LinkedHashMap {
+ protected int maxsize;
+
+ public LRULinkedHashMap(int maxsize) {
+ super(maxsize * 4 / 3 + 1, 0.75f, true);
+ this.maxsize = maxsize;
+ }
+
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ return this.size() > this.maxsize;
+ }
+ }
+
+}
Added: incubator/roller/trunk/src/org/apache/roller/presentation/cache/LazyExpiringCacheEntry.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/cache/LazyExpiringCacheEntry.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/cache/LazyExpiringCacheEntry.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/cache/LazyExpiringCacheEntry.java Mon May 1 15:23:02 2006
@@ -0,0 +1,91 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. The ASF licenses this file to You
+* 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+/*
+ * LazyExpiringCacheEntry.java
+ *
+ * Created on January 17, 2006, 10:14 AM
+ */
+
+package org.apache.roller.presentation.cache;
+
+import java.io.Serializable;
+
+
+/**
+ * A cache entry that is meant to expire in a lazy fashion.
+ *
+ * The way to use this class is to wrap the object you want to cache in an
+ * instance of this class and store that in your cache. Then when you want
+ * to retrieve this entry you must input a last-expired time which can be
+ * compared against the time this entry was cached to determine if the cached
+ * entry is "fresh". If the object is not fresh then we don't return it.
+ *
+ * This essentially allows us to track when an object is cached and then before
+ * we can retrieve that cached object we must compare it with it's last known
+ * invalidation time to make sure it hasn't expired. This is useful because
+ * instead of actively purging lots of cached objects from the cache at
+ * invalidation time, we can now be lazy and just invalidate them when we
+ * actually try to retrieve the cached object.
+ *
+ * This is useful for Roller because we will no longer have to iterate through
+ * the list of cached objects and inspect the keys to figure out what items to
+ * invalidate. Instead we can just sit back and let the items be invalidated as
+ * we try to use them.
+ *
+ * @author Allen Gilliland
+ */
+public class LazyExpiringCacheEntry implements Serializable {
+
+ private Object value = null;
+ private long timeCached = -1;
+
+
+ public LazyExpiringCacheEntry(Object item) {
+ this.value = item;
+ this.timeCached = System.currentTimeMillis();
+ }
+
+
+ /**
+ * Retrieve the value of this cache entry if it is still "fresh".
+ *
+ * If the value has expired then we return null.
+ */
+ public Object getValue(long lastInvalidated) {
+ if(this.isInvalid(lastInvalidated)) {
+ return null;
+ } else {
+ return this.value;
+ }
+ }
+
+
+ /**
+ * Determine if this cache entry has expired.
+ */
+ public boolean isInvalid(long lastInvalidated) {
+
+ return (this.timeCached < lastInvalidated);
+ }
+
+
+ public long getTimeCached() {
+ return timeCached;
+ }
+
+}
Added: incubator/roller/trunk/src/org/apache/roller/presentation/filters/BreadCrumbFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/BreadCrumbFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/BreadCrumbFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/BreadCrumbFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,144 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. The ASF licenses this file to You
+* 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.presentation.filters;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.collections.ArrayStack;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.config.RollerConfig;
+import org.apache.roller.presentation.RollerSession;
+import org.apache.roller.util.StringUtils;
+import org.apache.roller.util.Utilities;
+
+/**
+ * Intercepts requests and places URL
+ * into breadcrumb stack.
+ *
+ * @web.filter name="BreadCrumbFilter"
+ * *web.filter-mapping url-pattern="/*.do"
+ * @web.filter-init-param name="maxStackSize" value="3"
+ *
+ * @author <a href="mailto:lance@brainopolis.com">Lance Lavandowska</a>
+ *
+**/
+public final class BreadCrumbFilter implements Filter
+{
+ private static Log mLogger =
+ LogFactory.getFactory().getInstance(BreadCrumbFilter.class);
+
+ private int mMaxStackSize = 10;
+
+
+ public void doFilter(
+ ServletRequest req, ServletResponse resp, FilterChain chain)
+ throws IOException, ServletException
+ {
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) resp;
+
+ HttpSession ses = request.getSession(false);
+ ArrayStack stack = null;
+ if (ses != null)
+ {
+ stack = (ArrayStack)ses.getAttribute(RollerSession.BREADCRUMB);
+ }
+ if (stack == null)
+ {
+ stack = new ArrayStack();
+ }
+
+ // This gives you a chance to look at your breadcrumb trail
+ if (request.getQueryString() != null
+ && request.getQueryString().equals("BreadCrumb"))
+ {
+ response.setContentType("text/html; charset=UTF-8");
+ ServletOutputStream out = response.getOutputStream();
+
+ for (int i=0; i<stack.size(); i++)
+ {
+ out.println(stack.peek(i).toString() +"<br>");
+ }
+ out.flush();
+ out.close();
+ }
+ else
+ {
+ chain.doFilter(req, resp);
+ }
+
+ StringBuffer url = request.getRequestURL();
+ // now that we've successfully returned,
+ // add url to stack if it isn't a Velocity page
+ String servletPath = request.getServletPath();
+ if (servletPath.indexOf("page") == -1 &&
+ servletPath.indexOf("comments") == -1)
+ {
+ if (request.getQueryString() != null)
+ {
+ url.append("?").append( request.getQueryString() );
+ }
+ if (stack.size() == mMaxStackSize)
+ {
+ stack.remove(mMaxStackSize-1);
+ }
+ stack.push(url.toString());
+ }
+ if (ses != null)
+ {
+ ses.setAttribute(RollerSession.BREADCRUMB, stack);
+ }
+ }
+
+ /**
+ * Initialize controller values of filter.
+ **/
+ public void init(FilterConfig filterConfig)
+ {
+ mLogger.debug("Initializing Breadcrumb Filter");
+
+ String stackSize = RollerConfig.getProperty("breadcrumbs.stacksize");
+ if (!StringUtils.isEmpty(stackSize))
+ {
+ int mSS = Utilities.stringToInt(stackSize);
+ if (mSS != 0)
+ {
+ mMaxStackSize = mSS;
+ mLogger.info("set breadcrumb stack size to "+mSS);
+ }
+ }
+ }
+
+ /** destroy any instance values other than filterConfig **/
+ public void destroy()
+ {
+ mMaxStackSize = 10;
+ }
+}
Added: incubator/roller/trunk/src/org/apache/roller/presentation/filters/ByteArrayOutputStreamWrapper.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/ByteArrayOutputStreamWrapper.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/ByteArrayOutputStreamWrapper.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/ByteArrayOutputStreamWrapper.java Mon May 1 15:23:02 2006
@@ -0,0 +1,99 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. The ASF licenses this file to You
+* 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.presentation.filters;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+
+import javax.servlet.ServletOutputStream;
+
+/*
+ * @author llavandowska
+ *
+ * Implementation of ServletOutputStream that allows the filter to hold the
+ * Response content for insertion into the cache.
+ */
+public class ByteArrayOutputStreamWrapper extends ServletOutputStream
+{
+ protected OutputStream intStream;
+ protected ByteArrayOutputStream baStream;
+ protected boolean finallized = false;
+ protected boolean flushOnFinalizeOnly = true;
+
+ public ByteArrayOutputStreamWrapper(OutputStream outStream)
+ {
+ intStream = outStream;
+ baStream = new ByteArrayOutputStream();
+ }
+
+ public ByteArrayOutputStreamWrapper()
+ {
+ intStream = System.out;
+ baStream = new ByteArrayOutputStream();
+ }
+
+ public ByteArrayOutputStream getByteArrayStream()
+ {
+ return baStream;
+ }
+
+ public void setFinallized()
+ {
+ finallized = true;
+ }
+
+ public boolean isFinallized()
+ {
+ return finallized;
+ }
+
+
+ public void write(int i) throws java.io.IOException
+ {
+ baStream.write(i);
+ }
+
+ public void close() throws java.io.IOException
+ {
+ if (finallized) {
+ processStream();
+ intStream.close();
+ }
+ }
+
+ public void flush() throws java.io.IOException
+ {
+ if (baStream.size() != 0) {
+ if (!flushOnFinalizeOnly || finallized) {
+ processStream();
+ baStream = new ByteArrayOutputStream();
+ }
+ }
+ }
+
+ protected void processStream() throws java.io.IOException
+ {
+ intStream.write(baStream.toByteArray());
+ intStream.flush();
+ }
+
+ public void clear()
+ {
+ baStream = new ByteArrayOutputStream();
+ }
+}
Added: incubator/roller/trunk/src/org/apache/roller/presentation/filters/ByteArrayResponseWrapper.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/ByteArrayResponseWrapper.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/ByteArrayResponseWrapper.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/ByteArrayResponseWrapper.java Mon May 1 15:23:02 2006
@@ -0,0 +1,70 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. The ASF licenses this file to You
+* 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.presentation.filters;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+/*
+ * @author llavandowska
+ *
+ * Implementation of HttpServletResponseWrapper.
+ */
+public class ByteArrayResponseWrapper extends HttpServletResponseWrapper
+{
+ private PrintWriter tpWriter;
+ private ByteArrayOutputStreamWrapper tpStream;
+
+ public ByteArrayResponseWrapper(ServletResponse inResp)
+ throws java.io.IOException
+ {
+ super((HttpServletResponse) inResp);
+ tpStream = new ByteArrayOutputStreamWrapper(inResp.getOutputStream());
+ tpWriter = new PrintWriter(new OutputStreamWriter(tpStream,"UTF-8"));
+ }
+
+ public ServletOutputStream getOutputStream()
+ throws java.io.IOException
+ {
+ return tpStream;
+ }
+
+ public PrintWriter getWriter() throws java.io.IOException
+ {
+ return tpWriter;
+ }
+
+ /** Get a String representation of the entire buffer.
+ */
+ public String toString()
+ {
+ return tpStream.getByteArrayStream().toString();
+ }
+
+ public ByteArrayOutputStream getByteArrayOutputStream()
+ throws java.io.IOException
+ {
+ return tpStream.getByteArrayStream();
+ }
+}
Added: incubator/roller/trunk/src/org/apache/roller/presentation/filters/CharEncodingFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/CharEncodingFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/CharEncodingFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/CharEncodingFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. The ASF licenses this file to You
+ * 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. For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.presentation.filters;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Locale;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.servlet.jsp.jstl.core.Config;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.struts.Globals;
+
+/**
+ * Entry point filter for all requests. This filter ensures that the request encoding is set to UTF-8 before any other
+ * processing forces request parsing using a default encoding. It also syncs up the Struts and JSTL locales. This
+ * filter should normally be first and last in the chain.
+ *
+ * @author <a href="mailto:anil@busybuddha.org">Anil Gangolli</a>
+ * @web.filter name="CharEncodingFilter"
+ */
+
+public class CharEncodingFilter implements Filter
+{
+ private FilterConfig mFilterConfig = null;
+ private static Log mLogger =
+ LogFactory.getFactory().getInstance(CharEncodingFilter.class);
+
+ /**
+ * init
+ */
+ public void init(FilterConfig filterConfig) throws ServletException
+ {
+ mFilterConfig = filterConfig;
+ }
+
+ /**
+ * destroy
+ */
+ public void destroy()
+ {
+ }
+
+ /**
+ * Set the character encoding and sync up Struts and JSTL locales. This filter should normally be first (and last)
+ * in the chain.
+ */
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+ throws IOException, ServletException
+ {
+ if (mLogger.isDebugEnabled()) mLogger.debug("Processing CharEncodingFilter");
+ try
+ {
+ req.setCharacterEncoding("UTF-8");
+ if (mLogger.isDebugEnabled()) mLogger.debug("Set request character encoding to UTF-8");
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ // This should never happen since UTF-8 is a Java-specified required encoding.
+ throw new ServletException("Can't set incoming encoding to UTF-8");
+ }
+
+ // Keep JSTL and Struts Locale's in sync
+ // NOTE: The session here will get created if it is not present. This code was taken from its
+ // earlier incarnation in RequestFilter, which also caused the session to be created.
+ HttpSession session = ((HttpServletRequest) req).getSession();
+ if (mLogger.isDebugEnabled()) mLogger.debug("Synchronizing JSTL and Struts locales");
+ Locale locale = (Locale) session.getAttribute(Globals.LOCALE_KEY);
+ if (locale == null)
+ {
+ locale = req.getLocale();
+ }
+ if (req.getParameter("locale") != null)
+ {
+ locale = new Locale(req.getParameter("locale"));
+ }
+ session.setAttribute(Globals.LOCALE_KEY, locale);
+ Config.set(session, Config.FMT_LOCALE, locale);
+
+ chain.doFilter(req, res);
+ }
+
+}
Added: incubator/roller/trunk/src/org/apache/roller/presentation/filters/CompressionFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/CompressionFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/CompressionFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/CompressionFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,122 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. The ASF licenses this file to You
+* 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.presentation.filters;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.zip.GZIPOutputStream;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Filter that compresses output with gzip (assuming that browser supports gzip).
+ * <P>
+ * Taken from More Servlets and JavaServer Pages from Prentice Hall and
+ * Sun Microsystems Press, http://www.moreservlets.com/.
+ * © 2002 Marty Hall; may be freely used or adapted.
+ *
+ * @web.filter name="CompressionFilter"
+ */
+
+public class CompressionFilter implements Filter {
+
+ private static Log mLogger = LogFactory.getLog(CompressionFilter.class);
+
+
+ /**
+ * If browser does not support gzip, invoke resource normally. If browser
+ * does support gzip, set the Content-Encoding response header and invoke
+ * resource with a wrapped response that collects all the output. Extract
+ * the output and write it into a gzipped byte array. Finally, write that
+ * array to the client's output stream.
+ */
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws ServletException, IOException {
+
+ HttpServletRequest req = (HttpServletRequest) request;
+ HttpServletResponse res = (HttpServletResponse) response;
+
+ if (!isGzipSupported(req)) {
+ // Invoke resource normally.
+ chain.doFilter(req, res);
+ } else {
+ // Tell browser we are sending it gzipped data.
+ res.setHeader("Content-Encoding", "gzip");
+
+ // Invoke resource, accumulating output in the wrapper.
+ ByteArrayResponseWrapper responseWrapper =
+ new ByteArrayResponseWrapper(response);
+
+ chain.doFilter(req, responseWrapper);
+
+ ByteArrayOutputStream outputStream = responseWrapper.getByteArrayOutputStream();
+
+ // Get character array representing output.
+ mLogger.debug("Pre-zip size:" + outputStream.size());
+
+ // Make a writer that compresses data and puts
+ // it into a byte array.
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ GZIPOutputStream zipOut = new GZIPOutputStream(byteStream);
+
+ // Compress original output and put it into byte array.
+ zipOut.write(responseWrapper.getByteArrayOutputStream().toByteArray());
+
+ // Gzip streams must be explicitly closed.
+ zipOut.close();
+
+ mLogger.debug("Gzip size:" + byteStream.size());
+
+ // Update the Content-Length header.
+ res.setContentLength(byteStream.size());
+
+ ByteArrayOutputStreamWrapper newOut =
+ (ByteArrayOutputStreamWrapper) responseWrapper.getOutputStream();
+ newOut.clear();
+ newOut.setFinallized();
+
+ /* now force close of OutputStream */
+ newOut.write(byteStream.toByteArray());
+ newOut.close();
+ }
+
+ }
+
+
+ public void init(FilterConfig config) throws ServletException {}
+
+
+ public void destroy() {}
+
+
+ private boolean isGzipSupported(HttpServletRequest req) {
+ String browserEncodings = req.getHeader("Accept-Encoding");
+ return ((browserEncodings != null)
+ && (browserEncodings.indexOf("gzip") != -1));
+ }
+
+}
Added: incubator/roller/trunk/src/org/apache/roller/presentation/filters/DebugFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/DebugFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/DebugFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/DebugFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,71 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. The ASF licenses this file to You
+* 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+/*
+ * DebugFilter.java
+ *
+ * Created on April 17, 2006, 10:30 AM
+ */
+
+package org.apache.roller.presentation.filters;
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * A simple debugging filter.
+ *
+ * This filter is NOT mapped by default and is here only for Roller developers
+ * to use while they are working on the code and debugging things.
+ *
+ * @web.filter name="DebugFilter"
+ */
+public class DebugFilter implements Filter {
+
+ private static Log log = LogFactory.getLog(DebugFilter.class);
+
+
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+ throws IOException, ServletException {
+
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+
+ log.info("ENTERING "+request.getRequestURL());
+
+ chain.doFilter(request, response);
+
+ log.info("EXITING "+request.getRequestURL());
+ }
+
+
+ public void destroy() {}
+
+
+ public void init(FilterConfig filterConfig) {}
+
+}
Added: incubator/roller/trunk/src/org/apache/roller/presentation/filters/FeedCacheFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/FeedCacheFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/FeedCacheFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/FeedCacheFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,384 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. The ASF licenses this file to You
+* 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+/*
+ * RssCacheFilter.java
+ *
+ * Created on November 5, 2005, 6:32 PM
+ */
+
+package org.apache.roller.presentation.filters;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.config.RollerConfig;
+import org.apache.roller.pojos.BookmarkData;
+import org.apache.roller.pojos.CommentData;
+import org.apache.roller.pojos.FolderData;
+import org.apache.roller.pojos.RefererData;
+import org.apache.roller.pojos.UserData;
+import org.apache.roller.pojos.WeblogCategoryData;
+import org.apache.roller.pojos.WeblogEntryData;
+import org.apache.roller.pojos.WeblogTemplate;
+import org.apache.roller.pojos.WebsiteData;
+import org.apache.roller.presentation.WeblogFeedRequest;
+import org.apache.roller.presentation.cache.Cache;
+import org.apache.roller.presentation.cache.CacheHandler;
+import org.apache.roller.presentation.cache.CacheManager;
+import org.apache.roller.presentation.cache.LazyExpiringCacheEntry;
+import org.apache.roller.presentation.util.CacheHttpServletResponseWrapper;
+import org.apache.roller.presentation.util.ResponseContent;
+
+
+/**
+ * A filter used for caching fully rendered xml feeds.
+ *
+ * This filter should only be applied to /rss/*, /atom/*, /flavor/*
+ *
+ * @web.filter name="FeedCacheFilter"
+ *
+ * @author Allen Gilliland
+ */
+public class FeedCacheFilter implements Filter, CacheHandler {
+
+ private static Log mLogger = LogFactory.getLog(FeedCacheFilter.class);
+
+ // a unique identifier for this cache, this is used as the prefix for
+ // roller config properties that apply to this cache
+ private static final String CACHE_ID = "cache.feed";
+
+ // our cache of rendered feeds
+ private Cache mCache = null;
+
+ // the last time the main feeds were expired
+ private Date mainLastExpiredDate = new Date();
+
+ // for metrics
+ private double hits = 0;
+ private double misses = 0;
+ private double purges = 0;
+ private Date startTime = new Date();
+
+
+ /**
+ * Process filter.
+ */
+ public void doFilter(ServletRequest req,
+ ServletResponse res,
+ FilterChain chain)
+ throws IOException, ServletException {
+
+ mLogger.debug("entering");
+
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+
+ WeblogFeedRequest feedRequest = null;
+ try {
+ feedRequest = new WeblogFeedRequest(request);
+ } catch(Exception e) {
+ // some kind of error parsing the request
+ mLogger.error("error creating weblog feed request", e);
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ String key = this.CACHE_ID+":"+this.generateKey(feedRequest);
+
+ try {
+ ResponseContent respContent = null;
+ long lastExpiration = 0;
+
+ // first, we need to determine the last time the specified feed was expired.
+ // if this is a weblog specific feed then ask the CacheManager for
+ // the last expired time of the weblog. otherwise this is a main feed and we
+ // keep that last expired time ourselves
+ if(feedRequest.getWeblogHandle() != null) {
+ Date lastExpirationDate =
+ (Date) CacheManager.getLastExpiredDate(feedRequest.getWeblogHandle());
+ if(lastExpirationDate != null)
+ lastExpiration = lastExpirationDate.getTime();
+ } else {
+ lastExpiration = this.mainLastExpiredDate.getTime();
+ }
+
+ LazyExpiringCacheEntry entry =
+ (LazyExpiringCacheEntry) this.mCache.get(key);
+ if(entry != null) {
+ respContent = (ResponseContent) entry.getValue(lastExpiration);
+
+ if(respContent == null)
+ mLogger.debug("HIT-INVALID "+key);
+ }
+
+ if (respContent == null) {
+
+ mLogger.debug("MISS "+key);
+ this.misses++;
+
+ CacheHttpServletResponseWrapper cacheResponse =
+ new CacheHttpServletResponseWrapper(response);
+
+ chain.doFilter(request, cacheResponse);
+
+ cacheResponse.flushBuffer();
+
+ // only cache if there wasn't an exception
+ if (request.getAttribute("DisplayException") == null) {
+ ResponseContent rc = cacheResponse.getContent();
+
+ this.mCache.put(key, new LazyExpiringCacheEntry(rc));
+ } else {
+ // it is expected that whoever caught this display exception
+ // is the one who reported it to the logs
+ mLogger.debug("Display exception "+key);
+ }
+
+ } else {
+
+ mLogger.debug("HIT "+key);
+ this.hits++;
+
+ respContent.writeTo(response);
+ }
+
+ } catch(Exception ex) {
+
+ if(ex.getMessage().indexOf("ClientAbort") != -1) {
+ // ClientAbortException ... ignored
+ mLogger.debug(ex.getMessage());
+
+ } else if(ex.getMessage().indexOf("SocketException") != -1) {
+ // SocketException ... ignored
+ mLogger.debug(ex.getMessage());
+
+ } else {
+ mLogger.error("Unexpected exception rendering feed "+key, ex);
+ }
+
+ // gotta send something to the client
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+
+ mLogger.debug("exiting");
+ }
+
+
+ /**
+ * Generate a cache key from a parsed weblog feed request.
+ * This generates a key of the form ...
+ *
+ * <context>[/handle]/<flavor>[/category]/<language>[/excerpts]
+ *
+ * examples ...
+ *
+ * main/rss/en
+ * weblog/foo/rss/MyCategory/en
+ * weblog/foo/atom/en/excerpts
+ *
+ */
+ private String generateKey(WeblogFeedRequest feedRequest) {
+
+ StringBuffer key = new StringBuffer();
+ key.append(feedRequest.getContext());
+
+ if(feedRequest.getContext().equals("weblog")) {
+ key.append("/").append(feedRequest.getWeblogHandle().toLowerCase());
+ key.append("/").append(feedRequest.getFlavor());
+
+ if(feedRequest.getWeblogCategory() != null) {
+ String cat = feedRequest.getWeblogCategory();
+ if(cat.startsWith("/"))
+ cat = cat.substring(1).replaceAll("/","_");
+
+ // categories may contain spaces, which is not desired
+ key.append("/").append(org.apache.commons.lang.StringUtils.deleteWhitespace(cat));
+ }
+ } else {
+ key.append("/").append(feedRequest.getFlavor());
+ }
+
+ // add language
+ key.append("/").append(feedRequest.getLanguage());
+
+ if(feedRequest.isExcerpts()) {
+ key.append("/excerpts");
+ }
+
+ return key.toString();
+ }
+
+
+ /**
+ * A weblog entry has changed.
+ */
+ public void invalidate(WeblogEntryData entry) {
+ this.invalidate(entry.getWebsite());
+ }
+
+
+ /**
+ * A weblog has changed.
+ */
+ public synchronized void invalidate(WebsiteData website) {
+
+ mLogger.debug("invalidating website = "+website.getHandle());
+
+ // update our main feed last expiration date
+ synchronized(this) {
+ this.mainLastExpiredDate = new Date();
+ }
+ }
+
+
+ /**
+ * A bookmark has changed.
+ */
+ public void invalidate(BookmarkData bookmark) {
+ // ignored
+ }
+
+
+ /**
+ * A folder has changed.
+ */
+ public void invalidate(FolderData folder) {
+ // ignored
+ }
+
+
+ /**
+ * A comment has changed.
+ */
+ public void invalidate(CommentData comment) {
+ // ignored
+ }
+
+
+ /**
+ * A referer has changed.
+ */
+ public void invalidate(RefererData referer) {
+ // ignored
+ }
+
+
+ /**
+ * A user profile has changed.
+ */
+ public void invalidate(UserData user) {
+ // ignored
+ }
+
+
+ /**
+ * A category has changed.
+ */
+ public void invalidate(WeblogCategoryData category) {
+ this.invalidate(category.getWebsite());
+ }
+
+
+ /**
+ * Clear the entire cache.
+ */
+ public void clear() {
+ mLogger.info("Clearing cache");
+ this.mCache.clear();
+ this.startTime = new Date();
+ this.hits = 0;
+ this.misses = 0;
+ this.purges = 0;
+ }
+
+
+ /**
+ * A weblog template has changed.
+ */
+ public void invalidate(WeblogTemplate template) {
+ // ignored
+ }
+
+
+ public Map getStats() {
+
+ Map stats = new HashMap();
+ stats.put("cacheType", this.mCache.getClass().getName());
+ stats.put("startTime", this.startTime);
+ stats.put("hits", new Double(this.hits));
+ stats.put("misses", new Double(this.misses));
+ stats.put("purges", new Double(this.purges));
+
+ // calculate efficiency
+ if((misses - purges) > 0) {
+ double efficiency = hits / (misses + hits);
+ stats.put("efficiency", new Double(efficiency * 100));
+ }
+
+ return stats;
+ }
+
+
+ /**
+ * Destroy method for this filter
+ */
+ public void destroy() {
+ }
+
+
+ /**
+ * Init method for this filter
+ */
+ public void init(FilterConfig filterConfig) {
+
+ mLogger.info("Initializing feed cache");
+
+ Map cacheProps = new HashMap();
+ Enumeration allProps = RollerConfig.keys();
+ String prop = null;
+ while(allProps.hasMoreElements()) {
+ prop = (String) allProps.nextElement();
+
+ // we are only interested in props for this cache
+ if(prop.startsWith(CACHE_ID+".")) {
+ cacheProps.put(prop.substring(CACHE_ID.length()+1),
+ RollerConfig.getProperty(prop));
+ }
+ }
+
+ mLogger.info(cacheProps);
+
+ mCache = CacheManager.constructCache(this, cacheProps);
+ }
+
+}
Added: incubator/roller/trunk/src/org/apache/roller/presentation/filters/IPBanFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/IPBanFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/IPBanFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/IPBanFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,92 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. The ASF licenses this file to You
+* 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+
+package org.apache.roller.presentation.filters;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.util.StringUtils;
+
+/**
+ * Braindead simple IPBanFilter. XDoclet tags disabled because I don't want this
+ * to be on by default. Users who want it can configure it themselves in web.xml.
+ * web.filter name="IPBanFilter"
+ * web.filter-init-param name="denyFrom" value="" description="Comma-separated list of banned IPs"
+ * @author David M Johnson
+ */
+public class IPBanFilter implements Filter
+{
+ private List denyFrom = null;
+ private static Log mLogger =
+ LogFactory.getFactory().getInstance(IPBanFilter.class);
+
+ public IPBanFilter()
+ {
+ super();
+ }
+
+ public void init(FilterConfig filterConfig) throws ServletException
+ {
+ /*
+ * This should be updated to the new config, however I don't want
+ * to do it myself since I'm not sure if/how it is being used.
+ *
+ * This looks like something that could be a long list, so maybe
+ * it should be in the DB or possibly its own file?
+ * -- Allen G
+ */
+ String denyFromParam = filterConfig.getInitParameter("denyFrom");
+ denyFrom = Arrays.asList(StringUtils.split(denyFromParam,","));
+ }
+
+ public void doFilter(
+ ServletRequest req,
+ ServletResponse res,
+ FilterChain chain)
+ throws IOException, ServletException
+ {
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+ if (denyFrom.contains(request.getRemoteAddr()))
+ {
+ response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+ else
+ {
+ chain.doFilter(request, response);
+ }
+ }
+
+ public void destroy()
+ {
+ }
+}
Added: incubator/roller/trunk/src/org/apache/roller/presentation/filters/IfModifiedFeedCacheFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/IfModifiedFeedCacheFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/IfModifiedFeedCacheFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/IfModifiedFeedCacheFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,376 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. The ASF licenses this file to You
+* 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+/*
+ * IfModifiedFeedCacheFilter.java
+ *
+ * Created on November 9, 2005, 2:47 PM
+ */
+
+package org.apache.roller.presentation.filters;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.RollerException;
+import org.apache.roller.config.RollerConfig;
+import org.apache.roller.model.Roller;
+import org.apache.roller.model.RollerFactory;
+import org.apache.roller.model.UserManager;
+import org.apache.roller.model.WeblogManager;
+import org.apache.roller.pojos.BookmarkData;
+import org.apache.roller.pojos.CommentData;
+import org.apache.roller.pojos.FolderData;
+import org.apache.roller.pojos.RefererData;
+import org.apache.roller.pojos.UserData;
+import org.apache.roller.pojos.WeblogCategoryData;
+import org.apache.roller.pojos.WeblogEntryData;
+import org.apache.roller.pojos.WeblogTemplate;
+import org.apache.roller.pojos.WebsiteData;
+import org.apache.roller.presentation.WeblogFeedRequest;
+import org.apache.roller.presentation.cache.Cache;
+import org.apache.roller.presentation.cache.CacheHandler;
+import org.apache.roller.presentation.cache.CacheManager;
+import org.apache.roller.presentation.cache.LazyExpiringCacheEntry;
+
+
+/**
+ * A filter used for caching last modified dates.
+ *
+ * This may be applied to /rss/*, /atom/*, /flavor/*
+ *
+ * @web.filter name="IfModifiedFeedCacheFilter"
+ *
+ * @author Allen Gilliland
+ */
+public class IfModifiedFeedCacheFilter implements Filter, CacheHandler {
+
+ private static Log mLogger =
+ LogFactory.getLog(IfModifiedFeedCacheFilter.class);
+
+ // a unique identifier for this cache, this is used as the prefix for
+ // roller config properties that apply to this cache
+ private static final String CACHE_ID = "cache.ifmodified.feed";
+
+ // the cache of last updated times
+ private Cache mCache = null;
+
+ // the last time we expired our main feeds
+ private Date mainLastExpiredDate = new Date();
+
+ SimpleDateFormat dateFormatter =
+ new SimpleDateFormat("EEE MMM d HH:mm:ss z yyyy");
+
+
+ /**
+ * Process filter.
+ */
+ public void doFilter(ServletRequest req,
+ ServletResponse res,
+ FilterChain chain)
+ throws IOException, ServletException {
+
+ mLogger.debug("entering");
+
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+
+ WeblogFeedRequest feedRequest = null;
+ try {
+ feedRequest = new WeblogFeedRequest(request);
+ } catch(Exception e) {
+ mLogger.error("error creating feed request", e);
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ String key = this.CACHE_ID+":"+this.generateKey(feedRequest);
+
+ Date updateTime = null;
+ try {
+ long lastExpiration = 0;
+
+ // first, we need to determine the last time the specified feed was expired.
+ // if this is a weblog specific feed then ask the CacheManager for
+ // the last expired time of the weblog. otherwise this is a main feed and we
+ // keep that last expired time ourselves
+ if(feedRequest.getWeblogHandle() != null) {
+ Date lastExpirationDate =
+ (Date) CacheManager.getLastExpiredDate(feedRequest.getWeblogHandle());
+ if(lastExpirationDate != null)
+ lastExpiration = lastExpirationDate.getTime();
+ } else {
+ lastExpiration = this.mainLastExpiredDate.getTime();
+ }
+
+ LazyExpiringCacheEntry entry =
+ (LazyExpiringCacheEntry) this.mCache.get(key);
+ if(entry != null) {
+ updateTime = (Date) entry.getValue(lastExpiration);
+
+ if(updateTime == null)
+ mLogger.debug("HIT-INVALID "+key);
+ }
+
+ if (updateTime == null) {
+ mLogger.debug("MISS "+key);
+
+ if(feedRequest.getWeblogHandle() != null) {
+ Roller roller = RollerFactory.getRoller();
+ UserManager umgr = roller.getUserManager();
+ WeblogManager wmgr = roller.getWeblogManager();
+
+ updateTime = wmgr.getWeblogLastPublishTime(
+ umgr.getWebsiteByHandle(feedRequest.getWeblogHandle()),
+ feedRequest.getWeblogCategory());
+
+ this.mCache.put(key, new LazyExpiringCacheEntry(updateTime));
+
+ } else {
+ this.mCache.put(key, new LazyExpiringCacheEntry(new Date()));
+ }
+
+ } else {
+ mLogger.debug("HIT "+key);
+ }
+
+ // Check the incoming if-modified-since header
+ Date sinceDate =
+ new Date(request.getDateHeader("If-Modified-Since"));
+
+ if (updateTime != null) {
+ // convert date (JDK 1.5 workaround)
+ String date = dateFormatter.format(updateTime);
+ updateTime = new Date(date);
+ if (updateTime.compareTo(sinceDate) <= 0) {
+ mLogger.debug("NOT_MODIFIED "+key);
+ response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+ return;
+ }
+ }
+
+ } catch (RollerException e) {
+ // Thrown by getLastPublishedDate if there is a db-type error
+ response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ } catch (IllegalArgumentException e) {
+ // Thrown by getDateHeader if not in valid format. This can be
+ // safely ignored, the only consequence is that the NOT MODIFIED
+ // response is not set.
+ }
+
+ // Set outgoing last modified header
+ if (updateTime != null) {
+ response.setDateHeader("Last-Modified", updateTime.getTime());
+ }
+
+ chain.doFilter(request, response);
+
+ mLogger.debug("exiting");
+ }
+
+
+ /**
+ * Generate a cache key from a parsed weblog feed request.
+ * This generates a key of the form ...
+ *
+ * <context>/[handle]/<flavor>/[category]/<language>/[excerpts]
+ *
+ * examples ...
+ *
+ * main/rss/en
+ * planet/rss/en
+ * weblog/foo/rss/MyCategory/en
+ * weblog/foo/atom/en/excerpts
+ *
+ */
+ private String generateKey(WeblogFeedRequest feedRequest) {
+
+ StringBuffer key = new StringBuffer();
+ key.append(feedRequest.getContext());
+
+ if(feedRequest.getContext().equals("weblog")) {
+ key.append("/").append(feedRequest.getWeblogHandle().toLowerCase());
+ key.append("/").append(feedRequest.getFlavor());
+
+ if(feedRequest.getWeblogCategory() != null) {
+ String cat = feedRequest.getWeblogCategory();
+ if(cat.startsWith("/"))
+ cat = cat.substring(1).replaceAll("/","_");
+
+ // categories may contain spaces, which is not desired
+ key.append("/").append(org.apache.commons.lang.StringUtils.deleteWhitespace(cat));
+ }
+ } else {
+ key.append("/").append(feedRequest.getFlavor());
+ }
+
+ // add language
+ key.append("/").append(feedRequest.getLanguage());
+
+ if(feedRequest.isExcerpts()) {
+ key.append("/excerpts");
+ }
+
+ return key.toString();
+ }
+
+
+ /**
+ * A weblog entry has changed.
+ */
+ public void invalidate(WeblogEntryData entry) {
+ this.invalidate(entry.getWebsite());
+ }
+
+
+ /**
+ * A weblog has changed.
+ */
+ public synchronized void invalidate(WebsiteData website) {
+
+ mLogger.debug("invalidating website = "+website.getHandle());
+
+ // update our main feed last expiration date
+ synchronized(this) {
+ this.mainLastExpiredDate = new Date();
+ }
+ }
+
+
+ /**
+ * A bookmark has changed.
+ */
+ public void invalidate(BookmarkData bookmark) {
+ // ignored
+ }
+
+
+ /**
+ * A folder has changed.
+ */
+ public void invalidate(FolderData folder) {
+ // ignored
+ }
+
+
+ /**
+ * A comment has changed.
+ */
+ public void invalidate(CommentData comment) {
+ // ignored
+ }
+
+
+ /**
+ * A referer has changed.
+ */
+ public void invalidate(RefererData referer) {
+ // ignored
+ }
+
+
+ /**
+ * A user profile has changed.
+ */
+ public void invalidate(UserData user) {
+ // ignored
+ }
+
+
+ /**
+ * A category has changed.
+ */
+ public void invalidate(WeblogCategoryData category) {
+ this.invalidate(category.getWebsite());
+ }
+
+
+ /**
+ * A weblog template has changed.
+ */
+ public void invalidate(WeblogTemplate template) {
+ // ignored
+ }
+
+
+ /**
+ * Clear the entire cache.
+ */
+ public void clear() {
+ mLogger.info("Clearing cache");
+ this.mCache.clear();
+ }
+
+
+ public Map getStats() {
+
+ Map stats = new HashMap();
+
+ return stats;
+ }
+
+
+ /**
+ * Destroy method for this filter
+ */
+ public void destroy() {
+ }
+
+
+ /**
+ * Init method for this filter
+ */
+ public void init(FilterConfig filterConfig) {
+
+ mLogger.info("Initializing if-modified feed cache");
+
+ Map cacheProps = new HashMap();
+ Enumeration allProps = RollerConfig.keys();
+ String prop = null;
+ while(allProps.hasMoreElements()) {
+ prop = (String) allProps.nextElement();
+
+ // we are only interested in props for this cache
+ if(prop.startsWith(CACHE_ID+".")) {
+ cacheProps.put(prop.substring(CACHE_ID.length()+1),
+ RollerConfig.getProperty(prop));
+ }
+ }
+
+ mLogger.info(cacheProps);
+
+ mCache = CacheManager.constructCache(this, cacheProps);
+ }
+
+}
Added: incubator/roller/trunk/src/org/apache/roller/presentation/filters/IfModifiedWeblogPageCacheFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/IfModifiedWeblogPageCacheFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/IfModifiedWeblogPageCacheFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/IfModifiedWeblogPageCacheFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,390 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. The ASF licenses this file to You
+* 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+/*
+ * IfModifiedWeblogPageCacheFilter.java
+ *
+ * Created on November 9, 2005, 9:02 PM
+ */
+
+package org.apache.roller.presentation.filters;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.config.RollerConfig;
+import org.apache.roller.pojos.BookmarkData;
+import org.apache.roller.pojos.CommentData;
+import org.apache.roller.pojos.FolderData;
+import org.apache.roller.pojos.RefererData;
+import org.apache.roller.pojos.UserData;
+import org.apache.roller.pojos.WeblogCategoryData;
+import org.apache.roller.pojos.WeblogEntryData;
+import org.apache.roller.pojos.WeblogTemplate;
+import org.apache.roller.pojos.WebsiteData;
+import org.apache.roller.presentation.WeblogPageRequest;
+import org.apache.roller.presentation.cache.Cache;
+import org.apache.roller.presentation.cache.CacheHandler;
+import org.apache.roller.presentation.cache.CacheManager;
+import org.apache.roller.presentation.cache.LazyExpiringCacheEntry;
+import org.apache.roller.util.Utilities;
+
+
+/**
+ * A filter used for caching last modified dates.
+ *
+ * @web.filter name="IfModifiedWeblogPageCacheFilter"
+ *
+ * @author Allen Gilliland
+ */
+public class IfModifiedWeblogPageCacheFilter implements Filter, CacheHandler {
+
+ private static Log mLogger =
+ LogFactory.getLog(IfModifiedWeblogPageCacheFilter.class);
+
+ // a unique identifier for this cache, this is used as the prefix for
+ // roller config properties that apply to this cache
+ private static final String CACHE_ID = "cache.ifmodified.weblogpage";
+
+ private Cache mCache = null;
+
+ SimpleDateFormat dateFormatter =
+ new SimpleDateFormat("EEE MMM d HH:mm:ss z yyyy");
+
+
+ /**
+ * Process filter.
+ */
+ public void doFilter(ServletRequest req,
+ ServletResponse res,
+ FilterChain chain)
+ throws IOException, ServletException {
+
+ mLogger.debug("entering");
+
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+
+ WeblogPageRequest pageRequest = null;
+ try {
+ pageRequest = new WeblogPageRequest(request);
+ } catch(Exception e) {
+ mLogger.error("error creating page request", e);
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ String key = this.CACHE_ID+":"+this.generateKey(pageRequest);
+
+ Date updateTime = null;
+ try {
+ // we need the last expiration time for the given weblog
+ long lastExpiration = 0;
+ Date lastExpirationDate =
+ (Date) CacheManager.getLastExpiredDate(pageRequest.getWeblogHandle());
+ if(lastExpirationDate != null)
+ lastExpiration = lastExpirationDate.getTime();
+
+ LazyExpiringCacheEntry entry =
+ (LazyExpiringCacheEntry) this.mCache.get(key);
+ if(entry != null) {
+ updateTime = (Date) entry.getValue(lastExpiration);
+
+ if(updateTime == null)
+ mLogger.debug("HIT-INVALID "+key);
+ }
+
+ if (updateTime == null) {
+ mLogger.debug("MISS "+key);
+
+ if(pageRequest.getWeblogHandle() != null) {
+ // just set updateTime to now
+ updateTime = new Date();
+ this.mCache.put(key, new LazyExpiringCacheEntry(updateTime));
+ }
+
+ } else {
+ mLogger.debug("HIT "+key);
+ }
+
+ // Check the incoming if-modified-since header
+ Date sinceDate =
+ new Date(request.getDateHeader("If-Modified-Since"));
+
+ if (updateTime != null) {
+ // convert date (JDK 1.5 workaround)
+ String date = dateFormatter.format(updateTime);
+ updateTime = new Date(date);
+ if (updateTime.compareTo(sinceDate) <= 0) {
+ mLogger.debug("NOT_MODIFIED "+key);
+ response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+ return;
+ }
+ }
+
+ } catch (IllegalArgumentException e) {
+ // Thrown by getDateHeader if not in valid format. This can be
+ // safely ignored, the only consequence is that the NOT MODIFIED
+ // response is not set.
+ }
+
+ // Set outgoing last modified header
+ if (updateTime != null) {
+ response.setDateHeader("Last-Modified", updateTime.getTime());
+ }
+
+ chain.doFilter(request, response);
+
+ mLogger.debug("exiting");
+ }
+
+
+ /**
+ * Generate a cache key from a parsed weblog page request.
+ * This generates a key of the form ...
+ *
+ * weblog/<handle>/page/<weblogPage>/[anchor]/<language>/[user]
+ * or
+ * weblog/<handle>/page/<weblogPage>/[date]/[category]/<language>/[user]
+ *
+ *
+ * examples ...
+ *
+ * weblog/foo/page/Weblog/en
+ * weblog/foo/page/Weblog/entry_anchor/en
+ * weblog/foo/page/Weblog/20051110/en
+ * weblog/foo/page/Weblog/MyCategory/en
+ *
+ */
+ private String generateKey(WeblogPageRequest pageRequest) {
+
+ StringBuffer key = new StringBuffer();
+ key.append("weblog/");
+ key.append(pageRequest.getWeblogHandle().toLowerCase());
+ key.append("/page/");
+ key.append(pageRequest.getWeblogPage());
+
+ if(pageRequest.getWeblogAnchor() != null) {
+ // convert to base64 because there can be spaces in anchors :/
+ key.append("/").append(Utilities.toBase64(pageRequest.getWeblogAnchor().getBytes()));
+ } else {
+ if(pageRequest.getWeblogDate() != null) {
+ key.append("/").append(pageRequest.getWeblogDate());
+ }
+
+ if(pageRequest.getWeblogCategory() != null) {
+ String cat = pageRequest.getWeblogCategory();
+ if(cat.startsWith("/")) {
+ cat = cat.substring(1);
+ }
+
+ // categories may contain spaces, which is not desired
+ key.append("/").append(org.apache.commons.lang.StringUtils.deleteWhitespace(cat));
+ }
+ }
+
+ // add language
+ key.append("/").append(pageRequest.getLanguage());
+
+ // add login state
+ if(pageRequest.getAuthenticUser() != null) {
+ key.append("/user=").append(pageRequest.getAuthenticUser());
+ }
+
+ return key.toString();
+ }
+
+
+ /**
+ * A weblog entry has changed.
+ */
+ public void invalidate(WeblogEntryData entry) {
+
+ mLogger.debug("invalidating entry = "+entry.getAnchor());
+
+ // we need to remove the following cached items if they exist
+ // - the weblog main page
+ // - the weblog entry permalink page
+ // - the weblog entry category page
+ // - the weblog entry date archive pages
+
+ /*
+ Set removeSet = new HashSet();
+
+ // TODO: it would be nice to be able to do this without iterating
+ // over the entire cache key set
+ String key = null;
+ Iterator allKeys = this.mCache.keySet().iterator();
+ while(allKeys.hasNext()) {
+ key = (String) allKeys.next();
+ if(key.startsWith("ifmod:weblog/"+entry.getWebsite().getHandle())) {
+ removeSet.add(key);
+ }
+ }
+
+ this.mCache.remove(removeSet);
+ */
+ }
+
+
+ /**
+ * A weblog has changed.
+ */
+ public void invalidate(WebsiteData website) {
+
+ mLogger.debug("invalidating website = "+website.getHandle());
+
+ // we need to remove the following cached items if they exist
+ // - all pages for this weblog
+
+ /*
+ Set removeSet = new HashSet();
+
+ // TODO: it would be nice to be able to do this without iterating
+ // over the entire cache key set
+ String key = null;
+ Iterator allKeys = this.mCache.keySet().iterator();
+ while(allKeys.hasNext()) {
+ key = (String) allKeys.next();
+
+ if(key.startsWith("ifmod:weblog/"+website.getHandle())) {
+ removeSet.add(key);
+ }
+ }
+
+ this.mCache.remove(removeSet);
+ */
+ }
+
+
+ /**
+ * A bookmark has changed.
+ */
+ public void invalidate(BookmarkData bookmark) {
+ this.invalidate(bookmark.getWebsite());
+ }
+
+
+ /**
+ * A folder has changed.
+ */
+ public void invalidate(FolderData folder) {
+ this.invalidate(folder.getWebsite());
+ }
+
+
+ /**
+ * A comment has changed.
+ */
+ public void invalidate(CommentData comment) {
+ this.invalidate(comment.getWeblogEntry());
+ }
+
+
+ /**
+ * A referer has changed.
+ */
+ public void invalidate(RefererData referer) {
+ // ignored
+ // TODO: we probably should invalidate the entire website?
+ }
+
+
+ /**
+ * A user profile has changed.
+ */
+ public void invalidate(UserData user) {
+ // ignored
+ // TODO: i don't think weblog pages currently have user info, but this may change
+ }
+
+
+ /**
+ * A category has changed.
+ */
+ public void invalidate(WeblogCategoryData category) {
+ this.invalidate(category.getWebsite());
+ }
+
+
+ /**
+ * A weblog template has changed.
+ */
+ public void invalidate(WeblogTemplate template) {
+ this.invalidate(template.getWebsite());
+ }
+
+
+ public void clear() {
+ this.mCache.clear();
+ }
+
+
+ public Map getStats() {
+
+ Map stats = new HashMap();
+
+ return stats;
+ }
+
+
+ /**
+ * Destroy method for this filter
+ */
+ public void destroy() {
+ }
+
+
+ /**
+ * Init method for this filter
+ */
+ public void init(FilterConfig filterConfig) {
+
+ mLogger.info("Initializing if-modified cache");
+
+ Map cacheProps = new HashMap();
+ Enumeration allProps = RollerConfig.keys();
+ String prop = null;
+ while(allProps.hasMoreElements()) {
+ prop = (String) allProps.nextElement();
+
+ // we are only interested in props for this cache
+ if(prop.startsWith(CACHE_ID+".")) {
+ cacheProps.put(prop.substring(CACHE_ID.length()+1),
+ RollerConfig.getProperty(prop));
+ }
+ }
+
+ mLogger.info(cacheProps);
+
+ mCache = CacheManager.constructCache(this, cacheProps);
+ }
+
+}
Added: incubator/roller/trunk/src/org/apache/roller/presentation/filters/IfPlanetModifiedFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/IfPlanetModifiedFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/IfPlanetModifiedFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/IfPlanetModifiedFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,156 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. The ASF licenses this file to You
+* 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. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.presentation.filters;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.RollerException;
+import org.apache.roller.config.RollerConfig;
+import org.apache.roller.model.RollerFactory;
+import org.apache.roller.presentation.PlanetRequest;
+import org.apache.roller.presentation.cache.ExpiringCacheEntry;
+
+
+/**
+ * Handles if-modified-since checking for planet resources.
+ *
+ * @web.filter name="IfPlanetModifiedFilter"
+ *
+ * @author David M Johnson
+ */
+public class IfPlanetModifiedFilter implements Filter {
+
+ private static Log mLogger = LogFactory.getLog(IfPlanetModifiedFilter.class);
+
+ private long timeout = 15 * 60 * 1000;
+ private ExpiringCacheEntry lastUpdateTime = null;
+
+ SimpleDateFormat dateFormatter = new SimpleDateFormat("EEE MMM d HH:mm:ss z yyyy");
+
+
+ /**
+ * Filter processing.
+ *
+ * We check the incoming request for an "if-modified-since" header and
+ * repond with a 304 NOT MODIFIED when appropriate.
+ */
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+ throws IOException, ServletException {
+
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+
+ PlanetRequest planetRequest = null;
+ try {
+ planetRequest = new PlanetRequest(request);
+ } catch(Exception e) {
+ mLogger.error("error creating planet request", e);
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ Date updateTime = null;
+ try {
+ // first try our cached version
+ if(this.lastUpdateTime != null) {
+ updateTime = (Date) this.lastUpdateTime.getValue();
+ }
+
+ // we need to get a fresh value
+ if(updateTime == null) {
+
+ updateTime = RollerFactory.getRoller().getPlanetManager().getLastUpdated();
+ if (updateTime == null) {
+ updateTime = new Date();
+ mLogger.warn("Can't get lastUpdate time, using current time instead");
+ }
+
+ this.lastUpdateTime = new ExpiringCacheEntry(updateTime, this.timeout);
+ }
+
+ // RSS context loader needs updateTime, so stash it
+ request.setAttribute("updateTime", updateTime);
+
+ // Check the incoming if-modified-since header
+ Date sinceDate =
+ new Date(request.getDateHeader("If-Modified-Since"));
+
+ if (updateTime != null) {
+ // convert date (JDK 1.5 workaround)
+ synchronized (dateFormatter) {
+ String date = dateFormatter.format(updateTime);
+ updateTime = new Date(date);
+ }
+ if (updateTime.compareTo(sinceDate) <= 0) {
+ response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+ return;
+ }
+ }
+
+ } catch(RollerException re) {
+ // problem talking to db?
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ request.setAttribute("DisplayException", re);
+ return;
+ } catch(IllegalArgumentException e) {
+ // Thrown by getDateHeader if not in valid format. This can be
+ // safely ignored, the only consequence is that the NOT MODIFIED
+ // response is not set.
+ }
+
+ // Set outgoing last modified header
+ if (updateTime != null) {
+ response.setDateHeader("Last-Modified", updateTime.getTime());
+ }
+
+ chain.doFilter(request, response);
+ }
+
+
+ /**
+ * Init method for this filter
+ */
+ public void init(FilterConfig filterConfig) {
+
+ mLogger.info("Initializing if-modified planet filter");
+
+ // lookup our timeout value
+ String timeoutString = RollerConfig.getProperty("cache.planet.timeout");
+ try {
+ long timeoutSecs = Long.parseLong(timeoutString);
+ this.timeout = timeoutSecs * 1000;
+ } catch(Exception e) {
+ // ignored ... illegal value
+ }
+ }
+
+
+ public void destroy() {}
+
+}