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/08 18:06:46 UTC

svn commit: r189602 [22/50] - 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/ docs/ docs/images/ docs/installguide/ docs/installguide/old/ docs/userguide/ docs/userguide/images/ docs/userguide/old/ metadata/ metadata/database/ metadata/database/hibernate/ metadata/xdoclet/ personal/ personal/eclipse/ personal/testing/ src/ src/org/ src/org/roller/ src/org/roller/business/ src/org/roller/business/hibernate/ src/org/roller/business/utils/ src/org/roller/model/ src/org/roller/pojos/ src/org/roller/presentation/ src/org/roller/presentation/atom/ 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/tags/ src/org/roller/presentation/tags/calendar/ src/org/roller/presentation/tags/menu/ 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/search/ src/org/roller/presentation/weblog/search/operations/ 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/ tests/ tests/org/ tests/org/roller/ tests/org/roller/business/ tests/org/roller/model/ tests/org/roller/persistence/ tests/org/roller/presentation/ tests/org/roller/presentation/atom/ tests/org/roller/presentation/bookmarks/ 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/xmlrpc/ tests/org/roller/util/ tools/ tools/buildtime/ tools/buildtime/mockrunner-0.2.6/ tools/buildtime/mockrunner-0.2.6/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.1/ tools/struts-1.1/lib/ web/ web/WEB-INF/ web/WEB-INF/classes/ web/WEB-INF/classes/flavors/ web/WEB-INF/classes/themes/ web/bookmarks/ web/images/ web/images/editor/ web/images/midas/ web/images/preview/ web/images/smileys/ 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/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/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/velocity/PageHelper.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/PageHelper.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/PageHelper.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/PageHelper.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,578 @@
+package org.roller.presentation.velocity;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.struts.Globals;
+import org.apache.struts.util.RequestUtils;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.context.Context;
+import org.roller.RollerException;
+import org.roller.pojos.RefererData;
+import org.roller.pojos.WeblogEntryData;
+import org.roller.presentation.LanguageUtil;
+import org.roller.presentation.RollerRequest;
+import org.roller.presentation.tags.calendar.CalendarModel;
+import org.roller.presentation.tags.calendar.CalendarTag;
+import org.roller.presentation.tags.menu.EditorNavigationBarTag;
+import org.roller.presentation.tags.menu.MenuTag;
+import org.roller.presentation.weblog.tags.BigWeblogCalendarModel;
+import org.roller.presentation.weblog.tags.WeblogCalendarModel;
+import org.roller.util.StringUtils;
+
+import java.io.StringWriter;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Vector;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.PageContext;
+
+/**
+ * Provides assistance to VelociMacros, filling in where Velocity falls.
+ * 
+ * @author llavandowska
+ * @author David M Johnson
+ * 
+ */
+public class PageHelper
+{
+	private static Log mLogger = 
+	   LogFactory.getFactory().getInstance(PageHelper.class);
+    
+    private Context              mVelocityContext = null;
+	private PageContext          mPageContext = null;
+    private HttpServletResponse  mResponse = null;	   
+	private RollerRequest        mRollerReq = null;
+	private String               mUsername = null;
+    private Collection           mPagePlugins = new ArrayList();
+    private boolean              mSkipFlag = false;
+	
+    //------------------------------------------------------------------------
+    
+    /**
+     * Initialize VelocityHelper, setting the variables it will be hiding from
+     * the Velocimacros.
+     */
+    public PageHelper(
+            RollerRequest rreq, HttpServletResponse response, Context ctx)
+    {
+        mVelocityContext = ctx;
+        mRollerReq = rreq;
+        mResponse = response;
+        if (rreq != null) 
+        {
+            mPageContext = rreq.getPageContext();
+            
+            if ( rreq.getUser() != null )
+            {       
+                mUsername = rreq.getUser().getUserName();       
+            }
+        }
+        
+        if (mVelocityContext == null) mVelocityContext = new VelocityContext();
+    }
+    
+    //------------------------------------------------------------------------
+    
+    /**
+     * Initialized VelocityHelper without a Velocity Context.
+     */
+    public PageHelper(RollerRequest rreq, HttpServletResponse response)
+    {
+        this(rreq, response, null);
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Return a PageHelper with a new VelocityContext.
+     */
+    public static PageHelper createPageHelper(
+        HttpServletRequest request, HttpServletResponse response)
+    {
+        Context ctx = (Context)(new VelocityContext());
+        RollerRequest rreq = RollerRequest.getRollerRequest(request);
+        PageHelper pageHelper = new PageHelper(rreq, response, ctx);
+        pageHelper.initializePlugins(ContextLoader.getPagePlugins());
+
+        return pageHelper;
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * Create individual instances of the PagePlugins for use by this PageHelper.
+     */
+    protected void initializePlugins(Collection pluginClasses) 
+    {
+        Iterator it = pluginClasses.iterator();
+        while (it.hasNext()) 
+        {
+            try
+            {
+                PagePlugin plugin = (PagePlugin)it.next();
+                plugin.init(mRollerReq, mVelocityContext);
+                mPagePlugins.add(plugin);
+            }
+            catch (RollerException e)
+            {
+                mLogger.warn("Unable to init() PagePlugin: ", e    );
+            }
+        }
+    }
+
+    //------------------------------------------------------------------------
+    /**
+     * This is a quasi-hack: there are places we don't want to render the
+     * ReadMore Plugin in particular (I cannot think of other plugins
+     * which warrant this treatment).  The "skip flag" will be made
+     * available to the Plugin if it wants to check to see if it should
+     * be skipped.
+     */
+    public void setSkipFlag(boolean skip) 
+    {
+        mSkipFlag = skip;
+    }
+    
+    //------------------------------------------------------------------------
+    
+	/**
+	 * Another stupid helper method to make up for the shortcomings of Velocity.
+	 * @return HashMap
+	 */
+	public Hashtable addParam(String key, String value, Hashtable map)
+	{
+		if (map == null) map = new Hashtable();
+		if (key != null && value != null)
+			map.put(key, value);
+		return map;
+	}
+		
+    //------------------------------------------------------------------------
+    
+	/**
+	 * Evaluates the String as a Velocimacro, returning the results.
+	 * 
+	 * @param str String
+	 * @return String
+	 */
+	public String evaluateString(String str)
+	{
+        if (mVelocityContext == null) return str;
+        
+		StringWriter sw = new StringWriter();
+		try
+		{
+			Velocity.evaluate( mVelocityContext, sw, "evalStr", str );
+			return sw.toString();
+		}
+		catch (Exception e)
+		{
+			mLogger.warn("VelocityHelper.evaluateString()", e);
+		}
+		return "";
+	}
+   
+	/** Build the URL for editing an WeblogEntry **/
+	public String getEntryEditUrl(WeblogEntryData entry)
+	{
+		Hashtable params = new Hashtable();
+		params.put( RollerRequest.WEBLOGENTRYID_KEY, entry.getId());
+		params.put( RollerRequest.ANCHOR_KEY,        entry.getAnchor());
+        if (mUsername != null)
+        {    
+            params.put( RollerRequest.USERNAME_KEY,  mUsername);
+        }
+		try
+		{
+			return RequestUtils.computeURL( mPageContext,
+				"weblogEdit", null, null, null, params, null, false);
+		}
+		catch (MalformedURLException mue)
+		{
+			mLogger.warn("RollerRequest.editEntryUrl exception: ", mue);
+		}
+		return 
+           mRollerReq.getRequest().getContextPath() + "weblog.do?method=edit";
+	}
+	
+	//-------------------------------------------------------------------------
+	public String getToggleLinkbackDisplayHTML(RefererData referer)
+	{
+		String ret = "";
+
+		String userName = mRollerReq.getUser().getUserName();
+
+		String link = null;
+		try
+		{
+			if ( mRollerReq.isUserAuthorizedToEdit() )
+			{
+				Hashtable params = new Hashtable();
+				params.put( RollerRequest.REFERERID_KEY, referer.getId());
+				params.put( RollerRequest.USERNAME_KEY, userName);
+				link = RequestUtils.computeURL( mPageContext,
+					"toggleLinkback", null, null, null, params,null,false);
+                    
+				StringBuffer sb = new StringBuffer();
+				sb.append("[<a href=\"");
+				sb.append(link);
+				if ( referer.getVisible().booleanValue() )
+				{
+					sb.append("\">Visible</a>] ");
+				}
+				else
+				{
+					sb.append("\">Hidden</a>] ");
+				}
+				ret = sb.toString();
+			}
+		}
+		catch (Exception e)
+		{
+		   // should never happen, but if it does:
+		   mLogger.error("ERROR creating toggle-linkback URL",e);
+		}
+        
+		return ret;
+	}
+	
+    //------------------------------------------------------------------------
+    
+    public boolean isUserAuthorizedToEdit()
+    {
+        try
+        {
+            return mRollerReq.isUserAuthorizedToEdit();
+        }
+        catch (Exception e)
+        {
+            mLogger.warn("PageHelper.isUserAuthorizedToEdit)", e);
+        }
+        return false;
+    }
+    
+    //------------------------------------------------------------------------
+	public void setContentType( String type )
+    {
+        mResponse.setContentType(type);
+    }
+
+	//------------------------------------------------------------------------
+	/** 
+	 * Display big weblog calendar, well suited for an archive page.
+	 * @return HTML for calendar.
+	 */
+	public String showBigWeblogCalendar()
+	{
+		return showWeblogCalendar(true, null);
+	}
+	    
+    //------------------------------------------------------------------------
+    
+    /** 
+     * Call hybrid EditorNavBarTag to render editor navbar.
+     * @param vertical True for vertical navbar.
+     * @return String HTML for navbar.
+     */
+    public String showEditorNavBar(boolean vertical)
+    {
+        EditorNavigationBarTag editorTag = new EditorNavigationBarTag();
+        editorTag.setPageContext(mPageContext);
+        if ( vertical )
+        {
+            editorTag.setView("/navbar-vertical.vm");
+        }
+        else
+        {
+            editorTag.setView("/navbar-horizontal.vm");
+        }
+        editorTag.setModel("editor-menu.xml");
+        return editorTag.emit();
+    }
+    
+    //------------------------------------------------------------------------
+    
+    /** 
+     * Call hybrid EditorNavBarTag to render editor navbar.
+     * @param model Name of XML file in WEB-INF that contains XML for menu.
+     * @param template Name of Velocity template in classpath to display menu.
+     * @return String HTML for menu.
+     */
+    public String showMenu(String model, String template)
+    {
+        MenuTag menuTag = new MenuTag();
+        menuTag.setPageContext(mPageContext);
+        menuTag.setModel(model);
+        menuTag.setView(template);
+        return menuTag.emit();
+    }
+    
+	//------------------------------------------------- WeblogCalendar methods
+
+	/** 
+	 * Display weblog calendar.
+	 * @return HTML for calendar.
+	 */
+	public String showWeblogCalendar()
+	{
+		return showWeblogCalendar(false, null);
+	}
+
+	//------------------------------------------------------------------------
+	/** 
+	 * Weblog calendar display implementation.
+	 * @param big Show big archive style calendar.
+	 * @return HTML for calendar.
+	 */
+	public String showWeblogCalendar( boolean big, String cat )
+	{
+        if (PageModel.VELOCITY_NULL.equals(cat)) cat = null;
+		String ret = null;
+		try
+		{
+			HttpServletRequest request =
+				(HttpServletRequest)mPageContext.getRequest();
+			HttpServletResponse response =
+				(HttpServletResponse)mPageContext.getResponse();
+
+			String selfUrl = null;
+			String pageLink = mRollerReq.getPageLink();
+			if ( pageLink != null )
+			{
+				selfUrl = 
+                    request.getContextPath()+"/page/"+mUsername+"/"+pageLink;
+			}
+			else
+			{
+				selfUrl = request.getContextPath()+"/page/"+mUsername;
+			}
+
+			// setup weblog calendar model
+			CalendarModel model = null;
+			if ( big )
+			{
+				model = new BigWeblogCalendarModel(
+				           mRollerReq, response, selfUrl, cat);
+			}
+			else
+			{
+				model = new WeblogCalendarModel(
+				            mRollerReq, response, selfUrl, cat);
+			}
+
+			// save model in JSP page context so CalendarTag can find it
+			mPageContext.setAttribute("calendarModel",model);
+
+			// Create and setup calendar tag
+			CalendarTag calTag = new CalendarTag();
+			calTag.setPageContext(mPageContext);
+			calTag.setName("calendar");
+			calTag.setModel("calendarModel");
+            //calTag.setLocale(mRollerReq.getWebsite().getLocaleInstance());
+			calTag.setLocale(LanguageUtil.getViewLocale(request));
+            calTag.setTimeZone(mRollerReq.getWebsite().getTimeZoneInstance());
+			if ( big )
+			{
+				calTag.setClassSuffix("Big");
+			}
+			ret = calTag.emit();
+		}
+		catch (Exception e)
+		{
+			mLogger.error("Unexpected exception",e);
+		}
+		return ret;
+	}
+    
+    //------------------------------------------------------------------------
+    
+	/**
+	 * Convenience method, contrived helper for Velocity.
+	 * @param useIds
+	 * @param isAction
+	 * @param path
+	 * @param val1
+	 * @param val2
+	 * @return String
+	 */
+	public String strutsUrlHelper( boolean useIds, boolean isAction, 
+		String path, String val1, String val2)
+	{
+		Hashtable params = new Hashtable();
+		return strutsUrlHelper( useIds, isAction, path, val1, val2, params);
+	}
+    
+    //------------------------------------------------------------------------
+    
+	/**
+	 * Very contrived helper method for Velocimacros generating Struts links.
+	 * This is really only of use to the showNavBar macro.
+	 * @param useIds
+	 * @param isAction
+	 * @param path
+	 * @param val1
+	 * @param val2
+	 * @return String
+	 */
+	public String strutsUrlHelper( boolean useIds, boolean isAction, 
+		String path, String val1, String val2, Hashtable params)
+	{
+		if (useIds)
+		{
+			if (mRollerReq.getFolder() != null) 
+			{
+				params.put(RollerRequest.FOLDERID_KEY,
+				mRollerReq.getFolder().getId());
+			} 
+			if (mUsername != null)
+			{
+				params.put(RollerRequest.USERNAME_KEY, mUsername);
+			}
+		}
+    	
+		if (StringUtils.isNotEmpty(val1) && !val1.equals("null"))
+		{
+			params.clear();
+			params.put("rmk", val1);
+			params.put("rmik", val2);
+		}
+    	
+		String returnUrl = "";
+		try
+		{
+			if (isAction)
+			{
+				returnUrl = RequestUtils.computeURL( mPageContext,
+								path, null, null, null, params, null, false);
+			}
+			else
+			{
+				returnUrl = RequestUtils.computeURL( mPageContext,
+								null, path, null, null, params, null, false);
+			}
+		}
+		catch (MalformedURLException mue)
+		{
+			mLogger.warn("RollerRequest.strutsUrlHelper exception: ", mue);
+			returnUrl = "<span class=\"error\">ERROR generating link</span>";
+		}
+		return returnUrl;
+	}
+    
+    /**
+     * Pass the String through any PagePlugins that have been
+     * assigned to the PageHelper.
+     * 
+     * @param str
+     * @return
+     */
+    public String renderPlugins(String str)
+    {
+        if (mPagePlugins != null)
+        {
+            Iterator iter = mPagePlugins.iterator();
+            while (iter.hasNext())
+            {
+                str = ((PagePlugin)iter.next()).render(str);
+            }
+        }
+        return str;
+    }
+    
+    /**
+     * Pass the String through any PagePlugins that have been
+     * assigned to the PageHelper, as selected by the Entry.
+     * 
+     * @param str
+     * @return
+     */
+    public String renderPlugins(WeblogEntryData entry)
+    {
+        // we have to make a copy to temporarily store the
+        // changes wrought by Plugins (otherwise they might
+        // end up persisted!).
+        WeblogEntryData copy = new WeblogEntryData(entry);
+        
+        if (mPagePlugins != null)
+        {
+            List entryPlugins = copy.getPluginsList();
+            // if no Entry plugins, don't bother looping.
+            if (entryPlugins != null && !entryPlugins.isEmpty())
+            {    
+                // need to do this to tell ReadMore not to do its job
+                // if we are in the "view one Entry" page.
+                if (mRollerReq == null || mRollerReq.getWeblogEntry() != null)
+                {
+                    mSkipFlag = true;
+                }
+                
+                // now loop over mPagePlugins, matching
+                // against Entry plugins (by name):
+                // where a match is found render Plugin.
+                Iterator iter = mPagePlugins.iterator();
+                PagePlugin pagePlugin = null;
+                while (iter.hasNext())
+                {
+                    pagePlugin = (PagePlugin)iter.next();
+                    if (entryPlugins.contains(pagePlugin.getName()))
+                    {
+                        copy.setText((pagePlugin).render(copy, mSkipFlag));
+                    }
+                }
+            }
+        }
+        return copy.getText();
+    }
+    
+    /**
+     * This method returns an array of Locales for each supported
+     * language available, with the exeception of the language of the 
+     * current locale, if that language is supported.
+     * 
+     * So, if English and Dutch are supported, and the current Locale is Dutch,
+     * only English is returned. If the current Locale is Spanish, both English and Dutch are
+     * returned.
+     *    
+     * @return
+     */
+	public Locale[] getSupportedLanguages()
+	{
+		Locale currentLocale =
+			(Locale) mPageContext.getSession().getAttribute(Globals.LOCALE_KEY);
+		if (currentLocale==null) 
+		{
+			currentLocale = mPageContext.getRequest().getLocale();
+		}
+			
+		Vector supportedLanguages =
+			LanguageUtil.getSupportedLanguages(mPageContext.getServletContext());
+		if (supportedLanguages==null) {
+			return null;
+		}
+		
+		// filter out the current selected language
+		// and convert to locale
+		Vector result = new Vector();
+		for(int i=0; i<supportedLanguages.size(); i++) {
+			String l = (String) supportedLanguages.get(i);
+			if (currentLocale==null || !currentLocale.getLanguage().equals(l)) {
+				result.add(new Locale(l));
+			}
+		}
+		return (Locale[]) result.toArray(new Locale[result.size()]);
+	}
+
+	/**
+	 * @return relative URL to page, starting with /username
+	 */	
+	public String getPathInfo() 
+	{
+		return mRollerReq.getPathInfo();
+	}
+}

Added: incubator/roller/trunk/src/org/roller/presentation/velocity/PageModel.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/PageModel.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/PageModel.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/PageModel.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,685 @@
+package org.roller.presentation.velocity;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.roller.RollerException;
+import org.roller.model.BookmarkManager;
+import org.roller.model.RefererManager;
+import org.roller.model.UserManager;
+import org.roller.model.WeblogManager;
+import org.roller.pojos.FolderData;
+import org.roller.pojos.PageData;
+import org.roller.pojos.RefererData;
+import org.roller.pojos.WeblogCategoryData;
+import org.roller.pojos.WeblogEntryData;
+import org.roller.pojos.WebsiteData;
+import org.roller.presentation.RollerRequest;
+import org.roller.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provides Roller page templates with access to Roller domain model objects.
+ *  
+ * @author llavandowska
+ * @author David M Johnson
+ */
+public class PageModel
+{
+    public final static String VELOCITY_NULL = "nil";
+    
+	private static Log mLogger = 
+	   LogFactory.getFactory().getInstance(PageModel.class);
+	
+	private BookmarkManager      mBookmarkMgr = null;
+    private WeblogManager        mWeblogMgr = null;
+    private UserManager          mUserMgr = null;
+    private RefererManager       mRefererMgr = null;
+
+	private Map				     mCategories = new HashMap();
+	private HashMap              mPageMap = new HashMap();
+	private RollerRequest        mRollerReq = null;
+	private String               mUsername = null;
+    
+    private WeblogEntryData      mNextEntry = null;
+    private WeblogEntryData      mPreviousEntry = null;
+
+    private WeblogEntryData      mLastEntry = null;
+
+    private WeblogEntryData mFirstEntry;
+    	
+    //------------------------------------------------------------------------
+    
+	/**
+	 * Initialize PageModel and allow PageModel to initialized VelocityContext.
+	 * @param rreq
+	 * @param ctx
+	 */
+	public PageModel(RollerRequest rreq)
+	{
+		mRollerReq = rreq;
+        
+        if ( rreq.getUser() != null )
+        {
+            mUsername = rreq.getUser().getUserName();
+        }
+        
+		try
+		{
+			mBookmarkMgr = rreq.getRoller().getBookmarkManager();
+			mRefererMgr  = rreq.getRoller().getRefererManager();
+			mUserMgr     = rreq.getRoller().getUserManager();
+			mWeblogMgr   = rreq.getRoller().getWeblogManager();
+			
+			/** 
+			 * Preload what we can for encapsulation.  What we cannot preload we
+			 * will use the Managers later to fetch.
+			 */
+            if ( mUsername != null )
+            {
+                // Get the pages, put into context & load map
+                List pages = mUserMgr.getPages(mRollerReq.getWebsite());
+                Iterator pageIter = pages.iterator();
+                while (pageIter.hasNext())
+                {
+                    PageData page = (PageData) pageIter.next();
+                    mPageMap.put(page.getName(), page);
+                }
+            }
+            
+		}
+		catch (RollerException e)
+		{
+			mLogger.error("PageModel Roller get*Manager Exception", e);
+		}
+	}
+    
+    //------------------------------------------------------------------------
+    
+    /** Encapsulates folder.getBookmarks() & sorting */
+    public Collection getBookmarks(FolderData folder)
+    {
+        Collection bookmarks = folder.getBookmarks();
+        //Collections.sort( bookmarks, new BookmarkComparator() );
+        return bookmarks;
+    }
+    
+    //------------------------------------------------------------------------
+    
+    /** Get top level bookmark folders. */
+    public Collection getTopLevelFolders()
+    {
+        Collection tops = null;
+        try
+        {
+         tops= mBookmarkMgr.getRootFolder(
+                    mUserMgr.getWebsite(mUsername)).getFolders();
+        }
+        catch (RollerException e)
+        {
+            tops = new ArrayList();
+        }
+        return tops;
+    }
+    
+    //------------------------------------------------------------------------
+    
+	/** Encapsulates WeblogManager.getComments().size() */
+	public int getCommentCount(String entryId)
+	{
+		try
+		{
+			return mWeblogMgr.getComments( entryId ).size();
+		}
+		catch (RollerException e)
+		{
+			mLogger.error("PageModel getCommentCount()", e);
+		}
+		return 0;
+	}
+    
+    //------------------------------------------------------------------------
+    
+    /** Get comments for weblog entry specified by request */
+    public List getComments( WeblogEntryData entry )
+    {
+        try
+        {
+            return mWeblogMgr.getComments( entry.getId() );
+        }
+        catch (RollerException e)
+        {
+            mLogger.error("PageModel getComments()", e);
+        }
+        return new ArrayList();
+    }
+    
+    //------------------------------------------------------------------------
+    
+	/** Encapsulates RefererManager */
+	public int getDayHits()
+	{
+		try
+		{
+			return mRefererMgr.getDayHits(mRollerReq.getWebsite());
+		}
+		catch (RollerException e)
+		{
+			mLogger.error("PageModel getDayHits()", e);
+		}
+		return 0;
+	}
+	
+    //------------------------------------------------------------------------
+    
+	/** Encapsulates BookmarkManager.getFolder() */
+	public FolderData getFolder(String folderPath)
+	{
+		try
+		{
+			return mBookmarkMgr.getFolder(
+                mUserMgr.getWebsite(mUsername), folderPath);
+		}
+		catch (RollerException e)
+		{
+			mLogger.error("PageModel getFolder()", e);
+		}
+		return null;
+	}
+		
+    //------------------------------------------------------------------------
+    
+    /** Encapsulates UserManager.getPageByName() */
+    public PageData getUsersPageByName(WebsiteData website, String pageName)
+    {
+        PageData page = null;
+        try
+        {
+            if (website == null) 
+                throw new NullPointerException("website is null");
+                
+            if (pageName == null) 
+                throw new NullPointerException("pageName is null");
+                
+            page = mUserMgr.getPageByName(website, pageName);
+        }
+        catch (NullPointerException npe)
+        {
+            mLogger.warn(npe.getMessage());
+        }
+        catch (RollerException e)
+        {
+            mLogger.error("ERROR getting user's page by name: " + e.getMessage(),e);
+        }
+        return page;
+    }
+    
+    //------------------------------------------------------------------------
+    
+    /** Encapsulates UserManager.getPageByName() */
+    public PageData getPageByName(String pageName)
+    {
+        return (PageData)mPageMap.get(pageName);
+    }
+    
+    //------------------------------------------------------------------------
+    
+    /** Encapsulates UserManager.getPageByName() */
+    public String getPageIdByName(String pageName)
+    {
+        PageData pd = (PageData)mPageMap.get(pageName);
+        if ( pd != null ) 
+        {
+            return pd.getId();
+        }
+        else
+        {
+            return null;
+        }
+    }
+    
+    //------------------------------------------------------------------------
+    
+    /**
+     * Get collection of user pages.
+     * @return
+     */
+    public Object getPages()
+    {
+        return mPageMap.values();
+    }
+    
+    //------------------------------------------------------------------------
+    
+    /** 
+     * Returns a map of up to 100 recent weblog entries for the user and day 
+     * specified in the request, filtered by the category specified by the 
+     * request, limited by the 'maxEntries' argument, and sorted by reverse 
+     * chronological order.
+     * 
+     * <p>This method will look for a category name in the following places
+     * and in the following order:</p>
+     * <ul>
+     * <li>The request via RollerRequest.getWeblogCategory().</li>
+     * <li>The categoryName argument to this method.</li>
+     * <li>The default category for the website specified by the request via 
+     *     RollerRequest.getWebsite().getDefaultCategory().</li>
+     * <li></li>
+     * </ul>
+     * 
+     * @param maxEntries Maximum number of entries to be returned.
+     * @param categoryName Only return entries from this category and it's 
+     *         subcategories. If null, returns all categories of entry.
+     * @return Map of Lists of WeblogEntryData, keyed by 8-char date strings.
+     */
+    public Map getRecentWeblogEntries(int maxEntries, String categoryName)
+    {
+        if (VELOCITY_NULL.equals(categoryName)) categoryName = null;
+        Map ret = new HashMap();
+        try
+        {
+            Date dayParam = mRollerReq.getDate(true);
+            
+            // If request specifies a category, then use that
+            String catParam = null;
+            if (mRollerReq.getWeblogCategory() != null)
+            {
+                catParam = mRollerReq.getWeblogCategory().getPath();
+            }
+            else if (categoryName != null)
+            {
+                // use category argument instead
+                catParam = categoryName;
+            }
+            else if (mRollerReq.getWebsite() != null) // MAIN
+            {
+                catParam = mRollerReq.getWebsite().getDefaultCategory().getPath();
+                if (catParam.equals("/"))
+                {
+                    catParam = null;
+                }
+            }
+            
+            if (maxEntries > 100) maxEntries = 100;
+            
+            ret = mRollerReq.getRoller().getWeblogManager().getWeblogEntryObjectMap(
+                            mRollerReq.getWebsite(),  
+                            null,                     // startDate
+                            dayParam,                 // endDate
+                            catParam,                 // catName
+                            WeblogManager.PUB_ONLY,   // status
+                            new Integer(maxEntries)); // maxEntries
+            
+            setFirstAndLastEntries( ret );
+        }
+        catch (Exception e)
+        {
+            mLogger.error("PageModel getRecentWeblogEntries()", e);
+        }
+        return ret;
+    }
+    
+    //------------------------------------------------------------------------
+    
+    /**
+     * Pull the last WeblogEntryData out of the Map.
+     * @param ret
+     */
+    private void setFirstAndLastEntries(Map days)
+    {
+        int numDays = days.keySet().size();
+        if (numDays > 0) // there is at least one day
+        {
+            // get first entry in map
+            Object[] keys = days.keySet().toArray(new Object[numDays]);
+            List vals = (List)days.get( keys[0] );
+            int valSize = vals.size();
+            if (valSize > 0) 
+            {
+                mFirstEntry = (WeblogEntryData)vals.get(0);
+            }
+            
+            // get last entry in map
+            vals = (List)days.get( keys[--numDays] );
+            valSize = vals.size();
+            if (valSize > 0)
+            {
+                mLastEntry = (WeblogEntryData)vals.get(--valSize);
+            }
+        }
+    }
+
+    //------------------------------------------------------------------------
+    
+    /** 
+     * Returns list of recent weblog entries for the user and day specified in 
+     * the request, filtered by the category specified by the request, limited 
+     * by the 'maxEntries' argument, and sorted by reverse chronological order.
+     * 
+     * <p>This method will look for a category name in the same places and 
+     * same order as does the getRecentWeblogEntries() method.</p>
+     * 
+     * @param maxEntries   Maximum number of entries to be returned.
+     * @param categoryName Only return entries from this category and it's 
+     *         subcategories. If null, returns all categories of entry.
+     * @return List of WeblogEntryData objects in revese chronological order.
+     */
+    public List getRecentWeblogEntriesArray(int maxEntries, String categoryName)
+    {
+        if (VELOCITY_NULL.equals(categoryName)) categoryName = null;
+        List ret = new ArrayList();
+        try
+        {
+            Date day = mRollerReq.getDate();
+            if (day == null) day = new Date();
+            
+            // If request specifies a category, then use that
+            String catParam = null;
+            if (mRollerReq.getWeblogCategory() != null)
+            {
+                catParam = mRollerReq.getWeblogCategory().getPath();
+            }
+            else if (categoryName != null)
+            {
+                // use category argument instead
+                catParam = categoryName;
+            }
+            else if (mRollerReq.getWebsite() != null) // MAIN
+            {
+                catParam = mRollerReq.getWebsite().getDefaultCategory().getPath();
+                if (catParam.equals("/"))
+                {
+                    catParam = null;
+                }
+            }
+            WeblogManager mgr = mRollerReq.getRoller().getWeblogManager();
+            
+            //ret = mgr.getRecentWeblogEntriesArray( 
+                //name, day, catParam, maxEntries, true );
+            
+            ret = mgr.getWeblogEntries(
+                            mRollerReq.getWebsite(), 
+                            null,                    // startDate
+                            day,                      // endDate
+                            catParam,                 // catName
+                            WeblogManager.PUB_ONLY,   // status
+                            new Integer(maxEntries)); // maxEntries
+        }
+        catch (Exception e)
+        {
+            mLogger.error("PageModel getRecentWeblogEntries()", e);
+        }
+        return ret;
+    }   
+	
+    //------------------------------------------------------------------------
+    
+	/** Encapsulates RefererManager **/
+	public List getReferers(String date)
+	{
+        date = date.trim();
+		ArrayList referers = new ArrayList();
+		try
+		{
+            List refs = 
+                mRefererMgr.getReferersToDate(mRollerReq.getWebsite(), date);
+            
+            for (Iterator rdItr = refs.iterator(); rdItr.hasNext();) {
+				RefererData referer = (RefererData) rdItr.next();
+				String title =referer.getTitle();
+				String excerpt = referer.getExcerpt();
+				if (   StringUtils.isNotEmpty(title) 
+					&& StringUtils.isNotEmpty(excerpt) )
+				{
+					if (   referer.getVisible().booleanValue() 
+						|| this.mRollerReq.isUserAuthorizedToEdit() )
+					{ 
+						referers.add(referer);
+					}
+				}
+			}
+            
+		}
+		catch (Exception e)
+		{
+			mLogger.error("PageModel getReferersToDate() fails with URL" 
+                            + mRollerReq.getRequestURL(), e);
+		}
+		return referers;
+	}	
+    
+    //------------------------------------------------------------------------
+    
+	/** Encapsulates RefererManager */
+	public List getTodaysReferers()
+	{
+		List referers = null;
+		try
+		{
+            referers = mRefererMgr.getTodaysReferers(mRollerReq.getWebsite());
+         
+		}
+		catch (RollerException e)
+		{
+			mLogger.error("PageModel getTodaysReferers()", e);
+		}
+		return (referers == null ? Collections.EMPTY_LIST : referers);
+	}
+	
+    //------------------------------------------------------------------------
+    
+	/** Encapsulates RefererManager */
+	public int getTotalHits()
+	{
+		try
+		{
+			return mRefererMgr.getTotalHits(mRollerReq.getWebsite());
+		}
+		catch (RollerException e)
+		{
+			mLogger.error("PageModel getTotalHits()", e);
+		}
+		return 0;
+	}
+    
+    //------------------------------------------------------------------------
+    /**
+     * Returns most recent update time of collection of weblog entries.
+     * @param weblogEntries Collection of weblog entries.
+     * @return Most recent update time.
+     */
+    public static Date getUpdateTime( ArrayList weblogEntries )
+    {
+        Date updateTime = null;
+        Iterator iter = weblogEntries.iterator();
+        while (iter.hasNext())
+        {
+            WeblogEntryData wd = (WeblogEntryData)iter.next();
+            if ( updateTime == null )
+            {
+                updateTime = wd.getUpdateTime();
+            }
+            //else if ( updateTime.compareTo(wd.getUpdateTime()) < 0 )
+            else if (updateTime.before( wd.getUpdateTime() ))
+            {
+                updateTime = wd.getUpdateTime();
+            }
+        }
+        return updateTime;
+    }
+
+    //------------------------------------------------------------------------
+    
+	/** Encapsulates WeblogManager.getWeblogCategories() */
+	public List getWeblogCategories(String categoryName)
+	{
+        List ret = null;
+        if (VELOCITY_NULL.equals(categoryName)) categoryName = null;
+        
+        // Make sure we have not already fetched this category.
+        if (categoryName != null)
+        {
+            ret = (List)mCategories.get(categoryName);
+        }
+        
+        if (null == ret) 
+        {
+            try 
+            {
+                WeblogCategoryData category = null;                
+                if (categoryName != null)
+                {
+                    category = mWeblogMgr.getWeblogCategoryByPath(
+                                  mRollerReq.getWebsite(), null, categoryName);                    
+                }
+                else 
+                {
+                    category = mRollerReq.getWebsite().getDefaultCategory();
+                }
+                ret = category.getWeblogCategories();
+                mCategories.put(categoryName, ret);
+            }
+            catch (RollerException e) 
+            {
+                mLogger.error(e);
+            }
+        }       
+        return ret;
+	}
+	
+    //------------------------------------------------------------------------
+    
+    /** Encapsulates RollerRequest.getWeblogEntry() */
+    public WeblogEntryData getWeblogEntry()
+    {
+        return mRollerReq.getWeblogEntry();
+    }
+    
+    //------------------------------------------------------------------------
+    
+    /**
+     * Get the next occurring Entry.
+     */
+    public WeblogEntryData getNextEntry()
+    {
+        WeblogEntryData currentEntry = getWeblogEntry();
+        if (mFirstEntry != null) currentEntry = mFirstEntry;
+        if (mNextEntry == null && currentEntry != null) 
+        {
+            String catName = null;
+            if (mRollerReq.getWeblogCategory() != null)
+            {
+                catName = mRollerReq.getWeblogCategory().getName();
+            }
+            try
+            {
+                mNextEntry = mWeblogMgr.getNextEntry(currentEntry, catName);
+                
+                // make sure that mNextEntry is not published to future
+                if (mNextEntry != null && 
+                    mNextEntry.getPubTime().after( new Date() ))
+                {
+                    mNextEntry = null;
+                }
+            }
+            catch (RollerException e)
+            {
+                mLogger.error("PageModel.getNextEntry)", e);
+            }
+        }
+        return mNextEntry;
+    }
+
+    //------------------------------------------------------------------------
+    
+    /**
+     * Get the previous occurring Entry.
+     */
+    public WeblogEntryData getPreviousEntry()
+    {
+        WeblogEntryData currentEntry = getWeblogEntry();
+        if (mLastEntry != null) currentEntry = mLastEntry;
+        if (mPreviousEntry == null && currentEntry != null )
+        {
+            String catName = null;
+            if (mRollerReq.getWeblogCategory() != null)
+            {
+                catName = mRollerReq.getWeblogCategory().getName();
+            }
+            try
+            {
+                mPreviousEntry = mWeblogMgr.getPreviousEntry(currentEntry, catName);
+            }
+            catch (RollerException e)
+            {
+                mLogger.error("PageModel.getPreviousEntry)", e);
+            }            
+        }
+        return mPreviousEntry;
+    }
+
+    //------------------------------------------------------------------------
+    
+    public boolean isUserAuthorizedToEdit()
+    {
+        try
+        {
+            return mRollerReq.isUserAuthorizedToEdit();
+        }
+        catch (Exception e)
+        {
+            mLogger.warn("PageModel.isUserAuthorizedToEdit)", e);
+        }
+        return false;
+    }
+    
+    //------------------------------------------------------------------------
+    
+    public String getRequestParameter(String key)
+    {
+        return mRollerReq.getRequest().getParameter(key);
+    }
+    
+    //------------------------------------------------------------------------
+    
+    public FolderData getFolderByPath(String path)
+    {
+        try
+        {
+            return mBookmarkMgr.getFolderByPath(
+                mUserMgr.getWebsite(mUsername), null, path);
+        }
+        catch (RollerException e)
+        {
+            mLogger.error(e);
+            return null;
+        }
+    }
+
+    /**
+     * Facade for WeblogManager.getRecentComments().
+     * Get the most recent (chronologically) posted Comments
+     * for this website, limited to maxCount.  
+     * @return List of Comments.
+     */
+    public List getRecentComments(int maxCount)
+    {
+        try
+        {
+            return mWeblogMgr.getRecentComments(mRollerReq.getWebsite(), maxCount);
+        }
+        catch (RollerException e)
+        {
+            mLogger.error(e);
+            return new ArrayList();
+        }
+    }
+    
+}

Added: incubator/roller/trunk/src/org/roller/presentation/velocity/PagePlugin.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/PagePlugin.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/PagePlugin.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/PagePlugin.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,84 @@
+/*
+ * Created on May 26, 2003
+ */
+package org.roller.presentation.velocity;
+
+import org.apache.velocity.context.Context;
+import org.roller.RollerException;
+import org.roller.pojos.WeblogEntryData;
+import org.roller.presentation.RollerRequest;
+
+/**
+ * Interface for a Roller WeblogEntry Plugin.  Implementors of this
+ * class are expected to operate on the text field of a WeblogEntryData
+ * object.  Existing implementations autogenerate links from Bookmarks (BookmarkPlugin),
+ * obfuscate email addresses (EmailObfuscator), truncate an Entry at 250
+ * characters and add a Read More... link (ReadMorePlugin), and transform
+ * 'simple markup' according to several schemes (JSPWiki, Radeox, Textile).
+ * See the "contrib" directory for these implementations.
+ * 
+ * @author David M Johnson
+ */
+public interface PagePlugin
+{    
+    public String name = "PagePlugin";
+    
+    /** 
+     * Plugins can this as an opportunity to add any required objects
+     * to the RollerRequest and the VelocityContext, or to initialize
+     * any internal values reachable from RollerRequest.
+     * 
+     * @param rreq Plugins may need to access RollerRequest.
+     * @param ctx Plugins may place objects into the Velocity Context.
+     */    
+    public void init(RollerRequest rreq, Context ctx) throws RollerException;
+
+	/**
+     * Apply plugin to content of specified WeblogEntry.  The WeblogEntryData
+     * is actually a copy of the real thing, so that changes made via
+     * entry.setText() are not persisted.  Notice this; no changes made
+     * to the entry will be persisted.
+     * Some Plugins are only suited to rendering during Page display 
+     * (not when generating RSS or Trackback content or in the 
+     * Entry Preview) - ReadMorePlugin is an example of such a case.  
+     * If the skipFlag is set to 'true' it merely returns the 
+     * unadorned contents of entry.getText().
+     * 
+     * @param entry WeblogEntry to which plugin should be applied.
+     * @param skipFlag Should processing be skipped.
+     * @return Results of applying plugin to entry.
+	 */
+	public String render(WeblogEntryData entry, boolean skipFlag);
+    
+    /**
+     * Apply plugin to content of specified String.  Some plugins
+     * may require interaction with an Entry to do its job (such
+     * as the BookmarkPlugin) and will simply return the String 
+     * that was passed in.
+     * 
+     * @param str String to which plugin should be applied.
+     * @return Results of applying plugin to string.
+     */
+    public String render(String str);
+    
+    /**
+     * Must implement toString(), returning the human-friendly
+     * name of this Plugin.  This is what users will see.
+     * @return The human-friendly name of this Plugin.
+     */
+    public String toString();
+    
+    /**
+     * Returns the human-friendly name of this Plugin.
+     * This is what users will see.
+     * @return The human-friendly name of this Plugin.
+     */
+    public String getName();
+    
+    /**
+     * Briefly describes the function of the Plugin. May
+     * contain HTML.
+     * @return A brief description of the Plugin.
+     */
+    public String getDescription();
+}

Added: incubator/roller/trunk/src/org/roller/presentation/velocity/PageServlet.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/PageServlet.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/PageServlet.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/PageServlet.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,138 @@
+
+package org.roller.presentation.velocity;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.velocity.Template;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.context.Context;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+
+import java.util.Properties;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * Extend RollerServlet to load proper resource loader for page execution.
+ * 
+ * @web.servlet name="PageServlet" load-on-startup="0"
+ * @web.servlet-init-param name="properties" value="/WEB-INF/velocity.properties"
+ *  
+ * @web.servlet-mapping url-pattern="/page/*"
+ * @web.servlet-mapping url-pattern="/comments/*"
+ */ 
+
+public class PageServlet extends BasePageServlet
+{
+    private static Log mLogger = 
+        LogFactory.getFactory().getInstance(PageServlet.class);
+
+	/** We are overriding the default Runtime Velocity
+	 * singleton to gain control over the initialization
+	 * and so that the PreviewResourceLoader is not set
+	 * for the PageServlet.
+	 */
+	VelocityEngine ve = null;
+	
+    public Template handleRequest( HttpServletRequest request,
+                                    HttpServletResponse response, 
+                                    Context ctx ) throws Exception
+    {
+		return super.handleRequest(request, response, ctx);
+    }
+	
+	/**
+	 * Override initVelocity() so we can man-handle the list of
+	 * resource loaders and remove "preview" if it is present.
+	 * @see org.apache.velocity.servlet.VelocityServlet#initVelocity(ServletConfig)
+	 */
+	protected void initVelocity( ServletConfig config )
+		 throws ServletException
+	{
+		try
+		{
+			/*
+			 *  call the overridable method to allow the 
+			 *  derived classes a shot at altering the configuration
+			 *  before initializing Runtime
+			 */
+			Properties props = loadConfiguration( config );
+			
+			// remove "preview," from the beginning of the 
+			// resource.loader list
+			String resourceLoaders = (String)props.get("resource.loader");
+			if (resourceLoaders != null &&
+				resourceLoaders.indexOf("preview") > -1)
+			{
+				int begin = resourceLoaders.indexOf("preview");
+				int length = "preview".length() + 1;
+				String tempStr = "";
+				if (begin > 0)
+				{
+					tempStr = resourceLoaders.substring(0,begin);
+				}
+				resourceLoaders = tempStr + resourceLoaders.substring(begin+length);
+
+				//System.out.println("PageServlet RESOURCELOADERS: " + resourceLoaders);
+				props.put("resource.loader", resourceLoaders);
+			}
+			
+			// remove all trace of the PreviewResourceLoader
+			props.remove("preview.resource.loader.public.name");
+			props.remove("preview.resource.loader.description");
+			props.remove("preview.resource.loader.class");
+			props.remove("preview.resource.loader.cache");
+			props.remove("preview.resource.loader.modificationCheckInterval");
+			
+			/** set custom logging file */
+			props.setProperty( "runtime.log", "page_servlet.log" );
+			
+			// make user WebappResourceLoader has what it needs
+			WebappResourceLoader.setServletContext( getServletContext() );
+			
+            if (mLogger.isDebugEnabled())
+            {
+                mLogger.debug("VelocityEngine props: " + props.toString());
+            }
+            
+			ve = new VelocityEngine();
+			ve.info("*******************************************");
+			ve.info("Initializing VelocityEngine for PageServlet");
+			ve.init( props );
+			ve.info("Done initializing VelocityEngine for PageServlet");
+			ve.info("************************************************");
+		}
+		catch( Exception e )
+		{
+			String msg = "Error initializing Velocity: " + e.toString();
+            mLogger.error(msg, e);
+			throw new ServletException(msg, e);
+		}   
+	}
+
+	/**
+	 * Override the parent getTemplate( String name ) method.
+	 * @see org.apache.velocity.servlet.VelocityServlet#getTemplate(String, String)
+	 */
+	public Template getTemplate( String name )
+		throws ResourceNotFoundException, ParseErrorException, Exception
+	{
+		return ve.getTemplate( name );
+	}
+
+	/**
+	 * Override the parent getTemplate(String name, String encoding) method.
+	 * @see org.apache.velocity.servlet.VelocityServlet#getTemplate(String, String)
+	 */
+	public Template getTemplate( String name, String encoding )
+		throws ResourceNotFoundException, ParseErrorException, Exception
+	{
+		return ve.getTemplate( name, encoding );
+	}
+}
+

Added: incubator/roller/trunk/src/org/roller/presentation/velocity/PreviewResourceLoader.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/PreviewResourceLoader.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/PreviewResourceLoader.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/PreviewResourceLoader.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,164 @@
+package org.roller.presentation.velocity;
+
+import org.apache.commons.collections.ExtendedProperties;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.Runtime;
+import org.apache.velocity.runtime.resource.Resource;
+import org.apache.velocity.runtime.resource.loader.ResourceLoader;
+import org.roller.util.LRUCache2;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * This is a simple template file loader that loads 
+ * "preview" templates
+ * from a HashMap instance instead of plain files.
+ *
+ * Ideally this would use some smarter caching
+ * (re-implement with Commons-Cache?) so that the
+ * templates put here could expire in case the user
+ * forgot/neglected to clear their "work area".
+ *
+ * There is no configuration.
+ *
+ * @author <a href="mailto:lance@brainopolis.com">Lance Lavandowska</a>
+ * @version $Id: PreviewResourceLoader.java,v 1.16 2004/08/05 02:16:16 snoopdave Exp $
+*/
+public class PreviewResourceLoader extends ResourceLoader
+{
+    private static Log mLogger = 
+        LogFactory.getFactory().getInstance(PreviewResourceLoader.class);
+
+	private static String cacheName = "PreviewCache";
+	
+	/**
+	 * number of objects to store in the cache, older objects
+	 * are pushed out (acts like LRU) if maxObjects reached.
+	 * @TODO Add configuration for this maxObject in preview cache
+	 */
+	private static int  maxObjects = 50;
+
+	/**
+	 * time objects are in cache before they expire - default one hour.
+	 * Configuration parameter is in seconds which we convert
+	 * to milliseconds.
+	 * @TODO Add configuration for preview cache timeout
+	 */
+	private static int  time = 60 * 60 * 1000;
+    
+    private static LRUCache2 mCache = new LRUCache2(maxObjects, time);
+	
+    public void init( ExtendedProperties configuration)
+    {
+    }
+
+    public boolean isSourceModified(Resource resource)
+    {
+        return true;
+    }
+
+    public long getLastModified(Resource resource)
+    {
+        return 0;
+    }
+
+    /**
+     * Get an InputStream so that the Runtime can build a
+     * template with it.
+     *
+     *  @param name name of template
+     *  @return InputStream containing template
+    */
+    public InputStream getResourceStream( String name )
+    throws ResourceNotFoundException
+    {
+        if (name == null || name.length() == 0)
+        {
+            throw new ResourceNotFoundException(
+                "Need to specify a template name!");
+        }
+
+        if (mLogger.isDebugEnabled())
+        {
+		    mLogger.debug("PreviewResourceLoader.getResourceStream(" + name + ")");
+        }
+        
+        try
+        {
+			String template = PreviewResourceLoader.getTemplate(name);
+			if (template != null && mLogger.isDebugEnabled())
+			{
+                mLogger.debug("PreviewResourceLoader found resource " + name);
+		    }
+            return new ByteArrayInputStream( template.getBytes() );
+        }
+        catch (NullPointerException npe)
+        {
+        	// to be expected if resource is not in cache
+        	throw new ResourceNotFoundException("Resource not found in PreviewResourceLoader");
+        }
+        catch (Exception e)
+        {
+            String msg = "PreviewResourceLoader Error: " +
+                "problem trying to load resource " + name + ": " + e.getMessage();
+            if (mLogger.isDebugEnabled()) 
+            {
+                mLogger.debug( msg);
+            }
+            Runtime.error(msg );
+            throw new ResourceNotFoundException (msg);
+        }
+    }
+		
+    /**
+     * Set the temporary Template into memory.
+     */
+    public static void setTemplate(String id, String template, String username)
+    {
+        if (mLogger.isDebugEnabled())
+        {
+            mLogger.debug("PreviewResourceLoader.setTemplate(" 
+    			+ id + ", template)");
+        
+        }
+		mCache.put(id, template);
+    }
+    
+    /**
+     * Get the temporary Template from the Map.
+     */    
+    public static String getTemplate(String id)
+    {
+        if (mLogger.isDebugEnabled())
+        {
+            mLogger.debug("PreviewResourceLoader.getTemplate(" 
+    			+ id + ")");
+        }        
+    	    return (String) mCache.get( id );
+    }
+    
+    /**
+     * Remove the temporary Template from the Map.
+     */    
+    public static void clearTemplate(String id)
+    {
+        if (mLogger.isDebugEnabled())
+        {
+            mLogger.debug("PreviewResourceLoader.clearTemplate(" + id + ")");
+        }
+		mCache.purge(new String[] {id});
+    }
+    
+    /**
+     * Clear all templates for this user.
+     * @param username
+     */
+    public static void clearAllTemplates(String username)
+    {
+        // TODO: add support for 'groups' to LRUCache2
+        mCache.purge();
+    }
+}

Added: incubator/roller/trunk/src/org/roller/presentation/velocity/PreviewServlet.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/PreviewServlet.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/PreviewServlet.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/PreviewServlet.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,26 @@
+
+package org.roller.presentation.velocity;
+
+import org.apache.velocity.Template;
+import org.apache.velocity.context.Context;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Extend RollerServlet to load proper resource loader for page execution.
+ * 
+ * @web.servlet name="PreviewServlet" load-on-startup="1"
+ * @web.servlet-init-param name="properties" value="/WEB-INF/velocity.properties" 
+ * @web.servlet-mapping url-pattern="/preview/*"
+ */ 
+public class PreviewServlet extends BasePageServlet
+{
+    public Template handleRequest( HttpServletRequest request,
+                                    HttpServletResponse response, 
+                                    Context ctx ) throws Exception
+    {
+        return super.handleRequest(request, response, ctx);
+    }
+}
+

Added: incubator/roller/trunk/src/org/roller/presentation/velocity/RollerResourceLoader.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/RollerResourceLoader.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/RollerResourceLoader.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/RollerResourceLoader.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,136 @@
+package org.roller.presentation.velocity;
+
+import org.apache.commons.collections.ExtendedProperties;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.resource.Resource;
+import org.apache.velocity.runtime.resource.loader.ResourceLoader;
+import org.roller.RollerException;
+import org.roller.model.Roller;
+import org.roller.pojos.PageData;
+import org.roller.presentation.RollerContext;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * This is a simple template file loader that loads templates
+ * from the Roller instance instead of plain files.
+ *
+ * RollerResourceLoader makes use of RollerFactory.
+ *
+ * @author <a href="mailto:lance@brainopolis.com">Lance Lavandowska</a>
+ * @version $Id: RollerResourceLoader.java,v 1.8 2004/06/19 02:15:54 lavandowska Exp $
+*/
+public class RollerResourceLoader extends ResourceLoader
+{
+    private static Log mLogger = 
+        LogFactory.getFactory().getInstance(RollerResourceLoader.class);
+        
+    public void init( ExtendedProperties configuration)
+    {
+        if (mLogger.isDebugEnabled())
+        {
+		    mLogger.debug(configuration);
+        }
+    }
+    
+    /**
+     * The web-app startup timing may be tricky.  In the case that roller is
+     * null (which means that RollerContext may not have had a chance to call
+     * RollerFactory yet) ask RollerContext for Roller because it has the
+     * information necessary for RollerFactory to do its job.
+     * @return Roller
+     */
+    private Roller getRoller()
+    {
+    	return RollerContext.getRoller( null );
+    }
+
+    public boolean isSourceModified(Resource resource)
+    {
+        return (resource.getLastModified() !=
+            readLastModified(resource, "checking timestamp"));
+    }
+
+    public long getLastModified(Resource resource)
+    {
+        return readLastModified(resource, "getting timestamp");
+    }
+
+    /**
+     * Get an InputStream so that the Runtime can build a
+     * template with it.
+     *
+     *  @param name name of template
+     *  @return InputStream containing template
+    */
+    public InputStream getResourceStream( String name )
+    throws ResourceNotFoundException
+    {
+        if (name == null || name.length() == 0)
+        {
+            throw new ResourceNotFoundException ("Need to specify a template name!");
+        }
+
+        try
+        {
+            PageData page = getPage( name );
+            if (page == null)
+            {
+            	throw new ResourceNotFoundException(
+					"RollerResourceLoader: page \"" + 
+					name + "\" not found");
+            }
+            return new ByteArrayInputStream( page.getTemplate().getBytes() );
+        }
+        catch (RollerException re)
+        {
+             String msg = "RollerResourceLoader Error: " +
+                "database problem trying to load resource " + name;
+            mLogger.error( msg, re );
+            throw new ResourceNotFoundException (msg);
+        }
+    }
+
+    /**
+     *  Fetches the last modification time of the resource
+     *
+     *  @param resource Resource object we are finding timestamp of
+     *  @param i_operation string for logging, indicating caller's intention
+     *
+     *  @return timestamp as long
+     */
+    private long readLastModified(Resource resource, String i_operation)
+    {
+        /*
+         *  get the template name from the resource
+        */
+        String name = resource.getName();
+        try
+        {
+            PageData page = getPage( name );
+            
+            if (mLogger.isDebugEnabled())
+            {
+                mLogger.debug(name + ": resource=" + resource.getLastModified() + 
+							    " vs. page=" + page.getUpdateTime().getTime());
+            }
+            return page.getUpdateTime().getTime();
+        }
+        catch (RollerException re)
+        {
+            mLogger.error( "Error " + i_operation, re );
+        }
+        return 0;
+    }
+
+    public PageData getPage(String id) throws RollerException
+    {
+    	if (getRoller() == null) throw new RollerException(
+			"RollerResourceLoader.getRoller() returned NULL");
+        return getRoller().getUserManager().retrievePage(id); //retrievePageReadOnly( id );
+    }
+
+}

Added: incubator/roller/trunk/src/org/roller/presentation/velocity/SearchServlet.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/SearchServlet.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/SearchServlet.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/SearchServlet.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,416 @@
+package org.roller.presentation.velocity;
+
+import org.apache.commons.collections.comparators.ReverseComparator;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.search.Hits;
+import org.apache.velocity.Template;
+import org.apache.velocity.context.Context;
+import org.roller.RollerException;
+import org.roller.model.UserManager;
+import org.roller.model.WeblogManager;
+import org.roller.pojos.WeblogCategoryData;
+import org.roller.pojos.WeblogEntryComparator;
+import org.roller.pojos.WeblogEntryData;
+import org.roller.pojos.WebsiteData;
+import org.roller.presentation.RollerContext;
+import org.roller.presentation.RollerRequest;
+import org.roller.presentation.weblog.search.FieldConstants;
+import org.roller.presentation.weblog.search.IndexManager;
+import org.roller.presentation.weblog.search.operations.SearchOperation;
+import org.roller.util.DateUtil;
+import org.roller.util.StringUtils;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.JspFactory;
+import javax.servlet.jsp.PageContext;
+
+
+/**
+ * This servlet retrieves (and displays) search results.
+ *
+ * @web.servlet name="SearchServlet" load-on-startup="5"
+ * @web.servlet-init-param name="properties" value="/WEB-INF/velocity.properties"
+ * @web.servlet-mapping url-pattern="/search/*"
+ */
+public class SearchServlet extends BasePageServlet
+{
+    //~ Static fields/initializers =============================================
+
+    private static Log mLogger =
+        LogFactory.getFactory().getInstance(SearchServlet.class);
+    
+    /* How many results to display */
+    private static int LIMIT = 10;
+    /* Where to start fetching results */
+    private static int OFFSET = 0;
+
+    //~ Methods ================================================================
+
+    public Template handleRequest(HttpServletRequest request,
+                        HttpServletResponse response, Context ctx) throws Exception
+    {
+    	// set request Charcter Encoding here, because the SearchServlet
+    	// is not preceeded by the RequestFilter
+    	mLogger.debug("handleRequest()");
+		try
+		{
+			// insure that incoming data is parsed as UTF-8
+			request.setCharacterEncoding("UTF-8");
+		}
+		catch (UnsupportedEncodingException e)
+		{
+			throw new ServletException("Can't set incoming encoding to UTF-8");
+		}
+    	        
+        ctx.put("term", "");
+        ctx.put("hits", new Integer(0));
+        ctx.put("searchResults", new TreeMap());  
+        
+        mLogger.debug("q = "+request.getParameter("q"));
+        
+        // do no work if query term is empty
+        if (StringUtils.isEmpty(request.getParameter("q")))
+        {  
+            return generalSearchResults(request, response, ctx);        
+        }
+
+        boolean userSpecificSearch = checkForUser(request);
+        try
+        {
+            RollerRequest rreq = getRollerRequest(request, response);
+            
+            SearchOperation search = new SearchOperation();
+            search.setTerm(request.getParameter("q"));
+            ctx.put("term", request.getParameter("q"));
+
+            WebsiteData website = null;
+            if (userSpecificSearch)
+            {    
+                website = rreq.getWebsite();
+                search.setUsername(rreq.getUser().getUserName());
+                ctx.put("username", rreq.getUser().getUserName());
+            }
+            
+            if (StringUtils.isNotEmpty(request.getParameter("c")))
+            {
+                search.setCategory(request.getParameter("c"));
+            }
+
+            // execute search
+            executeSearch(search);
+
+            Map searchResults = new TreeMap();
+            int hitCount = search.getResultsCount();
+            if (hitCount == -1)
+            {
+                // this means there has been a parsing (or IO) error
+                //ctx.put("errorMessage", search.getParseError());
+                ctx.put("errorMessage", "There was a problem with your search.");
+                hitCount = 0;
+            }
+            else
+            {    
+                // Convert the Hits into WeblogEntryData instances.
+                Hits hits = search.getResults();
+                searchResults = convertHitsToEntries(rreq, website, hits);
+                ctx.put("offset", request.getAttribute("offset"));
+                ctx.put("limit", request.getAttribute("limit"));
+                
+                if (request.getAttribute("categories") != null)
+                {
+                    Set cats = (Set)request.getAttribute("categories");
+                    if (cats.size() > 0)
+                    {
+                        ctx.put("categories", cats);
+                    }
+                }
+            }
+            ctx.put("searchResults", searchResults);
+            ctx.put("hits", new Integer(hitCount));
+        }
+        catch (Exception e)
+        {
+            mLogger.error("EXCEPTION: in SearchServlet", e);
+            request.setAttribute("DisplayException", e);
+            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+        }        
+
+        if (userSpecificSearch)   
+        {    
+            return super.handleRequest(request, response, ctx);
+        }
+
+        return generalSearchResults(request, response, ctx);
+    }
+
+    /**
+     * execute search
+     * @param search
+     */
+    private void executeSearch(SearchOperation search)
+    {
+        IndexManager indexMgr =
+            RollerContext.getRollerContext(
+                this.getServletContext()).getIndexManager();
+        indexMgr.executeIndexOperationNow(search);
+        if (mLogger.isDebugEnabled())
+        {
+            mLogger.debug("numresults = " + search.getResultsCount());
+        }
+    }
+
+    /**
+     * Iterate over Hits and build sets of WeblogEntryData
+     * objects, placed into Date buckets (in reverse order).
+     * 
+     * @param rreq
+     * @param website
+     * @param hits
+     * @throws RollerException
+     * @throws IOException
+     */
+    private TreeMap convertHitsToEntries(
+        RollerRequest rreq, WebsiteData website, Hits hits) 
+        throws RollerException, IOException
+    {
+        // determine offset (starting point)
+        int offset = useOffset(rreq.getRequest());
+        if (offset >= hits.length()) offset = OFFSET;
+        rreq.getRequest().setAttribute("offset", new Integer(offset));
+        
+        // determine limit (number of results to display)
+        int limit = useLimit(rreq.getRequest());
+        rreq.getRequest().setAttribute("limit", new Integer(limit));
+        if (offset + limit > hits.length()) limit = hits.length()-offset;
+        
+        boolean userSpecificSearch = checkForUser(rreq.getRequest());
+        TreeMap searchResults = new TreeMap(new ReverseComparator());
+        TreeSet categories = new TreeSet();
+        UserManager userMgr = 
+            RollerContext.getRoller(rreq.getRequest()).getUserManager();
+        WeblogManager weblogMgr =
+            RollerContext.getRoller(rreq.getRequest()).getWeblogManager();
+        WeblogEntryData entry;
+        Document doc = null;
+        String username = null;
+        for (int i = offset; i < offset+limit; i++)
+        {
+            entry = null; // reset for each iteration
+            
+            doc = hits.doc(i);
+            username =
+                doc.getField(FieldConstants.USERNAME).stringValue();
+            
+            if (userSpecificSearch && website != null) 
+            {
+                // "wrong user" results have been reported
+                if (username.equals(rreq.getUser().getUserName()))
+                {    
+                    //entry = buildSearchEntry(website, doc);
+                    
+                    // get real entry for display on user's site
+                    entry = weblogMgr.retrieveWeblogEntry(
+                        doc.getField(FieldConstants.ID).stringValue() );
+                }
+            }
+            else
+            {
+                website = userMgr.getWebsite(username);
+                // if user is not enabled, website will be null
+                if (website != null)
+                {
+                    entry = buildSearchEntry(website, doc);
+                    if (doc.getField(FieldConstants.CATEGORY) != null)
+                    {
+                        categories.add(
+                            doc.getField(FieldConstants.CATEGORY)
+                                .stringValue());
+                    }
+                }
+            }
+            
+            // maybe null if search result returned inactive user
+            // or entry's user is not the requested user.
+            if (entry != null)
+            {    
+                addToSearchResults(searchResults, entry);
+            }
+        }
+        rreq.getRequest().setAttribute("categories", categories);
+        return searchResults;
+    }
+
+    /**
+     * @param request
+     * @return
+     */
+    private int useOffset(HttpServletRequest request)
+    {
+        int offset = OFFSET;
+        if (request.getParameter("o") != null)
+        {
+            try
+            {
+                offset = Integer.valueOf(request.getParameter("o")).intValue();
+            }
+            catch (NumberFormatException e)
+            {
+                // Not a valid Integer
+            }
+        }
+        return offset;
+    }
+
+    /**
+     * @param request
+     * @return
+     */
+    private int useLimit(HttpServletRequest request)
+    {
+        int limit = LIMIT;
+        if (request.getParameter("n") != null)
+        {
+            try
+            {
+                limit = Integer.valueOf(request.getParameter("n")).intValue();
+            }
+            catch (NumberFormatException e)
+            {
+                // Not a valid Integer
+            }
+        }
+        return limit;
+    }
+
+    /**
+     * @param request
+     * @param response
+     * @return
+     */
+    private RollerRequest getRollerRequest(HttpServletRequest request, HttpServletResponse response)
+    {
+        PageContext pageContext =
+            JspFactory.getDefaultFactory()
+                .getPageContext(this, request, response, "", true, 8192, true);
+        
+        // Needed to init request attributes, etc.
+        return RollerRequest.getRollerRequest(pageContext);
+    }
+
+    /**
+     * @param searchResults
+     * @param entry
+     */
+    private void addToSearchResults(TreeMap searchResults, WeblogEntryData entry)
+    {
+        // convert entry's each date to midnight (00m 00h 00s)
+        Date midnight = DateUtil.getStartOfDay( entry.getPubTime() );
+        
+        // ensure we do not get duplicates from Lucene by
+        // using a Set Collection.  Entries sorted by pubTime.
+        TreeSet set = (TreeSet) searchResults.get(midnight);
+        if (set == null)
+        {
+            // date is not mapped yet, so we need a new Set
+            set = new TreeSet( new WeblogEntryComparator() );
+            searchResults.put(midnight, set);
+        }
+        set.add(entry);
+    }
+
+    /**
+     * @param website
+     * @param doc
+     * @param anchor
+     * @return
+     */
+    private WeblogEntryData buildSearchEntry(WebsiteData website, Document doc)
+    {
+        String pubTimeStr = doc.getField(FieldConstants.PUBLISHED).stringValue();
+        WeblogEntryData entry = new WeblogEntryData();
+        entry.setWebsite(website);
+        entry.setTitle(doc.getField(FieldConstants.TITLE).stringValue());
+        entry.setAnchor(doc.getField(FieldConstants.ANCHOR).stringValue());
+        entry.setPubTime( DateUtil.parseTimestampFromFormats(pubTimeStr) );
+        entry.setText( doc.getField(FieldConstants.CONTENT_STORED).stringValue() );
+        if (doc.getField(FieldConstants.CATEGORY) != null)
+        {
+            WeblogCategoryData category = new WeblogCategoryData();
+            category.setWebsite(website);
+            category.setName(doc.getField(FieldConstants.CATEGORY).stringValue());
+            entry.setCategory( category );
+        }
+        return entry;
+    }
+
+    /**
+     * If this is not a user-specific search, we need to display the 
+     * "generic" search results list.
+     * 
+     * @param request
+     * @param response
+     * @param ctx
+     * @return
+     */
+    private Template generalSearchResults(HttpServletRequest request, HttpServletResponse response, Context ctx)
+    {
+        Template outty = null;
+        Exception pageException = null;
+        try
+        {
+            ContextLoader.setupContext( 
+                ctx, RollerRequest.getRollerRequest(request), response );
+            outty = getTemplate( "searchresults.vm", "UTF-8" );
+        }
+        catch (Exception e)
+        {
+            pageException = e;
+            response.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
+        }
+
+        if (pageException != null)
+        {
+            mLogger.error("EXCEPTION: in RollerServlet", pageException);
+            request.setAttribute("DisplayException", pageException);
+        }
+        return outty;
+    }
+
+    /**
+     * Look in PathInfo so req.getRemoteUser() doesn't interfere.
+     * 
+     * @param request
+     * @return
+     */
+    private boolean checkForUser(HttpServletRequest request)
+    {
+        if (StringUtils.isNotEmpty(
+                request.getParameter(RollerRequest.USERNAME_KEY))) 
+        {
+            return true;
+        }
+        
+        String pathInfoStr = request.getPathInfo();
+        pathInfoStr = (pathInfoStr!=null) ? pathInfoStr : "";            
+        
+        String[] pathInfo = StringUtils.split(pathInfoStr,"/");            
+        if ( pathInfo.length > 0 )
+        {
+            return true; // is a user page
+        }
+        return false;
+    }
+
+}

Added: incubator/roller/trunk/src/org/roller/presentation/velocity/WebappResourceLoader.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/WebappResourceLoader.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/WebappResourceLoader.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/WebappResourceLoader.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,120 @@
+package org.roller.presentation.velocity;
+
+import org.apache.commons.collections.ExtendedProperties;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.resource.Resource;
+import org.apache.velocity.runtime.resource.loader.ResourceLoader;
+import org.roller.presentation.RollerContext;
+
+import java.io.InputStream;
+
+import javax.servlet.ServletContext;
+
+/**
+ * Tries to load Velocity resources from the Webapp.
+ * This class borrows heavily from
+ * org.apache.velocity.tools.view.servlet.WebappLoader
+ * http://cvs.apache.org/viewcvs/jakarta-velocity-
+ * tools/view/src/java/org/apache/velocity/tools/view/servlet/WebappLoader.java?
+ * rev=1.1.1.1&content-type=text/vnd.viewcvs-markup
+ * 
+ * @author Lance Lavandowska
+ */
+public class WebappResourceLoader extends ResourceLoader
+{
+	private static Log mLogger = 
+		LogFactory.getFactory().getInstance(WebappResourceLoader.class);
+    
+    private static ServletContext mContext = null; 
+  
+	/**
+	 * @see org.apache.velocity.runtime.resource.loader.ResourceLoader#init(org.apache.commons.collections.ExtendedProperties)
+	 */
+	public void init(ExtendedProperties arg0)
+	{
+		rsvc.info("WebappResourceLoader : initialization starting.");
+
+		this.getContext();
+		if (mContext == null)
+		{
+			mLogger.warn("WebappResourceLoader : Unable to find ServletContext!");
+		}
+
+		rsvc.info("WebappResourceLoader : initialization complete.");
+	}
+	
+	private ServletContext getContext()
+	{
+		if (mContext == null)
+		{
+			mContext = RollerContext.getServletContext();
+		}
+		return mContext;
+	}
+	
+	public static void setServletContext(ServletContext context)
+	{
+		mContext = context;
+	}
+	
+	/**
+	 * @see org.apache.velocity.runtime.resource.loader.ResourceLoader#getResourceStream(java.lang.String)
+	 */
+	public InputStream getResourceStream(String name)
+		throws ResourceNotFoundException
+	{
+		InputStream result = null;
+        
+		if (name == null || name.length() == 0)
+		{
+			throw new ResourceNotFoundException ("No template name provided");
+		}
+        
+		try 
+		{
+			if (!name.startsWith("/"))
+				name = "/" + name;
+
+			result = getContext().getResourceAsStream( name );
+		}
+		catch( NullPointerException npe)
+		{
+			String msg = "WebappResourceLoader.getResourceStream(): " + name;
+			if (mContext == null)
+			{
+				mLogger.info("WebappResourceLoader("+name+"): ServletContext is null");
+				msg += "\n\tServletContext is null";
+			}
+			throw new ResourceNotFoundException(msg);
+		}
+		catch( Exception fnfe )
+		{
+			/*
+			 *  log and convert to a general Velocity ResourceNotFoundException
+			 */            
+			throw new ResourceNotFoundException( fnfe.getMessage() );
+		}
+        
+		return result;
+	}
+	
+	/**
+	 * Defaults to return false.
+	 * @see org.apache.velocity.runtime.resource.loader.ResourceLoader#isSourceModified(org.apache.velocity.runtime.resource.Resource)
+	 */
+	public boolean isSourceModified(Resource arg0)
+	{
+		return false;
+	}
+	
+	/**
+	 * Defaults to return 0.
+	 * @see org.apache.velocity.runtime.resource.loader.ResourceLoader#getLastModified(org.apache.velocity.runtime.resource.Resource)
+	 */
+	public long getLastModified(Resource arg0)
+	{
+		return 0;
+	}
+}

Added: incubator/roller/trunk/src/org/roller/presentation/velocity/export_atom.vm
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/export_atom.vm?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/export_atom.vm (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/export_atom.vm Wed Jun  8 09:06:16 2005
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding='utf-8'?>
+<feed version="0.3" xmlns="http://purl.org/atom/ns#">
+	<!-- Special Archive version of Atom, created by Roller -->
+    <title>$utilities.textToHTML($website.name,true)</title>
+    <tagline>$utilities.textToHTML($website.description,true)</tagline>
+    <modified>$utilities.formatIso8601Date($updateTime)</modified>
+
+    #foreach( $entry in $entries )
+    <entry xmlns="http://purl.org/atom/ns#" >
+        <id>$entry.id</id>
+        <title>$utilities.textToHTML($entry.title,true)</title>
+        <subject>$entry.category.path</subject>
+
+        <author>
+          <name>$fullName</name>
+        </author>
+
+        <issued>$utilities.formatIso8601Date($entry.pubTime)</issued>
+        <created>$utilities.formatIso8601Date($entry.pubTime)</created>
+        <modified>$utilities.formatIso8601Date($entry.updateTime)</modified>
+
+        <content><![CDATA[$entry.text]]></content>
+    </entry>
+        ## use "experimental" form of Comment 'annotation'
+        #foreach( $comment in $entry.comments )
+        <entry xmlns="http://purl.org/atom/ns#" >
+            <id>$comment.id</id>
+            <title>$utilities.truncateNicely($comment.content,40,50,"...")</title>
+
+            <author>
+              <name>$comment.name</name>
+              <url>$comment.url</url>
+              <email>$comment.email</email>
+            </author>
+            <issued>$utilities.formatIso8601Date($comment.postTime)</issued>
+            <content><![CDATA[$comment.content]]></content>
+            <annotate type="comment" rel="parent">$entry.id</annotate>
+        </entry>
+        #end
+    #end
+</feed>
\ No newline at end of file

Added: incubator/roller/trunk/src/org/roller/presentation/velocity/export_rss.vm
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/export_rss.vm?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/export_rss.vm (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/export_rss.vm Wed Jun  8 09:06:16 2005
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<rss version="2.0">
+<channel>
+  <!-- Special Archive version of RSS2, created by Roller -->
+  <title>$utilities.textToHTML($website.name,true)</title>
+  <description>$utilities.textToHTML($website.description,true)</description>
+  <language>$website.locale</language>
+  <copyright>Copyright #formatDate("yyyy" $now)</copyright>
+
+  #foreach( $entry in $entries )
+  <item>
+    <title>$utilities.textToHTML($entry.title,true)</title>
+    <description><![CDATA[$entry.text]]></description>
+    <category>$entry.category.path</category>
+    <pubDate>$utilities.formatRfc822Date($entry.pubTime)</pubDate>
+    <guid isPermaLink="false">$entry.id</guid>
+  </item>
+  #end
+</channel>
+</rss>
\ No newline at end of file

Added: incubator/roller/trunk/src/org/roller/presentation/velocity/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/package.html?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/package.html (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/package.html Wed Jun  8 09:06:16 2005
@@ -0,0 +1,9 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title></title>
+</head>
+<body>
+Velocity integration, Page Servlet and Macros object.<br>
+</body>
+</html>