roller-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From snoopd...@apache.org
Subject svn commit: r189695 [36/67] - in /incubator/roller/trunk: ./ contrib/ contrib/lib/ contrib/plugins/ contrib/plugins/src/ contrib/plugins/src/org/ contrib/plugins/src/org/roller/ contrib/plugins/src/org/roller/presentation/ contrib/plugins/src/org/roller/presentation/velocity/ contrib/plugins/src/org/roller/presentation/velocity/plugins/ contrib/plugins/src/org/roller/presentation/velocity/plugins/acronyms/ contrib/plugins/src/org/roller/presentation/velocity/plugins/bookmarks/ contrib/plugins/src/org/roller/presentation/velocity/plugins/email/ contrib/plugins/src/org/roller/presentation/velocity/plugins/jspwiki/ contrib/plugins/src/org/roller/presentation/velocity/plugins/radeox/ contrib/plugins/src/org/roller/presentation/velocity/plugins/readmore/ contrib/plugins/src/org/roller/presentation/velocity/plugins/smileys/ contrib/plugins/src/org/roller/presentation/velocity/plugins/textile/ contrib/plugins/src/org/roller/presentation/velocity/plugins/topictag/ custom/ custom/src/ custom/web/ docs/ docs/images/ docs/installguide/ docs/installguide/old/ docs/userguide/ docs/userguide/images/ docs/userguide/old/ metadata/ metadata/database/ metadata/database/hibernate/ metadata/xdoclet/ nbproject/ personal/ personal/eclipse/ personal/testing/ sandbox/ sandbox/planetroller/ sandbox/planetroller/metadata/ sandbox/planetroller/metadata/database/ sandbox/planetroller/src/ sandbox/planetroller/src/org/ sandbox/planetroller/src/org/roller/ sandbox/planetroller/src/org/roller/tools/ sandbox/planetroller/src/org/roller/tools/planet/ sandbox/planetroller/templates/ sandbox/planetroller/test/ sandbox/planetroller/test/org/ sandbox/planetroller/test/org/roller/ sandbox/planetroller/test/org/roller/model/ sandbox/planetroller/test/org/roller/tools/ sandbox/planetroller/test/org/roller/tools/planet/ sandbox/planetroller/testdata/ sandbox/planetroller/testdata/cache/ sandbox/planetroller/testdata/output/ sandbox/standalone/ sandbox/standalone/jspwiki/ sandbox/standalone/jspwiki/default/ sandbox/standalone/jspwiki/default/images/ sandbox/standalone/lib/ sandbox/standalone/src/ sandbox/standalone/src/org/ sandbox/standalone/src/org/roller/ sandbox/standalone/src/org/roller/jspwiki/ sandbox/standalone/src/org/roller/tomcat/ sandbox/standalone/src/org/roller/util/ sandbox/standalone/tests/ sandbox/standalone/tests/org/ sandbox/standalone/tests/org/roller/ sandbox/standalone/tests/org/roller/util/ sandbox/standalone/tomcat/ src/ src/org/ src/org/roller/ src/org/roller/business/ src/org/roller/business/hibernate/ src/org/roller/business/search/ src/org/roller/business/search/operations/ src/org/roller/business/utils/ src/org/roller/config/ src/org/roller/config/runtime/ src/org/roller/model/ src/org/roller/pojos/ src/org/roller/presentation/ src/org/roller/presentation/atomapi/ src/org/roller/presentation/bookmarks/ src/org/roller/presentation/bookmarks/actions/ src/org/roller/presentation/bookmarks/formbeans/ src/org/roller/presentation/bookmarks/tags/ src/org/roller/presentation/filters/ src/org/roller/presentation/forms/ src/org/roller/presentation/newsfeeds/ src/org/roller/presentation/pagecache/ src/org/roller/presentation/pagecache/rollercache/ src/org/roller/presentation/pings/ src/org/roller/presentation/planet/ src/org/roller/presentation/tags/ src/org/roller/presentation/tags/calendar/ src/org/roller/presentation/tags/menu/ src/org/roller/presentation/util/ src/org/roller/presentation/velocity/ src/org/roller/presentation/weblog/ src/org/roller/presentation/weblog/actions/ src/org/roller/presentation/weblog/formbeans/ src/org/roller/presentation/weblog/tags/ src/org/roller/presentation/website/ src/org/roller/presentation/website/actions/ src/org/roller/presentation/website/formbeans/ src/org/roller/presentation/website/tags/ src/org/roller/presentation/xmlrpc/ src/org/roller/util/ src/org/roller/util/rome/ tests/ tests/org/ tests/org/roller/ tests/org/roller/ant/ tests/org/roller/business/ tests/org/roller/presentation/ tests/org/roller/presentation/atomapi/ tests/org/roller/presentation/bookmarks/ tests/org/roller/presentation/filters/ tests/org/roller/presentation/velocity/ tests/org/roller/presentation/velocity/plugins/ tests/org/roller/presentation/velocity/plugins/smileys/ tests/org/roller/presentation/velocity/plugins/textile/ tests/org/roller/presentation/weblog/ tests/org/roller/presentation/xmlrpc/ tests/org/roller/util/ tests/org/roller/util/rome/ tools/ tools/buildtime/ tools/buildtime/ant-1.6.2/ tools/buildtime/findbugs/ tools/buildtime/findbugs/lib/ tools/buildtime/findbugs/plugin/ tools/buildtime/mockrunner-0.3/ tools/buildtime/mockrunner-0.3/lib/ tools/buildtime/mockrunner-0.35/ tools/buildtime/mockrunner-0.35/lib/ tools/buildtime/tomcat-4.1.24/ tools/buildtime/xdoclet-1.2/ tools/buildtime/xdoclet-1.2/lib/ tools/hibernate-2.1/ tools/hibernate-2.1/lib/ tools/lib/ tools/standard-1.0.3/ tools/standard-1.0.3/lib/ tools/standard-1.0.3/tld/ tools/struts-1.2.4/ tools/struts-1.2.4/lib/ web/ web/WEB-INF/ web/WEB-INF/classes/ web/WEB-INF/classes/flavors/ web/WEB-INF/classes/themes/ web/bookmarks/ web/editor/ web/editor/images/ web/images/ web/images/editor/ web/images/midas/ web/images/preview/ web/images/smileys/ web/planet/ web/tags/ web/templates/ web/theme/ web/theme/images/ web/theme/lavender/ web/theme/scripts/ web/theme/scripts/classes/ web/themes/ web/themes/basic/ web/themes/berkley/ web/themes/berkley/images/ web/themes/brushedmetal/ web/themes/brushedmetal/images/ web/themes/cheb/ web/themes/cheb/images/ web/themes/cheb/scripts/ web/themes/clean/ web/themes/currency-i18n/ web/themes/currency-i18n/images/ web/themes/currency/ web/themes/currency/images/ web/themes/grey2/ web/themes/moonshine/ web/themes/movablemanila/ web/themes/movablemanila/images/ web/themes/pacifica/ web/themes/robot/ web/themes/rolling/ web/themes/rolling/images/ web/themes/sotto/ web/themes/sotto/images/ web/themes/sotto/styles/ web/themes/sunsets/ web/themes/sunsets/images/ web/themes/sunsets/scripts/ web/themes/sunsets/styles/ web/themes/werner/ web/themes/x2/ web/themes/x2/images/ web/themes/x2/scripts/ web/themes/x2/styles/ web/weblog/ web/website/
Date Thu, 09 Jun 2005 03:19:20 GMT
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=189695&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 20:18:46 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=189695&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 20:18:46 2005
@@ -0,0 +1,139 @@
+
+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="org.apache.velocity.properties" 
+ * 		                  value="/WEB-INF/velocity.properties"
+ *  
+ * @web.servlet-mapping url-pattern="/page/*"
+ */ 
+public class PageServlet extends BasePageServlet
+{
+    static final long serialVersionUID = 5083624357559616805L;
+    
+    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.
+	 */
+	transient 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/PlanetFeedServlet.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/PlanetFeedServlet.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/PlanetFeedServlet.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/PlanetFeedServlet.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1 @@
+package org.roller.presentation.velocity;
import java.io.IOException;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.Template;
import org.apache.velocity.context.Context;
import org.apache.velocity.servlet.VelocityServlet;
import org.roller.RollerException;
import org.roller.model.PlanetManager;
import org.roller.presentation.RollerRequest;
import org.roller.util.Utilities;

/////////////////////////////////////////////////////////////////////////////
/**
 * Planet Roller (i.e. NOT for Planet Tool) RSS feed. 
 * @author David M Johnson
 * @web.servlet name="PlanetFeedServlet"
 * @web.servlet-mapping url-pattern="/planetrss/*"
 */
public class PlanetFeedServlet extends VelocityServlet
{
    private static Log mLogger = 
        LogFactory.getFactory().getInstance(RollerRequest.class);
    
    public Template handleRequest(HttpServletRequest request,
                                  HttpServletResponse response, Context context)
    {
        RollerRequest rreq = null;
        try
        {
            rreq = RollerRequest.getRollerRequest(request, getServletContext());
        }
        catch (RollerException e)
        {
            // An error initializing the request is considered to be a 404
            if (mLogger.isDebugEnabled())
            {
                mLogger.debug("RollerRequest threw Exception", e);
            }
            try
            {
                response.sendError(HttpServletResponse.SC_NOT_FOUND);
            }
            catch (IOException e1)
            {
                if (mLogger.isDebugEnabled())
                {
                    mLogger.debug("IOException sending error", e);
                }
            }
            return null;
        }
        try
        {
            response.setContentType("application/rss+xml;charset=utf-8");
            PlanetManager planet = 
                rreq.getRoller().getPlanetManager();
            if (request.getParameter("group") != null) 
            {
                context.put("groupName", request.getParameter("group"));
            }
            context.put("planet", planet);
            context.put("date", new Date());
            context.put("utilities", new Utilities());
            return getTemplate("planetrss.vm");
        }
        catch (Exception e)
        {
            mLogger.error("ERROR in PlanetFeedServlet", e);
        }
        return null;
    }

    //------------------------------------------------------------------------
    /**
     * Handle error in Velocity processing.
     */
    protected void error( HttpServletRequest req, HttpServletResponse res,
        Exception e) throws ServletException, IOException
    {
        mLogger.warn("ERROR in PlanetFeedServlet",e);
    }
}
\ No newline at end of file

Added: incubator/roller/trunk/src/org/roller/presentation/velocity/PlanetPageModel.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/PlanetPageModel.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/PlanetPageModel.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/PlanetPageModel.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,69 @@
+
+package org.roller.presentation.velocity;
+import java.util.ArrayList;
+import java.util.List;
+import org.roller.model.PlanetManager;
+import org.roller.model.Roller;
+import org.roller.pojos.PlanetGroupData;
+import org.roller.pojos.PlanetSubscriptionData;
+import org.roller.presentation.RollerRequest;
+import org.roller.presentation.velocity.PageModel;
+
+/**
+ * Allow Roller page templates to get the main Planet aggregation (the 'all'
+ * and 'external' group), custom aggregations, specified by handle, and 
+ * subscription entries (specified by feedUrl). 
+ * @author Dave Johnson
+ */
+public class PlanetPageModel extends PageModel 
+{
+    PlanetManager planetManager = null;
+    public void init(RollerRequest rreq)
+    {
+        super.init(rreq);
+        try 
+        {
+            planetManager = rreq.getRoller().getPlanetManager();
+        }
+        catch (Exception e)
+        {
+            mLogger.error("ERROR initializing page model",e);
+        }
+    }
+    /** 
+     * Get main aggregation (of 'all' and 'external' groups) 
+     * @returns List of PlanetEntryData objects
+     */
+    public List getPlanetAggregation(int max) throws Exception
+    {
+        return planetManager.getAggregation(max);
+    }
+    /** 
+     * Get aggregation by group handle 
+     * @returns List of PlanetEntryData objects
+     */
+    public List getPlanetAggregation(String groupHandle, int max) throws Exception
+    {
+        List list = new ArrayList();
+        PlanetGroupData group = planetManager.getGroup(groupHandle);
+        if (group != null) 
+        {
+            list = planetManager.getAggregation(group, max);
+        }
+        return list;
+    }
+    /** 
+     * Get entries in a subscription specified by feedUrl.
+     * @returns List of PlanetEntryData objects
+     */
+    public List getPlanetSubscriptionEntries(String feedUrl, int max) throws Exception 
+    {
+        List list = new ArrayList();
+        PlanetSubscriptionData sub = planetManager.getSubscription(feedUrl);
+        if (sub != null)
+        {
+            list = sub.getEntries();
+        }
+        return list;
+    }
+}

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=189695&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 20:18:46 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.19 2005/01/15 03:32:49 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("UTF-8") );
+        }
+        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();
+    }
+}
\ No newline at end of file

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=189695&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 20:18:46 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=189695&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 20:18:46 2005
@@ -0,0 +1,144 @@
+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;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * 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.9 2005/01/15 03:32:49 snoopdave 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("UTF-8") );
+        }
+        catch (UnsupportedEncodingException uex)
+        {
+            // This should never actually happen.  We expect UTF-8 in all JRE installation.
+            // This rethrows as a Runtime exception after logging. 
+            mLogger.error(uex);
+            throw new RuntimeException(uex);
+        }
+        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=189695&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 20:18:46 2005
@@ -0,0 +1,418 @@
+package org.roller.presentation.velocity;
+
+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;
+
+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.business.search.FieldConstants;
+import org.roller.business.search.operations.SearchOperation;
+import org.roller.model.IndexManager;
+import org.roller.model.Roller;
+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.util.DateUtil;
+import org.roller.util.StringUtils;
+
+
+/**
+ * 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 =============================================
+    static final long serialVersionUID = -2150090108300585670L;
+
+    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());          
+        // to enable better unit testing
+        request.setAttribute("zzz_VelocityContext_zzz", ctx);
+        
+        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(rreq.getRoller().getIndexManager());
+            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(rreq.getRoller(), search);
+
+            Map searchResults = new TreeMap();
+            if (search.getResultsCount() == -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.");
+            }
+            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(search.getResultsCount()));      
+        }
+        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(Roller roller, SearchOperation search) 
+    throws RollerException
+    {
+        IndexManager indexMgr = roller.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
+     * @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/VelocityPageInsert.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/velocity/VelocityPageInsert.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/velocity/VelocityPageInsert.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/velocity/VelocityPageInsert.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,21 @@
+package org.roller.presentation.velocity;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.velocity.VelocityContext;
+import org.roller.pojos.PageData;
+
+/**
+ * A web page insert is a big of HTML that is inserted into a page into 
+ * any page that is rendered by the Roller Page Servlet and CommentServlet.
+ *
+ * @author David M Johnson
+ */
+public interface VelocityPageInsert 
+{
+    public void display(
+        PageData page,
+        VelocityContext context,
+        HttpServletRequest request, 
+        HttpServletResponse response);
+}

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=189695&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 20:18:46 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=189695&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 20:18:46 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=189695&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 20:18:46 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=189695&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 20:18:46 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>

Added: incubator/roller/trunk/src/org/roller/presentation/weblog/TrackbackServlet.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/weblog/TrackbackServlet.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/weblog/TrackbackServlet.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/weblog/TrackbackServlet.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,175 @@
+/*
+ * Created on Apr 13, 2003
+ */
+package org.roller.presentation.weblog;
+
+import org.roller.pojos.WeblogEntryData;
+import org.roller.presentation.RollerRequest;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.UnsupportedEncodingException;
+
+
+/**
+ * Roller's Trackback server implementation. POSTing to this Servlet will add a
+ * Trackback to a Weblog Entrty. For more info on Trackback, read the spec: 
+ * <a href="http://www.movabletype.org/docs/mttrackback.html>MT Trackback</a>.
+ * 
+ * @web.servlet name="TrackbackServlet"
+ * @web.servlet-mapping url-pattern="/trackback/*"
+ * 
+ * @author David M Johnson
+ */
+public class TrackbackServlet extends HttpServlet
+{
+    /** Request parameter to indicate a trackback "tb" */
+    //private static final String TRACKBACK_PARAM = "tb";
+
+    /** Request parameter for the trackback "title" */
+    private static final String TRACKBACK_TITLE_PARAM = "title";
+
+    /** Request parameter for the trackback "excerpt" */
+    private static final String TRACKBACK_EXCERPT_PARAM = "excerpt";
+
+    /** Request parameter for the trackback "url" */
+    private static final String TRACKBACK_URL_PARAM = "url";
+
+    /** Request parameter for the trackback "blog_name" */
+    private static final String TRACKBACK_BLOG_NAME_PARAM = "blog_name";
+
+    /** Key under which the trackback return code will be placed
+     * (example: on the request for the JSPDispatcher) */
+    public static final String BLOJSOM_TRACKBACK_RETURN_CODE = 
+            "BLOJSOM_TRACKBACK_RETURN_CODE";
+
+    /** Key under which the trackback error message will be placed
+     * (example: on the request for the JSPDispatcher) */
+    public static final String BLOJSOM_TRACKBACK_MESSAGE = 
+            "BLOJSOM_TRACKBACK_MESSAGE";
+
+    /** Trackback success page */
+    //private static final String TRACKBACK_SUCCESS_PAGE = "trackback-success";
+
+    /** Trackback failure page */
+    //private static final String TRACKBACK_FAILURE_PAGE = "trackback-failure";
+
+    /**
+     * Constructor.
+     */
+    public TrackbackServlet()
+    {
+        super();
+    }
+
+    /** 
+     * POSTing to this Servlet will add a Trackback to a Weblog Entrty.
+     */
+    protected void doGet(HttpServletRequest req, HttpServletResponse res)
+                   throws ServletException, IOException
+    {
+        doPost(req,res);
+    }
+    
+    /** 
+     * POSTing to this Servlet will add a Trackback to a Weblog Entrty.
+     */
+    protected void doPost(HttpServletRequest req, HttpServletResponse res)
+                   throws ServletException, IOException
+    {
+        try
+        {
+            // insure that incoming data is parsed as UTF-8
+            req.setCharacterEncoding("UTF-8");
+        }
+        catch (UnsupportedEncodingException e)
+        {
+            throw new ServletException("Can't set incoming encoding to UTF-8");
+        }
+
+        String url = req.getParameter(TRACKBACK_URL_PARAM);
+        String title = req.getParameter(TRACKBACK_TITLE_PARAM);
+        String excerpt = req.getParameter(TRACKBACK_EXCERPT_PARAM);
+        String blogName = req.getParameter(TRACKBACK_BLOG_NAME_PARAM);
+
+        if ((title == null) || "".equals(title))
+        {
+            title = url;
+        }
+
+        if (excerpt == null)
+        {
+            excerpt = "";
+        }
+        else
+        {
+            if (excerpt.length() >= 255)
+            {
+                excerpt = excerpt.substring(0, 252);
+                excerpt += "...";
+            }
+        }
+               
+        String error = null;
+        PrintWriter pw = new PrintWriter(res.getOutputStream());
+        try
+        {
+            if ( title==null || url==null || excerpt==null || blogName==null )
+            {
+                error = "title, url, excerpt, and blog_name not specified.";
+            }
+            else
+            {
+                RollerRequest rreq = RollerRequest.getRollerRequest(req);
+                WeblogEntryData entry = rreq.getWeblogEntry();
+                
+                if (entry!=null && entry.getCommentsStillAllowed())
+                {
+                    entry.addTrackback(url,title,excerpt,blogName);
+                    rreq.getRoller().commit();
+            
+                    pw.println("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>");
+                    pw.println("<response>");
+                    pw.println("<error>0</error>");
+                    pw.println("</response>");
+                    pw.flush();
+                }
+                else if (entry!=null)
+                {
+                    error = "Comments and Trackbacks are disabled for the entry you specified.";
+                }                
+                else
+                {
+                    error = "Entry not specified.";
+                }                
+            }
+            
+        }
+        catch (Exception e)
+        {
+            error = e.getMessage();
+            if ( error == null )
+            {   
+                error = e.getClass().getName();
+            }
+        }
+        
+        if ( error!= null )
+        {
+            pw.println("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>");
+            pw.println("<response>");
+            pw.println("<error>1</error>");
+            pw.println("<message>ERROR: "+error+"</message>");
+            pw.println("</response>");
+            pw.flush();
+        }
+        res.flushBuffer();
+        
+        // TODO : FindBugs thinks 'pw' should close
+    }
+}
\ No newline at end of file

Added: incubator/roller/trunk/src/org/roller/presentation/weblog/actions/BakeWeblogAction.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/weblog/actions/BakeWeblogAction.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/weblog/actions/BakeWeblogAction.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/weblog/actions/BakeWeblogAction.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,246 @@
+package org.roller.presentation.weblog.actions;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.actions.DispatchAction;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.roller.RollerException;
+import org.roller.model.UserManager;
+import org.roller.model.WeblogManager;
+import org.roller.pojos.PageData;
+import org.roller.pojos.WebsiteData;
+import org.roller.presentation.RollerContext;
+import org.roller.presentation.RollerRequest;
+import org.roller.presentation.RollerSession;
+import org.roller.presentation.velocity.ContextLoader;
+import org.roller.presentation.weblog.tags.WeblogEntryMacros;
+import org.roller.util.DateUtil;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.JspFactory;
+import javax.servlet.jsp.PageContext;
+
+/////////////////////////////////////////////////////////////////////////////
+/**
+ * Generates static pages for each day containing Weblog entries.
+ *
+ * @struts.action name="bakeWeblogForm" path="/editor/bake"
+ * 		scope="session" parameter="method"
+ *
+ * @struts.action-forward name="baking.done" path="/weblog/bakeWeblog.jsp"
+ *
+ * @author llavandowska
+ */
+public class BakeWeblogAction extends DispatchAction {
+    private static Log mLogger =
+            LogFactory.getFactory().getInstance(BakeWeblogAction.class);
+    
+    public ActionForward load(
+            ActionMapping       mapping,
+            ActionForm          actionForm,
+            HttpServletRequest  request,
+            HttpServletResponse response)
+            throws IOException, ServletException {
+        RollerRequest rreq = RollerRequest.getRollerRequest(request);
+        try {
+            if ( !rreq.isUserAuthorizedToEdit() ) {
+                return mapping.findForward("access-denied");
+            }
+        } catch (Exception e) {
+            return mapping.findForward("access-denied");
+        }
+        return mapping.findForward("baking.done");
+    }
+    
+    public ActionForward bake(
+            ActionMapping       mapping,
+            ActionForm          actionForm,
+            HttpServletRequest  request,
+            HttpServletResponse response)
+            throws IOException, ServletException {
+        ActionForward forward = mapping.findForward("baking.done");
+        ActionErrors errors = new ActionErrors();
+        try {
+            PageContext pageContext =
+                    JspFactory.getDefaultFactory().getPageContext(
+                    this.getServlet(), request, response,"", true, 8192, true);
+            RollerRequest rreq = RollerRequest.getRollerRequest(pageContext);
+            if ( !rreq.isUserAuthorizedToEdit() ) {
+                return mapping.findForward("access-denied");
+            }
+            
+            String pid = getDefaultPageId( rreq );
+            
+            VelocityContext context = new VelocityContext();
+            ContextLoader.setupContext( context, rreq, response );
+            
+            // Get this months Entries
+            WeblogManager mgr = rreq.getRoller().getWeblogManager();
+            //Map entryMap = mgr.getWeblogEntryMonthMap(
+            //rreq.getUser().getUserName(),
+            //rreq.getDate(true),
+            //null,
+            //false,
+            //true );
+            
+            Map entryMap = mgr.getWeblogEntryObjectMap(
+                    rreq.getWebsite(),
+                    null,                        // startDate
+                    rreq.getDate(true),          // endDate
+                    null,                        // catName
+                    WeblogManager.PUB_ONLY,      // status
+                    null);                      // maxEntries
+            
+            if (mLogger.isDebugEnabled()) {
+                mLogger.debug("Num Days to Bake: " + entryMap.size());
+            }
+            
+            Iterator iter = entryMap.keySet().iterator();
+            if (iter.hasNext()) {
+                Date d = (Date)iter.next();
+                
+                if (mLogger.isDebugEnabled()) {
+                    mLogger.debug("Bake Weblog for date:" + d);
+                }
+                
+                // Do we need this to continue supporting Macros?
+                WeblogEntryMacros macros =
+                        new WeblogEntryMacros( rreq.getPageContext(), d );
+                context.put( "macros", macros );
+                
+                List entries = (List) entryMap.get( d );
+                String content = transformTemplate(pid, entries, context, rreq);
+                
+                String fileName = writeToFile(content, d, rreq);
+                request.getSession().setAttribute(
+                        RollerSession.STATUS_MESSAGE,
+                        "Weblog baked to :" + fileName);
+            }
+            
+            /** put some user message **/
+            String message = (String) request.getSession().getAttribute(
+                    RollerSession.STATUS_MESSAGE);
+            if (message == null) message = "No Files Written";
+            request.getSession().setAttribute(
+                    RollerSession.STATUS_MESSAGE,
+                    message);
+        } catch (Exception e) {
+            forward = mapping.findForward("error");
+            
+            errors.add(ActionErrors.GLOBAL_ERROR,
+                    new ActionError("error.bake.weblog", e.toString()));
+            saveErrors(request,errors);
+            
+            mLogger.error(getResources(request).getMessage("error.bake.weblog")
+            + e.toString(),e);
+        }
+        
+        return forward;
+    }
+    
+    /**
+     * Write the content generated by transformTemplate to a file in the Upload
+     * directory, where the user can reach it.
+     *
+     * @param content
+     * @param d
+     * @param rreq
+     */
+    private String writeToFile(String content, Date d, RollerRequest rreq)
+    throws IOException {
+        if (mLogger.isDebugEnabled()) {
+            mLogger.debug("Write file for:" + d);
+        }
+        
+        String dir = RollerContext.getUploadDir( rreq.getServletContext() );
+        String username = rreq.getUser().getUserName();
+        File dirF = new File(dir + username + File.separator + "baked");
+        if (!dirF.exists()) {
+            dirF.mkdirs();
+        }
+        
+        SimpleDateFormat mFmt = DateUtil.get8charDateFormat();
+        String dString = mFmt.format( d ) + ".html";
+        File pFile = new File(dirF, dString);
+        
+        OutputStream bos = null;
+        try {
+            bos = new FileOutputStream(pFile);
+            bos.write( content.getBytes() );
+        } catch (IOException e) {
+            mLogger.error("Unable to write to " + pFile.getName());
+        } finally {
+            try {
+                if (bos != null) bos.close();
+            } catch (IOException e1) {
+                mLogger.error("Unable to close stream to " + pFile.getName());
+            }
+        }
+        
+        return pFile.getName();
+    }
+    
+    /**
+     * Transform the Page specified by the pageId using Velocity. Return the
+     * resulting String.
+     *
+     * @param pid
+     * @param context
+     * @throws ResourceNotFoundException
+     * @throws ParseErrorException
+     * @throws MethodInvocationException
+     * @throws Exception
+     */
+    private String transformTemplate(String pid, List entries,
+            VelocityContext context, RollerRequest rreq)
+            throws
+            ResourceNotFoundException,
+            ParseErrorException,
+            MethodInvocationException,
+            Exception {
+        
+        context.put( "entries", entries );
+        
+        StringWriter sw = new StringWriter();
+        Velocity.mergeTemplate(pid, Velocity.ENCODING_DEFAULT, context, sw );
+        return sw.toString();
+    }
+    
+    /**
+     * Get the default pageId for this Website, this is assumed to be the Weblog
+     * page since we have no other way of declaring it.
+     *
+     * @param rreq
+     * @return String
+     * @throws RollerException
+     */
+    private String getDefaultPageId(RollerRequest rreq) throws RollerException {
+        UserManager userMgr = rreq.getRoller().getUserManager();
+        WebsiteData wd = rreq.getWebsite();
+        PageData pd = userMgr.retrievePage(wd.getDefaultPageId());
+        return pd.getId();
+    }
+    
+}

Added: incubator/roller/trunk/src/org/roller/presentation/weblog/actions/BasePingTargetsAction.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/weblog/actions/BasePingTargetsAction.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/weblog/actions/BasePingTargetsAction.java (added)
+++ incubator/roller/trunk/src/org/roller/presentation/weblog/actions/BasePingTargetsAction.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2005
+ * Anil R. Gangolli. All rights reserved.
+ *
+ * Distributed with the Roller Weblogger Project under the terms of the Roller Software
+ * License
+ */
+
+package org.roller.presentation.weblog.actions;
+
+import org.apache.struts.actions.DispatchAction;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMessages;
+import org.apache.struts.action.ActionMessage;
+import org.apache.commons.logging.Log;
+import org.roller.presentation.RollerRequest;
+import org.roller.presentation.forms.PingTargetForm;
+import org.roller.model.PingTargetManager;
+import org.roller.pojos.PingTargetData;
+import org.roller.RollerException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.ServletException;
+import java.util.List;
+
+/**
+ * Base class for both common and custom ping target operations.  The methods here apply to
+ * creating, editing and removing ping targets.  Operations for maintaining automatic ping
+ * configurations are handled by {@link PingSetupAction}.
+ */
+public abstract class BasePingTargetsAction extends DispatchAction
+{
+    // These are expected to be defined forwards by the concrete subclass actions.
+    protected static final String VIEW_PAGE = "pingTargets.page";
+    protected static final String PING_TARGET_EDIT_PAGE = "pingTargetEdit.page";
+    protected static final String PING_TARGET_DELETE_PAGE = "pingTargetDeleteOK.page";
+    protected static final String ACCESS_DENIED_PAGE = "access-denied";
+
+    public BasePingTargetsAction() {
+
+    }
+
+    /**
+     * Implements the default action (view) if the method is not specified.
+     * @param mapping
+     * @param actionForm
+     * @param request
+     * @param response
+     * @return the same result as <code>view()</code>
+     * @throws Exception
+     * @see org.apache.struts.actions.DispatchAction#unspecified(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+     */
+    protected ActionForward unspecified(ActionMapping mapping,
+                                        ActionForm actionForm,
+                                        HttpServletRequest request,
+                                        HttpServletResponse response)
+        throws Exception
+    {
+        return view(mapping, actionForm, request, response);
+    }
+
+    /**
+     * Display the ping targets.
+     *
+     * @param mapping
+     * @param form
+     * @param req
+     * @param res
+     * @return forward to the ping targets page
+     * @throws Exception
+     */
+    public ActionForward view(ActionMapping mapping, ActionForm form,
+                              HttpServletRequest req, HttpServletResponse res)
+        throws Exception
+    {
+        ActionForward forward = mapping.findForward(VIEW_PAGE);
+        RollerRequest rreq = RollerRequest.getRollerRequest(req);
+        try
+        {
+            if (!hasRequiredRights(rreq))
+            {
+                return mapping.findForward(ACCESS_DENIED_PAGE);
+            }
+
+            List pingTargets = getPingTargets(rreq);
+            req.setAttribute("pingTargets", pingTargets);
+            return forward;
+        }
+        catch (Exception e)
+        {
+            getLogger().error("ERROR in action", e);
+            throw new ServletException(e);
+        }
+    }
+
+    /**
+     * Save a ping target, new or existing (depending on whether the id is non-empty).
+     *
+     * @param mapping
+     * @param form
+     * @param req
+     * @param res
+     * @return the result of <code>view()</code> after the target is saved.
+     * @throws Exception
+     */
+    public ActionForward save(ActionMapping mapping, ActionForm form,
+                              HttpServletRequest req, HttpServletResponse res)
+        throws Exception
+    {
+        RollerRequest rreq = RollerRequest.getRollerRequest(req);
+        PingTargetManager pingTargetMgr = rreq.getRoller().getPingTargetManager();
+        PingTargetForm pingTargetForm = (PingTargetForm) form;
+        try
+        {
+            if (!hasRequiredRights(rreq))
+            {
+                return mapping.findForward(ACCESS_DENIED_PAGE);
+            }
+
+            PingTargetData pingTarget = null;
+            String pingTargetId = pingTargetForm.getId();
+            if (pingTargetId != null && pingTargetId.length() > 0)
+            {
+                pingTarget = pingTargetMgr.retrievePingTarget(pingTargetForm.getId());
+                if (pingTarget == null) throw new RollerException("No such ping target id: " + pingTargetId);
+                pingTargetForm.copyTo(pingTarget, req.getLocale());
+            }
+            else
+            {
+                pingTarget = createPingTarget(rreq, pingTargetForm);
+            }
+
+            // Call private helper to validate ping target
+            // If there are errors, go back to the target edit page.
+            ActionMessages errors = validate(rreq, pingTarget);
+            if (!errors.isEmpty()) {
+                saveErrors(rreq.getRequest(), errors);
+                return mapping.findForward(PING_TARGET_EDIT_PAGE);
+            }
+
+            // Appears to be ok.  Save it, commit and return refreshed view of target list.
+            pingTarget.save();
+            rreq.getRoller().commit();
+            return view(mapping, form, req, res);
+        }
+        catch (Exception e)
+        {
+            getLogger().error("ERROR in action", e);
+            throw new ServletException(e);
+        }
+    }
+
+    /**
+     * Add a new ping target. Loads the edit view blank.
+     *
+     * @param mapping
+     * @param form
+     * @param req
+     * @param res
+     * @return the edit page (blank)
+     * @throws Exception
+     */
+    public ActionForward addNew(ActionMapping mapping, ActionForm form,
+                                HttpServletRequest req, HttpServletResponse res)
+        throws Exception
+    {
+        return mapping.findForward(PING_TARGET_EDIT_PAGE);
+    }
+
+    /**
+     * Edit a ping target (load edit view)
+     *
+     * @param mapping
+     * @param form
+     * @param req
+     * @param res
+     * @return the edit view with the form populated with the ping target specified by the id in the request.
+     * @throws Exception
+     */
+    public ActionForward editSelected(ActionMapping mapping, ActionForm form,
+                                      HttpServletRequest req, HttpServletResponse res)
+        throws Exception
+    {
+        ActionForward forward = mapping.findForward(PING_TARGET_EDIT_PAGE);
+        RollerRequest rreq = RollerRequest.getRollerRequest(req);
+        try
+        {
+            if (!hasRequiredRights(rreq))
+            {
+                return mapping.findForward(ACCESS_DENIED_PAGE);
+            }
+            PingTargetData pingTarget = select(rreq);
+            ((PingTargetForm) form).copyFrom(pingTarget, req.getLocale());
+            return forward;
+        }
+        catch (Exception e)
+        {
+            getLogger().error("ERROR in action", e);
+            throw new ServletException(e);
+        }
+    }
+
+    /**
+     * Delete a ping target (load delete confirmation view).
+     *
+     * @param mapping
+     * @param form
+     * @param req
+     * @param res
+     * @return the delete confirmation view with the form populated with the ping target specified by the id in the request.
+     * @throws Exception
+     */
+    public ActionForward deleteSelected(ActionMapping mapping, ActionForm form,
+                                        HttpServletRequest req, HttpServletResponse res)
+        throws Exception
+    {
+        ActionForward forward = mapping.findForward(PING_TARGET_DELETE_PAGE);
+        RollerRequest rreq = RollerRequest.getRollerRequest(req);
+        try
+        {
+            if (!hasRequiredRights(rreq))
+            {
+                return mapping.findForward(ACCESS_DENIED_PAGE);
+            }
+            PingTargetData pingTarget = select(rreq);
+            ((PingTargetForm) form).copyFrom(pingTarget, req.getLocale());
+            return forward;
+        }
+        catch (Exception e)
+        {
+            getLogger().error("ERROR in action", e);
+            throw new ServletException(e);
+        }
+    }
+
+    /**
+     * Delete a ping target (already confirmed).  This performs the actual deletion.
+     *
+     * @param mapping
+     * @param form
+     * @param req
+     * @param res
+     * @return the result of <code>view()</code> after the deletion
+     * @throws Exception
+     */
+    public ActionForward deleteConfirmed(ActionMapping mapping, ActionForm form,
+                                         HttpServletRequest req, HttpServletResponse res)
+        throws Exception
+    {
+        RollerRequest rreq = RollerRequest.getRollerRequest(req);
+        PingTargetForm pingTargetForm = (PingTargetForm) form;
+        PingTargetManager pingTargetMgr = rreq.getRoller().getPingTargetManager();
+        try
+        {
+            if (!hasRequiredRights(rreq))
+            {
+                return mapping.findForward(ACCESS_DENIED_PAGE);
+            }
+            String pingTargetId = pingTargetForm.getId();
+            if (pingTargetId == null || pingTargetId.length() == 0)
+            {
+                throw new RollerException("Missing ping target id.");
+            }
+            pingTargetMgr.removePingTarget(pingTargetId);
+            rreq.getRoller().commit();
+            return view(mapping, form, req, res);
+        }
+        catch (Exception e)
+        {
+            getLogger().error("ERROR in action", e);
+            throw new ServletException(e);
+        }
+    }
+
+    // TODO: Consider unifying with other RollerRequest methods
+    /*
+     * Helper to select the ping target specified by the id in the request.
+     * @param rreq
+     * @return the ping target specified by the id in the request
+     * @throws RollerException
+     */
+    private PingTargetData select(RollerRequest rreq) throws RollerException
+    {
+        String pingTargetId = rreq.getRequest().getParameter(RollerRequest.PINGTARGETID_KEY);
+        PingTargetManager pingTargetMgr = rreq.getRoller().getPingTargetManager();
+        if (pingTargetId == null || pingTargetId.length() == 0)
+        {
+            throw new RollerException("Missing ping target id: " + pingTargetId);
+        }
+
+        PingTargetData pingTarget = pingTargetMgr.retrievePingTarget(pingTargetId);
+        if (pingTarget == null)
+        {
+            throw new RollerException("No such ping target id: " + pingTargetId);
+        }
+        return pingTarget;
+    }
+
+    /*
+     * Private helper to validate a ping target.
+     * @param rreq       the request
+     * @param pingTarget the ping target to validate
+     * @return an <code>ActionMessages</code> object with <code>ActionMessage</code> for each error encountered, empty if no
+     * errors were encountered.
+     * @throws RollerException
+     */
+    private ActionMessages validate(RollerRequest rreq, PingTargetData pingTarget) throws RollerException
+    {
+        ActionMessages errors = new ActionMessages();
+
+        PingTargetManager pingTargetMgr = rreq.getRoller().getPingTargetManager();
+        if (!pingTargetMgr.isNameUnique(pingTarget))
+        {
+            errors.add(ActionMessages.GLOBAL_MESSAGE,
+                new ActionMessage("pingTarget.nameNotUnique"));
+        }
+        if (!pingTargetMgr.isUrlWellFormed(pingTarget))
+        {
+            errors.add(ActionMessages.GLOBAL_MESSAGE,
+                new ActionMessage("pingTarget.malformedUrl"));
+        } else if (!pingTargetMgr.isHostnameKnown(pingTarget))
+        {
+            errors.add(ActionMessages.GLOBAL_MESSAGE,
+                new ActionMessage("pingTarget.unknownHost"));
+        }
+        return errors;
+    }
+
+
+    /*
+     *  Helper defined by the subclass to determine if user has adequate rights for the action.
+     *  This and the {@link org.roller.pojos.PingTargetData#canSave()} method determine the access
+     *  control for the action.
+     */
+    protected abstract boolean hasRequiredRights(RollerRequest rreq) throws RollerException;
+
+    /*
+     * Get the logger from the concrete subclass
+     */
+    protected abstract Log getLogger();
+
+    /*
+     * Get the ping targets for the view.  This is implemented differently in the concrete subclasses.
+     */
+    protected abstract List getPingTargets(RollerRequest rreq) throws RollerException;
+
+
+    /*
+     * Create a new ping target (blank). This is implemented differently in the concrete subclasses.
+     */
+    protected abstract PingTargetData createPingTarget(RollerRequest rreq, PingTargetForm pingTargetForm) throws RollerException;
+}



Mime
View raw message