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 [16/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/filters/MainPageCacheFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/MainPageCacheFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/MainPageCacheFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/MainPageCacheFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,332 @@
+/*
+* 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.
+*/
+/*
+ * MainPageCacheFilter.java
+ *
+ * Created on November 7, 2005, 2:32 PM
+ */
+package org.apache.roller.presentation.filters;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+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.LanguageUtil;
+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.util.CacheHttpServletResponseWrapper;
+import org.apache.roller.presentation.util.ResponseContent;
+
+
+/**
+ * A filter used for caching the fully rendered pages ... /main.do, /planet.do
+ *
+ * @web.filter name="MainPageCacheFilter"
+ *
+ * @author Allen Gilliland
+ */
+public class MainPageCacheFilter implements Filter, CacheHandler {
+
+ private static Log mLogger = LogFactory.getLog(MainPageCacheFilter.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.mainpage";
+
+ private boolean excludeOwnerPages = false;
+ private Cache mCache = null;
+
+ // for metrics
+ private double hits = 0;
+ private double misses = 0;
+ private double skips = 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;
+
+ String key = null;
+ Principal prince = null;
+
+ String servlet = request.getServletPath();
+ if(servlet.equals("/main.do")) {
+ key = "main/page";
+ } else {
+ // not a main page request
+ mLogger.warn("not a main page "+servlet);
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ try {
+ // determine language
+ Locale locale = LanguageUtil.getViewLocale(request);
+ key += "/" + locale.getLanguage();
+
+ // login status
+ prince = request.getUserPrincipal();
+ if(prince != null) {
+ key += "/user=" + prince.getName();
+ }
+
+ } catch(Exception e) {
+ // problem getting language?
+ mLogger.error("problem parsing request", e);
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+
+ try {
+ ResponseContent respContent = null;
+ if(!this.excludeOwnerPages || prince == null) {
+ respContent = (ResponseContent) this.mCache.get(key);
+ }
+
+ if(respContent == null) {
+
+ mLogger.debug("MISS "+key);
+ this.misses++;
+
+ CacheHttpServletResponseWrapper cacheResponse =
+ new CacheHttpServletResponseWrapper(response);
+
+ chain.doFilter(request, cacheResponse);
+
+ cacheResponse.flushBuffer();
+
+ // only cache if we didn't get an exception
+ if (request.getAttribute("DisplayException") == null) {
+ ResponseContent rc = cacheResponse.getContent();
+
+ // only cache if this is not a logged in user?
+ if(!this.excludeOwnerPages || prince == null) {
+ this.mCache.put(key, rc);
+ } else {
+ mLogger.debug("SKIPPED "+key);
+ this.skips++;
+ }
+ } 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 page "+key, ex);
+ }
+
+ // gotta send something to the client
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+
+ mLogger.debug("exiting");
+ }
+
+
+ /**
+ * A weblog entry has changed.
+ */
+ public void invalidate(WeblogEntryData entry) {
+ this.mCache.clear();
+ }
+
+
+ /**
+ * A weblog has changed.
+ */
+ public void invalidate(WebsiteData website) {
+ this.mCache.clear();
+ }
+
+
+ /**
+ * 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) {
+ // ignored
+ }
+
+
+ /**
+ * 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();
+ this.startTime = new Date();
+ this.hits = 0;
+ this.misses = 0;
+ this.skips = 0;
+ }
+
+
+ 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("skips", new Double(this.skips));
+
+ // calculate efficiency
+ if(misses > 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 main page cache");
+
+ this.excludeOwnerPages =
+ RollerConfig.getBooleanProperty("cache.mainpage.excludeOwnerEditPages");
+
+ 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/PersistenceSessionFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/PersistenceSessionFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/PersistenceSessionFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/PersistenceSessionFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,75 @@
+/*
+* 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.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.model.Roller;
+import org.apache.roller.model.RollerFactory;
+
+
+/**
+ * Sole responsibility is to ensure that each request's Roller
+ * persistence session is released at end of the request.
+ *
+ * @web.filter name="PersistenceSessionFilter"
+ * @author David M. Johnson
+ */
+public class PersistenceSessionFilter implements Filter {
+
+ private static Log mLogger = LogFactory.getLog(PersistenceSessionFilter.class);
+
+
+ /**
+ * Release Roller persistence session at end of request processing.
+ */
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+ throws IOException, ServletException {
+
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+
+ mLogger.debug("Entered PersistenceSessionFilter");
+
+ Roller roller = RollerFactory.getRoller();
+ try {
+ chain.doFilter(request, response);
+ } finally {
+ mLogger.debug("Releasing Roller Session");
+ roller.release();
+ }
+
+ mLogger.debug("Exiting PersistenceSessionFilter");
+ }
+
+
+ public void init(FilterConfig filterConfig) throws ServletException {}
+
+ public void destroy() {}
+
+}
+
Added: incubator/roller/trunk/src/org/apache/roller/presentation/filters/PlanetCacheFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/PlanetCacheFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/PlanetCacheFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/PlanetCacheFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,355 @@
+/*
+* 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.
+*/
+/*
+ * PlanetCacheFilter.java
+ *
+ * Created on December 12, 2005, 10:03 AM
+ */
+
+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.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.PlanetRequest;
+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.util.CacheHttpServletResponseWrapper;
+import org.apache.roller.presentation.util.ResponseContent;
+
+/**
+ * A cache filter for Planet Roller items ... /planet.do, /planetrss
+ *
+ * @web.filter name="PlanetCacheFilter"
+ *
+ * @author Allen Gilliland
+ */
+public class PlanetCacheFilter implements Filter, CacheHandler {
+
+ private static Log mLogger = LogFactory.getLog(PlanetCacheFilter.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.planet";
+
+ private boolean excludeOwnerPages = false;
+ private Cache mCache = null;
+
+ // for metrics
+ private double hits = 0;
+ private double misses = 0;
+ private double skips = 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;
+
+ PlanetRequest planetRequest = null;
+ try {
+ planetRequest = new PlanetRequest(request);
+ } catch(Exception e) {
+ // some kind of error parsing the request
+ mLogger.error("error creating planet request", e);
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ String key = "planetCache:"+this.generateKey(planetRequest);
+
+ try {
+ ResponseContent respContent = null;
+ if(!this.excludeOwnerPages || !planetRequest.isLoggedIn()) {
+ respContent = (ResponseContent) this.mCache.get(key);
+ }
+
+ if(respContent == null) {
+
+ mLogger.debug("MISS "+key);
+ this.misses++;
+
+ CacheHttpServletResponseWrapper cacheResponse =
+ new CacheHttpServletResponseWrapper(response);
+
+ chain.doFilter(request, cacheResponse);
+
+ cacheResponse.flushBuffer();
+
+ // only cache if we didn't get an exception
+ if (request.getAttribute("DisplayException") == null) {
+ ResponseContent rc = cacheResponse.getContent();
+
+ // only cache if this is not a logged in user?
+ if(!this.excludeOwnerPages || !planetRequest.isLoggedIn()) {
+ this.mCache.put(key, rc);
+ } else {
+ mLogger.debug("SKIPPED "+key);
+ this.skips++;
+ }
+ } 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 page "+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 planet request.
+ * This generates a key of the form ...
+ *
+ * <context>/<type>/<language>[/user]
+ * or
+ * <context>/<type>[/flavor]/<language>[/excerpts]
+ *
+ *
+ * examples ...
+ *
+ * planet/page/en
+ * planet/feed/rss/en/excerpts
+ *
+ */
+ private String generateKey(PlanetRequest planetRequest) {
+
+ StringBuffer key = new StringBuffer();
+ key.append(planetRequest.getContext());
+ key.append("/");
+ key.append(planetRequest.getType());
+
+ if(planetRequest.getFlavor() != null) {
+ key.append("/").append(planetRequest.getFlavor());
+ }
+
+ // add language
+ key.append("/").append(planetRequest.getLanguage());
+
+ if(planetRequest.getFlavor() != null) {
+ // add excerpts
+ if(planetRequest.isExcerpts()) {
+ key.append("/excerpts");
+ }
+ } else {
+ // add login state
+ if(planetRequest.getAuthenticUser() != null) {
+ key.append("/user=").append(planetRequest.getAuthenticUser());
+ }
+ }
+
+ return key.toString();
+ }
+
+
+ /**
+ * A weblog entry has changed.
+ */
+ public void invalidate(WeblogEntryData entry) {
+ // ignored
+ }
+
+
+ /**
+ * A weblog has changed.
+ */
+ public void invalidate(WebsiteData website) {
+ // ignored
+ }
+
+
+ /**
+ * 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) {
+ // ignored
+ }
+
+
+ /**
+ * 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();
+ this.startTime = new Date();
+ this.hits = 0;
+ this.misses = 0;
+ this.skips = 0;
+ }
+
+
+ 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("skips", new Double(this.skips));
+
+ // calculate efficiency
+ if(misses > 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 planet cache");
+
+ this.excludeOwnerPages =
+ RollerConfig.getBooleanProperty("cache.planet.excludeOwnerEditPages");
+
+ 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/RefererFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/RefererFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/RefererFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/RefererFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,223 @@
+/*
+* 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.regex.Pattern;
+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.business.referrers.IncomingReferrer;
+import org.apache.roller.business.referrers.ReferrerQueueManager;
+import org.apache.roller.model.RollerFactory;
+import org.apache.roller.presentation.RollerContext;
+import org.apache.roller.config.RollerConfig;
+import org.apache.roller.model.UserManager;
+import org.apache.roller.pojos.WebsiteData;
+import org.apache.roller.presentation.InvalidRequestException;
+import org.apache.roller.presentation.WeblogPageRequest;
+import org.apache.roller.util.SpamChecker;
+
+
+/**
+ * Keep track of referers.
+ *
+ * @author David M. Johnson
+ * @web.filter name="RefererFilter"
+ */
+public class RefererFilter implements Filter {
+
+ private static Log mLogger = LogFactory.getLog(RefererFilter.class);
+ private static final String ROBOT_PATTERN_PROP_NAME = "referrer.robotCheck.userAgentPattern";
+
+ private static Pattern robotPattern = null;
+
+ private FilterConfig mFilterConfig = null;
+ private boolean processingEnabled = true;
+
+
+ /**
+ * doFilter
+ */
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+ throws IOException, ServletException {
+
+ // if referrer processing is disabled then we are done
+ if(!this.processingEnabled) {
+ chain.doFilter(req, res);
+ return;
+ }
+
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+ boolean ignoreReferrer = false;
+ boolean isRefSpammer = false;
+ boolean isRobot = false;
+ String referrerUrl = request.getHeader("Referer");
+ StringBuffer reqsb = request.getRequestURL();
+ if (request.getQueryString() != null) {
+ reqsb.append("?");
+ reqsb.append(request.getQueryString());
+ }
+ String requestUrl = reqsb.toString();
+
+ // parse the incoming request and make sure it's a valid page request
+ WebsiteData weblog = null;
+ WeblogPageRequest pageRequest = null;
+ try {
+ pageRequest = new WeblogPageRequest(request);
+ UserManager userMgr = RollerFactory.getRoller().getUserManager();
+ weblog = userMgr.getWebsiteByHandle(pageRequest.getWeblogHandle());
+
+ if(weblog == null) {
+ throw new Exception("no weblog named "+pageRequest.getWeblogHandle());
+ }
+
+ } catch(Exception ex) {
+ // bad url or couldn't obtain weblog
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ // determine if this request came from a robot
+ if (robotPattern != null) {
+ // If the pattern is present, we check for whether the User-Agent matches,
+ // and set isRobot if so. Currently, all referral processing, including
+ // spam check, is skipped for robots identified in this way.
+ String userAgent = request.getHeader("User-Agent");
+ isRobot = (userAgent != null && userAgent.length() > 0 && robotPattern.matcher(userAgent).matches());
+ }
+
+ // validate the referrer
+ if (pageRequest != null && pageRequest.getWeblogHandle() != null && !isRobot) {
+
+ RollerContext rctx = RollerContext.getRollerContext();
+
+ // Base page URLs, with and without www.
+ String basePageUrlWWW =
+ rctx.getAbsoluteContextUrl(request)+"/page/"+weblog.getHandle();
+ String basePageUrl = basePageUrlWWW;
+ if ( basePageUrlWWW.startsWith("http://www.") ) {
+ // chop off the http://www.
+ basePageUrl = "http://"+basePageUrlWWW.substring(11);
+ }
+
+ // ignore referrers coming from users own blog
+ if (referrerUrl == null ||
+ (!referrerUrl.startsWith(basePageUrl) &&
+ !referrerUrl.startsWith(basePageUrlWWW))) {
+
+ String selfSiteFragment = "/page/"+weblog.getHandle();
+
+ // validate the referrer
+ if ( referrerUrl != null ) {
+ // ignore a Referrer from the persons own blog
+ if (referrerUrl.indexOf(selfSiteFragment) != -1) {
+ referrerUrl = null;
+ ignoreReferrer = true;
+ } else {
+ // treat editor referral as direct
+ int lastSlash = requestUrl.indexOf("/", 8);
+ if (lastSlash == -1) lastSlash = requestUrl.length();
+ String requestSite = requestUrl.substring(0, lastSlash);
+
+ if (referrerUrl.matches(requestSite + ".*\\.do.*")) {
+ referrerUrl = null;
+ } else {
+ // If referer URL is blacklisted, throw it out
+ isRefSpammer = SpamChecker.checkReferrer(weblog, referrerUrl);
+ }
+ }
+ }
+
+ } else {
+ mLogger.debug("Ignoring referer = "+referrerUrl);
+ ignoreReferrer = true;
+ }
+ }
+
+ // pre-processing complete, let's finish the job
+ if (isRefSpammer) {
+ // spammers get a 403 Access Denied
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+
+ } else if(!isRobot && !ignoreReferrer) {
+ // referrer is valid, lets record it
+ try {
+ IncomingReferrer referrer = new IncomingReferrer();
+ referrer.setReferrerUrl(referrerUrl);
+ referrer.setRequestUrl(requestUrl);
+ referrer.setWeblogHandle(pageRequest.getWeblogHandle());
+ referrer.setWeblogAnchor(pageRequest.getWeblogAnchor());
+ referrer.setWeblogDateString(pageRequest.getWeblogDate());
+
+ ReferrerQueueManager refQueue =
+ RollerFactory.getRoller().getReferrerQueueManager();
+ refQueue.processReferrer(referrer);
+ } catch(Exception e) {
+ mLogger.error("Error processing referrer", e);
+ }
+ }
+
+ // referrer processed, continue with request
+ chain.doFilter(req, res);
+ }
+
+
+ /**
+ * init
+ */
+ public void init(FilterConfig filterConfig) throws ServletException {
+
+ this.mFilterConfig = filterConfig;
+
+ // see if built-in referrer processing is enabled
+ this.processingEnabled =
+ RollerConfig.getBooleanProperty("referrers.processing.enabled");
+
+ mLogger.info("Referrer processing enabled = "+this.processingEnabled);
+
+ // check for possible robot pattern
+ String robotPatternStr = RollerConfig.getProperty(ROBOT_PATTERN_PROP_NAME);
+ if (robotPatternStr != null && robotPatternStr.length() >0) {
+ // Parse the pattern, and store the compiled form.
+ try {
+ robotPattern = Pattern.compile(robotPatternStr);
+ } catch (Exception e) {
+ // Most likely a PatternSyntaxException; log and continue as if it is not set.
+ mLogger.error("Error parsing "+ ROBOT_PATTERN_PROP_NAME + " value '" +
+ robotPatternStr + "'. Robots will not be filtered. ", e);
+ }
+ }
+ }
+
+
+ /**
+ * destroy
+ */
+ public void destroy() {}
+
+}
Added: incubator/roller/trunk/src/org/apache/roller/presentation/filters/RequestFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/RequestFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/RequestFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/RequestFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,93 @@
+/*
+* 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.Date;
+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.HttpServletResponse;
+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;
+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.presentation.RollerContext;
+import org.apache.roller.presentation.RollerRequest;
+import org.apache.roller.presentation.util.RequestUtil;
+
+
+/**
+ * Entry point filter for Weblog page and Editor UI, this filter
+ * creates a RollerRequest object to parse pathinfo and request parameters.
+ *
+ * @web.filter name="RequestFilter"
+ *
+ * @author David M. Johnson, Matt Raible
+ */
+public class RequestFilter implements Filter {
+ private FilterConfig mFilterConfig = null;
+ private static Log mLogger =
+ LogFactory.getFactory().getInstance(RequestFilter.class);
+
+ public void doFilter(
+ ServletRequest req, ServletResponse res, FilterChain chain)
+ throws IOException, ServletException {
+
+ // NOTE: Setting character encoding and JSTL/Struts locale sync has been
+ // moved to CharEncodingFilter, which is mapped for all URIs in the context.
+
+ HttpSession session = ((HttpServletRequest)req).getSession();
+ HttpServletRequest request = (HttpServletRequest)req;
+ HttpServletResponse response = (HttpServletResponse)res;
+ Roller roller = RollerFactory.getRoller();
+ RollerRequest rreq = null;
+ try {
+ rreq = RollerRequest.getRollerRequest(
+ request, mFilterConfig.getServletContext());
+ } catch (Throwable e) {
+ // NOTE: this is not a page-not-found problem
+ request.setAttribute("DisplayException", e);
+ mLogger.error(e);
+ return;
+ }
+ chain.doFilter(req, res);
+ }
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ mFilterConfig = filterConfig;
+ }
+
+ public void destroy() {
+ }
+}
+
Added: incubator/roller/trunk/src/org/apache/roller/presentation/filters/SchemeEnforcementFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/SchemeEnforcementFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/SchemeEnforcementFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/SchemeEnforcementFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,174 @@
+/*
+* 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.
+*/
+/*
+ * SchemeEnforcementFilter.java
+ *
+ * Created on September 16, 2005, 3:17 PM
+ */
+
+package org.apache.roller.presentation.filters;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Iterator;
+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;
+
+
+/**
+ * The SchemeEnforcementFilter is provided for Roller sites that enable secure
+ * logins and want to ensure that only login urls are used under https.
+ *
+ * @author Allen Gilliland
+ *
+ * @web.filter name="SchemeEnforcementFilter"
+ */
+public class SchemeEnforcementFilter implements Filter {
+
+ private static Log mLogger =
+ LogFactory.getLog(SchemeEnforcementFilter.class);
+
+ private FilterConfig filterConfig = null;
+
+ private boolean schemeEnforcementEnabled = false;
+ private boolean secureLoginEnabled = false;
+ private int httpPort = 80;
+ private int httpsPort = 443;
+ private String httpsHeaderName = null;
+ private String httpsHeaderValue = null;
+
+ private Set allowedUrls = new HashSet();
+
+
+ /**
+ * Process filter.
+ *
+ * We'll take the incoming request and first determine if this is a
+ * secure request. If the request is secure then we'll see if it matches
+ * one of the allowed secure urls, if not then we will redirect back out
+ * of https.
+ */
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain)
+ throws IOException, ServletException {
+
+ if(this.schemeEnforcementEnabled && this.secureLoginEnabled) {
+
+ HttpServletRequest req = (HttpServletRequest) request;
+ HttpServletResponse res = (HttpServletResponse) response;
+
+ mLogger.debug("checking path = "+req.getServletPath());
+
+ if(!request.isSecure() && allowedUrls.contains(req.getServletPath())) {
+ // http insecure request that should be over https
+ String redirect = "https://"+req.getServerName();
+
+ if(this.httpsPort != 443)
+ redirect += ":"+this.httpsPort;
+
+ redirect += req.getRequestURI();
+
+ if(req.getQueryString() != null)
+ redirect += "?"+req.getQueryString();
+
+ mLogger.debug("Redirecting to "+redirect);
+ res.sendRedirect(redirect);
+ return;
+
+ } else if(request.isSecure() && !allowedUrls.contains(req.getServletPath())) {
+ // https secure request that should be over http
+ String redirect = "http://"+req.getServerName();
+
+ if(this.httpPort != 80)
+ redirect += ":"+this.httpPort;
+
+ redirect += req.getRequestURI();
+
+ if(req.getQueryString() != null)
+ redirect += "?"+req.getQueryString();
+
+ mLogger.debug("Redirecting to "+redirect);
+ res.sendRedirect(redirect);
+ return;
+ }
+ }
+
+ chain.doFilter(request, response);
+ }
+
+
+ public void destroy() {}
+
+
+ /**
+ * Filter init.
+ *
+ * We are just collecting init properties which we'll use for each request.
+ */
+ public void init(FilterConfig filterConfig) {
+ this.filterConfig = filterConfig;
+
+ // determine if we are doing scheme enforcement
+ this.schemeEnforcementEnabled =
+ RollerConfig.getBooleanProperty("schemeenforcement.enabled");
+ this.secureLoginEnabled =
+ RollerConfig.getBooleanProperty("securelogin.enabled");
+
+ if(this.schemeEnforcementEnabled && this.secureLoginEnabled) {
+ // gather some more properties
+ String http_port =
+ RollerConfig.getProperty("securelogin.http.port");
+ String https_port =
+ RollerConfig.getProperty("securelogin.https.port");
+
+ try {
+ this.httpPort = Integer.parseInt(http_port);
+ this.httpsPort = Integer.parseInt(https_port);
+ } catch(NumberFormatException nfe) {
+ // ignored ... guess we'll have to use the defaults
+ mLogger.warn("error with secure login ports", nfe);
+ }
+
+ // finally, construct our list of allowable https urls
+ String urls =
+ RollerConfig.getProperty("schemeenforcement.https.urls");
+ String[] urlsArray = urls.split(",");
+ for(int i=0; i < urlsArray.length; i++)
+ this.allowedUrls.add(urlsArray[i]);
+
+ // some logging for the curious
+ mLogger.info("Scheme enforcement = enabled");
+ if(mLogger.isDebugEnabled()) {
+ mLogger.debug("allowed urls are:");
+ for(Iterator it = this.allowedUrls.iterator(); it.hasNext();)
+ mLogger.debug(it.next());
+ }
+ }
+ }
+
+}
Added: incubator/roller/trunk/src/org/apache/roller/presentation/filters/WeblogPageCacheFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/WeblogPageCacheFilter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/WeblogPageCacheFilter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/WeblogPageCacheFilter.java Mon May 1 15:23:02 2006
@@ -0,0 +1,460 @@
+/*
+* 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.
+*/
+/*
+ * WeblogPageCacheFilter.java
+ *
+ * Created on October 27, 2005, 12:19 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.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.presentation.util.CacheHttpServletResponseWrapper;
+import org.apache.roller.presentation.util.ResponseContent;
+import org.apache.roller.util.Utilities;
+
+
+/**
+ * A filter used for caching fully rendered weblog pages ... /page/*
+ *
+ * @web.filter name="WeblogPageCacheFilter"
+ *
+ * @author Allen Gilliland
+ */
+public class WeblogPageCacheFilter implements Filter, CacheHandler {
+
+ private static Log mLogger = LogFactory.getLog(WeblogPageCacheFilter.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.weblogpage";
+
+ private boolean excludeOwnerPages = false;
+ private Cache mCache = null;
+
+ // for metrics
+ private double hits = 0;
+ private double misses = 0;
+ private double purges = 0;
+ private double skips = 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;
+
+ WeblogPageRequest pageRequest = null;
+ try {
+ pageRequest = new WeblogPageRequest(request);
+ } catch(Exception e) {
+ // some kind of error parsing the request
+ mLogger.error("error creating page request", e);
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ String key = this.CACHE_ID+":"+this.generateKey(pageRequest);
+
+ try {
+ ResponseContent respContent = null;
+ if(!this.excludeOwnerPages || !pageRequest.isLoggedIn()) {
+ // 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) {
+ 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();
+
+ // Store as the cache content the result of the response
+ // if no exception was noted by content generator.
+ if (request.getAttribute("DisplayException") == null) {
+ ResponseContent rc = cacheResponse.getContent();
+
+ // only cache if this is not a logged in user?
+ if (!this.excludeOwnerPages || !pageRequest.isLoggedIn()) {
+ if (rc != null && rc.getSize() > 0) {
+ this.mCache.put(key, new LazyExpiringCacheEntry(rc));
+ } else {
+ mLogger.debug("Not caching zero length content for key: " + key);
+ }
+ } else {
+ mLogger.debug("SKIPPED "+key);
+ this.skips++;
+ }
+ } 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 page "+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 page request.
+ * This generates a key of the form ...
+ *
+ * weblog/<handle>/page/<type>[/anchor]/<weblogPage>/<language>[/user]
+ * or
+ * weblog/<handle>/page/<type>[/date][/category]/<weblogPage>/<language>[/user]
+ *
+ *
+ * examples ...
+ *
+ * weblog/foo/page/main/Weblog/en
+ * weblog/foo/page/permalink/entry_anchor/Weblog/en
+ * weblog/foo/page/archive/20051110/Weblog/en
+ * weblog/foo/page/archive/MyCategory/Weblog/en/user=myname
+ *
+ */
+ private String generateKey(WeblogPageRequest pageRequest) {
+
+ StringBuffer key = new StringBuffer();
+ key.append("weblog/");
+ key.append(pageRequest.getWeblogHandle().toLowerCase());
+ key.append("/page/");
+ key.append(pageRequest.getPageType());
+
+ 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 page name
+ key.append("/").append(pageRequest.getWeblogPage());
+
+ // 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 synchronized 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 archive pages
+
+ /*
+ String handle = entry.getWebsite().getHandle();
+ String keyBase = "pageCache:weblog/"+handle+"/page";
+
+ 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;
+
+ synchronized(mCache) {
+ Iterator allKeys = this.mCache.keySet().iterator();
+ while(allKeys.hasNext()) {
+ key = (String) allKeys.next();
+ if(key.startsWith(keyBase+"/main")) {
+ removeSet.add(key);
+ } else if(key.startsWith(keyBase+"/archive")) {
+ // at some point it would be cool to actually calculate what
+ // archive pages to remove in specific, rather than all of 'em
+ removeSet.add(key);
+ } else if(key.startsWith(keyBase+"/permalink/"+entry.getAnchor())) {
+ removeSet.add(key);
+ }
+ }
+ }
+
+ this.mCache.remove(removeSet);
+ this.purges += removeSet.size();
+ */
+
+ this.invalidate(entry.getWebsite());
+ }
+
+
+ /**
+ * A weblog has changed.
+ */
+ public synchronized 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;
+
+ synchronized(mCache) {
+ Iterator allKeys = this.mCache.keySet().iterator();
+ while(allKeys.hasNext()) {
+ key = (String) allKeys.next();
+
+ if(key.startsWith("pageCache:weblog/"+website.getHandle())) {
+ removeSet.add(key);
+ }
+ }
+ }
+
+ this.mCache.remove(removeSet);
+ this.purges += removeSet.size();
+ */
+ }
+
+
+ /**
+ * 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 reference user objects
+ }
+
+
+ /**
+ * 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());
+ }
+
+
+ /**
+ * 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;
+ this.skips = 0;
+ }
+
+
+ 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));
+ stats.put("skips", new Double(this.skips));
+
+ // 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 weblog page cache");
+
+ this.excludeOwnerPages =
+ RollerConfig.getBooleanProperty("cache.weblogpage.excludeOwnerEditPages");
+
+ 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/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/filters/package.html?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/filters/package.html (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/filters/package.html Mon May 1 15:23:02 2006
@@ -0,0 +1,27 @@
+<!--
+ 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.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title></title>
+</head>
+<body>
+Servlet filters for persistence, conditional get, compression, referers.
+
+</body>
+</html>
Added: incubator/roller/trunk/src/org/apache/roller/presentation/newsfeeds/NewsfeedCache.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/newsfeeds/NewsfeedCache.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/newsfeeds/NewsfeedCache.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/newsfeeds/NewsfeedCache.java Mon May 1 15:23:02 2006
@@ -0,0 +1,18 @@
+/*
+* 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.newsfeeds;
import java.io.InputStreamReader;
import java.net.URL;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.roller.util.LRUCache2;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.SyndFeedInput;
import java.io.UnsupportedEncodingException;
import java.net.URLConnection;
import org.apache.roller.config.RollerConfig;
/**
* Returns parsed RSS feed by pulling one from a cache or by retrieving and
* parging the specified feed using the Flock RSS parser.
* <br />
* TODO: use PlanetRoller to implement NewsfeedCache instead.
* <br />
* @author Lance Lavandowska
* @author Dave Johnson
*/
public class NewsfeedCache
{
private static Log mLogger = LogFactory.getFactory().getInstance(
NewsfeedCache.class);
/** Static singleton * */
private static NewsfeedCache mInstance = null;
/** Instance vars * */
private boolean
aggregator_enabled = true;
private boolean aggregator_cache_enabled = true;
private int aggregator_cache_timeout = 14400;
/** LRU cache */
LRUCache2 mCache = null;
/** Constructor */
private NewsfeedCache()
{
// lookup the props we need
String enabled = RollerConfig.getProperty("aggregator.enabled");
String usecache = RollerConfig.getProperty("aggregator.cache.enabled");
String cachetime = RollerConfig.getProperty("aggregator.cache.timeout");
if("true".equalsIgnoreCase(enabled))
this.aggregator_enabled = true;
if("true".equalsIgnoreCase(usecache))
this.aggregator_cache_enabled = true;
try {
this.aggregator_cache_timeout = Integer.parseInt(cachetime);
} catch(Exception e) { mLogger.warn(e); }
// finally ... create the cache
this.mCache = new LRUCache2(100, 1000 * this.aggregator_cache_timeout);
}
/** static singleton retriever */
public static NewsfeedCache getInstance()
{
synchronized (NewsfeedCache.class)
{
if (mInstance == null)
{
if (mLogger.isDebugEnabled())
{
mLogger.debug("Instantiating new NewsfeedCache");
}
mInstance = new NewsfeedCache();
}
}
return mInstance;
}
/**
* Returns a Channel object for the supplied RSS newsfeed URL.
*
* @param feedUrl
* RSS newsfeed URL.
* @return FlockFeedI for specified RSS newsfeed URL.
*/
public SyndFeed getChannel(String feedUrl)
{
SyndFeed feed = null;
try
{
// If aggregator has been disable return null
if (!aggregator_enabled)
{
return null;
}
if (aggregator_cache_enabled)
{
if (mLogger.isDebugEnabled())
{
mLogger.debug("Newsfeed: use Cache for " + feedUrl);
}
// Get pre-parsed feed from the cache
feed = (SyndFeed) mCache.get(feedUrl);
if (mLogger.isDebugEnabled())
{
mLogger.debug("Newsfeed: got from Cache");
}
if (feed == null)
{
try
{
// Parse the feed
SyndFeedInput feedInput = new SyndFeedInput();
feed = feedInput.build(new InputStreamReader(
new URL(feedUrl).openStream()));
}
catch (Exception e1)
{
mLogger.info("Error parsing RSS: " + feedUrl);
}
}
// Store parsed feed in the cache
mCache.put(feedUrl, feed);
mLogger.debug("Newsfeed: not in Cache");
}
else
{
if (mLogger.isDebugEnabled())
{
mLogger.debug("Newsfeed: not using Cache for " + feedUrl);
}
try
{
// charset fix from Jason Rumney (see ROL-766)
URLConnection connection = new URL(feedUrl).openConnection();
connection.connect();
String contentType = connection.getContentType();
// Default charset to UTF-8, since we are expecting XML
String charset = "UTF8";
if (contentType != null) {
int charsetStart = contentType.indexOf("charset=");
if (charsetStart >= 0) {
int charsetEnd = conte
ntType.indexOf(";", charsetStart);
if (charsetEnd == -1) charsetEnd = contentType.length();
charsetStart += "charset=".length();
charset = contentType.substring(charsetStart, charsetEnd);
// Check that charset is recognized by Java
try {
byte[] test = "test".getBytes(charset);
}
catch (UnsupportedEncodingException codingEx) {
// default to UTF-8
charset = "UTF8";
}
}
}
// Parse the feed
SyndFeedInput feedInput = new SyndFeedInput();
feed = feedInput.build(new InputStreamReader(
connection.getInputStream(), charset));
}
catch (Exception e1)
{
mLogger.info("Error parsing RSS: " + feedUrl);
}
}
}
catch (Exception ioe)
{
if (mLogger.isDebugEnabled())
{
mLogger.debug("Newsfeed: Unexpected exception", ioe);
}
}
return feed;
}
}
\ No newline at end of file
Added: incubator/roller/trunk/src/org/apache/roller/presentation/newsfeeds/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/newsfeeds/package.html?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/newsfeeds/package.html (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/newsfeeds/package.html Mon May 1 15:23:02 2006
@@ -0,0 +1,27 @@
+<!--
+ 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.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title></title>
+</head>
+<body>
+Cache used by deprecated #showNewsfeed() macros.
+
+</body>
+</html>
Added: incubator/roller/trunk/src/org/apache/roller/presentation/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/package.html?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/package.html (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/package.html Mon May 1 15:23:02 2006
@@ -0,0 +1,29 @@
+<!--
+ 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.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title></title>
+</head>
+<body>
+Top-level presentation layer classes: context, session, request, etc.
+<p />
+<img src="roller-ui.png" alt="diagram of Roller UI packages" />
+
+</body>
+</html>
Added: incubator/roller/trunk/src/org/apache/roller/presentation/pings/PingQueueProcessor.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/pings/PingQueueProcessor.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/pings/PingQueueProcessor.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/pings/PingQueueProcessor.java Mon May 1 15:23:02 2006
@@ -0,0 +1,202 @@
+/*
+ * 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.pings;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.RollerException;
+import org.apache.roller.config.PingConfig;
+import org.apache.roller.model.PingQueueManager;
+import org.apache.roller.model.RollerFactory;
+import org.apache.roller.pojos.PingQueueEntryData;
+import org.apache.roller.pojos.PingTargetData;
+import org.apache.roller.pojos.WebsiteData;
+import org.apache.roller.presentation.RollerContext;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Ping Queue Processor. Singleton encapsulating logic for processing the weblog update ping queue.
+ *
+ * @author <a href="mailto:anil@busybuddha.org">Anil Gangolli</a>
+ */
+public class PingQueueProcessor
+{
+ private static final Log logger = LogFactory.getLog(PingQueueProcessor.class);
+
+ private static PingQueueProcessor theInstance;
+
+
+ private RollerContext rollerContext;
+ private PingQueueManager pingQueueMgr;
+
+ public static PingQueueProcessor getInstance()
+ {
+ return theInstance;
+ }
+
+ private PingQueueProcessor(RollerContext rc) throws RollerException
+ {
+ rollerContext = rc;
+ pingQueueMgr = RollerFactory.getRoller().getPingQueueManager();
+ }
+
+ /**
+ * Initialize the singleton. This is called during <code>RollerContext</code> initialization.
+ *
+ * @param rc the Roller context
+ * @throws RollerException
+ */
+ public static synchronized void init(RollerContext rc) throws RollerException
+ {
+ if (theInstance != null)
+ {
+ logger.warn("Ignoring duplicate initialization of PingQueueProcessor!");
+ return;
+ }
+ theInstance = new PingQueueProcessor(rc);
+ if (logger.isDebugEnabled()) logger.debug("Ping queue processor initialized.");
+ }
+
+ /**
+ * Process the ping queue. Performs one pass through the ping queue, processing every entry once. On ping failure
+ * an entry is requeued for processing on subsequent passes until the configured maximum number of attempts is
+ * reached.
+ */
+ public synchronized void processQueue()
+ {
+ if (PingConfig.getSuspendPingProcessing()) {
+ logger.info("Ping processing has been suspended. Skipping current round of ping queue processing.");
+ return;
+ }
+
+ String absoluteContextUrl = rollerContext.getAbsoluteContextUrl();
+ if (absoluteContextUrl == null)
+ {
+ logger.warn("WARNING: Skipping current ping queue processing round because we cannot yet determine the site's absolute context url.");
+ return;
+ }
+
+ // TODO: Group by ping target and ping all sites for that target?
+ // We're currently not taking advantage of grouping by ping target site and then sending
+ // all of the pings for that target at once. If it becomes an efficiency issue, we should do
+ // that.
+
+ try
+ {
+ if (logger.isDebugEnabled()) logger.debug("Started processing ping queue.");
+ // Get all of the entries
+ List entries = pingQueueMgr.getAllQueueEntries();
+
+ // Process each entry
+ for (Iterator i = entries.iterator(); i.hasNext();)
+ {
+ PingQueueEntryData pingQueueEntry = (PingQueueEntryData) i.next();
+ processQueueEntry(absoluteContextUrl, pingQueueEntry);
+ }
+ if (logger.isDebugEnabled()) logger.debug("Finished processing ping queue.");
+ }
+ catch (Exception ex)
+ {
+ logger.error("Unexpected exception processing ping queue! Aborting this pass of ping queue processing.", ex);
+ }
+ }
+
+ /**
+ * Process an individual ping queue entry.
+ *
+ * @param absoluteContextUrl absolute context URL of the Roller site
+ * @param pingQueueEntry the ping queue entry
+ * @throws RollerException only if there are problems processing the queue. Exceptions from sending pings are
+ * handled, not thrown.
+ */
+ private void processQueueEntry(String absoluteContextUrl, PingQueueEntryData pingQueueEntry)
+ throws RollerException
+ {
+ if (logger.isDebugEnabled()) logger.debug("Processing ping queue entry: " + pingQueueEntry);
+
+ PingTargetData pingTarget = pingQueueEntry.getPingTarget();
+ WebsiteData website = pingQueueEntry.getWebsite();
+ boolean pingSucceeded = false;
+ if (PingConfig.getLogPingsOnly())
+ {
+ // Just log the ping and pretend it succeeded.
+ logger.info("Logging simulated ping for ping queue entry " + pingQueueEntry);
+ pingSucceeded = true;
+ }
+ else
+ {
+ // Actually process the ping
+ try
+ {
+ // Send the ping
+ WeblogUpdatePinger.sendPing(absoluteContextUrl, pingTarget, website);
+ // Consider successful ping transmission if we didn't get an exception. We don't care here
+ // about the result of the ping if it was transmitted.
+ pingSucceeded = true;
+ }
+ catch (Exception ex)
+ {
+ // Handle the ping error, either removing or requeuing the ping queue entry.
+ handlePingError(pingQueueEntry, ex);
+ }
+ }
+ // We do this outside of the previous try-catch because we don't want an exception here to be considered a ping error.
+ if (pingSucceeded)
+ {
+ if (logger.isDebugEnabled()) logger.debug("Processed ping: " + pingQueueEntry);
+ pingQueueMgr.removeQueueEntry(pingQueueEntry);
+ }
+ }
+
+ /**
+ * Handle any ping error.
+ *
+ * @param pingQueueEntry the ping queue entry
+ * @param ex the exception that occurred on the ping attempt
+ * @throws RollerException
+ */
+ private void handlePingError(PingQueueEntryData pingQueueEntry, Exception ex)
+ throws RollerException
+ {
+ if ((pingQueueEntry.incrementAttempts() < PingConfig.getMaxPingAttempts()) &&
+ WeblogUpdatePinger.shouldRetry(ex))
+ {
+ // We have attempts remaining, and it looks like we should retry,
+ // so requeue the entry for processing on subsequent rounds
+ logger.warn("Error on ping attempt (" + pingQueueEntry.getAttempts() + ") for " + pingQueueEntry +
+ ": [" + ex.getMessage() + "]. Will re-queue for later attempts.");
+ if (logger.isDebugEnabled()) logger.debug("Error on last ping attempt was: ", ex);
+ pingQueueMgr.saveQueueEntry(pingQueueEntry);
+ }
+ else
+ {
+ // Remove the entry
+ logger.warn("Error on ping attempt (" + pingQueueEntry.getAttempts() + ") for " + pingQueueEntry +
+ ": [" + ex.getMessage() + "]. Entry will be REMOVED from ping queue.");
+ if (logger.isDebugEnabled()) logger.debug("Error on last ping attempt was: ", ex);
+ pingQueueMgr.removeQueueEntry(pingQueueEntry);
+ // TODO: mark ping target invalid?
+ }
+ }
+
+
+}
Added: incubator/roller/trunk/src/org/apache/roller/presentation/pings/PingQueueTask.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/pings/PingQueueTask.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/pings/PingQueueTask.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/pings/PingQueueTask.java Mon May 1 15:23:02 2006
@@ -0,0 +1,89 @@
+/*
+ * 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.pings;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.RollerException;
+import org.apache.roller.model.Roller;
+import org.apache.roller.model.RollerFactory;
+import org.apache.roller.presentation.RollerContext;
+
+import java.util.TimerTask;
+
+/**
+ * Task for processing the ping queue at fixed intervals. This is set up during context initialization by {@link
+ * RollerContext}. The queue processing interval is currently set from the configuration {@link
+ * org.apache.roller.config.PingConfig} at startup time only.
+ *
+ * @author <a href="mailto:anil@busybuddha.org">Anil Gangolli</a>
+ */
+public class PingQueueTask extends TimerTask
+{
+ private static final Log logger = LogFactory.getLog(PingQueueTask.class);
+
+ // The periodic interval (in minutes) at which we are configured to run
+ long intervalMins;
+
+ /**
+ * Initialize the task.
+ *
+ * @param rc the Roller context.
+ * @throws RollerException
+ */
+ public void init(RollerContext rc, long intervalMins) throws RollerException
+ {
+ PingQueueProcessor.init(rc);
+ this.intervalMins = intervalMins;
+ }
+
+ /**
+ * Get the task's configured interval (in minutes).
+ *
+ * @return the tasks configured interval (in minutes).
+ */
+ public long getIntervalMins()
+ {
+ return intervalMins;
+ }
+
+ /**
+ * Run the task once.
+ */
+ public void run()
+ {
+ // Call the ping queue processor to process the queue
+ Roller roller = null;
+ try
+ {
+ roller = RollerFactory.getRoller();
+ PingQueueProcessor.getInstance().processQueue();
+ roller.flush();
+ }
+ catch (RollerException e)
+ {
+ // This is probably duplicate logging. May want to eliminate it, but should be rare.
+ logger.error("Error while processing ping queuer", e);
+ }
+ finally
+ {
+ if (roller != null) roller.release();
+ }
+ }
+}