You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@roller.apache.org by sn...@apache.org on 2006/05/02 00:23:34 UTC

svn commit: r398712 [20/32] - in /incubator/roller/trunk/src/org/apache: ./ roller/ roller/business/ roller/business/hibernate/ roller/business/referrers/ roller/business/runnable/ roller/business/search/ roller/business/search/operations/ roller/busin...

Added: incubator/roller/trunk/src/org/apache/roller/presentation/tags/menu/RollerMenuModel.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/tags/menu/RollerMenuModel.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/tags/menu/RollerMenuModel.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/tags/menu/RollerMenuModel.java Mon May  1 15:23:02 2006
@@ -0,0 +1,201 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+
+package org.apache.roller.presentation.tags.menu;
+
+import java.io.InputStream;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.digester.Digester;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.RollerException;
+import org.apache.roller.pojos.WebsiteData;
+import org.apache.roller.presentation.BasePageModel;
+import org.apache.roller.presentation.RollerRequest;
+import org.xml.sax.SAXException;
+
+//////////////////////////////////////////////////////////////////////////////
+
+/** 
+ * @author David M Johnson
+ */ 
+public class RollerMenuModel extends BaseRollerMenu implements MenuModel
+{
+    private static Log mLogger = 
+        LogFactory.getFactory().getInstance(RollerMenuModel.class);
+        
+	private String mMenuId = null;
+
+	/** Vector of MenuImpl objects */
+	private Vector mMenus = new Vector();
+
+	/** Key used to store selected menu in request */
+	public static final String MENU_KEY = "rmk";
+
+	/** Key used to store selected menu item in request */
+	public static final String MENU_ITEM_KEY = "rmik";
+
+	//------------------------------------------------------------------------
+
+	/** Construct menu model based on menu XML */	
+	public RollerMenuModel( String menuId, String config, ServletContext ctx )
+	{
+		try
+		{
+			mMenuId = menuId;
+
+			Digester digester = new Digester();
+			digester.push(this);
+			//digester.setDebug(99);
+			//digester.setClassLoader( getClass().getClassLoader() );
+			//digester.setValidating(true);
+
+			String menuPath = "menu-bar/menu";
+			String menuItemPath = "menu-bar/menu/menu-item";
+
+			digester.addObjectCreate( menuPath,
+			 	"org.apache.roller.presentation.tags.menu.MenuImpl");
+			digester.addSetProperties( menuPath );
+			digester.addSetNext( menuPath,"addMenu",
+			 	"org.apache.roller.presentation.tags.menu.Menu");
+
+			digester.addObjectCreate( menuItemPath,
+			 	"org.apache.roller.presentation.tags.menu.MenuItemImpl");
+			digester.addSetProperties( menuItemPath );
+			digester.addSetNext( menuItemPath, "addItem",
+			 	"org.apache.roller.presentation.tags.menu.MenuItemImpl");
+
+			InputStream input = ctx.getResourceAsStream(config);
+			try 
+			{
+				digester.parse(input);
+
+				if ( getMenus() != null )
+				{
+					Vector menus = getMenus();
+					for (int i=0; i<menus.size(); i++)
+					{
+						MenuImpl menu = (MenuImpl)menus.elementAt(i);
+						menu.setMenuId( mMenuId );
+						Vector menuItems = menu.getMenuItems();
+						if ( menuItems != null )
+						{
+						  for (int j=0; j<menuItems.size(); j++ )
+						  {
+							  MenuItemImpl item = 
+							  	(MenuItemImpl)menuItems.elementAt(j);
+							  item.setMenuId( mMenuId );
+						  }
+						}
+					}
+				}
+			} 
+			catch (SAXException e) 
+			{
+                mLogger.error("Unexpected exception",e);
+			}
+            finally 
+            {
+                if ( input!=null )
+                {
+                    try { input.close(); } 
+                    catch (Exception e) { mLogger.error("Unexpected exception",e); };
+                }
+            }
+		}	
+		catch (Exception e)
+       	{
+            mLogger.error("Unexpected exception",e);
+		}
+	}
+
+	//----------------------------------------------- MenuModel implementation
+
+	public Vector getMenus()
+	{
+		return mMenus;
+	}
+
+	//----------------------------------------------------
+	public Menu getSelectedMenu( HttpServletRequest req ) throws RollerException
+	{
+		MenuImpl def = null;
+		MenuImpl selected = null; 
+		for ( int i=0; i<mMenus.size(); i++ ) 
+		{
+			MenuImpl menu = (MenuImpl)mMenus.elementAt(i);
+			if ( menu.isSelected( req ) )
+			{
+				selected = menu;
+				break;
+			}
+			if (def == null)
+			{
+				def = menu;
+			}
+		}
+		if ( selected != null )
+		{
+			return selected;
+		}
+		else
+		{
+			return def;
+		}
+	}
+
+	//----------------------------------------------------
+	public void addMenu( Menu menu )
+	{
+		mMenus.addElement( menu );
+	}
+
+	//------------------------------------------------------------------------
+
+	/** Create params based on incoming request */
+	static Hashtable createParams( HttpServletRequest req )
+	{
+		Hashtable params = new Hashtable();
+		RollerRequest rreq = RollerRequest.getRollerRequest(req);
+		try
+		{
+            WebsiteData website = rreq.getWebsite();
+            BasePageModel pageModel = (BasePageModel)req.getAttribute("model");
+            if (website == null && pageModel != null) 
+            {
+                website = pageModel.getWebsite();              
+            }
+            if (website != null)
+            {
+                params.put(RollerRequest.WEBLOG_KEY, website.getHandle());
+            }
+        }
+		catch (Exception e)
+		{
+			mLogger.error("ERROR getting user in menu model", e);
+		}
+		return params;
+	}
+}
+
+

Added: incubator/roller/trunk/src/org/apache/roller/presentation/tags/menu/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/tags/menu/package.html?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/tags/menu/package.html (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/tags/menu/package.html Mon May  1 15:23:02 2006
@@ -0,0 +1,27 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  The ASF licenses this file to You
+  under the Apache License, Version 2.0 (the "License"); you may not
+  use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.  For additional information regarding
+  copyright in this work, please see the NOTICE file in the top level
+  directory of this distribution.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title></title>
+</head>
+<body>
+Roller's tabbed menu implementation (menu's defined by XML)
+
+</body>
+</html>

Added: incubator/roller/trunk/src/org/apache/roller/presentation/tags/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/tags/package.html?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/tags/package.html (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/tags/package.html Mon May  1 15:23:02 2006
@@ -0,0 +1,27 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  The ASF licenses this file to You
+  under the Apache License, Version 2.0 (the "License"); you may not
+  use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.  For additional information regarding
+  copyright in this work, please see the NOTICE file in the top level
+  directory of this distribution.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title></title>
+</head>
+<body>
+JSP tags used in Roller UI.
+
+</body>
+</html>

Added: incubator/roller/trunk/src/org/apache/roller/presentation/util/CacheHttpServletResponseWrapper.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/util/CacheHttpServletResponseWrapper.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/util/CacheHttpServletResponseWrapper.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/util/CacheHttpServletResponseWrapper.java Mon May  1 15:23:02 2006
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package org.apache.roller.presentation.util;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.Locale;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+/**
+ * CacheServletResponse is a serialized representation of a response
+ *
+ * @author  <a href="mailto:sergek@lokitech.com">Serge Knystautas</a>
+ * @version $Revision: 1.2 $
+ */
+public class CacheHttpServletResponseWrapper extends HttpServletResponseWrapper {
+    private final Log log = LogFactory.getLog(this.getClass());
+
+    /**
+     * We cache the printWriter so we can maintain a single instance
+     * of it no matter how many times it is requested.
+     */
+    private PrintWriter cachedWriter;
+    private ResponseContent result = null;
+    private SplitServletOutputStream cacheOut = null;
+    private int status = SC_OK;
+
+    /**
+     * Constructor
+     *
+     * @param response The servlet response
+     */
+    public CacheHttpServletResponseWrapper(HttpServletResponse response) {
+        super(response);
+        result = new ResponseContent();
+    }
+
+    /**
+     * Get a response content
+     *
+     * @return The content
+     */
+    public ResponseContent getContent() {
+        //Create the byte array
+        result.commit();
+
+        //Return the result from this response
+        return result;
+    }
+
+    /**
+     * Set the content type
+     *
+     * @param value The content type
+     */
+    public void setContentType(String value) {
+        super.setContentType(value);
+        result.setContentType(value);
+    }
+
+    /**
+     * Set the date of a header
+     *
+     * @param name The header name
+     * @param value The date
+     */
+    public void setDateHeader(String name, long value) {
+        if (log.isDebugEnabled()) {
+            log.debug("dateheader: " + name + ": " + value);
+        }
+
+        if ("last-modified".equalsIgnoreCase(name)) {
+            result.setLastModified(value);
+        }
+
+        super.setDateHeader(name, value);
+    }
+
+    /**
+     * Set a header field
+     *
+     * @param name The header name
+     * @param value The header value
+     */
+    public void setHeader(String name, String value) {
+        if (log.isDebugEnabled()) {
+            log.debug("header: " + name + ": " + value);
+        }
+
+        super.setHeader(name, value);
+    }
+
+    /**
+     * Set the int value of the header
+     *
+     * @param name The header name
+     * @param value The int value
+     */
+    public void setIntHeader(String name, int value) {
+        if (log.isDebugEnabled()) {
+            log.debug("intheader: " + name + ": " + value);
+        }
+
+        super.setIntHeader(name, value);
+    }
+
+    /**
+     * We override this so we can catch the response status. Only
+     * responses with a status of 200 (<code>SC_OK</code>) will
+     * be cached.
+     */
+    public void setStatus(int status) {
+        super.setStatus(status);
+        this.status = status;
+    }
+
+    /**
+     * We override this so we can catch the response status. Only
+     * responses with a status of 200 (<code>SC_OK</code>) will
+     * be cached.
+     */
+    public void sendError(int status, String string) throws IOException {
+        super.sendError(status, string);
+        this.status = status;
+    }
+
+    /**
+     * We override this so we can catch the response status. Only
+     * responses with a status of 200 (<code>SC_OK</code>) will
+     * be cached.
+     */
+    public void sendError(int status) throws IOException {
+        super.sendError(status);
+        this.status = status;
+    }
+
+    /**
+     * We override this so we can catch the response status. Only
+     * responses with a status of 200 (<code>SC_OK</code>) will
+     * be cached.
+     */
+    public void setStatus(int status, String string) {
+        super.setStatus(status, string);
+        this.status = status;
+    }
+
+    public void sendRedirect(String location) throws IOException {
+        this.status = SC_MOVED_TEMPORARILY;
+        super.sendRedirect(location);
+    }
+
+    /**
+     * Retrieves the captured HttpResponse status.
+     */
+    public int getStatus() {
+        return status;
+    }
+
+    /**
+     * Set the locale
+     *
+     * @param value The locale
+     */
+    public void setLocale(Locale value) {
+        super.setLocale(value);
+        result.setLocale(value);
+    }
+
+    /**
+     * Get an output stream
+     *
+     * @throws IOException
+     */
+    public ServletOutputStream getOutputStream() throws IOException {
+        // Pass this faked servlet output stream that captures what is sent
+        if (cacheOut == null) {
+            cacheOut = new SplitServletOutputStream(
+                result.getOutputStream(), super.getOutputStream());
+        }
+
+        return cacheOut;
+    }
+
+    /**
+     * Get a print writer
+     *
+     * @throws IOException
+     */
+    public PrintWriter getWriter() throws IOException {
+       if (cachedWriter == null) {
+           cachedWriter = new SplitPrintWriter(
+              new PrintWriter(new OutputStreamWriter(result.getOutputStream(),"UTF-8")), 
+              super.getWriter());
+       }
+       return cachedWriter;
+    }
+
+    public void flushBuffer() throws IOException {
+        super.flushBuffer();
+
+        if (cacheOut != null) {
+            cacheOut.flush();
+        }
+
+        if (cachedWriter != null) {
+            cachedWriter.flush();
+        }
+    }
+    
+    public String getCharacterEncoding()
+    {
+        return "UTF-8";
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/presentation/util/RequestUtil.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/util/RequestUtil.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/util/RequestUtil.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/util/RequestUtil.java Mon May  1 15:23:02 2006
@@ -0,0 +1,278 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.presentation.util;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.struts.taglib.TagUtils;
+
+/**
+ * RequestUtil utility class Good ol' copy-n-paste from <a
+ * href="http://www.javaworld.com/javaworld/jw-02-2002/ssl/utilityclass.txt">
+ * http://www.javaworld.com/javaworld/jw-02-2002/ssl/utilityclass.txt </a> which
+ * is referenced in the following article: <a
+ * href="http://www.javaworld.com/javaworld/jw-02-2002/jw-0215-ssl.html">
+ * http://www.javaworld.com/javaworld/jw-02-2002/jw-0215-ssl.html </a>
+ */
+public class RequestUtil
+{
+    private static final String STOWED_REQUEST_ATTRIBS = "ssl.redirect.attrib.stowed";
+    private transient static Log log = LogFactory.getLog(RequestUtil.class);
+
+    /**
+     * Creates query String from request body parameters
+     */
+    public static String getRequestParameters(HttpServletRequest aRequest)
+    {
+        // set the ALGORIGTHM as defined for the application
+        //ALGORITHM = (String) aRequest.getAttribute(Constants.ENC_ALGORITHM);
+        Map m = aRequest.getParameterMap();
+        return createQueryStringFromMap(m, "&").toString();
+    }
+
+    /**
+     * Builds a query string from a given map of parameters
+     * 
+     * @param m
+     *            A map of parameters
+     * @param ampersand
+     *            String to use for ampersands (e.g. "&" or "&amp;" )
+     * 
+     * @return query string (with no leading "?")
+     */
+    public static StringBuffer createQueryStringFromMap(Map m, String ampersand)
+    {
+        StringBuffer aReturn = new StringBuffer("");
+        Set aEntryS = m.entrySet();
+        Iterator aEntryI = aEntryS.iterator();
+        while (aEntryI.hasNext())
+        {
+            Map.Entry aEntry = (Map.Entry) aEntryI.next();
+            Object o = aEntry.getValue();
+            if (o == null)
+            {
+                append(aEntry.getKey(), "", aReturn, ampersand);
+            }
+            else if (o instanceof String)
+            {
+                append(aEntry.getKey(), o, aReturn, ampersand);
+            }
+            else if (o instanceof String[])
+            {
+                String[] aValues = (String[]) o;
+                for (int i = 0; i < aValues.length; i++)
+                {
+                    append(aEntry.getKey(), aValues[i], aReturn, ampersand);
+                }
+            }
+            else
+            {
+                append(aEntry.getKey(), o, aReturn, ampersand);
+            }
+        }
+        return aReturn;
+    }
+
+    /**
+     * Appends new key and value pair to query string
+     * 
+     * @param key
+     *            parameter name
+     * @param value
+     *            value of parameter
+     * @param queryString
+     *            existing query string
+     * @param ampersand
+     *            string to use for ampersand (e.g. "&" or "&amp;")
+     * 
+     * @return query string (with no leading "?")
+     */
+    private static StringBuffer append(Object key, Object value,
+                    StringBuffer queryString, String ampersand)
+    {
+        if (queryString.length() > 0)
+        {
+            queryString.append(ampersand);
+        }
+        TagUtils tagUtils = TagUtils.getInstance();
+        // Use encodeURL from Struts' RequestUtils class - it's JDK 1.3 and 1.4
+        // compliant
+        queryString.append(tagUtils.encodeURL(key.toString()));
+        queryString.append("=");
+        queryString.append(tagUtils.encodeURL(value.toString()));
+        return queryString;
+    }
+
+    /**
+     * Stores request attributes in session
+     * 
+     * @param aRequest
+     *            the current request
+     */
+    public static void stowRequestAttributes(HttpServletRequest aRequest)
+    {
+        if (aRequest.getSession().getAttribute(STOWED_REQUEST_ATTRIBS) != null)
+        {
+            return;
+        }
+        Enumeration e = aRequest.getAttributeNames();
+        Map map = new HashMap();
+        while (e.hasMoreElements())
+        {
+            String name = (String) e.nextElement();
+            map.put(name, aRequest.getAttribute(name));
+        }
+        aRequest.getSession().setAttribute(STOWED_REQUEST_ATTRIBS, map);
+    }
+
+    /**
+     * Returns request attributes from session to request
+     * 
+     * @param aRequest
+     *            DOCUMENT ME!
+     */
+    public static void reclaimRequestAttributes(HttpServletRequest aRequest)
+    {
+        Map map = (Map) aRequest.getSession().getAttribute(
+                        STOWED_REQUEST_ATTRIBS);
+        if (map == null)
+        {
+            return;
+        }
+        Iterator itr = map.keySet().iterator();
+        while (itr.hasNext())
+        {
+            String name = (String) itr.next();
+            aRequest.setAttribute(name, map.get(name));
+        }
+        aRequest.getSession().removeAttribute(STOWED_REQUEST_ATTRIBS);
+    }
+
+    /**
+     * Convenience method to set a cookie
+     * 
+     * @param response
+     * @param name
+     * @param value
+     * @param path
+     */
+    public static void setCookie(HttpServletResponse response, String name,
+                    String value, String path)
+    {
+        if (log.isDebugEnabled())
+        {
+            log.debug("Setting cookie '" + name + "' on path '" + path + "'");
+        }
+        Cookie cookie = new Cookie(name, value);
+        cookie.setSecure(false);
+        // if path is nothing, use "/" so remember me will work 
+        // when installed as root app
+        cookie.setPath((path.length() == 0) ? "/" : path);
+        cookie.setMaxAge(3600 * 24 * 30); // 30 days
+        response.addCookie(cookie);
+    }
+
+    /**
+     * Convenience method to get a cookie by name
+     * 
+     * @param request
+     *            the current request
+     * @param name
+     *            the name of the cookie to find
+     * 
+     * @return the cookie (if found), null if not found
+     */
+    public static Cookie getCookie(HttpServletRequest request, String name)
+    {
+        Cookie[] cookies = request.getCookies();
+        Cookie returnCookie = null;
+        if (cookies == null)
+        {
+            return returnCookie;
+        }
+        for (int i = 0; i < cookies.length; i++)
+        {
+            Cookie thisCookie = cookies[i];
+            if (thisCookie.getName().equals(name))
+            {
+                // cookies with no value do me no good!
+                if (!thisCookie.getValue().equals(""))
+                {
+                    returnCookie = thisCookie;
+                    break;
+                }
+            }
+        }
+        return returnCookie;
+    }
+
+    /**
+     * Convenience method for deleting a cookie by name
+     * 
+     * @param response
+     *            the current web response
+     * @param cookie
+     *            the cookie to delete
+     * @param path
+     *            the path on which the cookie was set (i.e. /appfuse)
+     */
+    public static void deleteCookie(HttpServletResponse response,
+                    Cookie cookie, String path)
+    {
+        if (cookie != null)
+        {
+            // Delete the cookie by setting its maximum age to zero
+            cookie.setMaxAge(0);
+            cookie.setPath(path);
+            response.addCookie(cookie);
+        }
+    }
+
+    /**
+     * Convenience method to get the application's URL based on request
+     * variables.
+     */
+    public static String getAppURL(HttpServletRequest request)
+    {
+        StringBuffer url = new StringBuffer();
+        int port = request.getServerPort();
+        if (port < 0)
+        {
+            port = 80; // Work around java.net.URL bug
+        }
+        String scheme = request.getScheme();
+        url.append(scheme);
+        url.append("://");
+        url.append(request.getServerName());
+        if ((scheme.equals("http") && (port != 80))
+                        || (scheme.equals("https") && (port != 443)))
+        {
+            url.append(':');
+            url.append(port);
+        }
+        return url.toString();
+    }
+}
\ No newline at end of file

Added: incubator/roller/trunk/src/org/apache/roller/presentation/util/ResponseContent.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/util/ResponseContent.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/util/ResponseContent.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/util/ResponseContent.java Mon May  1 15:23:02 2006
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package org.apache.roller.presentation.util;
+
+import java.io.*;
+
+import java.util.Locale;
+
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Holds the servlet response in a byte array so that it can be held
+ * in the cache (and, since this class is serializable, optionally
+ * persisted to disk).
+ *
+ * @version $Revision: 1.3 $
+ * @author  <a href="mailto:sergek@lokitech.com">Serge Knystautas</a>
+ */
+public class ResponseContent implements Serializable {
+    private transient ByteArrayOutputStream bout = new ByteArrayOutputStream(1000);
+    private Locale locale = null;
+    private String contentType = null;
+    private byte[] content = null;
+    private long lastModified = -1;
+
+    /**
+     * Set the content type. We capture this so that when we serve this
+     * data from cache, we can set the correct content type on the response.
+     */
+    public void setContentType(String value) {
+        contentType = value;
+    }
+
+    public long getLastModified() {
+        return lastModified;
+    }
+
+    public void setLastModified(long value) {
+        lastModified = value;
+    }
+
+    /**
+     * Set the Locale. We capture this so that when we serve this data from
+     * cache, we can set the correct locale on the response.
+     */
+    public void setLocale(Locale value) {
+        locale = value;
+    }
+
+    /**
+     * Get an output stream. This is used by the {@link SplitServletOutputStream}
+     * to capture the original (uncached) response into a byte array.
+     */
+    public OutputStream getOutputStream() {
+        return bout;
+    }
+
+    /**
+     * Gets the size of this cached content.
+     *
+     * @return The size of the content, in bytes. If no content
+     * exists, this method returns <code>-1</code>.
+     */
+    public int getSize() {
+        return (content != null) ? content.length : (-1);
+    }
+
+    /**
+     * Called once the response has been written in its entirety. This
+     * method commits the response output stream by converting the output
+     * stream into a byte array.
+     */
+    public void commit() {
+        content = bout.toByteArray();
+    }
+
+    /**
+     * Writes this cached data out to the supplied <code>ServletResponse</code>.
+     *
+     * @param response The servlet response to output the cached content to.
+     * @throws IOException
+     */
+    public void writeTo(ServletResponse response) throws IOException {
+        //Send the content type and data to this response
+        if (contentType != null) {
+            response.setContentType(contentType);
+        }
+
+        //if (response instanceof HttpServletResponse) {
+            //((HttpServletResponse) response).setDateHeader("Last-Modified", lastModified);
+        //}
+
+        response.setContentLength(content.length);
+
+        if (locale != null) {
+            response.setLocale(locale);
+        }
+
+        OutputStream out = new BufferedOutputStream(response.getOutputStream());
+        out.write(content);
+        out.flush();
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/presentation/util/SplitPrintWriter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/util/SplitPrintWriter.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/util/SplitPrintWriter.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/util/SplitPrintWriter.java Mon May  1 15:23:02 2006
@@ -0,0 +1,56 @@
+package org.apache.roller.presentation.util;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ * @author Dave Johnson
+ */
+public class SplitPrintWriter extends PrintWriter 
+{
+    private PrintWriter captureWriter = null;
+    private PrintWriter passThroughWriter = null;
+    
+    public SplitPrintWriter(PrintWriter captureWriter, PrintWriter passThroughWriter) 
+    {
+        super(passThroughWriter);
+        this.captureWriter = captureWriter;
+        this.passThroughWriter = passThroughWriter;
+    }  
+      
+    public void write(char[] cbuf)
+    {
+        captureWriter.write(cbuf);
+        passThroughWriter.write(cbuf);
+    }
+    public void write(char[] cbuf, int off, int len)
+    {       
+        captureWriter.write(cbuf,off,len);
+        passThroughWriter.write(cbuf,off,len);
+    }
+    public void write(int c)
+    {       
+        captureWriter.write(c);
+        passThroughWriter.write(c);
+    }
+    public void write(String str)
+    {       
+        captureWriter.write(str);
+        passThroughWriter.write(str);
+    }
+    public void write(String str, int off, int len)
+    {       
+        captureWriter.write(str,off,len);
+        passThroughWriter.write(str,off,len);
+    }
+    public void flush() 
+    {
+        captureWriter.flush();
+        passThroughWriter.flush();
+    }    
+    public void close() 
+    {
+        captureWriter.close();
+        passThroughWriter.close();
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/presentation/util/SplitServletOutputStream.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/util/SplitServletOutputStream.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/util/SplitServletOutputStream.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/util/SplitServletOutputStream.java Mon May  1 15:23:02 2006
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package org.apache.roller.presentation.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.servlet.ServletOutputStream;
+
+/**
+ * Extends the base <code>ServletOutputStream</code> class so that
+ * the stream can be captured as it gets written. This is achieved
+ * by overriding the <code>write()</code> methods and outputting
+ * the data to two streams - the original stream and a secondary stream
+ * that is designed to capture the written data.
+ *
+ * @version $Revision: 1.1 $
+ * @author  <a href="mailto:sergek@lokitech.com">Serge Knystautas</a>
+ */
+public class SplitServletOutputStream extends ServletOutputStream {
+    OutputStream captureStream = null;
+    OutputStream passThroughStream = null;
+
+    /**
+     * Constructs a split output stream that both captures and passes through
+     * the servlet response.
+     *
+     * @param captureStream The stream that will be used to capture the data.
+     * @param passThroughStream The pass-through <code>ServletOutputStream</code>
+     * that will write the response to the client as originally intended.
+     */
+    public SplitServletOutputStream(OutputStream captureStream, OutputStream passThroughStream) {
+        this.captureStream = captureStream;
+        this.passThroughStream = passThroughStream;
+    }
+
+    /**
+     * Writes the incoming data to both the output streams.
+     *
+     * @param value The int data to write.
+     * @throws IOException
+     */
+    public void write(int value) throws IOException {
+        captureStream.write(value);
+        passThroughStream.write(value);
+    }
+
+    /**
+     * Writes the incoming data to both the output streams.
+     *
+     * @param value The bytes to write to the streams.
+     * @throws IOException
+     */
+    public void write(byte[] value) throws IOException {
+        captureStream.write(value);
+        passThroughStream.write(value);
+    }
+
+    /**
+     * Writes the incoming data to both the output streams.
+     *
+     * @param b The bytes to write out to the streams.
+     * @param off The offset into the byte data where writing should begin.
+     * @param len The number of bytes to write.
+     * @throws IOException
+     */
+    public void write(byte[] b, int off, int len) throws IOException {
+        captureStream.write(b, off, len);
+        passThroughStream.write(b, off, len);
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/presentation/util/StrutsUtil.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/util/StrutsUtil.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/util/StrutsUtil.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/util/StrutsUtil.java Mon May  1 15:23:02 2006
@@ -0,0 +1,105 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.presentation.util;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.TreeSet;
+
+import org.apache.struts.util.LabelValueBean;
+import org.apache.roller.util.LocaleComparator;
+import org.apache.roller.util.TimeZoneComparator;
+
+public class StrutsUtil
+{
+    public static ArrayList locales;
+    public static ArrayList timeZones;
+    
+    //-----------------------------------------------------------------------
+    /**
+     * LabelValueBeans are Comparable but violate the
+     * equals() part of the TreeSet requirements.
+     * And the html:options tag won't recognize
+     * toString as a property.  So we have to put the
+     * Locales into a TreeSet to sort them, then convert
+     * them to LabelValueBeans to display them.
+     * Glad we only have to do this once.
+     * 
+     * @return List of LabelValueBeans, one for each locale available from the JVM
+     */
+    public static List getLocaleBeans() 
+    {
+        if (locales == null)
+        {
+            locales = new ArrayList();
+            TreeSet locTree = new TreeSet(new LocaleComparator());
+            Locale[] localeArray = Locale.getAvailableLocales();
+            for (int i=0; i<localeArray.length; i++)
+            {
+                locTree.add(localeArray[i]);
+            }
+            java.util.Iterator it = locTree.iterator();
+            while (it.hasNext())
+            {
+                Locale loc = (Locale)it.next();
+                locales.add(new LabelValueBean(
+                   loc.getDisplayName(),
+                   loc.toString()));
+            }
+
+        }
+        return locales;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * html:options tag recognizes "ID" as a property
+     * so we don't have to go through all the rigamarole (sp?)
+     * that we did for Locales.
+     */
+    public static List getTimeZoneBeans() 
+    {
+        if (timeZones == null)
+        {
+            Date today = new Date();
+            timeZones = new ArrayList();
+            TreeSet zoneTree = new TreeSet(new TimeZoneComparator());
+            String[] zoneArray = TimeZone.getAvailableIDs();
+            for (int i=0; i<zoneArray.length; i++)
+            {
+                zoneTree.add((TimeZone)TimeZone.getTimeZone(zoneArray[i]));
+            }
+            java.util.Iterator it = zoneTree.iterator();
+            while (it.hasNext())
+            {
+                StringBuffer sb = new StringBuffer();
+                TimeZone zone = (TimeZone)it.next();
+                sb.append(zone.getDisplayName(zone.inDaylightTime(today), TimeZone.SHORT));
+                sb.append(" - ");
+                sb.append(zone.getID());
+                timeZones.add(new LabelValueBean(
+                   sb.toString(),
+                   zone.getID()));
+            }
+        }
+        return timeZones;
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/presentation/util/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/util/package.html?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/util/package.html (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/util/package.html Mon May  1 15:23:02 2006
@@ -0,0 +1,27 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  The ASF licenses this file to You
+  under the Apache License, Version 2.0 (the "License"); you may not
+  use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.  For additional information regarding
+  copyright in this work, please see the NOTICE file in the top level
+  directory of this distribution.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title></title>
+</head>
+<body>
+Presentation layer utilities.
+
+</body>
+</html>

Added: incubator/roller/trunk/src/org/apache/roller/presentation/velocity/CommentAuthenticator.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/velocity/CommentAuthenticator.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/velocity/CommentAuthenticator.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/velocity/CommentAuthenticator.java Mon May  1 15:23:02 2006
@@ -0,0 +1,56 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.presentation.velocity;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.velocity.context.Context;
+import org.apache.roller.pojos.CommentData;
+
+/**
+ * Interface for comment authentication plugin.
+ * @author David M Johnson
+ */
+public interface CommentAuthenticator
+{
+    /**
+     * Plugin should write out HTML for the form fields and other UI elements
+     * needed inside the Roller comment form. Called when HTML form is being 
+     * displayed by Velocity template (see comments.vm).
+     *
+     * @param context Plugin can access objects in context of calling page.
+     * @param request Plugin can access request parameters
+     * @param response Plugin should write to response
+     */
+    public String getHtml(
+                        Context context,
+                        HttpServletRequest request, 
+                        HttpServletResponse response);
+    /**
+     * Plugin should return true only if comment passes authentication test.
+     * Called when a comment is posted, not called when a comment is previewed.
+     *
+     * @param comment Comment data that was posted 
+     * @param request Plugin can access request parameters
+     * @return True if comment passes authentication test
+     */
+    public boolean authenticate(
+                        CommentData comment,
+                        HttpServletRequest request);
+}

Added: incubator/roller/trunk/src/org/apache/roller/presentation/velocity/CommentServlet.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/velocity/CommentServlet.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/velocity/CommentServlet.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/velocity/CommentServlet.java Mon May  1 15:23:02 2006
@@ -0,0 +1,117 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.presentation.velocity;
+
+import java.io.IOException;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.pojos.WeblogEntryData;
+import org.apache.roller.presentation.RollerRequest;
+
+
+/**
+ * This is the old Roller CommentServlet which used to extend the PageServlet
+ * and do some page rendering.  This was replaced by the new version ...
+ * org.apache.roller.persentation.CommentServlet which does not do any rendering.
+ *
+ * This servlet is left in place to maintain old urls and redirect them to
+ * their proper new location.
+ *
+ * @web.servlet name="CommentsServlet"
+ * @web.servlet-mapping url-pattern="/comments/*"
+ *
+ * @author Allen Gilliland
+ */
+public class CommentServlet extends HttpServlet {
+    
+    private static Log mLogger =
+            LogFactory.getFactory().getInstance(CommentServlet.class);
+    
+    
+    /**
+     * Handle GET requests.
+     *
+     * This method just responds to all GET requests with a 301 redirect 
+     * because these old comment servlet urls are deprecated now.
+     */
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // a GET request means that this client is trying to use this old
+        // comment servlet as a form of permalink for rendering an entry.
+        // we want to discourage this, so we send a 301 response which means
+        // this url has been permanently moved.
+        String forward = request.getContextPath();
+        
+        // calculate the location of the requested permalink
+        RollerRequest rreq = RollerRequest.getRollerRequest(request);
+        
+        // ROL-1102: prevent NPE for bad URLs
+        if (rreq == null) {
+            response.sendError(HttpServletResponse.SC_NOT_FOUND);
+            return;
+        } 
+        WeblogEntryData entry = rreq.getWeblogEntry();
+        if (entry != null) {
+            forward += entry.getPermaLink();
+            
+            // make sure to propogate popup requests
+            if(request.getParameter("popup") != null) {
+                if(forward.indexOf("?") == -1)
+                    forward += "?popup=true";
+                else
+                    forward += "&popup=true";
+            }
+                
+        }        
+        mLogger.debug("forwarding to "+forward);
+        
+        // send an HTTP 301 response
+        response.setStatus(response.SC_MOVED_PERMANENTLY);
+        response.setHeader("Location", forward);
+    }
+
+    
+    /**
+     * Handle POST requests.
+     *
+     * POST requests to this old CommentServlet are simply dispatched to the
+     * new CommentServlet inside our servlet container.  We log these requests
+     * in the log file with a WARN so that site admins can track which users
+     * have hard coded the use of the old comment servlet and hopefully those
+     * users can be contacted about udating their templates.
+     */
+    public void doPost(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        mLogger.warn(request.getHeader("referer")+
+                " is posting to the OLD CommentServlet");
+        
+        // just dispatch to new CommentServlet
+        RequestDispatcher dispatch = request.getRequestDispatcher("/comment");
+        dispatch.forward(request, response);
+    }
+
+}
+

Added: incubator/roller/trunk/src/org/apache/roller/presentation/velocity/ContextLoader.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/velocity/ContextLoader.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/velocity/ContextLoader.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/velocity/ContextLoader.java Mon May  1 15:23:02 2006
@@ -0,0 +1,502 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.presentation.velocity;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.struts.util.RequestUtils;
+import org.apache.velocity.context.Context;
+import org.apache.velocity.tools.view.context.ChainedContext;
+import org.apache.velocity.tools.view.context.ToolboxContext;
+import org.apache.velocity.tools.view.servlet.ServletToolboxManager;
+import org.apache.roller.RollerException;
+import org.apache.roller.config.RollerConfig;
+import org.apache.roller.config.RollerRuntimeConfig;
+import org.apache.roller.model.Roller;
+import org.apache.roller.model.RollerFactory;
+import org.apache.roller.pojos.Template;
+import org.apache.roller.pojos.CommentData;
+import org.apache.roller.pojos.RollerPropertyData;
+import org.apache.roller.pojos.WeblogEntryData;
+import org.apache.roller.pojos.WebsiteData;
+import org.apache.roller.pojos.wrapper.CommentDataWrapper;
+import org.apache.roller.pojos.wrapper.TemplateWrapper;
+import org.apache.roller.pojos.wrapper.WeblogEntryDataWrapper;
+import org.apache.roller.pojos.wrapper.WebsiteDataWrapper;
+import org.apache.roller.presentation.LanguageUtil;
+import org.apache.roller.presentation.RollerContext;
+import org.apache.roller.presentation.RollerRequest;
+import org.apache.roller.presentation.RollerSession;
+import org.apache.roller.presentation.newsfeeds.NewsfeedCache;
+import org.apache.roller.presentation.weblog.formbeans.CommentFormEx;
+import org.apache.roller.util.RegexUtil;
+import org.apache.roller.util.StringUtils;
+import org.apache.roller.util.Utilities;
+
+
+/**
+ * Load Velocity Context with Roller objects, values, and custom plugins.
+ * @author llavandowska
+ * @author David M Johnson
+ */
+public class ContextLoader {
+    
+    private static Log mLogger = LogFactory.getLog(ContextLoader.class);
+    
+    private static final String TOOLBOX_KEY =
+            "org.apache.roller.presentation.velocity.toolbox";
+    
+    private static final String TOOLBOX_MANAGER_KEY =
+            "org.apache.roller.presentation.velocity.toolboxManager";
+    
+    private RollerRequest mRollerReq = null;
+    
+    
+    /**
+     * Setup the a Velocity context by loading it with objects, values, and
+     * RollerPagePlugins needed for Roller page execution.
+     */
+    public static void setupContext(
+            Context ctx, 
+            RollerRequest rreq, 
+            HttpServletResponse response )
+            throws RollerException {
+        
+        mLogger.debug("setupContext( ctx = "+ctx+")");
+        
+        HttpServletRequest request = rreq.getRequest();
+        RollerContext rollerCtx = RollerContext.getRollerContext( );
+        
+        try {
+            // Add page model object to context
+            String pageModelClassName =
+                RollerConfig.getProperty("velocity.pagemodel.classname");
+            Class pageModelClass = Class.forName(pageModelClassName);
+            PageModel pageModel = (PageModel)pageModelClass.newInstance();
+            pageModel.init(rreq);
+            ctx.put("pageModel", pageModel );
+            ctx.put("pages", pageModel.getPages());
+        } catch (Exception e) {
+            throw new RollerException("ERROR creating Page Model",e);
+        }
+        
+        // Add Velocity page helper to context
+        PageHelper pageHelper = new PageHelper(request, response, ctx);
+        Roller roller = RollerFactory.getRoller();
+        ctx.put("pageHelper", pageHelper);
+                
+        // Load standard Roller objects and values into the context
+        WebsiteData website = 
+            loadWeblogValues(ctx, rreq, rollerCtx );
+        loadPathValues(       ctx, rreq, rollerCtx, website );
+        loadRssValues(        ctx, rreq, website );
+        loadUtilityObjects(   ctx, rreq, rollerCtx, website );
+        loadRequestParamKeys( ctx);
+        loadStatusMessage(    ctx, rreq );
+        
+        // If single entry is specified, load comments too
+        if ( rreq.getWeblogEntry() != null ) {
+            loadCommentValues( ctx, rreq, rollerCtx );
+        }
+        
+        // add Velocity Toolbox tools to context
+        loadToolboxContext(request, response, ctx);
+    }
+        
+    /**
+     * Load website object and related objects.
+     */
+    protected static WebsiteData loadWeblogValues(
+            Context ctx, 
+            RollerRequest rreq, 
+            RollerContext rollerCtx )
+            throws RollerException {
+                
+        Roller mRoller = RollerFactory.getRoller();
+        Map props = mRoller.getPropertiesManager().getProperties();
+        
+        WebsiteData weblog = rreq.getWebsite();            
+        if (weblog == null && rreq.getRequest().getParameter("entry") != null) {
+            String handle = rreq.getRequest().getParameter("entry");
+            weblog = RollerFactory.getRoller().getUserManager().getWebsiteByHandle(handle);
+        }
+        if (weblog == null && rreq.getRequest().getAttribute(RollerRequest.OWNING_WEBSITE) != null) {
+            weblog = (WebsiteData)rreq.getRequest().getAttribute(RollerRequest.OWNING_WEBSITE);
+        } 
+        
+        if (weblog != null) {
+            ctx.put("userName",         weblog.getHandle());
+            ctx.put("fullName",         weblog.getName() );
+            ctx.put("emailAddress",     weblog.getEmailAddress() );
+            ctx.put("encodedEmail",     RegexUtil.encode(weblog.getEmailAddress()));
+            ctx.put("obfuscatedEmail",  RegexUtil.obfuscateEmail(weblog.getEmailAddress()));
+            
+            // setup Locale for future rendering
+            ctx.put("locale", weblog.getLocaleInstance());
+            
+            // setup Timezone for future rendering
+            ctx.put("timezone", weblog.getTimeZoneInstance());
+            ctx.put("timeZone", weblog.getTimeZoneInstance());
+        } else {
+            // create dummy website for use in site-wide feeds
+            weblog = new WebsiteData();
+            weblog.setAllowComments(Boolean.FALSE);
+            weblog.setHandle("zzz_none_zzz");
+            weblog.setName(
+                ((RollerPropertyData)props.get("site.name")).getValue());
+            weblog.setDescription(
+                ((RollerPropertyData)props.get("site.description")).getValue());
+            weblog.setEntryDisplayCount(
+                RollerRuntimeConfig.getIntProperty("site.newsfeeds.defaultEntries"));
+            ctx.put("handle",   weblog.getHandle() );
+            ctx.put("userName", weblog.getHandle() );
+            ctx.put("fullName", weblog.getHandle());
+            ctx.put("locale",   Locale.getDefault());
+            ctx.put("timezone", TimeZone.getDefault());
+            ctx.put("timeZone", TimeZone.getDefault());
+            ctx.put("emailAddress",
+                ((RollerPropertyData)props.get("site.adminemail")).getValue());           
+        }
+        ctx.put("website", WebsiteDataWrapper.wrap(weblog) );
+        
+        String siteName = ((RollerPropertyData)props.get("site.name")).getValue();
+        if ("Roller-based Site".equals(siteName)) siteName = "Main";
+        ctx.put("siteName", siteName);
+        
+        String siteShortName = ((RollerPropertyData)props.get("site.shortName")).getValue();
+        ctx.put("siteShortName", siteShortName);
+        
+        // add language of the session (using locale of viewer set by Struts)
+        ctx.put("viewLocale",
+                LanguageUtil.getViewLocale(rreq.getRequest()));
+        mLogger.debug("context viewLocale = "+ctx.get( "viewLocale"));
+               
+        // if there is an "_entry" page, only load it once
+        // but don't do it for dummy website
+        if (weblog != null && !"zzz_none_zzz".equals(weblog.getHandle())) {
+            // alternative display pages - customization
+            Template entryPage = weblog.getPageByName("_entry");
+            if (entryPage != null) {
+                ctx.put("entryPage", TemplateWrapper.wrap(entryPage));
+            }
+            Template descPage = weblog.getPageByName("_desc");
+            if (descPage != null) {
+                ctx.put("descPage", TemplateWrapper.wrap(descPage));
+            }
+        }
+
+        boolean commentsEnabled =
+            RollerRuntimeConfig.getBooleanProperty("users.comments.enabled");
+        boolean trackbacksEnabled =
+            RollerRuntimeConfig.getBooleanProperty("users.trackbacks.enabled");
+        boolean linkbacksEnabled =
+            RollerRuntimeConfig.getBooleanProperty("site.linkbacks.enabled");
+        
+        ctx.put("commentsEnabled",   new Boolean(commentsEnabled) );
+        ctx.put("trackbacksEnabled", new Boolean(trackbacksEnabled) );
+        ctx.put("linkbacksEnabled",  new Boolean(linkbacksEnabled) );
+        
+        return weblog;
+    }
+            
+    /**
+     * Load comments for one weblog entry and related objects.
+     */
+    protected static void loadCommentValues(
+            Context       ctx, 
+            RollerRequest rreq, 
+            RollerContext rollerCtx )
+            throws RollerException {
+        
+        mLogger.debug("Loading comment values");
+        
+        HttpServletRequest request = rreq.getRequest();
+        
+        String escapeHtml =
+            RollerRuntimeConfig.getProperty("users.comments.escapehtml");
+        String autoFormat =
+            RollerRuntimeConfig.getProperty("users.comments.autoformat");
+        ctx.put("isCommentPage",     Boolean.TRUE);
+        ctx.put("escapeHtml",        new Boolean(escapeHtml) );
+        ctx.put("autoformat",        new Boolean(autoFormat) );                
+        
+        // Make sure comment form object is available in context
+        CommentFormEx commentForm =
+                (CommentFormEx) request.getAttribute("commentForm");
+        if ( commentForm == null ) {
+            commentForm = new CommentFormEx();
+            
+            // Set fields to spaces to please Velocity
+            commentForm.setName("");
+            commentForm.setEmail("");
+            commentForm.setUrl("");
+            commentForm.setContent("");
+        }
+        ctx.put("commentForm",commentForm);
+        
+        // Either put a preview comment in to context
+        if ( request.getAttribute("previewComments")!=null ) {
+            ArrayList list = new ArrayList();
+            CommentData cd = new CommentData();
+            commentForm.copyTo(cd, request.getLocale());
+            list.add(CommentDataWrapper.wrap(cd));
+            ctx.put("previewComments",list);
+        }
+        
+        WeblogEntryData entry = rreq.getWeblogEntry();
+        if (entry.getStatus().equals(WeblogEntryData.PUBLISHED)) {
+            ctx.put("entry", WeblogEntryDataWrapper.wrap(entry));
+        }
+    }
+    
+    /**
+     * Load objects needed for RSS and Atom newsfeed generation.
+     */
+    protected static void loadRssValues(
+            Context ctx, 
+            RollerRequest rreq, 
+            WebsiteData website) 
+            throws RollerException {
+        
+        mLogger.debug("Loading rss values");
+        
+        HttpServletRequest request = rreq.getRequest();
+        
+        int entryLength = -1;
+        String sExcerpts = request.getParameter("excerpts");
+        if ( sExcerpts!=null && sExcerpts.equalsIgnoreCase("true")) {
+            entryLength = 150;
+        }
+        ctx.put("entryLength",  new Integer(entryLength));
+        
+        // Display same number of entries in feed as displayed on page
+        int entryCount = website.getEntryDisplayCount();
+        
+        // But don't exceed installation-wide maxEntries settings
+        int maxEntries = 
+            RollerRuntimeConfig.getIntProperty("site.newsfeeds.maxEntries");
+        int defaultEntries = 
+            RollerRuntimeConfig.getIntProperty("site.newsfeeds.defaultEntries");
+        if (entryCount < 1) entryCount = defaultEntries;
+        if (entryCount > maxEntries) entryCount = maxEntries;
+        ctx.put("entryCount",  new Integer(entryCount));
+        
+        String catname = null;
+        String catPath = null;
+        if ( rreq.getWeblogCategory() != null ) {
+            catname = rreq.getWeblogCategory().getName();
+            catPath = rreq.getWeblogCategory().getPath();
+        }
+        ctx.put("catname", (catname!=null) ? catname : "");
+        ctx.put("catPath", (catPath != null) ? catPath : "");
+        ctx.put("updateTime", request.getAttribute("updateTime"));
+        ctx.put("now", new Date());
+    }
+    
+    /**
+     * Load useful utility objects for string and date formatting.
+     */
+    protected static void loadUtilityObjects(
+            Context ctx, 
+            RollerRequest rreq,                                             
+            RollerContext rollerCtx, 
+            WebsiteData website)
+            throws RollerException {
+        
+        mLogger.debug("Loading utility objects");
+        
+        // date formatter for macro's set this up with the Locale to make 
+        // sure we can reuse it with other patterns in the macro's
+        Locale viewLocale = (Locale) ctx.get("viewLocale");
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd", viewLocale);
+        if (website != null) {
+            sdf.setTimeZone(website.getTimeZoneInstance());
+        }
+        // add formatter to context
+        ctx.put("dateFormatter", sdf );
+        
+        // Note: in the macro's, the formats are taken from the ResourceBundles.
+        // Only the plainFormat is specified here, because it is used to render
+        // the Entry Day link.
+        ctx.put("plainFormat", "yyyyMMdd");
+        
+        ctx.put("page",            TemplateWrapper.wrap(rreq.getPage()));
+        ctx.put("utilities",       new Utilities() );
+        ctx.put("stringUtils",     new StringUtils() );
+        ctx.put("rollerVersion",   rollerCtx.getRollerVersion() );
+        ctx.put("rollerBuildTime", rollerCtx.getRollerBuildTime() );
+        ctx.put("rollerBuildUser", rollerCtx.getRollerBuildUser() );
+        ctx.put("newsfeedCache",   NewsfeedCache.getInstance() );
+        
+        ctx.put("requestParameters", rreq.getRequest().getParameterMap());
+    }
+        
+    /**
+     * Load URL paths useful in page templates.
+     */
+    protected static void loadPathValues(
+            Context ctx,  RollerRequest rreq, 
+            RollerContext rollerCtx, 
+            WebsiteData   website)
+            throws RollerException {
+        
+        mLogger.debug("Loading path values");
+        
+        HttpServletRequest request = rreq.getRequest();
+        String url = null;
+        if (website != null  && !"zzz_none_zzz".equals(website.getHandle())) {
+            url = Utilities.escapeHTML(
+                      rollerCtx.getAbsoluteContextUrl(request) 
+                          + "/page/" + website.getHandle());
+        } else {
+            url= Utilities.escapeHTML(rollerCtx.getAbsoluteContextUrl(request));
+        }
+        ctx.put("websiteURL", url);
+        ctx.put("baseURL",    rollerCtx.getContextUrl( request ) );
+        ctx.put("absBaseURL", rollerCtx.getAbsoluteContextUrl( request ) );
+        ctx.put("ctxPath",    request.getContextPath() );
+        ctx.put("uploadPath", ContextLoader.figureResourcePath( rreq ) );
+        
+        try {
+            URL absUrl = RequestUtils.absoluteURL(request, "/");
+            ctx.put("host", absUrl.getHost());
+        } catch (MalformedURLException e) {
+            throw new RollerException(e);
+        }
+    }
+      
+    /**
+     * Determine URL path to Roller upload directory.
+     */
+    private static String figureResourcePath(RollerRequest rreq) {
+        
+        String uploadurl = null;
+        try {
+            uploadurl = RollerFactory.getRoller().getFileManager().getUploadUrl();
+        } catch(Exception e) {}
+        
+        return uploadurl;
+    }
+    
+    /**
+     * If there is an ERROR or STATUS message in the session,
+     * place it into the Context for rendering later.
+     */
+    private static void loadStatusMessage(Context ctx, RollerRequest rreq) {
+        
+        mLogger.debug("Loading status message");
+        
+        HttpSession session = rreq.getRequest().getSession(false);
+        String msg = null;
+        if (session != null)
+            msg = (String)session.getAttribute(RollerSession.ERROR_MESSAGE);
+        if (msg != null) {
+            ctx.put("errorMessage", msg);
+            session.removeAttribute(RollerSession.ERROR_MESSAGE);
+        }
+        
+        if (session != null)
+            msg = (String)session.getAttribute(RollerSession.STATUS_MESSAGE);
+        if (msg != null) {
+            ctx.put("statusMessage", msg);
+            session.removeAttribute(RollerSession.STATUS_MESSAGE);
+        }
+    }
+        
+    protected static void loadRequestParamKeys(Context ctx) {
+        
+        mLogger.debug("Loading request param keys");
+        
+        // Since Velocity *requires* accessor methods, these values from
+        // RollerRequest are not available to it, put them into the context
+        ctx.put("USERNAME_KEY",           RollerRequest.USERNAME_KEY);
+        ctx.put("WEBSITEID_KEY",          RollerRequest.WEBSITEID_KEY);
+        ctx.put("FOLDERID_KEY",           RollerRequest.FOLDERID_KEY);
+        ctx.put("NEWSFEEDID_KEY",         RollerRequest.NEWSFEEDID_KEY);
+        ctx.put("PAGEID_KEY",             RollerRequest.PAGEID_KEY);
+        ctx.put("PAGELINK_KEY",           RollerRequest.PAGELINK_KEY);
+        ctx.put("ANCHOR_KEY",             RollerRequest.ANCHOR_KEY);
+        ctx.put("EXCERPTS_KEY",           RollerRequest.EXCERPTS_KEY);
+        ctx.put("BOOKMARKID_KEY",         RollerRequest.BOOKMARKID_KEY);
+        ctx.put("REFERERID_KEY",          RollerRequest.REFERERID_KEY);
+        ctx.put("WEBLOGENTRYID_KEY",      RollerRequest.WEBLOGENTRYID_KEY);
+        ctx.put("WEBLOGCATEGORYNAME_KEY", RollerRequest.WEBLOGCATEGORYNAME_KEY);
+        ctx.put("WEBLOGCATEGORYID_KEY",   RollerRequest.WEBLOGENTRIES_KEY);
+        ctx.put("WEBLOGENTRIES_KEY",      RollerRequest.WEBLOGENTRIES_KEY);
+        ctx.put("WEBLOGDAY_KEY",          RollerRequest.WEBLOGDAY_KEY);
+        ctx.put("WEBLOGCOMMENTID_KEY",    RollerRequest.WEBLOGCOMMENTID_KEY);
+    }
+    
+    public static ToolboxContext loadToolboxContext(
+            HttpServletRequest request,                                                     
+            HttpServletResponse response,                                                    
+            Context ctx) {
+        
+        mLogger.debug("Loading toolbox context");
+        
+        ServletContext servletContext = RollerContext.getServletContext();
+        
+        // get the toolbox manager
+        ServletToolboxManager toolboxManager =
+                (ServletToolboxManager)servletContext.getAttribute(TOOLBOX_MANAGER_KEY);
+        if (toolboxManager==null) {
+            String file = RollerConfig.getProperty("velocity.toolbox.file");
+            mLogger.debug("Creating new toolboxContext using config-file: "+file);
+            toolboxManager = ServletToolboxManager.getInstance(servletContext, file);
+            servletContext.setAttribute(TOOLBOX_MANAGER_KEY, toolboxManager);
+        }
+        
+        // load a toolbox context
+        ChainedContext chainedContext =
+                new ChainedContext(ctx, request, response, servletContext);
+        ToolboxContext toolboxContext =
+                toolboxManager.getToolboxContext(chainedContext);
+        
+        if (toolboxContext != null) {
+            // add MessageTool to VelocityContext
+            ctx.put("text", toolboxContext.internalGet("text"));
+            
+            /*
+            Object[] keys = toolboxContext.internalGetKeys();
+            for (int i=0;i<keys.length;i++) {
+                String key = (String)keys[i];
+                System.out.println("key = "+key);
+                Object tool = toolboxContext.get(key);
+                System.out.println("tool = "+tool);
+                ctx.put(key, tool);
+            }
+             */
+        }
+        
+        return toolboxContext;
+    }
+    
+}

Added: incubator/roller/trunk/src/org/apache/roller/presentation/velocity/DefaultCommentAuthenticator.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/velocity/DefaultCommentAuthenticator.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/velocity/DefaultCommentAuthenticator.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/velocity/DefaultCommentAuthenticator.java Mon May  1 15:23:02 2006
@@ -0,0 +1,46 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.presentation.velocity;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.velocity.context.Context;
+import org.apache.roller.pojos.CommentData;
+
+/**
+ * Default authenticator does nothing, always returns true.
+ * @author David M Johnson
+ */
+public class DefaultCommentAuthenticator implements CommentAuthenticator 
+{   
+    public String getHtml(
+                        Context context,
+                        HttpServletRequest request, 
+                        HttpServletResponse response)
+    {
+        return "<!-- custom authenticator would go here -->";
+    }
+    
+    public boolean authenticate(
+                        CommentData comment,
+                        HttpServletRequest request) 
+    {
+        return true;
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/presentation/velocity/ExportRss.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/presentation/velocity/ExportRss.java?rev=398712&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/presentation/velocity/ExportRss.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/presentation/velocity/ExportRss.java Mon May  1 15:23:02 2006
@@ -0,0 +1,247 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+*  contributor license agreements.  The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.  For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.roller.presentation.velocity;
+
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.roller.RollerException;
+import org.apache.roller.model.RollerFactory;
+import org.apache.roller.pojos.UserData;
+import org.apache.roller.pojos.WebsiteData;
+import org.apache.roller.presentation.RollerContext;
+import org.apache.roller.util.RegexUtil;
+import org.apache.roller.util.StringUtils;
+import org.apache.roller.util.Utilities;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.TimeZone;
+
+/**
+ * Does a lot of the same work as ContextLoader in preparing
+ * a VelocityContext for parsing.  However, it is ignorant of
+ * any HttpServletRequest related features, and so has 
+ * considerably trimmed down information.
+ * 
+ * Created on Mar 25, 2004
+ * @author lance.lavandowska
+ */
+public class ExportRss
+{
+    private VelocityEngine ve = null;
+    private VelocityContext ctx = null;
+    private UserData user = null;
+    private boolean exportAtom;
+    
+    private static final String RSS_TEMPLATE = "org/roller/presentation/velocity/export_rss.vm";
+    private static final String ATOM_TEMPLATE = "org/roller/presentation/velocity/export_atom.vm";
+    
+    public ExportRss(WebsiteData website) throws Exception
+    {
+        Properties props = new Properties();
+        props.load(RollerContext.getServletContext().
+                   getResourceAsStream("/WEB-INF/velocity.properties"));
+        ve = new VelocityEngine();
+        ve.info("*******************************************");
+        ve.info("Initializing VelocityEngine for ExportRss");
+        ve.init( props );
+        ve.info("Done initializing VelocityEngine for ExportRss");
+        ve.info("************************************************");
+        
+        ctx = new VelocityContext();
+        
+        RollerContext rollerCtx = RollerContext.getRollerContext();
+        
+        loadPageHelper();
+        
+        loadDates(website);
+        
+        loadWebsiteInfo(rollerCtx, website);
+
+        loadTheRest(rollerCtx);
+    }
+    
+    public void setExportAtom(boolean atom)
+    {
+        exportAtom = atom;
+    }
+    
+    /**
+     * Export the given entries using export_rss.vm.
+     * 
+     * @param entries
+     * @throws ResourceNotFoundException
+     * @throws ParseErrorException
+     * @throws Exception
+     */
+    public void exportEntries(Collection entries, String fileName) throws ResourceNotFoundException, ParseErrorException, Exception 
+    {
+        ctx.put("entries", entries);
+        
+        String templateFile = RSS_TEMPLATE;
+        if (exportAtom) templateFile = ATOM_TEMPLATE;
+        Template template = ve.getTemplate( templateFile, "utf-8" );
+        StringWriter sw = new StringWriter();
+        template.merge(ctx, sw);
+        
+        writeResultsToFile((String)ctx.get("uploadPath"), sw, fileName);
+    }
+
+    /**
+     * @param sw
+     */
+    private void writeResultsToFile(String filePath, StringWriter sw, String fileName) 
+        throws RollerException, IOException
+    {
+        filePath += "/" + user.getUserName();
+        new java.io.File( filePath ).mkdirs(); // create dir path on drive
+        
+        filePath += "/" + fileName;
+        
+        File outputFile = new java.io.File( filePath );
+        FileOutputStream out = null;
+        try
+        {
+            //outputFile.createNewFile();
+            out = new FileOutputStream( outputFile );
+            out.write( sw.toString().getBytes() );
+            out.flush();
+        }
+        catch ( FileNotFoundException e )
+        {
+            throw new RollerException( "Unable to write to: " + outputFile.getAbsolutePath(), e );
+        }
+        finally
+        {
+            try
+            {
+                if ( out != null )
+                {
+                    out.close();
+                }
+            }
+            catch ( java.io.IOException ioe )
+            {
+                System.err.println( "ExportRss unable to close OutputStream" );
+            }
+        }
+    }
+
+    /**
+     * Load miscellaneous values into the Context.
+     * @param rollerCtx
+     */
+    private void loadTheRest(RollerContext rollerCtx)
+    {
+        ctx.put("utilities",       new Utilities() );
+        ctx.put("stringUtils",     new StringUtils() );        
+        ctx.put("entryLength",     new Integer(-1));
+    }
+
+    /**
+     * Load information pertaining to the Website and
+     * its associated User.
+     * @param rollerCtx
+     */
+    private void loadWebsiteInfo(RollerContext rollerCtx, WebsiteData website)
+    {
+        ctx.put("website",       website);
+        ctx.put("userName",      user.getUserName() );
+        ctx.put("fullName",      user.getFullName() );
+        ctx.put("emailAddress",  user.getEmailAddress() );
+
+        ctx.put("encodedEmail",  RegexUtil.encode(user.getEmailAddress()));
+        ctx.put("obfuscatedEmail",  RegexUtil.obfuscateEmail(user.getEmailAddress()));
+
+        
+        // custom figureResourcePath() due to no "request" object
+        StringBuffer sb = new StringBuffer();
+        String uploadDir = null;
+        try {
+            uploadDir = RollerFactory.getRoller().getFileManager().getUploadDir();
+        } catch(Exception e) {}
+
+        ctx.put("uploadPath", uploadDir);
+    }
+
+    /**
+     * Load time-related information.
+     * @param website
+     */
+    private void loadDates(WebsiteData website)
+    {
+        try
+        {
+            // Add current time and last updated times to context
+            Date updateTime = RollerFactory.getRoller().getWeblogManager()
+                .getWeblogLastPublishTime(website, null);                        
+            ctx.put("updateTime",   updateTime);
+        }
+        catch (RollerException e)
+        {                       
+            ctx.put("updateTime",   new Date());
+        }
+        ctx.put("now",              new Date());
+        
+        // setup Locale for future rendering
+        Locale locale = website.getLocaleInstance();
+        ctx.put("locale", locale);
+        
+        // setup Timezone for future rendering
+        ctx.put("timezone", website.getTimeZoneInstance());
+
+        // date formats need to be run through the Localized
+        // SimpleDateFormat and pulled back out as localized patterns.
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd", locale);  
+        sdf.setTimeZone( (TimeZone)ctx.get("timezone") );    
+        ctx.put("plainFormat",     sdf.toLocalizedPattern());
+        
+        sdf.applyPattern("EEEE MMMM dd, yyyy");
+        ctx.put("toStringFormat",  sdf.toLocalizedPattern());
+        
+        sdf.applyPattern("MMM dd yyyy, hh:mm:ss a z");
+        ctx.put("timestampFormat", sdf.toLocalizedPattern());
+        
+        ctx.put("dateFormatter", sdf );
+    }
+    /**
+     * Create a PageHelper.  Note that will have no values
+     * necessary in parsing a Web request (such as /page) -
+     * it is only useful for the restricted export_rss.vm
+     * and has no PagePlugins either.  We want the exported
+     * Entry.text to be the raw values.
+     */
+    private void loadPageHelper() throws RollerException
+    {
+        // Add Velocity page helper to context
+        PageHelper pageHelper = new PageHelper(null, null, ctx);
+        // set no PagePlugins - we *do not* want to render them.
+        ctx.put("pageHelper", pageHelper );
+    }
+}