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 2005/10/21 23:46:28 UTC
svn commit: r327589 [32/72] - in /incubator/roller/branches/roller_1.x: ./
contrib/ contrib/lib/ contrib/plugins/ contrib/plugins/src/
contrib/plugins/src/org/ contrib/plugins/src/org/roller/
contrib/plugins/src/org/roller/presentation/ contrib/plugins...
Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/LRUCacheHandler.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/LRUCacheHandler.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/LRUCacheHandler.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/LRUCacheHandler.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,470 @@
+/*
+ * Created on Jun 15, 2004
+ */
+package org.roller.presentation.pagecache.rollercache;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.roller.pojos.UserData;
+import org.roller.presentation.LanguageUtil;
+import org.roller.presentation.pagecache.FilterHandler;
+import org.roller.util.LRUCache;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.TreeMap;
+
+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.roller.config.RollerConfig;
+
+/**
+ * Page cache implementation that uses a simple LRUCache. Can be configured
+ * using filter configuration parameters:
+ * <ul>
+ * <li><b>size</b>: number of pages to keep in cache. Once cache reaches
+ * this size, each new cache entry will push out the LRU cache entry.</li>
+ *
+ * <li><b>timeoutInterval</b>: interval to timeout pages in seconds
+ * (default is 1800 seconds). Sites with a large number of users, and thus a
+ * lot of cache churn which makes this check unnecessary, may wish to set this
+ * to -1 to disable timeout checking.</li>
+ *
+ * <li><b>timeoutRatio</b>: portion of old pages to expire on timeout
+ * interval where 1.0 is 100% (default is 1.0). This only applies if the
+ * timeoutInterval is set to something other than -1.</li>
+ * </ul>
+ * @author David M Johnson
+ */
+public class LRUCacheHandler implements FilterHandler
+{
+ private static Log mLogger =
+ LogFactory.getFactory().getInstance(LRUCacheHandler.class);
+
+ private Map mPageCache = null;
+
+ private String mName = null;
+
+ /** Timeout interval: how often to run timeout task (default 30 mintes) */
+ private long mTimeoutInterval = 30 * 60 * 1000; // milliseconds
+
+ /** Timeout ratio: % of cache to expire on each timeout (default 1.0) */
+ private float mTimeoutRatio = 1.0F;
+
+ // Statistics
+ private int misses = 0;
+ private int hits = 0;
+
+ private final static String FILE_SEPARATOR = "/";
+ private final static char FILE_SEPARATOR_CHAR = FILE_SEPARATOR.charAt(0);
+ private final static short AVERAGE_KEY_LENGTH = 30;
+ private static final String m_strBase64Chars =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+
+ public LRUCacheHandler(FilterConfig config)
+ {
+ mName = config.getFilterName();
+ mLogger.info("Initializing for: " + mName);
+
+ String cacheSize = RollerConfig.getProperty("cache.filter.page.size");
+ String cacheTimeout = RollerConfig.getProperty("cache.filter.page.timeout");
+
+ int size = 200;
+ try
+ {
+ size = Integer.parseInt(cacheSize);
+ }
+ catch (Exception e)
+ {
+ mLogger.warn(config.getFilterName()
+ + "Can't read cache size parameter, using default...");
+ }
+ mLogger.info(mName + " size=" + size);
+ mPageCache = Collections.synchronizedMap(new LRUCache(size));
+
+ long intervalSeconds = mTimeoutInterval / 1000L;
+ try
+ {
+ mTimeoutInterval = 1000L * Long.parseLong(cacheTimeout);
+
+ if (mTimeoutInterval == -1)
+ {
+ mLogger.info(config.getFilterName()
+ + "timeoutInterval of -1: timeouts are disabled");
+ }
+ else if (mTimeoutInterval < (30 * 1000))
+ {
+ mTimeoutInterval = 30 * 1000;
+ mLogger.warn(config.getFilterName()
+ + "timeoutInterval cannot be less than 30 seconds");
+ }
+ }
+ catch (Exception e)
+ {
+ mLogger.warn(config.getFilterName()
+ + "Can't read timeoutInterval parameter, disabling timeout.");
+ mTimeoutInterval = -1;
+ }
+ mLogger.info(mName + " timeoutInterval=" + intervalSeconds);
+
+ try
+ {
+ mTimeoutRatio = Float.parseFloat(
+ config.getInitParameter("timeoutRatio"));
+ }
+ catch (Exception e)
+ {
+ mLogger.warn(config.getFilterName()
+ + "Can't read timeoutRatio parameter, using default...");
+ }
+ mLogger.info(mName + " timeoutRatio=" + mTimeoutRatio);
+
+ if (mTimeoutInterval != -1 && mTimeoutRatio != 0.0)
+ {
+ Timer timer = new Timer();
+ timer.scheduleAtFixedRate(new TimerTask() {
+ public void run() {
+ timeoutCache();
+ }
+ }, mTimeoutInterval, mTimeoutInterval);
+ }
+ }
+
+ /**
+ * @see org.roller.presentation.pagecache.FilterHandler#destroy()
+ */
+ public void destroy()
+ {
+ }
+
+ /**
+ * @see org.roller.presentation.pagecache.FilterHandler#doFilter(
+ * javax.servlet.ServletRequest, javax.servlet.ServletResponse,
+ * javax.servlet.FilterChain)
+ */
+ public void doFilter(ServletRequest req, ServletResponse res,
+ FilterChain chain) throws ServletException, IOException
+ {
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+
+ // get locale
+ Locale locale = LanguageUtil.getViewLocale(request);
+
+ // generate language-sensitive cache-key
+ String generatedKey = null;
+ if (locale != null)
+ {
+ generatedKey = generateEntryKey(null,
+ request, 1, locale.getLanguage());
+ }
+ else
+ {
+ generatedKey = generateEntryKey(null,
+ request, 1, null);
+ }
+
+ // Add authenticated user name, if there is one, to cache key
+ java.security.Principal prince = request.getUserPrincipal();
+ StringBuffer keyb = new StringBuffer();
+ keyb.append(generatedKey);
+ if (prince != null)
+ {
+ keyb.append("_");
+ keyb.append(prince);
+ }
+ String key = keyb.toString();
+
+ ResponseContent respContent = (ResponseContent)getFromCache(key);
+ if (respContent == null)
+ {
+ try
+ {
+ CacheHttpServletResponseWrapper cacheResponse =
+ new CacheHttpServletResponseWrapper(response);
+ chain.doFilter(request, cacheResponse);
+
+ // 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();
+ putToCache(key, rc);
+ }
+ else
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("Display exception, cache, key=");
+ sb.append(key);
+ mLogger.error(sb.toString());
+ }
+ }
+ catch (java.net.SocketException se)
+ {
+ // ignore socket exceptions
+ }
+ catch (Exception e)
+ {
+ // something unexpected and bad happened
+ StringBuffer sb = new StringBuffer();
+ sb.append("Error rendering page, key=");
+ sb.append(key);
+ mLogger.error(sb.toString());
+ }
+ }
+ else
+ {
+ try
+ {
+ respContent.writeTo(response);
+ }
+ catch (java.net.SocketException se)
+ {
+ // ignore socket exceptions
+ }
+ catch (Exception e)
+ {
+ if (mLogger.isDebugEnabled())
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("Probably a client abort exception, key=");
+ sb.append(key);
+ mLogger.error(sb.toString());
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Purge entire cache.
+ */
+ public synchronized void flushCache(HttpServletRequest req)
+ {
+ mPageCache.clear();
+ }
+
+ /**
+ * Purge user's entries from cache.
+ */
+ public synchronized void removeFromCache(HttpServletRequest req, UserData user)
+ {
+ // TODO: can we make this a little more precise, perhaps via regex?
+ String rssString = "/rss/" + user.getUserName(); // user's pages
+ String pageString = "/page/" + user.getUserName(); // user's RSS feeds
+ String mainRssString = "/rss_"; // main RSS feed
+ List purgeList = new ArrayList();
+
+ Iterator keys = mPageCache.keySet().iterator();
+ while (keys.hasNext())
+ {
+ String key = (String) keys.next();
+
+ if (key.indexOf(rssString)!=-1 || key.indexOf(pageString)!=-1 || key.indexOf(mainRssString)!=-1)
+ {
+ purgeList.add(key);
+ }
+ }
+
+ Iterator purgeIter = purgeList.iterator();
+ while (purgeIter.hasNext())
+ {
+ String key = (String) purgeIter.next();
+ mPageCache.remove(key);
+ }
+
+ if (mLogger.isDebugEnabled())
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("Purged, count=");
+ sb.append(purgeList.size());
+ sb.append(", user=");
+ sb.append(user.getUserName());
+ mLogger.debug(sb.toString());
+ }
+ }
+
+ public synchronized void timeoutCache()
+ {
+ if (mTimeoutRatio == 1.0)
+ {
+ mLogger.debug("Timing out whole cache: " + mName);
+ mPageCache.clear();
+ }
+ else
+ {
+ int numToTimeout = (int)(mTimeoutRatio * mPageCache.size());
+ mLogger.debug(
+ "Timing out " + numToTimeout + " of " + mPageCache.size()
+ + " entries from cache: " + mName);
+ ArrayList allKeys = new ArrayList(mPageCache.keySet());
+ for (int i=numToTimeout; i>0; i--)
+ {
+ mPageCache.remove(allKeys.get(i));
+ }
+ }
+ }
+
+ /**
+ * Get from cache. Synchronized because "In access-ordered linked hash
+ * maps, merely querying the map with get is a structural modification"
+ */
+ public synchronized Object getFromCache(String key)
+ {
+ Object entry = mPageCache.get(key);
+
+ if (entry != null && mLogger.isDebugEnabled())
+ {
+ hits++;
+ }
+ return entry;
+ }
+
+ public synchronized void putToCache(String key, Object entry)
+ {
+ mPageCache.put(key, entry);
+ if (mLogger.isDebugEnabled())
+ {
+ misses++;
+
+ StringBuffer sb = new StringBuffer();
+ sb.append("Missed, cache size=");
+ sb.append(mPageCache.size());
+ sb.append(", hits=");
+ sb.append(hits);
+ sb.append(", misses=");
+ sb.append(misses);
+ sb.append(", key=");
+ sb.append(key);
+ mLogger.debug(sb.toString());
+ }
+ }
+
+ public String generateEntryKey(String key,
+ HttpServletRequest request, int scope, String language)
+ {
+ StringBuffer cBuffer = new StringBuffer(AVERAGE_KEY_LENGTH);
+ // Append the language if available
+ if (language != null)
+ {
+ cBuffer.append(FILE_SEPARATOR).append(language);
+ }
+
+ //cBuffer.append(FILE_SEPARATOR).append(request.getServerName());
+
+ if (key != null)
+ {
+ cBuffer.append(FILE_SEPARATOR).append(key);
+ }
+ else
+ {
+ String generatedKey = request.getRequestURI();
+ if (generatedKey.charAt(0) != FILE_SEPARATOR_CHAR)
+ {
+ cBuffer.append(FILE_SEPARATOR_CHAR);
+ }
+ cBuffer.append(generatedKey);
+ cBuffer.append("_").append(request.getMethod()).append("_");
+ generatedKey = getSortedQueryString(request);
+ if (generatedKey != null)
+ {
+ try
+ {
+ java.security.MessageDigest digest =
+ java.security.MessageDigest.getInstance("MD5");
+ byte[] b = digest.digest(generatedKey.getBytes());
+ cBuffer.append("_");
+ // Base64 encoding allows for unwanted slash characters.
+ cBuffer.append(toBase64(b).replace('/', '_'));
+ }
+ catch (Exception e)
+ {
+ // Ignore query string
+ }
+ }
+ }
+ return cBuffer.toString();
+ }
+
+ protected String getSortedQueryString(HttpServletRequest request)
+ {
+ Map paramMap = request.getParameterMap();
+ if (paramMap.isEmpty())
+ {
+ return null;
+ }
+ Set paramSet = new TreeMap(paramMap).entrySet();
+ StringBuffer buf = new StringBuffer();
+ boolean first = true;
+ for (Iterator it = paramSet.iterator(); it.hasNext();)
+ {
+ Map.Entry entry = (Map.Entry) it.next();
+ String[] values = (String[]) entry.getValue();
+ for (int i = 0; i < values.length; i++)
+ {
+ String key = (String) entry.getKey();
+ if ((key.length() != 10) || !"jsessionid".equals(key))
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append('&');
+ }
+ buf.append(key).append('=').append(values[i]);
+ }
+ }
+ }
+ // We get a 0 length buffer if the only parameter was a jsessionid
+ if (buf.length() == 0)
+ {
+ return null;
+ }
+ else
+ {
+ return buf.toString();
+ }
+ }
+
+ /**
+ * Convert a byte array into a Base64 string (as used in mime formats)
+ */
+ private static String toBase64(byte[] aValue)
+ {
+ int byte1;
+ int byte2;
+ int byte3;
+ int iByteLen = aValue.length;
+ StringBuffer tt = new StringBuffer();
+ for (int i = 0; i < iByteLen; i += 3)
+ {
+ boolean bByte2 = (i + 1) < iByteLen;
+ boolean bByte3 = (i + 2) < iByteLen;
+ byte1 = aValue[i] & 0xFF;
+ byte2 = (bByte2) ? (aValue[i + 1] & 0xFF) : 0;
+ byte3 = (bByte3) ? (aValue[i + 2] & 0xFF) : 0;
+ tt.append(m_strBase64Chars.charAt(byte1 / 4));
+ tt.append(m_strBase64Chars.charAt((byte2 / 16)
+ + ((byte1 & 0x3) * 16)));
+ tt.append(((bByte2) ? m_strBase64Chars.charAt((byte3 / 64)
+ + ((byte2 & 0xF) * 4)) : '='));
+ tt.append(((bByte3) ? m_strBase64Chars.charAt(byte3 & 0x3F) : '='));
+ }
+ return tt.toString();
+ }
+}
Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/LRUCacheHandler2.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/LRUCacheHandler2.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/LRUCacheHandler2.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/LRUCacheHandler2.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,403 @@
+/*
+ * Created on Jun 15, 2004
+ */
+package org.roller.presentation.pagecache.rollercache;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+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.roller.config.RollerConfig;
+import org.roller.pojos.UserData;
+import org.roller.presentation.LanguageUtil;
+import org.roller.presentation.pagecache.FilterHandler;
+import org.roller.util.LRUCache2;
+
+/**
+ * Page cache implementation that uses a simple LRUCache. Can be configured
+ * using filter configuration parameters:
+ * <ul>
+ * <li><b>size</b>: number of pages to keep in cache. Once cache reaches
+ * this size, each new cache entry will push out the LRU cache entry.</li>
+ * <li><b>timeout</b>: interval to timeout pages in milliseconds.</li>
+ * </ul>
+ * @author David M Johnson
+ */
+public class LRUCacheHandler2 implements FilterHandler
+{
+ private static Log mLogger =
+ LogFactory.getFactory().getInstance(LRUCacheHandler2.class);
+
+ private LRUCache2 mPageCache = null;
+ private String mName = null;
+
+ // Statistics
+ private int misses = 0;
+ private int hits = 0;
+
+ private final static String FILE_SEPARATOR = "/";
+ private final static char FILE_SEPARATOR_CHAR = FILE_SEPARATOR.charAt(0);
+ private final static short AVERAGE_KEY_LENGTH = 30;
+ private static final String m_strBase64Chars =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ public LRUCacheHandler2(FilterConfig config)
+ {
+ mName = config.getFilterName();
+ mLogger.info("Initializing for: " + mName);
+
+ String cacheSize = RollerConfig.getProperty("cache.filter.page.size");
+ String cacheTimeout = RollerConfig.getProperty("cache.filter.page.timeout");
+
+ int size = 200;
+ try
+ {
+ size = Integer.parseInt(cacheSize);
+ }
+ catch (Exception e)
+ {
+ mLogger.warn(config.getFilterName()
+ + "Can't read cache size parameter, using default...");
+ }
+ mLogger.info(mName + " size=" + size);
+
+ long timeout = 30000;
+ try
+ {
+ timeout = Long.parseLong(cacheTimeout);
+ }
+ catch (Exception e)
+ {
+ mLogger.warn(config.getFilterName()
+ + "Can't read timeout parameter, using default.");
+ }
+ mLogger.info(mName + " timeout=" + timeout + "seconds");
+ mPageCache = new LRUCache2(size, timeout*1000);
+ }
+
+ /**
+ * @see org.roller.presentation.pagecache.FilterHandler#destroy()
+ */
+ public void destroy()
+ {
+ }
+
+ /**
+ * @see org.roller.presentation.pagecache.FilterHandler#doFilter(
+ * javax.servlet.ServletRequest, javax.servlet.ServletResponse,
+ * javax.servlet.FilterChain)
+ */
+ public void doFilter(ServletRequest req, ServletResponse res,
+ FilterChain chain) throws ServletException, IOException
+ {
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+
+ // Get locale, needed for creating cache key.
+ // Unfortunately, getViewLocal works by parsing the request URL
+ // which we would like to avoid where possible.
+ Locale locale = null;
+ try
+ {
+ locale = LanguageUtil.getViewLocale(request);
+ }
+ catch (Exception e)
+ {
+ // An error parsjng the request is considered to be a 404
+ mLogger.debug("Unable determine view local from request");
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ // generate language-sensitive cache-key
+ String generatedKey = null;
+ if (locale != null)
+ {
+ generatedKey = generateEntryKey(null,
+ request, 1, locale.getLanguage());
+ }
+ else
+ {
+ generatedKey = generateEntryKey(null,
+ request, 1, null);
+ }
+
+ // Add authenticated user name, if there is one, to cache key
+ java.security.Principal prince = request.getUserPrincipal();
+ StringBuffer keyb = new StringBuffer();
+ keyb.append(generatedKey);
+ if (prince != null)
+ {
+ keyb.append("_");
+ keyb.append(prince);
+ }
+ String key = keyb.toString();
+
+ ResponseContent respContent = (ResponseContent)getFromCache(key);
+ if (respContent == null)
+ {
+ try
+ {
+ 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();
+ putToCache(key, rc);
+ }
+ else
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("Display exception, cache, key=");
+ sb.append(key);
+ mLogger.error(sb.toString());
+ }
+ }
+ catch (java.net.SocketException se)
+ {
+ // ignore socket exceptions
+ }
+ catch (Exception e)
+ {
+ // something unexpected and bad happened
+ StringBuffer sb = new StringBuffer();
+ sb.append("Error rendering page, key=");
+ sb.append(key);
+ mLogger.error(sb.toString());
+ mLogger.debug(e);
+ }
+ }
+ else
+ {
+ try
+ {
+ respContent.writeTo(response);
+ }
+ catch (java.net.SocketException se)
+ {
+ // ignore socket exceptions
+ }
+ catch (Exception e)
+ {
+ if (mLogger.isDebugEnabled())
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("Probably a client abort exception, key=");
+ sb.append(key);
+ mLogger.error(sb.toString());
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Purge entire cache.
+ */
+ public synchronized void flushCache(HttpServletRequest req)
+ {
+ mPageCache.purge();
+ }
+
+ /**
+ * Purge user's entries from cache.
+ */
+ public synchronized void removeFromCache(HttpServletRequest req, UserData user)
+ {
+ // TODO: can we make this a little more precise, perhaps via regex?
+ String rssString = "/rss/" + user.getUserName(); // user's pages
+ String pageString = "/page/" + user.getUserName(); // user's RSS feeds
+ String mainRssString = "/rss_"; // main RSS feed
+ String mainPageString = "/main.do"; // main page
+ String planetPageString = "/planet.do"; // planet page
+
+ int beforeSize = mPageCache.size();
+ mPageCache.purge(new String[]
+ {
+ rssString,
+ pageString,
+ mainRssString,
+ mainPageString,
+ planetPageString
+ });
+ int afterSize = mPageCache.size();
+
+ if (mLogger.isDebugEnabled())
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("Purged, count=");
+ sb.append(beforeSize - afterSize);
+ sb.append(", user=");
+ sb.append(user.getUserName());
+ mLogger.debug(sb.toString());
+ }
+ }
+
+ /**
+ * Get from cache. Synchronized because "In access-ordered linked hash
+ * maps, merely querying the map with get is a structural modification"
+ */
+ public synchronized Object getFromCache(String key)
+ {
+ Object entry = mPageCache.get(key);
+
+ if (entry != null && mLogger.isDebugEnabled())
+ {
+ hits++;
+ }
+ return entry;
+ }
+
+ public synchronized void putToCache(String key, Object entry)
+ {
+ mPageCache.put(key, entry);
+ if (mLogger.isDebugEnabled())
+ {
+ misses++;
+
+ StringBuffer sb = new StringBuffer();
+ sb.append("Missed, cache size=");
+ sb.append(mPageCache.size());
+ sb.append(", hits=");
+ sb.append(hits);
+ sb.append(", misses=");
+ sb.append(misses);
+ sb.append(", key=");
+ sb.append(key);
+ mLogger.debug(sb.toString());
+ }
+ }
+
+ public String generateEntryKey(String key,
+ HttpServletRequest request, int scope, String language)
+ {
+ StringBuffer cBuffer = new StringBuffer(AVERAGE_KEY_LENGTH);
+ // Append the language if available
+ if (language != null)
+ {
+ cBuffer.append(FILE_SEPARATOR).append(language);
+ }
+
+ //cBuffer.append(FILE_SEPARATOR).append(request.getServerName());
+
+ if (key != null)
+ {
+ cBuffer.append(FILE_SEPARATOR).append(key);
+ }
+ else
+ {
+ String generatedKey = request.getRequestURI();
+ if (generatedKey.charAt(0) != FILE_SEPARATOR_CHAR)
+ {
+ cBuffer.append(FILE_SEPARATOR_CHAR);
+ }
+ cBuffer.append(generatedKey);
+ cBuffer.append("_").append(request.getMethod()).append("_");
+ generatedKey = getSortedQueryString(request);
+ if (generatedKey != null)
+ {
+ try
+ {
+ java.security.MessageDigest digest =
+ java.security.MessageDigest.getInstance("MD5");
+ byte[] b = digest.digest(generatedKey.getBytes());
+ cBuffer.append("_");
+ // Base64 encoding allows for unwanted slash characters.
+ cBuffer.append(toBase64(b).replace('/', '_'));
+ }
+ catch (Exception e)
+ {
+ // Ignore query string
+ }
+ }
+ }
+ return cBuffer.toString();
+ }
+
+ protected String getSortedQueryString(HttpServletRequest request)
+ {
+ Map paramMap = request.getParameterMap();
+ if (paramMap.isEmpty())
+ {
+ return null;
+ }
+ Set paramSet = new TreeMap(paramMap).entrySet();
+ StringBuffer buf = new StringBuffer();
+ boolean first = true;
+ for (Iterator it = paramSet.iterator(); it.hasNext();)
+ {
+ Map.Entry entry = (Map.Entry) it.next();
+ String[] values = (String[]) entry.getValue();
+ for (int i = 0; i < values.length; i++)
+ {
+ String key = (String) entry.getKey();
+ if ((key.length() != 10) || !"jsessionid".equals(key))
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append('&');
+ }
+ buf.append(key).append('=').append(values[i]);
+ }
+ }
+ }
+ // We get a 0 length buffer if the only parameter was a jsessionid
+ if (buf.length() == 0)
+ {
+ return null;
+ }
+ else
+ {
+ return buf.toString();
+ }
+ }
+
+ /**
+ * Convert a byte array into a Base64 string (as used in mime formats)
+ */
+ private static String toBase64(byte[] aValue)
+ {
+ int byte1;
+ int byte2;
+ int byte3;
+ int iByteLen = aValue.length;
+ StringBuffer tt = new StringBuffer();
+ for (int i = 0; i < iByteLen; i += 3)
+ {
+ boolean bByte2 = (i + 1) < iByteLen;
+ boolean bByte3 = (i + 2) < iByteLen;
+ byte1 = aValue[i] & 0xFF;
+ byte2 = (bByte2) ? (aValue[i + 1] & 0xFF) : 0;
+ byte3 = (bByte3) ? (aValue[i + 2] & 0xFF) : 0;
+ tt.append(m_strBase64Chars.charAt(byte1 / 4));
+ tt.append(m_strBase64Chars.charAt((byte2 / 16)
+ + ((byte1 & 0x3) * 16)));
+ tt.append(((bByte2) ? m_strBase64Chars.charAt((byte3 / 64)
+ + ((byte2 & 0xF) * 4)) : '='));
+ tt.append(((bByte3) ? m_strBase64Chars.charAt(byte3 & 0x3F) : '='));
+ }
+ return tt.toString();
+ }
+}
Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/ResponseContent.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/ResponseContent.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/ResponseContent.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/ResponseContent.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package org.roller.presentation.pagecache.rollercache;
+
+import java.io.*;
+
+import java.util.Locale;
+
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Holds the servlet response in a byte array so that it can be held
+ * in the cache (and, since this class is serializable, optionally
+ * persisted to disk).
+ *
+ * @version $Revision: 1.3 $
+ * @author <a href="mailto:sergek@lokitech.com">Serge Knystautas</a>
+ */
+public class ResponseContent implements Serializable {
+ private transient ByteArrayOutputStream bout = new ByteArrayOutputStream(1000);
+ private Locale locale = null;
+ private String contentType = null;
+ private byte[] content = null;
+ private long lastModified = -1;
+
+ /**
+ * Set the content type. We capture this so that when we serve this
+ * data from cache, we can set the correct content type on the response.
+ */
+ public void setContentType(String value) {
+ contentType = value;
+ }
+
+ public long getLastModified() {
+ return lastModified;
+ }
+
+ public void setLastModified(long value) {
+ lastModified = value;
+ }
+
+ /**
+ * Set the Locale. We capture this so that when we serve this data from
+ * cache, we can set the correct locale on the response.
+ */
+ public void setLocale(Locale value) {
+ locale = value;
+ }
+
+ /**
+ * Get an output stream. This is used by the {@link SplitServletOutputStream}
+ * to capture the original (uncached) response into a byte array.
+ */
+ public OutputStream getOutputStream() {
+ return bout;
+ }
+
+ /**
+ * Gets the size of this cached content.
+ *
+ * @return The size of the content, in bytes. If no content
+ * exists, this method returns <code>-1</code>.
+ */
+ public int getSize() {
+ return (content != null) ? content.length : (-1);
+ }
+
+ /**
+ * Called once the response has been written in its entirety. This
+ * method commits the response output stream by converting the output
+ * stream into a byte array.
+ */
+ public void commit() {
+ content = bout.toByteArray();
+ }
+
+ /**
+ * Writes this cached data out to the supplied <code>ServletResponse</code>.
+ *
+ * @param response The servlet response to output the cached content to.
+ * @throws IOException
+ */
+ public void writeTo(ServletResponse response) throws IOException {
+ //Send the content type and data to this response
+ if (contentType != null) {
+ response.setContentType(contentType);
+ }
+
+ //if (response instanceof HttpServletResponse) {
+ //((HttpServletResponse) response).setDateHeader("Last-Modified", lastModified);
+ //}
+
+ response.setContentLength(content.length);
+
+ if (locale != null) {
+ response.setLocale(locale);
+ }
+
+ OutputStream out = new BufferedOutputStream(response.getOutputStream());
+ out.write(content);
+ out.flush();
+ }
+}
Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/SplitPrintWriter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/SplitPrintWriter.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/SplitPrintWriter.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/SplitPrintWriter.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,56 @@
+package org.roller.presentation.pagecache.rollercache;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ * @author Dave Johnson
+ */
+public class SplitPrintWriter extends PrintWriter
+{
+ private PrintWriter captureWriter = null;
+ private PrintWriter passThroughWriter = null;
+
+ public SplitPrintWriter(PrintWriter captureWriter, PrintWriter passThroughWriter)
+ {
+ super(passThroughWriter);
+ this.captureWriter = captureWriter;
+ this.passThroughWriter = passThroughWriter;
+ }
+
+ public void write(char[] cbuf)
+ {
+ captureWriter.write(cbuf);
+ passThroughWriter.write(cbuf);
+ }
+ public void write(char[] cbuf, int off, int len)
+ {
+ captureWriter.write(cbuf,off,len);
+ passThroughWriter.write(cbuf,off,len);
+ }
+ public void write(int c)
+ {
+ captureWriter.write(c);
+ passThroughWriter.write(c);
+ }
+ public void write(String str)
+ {
+ captureWriter.write(str);
+ passThroughWriter.write(str);
+ }
+ public void write(String str, int off, int len)
+ {
+ captureWriter.write(str,off,len);
+ passThroughWriter.write(str,off,len);
+ }
+ public void flush()
+ {
+ captureWriter.flush();
+ passThroughWriter.flush();
+ }
+ public void close()
+ {
+ captureWriter.close();
+ passThroughWriter.close();
+ }
+}
Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/SplitServletOutputStream.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/SplitServletOutputStream.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/SplitServletOutputStream.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/SplitServletOutputStream.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package org.roller.presentation.pagecache.rollercache;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.servlet.ServletOutputStream;
+
+/**
+ * Extends the base <code>ServletOutputStream</code> class so that
+ * the stream can be captured as it gets written. This is achieved
+ * by overriding the <code>write()</code> methods and outputting
+ * the data to two streams - the original stream and a secondary stream
+ * that is designed to capture the written data.
+ *
+ * @version $Revision: 1.1 $
+ * @author <a href="mailto:sergek@lokitech.com">Serge Knystautas</a>
+ */
+public class SplitServletOutputStream extends ServletOutputStream {
+ OutputStream captureStream = null;
+ OutputStream passThroughStream = null;
+
+ /**
+ * Constructs a split output stream that both captures and passes through
+ * the servlet response.
+ *
+ * @param captureStream The stream that will be used to capture the data.
+ * @param passThroughStream The pass-through <code>ServletOutputStream</code>
+ * that will write the response to the client as originally intended.
+ */
+ public SplitServletOutputStream(OutputStream captureStream, OutputStream passThroughStream) {
+ this.captureStream = captureStream;
+ this.passThroughStream = passThroughStream;
+ }
+
+ /**
+ * Writes the incoming data to both the output streams.
+ *
+ * @param value The int data to write.
+ * @throws IOException
+ */
+ public void write(int value) throws IOException {
+ captureStream.write(value);
+ passThroughStream.write(value);
+ }
+
+ /**
+ * Writes the incoming data to both the output streams.
+ *
+ * @param value The bytes to write to the streams.
+ * @throws IOException
+ */
+ public void write(byte[] value) throws IOException {
+ captureStream.write(value);
+ passThroughStream.write(value);
+ }
+
+ /**
+ * Writes the incoming data to both the output streams.
+ *
+ * @param b The bytes to write out to the streams.
+ * @param off The offset into the byte data where writing should begin.
+ * @param len The number of bytes to write.
+ * @throws IOException
+ */
+ public void write(byte[] b, int off, int len) throws IOException {
+ captureStream.write(b, off, len);
+ passThroughStream.write(b, off, len);
+ }
+}
Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/package.html?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/package.html (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/pagecache/rollercache/package.html Fri Oct 21 14:27:36 2005
@@ -0,0 +1,10 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title></title>
+</head>
+<body>
+In-memory LRU implemtation for PageCacheFilter.
+
+</body>
+</html>
Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/pings/PingQueueProcessor.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/pings/PingQueueProcessor.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/pings/PingQueueProcessor.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/pings/PingQueueProcessor.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2005
+ * Anil R. Gangolli. All rights reserved.
+ *
+ * Distributed with the Roller Weblogger Project under the terms of the Roller Software
+ * License
+ */
+
+package org.roller.presentation.pings;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.roller.RollerException;
+import org.roller.config.PingConfig;
+import org.roller.model.PingQueueManager;
+import org.roller.model.RollerFactory;
+import org.roller.pojos.PingQueueEntryData;
+import org.roller.pojos.PingTargetData;
+import org.roller.pojos.WebsiteData;
+import org.roller.presentation.RollerContext;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Ping Queue Processor. Singleton encapsulating logic for processing the weblog update ping queue.
+ */
+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.storeQueueEntry(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/branches/roller_1.x/src/org/roller/presentation/pings/PingQueueTask.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/pings/PingQueueTask.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/pings/PingQueueTask.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/pings/PingQueueTask.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2005
+ * Anil R. Gangolli. All rights reserved.
+ *
+ * Distributed with the Roller Weblogger Project under the terms of the Roller Software
+ * License
+ */
+
+package org.roller.presentation.pings;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.roller.RollerException;
+import org.roller.model.Roller;
+import org.roller.model.RollerFactory;
+import org.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.roller.config.PingConfig} at startup time only.
+ */
+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();
+ roller.begin();
+ PingQueueProcessor.getInstance().processQueue();
+ roller.commit();
+ }
+ 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();
+ }
+ }
+}
Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/pings/WeblogUpdatePinger.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/pings/WeblogUpdatePinger.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/pings/WeblogUpdatePinger.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/pings/WeblogUpdatePinger.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2004-2005
+ * Lance Lavandowska, Anil R. Gangolli.
+ * All rights reserved.
+ *
+ * Distributed with the Roller Weblogger Project under the terms of the Roller Software
+ * License.
+ */
+
+package org.roller.presentation.pings;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.xmlrpc.XmlRpcClient;
+import org.apache.xmlrpc.XmlRpcException;
+import org.roller.RollerException;
+import org.roller.model.RollerFactory;
+import org.roller.pojos.PingTargetData;
+import org.roller.pojos.WebsiteData;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * Utility for sending a weblog update ping.
+ *
+ * @author <a href="mailto:anil@busybuddha.org">Anil Gangolli</author>
+ * @author llavandowska (for code refactored from the now-defunct <code>RollerXmlRpcClient</code>)
+ */
+public class WeblogUpdatePinger
+{
+ public static final Log logger = LogFactory.getLog(WeblogUpdatePinger.class);
+
+ /**
+ * Conveys a ping result.
+ */
+ public static class PingResult
+ {
+ boolean error;
+ String message;
+
+ public PingResult(Boolean error, String message)
+ {
+ this.error = error != null ? error.booleanValue() : false;
+ this.message = message;
+ }
+
+ public boolean isError()
+ {
+ return error;
+ }
+
+ public void setError(boolean error)
+ {
+ this.error = error;
+ }
+
+ public String getMessage()
+ {
+ return message;
+ }
+
+ public void setMessage(String message)
+ {
+ this.message = message;
+ }
+
+ public String toString()
+ {
+ return "PingResult{" +
+ "error=" + error +
+ ", message='" + message + "'" +
+ "}";
+ }
+ }
+
+ // Inhibit construction
+ private WeblogUpdatePinger()
+ {
+ }
+
+ /**
+ * Send a weblog update ping.
+ *
+ * @param absoluteContextUrl the absolute context url of the Roller site.
+ * @param pingTarget the target site to ping
+ * @param website the website that changed (from which the ping originates)
+ * @return the result message string sent by the server.
+ * @throws IOException
+ * @throws XmlRpcException
+ * @throws RollerException
+ */
+ public static PingResult sendPing(String absoluteContextUrl, PingTargetData pingTarget, WebsiteData website)
+ throws RollerException, IOException, XmlRpcException
+ {
+ // Figure out the url of the user's website.
+ String websiteUrl =
+ RollerFactory.getRoller().getWeblogManager().getUrl(website.getUser(), absoluteContextUrl);
+
+ // Set up the ping parameters.
+ Vector params = new Vector();
+ params.addElement(website.getName());
+ params.addElement(websiteUrl);
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Executing ping to '" + pingTarget.getPingUrl() + "' for website '" +
+ websiteUrl + "' (" + website.getName() + ")");
+ }
+
+ // Send the ping
+ XmlRpcClient client = new XmlRpcClient(pingTarget.getPingUrl());
+ Hashtable result = (Hashtable) client.execute("weblogUpdates.ping", params);
+ PingResult pingResult = new PingResult((Boolean) result.get("flerror"), (String) result.get("message"));
+ if (logger.isDebugEnabled()) logger.debug("Ping result is: " + pingResult);
+ return pingResult;
+ }
+
+ /**
+ * Decide if the given exception appears to warrant later retrial attempts.
+ *
+ * @param ex an exception thrown by the <coce>sendPing</code> operation
+ * @return true if the error warrants retrial
+ */
+ public static boolean shouldRetry(Exception ex)
+ {
+ // Determine if error appears transient (warranting retrial)
+ // We give most errors the "benefit of the doubt" by considering them transient
+ // This picks out a few that we consider non-transient
+ if (ex instanceof UnknownHostException)
+ {
+ // User probably mistyped the url in the custom target.
+ return false;
+ }
+ else if (ex instanceof MalformedURLException)
+ {
+ // This should never happen due to validations but if we get here, retrial won't fix it.
+ return false;
+ }
+ return true;
+ }
+
+}
Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/pings/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/pings/package.html?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/pings/package.html (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/pings/package.html Fri Oct 21 14:27:36 2005
@@ -0,0 +1,10 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title></title>
+</head>
+<body>
+Classes for sending Weblogs.com-style pings.
+
+</body>
+</html>
Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetAction.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetAction.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetAction.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetAction.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,190 @@
+package org.roller.presentation.planet;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ResourceBundle;
+
+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.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.roller.RollerException;
+import org.roller.config.RollerRuntimeConfig;
+import org.roller.model.Roller;
+import org.roller.pojos.PlanetConfigData;
+import org.roller.pojos.PlanetGroupData;
+import org.roller.presentation.RollerContext;
+import org.roller.presentation.RollerRequest;
+
+/**
+ * Main page action for Roller Planet.
+ * @struts.action name="main" path="/planet" scope="request"
+ * @struts.action-forward name="planet.page" path="/planet.jsp"
+ */
+public class PlanetAction extends Action
+{
+ private static Log mLogger =
+ LogFactory.getFactory().getInstance(PlanetAction.class);
+ private static ResourceBundle bundle =
+ ResourceBundle.getBundle("ApplicationResources");
+
+ /**
+ * Loads model and forwards to planet.page.
+ */
+ public ActionForward execute(
+ ActionMapping mapping, ActionForm form,
+ HttpServletRequest req, HttpServletResponse res)
+ throws Exception
+ {
+ RollerContext rctx = RollerContext.getRollerContext(req);
+ req.setAttribute("version",rctx.getRollerVersion());
+ req.setAttribute("buildTime",rctx.getRollerBuildTime());
+ req.setAttribute("baseURL", rctx.getContextUrl(req));
+ req.setAttribute("data", new PlanetPageData(req));
+
+ boolean allowNewUsers =
+ RollerRuntimeConfig.getBooleanProperty("users.registration.enabled");
+
+ java.security.Principal prince = req.getUserPrincipal();
+ if (prince != null)
+ {
+ req.setAttribute("loggedIn",Boolean.TRUE);
+ req.setAttribute("userName",prince.getName());
+ }
+ else if (allowNewUsers)
+ {
+ req.setAttribute("allowNewUsers",Boolean.TRUE);
+ }
+ req.setAttribute("leftPage","/theme/status.jsp");
+
+ return mapping.findForward("planet.page");
+ }
+
+ /**
+ * Page model.
+ */
+ public static class PlanetPageData
+ {
+ private HttpServletRequest mRequest = null;
+ private String mTitle =
+ bundle.getString("planet.title.unconfigured");
+ private String mDescription =
+ bundle.getString("planet.description.unconfigured");
+
+ public String getTitle() {return mTitle;}
+ public String getDescription() {return mDescription;}
+
+ public PlanetPageData(HttpServletRequest req) throws RollerException
+ {
+ mRequest = req;
+ Roller roller =
+ RollerRequest.getRollerRequest(mRequest).getRoller();
+ PlanetConfigData cfg = roller.getPlanetManager().getConfiguration();
+ if (cfg != null)
+ {
+ mTitle = cfg.getTitle();
+ mDescription = cfg.getDescription();
+ }
+ }
+
+ /**
+ * Get aggregation of entries in 'all' and 'external' groups
+ */
+ public List getAggregation(int num) throws RollerException
+ {
+ Roller roller =
+ RollerRequest.getRollerRequest(mRequest).getRoller();
+ return roller.getPlanetManager().getAggregation(num);
+ }
+ /**
+ * Get named group
+ */
+ public PlanetGroupData getGroup(String name) throws RollerException
+ {
+ PlanetGroupData group = null;
+ try
+ {
+ Roller roller =
+ RollerRequest.getRollerRequest(mRequest).getRoller();
+ group = roller.getPlanetManager().getGroup(name);
+ }
+ catch (RollerException e)
+ {
+ mLogger.error(e);
+ }
+ return group;
+ }
+ /**
+ * Get aggregation of entries in named group
+ */
+ public List getAggregation(String name, int num) throws RollerException
+ {
+ List ret = new ArrayList();
+ try
+ {
+ Roller roller =
+ RollerRequest.getRollerRequest(mRequest).getRoller();
+ PlanetGroupData group= roller.getPlanetManager().getGroup(name);
+ ret = roller.getPlanetManager().getAggregation(group, num);
+ }
+ catch (RollerException e)
+ {
+ mLogger.error(e);
+ }
+ return ret;
+ }
+ /**
+ * Get top blogs according to Technorati
+ */
+ public List getTopSubscriptions(int num) throws RollerException
+ {
+ List ret = new ArrayList();
+ try
+ {
+ Roller roller =
+ RollerRequest.getRollerRequest(mRequest).getRoller();
+ ret = roller.getPlanetManager().getTopSubscriptions(num);
+ }
+ catch (RollerException e)
+ {
+ mLogger.error(e);
+ }
+ return ret;
+ }
+ /**
+ * Get top blogs in a group according to Technorati
+ */
+ public List getTopSubscriptions(String name, int num)
+ throws RollerException
+ {
+ List ret = new ArrayList();
+ try
+ {
+ Roller roller =
+ RollerRequest.getRollerRequest(mRequest).getRoller();
+ PlanetGroupData group= roller.getPlanetManager().getGroup(name);
+ ret = roller.getPlanetManager().getTopSubscriptions(group,num);
+ }
+ catch (RollerException e)
+ {
+ mLogger.error(e);
+ }
+ return ret;
+ }
+ /**
+ * Get list of most popular websites in terms of day hits.
+ */
+ public List getPopularWebsites(int num) throws RollerException
+ {
+ Roller roller =
+ RollerRequest.getRollerRequest(mRequest).getRoller();
+ return roller.getRefererManager().getDaysPopularWebsites(num);
+ }
+ }
+}
+
Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetConfigAction.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetConfigAction.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetConfigAction.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetConfigAction.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.roller.presentation.planet;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+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.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.action.ActionMessage;
+import org.apache.struts.action.ActionMessages;
+import org.apache.struts.actions.DispatchAction;
+import org.roller.presentation.forms.PlanetConfigForm;
+import org.roller.config.RollerRuntimeConfig;
+import org.roller.model.PlanetManager;
+import org.roller.model.Roller;
+import org.roller.pojos.PlanetConfigData;
+import org.roller.pojos.PlanetGroupData;
+import org.roller.presentation.RollerRequest;
+import org.roller.presentation.planet.RefreshEntriesTask;
+import org.roller.presentation.planet.SyncWebsitesTask;
+
+/////////////////////////////////////////////////////////////////////////////
+/**
+ * Allows configuration of Planet Roller.
+ *
+ * @struts.action name="planetConfigForm" path="/admin/planetConfig"
+ * scope="request" parameter="method"
+ *
+ * @struts.action-forward name="planetConfig.page"
+ * path="/planet/PlanetConfig.jsp"
+ */
+public final class PlanetConfigAction extends DispatchAction
+{
+ private static Log logger =
+ LogFactory.getFactory().getInstance(PlanetConfigAction.class);
+
+ /** Populate config form and forward to config page */
+ public ActionForward getConfig(ActionMapping mapping,
+ ActionForm actionForm, HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException
+ {
+ ActionForward forward = mapping.findForward("planetConfig.page");
+ try
+ {
+ RollerRequest rreq = RollerRequest.getRollerRequest(request);
+ if (rreq.isUserAuthorizedToEdit())
+ {
+ Roller roller = rreq.getRoller();
+ PlanetManager planet = roller.getPlanetManager();
+ PlanetConfigData config = planet.getConfiguration();
+ PlanetConfigForm form = (PlanetConfigForm)actionForm;
+ if (config != null)
+ {
+ form.copyFrom(config, request.getLocale());
+ }
+ else
+ {
+ form.setTitle("Planet Roller");
+ form.setAdminEmail(RollerRuntimeConfig.getProperty("site.adminemail"));
+ form.setSiteUrl(RollerRuntimeConfig.getProperty("site.absoluteurl"));
+ form.setCacheDir("/tmp");
+ }
+ }
+ else
+ {
+ forward = mapping.findForward("access-denied");
+ }
+ }
+ catch (Exception e)
+ {
+ request.getSession().getServletContext().log("ERROR", e);
+ throw new ServletException(e);
+ }
+ return forward;
+ }
+
+ /** Save posted config form data */
+ public ActionForward saveConfig(ActionMapping mapping,
+ ActionForm actionForm, HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException
+ {
+ ActionForward forward = mapping.findForward("planetConfig.page");
+ try
+ {
+ RollerRequest rreq = RollerRequest.getRollerRequest(request);
+ if (rreq.isUserAuthorizedToEdit())
+ {
+ Roller roller = rreq.getRoller();
+ PlanetManager planet = roller.getPlanetManager();
+ PlanetConfigData config = planet.getConfiguration();
+ if (config == null)
+ {
+ config = new PlanetConfigData();
+ }
+ PlanetConfigForm form = (PlanetConfigForm) actionForm;
+ ActionErrors errors = validate(form);
+ if (errors.isEmpty())
+ {
+ form.copyTo(config, request.getLocale());
+ planet.saveConfiguration(config);
+ if (planet.getGroup("external") == null)
+ {
+ PlanetGroupData group = new PlanetGroupData();
+ group.setHandle("external");
+ group.setTitle("external");
+ planet.saveGroup(group);
+ }
+ roller.commit();
+ ActionMessages messages = new ActionMessages();
+ messages.add(null, new ActionMessage("planetConfig.success.saved"));
+ saveMessages(request, messages);
+ }
+ else
+ {
+ saveErrors(request, errors);
+ }
+ }
+ else
+ {
+ forward = mapping.findForward("access-denied");
+ }
+ }
+ catch (Exception e)
+ {
+ request.getSession().getServletContext().log("ERROR", e);
+ throw new ServletException(e);
+ }
+ return forward;
+ }
+
+ /** Refresh entries in backgrounded thread (for testing) */
+ public ActionForward refreshEntries(ActionMapping mapping,
+ ActionForm actionForm, HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException
+ {
+ ActionForward forward = mapping.findForward("planetConfig.page");
+ try
+ {
+ RollerRequest rreq = RollerRequest.getRollerRequest(request);
+ if (rreq.isUserAuthorizedToEdit())
+ {
+ Roller roller = rreq.getRoller();
+ RefreshEntriesTask task = new RefreshEntriesTask();
+ task.init(roller, "dummy");
+ roller.getThreadManager().executeInBackground(task);
+
+ ActionMessages messages = new ActionMessages();
+ messages.add(null,
+ new ActionMessage("planetConfig.success.refreshed"));
+ saveMessages(request, messages);
+ }
+ else
+ {
+ forward = mapping.findForward("access-denied");
+ }
+ }
+ catch (Exception e)
+ {
+ request.getSession().getServletContext().log("ERROR", e);
+ throw new ServletException(e);
+ }
+ return forward;
+ }
+
+ /** Sync websites in backgrounded thread (for testing) */
+ public ActionForward syncWebsites(ActionMapping mapping,
+ ActionForm actionForm, HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException
+ {
+ ActionForward forward = mapping.findForward("planetConfig.page");
+ try
+ {
+ RollerRequest rreq = RollerRequest.getRollerRequest(request);
+ if (rreq.isUserAuthorizedToEdit())
+ {
+ Roller roller = (Roller)rreq.getRoller();
+ SyncWebsitesTask task = new SyncWebsitesTask();
+ task.init(roller, "dummy");
+ roller.getThreadManager().executeInBackground(task);
+ ActionMessages messages = new ActionMessages();
+ messages.add(null,
+ new ActionMessage("planetConfig.success.synced"));
+ saveMessages(request, messages);
+ }
+ else
+ {
+ forward = mapping.findForward("access-denied");
+ }
+ }
+ catch (Exception e)
+ {
+ request.getSession().getServletContext().log("ERROR", e);
+ throw new ServletException(e);
+ }
+ return forward;
+ }
+
+ /** Validate config form, returns empty collection if all OK */
+ public ActionErrors validate(PlanetConfigForm form)
+ {
+ ActionErrors errors = new ActionErrors();
+ if (form.getCacheDir()==null || form.getCacheDir().trim().length()==0)
+ {
+ errors.add(null, new ActionError("planetConfig.error.feedUrl"));
+ }
+ else
+ {
+ File file = new File(form.getCacheDir());
+ if (!file.isDirectory())
+ {
+ errors.add(null, new ActionError(
+ "planetConfig.error.cacheDirNotFound"));
+ }
+ if (!file.canWrite())
+ {
+ errors.add(null, new ActionError(
+ "planetConfig.error.cacheDirNotWritable"));
+ }
+ }
+ if (form.getProxyHost()!=null && form.getProxyHost().trim().length()>0)
+ {
+ if (form.getProxyPort()<1)
+ {
+ errors.add(null, new ActionError(
+ "planetConfig.error.badProxyPort"));
+ }
+ }
+ return errors;
+ }
+}
+
Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetGroupsAction.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetGroupsAction.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetGroupsAction.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetGroupsAction.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.roller.presentation.planet;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.servlet.ServletException;
+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.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.action.ActionMessage;
+import org.apache.struts.action.ActionMessages;
+import org.apache.struts.actions.DispatchAction;
+import org.roller.RollerException;
+import org.roller.model.PlanetManager;
+import org.roller.model.Roller;
+import org.roller.pojos.PlanetGroupData;
+import org.roller.presentation.BasePageModel;
+import org.roller.presentation.RollerRequest;
+import org.roller.presentation.forms.PlanetGroupForm;
+
+
+/////////////////////////////////////////////////////////////////////////////
+/**
+ * Add, remove, and view user defined groups.
+ *
+ * @struts.action name="planetGroupForm" path="/admin/planetGroups"
+ * scope="request" parameter="method"
+ *
+ * @struts.action-forward name="planetGroups.page"
+ * path="/planet/PlanetGroups.jsp"
+ */
+public final class PlanetGroupsAction extends DispatchAction
+{
+ private static Log logger = LogFactory.getFactory().getInstance(
+ PlanetGroupsAction.class);
+
+ /** Populate page model and forward to subscription page */
+ public ActionForward getGroups(ActionMapping mapping,
+ ActionForm actionForm, HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException
+ {
+ ActionForward forward = mapping.findForward("planetGroups.page");
+ try
+ {
+ RollerRequest rreq = RollerRequest.getRollerRequest(request);
+ if (rreq.isUserAuthorizedToEdit())
+ {
+ Roller roller = rreq.getRoller();
+ PlanetManager planet = roller.getPlanetManager();
+ PlanetGroupForm form = (PlanetGroupForm)actionForm;
+ if (request.getParameter("groupHandle") != null)
+ {
+ String feedUrl = request.getParameter("groupHandle");
+ PlanetGroupData group = planet.getGroup(feedUrl);
+ form.copyFrom(group, request.getLocale());
+ }
+ else
+ {
+ form.doReset(mapping, request);
+ }
+ request.setAttribute("model",
+ new GroupsPageModel(request, response, mapping));
+ }
+ else
+ {
+ forward = mapping.findForward("access-denied");
+ }
+ }
+ catch (Exception e)
+ {
+ request.getSession().getServletContext().log("ERROR", e);
+ throw new ServletException(e);
+ }
+ return forward;
+ }
+
+ /** Cancel editing, reset form */
+ public ActionForward cancelEditing(ActionMapping mapping,
+ ActionForm actionForm, HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException
+ {
+ ActionForward forward = mapping.findForward("planetGroups.page");
+ try
+ {
+ RollerRequest rreq = RollerRequest.getRollerRequest(request);
+ if (rreq.isUserAuthorizedToEdit())
+ {
+ Roller roller = rreq.getRoller();
+ PlanetManager planet = roller.getPlanetManager();
+ PlanetGroupForm form = (PlanetGroupForm)actionForm;
+
+ form.doReset(mapping, request);
+
+ request.setAttribute("model",
+ new GroupsPageModel(request, response, mapping));
+ }
+ else
+ {
+ forward = mapping.findForward("access-denied");
+ }
+ }
+ catch (Exception e)
+ {
+ request.getSession().getServletContext().log("ERROR", e);
+ throw new ServletException(e);
+ }
+ return forward;
+ }
+
+ /** Delete subscription, reset form */
+ public ActionForward deleteGroup(ActionMapping mapping,
+ ActionForm actionForm, HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException
+ {
+ ActionForward forward = mapping.findForward("planetGroups.page");
+ try
+ {
+ RollerRequest rreq = RollerRequest.getRollerRequest(request);
+ if (rreq.isUserAuthorizedToEdit())
+ {
+ Roller roller = rreq.getRoller();
+ PlanetManager planet = roller.getPlanetManager();
+ PlanetGroupForm form = (PlanetGroupForm)actionForm;
+ if (form.getHandle() != null)
+ {
+ PlanetGroupData group = planet.getGroup(form.getHandle());
+ planet.deleteGroup(group);
+ roller.commit();
+ roller.release();
+
+ roller.begin();
+ form.doReset(mapping, request);
+
+ request.setAttribute("model",
+ new GroupsPageModel(request, response, mapping));
+
+ ActionMessages messages = new ActionMessages();
+ messages.add(null,
+ new ActionMessage("planetSubscription.success.deleted"));
+ saveMessages(request, messages);
+ }
+ }
+ else
+ {
+ forward = mapping.findForward("access-denied");
+ }
+ }
+ catch (Exception e)
+ {
+ ActionErrors errors = new ActionErrors();
+ errors.add(null, new ActionError("planetGroup.error.deleting"));
+ saveErrors(request, errors);
+ }
+ return forward;
+ }
+
+ /** Save subscription, add to "external" group */
+ public ActionForward saveGroup(ActionMapping mapping,
+ ActionForm actionForm, HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException
+ {
+ ActionForward forward = mapping.findForward("planetGroups.page");
+ try
+ {
+ RollerRequest rreq = RollerRequest.getRollerRequest(request);
+ if (rreq.isUserAuthorizedToEdit())
+ {
+ PlanetGroupForm form = (PlanetGroupForm)actionForm;
+ Roller roller = rreq.getRoller();
+ PlanetManager planet = roller.getPlanetManager();
+ ActionErrors errors = validate(planet, form);
+ if (errors.isEmpty())
+ {
+ PlanetGroupData group = null;
+ if (form.getId() == null || form.getId().trim().length() == 0)
+ {
+ group = new PlanetGroupData();
+ }
+ else
+ {
+ group = planet.getGroupById(form.getId());
+ }
+ form.copyTo(group, request.getLocale());
+ planet.saveGroup(group);
+ roller.commit();
+
+ ActionMessages messages = new ActionMessages();
+ messages.add(null,
+ new ActionMessage("planetGroups.success.saved"));
+ saveMessages(request, messages);
+ form.doReset(mapping, request);
+
+ request.setAttribute("model",
+ new GroupsPageModel(request, response, mapping));
+ }
+ else
+ {
+ saveErrors(request, errors);
+ }
+ }
+ else
+ {
+ forward = mapping.findForward("access-denied");
+ }
+ }
+ catch (RollerException e)
+ {
+ ActionErrors errors = new ActionErrors();
+ errors.add(null, new ActionError(
+ "planetSubscriptions.error.duringSave",e.getRootCauseMessage()));
+ saveErrors(request, errors);
+ }
+ return forward;
+ }
+
+ /** Validate posted group */
+ private ActionErrors validate(
+ PlanetManager planet, PlanetGroupForm form)
+ {
+ ActionErrors errors = new ActionErrors();
+ if (form.getTitle()==null || form.getTitle().trim().length()==0)
+ {
+ errors.add(null, new ActionError("planetGroups.error.title"));
+ }
+ if (form.getHandle()==null || form.getHandle().trim().length()==0)
+ {
+ errors.add(null, new ActionError("planetGroups.error.handle"));
+ }
+ if (form.getHandle() != null &&
+ (form.getHandle().equals("all") || form.getHandle().equals("external")))
+ {
+ errors.add(null, new ActionError("planetGroups.error.nameReserved"));
+ }
+ return errors;
+ }
+
+ /** Page model */
+ public class GroupsPageModel extends BasePageModel
+ {
+ private List groups = new ArrayList();
+ private boolean unconfigured = false;
+ public GroupsPageModel(
+ HttpServletRequest request,
+ HttpServletResponse response,
+ ActionMapping mapping) throws RollerException
+ {
+ super(request, response, mapping);
+ RollerRequest rreq = RollerRequest.getRollerRequest(request);
+ Roller roller = rreq.getRoller();
+ PlanetManager planet = roller.getPlanetManager();
+ PlanetGroupData externalGroup = planet.getGroup("external");
+ if (externalGroup != null)
+ {
+ Iterator allgroups = planet.getGroups().iterator();
+ while (allgroups.hasNext())
+ {
+ PlanetGroupData agroup = (PlanetGroupData)allgroups.next();
+ if ( !agroup.getHandle().equals("external")
+ && !agroup.getHandle().equals("all"))
+ {
+ groups.add(agroup);
+ }
+ }
+ }
+ else
+ {
+ unconfigured = true;
+ }
+ }
+ public List getGroups()
+ {
+ return groups;
+ }
+ public boolean isUnconfigured()
+ {
+ return unconfigured;
+ }
+ }
+}
Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetSubscriptionFormEx.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetSubscriptionFormEx.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetSubscriptionFormEx.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/planet/PlanetSubscriptionFormEx.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,28 @@
+package org.roller.presentation.planet;
+
+import java.util.Locale;
+import org.roller.pojos.PlanetSubscriptionData;
+import org.roller.presentation.forms.PlanetSubscriptionForm;
+
+/**
+ * @struts.form name="planetSubscriptionFormEx"
+ */
+public class PlanetSubscriptionFormEx
+ extends PlanetSubscriptionForm
+ implements java.io.Serializable
+{
+ private String groupHandle = null;
+ public PlanetSubscriptionFormEx()
+ {
+ super();
+ }
+ public String getGroupHandle()
+ {
+ return groupHandle;
+ }
+ public void setGroupHandle(String groupHandle)
+ {
+ this.groupHandle = groupHandle;
+ }
+}
+