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 [11/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/model/BookmarkManager.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/model/BookmarkManager.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/model/BookmarkManager.java (added)
+++ incubator/roller/trunk/src/org/roller/model/BookmarkManager.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,167 @@
+
+package org.roller.model;
+
+import org.roller.RollerException;
+import org.roller.pojos.Assoc;
+import org.roller.pojos.BookmarkData;
+import org.roller.pojos.FolderData;
+import org.roller.pojos.WebsiteData;
+
+import java.util.List;
+import java.util.Set;
+
+
+/** 
+ * Interface to Bookmark Management. Provides methods for retrieving, storing,
+ * moving, removing and querying for folders and bookmarks.
+ * 
+ * @author David M Johnson
+ */
+public interface BookmarkManager
+{
+	//---------------------------------------------------------- Bookmark CRUD
+
+    /** Create new bookmark, NOT a persistent instance. */
+    public BookmarkData createBookmark();
+    
+    /** Create new bookmark, NOT a persistent instance. */
+    public BookmarkData createBookmark(
+        FolderData parent, 
+        String name, 
+        String desc, 
+        String url, 
+        String feedUrl,
+        Integer weight, 
+        Integer priority, 
+        String image) throws RollerException;
+
+    /** Retrieve bookmark by ID, a persistent instance. */
+    public BookmarkData retrieveBookmark(String id) throws RollerException;
+
+	/** Update or store bookmark object, becomes a persistent instance. */
+	//public void storeBookmark(BookmarkData data) throws RollerException;
+
+	/** Delete bookmark by ID. */
+	public void removeBookmark(String id) throws RollerException;
+
+	//------------------------------------------------------------ Folder CRUD 
+
+    /** Create new folder, NOT a persistent instance. */
+    public FolderData createFolder();
+    
+    /** Create new folder, NOT a persistent instance. */
+    public FolderData createFolder(
+        FolderData parent,
+        String name, 
+        String desc, 
+        WebsiteData website) throws RollerException;
+
+    /** Retrieve folder by ID, a persistent instance. */
+    public FolderData retrieveFolder(String id) throws RollerException;
+
+	/** Store folder object, becomes a persistent instance. */
+	//public void storeFolder(FolderData data) throws RollerException;
+
+	/** 
+     * Remove folder by ID, does not cascade to subfolders and bookmarks.
+     * You should instead use FolderData.remove() to remove a folder. 
+     */
+	//public void removeFolder(String id) throws RollerException;
+	
+    //------------------------------------------------------------- Operations
+
+    /** Import bookmarks from OPML string into specified folder. 
+      * @param site Website.
+      * @param folder Name of folder to hold bookmarks.
+      * @param opml OPML data to be imported. 
+      */
+    public void importBookmarks(WebsiteData site, String folder, String opml) 
+        throws RollerException;
+    
+	/** Move contents of folder to another folder.
+	  * @param src Source folder.
+	  * @param dest Destination folder.
+	  */
+	public void moveFolderContents(FolderData src, FolderData dest) 
+		throws RollerException;
+
+    public void deleteFolderContents(FolderData src) throws RollerException;
+    
+    //---------------------------------------------------------------- Queries 
+
+    /** Get all folders for a website.
+      * @param website Website.
+      */
+    public List getAllFolders(WebsiteData wd) throws RollerException;
+
+    /** Get top level folders for a website.
+      * @param website Website.
+      */
+    public FolderData getRootFolder(WebsiteData website) 
+        throws RollerException;
+
+	/** Get folder specified by website and folderPath. 
+	  * @param website Website of folder.
+	  * @param folderPath Path of folder, relative to folder root.
+	  */
+	public FolderData getFolder(WebsiteData website, String folderPath) 
+		throws RollerException;
+
+    /**
+     * Get absolute path to folder, appropriate for use by getFolderByPath().
+     * @param folder Folder.
+     * @return Forward slash separated path string.
+     */
+    public String getPath(FolderData folder) throws RollerException;
+
+    /**
+     * Get subfolder by path relative to specified folder.
+     * @param folder  Root of path or null to start at top of folder tree.
+     * @param path    Path of folder to be located.
+     * @param website Website of folders.
+     * @return FolderData specified by path or null if not found.
+     */
+    public FolderData getFolderByPath(
+        WebsiteData wd, FolderData folder, String string) 
+        throws RollerException;
+
+    /**
+     * @param folder
+     * @param ancestor
+     * @param relation
+     * @return
+     */
+    public Assoc createFolderAssoc(
+        FolderData folder, FolderData ancestor, String relation) 
+        throws RollerException;
+        
+    /**
+     * @param data
+     * @param subfolders
+     * @return
+     */
+    public List retrieveBookmarks(FolderData data, boolean subfolders)
+        throws RollerException;
+
+    /**
+     * Check duplicate folder name. 
+     */
+    public boolean isDuplicateFolderName(FolderData data) throws RollerException;
+
+    /**
+     */
+    public Assoc getFolderParentAssoc(FolderData data) throws RollerException;
+
+    /**
+     */
+    public List getFolderChildAssocs(FolderData data) throws RollerException;
+
+    /**
+     */
+    public List getAllFolderDecscendentAssocs(FolderData data) throws RollerException;
+
+    /**
+     */
+    public List getFolderAncestorAssocs(FolderData data) throws RollerException;
+}
+

Added: incubator/roller/trunk/src/org/roller/model/ConfigManager.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/model/ConfigManager.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/model/ConfigManager.java (added)
+++ incubator/roller/trunk/src/org/roller/model/ConfigManager.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,22 @@
+/*
+ * Created on Feb 4, 2004
+ */
+package org.roller.model;
+
+import org.roller.RollerException;
+import org.roller.pojos.RollerConfig;
+
+/**
+ * @author lance.lavandowska
+ */
+public interface ConfigManager {
+
+    /** Release any resources used */
+    public void release();
+
+    public void storeRollerConfig( RollerConfig data ) throws RollerException;
+    
+    public RollerConfig getRollerConfig() throws RollerException;
+    
+    public RollerConfig readFromFile(String filePath) throws RollerException;
+}

Added: incubator/roller/trunk/src/org/roller/model/ParsedRequest.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/model/ParsedRequest.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/model/ParsedRequest.java (added)
+++ incubator/roller/trunk/src/org/roller/model/ParsedRequest.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,32 @@
+
+package org.roller.model;
+import org.roller.pojos.WeblogEntryData;
+import org.roller.pojos.WebsiteData;
+
+/**
+ * Servlet API free interface that represents an incoming web request.
+ * @author David M Johnson
+ */
+public interface ParsedRequest
+{  
+    /** Get date specified by request as YYYYMMDD, or null */
+    public String getDateString();
+    
+    /** Get refering URL, or null. */
+    public String getRefererURL();
+    
+    /** Get request URL. */
+    public String getRequestURL();
+    
+    /** Get website specified by request, or null. */
+    public WebsiteData getWebsite();
+    
+    /** Get weblog entry specified by request, or null. */
+    public WeblogEntryData getWeblogEntry();
+    
+    /** Was date specified by request URL? */
+    public boolean isDateSpecified();
+
+    /** True if Linkback extraction is enabled */
+    public boolean isEnableLinkback();
+}
\ No newline at end of file

Added: incubator/roller/trunk/src/org/roller/model/RefererManager.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/model/RefererManager.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/model/RefererManager.java (added)
+++ incubator/roller/trunk/src/org/roller/model/RefererManager.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,117 @@
+
+package org.roller.model;
+import org.roller.RollerException;
+import org.roller.pojos.RefererData;
+import org.roller.pojos.WebsiteData;
+import org.roller.util.ThreadManager;
+
+import java.util.List;
+
+
+/////////////////////////////////////////////////////////////////////////////
+/**
+ * Interface to Referer management.
+ * @author David M Johnson
+ */
+public interface RefererManager
+{
+    //------------------------------------------ Access to Referer information
+
+    /**
+     * Get all referers for specified user.
+     * @param userName
+     * @return List of type RefererData
+     * @throws RollerException
+     */
+    public List getReferers(WebsiteData website)
+		throws RollerException;
+
+    /**
+     * Get all referers for specified user that were made today.
+     * @param userName Name of user.
+     * @return List of type RefererData
+     * @throws RollerException
+     */
+    public List getTodaysReferers(WebsiteData website)
+        throws RollerException;
+
+    /**
+     * Get referers for a specified date.
+     * @param userName Name of user.
+     * @param date YYYYMMDD format of day's date.
+     * @return List of type RefererData.
+     * @throws RollerException
+     */
+    public List getReferersToDate(WebsiteData website, String date)
+        throws RollerException;
+
+    /**
+     * Get most popular websites based on referer day hits.
+     * @return List of WebsiteDisplayData objects.
+     */
+    public List getDaysPopularWebsites(int max) throws RollerException;
+
+    /**
+     * Get referers that refer to a specific weblog entry.
+     * @param entryid Weblog entry ID
+     * @return List of RefererData objects.
+     * @throws RollerException
+     */
+    public List getReferersToEntry(String entryid)
+        throws RollerException;
+
+    /**
+     * Remove all referers for the specific weblog entry.
+	 * @param entryId Weblog entry ID
+	 * @throws RollerException
+     */
+    public void removeReferersForEntry(String entryid) throws RollerException;
+
+	/**
+	 * Get referers that refer to a specific weblog entry.
+	 * @param entryId Weblog entry ID
+	 * @param authorized Is the current user authorized to edit these Referers.
+	 * @return List of RefererData objects.
+	 * @throws RollerException
+	 */
+	public List getEntryReferers(String entryId, boolean authorized)
+		throws RollerException;
+
+    /** Get user's day hits */
+    public int getDayHits(WebsiteData website) throws RollerException;
+
+    /** Get user's all-time total hits */
+    public int getTotalHits(WebsiteData website) throws RollerException;
+
+    //--------------------------------------------- Referer processing methods
+
+    /**
+     * Process request for incoming referers.
+     * @param request Request to be processed.
+     */
+    public void processRequest(ParsedRequest request);
+
+    /**
+     * Set thread manager to be used.
+     * @param threadManager
+     */
+    public void setThreadManager(ThreadManager threadManager);
+
+    //---------------------------------------------- Referer tracking turnover
+
+    public void forceTurnover(String websiteId) throws RollerException;
+
+    public void checkForTurnover(boolean forceTurnover, String websiteId)
+            throws RollerException;
+
+    //----------------------------------------------- Standard manager methods
+
+    public RefererData retrieveReferer(String id)
+        throws RollerException;
+
+    public void removeReferer( String id )
+        throws RollerException;
+
+    public void release();
+}
+

Added: incubator/roller/trunk/src/org/roller/model/Roller.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/model/Roller.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/model/Roller.java (added)
+++ incubator/roller/trunk/src/org/roller/model/Roller.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,73 @@
+
+package org.roller.model;
+import org.roller.RollerException;
+import org.roller.business.PersistenceStrategy;
+
+import java.sql.Connection;
+
+/** The main entry point interface of the Roller business tier.
+ * @author David M Johnson
+ */
+public interface Roller
+{
+	/** Get UserManager associated with this Roller instance.
+     * @return UserManager associated with this Roller instance.
+     * @throws RollerException If unable to create or return UserManager.
+     */
+	public UserManager getUserManager() throws RollerException;
+
+	/** Get BookmarkManager associated with this Roller instance.
+     * @return BookmarkManager associated with this Roller instance.
+     * @throws RollerException If unable to create or return BookmarkManager.
+     */
+	public BookmarkManager getBookmarkManager() throws RollerException;
+
+	/** Get WeblogManager associated with this Roller instance.
+     * @return WeblogManager associated with this Roller instance.
+     * @throws RollerException If unable to create or return WeblogManager.
+     */
+	public WeblogManager getWeblogManager() throws RollerException;
+    
+	/** Get RefererManager associated with this Roller instance.
+	 * @return RefererManager associated with this Roller instance.
+	 * @throws RollerException If unable to create or return RefererManager.
+	 */	
+	public RefererManager getRefererManager() throws RollerException;
+    
+    /** Get RefererManager associated with this Roller instance.
+     * @return RefererManager associated with this Roller instance.
+     * @throws RollerException If unable to create or return RefererManager.
+     */ 
+    public ConfigManager getConfigManager() throws RollerException;
+    	
+    /** Begin transaction for a thread.
+     */ 
+    public void begin() throws RollerException;
+    
+    /** Commit transaction for a thread.
+     * @throws RollerException If database error is thrown.
+     */ 
+    public void commit() throws RollerException;
+    
+    /** Rollback uncommitted changes for a thread.
+     */ 
+    public void rollback();
+    
+    /** Rollback and release associated resources for a thread.
+     */ 
+    public void release();
+
+    /** Get persistence strategy used by managers and POJOs. */
+    public PersistenceStrategy getPersistenceStrategy();
+    
+    /** Repair websites if needed. */
+    public void upgradeDatabase(Connection con) throws RollerException;
+    
+    /**
+     * Release all resources necessary for this instance
+     * of Roller.
+     */
+    public void shutdown();
+    
+}
+

Added: incubator/roller/trunk/src/org/roller/model/RollerFactory.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/model/RollerFactory.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/model/RollerFactory.java (added)
+++ incubator/roller/trunk/src/org/roller/model/RollerFactory.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,99 @@
+package org.roller.model;
+

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.roller.RollerException;
import org.roller.util.StringUtils;
+
+/**
+ * This is primarily a static holder for whatever Roller implementation is 
+ * being used. RollerContext should call setRoller(ServletContext) during its 
+ * initialization so that the Roller implementation can be instantiated. 
+ * Likewise, RollerContext.getRoller() should be replaced with calls to 
+ * RollerFactory.getRoller(). This should prevent us any direct ties to 
+ * Castor and permit for experimentation* with other persistence frameworks.
+ * 
+ * @author llavandowska
+ */
+public abstract class RollerFactory
+{
+    private static final String DEFAULT_IMPL = 
+        "org.roller.business.hibernate.RollerImpl";
+    
+    private static Roller rollerInstance = null;
+
+    private static Log mLogger = 
+        LogFactory.getFactory().getInstance(RollerFactory.class);
+            
+    /**
+     * Let's just be doubling certain this class cannot be instantiated.
+     * @see java.lang.Object#Object()
+     */
+    private RollerFactory()
+    {
+        // hello all you beautiful people
+    }
+    
+    /**
+     * Static accessor for the instance of Roller
+     * held by this class.
+     * 
+     * @return Roller
+     */
+    public static Roller getRoller()
+    {
+		return rollerInstance;
+    }
+    
+    /**
+     * Looks up which implementation to use by the key ROLLER_IMPL_KEY and use
+     * reflection to call the implementation's instantiate(ServletContext ctx)
+     * method.  Should this fail (either no implementation is specified or
+     * instantiate() throws an Exception) than the DEFAULT_IMPL will be tried.
+     * If this should fail as well that is bad news!
+     * 
+     * @param rollerInstanceName The name of the Roller implementation class
+     * to instantiate.
+     * @param configData A string whose meaning is defined by the Roller
+     * implementation class being instantiated.
+     */
+    public static void setRoller(
+       String rollerInstanceName, String configData)
+    {
+        if (StringUtils.isEmpty( rollerInstanceName ))
+        {
+            rollerInstanceName = DEFAULT_IMPL;
+        }
+
+        try
+        {
+			Class factoryClass = Class.forName(rollerInstanceName);
+            java.lang.reflect.Method instanceMethod = 
+				factoryClass.getMethod("instantiate", 
+                	new Class[]{String.class});
+
+            rollerInstance = (Roller)instanceMethod.invoke( 
+				factoryClass, new Object[] {configData} );
+            
+            if (mLogger.isDebugEnabled()) 
+            {             
+                mLogger.debug("Using Roller impl: " + rollerInstanceName);
+            }
+        }
+        catch (Exception e)
+        {
+            mLogger.error("Error instantiating " + rollerInstanceName, e);
+            try 
+            {
+                rollerInstance = 
+                   org.roller.business.hibernate.RollerImpl.instantiate(configData);
+                mLogger.info("** Instantiating Hibernate RollerImpl **");
+            } 
+            catch (RollerException re) 
+            {
+                mLogger.warn("Unable to instantiate Hibernate RollerImpl", e);
+            }
+        }
+	}
+	
+	public static void setRoller(Roller roller)
+	{
+		if (roller != null) rollerInstance = roller;
+	}
+}

Added: incubator/roller/trunk/src/org/roller/model/RollerSpellCheck.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/model/RollerSpellCheck.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/model/RollerSpellCheck.java (added)
+++ incubator/roller/trunk/src/org/roller/model/RollerSpellCheck.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,117 @@
+package org.roller.model;
+
+import com.swabunga.spell.engine.SpellDictionary;
+import com.swabunga.spell.event.SpellCheckEvent;
+import com.swabunga.spell.event.SpellCheckListener;
+import com.swabunga.spell.event.SpellChecker;
+import com.swabunga.spell.event.StringWordTokenizer;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.roller.RollerException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
+/**
+ * Since this class cannot be thread-safe due to the
+ * SpellCheckListener interface, first a "canonical"
+ * SpellDictionary must be instantiated with the path
+ * to the dictionary.  Subsequently, call getInstance()
+ * which will return a new instance of RollerSpellCheck
+ * using the "precompiled" SpellDictionary, or will throw
+ * a NullPointerException.  A better way can
+ * probably be found.
+ **/
+public class RollerSpellCheck implements SpellCheckListener
+{
+    private static Log mLogger = 
+        LogFactory.getFactory().getInstance(RollerSpellCheck.class);
+        
+    private static SpellDictionary dictionary = null;
+
+    private SpellChecker spellCheck = null;
+    private ArrayList spellCheckEvents = new ArrayList();
+
+    /**
+     * Initializer which takes an InputStream for
+     * /WEB-INF/english.0 to load the SpellDictionary.
+     * Building the SpellDictionary, and thus the SpellChecker
+     * is an expensive operation.
+     * You can get this InputStream with ServletContext.getResource(
+     * "/WEB-INF/english.0").  Throws a RollerException if
+     * SpellDictionary cannot be instantiated.
+     **/
+    public static void init(InputStream in) throws RollerException
+    {
+        try {
+            InputStreamReader inR = new InputStreamReader( in );
+            RollerSpellCheck.dictionary = new SpellDictionary( inR );
+
+        } catch (IOException ioe) {
+            mLogger.error("RollerSpellCheck unable to load SpellDictionary",
+                ioe);
+            throw new RollerException(ioe);
+        }
+    }
+
+    /**
+     * Private constructor taking a prebuilt SpellChecker
+     * as an argument.
+     **/
+    private RollerSpellCheck()
+    {
+        spellCheck = new SpellChecker(dictionary);
+        spellCheck.addSpellCheckListener(this);
+    }
+
+    /**
+     * Returns a new instance of RollerSpellCheck, using
+     * the (hopefully) prebuilt SpellChecker.
+     **/
+    public static RollerSpellCheck getInstance() throws RollerException
+    {
+        if (RollerSpellCheck.dictionary == null)
+        {
+            throw new RollerException(
+                "RollerSpellCheck.SpellDictionary has not been defined");
+        }
+
+        return new RollerSpellCheck();
+    }
+
+    /**
+     * Fulfills interface SpellCheckListener.
+     * SpellCheckEvent is placed into the ArrayList
+     * spellCheckEvents held by this RollerSpellCheck.
+     **/
+    public void spellingError(SpellCheckEvent event)
+    {
+        spellCheckEvents.add( event );
+    }
+
+    /**
+     * This is the method to check spelling.
+     * The submitted String is "parsed" by SpellChecker,
+     * SpellCheckEvents are placed into an ArrayList, which
+     * is returned to the caller.  A SpellCheckEvent contains
+     * the "suspect" word, and a LinkedList of suggested replacements.
+     */
+    public ArrayList checkSpelling(String str) throws RollerException
+    {
+        spellCheck.checkSpelling( new StringWordTokenizer(str) );
+        return spellCheckEvents;
+    }
+
+    /**
+     * Convenience method. Creates a RollerSpellCheck object
+     * and calls checkSpelling(str) on it, returning the ArrayList.
+     */
+    public static ArrayList getSpellingErrors(String str) throws RollerException
+    {
+        RollerSpellCheck rCheck = RollerSpellCheck.getInstance();
+        return rCheck.checkSpelling(str);
+    }
+}
\ No newline at end of file

Added: incubator/roller/trunk/src/org/roller/model/UserManager.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/model/UserManager.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/model/UserManager.java (added)
+++ incubator/roller/trunk/src/org/roller/model/UserManager.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,125 @@
+
+package org.roller.model;
+
+import org.roller.RollerException;
+import org.roller.pojos.PageData;
+import org.roller.pojos.RoleData;
+import org.roller.pojos.UserData;
+import org.roller.pojos.WebsiteData;
+
+import java.util.Map;
+import java.util.List;
+
+
+/**
+ * Manages storage, retrieval, and querying of user, website, and page data.
+ * 
+ * @author David M Johnson
+ */
+public interface UserManager
+{
+    /** Release any resources used */
+    public void release();
+    
+    //--------------------------------------------------------------- UserData
+    
+    /** Get all enabled users */
+    public List getUsers() throws RollerException;
+    
+	/** Get all users, optionally include dis-enabled users */
+	public List getUsers(boolean enabledOnly) throws RollerException;
+
+    /** Get user object by user name (only enabled users) */
+    public UserData getUser( String userName ) throws RollerException;
+
+	/** Get user object by user name, optionally include dis-enabled users */
+	public UserData getUser( String userName, boolean enabledOnly ) throws RollerException;
+
+    /** Add a new user with pages, bookmarks, folders...
+     * @param user New user object to be added to database
+     * @param themeDir Directory containing theme for user
+     */
+    public void addUser( UserData user, Map page, String theme,
+            String locale, String timezone)
+        throws RollerException;
+
+    public UserData retrieveUser(String id)throws RollerException;
+    public void storeUser( UserData data ) throws RollerException;
+
+    public List getUserRoles(UserData user) throws RollerException;
+    public RoleData retrieveRole(String id) throws RollerException;
+    public void storeRole( RoleData data ) throws RollerException;
+    public void removeRole( String id ) throws RollerException;
+
+    //------------------------------------------------------------ WebsiteData
+    
+    /** Get website object by user name */
+    public WebsiteData getWebsite(String userName) throws RollerException;
+	public WebsiteData getWebsite(String userName, boolean enabledOnly) throws RollerException;
+
+    public WebsiteData retrieveWebsite(String id) throws RollerException;
+    public void storeWebsite(WebsiteData data) throws RollerException;
+    public void removeWebsite(String id) throws RollerException;
+
+    //--------------------------------------------------------------- PageData
+    
+    /** Get user's page by name */
+    public PageData getPageByName(WebsiteData w, String p) throws RollerException;
+
+    /** Get user's page by link */
+    public PageData getPageByLink(WebsiteData w, String p) throws RollerException;
+
+    /** Fix page link using page name */
+    public String fixPageLink(PageData data) throws RollerException;
+
+    /** Get users pages */
+    public List getPages(WebsiteData w) throws RollerException;
+
+    public PageData retrievePage(String id) throws RollerException;
+    public void storePage(PageData data) throws RollerException;
+    public void removePage(String id) throws RollerException;
+
+	/**
+	 * Retrieve the Page in read-only mode (does hibernate support this?).
+	 */
+	public PageData retrievePageReadOnly(String id) throws RollerException;
+    
+    /**
+     * Validates a user based on a cookie value.  If successful, it returns
+     * a new cookie String.  If not, then it returns null.
+     * 
+     * @param value (in format username|guid)
+     * @return indicator that this is a valid login
+     * @throws Exception
+     */
+    public String checkLoginCookie(String value) throws RollerException;
+ 
+    /**
+     * Creates a cookie string using a username - designed for use when
+     * a user logs in and wants to be remembered.
+     * 
+     * @param username
+     * @return String to put in a cookie for remembering user
+     * @throws Exception
+     */
+    public String createLoginCookie(String username) throws RollerException;
+    
+    /**
+     * Deletes all cookies for user.
+     * @param username
+     */
+    public void removeLoginCookies(String username) throws RollerException;
+
+    /**
+     * Remove website(s) associated with user.
+     */
+    public void removeUserWebsites(UserData data) throws RollerException;
+
+    /**
+     * Remove contents of website.
+     */
+    public void removeWebsiteContents(WebsiteData data) throws RollerException;
+}
+
+
+

Added: incubator/roller/trunk/src/org/roller/model/WeblogManager.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/model/WeblogManager.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/model/WeblogManager.java (added)
+++ incubator/roller/trunk/src/org/roller/model/WeblogManager.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,304 @@
+
+package org.roller.model;
+import org.roller.RollerException;
+import org.roller.pojos.Assoc;
+import org.roller.pojos.CommentData;
+import org.roller.pojos.WeblogCategoryAssoc;
+import org.roller.pojos.WeblogCategoryData;
+import org.roller.pojos.WeblogEntryData;
+import org.roller.pojos.WebsiteData;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Interface to Weblog Management.
+ */
+public interface WeblogManager
+{
+    public static final String CATEGORY_ATT = "category.att";
+    
+    public static final String ALL = "ALL";
+    public static final String DRAFT_ONLY = "DRAFT_ONLY";
+    public static final String PUB_ONLY = "PUB_ONLY";
+    
+    public void release();
+
+    //------------------------------------------------ WeblogCategoryData CRUD
+
+    /** Create new weblog category, NOT a persistent instance. */
+    public WeblogCategoryData createWeblogCategory();
+
+    /** Create new weblog category, NOT a persistent instance. */
+    public WeblogCategoryData createWeblogCategory(
+        WebsiteData website,
+        WeblogCategoryData parent,
+        String name,
+        String description,
+        String image) throws RollerException;
+
+    public WeblogCategoryData retrieveWeblogCategory(String id)
+        throws RollerException;
+
+    public void moveWeblogCategoryContents(String srcId, String destId)
+        throws RollerException;
+
+    //--------------------------------------------- WeblogCategoryData Queries
+
+    /** Get WebLogCategory objects for a website. */
+    public List getWeblogCategories(WebsiteData website)
+        throws RollerException;
+
+    /** Get WebLogCategory objects for a website. */
+    public List getWeblogCategories(WebsiteData website, boolean includeRoot)
+        throws RollerException;
+
+    /** 
+     * Get top level categories for a website.
+     * @param website Website.
+     */
+    public WeblogCategoryData getRootWeblogCategory(WebsiteData website)
+        throws RollerException;
+
+    /**
+     * Get absolute path to category, appropriate for use by getWeblogCategoryByPath().
+     * @param category WeblogCategoryData.
+     * @return         Forward slash separated path string.
+     */
+    public String getPath(WeblogCategoryData category) throws RollerException;
+
+    /** 
+     * Get category specified by website and categoryPath.
+     * @param website      Website of WeblogCategory.
+     * @param categoryPath Path of WeblogCategory, relative to category root.
+     */
+   public WeblogCategoryData getWeblogCategoryByPath(
+       WebsiteData website, String categoryPath)
+       throws RollerException;
+
+    /**
+     * Get sub-category by path relative to specified category.
+     * @param category  Root of path or null to start at top of category tree.
+     * @param path      Path of category to be located.
+     * @param website   Website of categories.
+     * @return          Category specified by path or null if not found.
+     */
+    public WeblogCategoryData getWeblogCategoryByPath(
+        WebsiteData wd, WeblogCategoryData category, String string)
+        throws RollerException;
+
+    //----------------------------------------------- WeblogCategoryAssoc CRUD
+
+    /** Create new weblog category assoc, NOT a persistent instance. */
+    public WeblogCategoryAssoc createWeblogCategoryAssoc();
+
+    /** Create new weblog category assoc, NOT a persistent instance. */
+    public WeblogCategoryAssoc createWeblogCategoryAssoc(
+        WeblogCategoryData category,
+        WeblogCategoryData ancestor,
+        String relation) throws RollerException;
+
+    public WeblogCategoryAssoc retrieveWeblogCategoryAssoc(String id)
+        throws RollerException;
+
+    //------------------------------------------------------- CommentData CRUD
+
+    public CommentData retrieveComment(String id)
+        throws RollerException;
+
+    public abstract List getComments( String entryId )
+        throws RollerException;
+
+    public abstract List getComments( String entryId, boolean nospam )
+        throws RollerException;
+
+    public void removeComment( String id )
+        throws RollerException;
+
+    public void removeComments( String[] ids )
+        throws RollerException;
+
+    public void removeCommentsForEntry(String entryId)
+    	throws RollerException;
+    
+    public List getRecentComments(WebsiteData website, int maxCount) 
+        throws RollerException;
+
+    //------------------------------------------------------- WeblogEntry CRUD
+
+    public WeblogEntryData retrieveWeblogEntry(String id)
+        throws RollerException;
+
+    public void removeWeblogEntry( String id )
+        throws RollerException;
+
+    //------------------------------------------------ WeblogEntryData Queries
+
+    /**
+     * Get WeblogEntries as a list in reverse chronological order.
+     * 
+     * @param userName   User name or null to get for all users.
+     * @param startDate  Start date or null for no start date.
+     * @param endDate    End date or null for no end date.
+     * @param catName    Category path or null for all categories.
+     * @param status     Status of ALL, DRAFT_ONLY, or PUB_ONLY.
+     * @param maxEntries Max entries or null for no limit.
+     * @return List of WeblogEntryData objects in reverse chrono order.
+     * @throws RollerException
+     */
+    public List getWeblogEntries(
+                    WebsiteData website, 
+                    Date    startDate, 
+                    Date    endDate, 
+                    String  catName, 
+                    String  status,
+                    Integer maxEntries)
+                    throws RollerException;
+    
+    /**
+     * Get Weblog Entries grouped by day. This method returns a Map that 
+     * contains Lists, each List contains WeblogEntryData objects, and the 
+     * Lists are keyed by Date objects.
+     * 
+     * @param userName   User name or null to get for all users.
+     * @param startDate  Start date or null for no start date.
+     * @param endDate    End date or null for no end date.
+     * @param catName    Category path or null for all categories.
+     * @param status     Status of ALL, DRAFT_ONLY, or PUB_ONLY.
+     * @param maxEntries Max entries or null for no limit.
+     * @return Map of Lists, keyed by Date, and containing WeblogEntryData.
+     * @throws RollerException
+     */
+    public Map getWeblogEntryObjectMap(
+                    WebsiteData website, 
+                    Date    startDate, 
+                    Date    endDate, 
+                    String  catName, 
+                    String  status,
+                    Integer maxEntries)
+                    throws RollerException;
+
+    /**
+     * Get Weblog Entry date strings grouped by day. This method returns a Map 
+     * that contains Lists, each List contains YYYYMMDD date strings objects, 
+     * and the Lists are keyed by Date objects.
+     * 
+     * @param userName   User name or null to get for all users.
+     * @param startDate  Start date or null for no start date.
+     * @param endDate    End date or null for no end date.
+     * @param catName    Category path or null for all categories.
+     * @param status     Status of ALL, DRAFT_ONLY, or PUB_ONLY.
+     * @param maxEntries Max entries or null for no limit.
+     * @return Map of Lists, keyed by Date, and containing date strings.
+     * @throws RollerException
+     */
+    public Map getWeblogEntryStringMap(
+                    WebsiteData website, 
+                    Date    startDate, 
+                    Date    endDate, 
+                    String  catName, 
+                    String  status,
+                    Integer maxEntries)
+                    throws RollerException;
+
+    /**
+     * Get weblog entries with given category or, optionally, any sub-category
+     * of that category.
+     * @param cat     Category.
+     * @param subcats True if sub-categories are to be fetched.
+     * @return        List of weblog entries in category.
+     */
+    public List retrieveWeblogEntries(WeblogCategoryData cat, boolean subcats)
+        throws RollerException;
+
+    /**
+     * Get the WeblogEntry following, chronologically, the current entry.  
+     * Restrict by the Category, if named.
+     * 
+     * @param current The "current" WeblogEntryData.
+     * @param catName The value of the requested Category Name.
+     * @return
+     */
+    public WeblogEntryData getNextEntry(WeblogEntryData current, String catName) 
+        throws RollerException;
+
+    /**
+     * Get the WeblogEntry prior to, chronologically, the current entry.
+     * Restrict by the Category, if named.
+     * 
+     * @param current The "current" WeblogEntryData.
+     * @param catName The value of the requested Category Name.
+     * @return
+     */
+    public WeblogEntryData getPreviousEntry(WeblogEntryData current, String catName) 
+        throws RollerException;
+    
+    /**
+     * Get specified number of most recent pinned and published Weblog Entries.
+     * @param max Maximum number to return.
+     * @return Collection of WeblogEntryData objects.
+     */
+    public List getWeblogEntriesPinnedToMain(Integer max) 
+        throws RollerException;
+
+    /** Get weblog entry by anchor. */
+    public WeblogEntryData getWeblogEntryByAnchor(
+        WebsiteData website, String anchor ) throws RollerException;
+
+    /** Get time of last update for a weblog specified by username */
+    public Date getWeblogLastPublishTime( String userName )
+        throws RollerException;
+
+    /**
+     * Gets the Date of the latest Entry publish time.
+     * @param userName User name of weblog or null for all users
+     * @param catName  Top-level category name of posts or null for all categories.
+     * @return         Date Of last publish time
+     * @throws         RollerException
+     */
+    public Date getWeblogLastPublishTime( String userName, String catName )
+        throws RollerException;
+
+    /**
+     * Remove WeblogEntry contents.
+     */
+    public void removeWeblogEntryContents(WeblogEntryData data) 
+        throws RollerException;
+
+    /**
+     * Create unique anchor for weblog entry.
+     */
+    public String createAnchor(WeblogEntryData data)
+        throws RollerException;
+
+    /**
+     * Check for duplicate category name.
+     */
+    public boolean isDuplicateWeblogCategoryName(WeblogCategoryData data)
+        throws RollerException;
+
+    /**
+     * Check if weblog category is in use.
+     */
+    public boolean isWeblogCategoryInUse(WeblogCategoryData data)
+        throws RollerException;
+    
+    /**
+     */
+    public Assoc getWeblogCategoryParentAssoc(WeblogCategoryData data) throws RollerException;
+
+    /**
+     */
+    public List getWeblogCategoryChildAssocs(WeblogCategoryData data) throws RollerException;
+
+    /**
+     */
+    public List getAllWeblogCategoryDecscendentAssocs(WeblogCategoryData data) throws RollerException;
+
+    /**
+     */
+    public List getWeblogCategoryAncestorAssocs(WeblogCategoryData data) throws RollerException;
+}
+

Added: incubator/roller/trunk/src/org/roller/model/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/model/package.html?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/model/package.html (added)
+++ incubator/roller/trunk/src/org/roller/model/package.html Wed Jun  8 09:06:16 2005
@@ -0,0 +1,25 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title></title>
+</head>
+<body>
+
+<p>This package defines the Roller Business Tier interfaces.</p>
+
+<p>This package depends on only these packages:</p>
+<ul>
+<li>org.roller.pojos.*</li>
+<li>com.swabunga.spell.*</li>
+<li>org.apache.commons.logging.*</li>
+</ul>
+
+<p>These packages depend on this package:</p>
+<ul>
+<li>org.roller.presentation.*</li>
+<li>org.roller.business.*</li>
+<li>org.roller.pojos.*</li>
+</ul>
+
+</body>
+</html>

Added: incubator/roller/trunk/src/org/roller/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/package.html?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/package.html (added)
+++ incubator/roller/trunk/src/org/roller/package.html Wed Jun  8 09:06:16 2005
@@ -0,0 +1,32 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title></title>
+</head>
+<body>
+<p>Roller is split into a number of top level packages and these packages can 
+be grouped as follows:</p>
+
+<b>Business Layer</b>
+<ul>
+<li>org.roller.model - Interfaces that define various Roller manager classes.</li>
+<li>org.roller.pojos - Domain objects and other persistent objects.</li>
+<li>org.roller.business - Impementations of the Roller org.roller.model interfaces.</li>
+</ul>
+
+<b>Presentation Layer</b>
+<ul>
+<li>org.roller.presentation - Roller's Web UI and Web Services implementations.</li>
+</ul>
+
+
+<b>Other...</b>
+<ul>
+<li>org.roller.util - General purpose utility classes, mostly independent of Roller.</li>
+<li>org.roller.persistence - Persistence abstraction allows Roller to use either 
+Castor or Hibernate.</li>
+<li></li>
+</ul>
+
+</body>
+</html>

Added: incubator/roller/trunk/src/org/roller/pojos/Assoc.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/Assoc.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/pojos/Assoc.java (added)
+++ incubator/roller/trunk/src/org/roller/pojos/Assoc.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,33 @@
+/*
+ * Created on Jan 13, 2004
+ */
+package org.roller.pojos;
+
+import org.roller.RollerException;
+
+/**
+ * Interface for hierarchical assocations.
+ * @author David M Johnson
+ */
+public interface Assoc
+{
+    public static final String PARENT = "PARENT";
+    public static final String GRANDPARENT = "GRANDPARENT";
+
+    /** Object that owns this association. */
+    public HierarchicalPersistentObject getObject();
+    public void setObject(HierarchicalPersistentObject hpo);
+    
+    /** Associated object. */
+    public HierarchicalPersistentObject getAncestor(); 
+    public void setAncestor(HierarchicalPersistentObject hpo); 
+    
+    /** Type of relationship, PARENT or GRANDPARENT. */   
+    public String getRelation();
+    
+    /** Save association. */
+    public abstract void save() throws RollerException;
+    
+    /** Remove association. */
+    public abstract void remove() throws RollerException;
+}

Added: incubator/roller/trunk/src/org/roller/pojos/BookmarkComparator.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/BookmarkComparator.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/pojos/BookmarkComparator.java (added)
+++ incubator/roller/trunk/src/org/roller/pojos/BookmarkComparator.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,32 @@
+package org.roller.pojos;
+
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+public class BookmarkComparator implements Comparator, Serializable
+{
+    public int compare(Object val1, Object val2)
+    throws ClassCastException
+    {
+        BookmarkData bd1 = (BookmarkData)val1;
+        BookmarkData bd2 = (BookmarkData)val2;
+        int priority1 = bd1.getPriority().intValue();
+        int priority2 = bd2.getPriority().intValue();
+
+        if (priority1 > priority2)
+        {
+            return 1;
+        }
+        else if (priority1 < priority2)
+        {
+            return -1;
+        }
+
+        // if priorities are the same, return
+        // results of String.compareTo()
+        return bd1.getName().compareTo(bd2.getName());
+
+    }
+
+}

Added: incubator/roller/trunk/src/org/roller/pojos/BookmarkData.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/BookmarkData.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/pojos/BookmarkData.java (added)
+++ incubator/roller/trunk/src/org/roller/pojos/BookmarkData.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,416 @@
+package org.roller.pojos;
+
+import org.roller.RollerException;
+import org.roller.business.PersistenceStrategy;
+import org.roller.model.BookmarkManager;
+import org.roller.model.RollerFactory;
+
+import java.io.Serializable;
+
+/**
+ * <p>Represents a single URL in a user's favorite web-bookmarks collection.
+ * Don't construct one of these yourself, instead use the create method in 
+ * the your BookmarkManager implementation.</p>
+ *
+ * @ejb:bean name="BookmarkData"
+ * 
+ * @struts.form include-all="true"
+ *    extends="org.apache.struts.validator.ValidatorForm"
+ * 
+ * @hibernate.class table="bookmark"
+ * hibernate.jcs-cache usage="read-write" 
+ */
+public class BookmarkData extends org.roller.pojos.PersistentObject
+    implements Serializable, Comparable
+{
+    static final long serialVersionUID = 2315131256728236003L;
+    
+    protected FolderData folder;
+
+    protected String id = null;
+    protected String name;
+    protected String description;
+    protected String url;
+    protected Integer weight;
+    protected Integer priority;
+    protected String image;
+    protected String feedUrl;  
+    
+    protected BookmarkManager bookmarkManager = null;
+
+    //----------------------------------------------------------- Constructors
+    
+    /** Default constructor, for use in form beans only. */
+    public BookmarkData()
+    {
+    }
+    
+    public BookmarkData(
+        FolderData parent,
+        String name, 
+        String desc, 
+        String url, 
+        String feedUrl,
+        Integer weight, 
+        Integer priority, 
+        String image)
+    {
+        this.folder = parent;
+        this.name = name;
+        this.description = desc;
+        this.url = url;
+        this.feedUrl = feedUrl;
+        this.weight = weight;
+        this.priority = priority;
+        this.image = image;   
+    }
+
+    /** For use by BookmarkManager implementations only. */
+    public BookmarkData(BookmarkManager bmgr)
+    {
+        bookmarkManager = bmgr;
+    }
+
+    //------------------------------------------------------------- Attributes
+    
+    /** 
+     * @ejb:persistent-field 
+     * 
+     * @hibernate.id column="id" type="string"
+     *     generator-class="uuid.hex" unsaved-value="null"
+     */
+    public String getId()
+    {
+        return this.id;
+    }
+
+    /** @ejb:persistent-field */
+    public void setId(String id)
+    {
+        this.id = id;
+    }
+
+    /** 
+     * Name of bookmark.
+     * 
+     * @struts.validator type="required" msgkey="errors.required"
+     * @struts.validator-args arg0resource="bookmarkForm.name"
+     * 
+     * @ejb:persistent-field 
+     * 
+     * @hibernate.property column="name" non-null="true" unique="false"
+     */
+    public String getName()
+    {
+        return this.name;
+    }
+
+    /** @ejb:persistent-field */
+    public void setName(String name)
+    {
+        this.name = name;
+    }
+
+    /** 
+     * Description of bookmark.
+     * 
+     * @ejb:persistent-field 
+     * 
+     * @hibernate.property column="description" non-null="true" unique="false"
+     */
+    public String getDescription()
+    {
+        return this.description;
+    }
+
+    /** @ejb:persistent-field */
+    public void setDescription(String description)
+    {
+        this.description = description;
+    }
+
+    /** 
+     * URL of bookmark.
+     * 
+     * @ejb:persistent-field 
+     * 
+     * @hibernate.property column="url" non-null="true" unique="false"
+     */
+    public String getUrl()
+    {
+        return this.url;
+    }
+
+    /** @ejb:persistent-field */
+    public void setUrl(String url)
+    {
+        this.url = url;
+    }
+
+    /** 
+     * Weight indicates prominence of link
+     * 
+     * @struts.validator type="required" msgkey="errors.required"
+     * @struts.validator type="integer" msgkey="errors.integer"
+     * @struts.validator-args arg0resource="bookmarkForm.weight"
+     * 
+     * @ejb:persistent-field 
+     * 
+     * @hibernate.property column="weight" non-null="true" unique="false"
+     */
+    public java.lang.Integer getWeight()
+    {
+        return this.weight;
+    }
+
+    /** @ejb:persistent-field */
+    public void setWeight(java.lang.Integer weight)
+    {
+        this.weight = weight;
+    }
+
+    /** 
+     * Priority determines order of display 
+     * 
+     * @struts.validator type="required" msgkey="errors.required"
+     * @struts.validator type="integer" msgkey="errors.integer"
+     * @struts.validator-args arg0resource="bookmarkForm.priority"
+     * 
+     * @ejb:persistent-field 
+     * 
+     * @hibernate.property column="priority" non-null="true" unique="false"
+     */
+    public java.lang.Integer getPriority()
+    {
+        return this.priority;
+    }
+
+    /** @ejb:persistent-field */
+    public void setPriority(java.lang.Integer priority)
+    {
+        this.priority = priority;
+    }
+
+    /** 
+     * @ejb:persistent-field 
+     * 
+     * @hibernate.property column="image" non-null="true" unique="false"
+     */
+    public String getImage()
+    {
+        return this.image;
+    }
+
+    /** @ejb:persistent-field */
+    public void setImage(String image)
+    {
+        this.image = image;
+    }
+
+    /** 
+     * @ejb:persistent-field 
+     * 
+     * @hibernate.property column="feedurl" non-null="true" unique="false"
+     */
+    public String getFeedUrl()
+    {
+        return this.feedUrl;
+    }
+
+    /** @ejb:persistent-field */
+    public void setFeedUrl(String feedUrl)
+    {
+        this.feedUrl = feedUrl;
+    }
+
+    //---------------------------------------------------------- Relationships
+    
+    /** 
+     * @ejb:persistent-field 
+     * 
+     * @hibernate.many-to-one column="folderid" cascade="none" not-null="true"
+     */
+    public org.roller.pojos.FolderData getFolder()
+    {
+        return this.folder;
+    }
+
+    /** @ejb:persistent-field */
+    public void setFolder(org.roller.pojos.FolderData folder)
+    {
+        this.folder = folder;
+    }
+
+    //------------------------------------------------------- Good citizenship
+
+    public String toString()
+    {
+        StringBuffer str = new StringBuffer("{");
+
+        str.append("id=" + id + " " + "name=" + name + " " + "description=" + 
+                   description + " " + "url=" + url + " " + "weight=" + 
+                   weight + " " + "priority=" + priority + " " + "folderId=" + 
+                   "image=" + image + " " + "feedUrl=" + 
+                   feedUrl);
+        str.append('}');
+
+        return (str.toString());
+    }
+
+    public boolean equals(Object pOther)
+    {
+        if (pOther instanceof BookmarkData)
+        {
+            BookmarkData lTest = (BookmarkData) pOther;
+            boolean lEquals = true;
+
+            if (this.id == null)
+            {
+                lEquals = lEquals && (lTest.id == null);
+            }
+            else
+            {
+                lEquals = lEquals && this.id.equals(lTest.id);
+            }
+
+            if (this.name == null)
+            {
+                lEquals = lEquals && (lTest.name == null);
+            }
+            else
+            {
+                lEquals = lEquals && this.name.equals(lTest.name);
+            }
+
+            if (this.description == null)
+            {
+                lEquals = lEquals && (lTest.description == null);
+            }
+            else
+            {
+                lEquals = lEquals && 
+                          this.description.equals(lTest.description);
+            }
+
+            if (this.url == null)
+            {
+                lEquals = lEquals && (lTest.url == null);
+            }
+            else
+            {
+                lEquals = lEquals && this.url.equals(lTest.url);
+            }
+
+            if (this.weight == null)
+            {
+                lEquals = lEquals && (lTest.weight == null);
+            }
+            else
+            {
+                lEquals = lEquals && this.weight.equals(lTest.weight);
+            }
+
+            if (this.priority == null)
+            {
+                lEquals = lEquals && (lTest.priority == null);
+            }
+            else
+            {
+                lEquals = lEquals && this.priority.equals(lTest.priority);
+            }
+
+//            if (this.mFolder == null)
+//            {
+//                lEquals = lEquals && (lTest.mFolder == null);
+//            }
+//            else
+//            {
+//                lEquals = lEquals && this.mFolder.equals(lTest.mFolder);
+//            }
+//
+            if (this.image == null)
+            {
+                lEquals = lEquals && (lTest.image == null);
+            }
+            else
+            {
+                lEquals = lEquals && this.image.equals(lTest.image);
+            }
+
+            if (this.feedUrl == null)
+            {
+                lEquals = lEquals && (lTest.feedUrl == null);
+            }
+            else
+            {
+                lEquals = lEquals && this.feedUrl.equals(lTest.feedUrl);
+            }
+
+            return lEquals;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+    public int hashCode()
+    {
+        int result = 17;
+        result = (37 * result) + 
+                 ((this.id != null) ? this.id.hashCode() : 0);
+        result = (37 * result) + 
+                 ((this.name != null) ? this.name.hashCode() : 0);
+        result = (37 * result) + 
+                 ((this.description != null) ? this.description.hashCode() : 0);
+        result = (37 * result) + 
+                 ((this.url != null) ? this.url.hashCode() : 0);
+        result = (37 * result) + 
+                 ((this.weight != null) ? this.weight.hashCode() : 0);
+        result = (37 * result) + 
+                 ((this.priority != null) ? this.priority.hashCode() : 0);
+        result = (37 * result) + 
+                 ((this.folder != null) ? this.folder.hashCode() : 0);
+        result = (37 * result) + 
+                 ((this.image != null) ? this.image.hashCode() : 0);
+        result = (37 * result) + 
+                 ((this.feedUrl != null) ? this.feedUrl.hashCode() : 0);
+
+        return result;
+    }
+
+    /**
+     * Setter is needed in RollerImpl.storePersistentObject()
+     */
+    public void setData(org.roller.pojos.PersistentObject otherData)
+    {
+        this.id = ((BookmarkData) otherData).id;
+        this.name = ((BookmarkData) otherData).name;
+        this.description = ((BookmarkData) otherData).description;
+        this.url = ((BookmarkData) otherData).url;
+        this.weight = ((BookmarkData) otherData).weight;
+        this.priority = ((BookmarkData) otherData).priority;
+        this.folder = ((BookmarkData) otherData).folder;
+        this.image = ((BookmarkData) otherData).image;
+        this.feedUrl = ((BookmarkData) otherData).feedUrl;
+    }
+
+    /** 
+     * @see java.lang.Comparable#compareTo(java.lang.Object)
+     */
+    public int compareTo(Object o)
+    {
+        return bookmarkComparator.compare(this, o);
+    }
+    
+    private BookmarkComparator bookmarkComparator = new BookmarkComparator();
+
+    /**
+     * @param impl
+     */
+    public void setBookmarkManager(BookmarkManager bmgr)
+    {
+        bookmarkManager = bmgr;
+    }
+
+}
\ No newline at end of file

Added: incubator/roller/trunk/src/org/roller/pojos/CommentData.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/CommentData.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/pojos/CommentData.java (added)
+++ incubator/roller/trunk/src/org/roller/pojos/CommentData.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,278 @@
+package org.roller.pojos;
+
+import org.roller.util.PojoUtil;
+
+/**
+ * Weblogentry Comment bean.
+ * @author Lance Lavandowska
+ *
+ * @ejb:bean name="CommentData"
+ * @struts.form include-all="true"
+ * 
+ * @hibernate.class table="comment"  
+ * hibernate.jcs-cache usage="read-write"
+ */
+public class CommentData extends org.roller.pojos.PersistentObject
+    implements java.io.Serializable
+{
+    static final long serialVersionUID = -6668122596726478462L;
+    protected java.lang.String id;
+    protected java.lang.String name;
+    protected java.lang.String email;
+    protected java.lang.String url;
+    protected java.lang.String content;
+    protected java.sql.Timestamp postTime;
+    protected WeblogEntryData mWeblogEntry;
+    protected Boolean spam;
+	protected String remoteHost;
+
+    public CommentData()
+    {
+        spam = Boolean.FALSE;
+    }
+
+    public CommentData(java.lang.String id, WeblogEntryData entry, 
+                       java.lang.String name, java.lang.String email, 
+                       java.lang.String url, java.lang.String content, 
+                       java.sql.Timestamp postTime, Boolean spam)
+    {
+        this.id = id;
+        this.name = name;
+        this.email = email;
+        this.url = url;
+        this.content = content;
+        this.postTime = postTime;
+        this.spam = spam;
+
+        mWeblogEntry = entry;
+    }
+
+    public CommentData(CommentData otherData)
+    {
+        this.id = otherData.id;
+        this.name = otherData.name;
+        this.email = otherData.email;
+        this.url = otherData.url;
+        this.content = otherData.content;
+        this.postTime = otherData.postTime;
+        this.spam = otherData.spam;
+        
+        mWeblogEntry = otherData.mWeblogEntry;
+    }
+
+    /** 
+     * @ejb:persistent-field 
+     * @hibernate.id column="id" type="string"
+     *  generator-class="uuid.hex" unsaved-value="null"
+     */
+    public java.lang.String getId()
+    {
+        return this.id;
+    }
+
+    /** @ejb:persistent-field */
+    public void setId(java.lang.String id)
+    {
+        this.id = id;
+    }
+
+    /** 
+     * @ejb:persistent-field 
+     * @hibernate.many-to-one column="entryid" cascade="none" not-null="true"
+     */
+    public WeblogEntryData getWeblogEntry()
+    {
+        return mWeblogEntry;
+    }
+
+    /** @ejb:persistent-field */
+    public void setWeblogEntry(WeblogEntryData entry)
+    {
+        mWeblogEntry = entry;
+    }
+
+    /** 
+     * @ejb:persistent-field 
+     * @hibernate.property column="name" non-null="true" unique="false"
+     */
+    public java.lang.String getName()
+    {
+        return this.name;
+    }
+
+    /** @ejb:persistent-field */
+    public void setName(java.lang.String name)
+    {
+        this.name = name;
+    }
+
+    /** 
+     * Email
+     * @ejb:persistent-field 
+     * @hibernate.property column="email" non-null="true" unique="false"
+     */
+    public java.lang.String getEmail()
+    {
+        return this.email;
+    }
+
+    /** @ejb:persistent-field */
+    public void setEmail(java.lang.String email)
+    {
+        this.email = email;
+    }
+
+    /** 
+     * @ejb:persistent-field 
+     * @hibernate.property column="url" non-null="true" unique="false"
+     */
+    public java.lang.String getUrl()
+    {
+        return this.url;
+    }
+
+    /** @ejb:persistent-field */
+    public void setUrl(java.lang.String url)
+    {
+        this.url = url;
+    }
+
+    /** 
+     * @ejb:persistent-field 
+     * @hibernate.property column="content" non-null="true" unique="false"
+     */
+    public java.lang.String getContent()
+    {
+        return this.content;
+    }
+
+    /** @ejb:persistent-field */
+    public void setContent(java.lang.String content)
+    {
+        this.content = content;
+    }
+
+    /** 
+     * @ejb:persistent-field 
+     * @hibernate.property column="posttime" non-null="true" unique="false"
+     */
+    public java.sql.Timestamp getPostTime()
+    {
+        return this.postTime;
+    }
+
+    /** @ejb:persistent-field */
+    public void setPostTime(java.sql.Timestamp postTime)
+    {
+        this.postTime = postTime;
+    }
+
+    /**
+     * @ejb:persistent-field
+     * @hibernate.property column="spam" non-null="true" unique="false"
+     */
+    public Boolean getSpam()
+    {
+        return this.spam;
+    }
+
+    /** @ejb:persistent-field */
+    public void setSpam(Boolean spam)
+    {
+        this.spam = spam;
+    }
+
+	/**
+     * @ejb:persistent-field 
+	 */
+	public void setRemoteHost(String remoteHost) {
+		this.remoteHost = remoteHost;
+    }
+	
+	/**
+     * @ejb:persistent-field 
+     * @hibernate.property column="remotehost" non-null="true" unique="false"
+	 */
+	public String getRemoteHost() {
+		return this.remoteHost;
+	}
+
+	public String toString()
+    {
+        StringBuffer str = new StringBuffer("{");
+
+        str.append("id=" + id + " " + 
+                   "name=" + name + " " + 
+                   "email=" + email + " " + 
+                   "url=" + url + " " + 
+                   "content=" + content + " " + 
+                   "postTime=" + postTime + " " + 
+                   "spam=" + spam);
+        str.append('}');
+
+        return (str.toString());
+    }
+
+    public boolean equals(Object pOther)
+    {
+        if (pOther instanceof CommentData)
+        {
+            CommentData lTest = (CommentData) pOther;
+            boolean lEquals = true;
+
+            lEquals = PojoUtil.equals(lEquals, this.id, lTest.id);
+            lEquals = PojoUtil.equals(lEquals, this.mWeblogEntry, lTest.mWeblogEntry);
+            lEquals = PojoUtil.equals(lEquals, this.name, lTest.name);
+            lEquals = PojoUtil.equals(lEquals, this.email, lTest.email);
+            lEquals = PojoUtil.equals(lEquals, this.url, lTest.url);
+            lEquals = PojoUtil.equals(lEquals, this.content, lTest.content);
+            lEquals = PojoUtil.equals(lEquals, this.postTime, lTest.postTime);
+            lEquals = PojoUtil.equals(lEquals, this.spam, lTest.spam);
+
+            return lEquals;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+    public int hashCode()
+    {
+        int result = 17;
+        result = PojoUtil.addHashCode(result, this.id);
+        result = PojoUtil.addHashCode(result, this.mWeblogEntry);
+        result = PojoUtil.addHashCode(result, this.name);
+        result = PojoUtil.addHashCode(result, this.email);
+        result = PojoUtil.addHashCode(result, this.url);
+        result = PojoUtil.addHashCode(result, this.content);
+        result = PojoUtil.addHashCode(result, this.postTime);
+        result = PojoUtil.addHashCode(result, this.spam);
+
+        return result;
+    }
+
+    /**
+     * Setter is needed in RollerImpl.storePersistentObject()
+     */
+    public void setData(org.roller.pojos.PersistentObject otherData)
+    {
+        CommentData otherComment = (CommentData) otherData;
+        this.id = otherComment.id;
+
+        this.mWeblogEntry = otherComment.mWeblogEntry;
+
+        this.name = otherComment.name;
+
+        this.email = otherComment.email;
+
+        this.url = otherComment.url;
+
+        this.content = otherComment.content;
+
+        this.postTime = otherComment.postTime;
+        
+        this.spam = otherComment.spam;
+    }
+
+}
\ No newline at end of file

Added: incubator/roller/trunk/src/org/roller/pojos/FolderAssoc.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/FolderAssoc.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/pojos/FolderAssoc.java (added)
+++ incubator/roller/trunk/src/org/roller/pojos/FolderAssoc.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,137 @@
+package org.roller.pojos;
+
+
+/**
+ * @author David M Johnson
+ *
+ * @ejb:bean name="FolderAssoc"
+ * @hibernate.class table="folderassoc" 
+ *     hibernate.jcs-cache usage="read-write"
+ */
+public class FolderAssoc extends PersistentObject
+    implements Assoc, java.io.Serializable
+{
+    public static final String PARENT = "PARENT";
+    public static final String GRANDPARENT = "GRANDPARENT";
+
+    protected String id;
+    protected FolderData folder;
+    protected FolderData ancestor;
+    protected java.lang.String relation;
+    
+    public FolderAssoc()
+    {
+    }
+
+    public FolderAssoc(
+        String id,
+        FolderData folder,
+        FolderData ancestor,
+        String relation)
+    {
+        this.id = id;
+        this.folder = folder;
+        this.ancestor = ancestor;
+        this.relation = relation;
+    }
+
+    public FolderAssoc(FolderAssoc otherData)
+    {
+        this.id = otherData.id;
+        this.folder = otherData.folder;
+        this.ancestor = otherData.ancestor;
+        this.relation = otherData.relation;
+    }
+
+    /**
+     * @ejb:persistent-field 
+     * @hibernate.id column="id" type="string"
+     *  generator-class="uuid.hex" unsaved-value="null"
+     */
+    public java.lang.String getId()
+    {
+        return this.id;
+    }
+    /** @ejb:persistent-field */
+    public void setId(java.lang.String id)
+    {
+        this.id = id;
+    }
+
+    /**
+    	* Setter is needed in RollerImpl.storePersistentObject()
+     */
+    public void setData(org.roller.pojos.PersistentObject otherData)
+    {
+        this.id = otherData.getId();
+        this.folder = ((FolderAssoc)otherData).getFolder();
+        this.ancestor = ((FolderAssoc)otherData).getAncestorFolder();
+        this.relation = ((FolderAssoc)otherData).getRelation();
+    }
+
+    /** 
+     * @ejb:persistent-field 
+     * @hibernate.many-to-one column="ancestorid" cascade="none"
+     */
+    public FolderData getAncestorFolder()
+    {
+        return ancestor;
+    }
+    
+    /** @ejb:persistent-field */ 
+    public void setAncestorFolder(FolderData data)
+    {
+        ancestor = data;
+    }
+
+    /** 
+     * @ejb:persistent-field 
+     * @hibernate.many-to-one column="folderid" cascade="none" not-null="true"
+     */
+    public FolderData getFolder()
+    {
+        return folder;
+    }
+
+    /** @ejb:persistent-field */ 
+    public void setFolder(FolderData data)
+    {
+        folder = data;
+    }
+
+    /** 
+     * @ejb:persistent-field 
+     * @hibernate.property column="relation" non-null="true" unique="false"
+     */
+    public java.lang.String getRelation()
+    {
+        return relation;
+    }
+
+    /** @ejb:persistent-field */ 
+    public void setRelation(java.lang.String string)
+    {
+        relation = string;
+    }
+
+    public HierarchicalPersistentObject getObject()
+    {
+        return getFolder();
+    }
+
+    public void setObject(HierarchicalPersistentObject hpo)
+    {
+        setFolder((FolderData)hpo);
+    }
+
+    public HierarchicalPersistentObject getAncestor()
+    {
+        return getAncestorFolder();
+    }
+
+    public void setAncestor(HierarchicalPersistentObject hpo)
+    {
+        setAncestorFolder((FolderData)hpo);
+    }
+
+}

Added: incubator/roller/trunk/src/org/roller/pojos/FolderData.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/FolderData.java?rev=189602&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/pojos/FolderData.java (added)
+++ incubator/roller/trunk/src/org/roller/pojos/FolderData.java Wed Jun  8 09:06:16 2005
@@ -0,0 +1,461 @@
+package org.roller.pojos;
+
+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.RollerFactory;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * <p>Folder that holds Bookmarks and other Folders. A Roller Website has a 
+ * set of Folders (there is no one root folder) and each Folder may contain 
+ * Folders or Bookmarks. Don't construct one of these yourself, instead use
+ * the create method in your BookmarkManager implementation.</p>
+ *
+ * @struts.form include-all="true"
+ *    extends="org.apache.struts.validator.ValidatorForm"
+ * @ejb:bean name="FolderData"
+ * 
+ * @hibernate.class table="folder"
+ * hibernate.jcs-cache usage="read-write"
+ */
+public class FolderData extends HierarchicalPersistentObject
+    implements Serializable, Comparable
+{
+    private static Log mLogger =
+        LogFactory.getFactory().getInstance(FolderData.class);
+
+    static final long serialVersionUID = -6272468884763861944L;
+    
+    protected Set bookmarks = new TreeSet();
+    protected List folders = null;
+    protected WebsiteData website;
+    
+    protected String id;
+    protected String name;
+    protected String description;
+    protected String path;
+    
+    //----------------------------------------------------------- Constructors
+    
+    /** For use by BookmarkManager implementations only. */
+    public FolderData()
+    {
+    }
+    
+    public FolderData(
+        FolderData parent,
+        String name, 
+        String desc, 
+        WebsiteData website)
+    {
+        mNewParent = parent;
+        this.name = name;
+        this.description = desc;
+        this.website = website;
+    }
+
+    public void setData(org.roller.pojos.PersistentObject otherData)
+    {
+        mNewParent = ((FolderData) otherData).mNewParent;
+        this.bookmarks = ((FolderData) otherData).bookmarks;
+        this.id = ((FolderData) otherData).id;
+        this.name = ((FolderData) otherData).name;
+        this.description = ((FolderData) otherData).description;
+        this.website = ((FolderData) otherData).website;
+    }
+
+    public void save() throws RollerException
+    {   
+        if (RollerFactory.getRoller().getBookmarkManager().isDuplicateFolderName(this))
+        {
+            throw new RollerException("Duplicate folder name");
+        }
+        super.save(); 
+    }
+    
+    /** 
+     * @see org.roller.pojos.HierarchicalPersistentObject#getAssocClass()
+     */
+    public Class getAssocClass()
+    {
+        return FolderAssoc.class;
+    }
+
+    /** 
+     * @see org.roller.pojos.HierarchicalPersistentObject#getObjectPropertyName()
+     */
+    public String getObjectPropertyName()
+    {
+        return "folder";
+    }
+
+    /** 
+     * @see org.roller.pojos.HierarchicalPersistentObject#getAncestorPropertyName()
+     */
+    public String getAncestorPropertyName()
+    {
+        return "ancestorFolder";
+    }
+
+    //------------------------------------------------------------- Attributes
+    
+    /** 
+     * @ejb:persistent-field 
+     * 
+     * @hibernate.id column="id" type="string"
+     *     generator-class="uuid.hex" unsaved-value="null"
+     */
+    public String getId()
+    {
+        return this.id;
+    }
+
+    /** @ejb:persistent-field */
+    public void setId(String id)
+    {
+        this.id = id;
+    }
+
+    /** 
+     * @struts.validator type="required" msgkey="errors.required"
+     * @struts.validator type="mask" msgkey="errors.noslashes"
+     * @struts.validator-var name="mask" value="${noslashes}"
+     * @struts.validator-args arg0resource="folderForm.name"
+     * 
+     * @ejb:persistent-field 
+     * 
+     * @hibernate.property column="name" non-null="true" unique="false"
+     */
+    public String getName()
+    {
+        return this.name;
+    }
+
+    /** @ejb:persistent-field */
+    public void setName(String name)
+    {
+        this.name = name;
+    }
+
+    /** 
+     * Description
+     * 
+     * @ejb:persistent-field 
+     * 
+     * @hibernate.property column="description" non-null="true" unique="false"
+     */
+    public String getDescription()
+    {
+        return this.description;
+    }
+
+    /** @ejb:persistent-field */
+    public void setDescription(String description)
+    {
+        this.description = description;
+    }
+
+    //---------------------------------------------------------- Relationships
+    
+    /** Get path to this bookmark folder. */
+    public String getPath() throws RollerException
+    {
+        if (mNewParent != null) 
+        {
+            throw new RollerException(
+                "Folder has a new parent and must be saved before getPath() will work");
+        }
+        
+        if (null == path)
+        {
+            path = RollerFactory.getRoller().getBookmarkManager().getPath(this);
+        }
+        return path;
+    }
+        
+    /** 
+     * @ejb:persistent-field 
+     * 
+     * @hibernate.many-to-one column="websiteid" cascade="none" not-null="true"
+     */
+    public WebsiteData getWebsite()
+    {
+        return website;
+    }
+
+    /** @ejb:persistent-field */
+    public void setWebsite( WebsiteData website )
+    {
+        this.website = website;
+    }
+
+    /** Return parent category, or null if category is root of hierarchy. */
+    public FolderData getParent() throws RollerException
+    {
+        if (mNewParent != null)
+        {
+            // Category has new parent, so return that
+            return (FolderData)mNewParent;
+        }
+        else if (getParentAssoc() != null)
+        {
+            // Return parent found in database
+            return ((FolderAssoc)getParentAssoc()).getAncestorFolder();
+        }
+        else 
+        {
+            return null;
+        }
+    }
+
+    /** Set parent category, database will be updated when object is saved. */
+    public void setParent(HierarchicalPersistentObject parent)
+    {
+        mNewParent = parent;
+    }
+
+    /** Query to get child categories of this category. */
+    public List getFolders() throws RollerException
+    {
+        if (folders == null)
+        {
+            folders = new LinkedList();
+            List childAssocs = getChildAssocs();
+            Iterator childIter = childAssocs.iterator();
+            while (childIter.hasNext())
+            {
+                FolderAssoc assoc =
+                    (FolderAssoc) childIter.next();
+                folders.add(assoc.getFolder());
+            }
+        }
+        return folders;
+    }
+
+    //------------------------------------------------------ Bookmark children
+    
+    /** 
+      * @ejb:persistent-field
+     * 
+     * @hibernate.set lazy="true" order-by="name" cascade="none" 
+     * @hibernate.collection-key column="folderid" 
+     * @hibernate.collection-one-to-many class="org.roller.pojos.BookmarkData"
+     */
+    public Set getBookmarks()    
+    {
+        return this.bookmarks;
+    }
+
+    /** @ejb:persistent-field */
+    public void setBookmarks(Set bookmarks)
+    {
+        this.bookmarks = bookmarks;
+    }
+    
+    /** Store bookmark and add to folder */
+    public void addBookmark(BookmarkData bookmark) throws RollerException
+    {
+        bookmark.setFolder(this);
+        bookmarks.add(bookmark);  
+        bookmark.save();      
+    }
+
+    /** Remove boomkark from folder */
+    public void removeBookmark(BookmarkData bookmark)
+    {
+        bookmarks.remove(bookmark);
+        bookmark.setFolder(null);
+    }
+
+    /**
+     * @param subfolders
+     */
+    public List retrieveBookmarks(boolean subfolders) throws RollerException
+    {
+        BookmarkManager bmgr = RollerFactory.getRoller().getBookmarkManager();
+        return bmgr.retrieveBookmarks(this, subfolders);
+    }
+
+    /** 
+     * Move all bookmarks that exist in this folder and all
+     * subfolders of this folder to a single new folder.
+     */ 
+    public void moveContents(FolderData dest) throws RollerException
+    {
+        Iterator entries = retrieveBookmarks(true).iterator();
+        while (entries.hasNext())
+        {
+            BookmarkData bookmark = (BookmarkData) entries.next();
+            bookmark.setFolder(dest);
+            bookmark.save();
+        }
+    }
+
+    //------------------------------------------------------------------------
+
+    /** 
+     * @see org.roller.pojos.HierarchicalPersistentObject#createAssoc(
+     *    org.roller.pojos.HierarchicalPersistentObject, 
+     *    org.roller.pojos.HierarchicalPersistentObject, java.lang.String)
+     */
+    public Assoc createAssoc(
+        HierarchicalPersistentObject object, 
+        HierarchicalPersistentObject associatedObject, 
+        String relation) throws RollerException
+    {
+        BookmarkManager bmgr = RollerFactory.getRoller().getBookmarkManager();
+        return bmgr.createFolderAssoc(
+            (FolderData)object, 
+            (FolderData)associatedObject, 
+            relation);
+    }
+
+    //------------------------------------------------------- Good citizenship
+
+    public String toString()
+    {
+        StringBuffer str = new StringBuffer("{");
+        str.append(
+              "bookmarks=" + bookmarks + " " 
+            + "id=" + id + " " 
+            + "name=" + name + " " 
+            + "description=" + description);
+        str.append('}');
+        return (str.toString());
+    }
+
+    public boolean equals(Object pOther)
+    {
+        if (pOther instanceof FolderData)
+        {
+            FolderData lTest = (FolderData) pOther;
+            boolean lEquals = true;
+
+//            if (this.bookmarks == null)
+//            {
+//                lEquals = lEquals && (lTest.bookmarks == null);
+//            }
+//            else
+//            {
+//                lEquals = lEquals && this.bookmarks.equals(lTest.bookmarks);
+//            }
+
+            if (this.id == null)
+            {
+                lEquals = lEquals && (lTest.id == null);
+            }
+            else
+            {
+                lEquals = lEquals && this.id.equals(lTest.id);
+            }
+
+            if (this.name == null)
+            {
+                lEquals = lEquals && (lTest.name == null);
+            }
+            else
+            {
+                lEquals = lEquals && this.name.equals(lTest.name);
+            }
+
+            if (this.description == null)
+            {
+                lEquals = lEquals && (lTest.description == null);
+            }
+            else
+            {
+                lEquals = lEquals && 
+                          this.description.equals(lTest.description);
+            }
+
+            if (this.website == null)
+            {
+                lEquals = lEquals && (lTest.website == null);
+            }
+            else
+            {
+                lEquals = lEquals && this.website.equals(lTest.website);
+            }
+
+            return lEquals;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+    public int hashCode()
+    {
+        int result = 17;
+                         
+        result = (37 * result) + 
+                 ((this.id != null) ? this.id.hashCode() : 0);
+        result = (37 * result) + 
+                 ((this.name != null) ? this.name.hashCode() : 0);
+        result = (37 * result) + 
+                 ((this.description != null) ? this.description.hashCode() : 0);
+        result = (37 * result) + 
+                 ((this.website != null) ? this.website.hashCode() : 0);
+
+        return result;
+    }
+
+    /** 
+     * @see java.lang.Comparable#compareTo(java.lang.Object)
+     */
+    public int compareTo(Object o)
+    {
+        FolderData other = (FolderData)o;
+        return getName().compareTo(other.getName());
+    }
+
+    /** TODO: fix Struts form generation template so this is not needed. */
+    public void setAssocClassName(String dummy) {};
+    /** TODO: fix Struts form generation template so this is not needed. */
+    public void setObjectPropertyName(String dummy) {};
+    /** TODO: fix Struts form generation template so this is not needed. */
+    public void setAncestorPropertyName(String dummy) {};
+    /** TODO: fix formbean generation so this is not needed. */
+    public void setPath(String string) {}
+
+    /** 
+     * @see org.roller.pojos.HierarchicalPersistentObject#getParentAssoc()
+     */
+    protected Assoc getParentAssoc() throws RollerException
+    {
+        return RollerFactory.getRoller().getBookmarkManager().getFolderParentAssoc(this);
+    }
+
+    /** 
+     * @see org.roller.pojos.HierarchicalPersistentObject#getChildAssocs()
+     */
+    protected List getChildAssocs() throws RollerException
+    {
+        return RollerFactory.getRoller().getBookmarkManager().getFolderChildAssocs(this);
+    }
+
+    /** 
+     * @see org.roller.pojos.HierarchicalPersistentObject#getAllDescendentAssocs()
+     */
+    public List getAllDescendentAssocs() throws RollerException
+    {
+        return RollerFactory.getRoller().getBookmarkManager().getAllFolderDecscendentAssocs(this);
+    }
+
+    /** 
+     * @see org.roller.pojos.HierarchicalPersistentObject#getAncestorAssocs()
+     */
+    public List getAncestorAssocs() throws RollerException
+    {
+        return RollerFactory.getRoller().getBookmarkManager().getFolderAncestorAssocs(this);
+    }
+}