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/06/09 05:19:20 UTC

svn commit: r189695 [28/67] - in /incubator/roller/trunk: ./ 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/src/org/roller/presentation/velocity/ contrib/plugins/src/org/roller/presentation/velocity/plugins/ contrib/plugins/src/org/roller/presentation/velocity/plugins/acronyms/ contrib/plugins/src/org/roller/presentation/velocity/plugins/bookmarks/ contrib/plugins/src/org/roller/presentation/velocity/plugins/email/ contrib/plugins/src/org/roller/presentation/velocity/plugins/jspwiki/ contrib/plugins/src/org/roller/presentation/velocity/plugins/radeox/ contrib/plugins/src/org/roller/presentation/velocity/plugins/readmore/ contrib/plugins/src/org/roller/presentation/velocity/plugins/smileys/ contrib/plugins/src/org/roller/presentation/velocity/plugins/textile/ contrib/plugins/src/org/roller/presentation/velocity/plugins/topictag/ custom/ custom/src/ custom/web/ docs/ docs/images/ docs/installguide/ docs/installguide/old/ docs/userguide/ docs/userguide/images/ docs/userguide/old/ metadata/ metadata/database/ metadata/database/hibernate/ metadata/xdoclet/ nbproject/ personal/ personal/eclipse/ personal/testing/ sandbox/ sandbox/planetroller/ sandbox/planetroller/metadata/ sandbox/planetroller/metadata/database/ sandbox/planetroller/src/ sandbox/planetroller/src/org/ sandbox/planetroller/src/org/roller/ sandbox/planetroller/src/org/roller/tools/ sandbox/planetroller/src/org/roller/tools/planet/ sandbox/planetroller/templates/ sandbox/planetroller/test/ sandbox/planetroller/test/org/ sandbox/planetroller/test/org/roller/ sandbox/planetroller/test/org/roller/model/ sandbox/planetroller/test/org/roller/tools/ sandbox/planetroller/test/org/roller/tools/planet/ sandbox/planetroller/testdata/ sandbox/planetroller/testdata/cache/ sandbox/planetroller/testdata/output/ sandbox/standalone/ sandbox/standalone/jspwiki/ sandbox/standalone/jspwiki/default/ sandbox/standalone/jspwiki/default/images/ sandbox/standalone/lib/ sandbox/standalone/src/ sandbox/standalone/src/org/ sandbox/standalone/src/org/roller/ sandbox/standalone/src/org/roller/jspwiki/ sandbox/standalone/src/org/roller/tomcat/ sandbox/standalone/src/org/roller/util/ sandbox/standalone/tests/ sandbox/standalone/tests/org/ sandbox/standalone/tests/org/roller/ sandbox/standalone/tests/org/roller/util/ sandbox/standalone/tomcat/ src/ src/org/ src/org/roller/ src/org/roller/business/ src/org/roller/business/hibernate/ src/org/roller/business/search/ src/org/roller/business/search/operations/ src/org/roller/business/utils/ src/org/roller/config/ src/org/roller/config/runtime/ src/org/roller/model/ src/org/roller/pojos/ src/org/roller/presentation/ src/org/roller/presentation/atomapi/ src/org/roller/presentation/bookmarks/ src/org/roller/presentation/bookmarks/actions/ src/org/roller/presentation/bookmarks/formbeans/ src/org/roller/presentation/bookmarks/tags/ src/org/roller/presentation/filters/ src/org/roller/presentation/forms/ src/org/roller/presentation/newsfeeds/ src/org/roller/presentation/pagecache/ src/org/roller/presentation/pagecache/rollercache/ src/org/roller/presentation/pings/ src/org/roller/presentation/planet/ src/org/roller/presentation/tags/ src/org/roller/presentation/tags/calendar/ src/org/roller/presentation/tags/menu/ src/org/roller/presentation/util/ src/org/roller/presentation/velocity/ src/org/roller/presentation/weblog/ src/org/roller/presentation/weblog/actions/ src/org/roller/presentation/weblog/formbeans/ src/org/roller/presentation/weblog/tags/ src/org/roller/presentation/website/ src/org/roller/presentation/website/actions/ src/org/roller/presentation/website/formbeans/ src/org/roller/presentation/website/tags/ src/org/roller/presentation/xmlrpc/ src/org/roller/util/ src/org/roller/util/rome/ tests/ tests/org/ tests/org/roller/ tests/org/roller/ant/ tests/org/roller/business/ tests/org/roller/presentation/ tests/org/roller/presentation/atomapi/ tests/org/roller/presentation/bookmarks/ tests/org/roller/presentation/filters/ tests/org/roller/presentation/velocity/ tests/org/roller/presentation/velocity/plugins/ tests/org/roller/presentation/velocity/plugins/smileys/ tests/org/roller/presentation/velocity/plugins/textile/ tests/org/roller/presentation/weblog/ tests/org/roller/presentation/xmlrpc/ tests/org/roller/util/ tests/org/roller/util/rome/ tools/ tools/buildtime/ tools/buildtime/ant-1.6.2/ tools/buildtime/findbugs/ tools/buildtime/findbugs/lib/ tools/buildtime/findbugs/plugin/ tools/buildtime/mockrunner-0.3/ tools/buildtime/mockrunner-0.3/lib/ tools/buildtime/mockrunner-0.35/ tools/buildtime/mockrunner-0.35/lib/ tools/buildtime/tomcat-4.1.24/ tools/buildtime/xdoclet-1.2/ tools/buildtime/xdoclet-1.2/lib/ tools/hibernate-2.1/ tools/hibernate-2.1/lib/ tools/lib/ tools/standard-1.0.3/ tools/standard-1.0.3/lib/ tools/standard-1.0.3/tld/ tools/struts-1.2.4/ tools/struts-1.2.4/lib/ web/ web/WEB-INF/ web/WEB-INF/classes/ web/WEB-INF/classes/flavors/ web/WEB-INF/classes/themes/ web/bookmarks/ web/editor/ web/editor/images/ web/images/ web/images/editor/ web/images/midas/ web/images/preview/ web/images/smileys/ web/planet/ web/tags/ web/templates/ web/theme/ web/theme/images/ web/theme/lavender/ web/theme/scripts/ web/theme/scripts/classes/ web/themes/ web/themes/basic/ web/themes/berkley/ web/themes/berkley/images/ web/themes/brushedmetal/ web/themes/brushedmetal/images/ web/themes/cheb/ web/themes/cheb/images/ web/themes/cheb/scripts/ web/themes/clean/ web/themes/currency-i18n/ web/themes/currency-i18n/images/ web/themes/currency/ web/themes/currency/images/ web/themes/grey2/ web/themes/moonshine/ web/themes/movablemanila/ web/themes/movablemanila/images/ web/themes/pacifica/ web/themes/robot/ web/themes/rolling/ web/themes/rolling/images/ web/themes/sotto/ web/themes/sotto/images/ web/themes/sotto/styles/ web/themes/sunsets/ web/themes/sunsets/images/ web/themes/sunsets/scripts/ web/themes/sunsets/styles/ web/themes/werner/ web/themes/x2/ web/themes/x2/images/ web/themes/x2/scripts/ web/themes/x2/styles/ web/weblog/ web/website/

Added: incubator/roller/trunk/src/org/roller/presentation/LoginServlet.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/LoginServlet.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/LoginServlet.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/LoginServlet.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,225 @@
+package org.roller.presentation;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.roller.presentation.util.SslUtil;
+import org.roller.util.Utilities;
+
+import java.io.IOException;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.roller.config.RollerConfig;
+
+
+
+/**
+ * Implementation of <strong>HttpServlet</strong> that is used
+ * to get a username and password and mEncrypt the password
+ * before sending to container-managed authentication.
+ *
+ * <p><a href="LoginServlet.java.html"><i>View Source</i></a></p>
+ *
+ * @author <a href="mailto:matt@raibledesigns.com">Matt Raible</a>
+ * @version $Revision: 1.19 $ $Date: 2005/06/07 18:30:18 $
+ *
+ * @web.servlet
+ *     display-name="Login Servlet"
+ *     load-on-startup="3"
+ *     name="login"
+ *
+ * @web.servlet-init-param
+ *     name="authURL"
+ *     value="/j_security_check"
+ *
+ * @web.servlet-mapping
+ *     url-pattern="/auth/*"
+ */
+public class LoginServlet extends HttpServlet
+{
+    static final long serialVersionUID = 8054268881470797053L;
+    
+    protected static String mAuthURL = "/j_security_check";
+    protected static String mAlgorithm = "SHA";
+    protected static Boolean mEncrypt = Boolean.FALSE;
+    
+    private boolean secureLogin = false;
+    private String loginHttpsPort = SslUtil.STD_HTTPS_PORT;
+    
+    //=========================================================================
+    // Private Member Variables
+    //=========================================================================
+    private static Log mLogger = LogFactory.getLog(LoginServlet.class);
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Validates the Init and Context parameters, configures authentication URL
+     *
+     * @throws ServletException if the init parameters are invalid or any
+     * other problems occur during initialisation
+     */
+    public void init() throws ServletException
+    {
+        // Get the container authentication URL for FORM-based Authentication
+        // J2EE spec says should be j_security_check
+        if (getInitParameter("authURL") != null) 
+        {
+        	    mAuthURL = getInitParameter("authURL");
+        }
+        
+        String secureLogin = RollerConfig.getProperty("securelogin.enabled");
+        if(secureLogin != null && "true".equalsIgnoreCase(secureLogin))
+            this.secureLogin = true;
+        
+        String secureLoginPort = RollerConfig.getProperty("securelogin.https.port");
+        if(secureLoginPort != null)
+            this.loginHttpsPort = secureLoginPort;
+        
+        mLogger.info("secure login enabled: "+this.secureLogin);
+        mLogger.info("secure login port: "+this.loginHttpsPort);
+    }
+
+    /**
+     * Route the user to the execute method
+     *
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+               throws IOException, ServletException
+    {
+        execute(request, response);
+    }
+
+    /**
+     * Route the user to the execute method
+     *
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public void doPost(HttpServletRequest request, HttpServletResponse response)
+                throws IOException, ServletException
+    {
+        execute(request, response);
+    }
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     *
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public void execute(HttpServletRequest request, 
+                        HttpServletResponse response) throws IOException, 
+                                                             ServletException
+    {
+        // if user is already authenticated, it means they probably bookmarked
+        // or typed in the URL to login.jsp directly, route them to the main
+        // menu if this is the case
+        if (request.getRemoteUser() != null) {
+            if (mLogger.isDebugEnabled()) {
+                mLogger.debug("User '" + request.getRemoteUser() +
+                          "' already logged in, routing to main");
+            }
+            response.sendRedirect(request.getContextPath() + "/main.do");
+            return;
+        }
+        
+        // Extract attributes we will need
+        String username = request.getParameter("j_username");
+        String password = request.getParameter("j_password");
+        
+        String encryptedPassword = getEncryptedPassword(request, username, password);
+
+        String req = null;
+        String contextUrl = null;
+        if (this.secureLogin)
+        {
+            // Secure login and app server may not know it, so we must build URL 
+            StringBuffer sb = new StringBuffer("");
+            sb.append("https://");
+            if (this.loginHttpsPort.equals(SslUtil.STD_HTTPS_PORT)) 
+            {
+                sb.append(request.getServerName());
+            }
+            else 
+            {
+                sb.append(request.getServerName() + ":" + this.loginHttpsPort);
+            }
+            sb.append(request.getContextPath());
+            contextUrl = sb.toString();
+        }
+        else 
+        {
+            contextUrl = request.getContextPath();
+        }
+        // TODO: is there a way we can do this without having password in the URL?
+        req = contextUrl + mAuthURL 
+            + "?j_username=" + username 
+            + "&j_password=" + encryptedPassword 
+            + "&j_uri=" + request.getParameter("j_uri");
+
+        if (mLogger.isDebugEnabled())
+        {
+            mLogger.debug("Authenticating user '" + username + "'");
+        }
+
+        response.sendRedirect(response.encodeRedirectURL(req));
+    }
+
+    /**
+     * Encode the user's password (if necessary) before redirecting to
+     * the Container Managed Security servlet.
+     * 
+     * @param request
+     * @param username
+     * @param password
+     * @return
+     */
+    public static String getEncryptedPassword(
+                       HttpServletRequest request, String username, String password)
+    {
+        // This determines if the password should be encrypted programmatically
+        mEncrypt = new Boolean(RollerConfig.getProperty("passwds.encryption.enabled"));
+        mAlgorithm = RollerConfig.getProperty("passwds.encryption.algorithm");
+
+        if (mLogger.isDebugEnabled())
+        {
+            mLogger.debug("Authentication URL: " + mAuthURL);
+            mLogger.debug("Programmatic encryption of password? " + mEncrypt);
+            mLogger.debug("Encryption algorithm: " + mAlgorithm);
+        }
+
+        if (request.getParameter("rememberMe") != null) {
+            request.getSession().setAttribute(RollerRequest.LOGIN_COOKIE, "true");
+        }
+        String encryptedPassword = "";
+        if (mEncrypt.booleanValue() && (request.getAttribute("encrypt") == null))
+        {
+            if (mLogger.isDebugEnabled())
+            {
+                mLogger.debug("Encrypting password for user '" + username + "'");
+            }
+            encryptedPassword = Utilities.encodePassword(password, mAlgorithm);
+        }
+        else
+        {
+            encryptedPassword = password;
+        }
+        return encryptedPassword;
+    }
+}
\ No newline at end of file

Added: incubator/roller/trunk/src/org/roller/presentation/MainPageAction.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/MainPageAction.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/MainPageAction.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/MainPageAction.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,194 @@
+package org.roller.presentation;
+
+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.model.Roller;
+import org.roller.model.WeblogManager;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.roller.config.RollerRuntimeConfig;
+
+
+/**
+ * Main page action for Roller.
+ * @struts.action name="main" path="/main" scope="request"
+ * @struts.action-forward name="main.page" path="/main.jsp"
+ */
+public class MainPageAction extends Action
+{
+    // TODO: make timeouts configurable
+    private static TimedHolder mPopularWebsites = new TimedHolder(30 * 60 * 1000);
+    private static TimedHolder mRecentEntries = new TimedHolder(120 * 60 * 1000);
+    private static TimedHolder mPinnedEntries = new TimedHolder(120 * 60 * 1000);
+    
+    private static Log mLogger = 
+        LogFactory.getFactory().getInstance(MainPageAction.class);
+        
+	/**
+	 * Loads model and forwards to main.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 MainPageData(req));
+        
+        /* I am pretty sure this value isn't used on the display anymore, 
+         * but I am scared to remove it ... Allen G */
+        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("main.page");
+	}
+    
+    public static void flushMainPageCache()
+    {
+        mLogger.debug("Flushing recent and pinned entries");
+        mRecentEntries.expire();    
+        mPinnedEntries.expire();    
+    }
+    
+    /**
+     * Page model. 
+     */
+    public static class MainPageData 
+    {
+        private HttpServletRequest mRequest = null;
+        
+        public MainPageData(HttpServletRequest req) 
+        {
+            mRequest = req;
+        }
+        
+        /** 
+         * Get list of most popular websites in terms of day hits.
+         * @param num Number of entries to return (takes effect on next cache refresh)
+         */
+        public List getPopularWebsites(int num) throws RollerException
+        {
+            List list = (List)mPopularWebsites.getObject();
+            if (list == null)
+            {
+                mLogger.debug("Refreshing popular websites list");
+                Roller roller = RollerRequest.getRollerRequest(mRequest).getRoller();            
+                list = roller.getRefererManager().getDaysPopularWebsites(num);
+                mPopularWebsites.setObject(list);
+            }
+            return list;
+       }
+        
+        /** 
+         * Get list of recent weblog entries.
+         * @param num Number of entries to return (takes effect on next cache refresh)
+         */
+        public List getRecentWeblogEntries(int num) throws RollerException
+        {
+            List list = (List)mRecentEntries.getObject();
+            try {
+            if (list == null)
+            {
+                mLogger.debug("Refreshing recent entries list");
+                Roller roller = RollerRequest.getRollerRequest(mRequest).getRoller();			                       
+                list = roller.getWeblogManager().getWeblogEntries(
+                    null,                   // userName
+                    null,                   // startDate
+                    new Date(),             // endDate
+                    null,                   // catName
+                    WeblogManager.PUB_ONLY, // status
+                    new Integer(num));       // maxEntries
+                mRecentEntries.setObject(list);
+            }
+            } 
+            catch (Exception e) 
+            {
+                mLogger.error(e);
+            }
+            return list;
+        }
+        
+        /** 
+         * Get list of recent weblog pinned entries 
+         * @param num Number of entries to return (takes effect on next cache refresh)
+         */
+        public List getWeblogEntriesPinnedToMain(int num) throws RollerException
+        {
+            List list = (List)mPinnedEntries.getObject();
+            if (list == null)
+            {
+                mLogger.debug("Refreshing pinned entries list");
+                Roller roller = RollerRequest.getRollerRequest(mRequest).getRoller();
+                list = roller.getWeblogManager()
+                    .getWeblogEntriesPinnedToMain(new Integer(num));  
+                mPinnedEntries.setObject(list);
+            }
+            return list;
+        }
+    }
+    
+    /** Hold object and expire after timeout passes. */
+    public static class TimedHolder 
+    {
+        private Object obj = null;
+        private long updated = 0L;
+        private long timeout = 3000L;  // 3 seconds ?? -Lance
+        
+        /** Create holder with timeout */
+        public TimedHolder(long timeout)
+        {
+            this.timeout = timeout;
+        }
+        /** Set object and reset the timeout clock */
+        public synchronized void setObject(Object obj)
+        {
+            this.obj = obj;
+            this.updated = new Date().getTime();
+        }
+        /** Force object to expire */
+        public synchronized void expire()
+        {
+            this.obj = null;
+        }
+        /** Get object or null if object has expired */
+        public Object getObject()
+        {
+            long currentTime = new Date().getTime();
+            if ((currentTime - this.updated) > this.timeout)
+            {
+                return null;
+            }
+            else 
+            {
+                return this.obj;
+            }
+        }
+    }
+}
+

Added: incubator/roller/trunk/src/org/roller/presentation/ResourceServlet.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/ResourceServlet.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/ResourceServlet.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/ResourceServlet.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,132 @@
+package org.roller.presentation;
+
+import java.io.*;
+import java.util.Date;
+
+import javax.servlet.*;
+import javax.servlet.http.*;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.roller.model.RollerFactory;
+
+
+/**
+ * Resources servlet.  Acts as a gateway to files uploaded by users.
+ *
+ * Since we keep uploaded resources in a location outside of the webapp
+ * context we need a way to serve them up.  This servlet assumes that 
+ * resources are stored on a filesystem in the "uploads.dir" directory.
+ *
+ * @author Allen Gilliland
+ *
+ * @web.servlet name="ResourcesServlet"
+ * @web.servlet-mapping url-pattern="/resources/*"
+ */
+public class ResourceServlet extends HttpServlet
+{   
+    private static Log mLogger =
+            LogFactory.getFactory().getInstance(ResourceServlet.class);
+    
+    private String upload_dir = null;
+    private ServletContext context = null;
+    
+    
+    /** Initializes the servlet.*/
+    public void init(ServletConfig config) throws ServletException {
+        super.init(config);
+        
+        this.context = config.getServletContext();
+
+        try {
+            this.upload_dir = RollerFactory.getRoller().getFileManager().getUploadDir();
+            mLogger.debug("upload dir is ["+this.upload_dir+"]");
+        } catch(Exception e) { mLogger.warn(e); }
+
+    }
+    
+    /** Destroys the servlet.
+     */
+    public void destroy() {
+        
+    }
+    
+    
+    /** Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
+     * @param request servlet request
+     * @param response servlet response
+     */
+    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
+    throws ServletException, IOException {
+        
+        String context = request.getContextPath();
+        String servlet = request.getServletPath();
+        String reqURI = request.getRequestURI();
+        
+        // calculate the path of the requested resource
+        // we expect ... /<context>/<servlet>/path/to/resource
+        String reqResource = reqURI.substring(servlet.length() + context.length());
+        
+        // now we can formulate the *real* path to the resource on the filesystem
+        String resource_path = this.upload_dir + reqResource;
+        File resource = new File(resource_path);
+
+        mLogger.debug("Resource requested ["+reqURI+"]");
+        mLogger.debug("Real path is ["+resource.getAbsolutePath()+"]");
+        
+        // do a quick check to make sure the resource exits, otherwise 404
+        if(!resource.exists() || !resource.canRead()) {
+            response.sendError(HttpServletResponse.SC_NOT_FOUND);
+            return;
+        }
+        
+        // does the client already have this file?  if so, then 304
+        Date ifModDate = new Date(request.getDateHeader("If-Modified-Since"));
+        Date lastMod = new Date(resource.lastModified());
+        if(lastMod.compareTo(ifModDate) <= 0) {
+            mLogger.debug("Resource unmodified ... sending 304");
+            response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+            return;
+        }
+        
+        // looks like we'll be serving up the file ... lets set some headers
+        // set last-modified date so we can do if-modified-since checks
+        // set the content type based on whatever is in our web.xml mime defs
+        response.addDateHeader("Last-Modified", (new Date()).getTime());
+        response.setContentType(this.context.getMimeType(resource.getAbsolutePath()));
+        
+        // ok, lets serve up the file
+        byte[] buf = new byte[8192];
+        int length = 0;
+        OutputStream out = response.getOutputStream();
+        InputStream resource_file = new FileInputStream(resource);
+        while((length = resource_file.read(buf)) > 0)
+            out.write(buf, 0, length);
+    }
+    
+    
+    /** Handles the HTTP <code>GET</code> method.
+     * @param request servlet request
+     * @param response servlet response
+     */
+    protected void doGet(HttpServletRequest request, HttpServletResponse response)
+    throws ServletException, IOException {
+        processRequest(request, response);
+    }
+    
+    /** Handles the HTTP <code>POST</code> method.
+     * @param request servlet request
+     * @param response servlet response
+     */
+    protected void doPost(HttpServletRequest request, HttpServletResponse response)
+    throws ServletException, IOException {
+        processRequest(request, response);
+    }
+    
+    /** Returns a short description of the servlet.
+     */
+    public String getServletInfo() {
+        return "ResourceServlet ... serving you since 2005 ;)";
+    }
+    
+}

Added: incubator/roller/trunk/src/org/roller/presentation/RollerContext.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/RollerContext.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/RollerContext.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/RollerContext.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,915 @@
+package org.roller.presentation;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.TimerTask;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSessionEvent;
+import javax.sql.DataSource;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.struts.util.RequestUtils;
+import org.roller.RollerException;
+import org.roller.config.RollerConfig;
+import org.roller.model.RefererManager;
+import org.roller.model.Roller;
+import org.roller.model.RollerFactory;
+import org.roller.model.RollerSpellCheck;
+import org.roller.model.ScheduledTask;
+import org.roller.pojos.UserData;
+import org.roller.pojos.WeblogEntryData;
+import org.roller.presentation.velocity.CommentAuthenticator;
+import org.roller.presentation.velocity.ContextLoader;
+import org.roller.presentation.velocity.DefaultCommentAuthenticator;
+import org.roller.presentation.website.ThemeCache;
+import org.roller.presentation.pings.PingQueueTask;
+import org.roller.util.DateUtil;
+import org.roller.util.StringUtils;
+import org.roller.util.Utilities;
+
+import EDU.oswego.cs.dl.util.concurrent.SynchronizedInt;
+import org.roller.config.RollerRuntimeConfig;
+import org.roller.config.PingConfig;
+
+//////////////////////////////////////////////////////////////////////////////
+/**
+ * Responds to app init/destroy events and holds Roller instance.
+ * @web.listener
+ */
+public class RollerContext implements ServletContextListener
+{
+    private static Log mLogger =
+        LogFactory.getFactory().getInstance(RollerContext.class);
+
+    private String mVersion = null;
+    private String mBuildTime = null;
+    private String mBuildUser = null;
+
+    public static final String ROLLER_KEY = "session.roller";
+    public static final String ROLLER_CONTEXT = "roller.context";
+    public static final String USER_RESOURCES = "/resources";
+    public static final String VERSION_KEY = "org.roller.version";
+    public static final String MEMDEBUG_KEY = "org.roller.memdebug";
+    public static final String INDEX_MGR_KEY = "org.roller.indexMgr";
+    public static final String HTTP_PORT = "http_port";
+    public static final String HTTPS_PORT = "https_port";
+    public static final String HTTPS_HEADER_NAME = "https_header_name";
+    public static final String HTTPS_HEADER_VALUE = "https_header_value";
+    private static final String HOURLY_TASK_KEY = "roller.hourly.tasks";
+    private static final String DAILY_TASK_KEY = "roller.daily.tasks";
+    
+    private static final String ROLLER_IMPL_KEY 
+        = "org.roller.persistence";
+    
+    private static final String ROLLER_COMMENT_AUTH_KEY 
+        = "org.roller.commentAuthenticatorClass";
+
+    private static ServletContext mContext = null;
+    private static Authenticator mAuthenticator = null;
+    private static CommentAuthenticator mCommentAuthenticator = null;
+    private final SynchronizedInt mSessionCount = new SynchronizedInt(0);
+    private boolean mMemDebug = false;
+
+    /**
+     * Constructor for RollerContext.
+     */
+    public RollerContext()
+    {
+        super();
+        Properties props = new Properties();
+        try
+        {
+            props.load(getClass().getResourceAsStream("/version.properties"));
+        }
+        catch (IOException e)
+        {
+            mLogger.error("version.properties not found", e);
+        }
+        mVersion = props.getProperty("ro.version", "UNKNOWN");
+        mBuildTime = props.getProperty("ro.buildTime", "UNKNOWN");
+        mBuildUser = props.getProperty("ro.buildUser", "UNKNOWN");
+    }
+
+    //-----------------------------------------------------------------------
+    /* Returns Roller instance for specified app */
+    public static RollerContext getRollerContext(ServletContext sc)
+    {
+        // get roller from servlet context
+        return (RollerContext) sc.getAttribute(ROLLER_CONTEXT);
+    }
+
+    //-----------------------------------------------------------------------
+    /* Returns Roller instance for specified app */
+    public static RollerContext getRollerContext(HttpServletRequest req)
+    {
+        // get roller from servlet context
+        ServletContext sc = RollerContext.getServletContext();
+        return (RollerContext) sc.getAttribute(ROLLER_CONTEXT);
+    }
+
+    //-----------------------------------------------------------------------
+    /** Responds to app-destroy by saving the indexManager's information */
+    public void contextDestroyed(ServletContextEvent sce)
+    {
+        RollerFactory.getRoller().shutdown();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Responds to context initialization event by processing context
+     * paramters for easy access by the rest of the application.
+     */
+    public void contextInitialized(ServletContextEvent sce)
+    {
+        if (mLogger.isDebugEnabled())
+        {
+            mLogger.debug("RollerContext initializing");
+        }
+
+        // Save context in self and self in context
+        mContext = sce.getServletContext();
+        mContext.setAttribute(ROLLER_CONTEXT, this);
+
+        try
+        {
+            // get the *real* path to <context>/resources
+            String ctxPath = mContext.getRealPath("/");
+            if(!ctxPath.endsWith(File.separator))
+                ctxPath += File.separator + "resources";
+            else
+                ctxPath += "resources";
+            
+            // try setting the uploads path to <context>/resources
+            // NOTE: this should go away at some point
+            // we leave it here for now to allow users to keep writing
+            // uploads into their webapp context, but this is a bad idea
+            //
+            // also, the RollerConfig.setUploadsDir() method is smart
+            // enough to disregard this call unless the uploads.path
+            // is set to ${webapp.context}
+            RollerConfig.setUploadsDir(ctxPath);
+            
+            
+            Roller roller = RollerFactory.getRoller();
+            
+            roller.begin(UserData.SYSTEM_USER);
+            
+            //setupRollerConfig();
+            setupRollerProperties();
+            upgradeDatabaseIfNeeded();
+            setupSpellChecker();
+            setupPagePlugins();
+            setupIndexManager(roller);
+            setupRefererManager(roller);
+            initializePingFeatures(roller);
+            setupPingQueueTask(roller);
+            setupScheduledTasks(mContext, roller);
+            
+            roller.commit();
+            roller.release();
+            
+            String flag = RollerConfig.getProperty("debug.memory.enabled");
+            if (flag != null && !flag.equalsIgnoreCase("false"))
+            {
+                mMemDebug = true;
+            }
+
+            if (mLogger.isDebugEnabled())
+            {
+                mLogger.debug("RollerContext initialization complete");
+            }
+        }
+        catch (Throwable t)
+        {
+            mLogger.fatal("RollerContext initialization failed", t);
+        }
+    }
+
+    
+    private void setupRollerProperties() throws RollerException
+    {
+        // init property manager by creating it
+        Roller mRoller = RollerFactory.getRoller();
+        mRoller.getPropertiesManager();
+    }
+
+    /** Setup daily and hourly tasks specified in web.xml */
+    private void setupScheduledTasks(ServletContext context, Roller roller) 
+        throws RollerException, InstantiationException, 
+               IllegalAccessException, ClassNotFoundException 
+    {
+        // setup the hourly tasks
+        String hourlyString = RollerConfig.getProperty("tasks.hourly");
+        if (hourlyString != null && hourlyString.trim().length() > 0)
+        {
+            String[] hourlyTasks = StringUtils.stripAll(
+                    StringUtils.split(hourlyString, ",") );
+            for (int i=0; i<hourlyTasks.length; i++)
+            {
+                mLogger.info("Setting hourly task: "+hourlyTasks[i]);
+                ScheduledTask task = 
+                    (ScheduledTask)Class.forName(hourlyTasks[i]).newInstance();
+                task.init(roller, mContext.getRealPath("/"));
+                roller.getThreadManager().scheduleHourlyTimerTask((TimerTask)task);
+            }
+        }
+        
+        // setup the daily tasks
+        String dailyString = RollerConfig.getProperty("tasks.daily");
+        if (dailyString != null && dailyString.trim().length() > 0)
+        {
+            String[] dailyTasks = StringUtils.stripAll(
+                    StringUtils.split(dailyString, ",") );
+            for (int j=0; j<dailyTasks.length; j++)
+            {
+                mLogger.info("Setting daily task: "+dailyTasks[j]);
+                ScheduledTask task = 
+                    (ScheduledTask)Class.forName(dailyTasks[j]).newInstance();
+                task.init(roller, mContext.getRealPath("/"));               
+                roller.getThreadManager().scheduleDailyTimerTask((TimerTask)task);
+            }
+        }
+    }
+
+    // Initialize ping features
+    private void initializePingFeatures(Roller roller) throws RollerException {
+        // Initialize common targets from the configuration
+        PingConfig.initializeCommonTargets();
+        // Remove csutom ping targets if they have been disallowed
+        if (PingConfig.getDisallowCustomTargets()) {
+            mLogger.info("Custom ping targets have been disallowed.  Removing any existing custom targets.");
+            roller.getPingTargetManager().removeAllCustomPingTargets();
+        }
+        // Remove all autoping configurations if ping usage has been disabled.
+        if (PingConfig.getDisablePingUsage()) {
+            mLogger.info("Ping usage has been disabled.  Removing any existing auto ping configurations.");
+            roller.getAutopingManager().removeAllAutoPings();
+        }
+    }
+
+
+    // Set up the ping queue processing task
+    private void setupPingQueueTask(Roller roller) throws RollerException
+    {
+        long intervalMins = PingConfig.getQueueProcessingIntervalMins();
+        if (intervalMins == 0) {
+            // Ping queue processing interval of 0 indicates that ping queue processing is disabled on this host.
+            // This provides a crude  way to disable running the ping queue task on some servers if there are
+            // multiple servers in a cluster sharing a db.  Exclusion should really be handled dynamically but isn't. 
+            mLogger.warn("Ping queue processing interval is zero; processing from the ping queue will be disabled on this server.");
+            mLogger.warn("Please make sure that ping queue processing is configured to run on one server in the cluster.");
+            return;
+        }
+
+        // Set up the task
+        PingQueueTask pingQueueTask = new PingQueueTask();
+        pingQueueTask.init(this, intervalMins);
+
+        // Schedule it at the appropriate interval, delay start for one interval.
+        mLogger.info("Scheduling ping queue task to run at " + intervalMins + " minute intervals.");
+        roller.getThreadManager().scheduleFixedRateTimerTask(pingQueueTask, intervalMins, intervalMins);
+    }
+
+    protected void upgradeDatabaseIfNeeded() throws RollerException
+    {
+        try
+        {
+            InitialContext ic = new InitialContext();
+            DataSource ds = (DataSource)ic.lookup("java:comp/env/jdbc/rollerdb");
+            Connection con = ds.getConnection();
+            RollerFactory.getRoller().upgradeDatabase(con);
+            con.close();
+        }
+        catch (NamingException e)
+        {
+            mLogger.warn("Unable to access DataSource", e);
+        }
+        catch (SQLException e)
+        {
+            mLogger.warn(e);
+        }
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Initialize the configured PagePlugins
+     * @param mContext
+     */
+    private void setupPagePlugins()
+    {
+        if (mLogger.isDebugEnabled())
+        {
+            mLogger.debug("Initialize PagePlugins");
+        }
+        ContextLoader.initializePagePlugins(mContext);
+
+    }
+
+    /**
+     * Add TurnoverReferersTask to run on a schedule.
+     */
+    private void setupRefererManager(Roller roller)
+    {
+        try
+        {
+            // Check for turnover when we first start
+            final RefererManager refManager = roller.getRefererManager();
+            refManager.checkForTurnover(false, null);
+
+            // Schedule a check every day, starting at end of today
+            //TurnoverReferersTask task = new TurnoverReferersTask();
+            //task.init(roller, mContext.getRealPath("/"));
+            //roller.getThreadManager().scheduleDailyTimerTask(task);
+        }
+        catch (RollerException e)
+        {
+            mLogger.warn("Couldn't schedule referer turnover task", e);
+        }
+    }
+
+    //------------------------------------------------------------------------
+
+    private void setupIndexManager(Roller roller) throws RollerException
+    {
+        roller.getIndexManager();        
+    }
+
+    public void sessionCreated(HttpSessionEvent se)
+    {
+        if (mMemDebug)
+        {
+            mSessionCount.increment();
+            mContext.log(
+                "Roller:SESSION_CREATED:count="
+                    + mSessionCount
+                    + ":freemem="
+                    + Runtime.getRuntime().freeMemory()
+                    + ":totmem="
+                    + Runtime.getRuntime().totalMemory());
+        }
+    }
+
+    //------------------------------------------------------------------------
+
+    public void sessionDestroyed(HttpSessionEvent se)
+    {
+        if (mMemDebug)
+        {
+            mSessionCount.decrement();
+            mContext.log(
+                "Roller:SESSION_DESTROY:count="
+                    + mSessionCount
+                    + ":freemem="
+                    + Runtime.getRuntime().freeMemory()
+                    + ":totalmem="
+                    + Runtime.getRuntime().totalMemory());
+        }
+    }
+
+    //------------------------------------------------------------------------
+
+    /**
+     * Get an instance of Roller from the RollerFactory.
+     * If one does not exist, tell Factory to create new one.
+     */
+    public static Roller getRoller(HttpServletRequest req)
+    {
+        return RollerFactory.getRoller();
+    }
+
+    //------------------------------------------------------------------------
+
+    /**
+     * Get authenticator
+     */
+    public Authenticator getAuthenticator()
+    {
+        if (mAuthenticator == null)
+        {
+            try
+            {
+                Class authClass =
+                    Class.forName(RollerConfig.getProperty("authenticator.classname"));
+                mAuthenticator = (Authenticator) authClass.newInstance();
+            }
+            catch (Exception e)
+            {
+                // this isn't an ERROR if no authenticatorClass was specified
+                if (!(e instanceof NullPointerException))
+                {    
+                    mLogger.error("ERROR creating authenticator, using default", e);
+                }
+                else
+                {
+                    mLogger.debug("No authenticator specified, using DefaultAuthenticator");
+                }
+                mAuthenticator = new DefaultAuthenticator();
+            }
+        }
+        return mAuthenticator;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns RollerConfig object. Changed so that it always tries
+     * to fetch from the database first. If it should error, return
+     * the stored copy.
+     */
+    /* not available anymore ... use the new config classes instead -- Allen G
+    public RollerConfigData getRollerConfig()
+    {
+        if (mConfig == null)
+        {
+            try 
+            {
+    			    mConfig = getRoller(null).getConfigManager().getRollerConfig();
+    		    } 
+            catch (RollerException e) 
+            {
+    			mLogger.error("Unable to get RollerConfig from database");
+    		    }
+        }
+        return mConfig;
+    }
+    */
+
+    //-----------------------------------------------------------------------
+    /**
+     *  Gets the hard-drive location of the upload directory.
+     */
+    public static String getUploadDir(ServletContext app)
+    {
+        // ACK ... this really isn't the right place for this lookup!!
+        String uploaddir = null;
+        try 
+        {
+            uploaddir = RollerFactory.getRoller().getFileManager().getUploadDir();
+        } 
+        catch(Exception e) {}
+        
+        return uploaddir;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the base url for the upload directory.
+     */
+    public static String getUploadPath(ServletContext app)
+    {
+        // ACK ... why do this here??
+        String uploadurl = null;
+        try {
+            uploadurl = RollerFactory.getRoller().getFileManager().getUploadUrl();
+        } catch(Exception e) {}
+        
+        return uploadurl;
+    }
+
+    //-----------------------------------------------------------------------
+	/**
+	 * Read Roller configuration parameters from roller-config.xml.
+	 */
+    /* no longer needed now that we have a new config system -- Allen G.
+	private void setupRollerConfig() throws RollerException
+	{
+	    mConfig = getRoller(null).getConfigManager().getRollerConfig();
+	    if (mConfig == null)
+	    {
+            // No entry in the rollerconfig table means that we are upgading to
+            // Roller 0.9.9. To upgrade, we need to read the values from the
+            // existing roller-config.xml and write them to the rollerconfig table.
+            String configPath = getConfigPath();
+	        mConfig = getRoller(null).getConfigManager().readFromFile(configPath);
+            
+            // Roller 0.9.9 uses roles for security, so create an admin role for 
+            // each of the admin users listed in the roller-config.xml file.
+            String adminUsers[] = mConfig.adminUsersArray();
+            for (int i=0; i<adminUsers.length; i++) 
+            {
+                UserData user = 
+                    getRoller(null).getUserManager().getUser(adminUsers[i]);
+                if (user != null) 
+                {
+                    RoleData role = new RoleData(null, user, "admin");
+                    role.save();
+                }
+            }
+            
+            // By setting the database version to null here, we ensure that the 
+            // rest of the database tables will be upgraded to 0.9.9.
+            mConfig.setDatabaseVersion(null);  
+            
+            saveRollerConfig(mConfig);
+	    }	    
+	}
+    */
+    
+    //-----------------------------------------------------------------------
+    /* Unused method ... this is the wrong place for this anyways -- Allen G.
+    public void saveRollerConfig(RollerConfigData rConfig) throws RollerException
+    {
+        mConfig = rConfig;
+        
+        // save database copy
+        //getRoller(null).begin(); // begin already called by RequestFilter
+        getRoller(null).getConfigManager().storeRollerConfig(rConfig);
+        getRoller(null).commit();
+        
+        // save file copy
+        OldRollerConfig rConfigFile = new OldRollerConfig(rConfig);
+        rConfigFile.writeConfig(getConfigPath());
+    }
+    */
+    
+    //-----------------------------------------------------------------------
+
+    /**
+     * Determine where we should read/write roller-config.xml to.
+     * A file in ${user.home} overrides one in WEB-INF.
+     */
+    /* Unused old method -- Allen G.
+    public String getConfigPath()
+    {
+        String configPath =
+            System.getProperty("user.home")
+                + File.separator
+                + "roller-config.xml";
+
+        if (mLogger.isDebugEnabled())
+        {
+            mLogger.debug(
+                "Looking for roller-config.xml at '" + configPath + "'");
+        }
+
+        boolean configFoundInHomeDir;
+        try
+        {
+            configFoundInHomeDir = new File(configPath).exists();
+        }
+        catch (SecurityException se)
+        {
+            configFoundInHomeDir = false;
+            mLogger.info("Permission denied at '" + configPath + "'");
+        }
+        if (!configFoundInHomeDir)
+        {
+            // No config found in user.home, store it in WEB-INF instead.
+            if (mLogger.isDebugEnabled())
+            {
+                mLogger.debug("File not found: '" + configPath);
+            }
+
+            String root = mContext.getRealPath("/");
+            configPath =
+                root
+                    + File.separator
+                    + "WEB-INF"
+                    + File.separator
+                    + "roller-config.xml";
+        }
+
+        mLogger.info("Using roller-config.xml at '" + configPath + "'");
+
+        return configPath;
+    }
+    */
+    
+    //-----------------------------------------------------------------------
+
+    /**
+     * RollerSpellCheck must be initialized with a dictionary file
+     * so that it can return valid a SpellChecker.
+     */
+    private void setupSpellChecker()
+    {
+        InputStream is = null;
+        try
+        {
+            is = mContext.getResourceAsStream("/WEB-INF/english.0");
+            RollerSpellCheck.init(is);
+        }
+        catch (Exception e)
+        {
+            mContext.log("ERROR reading dictionary file");
+        }
+        finally
+        {
+            if (is != null)
+            {
+                try
+                {
+                    is.close();
+                }
+                catch (Exception e)
+                {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the full url for the website of the specified username.
+     */
+    public String getContextUrl(HttpServletRequest request, String username)
+    {
+        String url = this.getContextUrl(request);
+        if (username != null)
+        {
+            url = url + "/page/" + username;
+        }
+        return url;
+    }
+
+    //-----------------------------------------------------------------------
+    /** Get absolute URL of Roller context */
+    public String getContextUrl(HttpServletRequest request)
+    {
+        String url = request.getContextPath();
+        if (url.endsWith("/"))
+        {
+            url = url.substring(0, url.length() - 1);
+        }
+        return url;
+    }
+
+    //-----------------------------------------------------------------------
+    /** Get absolute URL of Roller context */
+    public String getAbsoluteContextUrl(HttpServletRequest request)
+    {
+        String url = RollerRuntimeConfig.getProperty("site.absoluteurl");
+        
+        if (url == null || url.trim().length() == 0)
+        {
+            try
+            {
+                URL absURL = RequestUtils.absoluteURL(request, "/");
+                url = absURL.toString();
+            }
+            catch (MalformedURLException e)
+            {
+                url = "/";
+                mLogger.error("ERROR: forming absolute URL", e);
+            }
+        }
+        if (url.endsWith("/"))
+        {
+            url = url.substring(0, url.length() - 1);
+        }
+        mContext.setAttribute("org.roller.absoluteContextURL", url);
+        return url;
+    }
+
+    //-----------------------------------------------------------------------
+
+    /**
+     * For use by MetaWeblog API.
+     * @return Context URL or null if not initialized yet.
+     */
+    public String getAbsoluteContextUrl()
+    {
+        return (String) mContext.getAttribute("org.roller.absoluteContextURL");
+    }
+
+    //-----------------------------------------------------------------------
+
+    public String createEntryPermalink(
+        WeblogEntryData entry,
+        HttpServletRequest request,
+        boolean absolute)
+    {
+        String link = null;
+        try
+        {
+            String baseUrl = null;
+            if (absolute)
+            {
+                baseUrl = getAbsoluteContextUrl(request);
+            }
+            else
+            {
+                baseUrl = getContextUrl(request);
+            }
+
+            String dayString = DateUtil.format8chars(entry.getPubTime());
+
+            UserData ud = entry.getWebsite().getUser();
+
+            link =
+                Utilities.escapeHTML(
+                    baseUrl
+                        + "/page/"
+                        + ud.getUserName()
+                        + "/"
+                        + dayString
+                        + "#"
+                        + entry.getAnchor());
+        }
+        catch (Exception e)
+        {
+            mLogger.error("Unexpected exception", e);
+        }
+        return link;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Return the real filepath to the theme.
+     *
+     * @param theme
+     * @return String
+     */
+    public String getThemePath(String theme)
+    {
+        String themespath = RollerRuntimeConfig.getProperty("users.themes.path");
+
+        // Figure path to new user theme
+        return mContext.getRealPath(
+            "/" + themespath + "/" + theme);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Get the list of Theme names.  This consists
+     * of the directories under the /themes directory.
+     *
+     * @return String[]
+     */
+    public String[] getThemeNames()
+    {
+        String themespath = RollerRuntimeConfig.getProperty("users.themes.path");
+        
+        String themesPath =
+            mContext.getRealPath("/" + themespath);
+        File themeDir = new File(themesPath);
+        return themeDir.list(new FilenameFilter()
+        {
+            public boolean accept(File dir, String name)
+            {
+                File file =
+                    new File(dir.getAbsolutePath() + File.separator + name);
+                return file.isDirectory();
+            }
+        });
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the mContext.
+     * @return ServletContext
+     */
+    public static ServletContext getServletContext()
+    {
+        return mContext;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Reads the Theme files from harddisk (if necessary) and places them into a
+     * ThemeCache.  If the requested Theme's pages are already in the cache,
+     * return them instead.
+     *
+     * @param themeName
+     * @return HashMap
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    public HashMap readThemeMacros(String themeName)
+        throws FileNotFoundException, IOException
+    {
+        if (mLogger.isDebugEnabled())
+        {
+            mLogger.debug("themeName=" + themeName);
+        }
+
+        // Load all Velocity templates from root directory of the theme
+        String pageName = null;
+        String themeDir = this.getThemePath(themeName);
+        String[] children = getThemeFilenames(themeDir);
+        HashMap pages = new HashMap();
+        ThemeCache themeCache = ThemeCache.getInstance();
+        for (int i = 0; i < children.length; i++)
+        {
+            pageName = children[i].substring(0, children[i].length() - 3);
+
+            if (themeCache.getFromCache(themeName, pageName) != null)
+            {
+                pages.put(
+                    pageName,
+                    themeCache.getFromCache(themeName, pageName));
+            }
+            else
+            {
+                BufferedReader rdr = null;
+                try
+                {
+                    rdr = new BufferedReader(
+                        new FileReader(
+                            themeDir + File.separator + children[i]));
+                    String line = null;
+                    StringBuffer sb = new StringBuffer();
+                    while (null != (line = rdr.readLine()))
+                    {
+                        sb.append(line);
+                        sb.append("\n");
+                    }
+    
+                    pages.put(pageName, sb.toString());
+                    themeCache.putIntoCache(themeName, pageName, sb.toString());
+                }
+                finally 
+                {
+                    if (rdr != null) rdr.close();
+                }
+            }
+        }
+        return pages;
+    }
+
+    //-----------------------------------------------------------------------
+
+    public static String[] getThemeFilenames(String themeDir)
+    {
+        ThemeCache themeCache = ThemeCache.getInstance();
+        if (themeCache.getFileList(themeDir) != null)
+        {
+            return themeCache.getFileList(themeDir);
+        }
+
+        File dir = new File(themeDir);
+        FilenameFilter filter = new FilenameFilter()
+        {
+            public boolean accept(File dir, String name)
+            {
+                return name.endsWith(".vm");
+            }
+        };
+        String[] children = dir.list(filter);
+        themeCache.setFileList(themeDir, children);
+        return children;
+    }
+
+    //-----------------------------------------------------------------------
+
+    /** Roller version */
+    public String getRollerVersion()
+    {
+        return mVersion;
+    }
+
+    //-----------------------------------------------------------------------
+
+    /** Roller build time */
+    public String getRollerBuildTime()
+    {
+        return mBuildTime;
+    }
+
+    //-----------------------------------------------------------------------
+
+    /** Get username that built Roller */
+    public String getRollerBuildUser()
+    {
+        return mBuildUser;
+    }
+
+    //-----------------------------------------------------------------------
+
+    public static CommentAuthenticator getCommentAuthenticator() 
+    {
+        if (mCommentAuthenticator == null) 
+        {
+            String name = RollerConfig.getProperty("comment.authenticator.classname");
+            try 
+            {
+                Class clazz = Class.forName(name);
+                mCommentAuthenticator=(CommentAuthenticator)clazz.newInstance();
+            }
+            catch (Exception e)
+            {
+                mLogger.error(e);
+                mCommentAuthenticator = new DefaultCommentAuthenticator();
+            }
+        }        
+        return mCommentAuthenticator;
+    }
+}

Added: incubator/roller/trunk/src/org/roller/presentation/RollerRequest.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/RollerRequest.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/RollerRequest.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/RollerRequest.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,931 @@
+
+package org.roller.presentation;
+
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.jsp.PageContext;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.roller.RollerException;
+import org.roller.config.RollerRuntimeConfig;
+import org.roller.model.ParsedRequest;
+import org.roller.model.Roller;
+import org.roller.model.UserManager;
+import org.roller.model.WeblogManager;
+import org.roller.pojos.BookmarkData;
+import org.roller.pojos.FolderData;
+import org.roller.pojos.PageData;
+import org.roller.pojos.UserData;
+import org.roller.pojos.WeblogCategoryData;
+import org.roller.pojos.WeblogEntryData;
+import org.roller.pojos.WebsiteData;
+import org.roller.pojos.PingTargetData;
+import org.roller.util.DateUtil;
+import org.roller.util.Utilities;
+ 
+//////////////////////////////////////////////////////////////////////////////
+/**
+ * Access to objects and values specified by request. Parses out arguments from
+ * request URL needed for various parts of Roller and makes them available via
+ * getter methods.
+ * <br/><br/> 
+ * 
+ * These forms of pathinfo get special support:
+ * <br/><br/>
+ * 
+ * <pre>
+ * [username] - get default page for user for today's date 
+ * [username]/[date] - get default page for user for specified date 
+ * [username]/[pagelink] - get specified page for today's date 
+ * [username]/[pagelink]/[date] - get specified page for specified date
+ * [username]/[pagelink]/[anchor] - get specified page & entry (by anchor)
+ * [username]/[pagelink]/[date]/[anchor] - get specified page & entry (by anchor)
+ * </pre>
+ *  
+ * @author David M Johnson
+ */
+public class RollerRequest implements ParsedRequest
+{
+    //----------------------------------------------------------------- Fields
+    
+    private static Log mLogger = 
+        LogFactory.getFactory().getInstance(RollerRequest.class);
+
+    private BookmarkData       mBookmark;
+    private ServletContext     mContext = null;    
+    private Date               mDate = null;
+    private String             mDateString = null;
+    private String             mPathInfo = null; 
+    private String             mPageLink = null;
+    private PageData           mPage;
+    private PageContext        mPageContext = null;
+    private HttpServletRequest mRequest = null;
+    private WebsiteData        mWebsite;
+    private WeblogEntryData    mWeblogEntry;
+    private WeblogCategoryData mWeblogCategory;
+    private boolean           mIsDateSpecified = false;
+        
+    private static ThreadLocal mRollerRequestTLS = new ThreadLocal();
+    
+    public static final String ANCHOR_KEY             = "anchor";
+    public static final String USERNAME_KEY           = "username";
+    public static final String WEBSITEID_KEY          = "websiteid";
+    public static final String FOLDERID_KEY           = "folderid";
+    public static final String PARENTID_KEY           = "parentid";
+    public static final String NEWSFEEDID_KEY         = "feedid";
+    public static final String PAGEID_KEY             = "pageid";
+    public static final String PAGELINK_KEY           = "pagelink";
+    public static final String PINGTARGETID_KEY       = "pingtargetid";
+    public static final String EXCERPTS_KEY           = "excerpts";
+    public static final String BOOKMARKID_KEY         = "bookmarkid";
+    public static final String REFERERID_KEY          = "refid";
+    public static final String WEBLOGENTRYID_KEY      = "entryid";
+    public static final String WEBLOGENTRY_COUNT      = "count";
+    public static final String WEBLOGCATEGORYNAME_KEY = "catname";
+    public static final String WEBLOGCATEGORYID_KEY   = "catid";
+    public static final String WEBLOGENTRIES_KEY      = "entries";
+    public static final String WEBLOGDAY_KEY          = "day";
+    public static final String WEBLOGCOMMENTID_KEY    = "catid";
+    public static final String LOGIN_COOKIE           = "sessionId";
+    
+    public static final String OWNING_USER            = "OWNING_USER";
+    
+    private static final String ROLLER_REQUEST        = "roller_request";
+    
+    private SimpleDateFormat mFmt = DateUtil.get8charDateFormat();
+
+    //----------------------------------------------------------- Constructors
+
+    /** Construct Roller request for a Servlet request */
+    public RollerRequest( HttpServletRequest req, ServletContext ctx )
+        throws RollerException
+    {
+        mRequest = req;
+        mContext = ctx;
+        init();
+    }
+    
+    //------------------------------------------------------------------------
+    /** Convenience */
+    public RollerRequest( ServletRequest req, ServletContext ctx ) 
+        throws RollerException
+    {
+        mRequest = (HttpServletRequest)req;
+        mContext = ctx;
+        init();
+    }
+    
+    //------------------------------------------------------------------------
+    public RollerRequest( PageContext pCtx) throws RollerException
+    {
+        mRequest = (HttpServletRequest) pCtx.getRequest();
+        mContext = pCtx.getServletContext();
+        mPageContext = pCtx;
+        init();
+    }
+
+    //------------------------------------------------------------------------
+    private void init() throws RollerException
+    {
+        mRollerRequestTLS.set(this);
+        if (mRequest.getContextPath().equals("/atom"))
+        {
+            return; // Atom servlet request needs no init
+        }
+        
+        // Bind persistence session to authenticated user, if we have one
+        RollerContext rctx = RollerContext.getRollerContext(mContext); 
+        Authenticator auth = rctx.getAuthenticator();
+        String userName = auth.getAuthenticatedUserName(mRequest);
+        if (userName != null)
+        {
+            UserManager userMgr = getRoller().getUserManager();
+            UserData currentUser = userMgr.getUser(userName);
+            getRoller().setUser(currentUser);
+        }
+
+        // path info may be null, (e.g. on JSP error page)
+        mPathInfo = mRequest.getPathInfo();
+        mPathInfo = (mPathInfo!=null) ? mPathInfo : "";            
+        
+        String[] pathInfo = StringUtils.split(mPathInfo,"/");  
+        if ( pathInfo.length > 0 )
+        {
+            // Parse pathInfo and throw exception if it is invalid
+            if (!"j_security_check".equals(pathInfo[0]))
+            {
+                parsePathInfo( pathInfo );
+                return;
+            }
+        }
+
+        // Parse user, page, and entry from request params if possible
+        parseRequestParams();
+    }
+    
+    //------------------------------------------------------------------------
+    /** 
+     * Bind persistence session to specific user.
+     */
+    private void bindUser() throws RollerException
+    {
+    }
+    
+    //------------------------------------------------------------------------
+    /** Parse pathInfo and throw exception if it is invalid */
+    private void parsePathInfo( String[] pathInfo ) throws RollerException
+    {
+        try 
+        {
+            // If there is any path info, it must be in one of the 
+            // below formats or the request is considered to be invalid.
+            //
+            //   /username 
+            //   /username/datestring 
+            //   /username/pagelink
+            //   /username/pagelink/datestring
+            //   /username/pagelink/anchor (specific entry)
+            //   /username/pagelink/datestring/anchor (specific entry)
+            UserManager userMgr = getRoller().getUserManager();
+            mWebsite = userMgr.getWebsite(pathInfo[0]);
+            if (mWebsite != null)
+            {
+                if ( pathInfo.length == 1 )
+                {
+                    // we have the /username form of URL
+                    mDate = getDate(true);
+                    mDateString = DateUtil.format8chars(mDate);
+                    mPage = userMgr.retrievePage(mWebsite.getDefaultPageId());
+                }
+                else if ( pathInfo.length == 2 )
+                {
+                    mDate = parseDate(pathInfo[1]);
+                    if ( mDate == null ) // pre-jdk1.4 --> || mDate.getYear() <= 70 )
+                    {
+                        // we have the /username/pagelink form of URL
+                        mDate = getDate(true);
+                        mDateString = DateUtil.format8chars(mDate);
+                        mPageLink = pathInfo[1];
+                        mPage = userMgr.getPageByLink(mWebsite, pathInfo[1]);
+                    }
+                    else
+                    {
+                        // we have the /username/datestring form of URL
+                        mDateString = pathInfo[1];
+                        mPage = userMgr.retrievePage(mWebsite.getDefaultPageId());
+                        mIsDateSpecified = true;
+                    }               
+                }
+                else if ( pathInfo.length == 3 )
+                {
+                    mPageLink = pathInfo[1];
+                    mPage = userMgr.getPageByLink(mWebsite, pathInfo[1]);
+                    
+                    mDate = parseDate(pathInfo[2]);
+                    if ( mDate == null ) // pre-jdk1.4 --> || mDate.getYear() <= 70 )
+                    {
+                        // we have the /username/pagelink/anchor form of URL
+                        try
+                        {
+                            WeblogManager weblogMgr = getRoller().getWeblogManager();
+                            mWeblogEntry = weblogMgr.getWeblogEntryByAnchor(
+                                mWebsite, pathInfo[2]);
+                            mDate = mWeblogEntry.getPubTime();
+                            mDateString = DateUtil.format8chars(mDate);
+                        }
+                        catch (Exception damn)
+                        {
+                            // doesn't really matter, we've got the Page anyway
+                            mLogger.debug("Damn", damn);
+                        }
+                    }
+                    else
+                    {
+                        // we have the /username/pagelink/datestring form of URL
+                        mDateString = pathInfo[2];
+                        mIsDateSpecified = true;
+                    }
+                }
+                else if ( pathInfo.length == 4 )
+                {
+                    // we have the /username/pagelink/datestring/anchor form of URL
+                    mPageLink = pathInfo[1];
+                    mPage = userMgr.getPageByLink(mWebsite, pathInfo[1]);
+                    
+                    mDate = parseDate(pathInfo[2]);
+                    mDateString = pathInfo[2];
+                    mIsDateSpecified = true;
+
+                    // we have the /username/pagelink/date/anchor form of URL
+                    WeblogManager weblogMgr = getRoller().getWeblogManager();
+                    mWeblogEntry = weblogMgr.getWeblogEntryByAnchor(
+                                    mWebsite, pathInfo[3]);
+                }                
+            }
+        }
+        catch ( Exception ignored )
+        {
+            mLogger.debug("Exception parsing pathInfo",ignored);
+        }
+        
+        if ( mWebsite==null || mDate==null || mPage==null )
+        {            
+            String msg = "Invalid pathInfo: "+StringUtils.join(pathInfo,"|");
+            mLogger.info(msg);                       
+            throw new RollerException(msg);
+        }
+    }       
+    
+    //------------------------------------------------------------------------
+    /** Parse user, page, and entry from request params if possible */
+    private void parseRequestParams()
+    {
+        try
+        {
+            // No path info means that we need to parse request params
+            
+            // First, look for user in the request params
+            UserManager userMgr = getRoller().getUserManager();            
+            String userName = mRequest.getParameter(USERNAME_KEY);
+            if ( userName == null )
+            {
+                // then try remote user
+                userName = mRequest.getRemoteUser(); 
+            }
+            
+            if ( userName != null )
+            {
+                mWebsite = userMgr.getWebsite(userName);
+            }
+            
+            // Look for page ID in request params
+            String pageId = mRequest.getParameter(RollerRequest.PAGEID_KEY);                    
+            if ( pageId != null )
+            {
+                mPage = userMgr.retrievePage(pageId);
+                
+                // We can use page to find the user, if we don't have one yet
+                if ( mWebsite == null )
+                {
+                    mWebsite = mPage.getWebsite();
+                }                    
+            }
+            else if (mWebsite != null) 
+            {
+                mPage = userMgr.retrievePage( mWebsite.getDefaultPageId() );
+            }
+                                       
+            // Look for day in request params 
+            String daystr = mRequest.getParameter(WEBLOGDAY_KEY);
+            if ( daystr != null )
+            {
+                mDate = parseDate(daystr);
+                if ( mDate != null )
+                {
+                    // we have the /username/datestring form of URL
+                    mDateString = daystr;
+                    mIsDateSpecified = true;
+                }               
+            }                  
+        }
+        catch ( Exception ignored )
+        {
+            mLogger.debug("Exception parsing request params",ignored);
+        }
+    }
+
+    //------------------------------------------------------------------------
+    /** Get HttpServletmRequest that is wrapped by this RollerRequest */
+    public PageContext getPageContext()
+    {
+        return mPageContext;
+    }
+    
+    public void setPageContext(PageContext p)
+    {
+        mPageContext = p;
+    }
+
+    //------------------------------------------------------------------------
+    /** Get HttpServletmRequest that is wrapped by this RollerRequest */
+    public HttpServletRequest getRequest()
+    {
+        return mRequest;
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Get the RollerRequest object that is stored in the request. Creates
+     * RollerRequest if one not found in mRequest.
+     */
+    public static RollerRequest getRollerRequest( 
+        HttpServletRequest r, ServletContext ctx ) throws RollerException
+    {
+        RollerRequest ret= (RollerRequest)r.getAttribute(ROLLER_REQUEST);
+        if ( ret == null )
+        {
+            ret = new RollerRequest(r,ctx);
+            r.setAttribute( ROLLER_REQUEST, ret );
+        }
+        return ret;
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Get the RollerRequest object that is stored in the request. Creates
+     * RollerRequest if one not found in mRequest.
+     */
+    public static RollerRequest getRollerRequest( HttpServletRequest r )
+    {
+        try
+        {
+            return getRollerRequest(r, RollerContext.getServletContext());
+        }
+        catch (Exception e)
+        {
+            mLogger.debug("Unable to create a RollerRequest", e);
+        }
+        return null;
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Get the RollerRequest object that is stored in the request. Creates
+     * RollerRequest if one not found in mRequest.
+     */
+    public static RollerRequest getRollerRequest( PageContext p )
+    {
+        HttpServletRequest r = (HttpServletRequest)p.getRequest();
+        RollerRequest ret = (RollerRequest)r.getAttribute(ROLLER_REQUEST);
+        if (ret == null)
+        {
+            try
+            {
+                ret = new RollerRequest( p );
+                r.setAttribute( ROLLER_REQUEST, ret );
+            }
+            catch (Exception e)
+            {
+                mLogger.debug("Unable to create a RollerRequest", e);
+            }
+        }
+        else
+        {
+            ret.setPageContext( p );
+        }
+        return ret;
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Get RollerRequest object for the current thread using EVIL MAGIC, 
+     * do not use unless you absolutely, positively, cannot use on of the 
+     * getRollerRequest() methods.
+     */
+    public static RollerRequest getRollerRequest()
+    {
+        return (RollerRequest)mRollerRequestTLS.get();
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Get the RollerRequest object that is stored in the requeset.
+     * Creates RollerRequest if one not found in mRequest.
+     */
+    public ServletContext getServletContext()
+    {
+        return mContext;
+    }
+
+    //------------------------------------------------------------------------
+    /** Get Roller instance from */
+    public Roller getRoller()
+    {
+        return RollerContext.getRoller( mRequest );
+    }
+    
+    //------------------------------------------------------------------------
+    /** Is mRequest's user the admin user? */
+    public boolean isAdminUser() throws RollerException
+    {
+        UserData user = getUser();
+        if (user != null && user.hasRole("admin")) 
+        {
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+    //------------------------------------------------------------------------
+    /** Is mRequest's user authorized to edit the mRequested resource */
+    public boolean isUserAuthorizedToEdit() throws RollerException
+    {
+        // Make sure authenticated user is the owner of this item
+        // Session's principal's name must match user name in mRequest
+        
+        RollerContext rctx = RollerContext.getRollerContext(mContext); 
+        Authenticator auth = rctx.getAuthenticator();
+        
+        String userName = auth.getAuthenticatedUserName(mRequest);
+            
+        // TODO: A hack to be replaced by Object.canEdit()
+        UserData owningUser = null;
+        if (mRequest.getAttribute(OWNING_USER) != null)
+        {
+            owningUser = (UserData)mRequest.getAttribute(OWNING_USER);
+        }
+        else
+        {
+            owningUser = getUser(); 
+        }
+        
+        if (    userName != null 
+             && owningUser != null
+             && userName.equalsIgnoreCase( owningUser.getUserName() )
+             && auth.isAuthenticatedUserInRole(mRequest,"editor"))
+        {
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Get user by name.
+     */
+    public UserData getUser( String userName ) throws Exception
+    {
+        return getRoller().getUserManager().getUser(userName);
+    }
+
+    //------------------------------------------------------------------------
+    
+    public boolean isDateSpecified()
+    {
+        return mIsDateSpecified;
+    }
+            
+    //------------------------------------------------------------------------
+    
+    public int getWeblogEntryCount()
+    {
+        // Get count of entries to return, or 20 if null
+        int count = 20;
+        if ( mRequest.getParameter("count") != null )
+        {
+            count= Utilities.stringToInt(mRequest.getParameter("count"));
+            if ( count==0 || count>50 )
+            {
+                count = 20;
+            } 
+        } 
+        return count; 
+    }         
+            
+    //------------------------------------------------------------------------
+    
+    /**
+     * Gets the date specified by the request, or null.
+     * @return Date
+     */
+    public Date getDate()
+    {
+        return getDate(false);
+    }
+    
+    //------------------------------------------------------------------------
+    /**
+     * Gets the date specified by the request
+     * @param orToday If no date specified, then use today's date.
+     * @return Date
+     */
+    public Date getDate( boolean orToday )
+    {
+        Date ret = null;
+        if ( mDate != null )
+        {
+            ret = mDate;
+        }
+        else if ( orToday )
+        {
+            ret = getToday();
+        }
+        return ret;
+    }
+ 
+    /**
+     * Gets the current date based on Website's Locale & Timezone.
+     * @return
+     */
+    private Date getToday()
+    {
+        Calendar todayCal = Calendar.getInstance();
+        if (this.getWebsite() != null)
+        {
+            todayCal = Calendar.getInstance(
+                    this.getWebsite().getTimeZoneInstance(),
+                    this.getWebsite().getLocaleInstance());
+        }
+        todayCal.setTime( new Date() );
+        return todayCal.getTime(); 
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Gets the YYYYMMDD date string specified by the request, or null.
+     * @return String
+     */
+    public String getDateString()
+    {
+        return getDateString(false);
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Gets the date specified by the request
+     * @param orToday If no date specified, then use today's date.
+     * @return Date
+     */
+    public String getDateString( boolean orToday )
+    {
+        String ret = null;
+        if ( mDateString != null )
+        {
+            ret = mDateString;
+        }
+        else if ( orToday )
+        {
+            Calendar todayCal = Calendar.getInstance();
+            if (this.getWebsite() != null)
+            {
+            	todayCal = Calendar.getInstance(
+                        this.getWebsite().getTimeZoneInstance(),
+                        this.getWebsite().getLocaleInstance());
+            }
+            todayCal.setTime( new Date() );
+            ret = mFmt.format(todayCal.getTime());            
+        }
+        return ret;
+    }
+    
+    //------------------------------------------------------------------------
+    /**
+     * Gets the path-info specified by the request, or null.
+     * @return String
+     */
+    public String getPathInfo()
+    {
+        return mPathInfo;
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Gets the page link name specified by the request, or null.
+     * @return String
+     */
+    public String getPageLink()
+    {
+        return mPageLink;
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Gets the BookmarkData specified by the request, or null.
+     * @return BookmarkData
+     */
+    public BookmarkData getBookmark( )
+    {
+        if ( mBookmark == null )
+        {
+            String id = getFromRequest(BOOKMARKID_KEY);
+            if ( id != null )
+            {
+                try
+                {
+                    mBookmark = 
+                        getRoller().getBookmarkManager().retrieveBookmark(id);
+                }
+                catch (RollerException e)
+                {
+                    mLogger.error("Getting bookmark from request",e);
+                }
+            }
+        }
+        return mBookmark;
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Gets the WeblogCategoryData specified by the request, or null.
+     * @return 
+     */
+    public WeblogCategoryData getWeblogCategory()
+    {
+        if ( mWeblogCategory == null )
+        {
+            String id = getFromRequest(WEBLOGCATEGORYID_KEY);
+            if ( id != null )
+            {
+                try
+                {
+                    mWeblogCategory = 
+                        getRoller().getWeblogManager().retrieveWeblogCategory(id);
+                }
+                catch (RollerException e)
+                {
+                    mLogger.error("Getting weblog category by id from request",e);
+                }
+            }
+            else if (StringUtils.isNotEmpty(id = getFromRequest(WEBLOGCATEGORYNAME_KEY)))
+            {
+                try
+                {
+                    mWeblogCategory = 
+                        getRoller().getWeblogManager().getWeblogCategoryByPath(
+                            getWebsite(), null, id);
+                }
+                catch (RollerException e)
+                {
+                    mLogger.error("Getting weblog category by name from request",e);
+                }
+            }
+        }
+        return mWeblogCategory;
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Gets the FolderData specified by the request, or null.
+     * @return FolderData
+     */
+    public FolderData getFolder( )
+    {
+        FolderData folder = null;
+        //if ( folder == null )
+        //{
+            String id = getFromRequest(FOLDERID_KEY);
+            if ( id != null )
+            {
+                try
+                {
+                    folder = 
+                        getRoller().getBookmarkManager().retrieveFolder(id);
+                }
+                catch (RollerException e)
+                {
+                    mLogger.error("Getting folder from request",e);
+                }
+            }
+        //}
+        return folder;
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Gets the PageData specified by the request, or null.
+     * @return PageData
+     */
+    public PageData getPage()
+    {
+        if (mPage == null)
+        {
+            String id = getFromRequest(PAGEID_KEY);
+            if ( id != null )
+            {
+                try
+                {
+                    mPage = getRoller().getUserManager().retrievePage(id);
+                }
+                catch (RollerException e)
+                {
+                    mLogger.error("Getting page from request",e);
+                }
+            }
+        }
+        return mPage;
+    }
+    
+    /**
+     * Allow comment servlet to inject page that it has chosen.
+     */
+    public void setPage(PageData page) 
+    {
+        mPage = page;
+    }
+    
+    //------------------------------------------------------------------------
+    /**
+     * Gets the Request URL specified by the request, or null.
+     * @return String
+     */
+    public String getRequestURL( )
+    {
+        return mRequest.getRequestURL().toString();
+    }
+    
+    //------------------------------------------------------------------------
+    
+    /**
+     * Gets the Referer URL specified by the request, or null.
+     * @return String
+     */
+    public String getRefererURL( )
+    {
+        return mRequest.getHeader("referer");
+    }
+    
+    /**
+     * Gets the UserData specified by the request, or null.
+     * @return UserData
+     */
+    public UserData getUser()
+    {
+        if (mWebsite != null) return mWebsite.getUser();
+        return null;
+    }
+
+    /**
+     * Gets the WebsiteData specified by the request, or null.
+     * @return WeblogCategory
+     */
+    public WebsiteData getWebsite()
+    {
+        return mWebsite;
+    }
+    public void setWebsite(WebsiteData wd)
+    {
+        mWebsite = wd;
+    }
+
+    /**
+     * Gets the WeblogEntryData specified by the request, or null.
+     * 
+     * Why is this done lazily in the parseRequestParameters() method?
+     * 
+     * Because: that method is called from init(), which is called from
+     * a ServletFilter, and sometimes request parameters are not available
+     * in a ServletFiler. They ARE available when the URL points to a JSP,
+     * but they ARE NOT available when the URL points to the PageServlet.
+     * This may be a Tomcat bug, I'm not sure.
+     * 
+     * @return WeblogEntryData
+     */
+    public WeblogEntryData getWeblogEntry( )
+    {
+        if ( mWeblogEntry == null )
+        {        
+            // Look for anchor or entry ID that identifies a specific entry 
+            String anchor = mRequest.getParameter(ANCHOR_KEY);
+            String entryid = mRequest.getParameter(WEBLOGENTRYID_KEY);
+            if (entryid == null) 
+            {
+                entryid = (String)mRequest.getAttribute(WEBLOGENTRYID_KEY);
+            }
+            try
+            {
+                if ( entryid != null )
+                {
+                    WeblogManager weblogMgr = getRoller().getWeblogManager();
+                    mWeblogEntry = weblogMgr.retrieveWeblogEntry(entryid);                
+                
+                    // We can use entry to find the website, if we don't have one
+                    if ( mWeblogEntry != null && mWebsite == null )
+                    {
+                        mWebsite = mWeblogEntry.getWebsite();
+                    }
+                } 
+                else if ( mWebsite != null && anchor != null )
+                {
+                    WeblogManager weblogMgr = getRoller().getWeblogManager();
+                    mWeblogEntry = weblogMgr.getWeblogEntryByAnchor(
+                        mWebsite,anchor);
+                }                             
+            }
+            catch (RollerException e)
+            {
+                mLogger.error("EXCEPTION getting weblog entry",e);
+                mLogger.error("user=" + mWebsite.getUser());
+                mLogger.error("anchor=" + anchor);
+                mLogger.error("entryid=" + entryid);
+            }
+        }           
+        return mWeblogEntry;
+    }
+
+    //------------------------------------------------------------------------
+
+    /** Get attribute from mRequest, and if that fails try session */
+    private String getFromRequest( String key )
+    {
+        String ret = (String)mRequest.getAttribute( key );
+        if ( ret == null )
+        {
+            ret = mRequest.getParameter( key );
+            if (ret == null && mRequest.getSession(false) != null)
+            {
+                ret = (String)mRequest.getSession().getAttribute( key );
+            }
+        }
+        return ret;
+    }
+
+    //------------------------------------------------------------------------
+
+    private Date parseDate( String dateString )
+    {
+        Date ret = null;        
+        if (   dateString!=null 
+            && dateString.length()==8
+            && StringUtils.isNumeric(dateString) )
+        {
+            ParsePosition pos = new ParsePosition(0);
+            ret = mFmt.parse( dateString, pos );
+            
+            // make sure the requested date is not in the future
+            Date today = getToday();
+            if (ret.after(today)) ret = today;
+            
+            // since a specific date was requested set time to end of day
+            ret = DateUtil.getEndOfDay(ret);
+        }
+        return ret;
+    }
+    
+    //------------------------------------------------------------------------
+
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append("[");
+        sb.append(getRequestURL());
+        sb.append(", ");
+        sb.append(getRefererURL());
+        sb.append("]");
+        return sb.toString();
+    }
+
+    //------------------------------------------------------------------------
+
+    /** 
+     * @see org.roller.pojos.ParsedRequest#isLinkbackEnabled()
+     */
+    public boolean isEnableLinkback()
+    {
+        return RollerRuntimeConfig.getBooleanProperty("site.linkbacks.enabled");
+    }
+}
+