You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@roller.apache.org by sn...@apache.org on 2005/06/09 05:19:20 UTC

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

Added: incubator/roller/trunk/src/org/roller/pojos/RollerConfigData.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/RollerConfigData.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/pojos/RollerConfigData.java (added)
+++ incubator/roller/trunk/src/org/roller/pojos/RollerConfigData.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,804 @@
+package org.roller.pojos;
+
+import java.io.File;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.roller.RollerException;
+import org.roller.model.Roller;
+import org.roller.model.RollerFactory;
+import org.roller.util.PojoUtil;
+
+/**
+ * Configuration object for Roller.  Reads and writes roller-config.xml.
+ * RollerConfig extends Struts ActionForm so that it can be extended by
+ * RollerConfigForm in the administrator pages.
+ * <p />
+ * This is where you set default Roller configuration values.
+ *
+ * @ejb:bean name="RollerConfigData"
+ * @struts.form include-all="true"
+ * @hibernate.class table="rollerconfig"
+ * hibernate.jcs-cache usage="read-write"
+ */
+public class RollerConfigData
+    extends org.roller.pojos.PersistentObject
+    implements java.io.Serializable
+{
+    static final long serialVersionUID = -6354583200913127875L;
+
+    protected java.lang.String id = null;
+    
+    /**
+     * Roller database version.
+     */
+    protected String mDatabaseVersion = "995"; // 1.0 will be '1000'
+    
+    /**
+     * Absolute URL for site, for cases where infered absolute URL doesn't work.
+     */
+    protected String mAbsoluteURL = null;
+
+    /**
+     * Should Roller cache return RSS pages.
+     */
+    protected Boolean mRssUseCache = Boolean.FALSE;
+
+    /**
+     * Duration to cache RSS pages (in seconds).
+     */
+    protected Integer mRssCacheTime = new Integer(3000);
+
+    /**
+     * Does Roller allow the creation of new users.
+     */
+    protected Boolean mNewUserAllowed = Boolean.TRUE;
+
+    /**
+     * @deprecated Admins now indicated by roles in userroles table.
+     */
+    protected String mAdminUsers = "admin";
+
+    /**
+     * Where to get Themes presented to new users.
+     */
+    protected String mUserThemes = "/themes";
+
+    /**
+     * List of "editor pages" for the Weblog entry editor
+     * seperated with commas.
+     */
+    protected String mEditorPages = 
+    	   "editor-text.jsp,editor-text-js.jsp,editor-rte.jsp,editor-dhtml.jsp,editor-ekit.jsp,editor-wiki-js.jsp";
+
+    /**
+     * Dis/enble RSS aggregation capabilities.
+     */
+    protected Boolean mEnableAggregator = Boolean.FALSE;
+
+    /**
+     * Are file uploads enabled.
+     */
+    protected Boolean mUploadEnabled = Boolean.TRUE;
+
+    /**
+     * The maximum size of each user's upload directory.
+     */
+    protected BigDecimal mUploadMaxDirMB = new BigDecimal("2");
+
+    /**
+     * The maximum size allowed per uploaded file.
+     */
+    protected BigDecimal mUploadMaxFileMB = new BigDecimal(".5");
+
+    /**
+     * List of permitted file extensions (not including the "dot")
+     * seperated with commas.
+     * This attribute is mutually exclusive with uploadForbid.
+     */
+    protected String mUploadAllow = "";
+
+    /**
+     * List of forbidden file extensions (not including the "dot")
+     * seperated with commas.
+     * This attribute is mutually exclusive with uploadAllow.
+     */
+    protected String mUploadForbid = "";
+
+    /**
+     * Directory where uploaded files will be stored.
+     * May end with a slash.  Optional, this value will
+     * default to RollerContext.USER_RESOURCES.  If specified,
+     * should be a full path on the system harddrive or
+     * relative to the WebApp.
+     */
+    protected String mUploadDir = "";
+
+    /**
+     * The path from which the webserver will serve upload files.
+     * This values must not end in a slash.
+     */
+    protected String uploadPath = "/resources";
+
+    protected Boolean mMemDebug = Boolean.FALSE;
+
+    /**
+     * Determines if the Comment page will "autoformat"
+     * comments.  That is, replace carriage-returns with <br />.
+     */
+    protected Boolean mAutoformatComments = Boolean.FALSE;
+
+    /**
+     * Determines if the Comment page will escape html in comments.
+     */
+    protected Boolean mEscapeCommentHtml = Boolean.FALSE;
+
+    /**
+     * Determines if e-mailing comments is enabled.
+     */
+    protected Boolean mEmailComments = Boolean.FALSE;
+
+    /**
+     * Enable linkback extraction.
+     */
+    protected Boolean mEnableLinkback = Boolean.FALSE;
+
+    /**
+     * Name of this site
+     */
+    protected String mSiteName = "Roller-based Site";
+
+    /**
+     * Description of this site
+     */
+    protected String mSiteDescription = "Roller-based Site";
+
+    /**
+     * Site administrator's email address
+     */
+    protected String mEmailAddress = "";
+
+    /**
+     * Lucene index directory
+     */
+    protected String mIndexDir = "${user.home}" + File.separator
+    						     + "roller-index";
+    
+    /**
+     * Flag for encrypting passwords
+     */
+    protected Boolean mEncryptPasswords = Boolean.FALSE;
+    
+    protected String mAlgorithm = "SHA";
+    
+    /**
+     * Comma-delimited list of "words" for filtering referrer spam.
+     */
+    protected String mRefererSpamWords = "";
+    
+    //-------------------------------------- begin requisite getters & setters
+
+    /**
+     * Not remote since primary key may be extracted by other means.
+     *
+     * @struts.validator type="required" msgkey="errors.required"
+     * @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;
+    }
+
+    /**
+     * @ejb:persistent-field
+     * @hibernate.property column="absoluteurl" non-null="false" unique="false"
+     */
+    public String getAbsoluteURL()
+    {
+        return mAbsoluteURL;
+    }
+    /** @ejb:persistent-field */
+    public void setAbsoluteURL(String string)
+    {
+        mAbsoluteURL = string;
+    }
+
+    /**
+     * @ejb:persistent-field
+     * @hibernate.property column="rssusecache" non-null="true" unique="false"
+     */
+    public Boolean getRssUseCache()
+    {
+        return mRssUseCache;
+    }
+    /** @ejb:persistent-field */
+    public void setRssUseCache(Boolean use)
+    {
+        mRssUseCache = use;
+    }
+
+    /**
+     * @ejb:persistent-field
+     * @hibernate.property column="rsscachetime" non-null="true" unique="false"
+     */
+    public Integer getRssCacheTime()
+    {
+        return mRssCacheTime;
+    }
+    /** @ejb:persistent-field */
+    public void setRssCacheTime(Integer cacheTime)
+    {
+        mRssCacheTime = cacheTime;
+    }
+
+    /**
+    * @ejb:persistent-field
+    * @hibernate.property column="newuserallowed" non-null="true" unique="false"
+    */
+    public Boolean getNewUserAllowed()
+    {
+        return mNewUserAllowed;
+    }
+    /** @ejb:persistent-field */
+    public void setNewUserAllowed(Boolean use)
+    {
+        mNewUserAllowed = use;
+    }
+
+    /**
+     * @deprecated Admins now indicated by roles in userroles table.
+     */
+    public String getAdminUsers()
+    {
+        return mAdminUsers;
+    }
+    /**
+     * @deprecated Admins now indicated by roles in userroles table.
+     */
+    public void setAdminUsers(String _adminUsers)
+    {
+        mAdminUsers = _adminUsers;
+    }
+
+    /**
+     * @ejb:persistent-field
+     * @hibernate.property column="userthemes" non-null="true" unique="false"
+     */
+    public String getUserThemes()
+    {
+        return mUserThemes;
+    }
+    /** @ejb:persistent-field */
+    public void setUserThemes(String str)
+    {
+        mUserThemes = str;
+    }
+
+    /**
+     * @ejb:persistent-field
+     * @hibernate.property column="editorpages" non-null="false" unique="false"
+     */
+    public String getEditorPages()
+    {
+        return mEditorPages;
+    }
+    /** @ejb:persistent-field */
+    public void setEditorPages(String _editorPages)
+    {
+        mEditorPages = _editorPages;
+    }
+
+    /**
+    * @ejb:persistent-field
+    * @hibernate.property column="enableaggregator" non-null="true" unique="false"
+    */
+    public Boolean getEnableAggregator()
+    {
+        return mEnableAggregator;
+    }
+    /** @ejb:persistent-field */
+    public void setEnableAggregator(Boolean use)
+    {
+        mEnableAggregator = use;
+    }
+
+    /**
+    * @ejb:persistent-field
+    * @hibernate.property column="uploadenabled" non-null="true" unique="false"
+    */
+    public Boolean getUploadEnabled()
+    {
+        return mUploadEnabled;
+    }
+    /** @ejb:persistent-field */
+    public void setUploadEnabled(Boolean use)
+    {
+        mUploadEnabled = use;
+    }
+
+    /**
+    * @ejb:persistent-field
+    * @hibernate.property column="uploadmaxdirmb"
+    *   non-null="true" unique="false" type="big_decimal"
+    */
+    public BigDecimal getUploadMaxDirMB()
+    {
+        return mUploadMaxDirMB;
+    }
+    /** @ejb:persistent-field */
+    public void setUploadMaxDirMB(BigDecimal use)
+    {
+        mUploadMaxDirMB = use;
+    }
+
+    /**
+    * @ejb:persistent-field
+    * @hibernate.property column="uploadmaxfilemb"
+    *   non-null="true" unique="false" type="big_decimal"
+    */
+    public BigDecimal getUploadMaxFileMB()
+    {
+        return mUploadMaxFileMB;
+    }
+    /** @ejb:persistent-field */
+    public void setUploadMaxFileMB(BigDecimal use)
+    {
+        mUploadMaxFileMB = use;
+    }
+
+    /**
+     * @ejb:persistent-field
+     * @hibernate.property column="uploadallow" non-null="true" unique="false"
+     */
+    public String getUploadAllow()
+    {
+        return mUploadAllow;
+    }
+    /** @ejb:persistent-field */
+    public void setUploadAllow(String _uploadAllow)
+    {
+        mUploadAllow = _uploadAllow;
+    }
+
+    /**
+     * @ejb:persistent-field
+     * @hibernate.property column="uploadforbid" non-null="true" unique="false"
+     */
+    public String getUploadForbid()
+    {
+        return mUploadForbid;
+    }
+    /** @ejb:persistent-field */
+    public void setUploadForbid(String _uploadForbid)
+    {
+        mUploadForbid = _uploadForbid;
+    }
+
+    /**
+     * @ejb:persistent-field
+     * @hibernate.property column="uploaddir" non-null="true" unique="false"
+     */
+    public String getUploadDir()
+    {
+        return mUploadDir;
+    }
+    /** @ejb:persistent-field */
+    public void setUploadDir(String str)
+    {
+        mUploadDir = str;
+    }
+
+    /**
+     * @ejb:persistent-field
+     * @hibernate.property column="uploadpath" non-null="true" unique="false"
+     */
+    public String getUploadPath()
+    {
+        return uploadPath;
+    }
+    /** @ejb:persistent-field */
+    public void setUploadPath(String str)
+    {
+        uploadPath = str;
+    }
+
+    /**
+    * @ejb:persistent-field
+    * @hibernate.property column="memdebug" non-null="true" unique="false"
+    */
+    public Boolean getMemDebug() { return mMemDebug; }
+
+    /**
+     * Set memory debugging on or off.
+     * @param mMemDebug The mMemDebug to set
+     * @ejb:persistent-field
+     */
+    public void setMemDebug(Boolean memDebug)
+    {
+        mMemDebug = memDebug;
+    }
+
+    /**
+    * @ejb:persistent-field
+    * @hibernate.property column="autoformatcomments" non-null="true" unique="false"
+    */
+    public Boolean getAutoformatComments()
+    {
+        return mAutoformatComments;
+    }
+    /** @ejb:persistent-field */
+    public void setAutoformatComments(Boolean value)
+    {
+        mAutoformatComments = value;
+    }
+
+    /**
+    * @ejb:persistent-field
+    * @hibernate.property column="escapecommenthtml" non-null="true" unique="false"
+    */
+    public Boolean getEscapeCommentHtml()
+    {
+        return mEscapeCommentHtml;
+    }
+    /** @ejb:persistent-field */
+    public void setEscapeCommentHtml(Boolean value)
+    {
+        mEscapeCommentHtml = value;
+    }
+    
+    /**
+     * Does website allow Should Comments be emailed to participants?
+     *
+     * @ejb:persistent-field
+     * @hibernate.property column="emailcomments" non-null="true" unique="false"
+     */
+    public Boolean getEmailComments()
+    {
+        return mEmailComments;
+    }
+
+    /**
+     * @ejb:persistent-field
+     */
+    public void setEmailComments(Boolean emailComments)
+    {
+        this.mEmailComments = emailComments;
+    }
+
+    /**
+     * Enable linkback.
+     * @ejb:persistent-field
+     * @hibernate.property column="enablelinkback" non-null="true" unique="false"
+    */
+    public Boolean getEnableLinkback()
+    {
+        return mEnableLinkback;
+    }
+
+    /**
+     * Enable linkback.
+     * @ejb:persistent-field
+     */
+    public void setEnableLinkback(Boolean b)
+    {
+        mEnableLinkback = b;
+    }
+
+
+    /**
+     * @ejb:persistent-field
+     * @hibernate.property column="sitedescription" non-null="false" unique="false"
+     */
+    public String getSiteDescription()
+    {
+        return mSiteDescription;
+    }
+
+    /**
+     * @param string
+     * @ejb:persistent-field
+     */
+    public void setSiteDescription(String string)
+    {
+        mSiteDescription = string;
+    }
+
+    /**
+     * @ejb:persistent-field
+     * @hibernate.property column="sitename" non-null="false" unique="false"
+     */
+    public String getSiteName()
+    {
+        return mSiteName;
+    }
+
+    /**
+     * @param string
+     * @ejb:persistent-field
+     */
+    public void setSiteName(String string)
+    {
+        mSiteName = string;
+    }
+
+    /**
+     * @ejb:persistent-field
+     * @hibernate.property column="emailaddress" non-null="false" unique="false"
+     */
+    public String getEmailAddress()
+    {
+        return mEmailAddress;
+    }
+
+    /**
+     * @param string
+     * @ejb:persistent-field
+     */
+    public void setEmailAddress(String emailAddress)
+    {
+        mEmailAddress = emailAddress;
+    }
+
+	/**
+     * @ejb:persistent-field
+     * @hibernate.property column="indexdir" non-null="false" unique="false"
+     */
+    public String getIndexDir() {
+
+        return mIndexDir;
+    }
+
+	/**
+	 * @param the new index directory
+	 * @ejb:persistent-field
+	 */
+	public void setIndexDir(String indexDir)
+	{
+		mIndexDir = indexDir;
+	}
+
+    /**
+     * @ejb:persistent-field
+     * @hibernate.property column="encryptpasswords" non-null="true" unique="false"
+     */
+    public Boolean getEncryptPasswords()
+    {
+        return mEncryptPasswords;
+    }
+    /** @ejb:persistent-field */
+    public void setEncryptPasswords(Boolean value)
+    {
+        mEncryptPasswords = value;
+    }
+    
+    /**
+     * @ejb:persistent-field
+     * @hibernate.property column="algorithm" non-null="false" unique="false"
+     */
+    public String getAlgorithm() {
+
+        return mAlgorithm;
+    }
+
+    /**
+     * @param the new algorithm for encrypting passwords
+     * @ejb:persistent-field
+     */
+    public void setAlgorithm(String algorithm)
+    {
+        mAlgorithm = algorithm;
+    }
+        
+	/**
+	 * @return Returns the mDatabaseVersion.
+     * @hibernate.property column="dbversion" non-null="false" unique="false"
+	 */
+	public String getDatabaseVersion() {
+		return mDatabaseVersion;
+	}
+	/**
+	 * @param databaseVersion The mDatabaseVersion to set.
+     * @ejb:persistent-field
+	 */
+	public void setDatabaseVersion(String databaseVersion) {
+		mDatabaseVersion = databaseVersion;
+	}
+
+    /**
+     * @return Returns the mRefererSpamWords.
+     * @hibernate.property column="refspamwords" non-null="false" unique="false"
+     */
+    public String getRefererSpamWords()
+    {
+        return this.mRefererSpamWords;
+    }
+    /**
+     * @param refererSpamWords The mRefererSpamWords to set.
+     * @ejb:persistent-field
+     */
+    public void setRefererSpamWords(String refererSpamWords)
+    {
+        this.mRefererSpamWords = refererSpamWords;
+    }
+
+	//---------------------------------------- end requisite getters & setters
+
+    /**
+     * Convenience method for getAdminUsers.
+     **/
+    public String[] adminUsersArray()
+    {
+        return StringUtils.split(StringUtils.deleteWhitespace(mAdminUsers), ",");
+    }
+
+    /**
+     * Convenience method for getEditorPages.
+     **/
+    public List getEditorPagesList()
+    {
+        return Arrays.asList(
+            StringUtils.split(StringUtils.deleteWhitespace(mEditorPages), ","));
+    }
+
+    /**
+     * Convenience method for getUploadAllow.
+     **/
+    public String[] uploadAllowArray()
+    {
+        return StringUtils.split(StringUtils.deleteWhitespace(mUploadAllow), ",");
+    }
+
+    /**
+     * Convenience method for getUploadForbid.
+     **/
+    public String[] uploadForbidArray()
+    {
+        return StringUtils.split(StringUtils.deleteWhitespace(mUploadForbid), ",");
+    }
+
+    /**
+     * Convenience method for getRefererSpamWords.
+     **/
+    public String[] refererSpamWordsArray()
+    {
+        return StringUtils.split(StringUtils.deleteWhitespace(mRefererSpamWords), ",");
+    }
+
+    public void updateValues( RollerConfigData child )
+    {
+        this.mAbsoluteURL = child.getAbsoluteURL();
+        this.mRssUseCache = child.getRssUseCache();
+        this.mRssCacheTime = child.getRssCacheTime();
+        this.mNewUserAllowed = child.getNewUserAllowed();
+        this.mAdminUsers = child.getAdminUsers();
+        this.mDatabaseVersion = child.getDatabaseVersion();
+        this.mUserThemes = child.getUserThemes();
+        this.mEditorPages = child.getEditorPages();
+        this.mEnableAggregator = child.getEnableAggregator();
+        this.mUploadEnabled = child.getUploadEnabled();
+        this.mUploadMaxDirMB = child.getUploadMaxDirMB();
+        this.mUploadMaxFileMB = child.getUploadMaxFileMB();
+        this.mUploadAllow = child.getUploadAllow();
+        this.mUploadForbid = child.getUploadForbid();
+        this.mUploadDir = child.getUploadDir();
+        this.uploadPath = child.getUploadPath();
+        this.mMemDebug = child.getMemDebug();
+        this.mAutoformatComments = child.getAutoformatComments();
+        this.mEscapeCommentHtml = child.getEscapeCommentHtml();
+        this.mEmailComments = child.getEmailComments();
+        this.mEnableLinkback = child.getEnableLinkback();
+        this.mSiteName = child.getSiteName();
+        this.mSiteDescription = child.getSiteDescription();
+        this.mEmailAddress = child.getEmailAddress();
+        this.mIndexDir = child.getIndexDir();
+        this.mEncryptPasswords = child.getEncryptPasswords();
+        this.mAlgorithm = child.getAlgorithm();
+        this.mRefererSpamWords = child.getRefererSpamWords();
+    }
+
+    /** nice output for debugging */
+    public String toString()
+    {
+        StringBuffer buf = new StringBuffer();
+        buf.append("RollerConfig \n");
+        Class clazz = getClass();
+        Field[] fields = clazz.getDeclaredFields();
+
+        try {
+            AccessibleObject.setAccessible(fields, true);
+            for (int i = 0; i < fields.length; i++) {
+                buf.append(
+                    "\t["
+                        + fields[i].getName()
+                        + "="
+                        + fields[i].get(this)
+                        + "], \n");
+            }
+        } catch (Exception e) {
+            // ignored!
+        }
+
+        return buf.toString();
+    }
+
+
+	public void setData(PersistentObject vo) {
+		if (vo instanceof RollerConfigData) {
+      		this.id = ((RollerConfigData)vo).id;
+			updateValues((RollerConfigData)vo);
+        }
+	}
+
+    public boolean equals(Object pOther)
+    {
+        if (pOther instanceof WebsiteData)
+        {
+            RollerConfigData lTest = (RollerConfigData) pOther;
+            boolean lEquals = true;
+
+            lEquals = PojoUtil.equals(lEquals, this.id, lTest.id);
+			lEquals = PojoUtil.equals(lEquals, this.mAbsoluteURL, lTest.getAbsoluteURL());
+			lEquals = PojoUtil.equals(lEquals, this.mRssUseCache, lTest.getRssUseCache());
+			lEquals = PojoUtil.equals(lEquals, this.mRssCacheTime, lTest.getRssCacheTime());
+			lEquals = PojoUtil.equals(lEquals, this.mNewUserAllowed, lTest.getNewUserAllowed());
+			lEquals = PojoUtil.equals(lEquals, this.mAdminUsers, lTest.getAdminUsers());
+			lEquals = PojoUtil.equals(lEquals, this.mUserThemes, lTest.getUserThemes());
+			lEquals = PojoUtil.equals(lEquals, this.mEditorPages, lTest.getEditorPages());
+			lEquals = PojoUtil.equals(lEquals, this.mEnableAggregator, lTest.getEnableAggregator());
+			lEquals = PojoUtil.equals(lEquals, this.mUploadEnabled, lTest.getUploadEnabled());
+			lEquals = PojoUtil.equals(lEquals, this.mUploadMaxDirMB, lTest.getUploadMaxDirMB());
+			lEquals = PojoUtil.equals(lEquals, this.mUploadMaxFileMB, lTest.getUploadMaxFileMB());
+			lEquals = PojoUtil.equals(lEquals, this.mUploadAllow, lTest.getUploadAllow());
+			lEquals = PojoUtil.equals(lEquals, this.mUploadForbid, lTest.getUploadForbid());
+			lEquals = PojoUtil.equals(lEquals, this.mUploadDir, lTest.getUploadDir());
+			lEquals = PojoUtil.equals(lEquals, this.uploadPath, lTest.getUploadPath());
+			lEquals = PojoUtil.equals(lEquals, this.mMemDebug, lTest.getMemDebug());
+			lEquals = PojoUtil.equals(lEquals, this.mAutoformatComments, lTest.getAutoformatComments());
+			lEquals = PojoUtil.equals(lEquals, this.mEscapeCommentHtml, lTest.getEscapeCommentHtml());
+			lEquals = PojoUtil.equals(lEquals, this.mEmailComments, lTest.getEmailComments());
+			lEquals = PojoUtil.equals(lEquals, this.mEnableLinkback, lTest.getEnableLinkback());
+			lEquals = PojoUtil.equals(lEquals, this.mSiteName, lTest.getSiteName());
+			lEquals = PojoUtil.equals(lEquals, this.mSiteDescription, lTest.getSiteDescription());
+			lEquals = PojoUtil.equals(lEquals, this.mEmailAddress, lTest.getEmailAddress());
+			lEquals = PojoUtil.equals(lEquals, this.mIndexDir, lTest.getIndexDir());
+            lEquals = PojoUtil.equals(lEquals, this.mEncryptPasswords, lTest.getEncryptPasswords());
+            lEquals = PojoUtil.equals(lEquals, this.mAlgorithm, lTest.getAlgorithm());
+            lEquals = PojoUtil.equals(lEquals, this.mRefererSpamWords, lTest.getRefererSpamWords());
+
+		 	return lEquals;
+	  	}
+	  	else
+	  	{
+		 	return false;
+      	}
+	}
+    
+    public int hashCode()
+    {
+        return super.hashCode();
+    }
+
+    public boolean canSave() throws RollerException
+    {
+        Roller roller = RollerFactory.getRoller();
+        if (roller.getUser().equals(UserData.SYSTEM_USER)) 
+        {
+            return true;
+        }
+        if (roller.getUser().hasRole("admin"))
+        {
+            return true;
+        }
+        return false;
+    }
+}

Added: incubator/roller/trunk/src/org/roller/pojos/RollerPropertyData.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/RollerPropertyData.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/pojos/RollerPropertyData.java (added)
+++ incubator/roller/trunk/src/org/roller/pojos/RollerPropertyData.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,120 @@
+/*
+ * RollerConfigProperty.java
+ *
+ * Created on April 20, 2005, 2:58 PM
+ */
+
+package org.roller.pojos;
+
+
+/**
+ * This POJO represents a single property of the roller system.
+ *
+ * @author Allen Gilliland
+ *
+ * @ejb:bean name="RollerPropertyData"
+ * @hibernate.class table="roller_properties"
+ * hibernate.jcs-cache usage="read-write"
+ */
+public class RollerPropertyData 
+    extends org.roller.pojos.PersistentObject
+    implements java.io.Serializable
+{
+    
+    static final long serialVersionUID = 6913562779484028899L;
+    
+    
+    /**
+     * Holds value of property name.
+     */
+    private String name;
+
+    /**
+     * Holds value of property value.
+     */
+    private String value;
+
+    
+    public RollerPropertyData() {}
+    
+    
+    public RollerPropertyData(String name, String value) {
+        this.name = name;
+        this.value = value;
+    }
+    
+    
+    public void setData(PersistentObject object)
+    {
+	if (object instanceof RollerPropertyData)
+        {
+            RollerPropertyData prop = (RollerPropertyData) object;
+            this.name = prop.name;
+            this.value = prop.value;
+        }
+    }
+    
+    
+    public String toString()
+    {
+        return (this.name + "=" + this.value);
+    }
+    
+
+    /**
+     * Getter for property name.
+     *
+     * @return Value of property name.
+     * @ejb:persistent-field
+     * @hibernate.id column="name" type="string" generator-class="assigned"
+     */
+    public String getName() {
+
+        return this.name;
+    }
+
+    /**
+     * Setter for property name.
+     *
+     * @param name New value of property name.
+     * @ejb:persistent-field
+     */
+    public void setName(String name) {
+
+        this.name = name;
+    }
+
+    /**
+     * Getter for property value.
+     *
+     * @return Value of property value.
+     * @ejb:persistent-field
+     * @hibernate.property column="value" non-null="false" unique="false"
+     */
+    public String getValue() {
+
+        return this.value;
+    }
+
+    /**
+     * Setter for property value.
+     *
+     * @param value New value of property value.
+     * @ejb:persistent-field
+     */
+    public void setValue(String value) {
+
+        this.value = value;
+    }
+    
+    
+    public String getId() {
+        // this is only here because it is required by PersistentObject
+        return null;
+    }
+    
+    
+    public void setId(String id) {
+        // do nothing ... only here because the PersistentObject class requires it
+    }
+}

Added: incubator/roller/trunk/src/org/roller/pojos/UserCookieData.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/UserCookieData.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/pojos/UserCookieData.java (added)
+++ incubator/roller/trunk/src/org/roller/pojos/UserCookieData.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,192 @@
+package org.roller.pojos;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * This class is used to manage cookie-based authentication.
+ *
+ * @author Matt Raible
+ * @version $Revision: 1.2 $ $Date: 2005/01/21 19:01:10 $
+ *
+ * @hibernate.class table="usercookie"
+ */
+public class UserCookieData extends PersistentObject implements Serializable
+{
+    static final long serialVersionUID = -1109195226932397420L;
+
+    private String id;
+    private String username;
+    private String cookieId;
+    private Date dateCreated;
+
+    public UserCookieData()
+    {
+        this.dateCreated = new Date();
+    }
+
+    public UserCookieData( String id, String username, String cookieId,
+                       Date dateCreated )
+    {
+        this.id = id;
+        this.username = username;
+        this.cookieId = cookieId;
+        this.dateCreated = (Date)dateCreated.clone();
+    }
+
+    public UserCookieData( UserCookieData otherData )
+    {
+        this.id = otherData.id;
+        this.username = otherData.username;
+        this.cookieId = otherData.cookieId;
+        this.dateCreated = (Date)otherData.dateCreated.clone();
+    }
+
+
+    /**
+     * @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;
+    }
+
+    /**
+     * Returns the username.
+     * @ejb:persistent-field
+     * @hibernate.property column="username" not-null="true" unique="false"
+     * @return String
+     */
+    public String getUsername()
+    {
+        return username;
+    }
+
+    /**
+     * Sets the username.
+     * @ejb:persistent-field
+     * @param username The username to set
+     */
+    public void setUsername( String username )
+    {
+        this.username = username;
+    }
+
+    /**
+     * Returns the cookieId (a GUID).
+     * @ejb:persistent-field
+     * @hibernate.property column="cookieid" not-null="true" unique="true"
+     * @return String
+     */
+    public String getCookieId()
+    {
+        return cookieId;
+    }
+
+    /**
+     * Sets the cookieId.
+     * @ejb:persistent-field
+     * @param rolename The cookieId to set
+     */
+    public void setCookieId( String rolename )
+    {
+        this.cookieId = rolename;
+    }
+
+    /**
+     * @return Returns the dateCreated.
+     * @ejb:persistent-field
+     * @hibernate.property column="datecreated" not-null="true" unique="false"
+     */
+    public Date getDateCreated()
+    {
+        return (Date)dateCreated.clone();
+    }
+
+    /**
+     * @param dateCreated The dateCreated to set.
+     * @ejb:persistent-field
+     */
+    public void setDateCreated(final Date dateCreated )
+    {
+        if (dateCreated != null)
+        {
+        	this.dateCreated = (Date)dateCreated.clone();
+        }
+        else
+        {
+        	this.dateCreated = null;
+        }
+    }
+
+	/**
+	 * @see org.roller.pojos.PersistentObject#setData(org.roller.pojos.PersistentObject)
+	 */
+	public void setData(PersistentObject vo) {
+		UserCookieData newData = (UserCookieData) vo;
+        this.id = newData.getId();
+        this.username = newData.getUsername();
+        this.cookieId = newData.getCookieId();
+        this.dateCreated = newData.getDateCreated();
+	}
+
+    /**
+     * @see java.lang.Object#equals(Object)
+     */
+    public boolean equals(Object o)
+    {
+        // Generated by IDEA 4.5.1
+        // But avoid super.equals() because that has a full reflection-based implementation.
+        if (this == o)
+        {
+            return true;
+        }
+        if (!(o instanceof UserCookieData))
+        {
+            return false;
+        }
+        final UserCookieData userCookieData = (UserCookieData)o;
+
+        if (cookieId != null ? !cookieId.equals(userCookieData.cookieId) : userCookieData.cookieId != null)
+        {
+            return false;
+        }
+        if (dateCreated != null ? !dateCreated.equals(userCookieData.dateCreated) : userCookieData.dateCreated != null)
+        {
+            return false;
+        }
+        if (id != null ? !id.equals(userCookieData.id) : userCookieData.id != null)
+        {
+            return false;
+        }
+        if (username != null ? !username.equals(userCookieData.username) : userCookieData.username != null)
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode()
+    {
+        // Hash on id and dateCreated.
+        // But avoid super.hashCode() because that has a full reflection-based implementation.
+        int result = 0;
+        result = 29 * result + (id != null ? id.hashCode() : 0);
+        result = 29 * result + (dateCreated != null ? dateCreated.hashCode() : 0);
+        return result;
+    }
+
+}

Added: incubator/roller/trunk/src/org/roller/pojos/UserData.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/UserData.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/pojos/UserData.java (added)
+++ incubator/roller/trunk/src/org/roller/pojos/UserData.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,414 @@
+
+package org.roller.pojos;
+
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.roller.RollerException;
+import org.roller.config.RollerConfig;
+import org.roller.model.Roller;
+import org.roller.model.RollerFactory;
+import org.roller.model.UserManager;
+import org.roller.util.Utilities;
+
+
+/**
+ * User bean.
+ * @author David M Johnson
+ *
+ * @ejb:bean name="UserData"
+ * @struts.form include-all="true"
+ * @hibernate.class table="rolleruser"  
+ * hibernate.jcs-cache usage="read-write"
+ */
+public class UserData
+   extends org.roller.pojos.PersistentObject
+   implements java.io.Serializable
+{
+    public static final UserData SYSTEM_USER = 
+        new UserData("n/a","systemuser","n/a","systemuser","n/a",new Date());
+    
+    public static final UserData ANONYMOUS_USER = 
+        new UserData("n/a","anonymoususer","n/a","anonymoususer","n/a",new Date());
+   
+   static final long serialVersionUID = -6354583200913127874L;
+
+   protected java.lang.String id;
+   protected java.lang.String userName;
+   protected java.lang.String password;
+   protected java.lang.String fullName;
+   protected java.lang.String emailAddress;
+   protected java.util.Date dateCreated;
+   private Set roles = new TreeSet();
+
+   public UserData()
+   {
+   }
+
+	public UserData( java.lang.String id, java.lang.String userName,
+                     java.lang.String password, java.lang.String fullName,
+                     java.lang.String emailAddress, java.util.Date dateCreated)
+	{
+		this.id = id;
+		this.userName = userName;
+		this.password = password;
+		this.fullName = fullName;
+		this.emailAddress = emailAddress;
+		this.dateCreated = (Date)dateCreated.clone();
+	}
+
+	public UserData( UserData otherData )
+	{
+		this.id = otherData.id;
+		this.userName = otherData.userName;
+		this.password = otherData.password;
+		this.fullName = otherData.fullName;
+		this.emailAddress = otherData.emailAddress;
+		this.dateCreated = (Date)otherData.dateCreated.clone();
+
+	}
+
+   /** Id of the User.
+     * Not remote since primary key may be extracted by other means.
+     * 
+     * @struts.validator type="required" msgkey="errors.required"
+     * @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;
+   }
+
+   /** User name of the user.
+     * @ejb:persistent-field 
+     * @hibernate.property column="username" non-null="true" unique="true"
+     */
+   public java.lang.String getUserName()
+   {
+      return this.userName;
+   }
+   /** @ejb:persistent-field */ 
+   public void setUserName( java.lang.String userName )
+   {
+      this.userName = userName;
+   }
+
+   /** 
+    * Get password.
+    * If password encryption is enabled, will return encrypted password.
+    * @ejb:persistent-field 
+    * @hibernate.property column="passphrase" non-null="true"
+    */
+   public java.lang.String getPassword()
+   {
+      return this.password;
+   }
+   /** 
+    * Set password.
+    * If password encryption is turned on, then pass in an encrypted password. 
+    * @ejb:persistent-field 
+    */ 
+   public void setPassword( java.lang.String password )
+   {
+      this.password = password;
+   }
+
+   /** Full name of the user.
+     * @ejb:persistent-field 
+     * @hibernate.property column="fullname" non-null="true" unique="true"
+     */
+   public java.lang.String getFullName()
+   {
+      return this.fullName;
+   }
+   /** @ejb:persistent-field */ 
+   public void setFullName( java.lang.String fullName )
+   {
+      this.fullName = fullName;
+   }
+
+   /** E-mail address of the user.
+     * @ejb:persistent-field 
+     * @hibernate.property column="emailaddress" non-null="true" unique="true"
+     */
+   public java.lang.String getEmailAddress()
+   {
+      return this.emailAddress;
+   }
+   /** @ejb:persistent-field */ 
+   public void setEmailAddress( java.lang.String emailAddress )
+   {
+      this.emailAddress = emailAddress;
+   }
+
+   /** 
+	* @ejb:persistent-field 
+	* @hibernate.property column="datecreated" non-null="true" unique="false"
+	*/
+   public java.util.Date getDateCreated()
+   {
+       if (dateCreated == null) 
+       {
+           return null;
+       }
+       else 
+       {
+           return (Date)dateCreated.clone();
+       }
+   }
+   /** @ejb:persistent-field */ 
+   public void setDateCreated(final java.util.Date date)
+   {
+	   if (date != null) 
+	   {
+	   	   dateCreated = (Date)date.clone();
+	   }
+	   else
+	   {
+	       dateCreated = null;
+	   }
+   }
+
+   public String toString()
+   {
+		StringBuffer str = new StringBuffer("{");
+
+		str.append("id=" + id + " ");
+		str.append("userName=" + userName + " ");
+		str.append("password=" + password + " ");
+		str.append("fullName=" + fullName + " ");
+		str.append("emailAddress=" + emailAddress + " ");
+		str.append("dateCreated=" + dateCreated + " ");
+		str.append('}');
+
+		return(str.toString());
+   }
+
+   public boolean equals( Object pOther )
+   {
+      if( pOther instanceof UserData )
+      {
+         UserData lTest = (UserData) pOther;
+         boolean lEquals = true;
+
+         if( this.id == null )
+         {
+            lEquals = lEquals && ( lTest.id == null );
+         }
+         else
+         {
+            lEquals = lEquals && this.id.equals( lTest.id );
+         }
+         if( this.userName == null )
+         {
+            lEquals = lEquals && ( lTest.userName == null );
+         }
+         else
+         {
+            lEquals = lEquals && this.userName.equals( lTest.userName );
+         }
+         if( this.password == null )
+         {
+            lEquals = lEquals && ( lTest.password == null );
+         }
+         else
+         {
+            lEquals = lEquals && this.password.equals( lTest.password );
+         }
+         if( this.fullName == null )
+         {
+            lEquals = lEquals && ( lTest.fullName == null );
+         }
+         else
+         {
+            lEquals = lEquals && this.fullName.equals( lTest.fullName );
+         }
+         if( this.emailAddress == null )
+         {
+            lEquals = lEquals && ( lTest.emailAddress == null );
+         }
+         else
+         {
+            lEquals = lEquals && this.emailAddress.equals( lTest.emailAddress );
+         }
+         
+		if( this.dateCreated == null )
+		{
+		   lEquals = lEquals && ( lTest.dateCreated == null );
+		}
+		else
+		{
+		   lEquals = lEquals && datesEquivalent(this.dateCreated, lTest.dateCreated);
+		}
+
+        return lEquals;
+      }
+      else
+      {
+         return false;
+      }
+   }
+   
+    private boolean datesEquivalent(Date d1, Date d2)
+    {
+        boolean equiv = true;
+        equiv = equiv && d1.getHours() == d1.getHours();
+        equiv = equiv && d1.getMinutes() == d1.getMinutes();
+        equiv = equiv && d1.getSeconds() == d1.getSeconds();
+        equiv = equiv && d1.getMonth() == d1.getMonth();
+        equiv = equiv && d1.getDay() == d1.getDay();
+        equiv = equiv && d1.getYear() == d1.getYear();
+        return equiv;
+    }
+
+   public int hashCode()
+   {
+      int result = 17;
+      result = 37*result + ((this.id != null) ? this.id.hashCode() : 0);
+      result = 37*result + ((this.userName != null) ? this.userName.hashCode() : 0);
+      result = 37*result + ((this.password != null) ? this.password.hashCode() : 0);
+      result = 37*result + ((this.fullName != null) ? this.fullName.hashCode() : 0);
+      result = 37*result + ((this.emailAddress != null) ? this.emailAddress.hashCode() : 0);
+      result = 37*result + ((this.dateCreated != null) ? this.dateCreated.hashCode() : 0);
+      return result;
+      }
+
+   /**
+	* Setter is needed in RollerImpl.storePersistentObject()
+    */
+   public void setData( org.roller.pojos.PersistentObject otherData )
+   {
+      this.id = ((UserData)otherData).id;
+      this.userName = ((UserData)otherData).userName;
+      this.password = ((UserData)otherData).password;
+      this.fullName = ((UserData)otherData).fullName;
+      this.emailAddress = ((UserData)otherData).emailAddress;
+      this.dateCreated = ((UserData)otherData).dateCreated;
+   }
+
+    /** 
+     * Removing a user also removes his/her website.
+     * @see org.roller.pojos.PersistentObject#remove()
+     */
+    public void remove() throws RollerException
+    {
+        UserManager uMgr = RollerFactory.getRoller().getUserManager();
+        uMgr.removeUserWebsites(this);
+        
+        // remove user roles
+        Iterator roles = uMgr.getUserRoles(this).iterator();
+        while (roles.hasNext()) 
+        {
+            ((RoleData)roles.next()).remove();
+        }
+        
+        super.remove();
+    }
+    
+    /** 
+     * Reset this user's password.
+     * @param roller Roller instance to use for configuration information
+     * @param new1 New password
+     * @param new2 Confirm this matches new password
+     * @author Dave Johnson
+     */
+    public void resetPassword(Roller roller, String new1, String new2) throws RollerException 
+    {
+        if (!new1.equals(new2))
+        {
+            throw new RollerException("newUser.error.mismatchedPasswords");
+        }
+
+        String encrypt = RollerConfig.getProperty("passwds.encryption.enabled");
+        String algorithm = RollerConfig.getProperty("passwds.encryption.algorithm");
+        if (new Boolean(encrypt).booleanValue()) 
+        {
+            password = Utilities.encodePassword(new1, algorithm);            
+        }
+        else
+        {
+            password = new1;
+        }
+    }
+    
+    /** 
+     * @hibernate.set lazy="false" inverse="true" cascade="delete" 
+     * @hibernate.collection-key column="userid"
+     * @hibernate.collection-one-to-many class="org.roller.pojos.RoleData"
+     */
+    public Set getRoles() 
+    {
+        return roles;
+    }
+    
+    public void setRoles(Set roles)
+    {
+        this.roles = roles;
+    }
+    
+
+    /**
+     * Returns true if user has role specified.
+     * @param roleName Name of role
+     * @return True if user has specified role.
+     */
+    public boolean hasRole(String roleName) 
+    {
+        Iterator iter = roles.iterator();
+        while (iter.hasNext()) 
+        {
+            RoleData role = (RoleData) iter.next();
+            if (role.getRole().equals(roleName)) 
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Revokes specified role from user.
+     * @param roleName Name of role to be revoked.
+     */
+    public void revokeRole(String roleName) throws RollerException
+    {
+        RoleData removeme = null; 
+        Iterator iter = roles.iterator();
+        while (iter.hasNext()) 
+        {
+            RoleData role = (RoleData) iter.next();
+            if (role.getRole().equals(roleName)) 
+            {
+                removeme = role;
+            }
+        }
+        if (removeme != null)
+        {
+            roles.remove(removeme);
+            RollerFactory.getRoller().getUserManager().removeRole(removeme.getId());
+        }
+    }
+
+    /**
+     * Grant to user role specified by role name.
+     * @param roleName Name of role to be granted.
+     */
+    public void grantRole(String roleName) throws RollerException 
+    {
+        if (!hasRole(roleName))
+        {
+            RoleData role = new RoleData(null, this, roleName);
+            RollerFactory.getRoller().getUserManager().storeRole(role);
+            roles.add(role);
+        }
+    }
+}

Added: incubator/roller/trunk/src/org/roller/pojos/WeblogCategoryAssoc.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/WeblogCategoryAssoc.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/pojos/WeblogCategoryAssoc.java (added)
+++ incubator/roller/trunk/src/org/roller/pojos/WeblogCategoryAssoc.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,169 @@
+package org.roller.pojos;
+
+import org.roller.RollerException;
+import org.roller.business.PersistenceStrategy;
+import org.roller.model.RollerFactory;
+
+/**
+ * <p>WeblogCategoryAssoc represents association between weblog categories 
+ * in the weblog category hierarchy. For each category, there will be zero 
+ * or one parent category association and zero or more grandparent 
+ * associations.</p>
+ * 
+ * <p>Creating a new Cat</p>
+ * WeblogManager creates new Cat, not a PO<br />
+ * Cat has a parent Cat or null if parent is null. Parent must be PO.<br />
+ * On save, CatAssoc will be created for Cat.<br />
+ * 
+ * <p>Saving an existing Cat</p>
+ * If Cat has a new parent Cat, then update all of Cat's CatAssocs<br />
+ * 
+ * @author David M Johnson
+ *
+ * @ejb:bean name="WeblogCategoryAssoc"
+ * @hibernate.class table="weblogcategoryassoc" 
+ * hibernate.jcs-cache usage="read-write"
+ */
+public class WeblogCategoryAssoc extends PersistentObject
+    implements Assoc
+{
+    static final long serialVersionUID = 674856287447472015L;
+    
+    protected String id;
+    protected WeblogCategoryData category;
+    protected WeblogCategoryData ancestor;
+    protected java.lang.String relation;
+    
+    public WeblogCategoryAssoc()
+    {
+    }
+
+    public WeblogCategoryAssoc(
+        String id,
+        WeblogCategoryData category,
+        WeblogCategoryData ancestor,
+        java.lang.String relation)
+    {
+        this.id = id;
+        this.category = category;
+        this.ancestor = ancestor;
+        this.relation = relation;
+    }
+
+    public WeblogCategoryAssoc(WeblogCategoryAssoc otherData)
+    {
+        this.id = otherData.id;
+        this.category = otherData.category;
+        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;
+    }
+
+
+    /** 
+     * Remove self and all child categories. 
+     */
+    public void remove() throws RollerException
+    {
+        PersistenceStrategy pstrategy =
+            RollerFactory.getRoller().getPersistenceStrategy();
+        pstrategy.remove(this);
+    }
+
+    public void save() throws RollerException
+    {
+        PersistenceStrategy pstrategy =
+            RollerFactory.getRoller().getPersistenceStrategy();
+        pstrategy.store(this);
+    }
+
+    /**
+     * Setter is needed in RollerImpl.storePersistentObject()
+     */
+    public void setData(org.roller.pojos.PersistentObject otherData)
+    {
+        this.id = otherData.getId();
+        this.category = ((WeblogCategoryAssoc)otherData).getCategory();
+        this.ancestor = ((WeblogCategoryAssoc)otherData).getAncestorCategory();
+        this.relation = ((WeblogCategoryAssoc)otherData).getRelation();
+    }
+
+    /** 
+     * @ejb:persistent-field 
+     * @hibernate.many-to-one column="ancestorid" cascade="none"
+     */
+    public WeblogCategoryData getAncestorCategory()
+    {
+        return ancestor;
+    }
+    
+    /** @ejb:persistent-field */ 
+    public void setAncestorCategory(WeblogCategoryData data)
+    {
+        ancestor = data;
+    }
+
+    /** 
+     * @ejb:persistent-field 
+     * @hibernate.many-to-one column="categoryid" cascade="none" not-null="true"
+     */
+    public WeblogCategoryData getCategory()
+    {
+        return category;
+    }
+
+    /** @ejb:persistent-field */ 
+    public void setCategory(WeblogCategoryData data)
+    {
+        category = 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 getCategory();
+    }
+
+    public void setObject(HierarchicalPersistentObject hpo)
+    {
+        setCategory((WeblogCategoryData)hpo);
+    }
+
+    public HierarchicalPersistentObject getAncestor()
+    {
+        return getAncestorCategory();
+    }
+
+    public void setAncestor(HierarchicalPersistentObject hpo)
+    {
+        setAncestorCategory((WeblogCategoryData)hpo);
+    }
+}

Added: incubator/roller/trunk/src/org/roller/pojos/WeblogCategoryData.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/WeblogCategoryData.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/pojos/WeblogCategoryData.java (added)
+++ incubator/roller/trunk/src/org/roller/pojos/WeblogCategoryData.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1,488 @@
+package org.roller.pojos;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.roller.RollerException;
+import org.roller.model.Roller;
+import org.roller.model.RollerFactory;
+import org.roller.model.WeblogManager;
+import org.roller.util.PojoUtil;
+
+/**
+ * WeblogCategory bean.
+ * @author David M Johnson
+ *
+ * @ejb:bean name="WeblogCategoryData"
+ * @struts.form include-all="true"
+ * @hibernate.class table="weblogcategory" 
+ * hibernate.jcs-cache usage="read-write"
+ */
+public class WeblogCategoryData extends HierarchicalPersistentObject
+{
+    static final long serialVersionUID = 1435782148712018954L;
+
+    protected java.lang.String id = null;
+    protected java.lang.String name;
+    protected java.lang.String description;
+    protected java.lang.String image;
+    
+    protected String cachedPath = null;
+
+    protected WebsiteData mWebsite;
+    protected List mWeblogCategories;
+
+    public WeblogCategoryData()
+    {
+    }
+
+    public WeblogCategoryData(
+        java.lang.String id,
+        WebsiteData website,
+        WeblogCategoryData parent,
+        java.lang.String name,
+        java.lang.String description,
+        java.lang.String image)
+    {
+        this.id = id;
+        this.mWebsite = website;
+        this.mNewParent = parent;
+        this.name = name;
+        this.description = description;
+        this.image = image;
+    }
+
+    public WeblogCategoryData(WeblogCategoryData otherData)
+    {
+        this.id = otherData.id;
+        this.mWebsite = otherData.mWebsite;
+        this.mNewParent = otherData.mNewParent;
+        this.name = otherData.name;
+        this.description = otherData.description;
+        this.image = otherData.image;
+    }
+
+    /** Setter is needed in RollerImpl.storePersistentObject(). */
+    public void setData(org.roller.pojos.PersistentObject otherData)
+    {
+        this.id = ((WeblogCategoryData) otherData).id;
+        this.mWebsite = ((WeblogCategoryData) otherData).mWebsite;
+        this.mNewParent = ((WeblogCategoryData) otherData).mNewParent;
+        this.name = ((WeblogCategoryData) otherData).name;
+        this.description = ((WeblogCategoryData) otherData).description;
+        this.image = ((WeblogCategoryData) otherData).image;
+    }
+
+    public void save() throws RollerException
+    {   
+        if (RollerFactory.getRoller().getWeblogManager().isDuplicateWeblogCategoryName(this))
+        {
+            throw new RollerException("Duplicate category name");
+        }
+        super.save();
+    }
+   
+    /**
+     * Remove this category and recategorize all entries in this category and
+     * in all subcategories to a specified destination category (destCat).
+     * @param destCat New category for entries in remove categories (or null if none).
+     */
+    public void remove(WeblogCategoryData destCat) throws RollerException
+    {
+        WeblogManager wmgr = RollerFactory.getRoller().getWeblogManager();
+        
+        // recategorize entries in this category
+        if (destCat != null) 
+        {
+            wmgr.moveWeblogCategoryContents(getId(), destCat.getId());
+        }
+        // delete this category
+        super.remove();
+        
+        if (getWebsite().getBloggerCategory().equals(this))
+        {
+            WeblogCategoryData rootCat = wmgr.getRootWeblogCategory(getWebsite());
+            getWebsite().setBloggerCategory(rootCat);
+        }
+        
+        if (getWebsite().getDefaultCategory().equals(this))
+        {
+            WeblogCategoryData rootCat = wmgr.getRootWeblogCategory(getWebsite());
+            getWebsite().setDefaultCategory(rootCat);
+        }
+        
+        getWebsite().save();
+    }
+    
+    /** 
+     * @see org.roller.pojos.HierarchicalPersistentObject#getAssocClass()
+     */
+    public Class getAssocClass()
+    {
+        return WeblogCategoryAssoc.class;
+    }
+
+    /** 
+     * @see org.roller.pojos.HierarchicalPersistentObject#getObjectPropertyName()
+     */
+    public String getObjectPropertyName()
+    {
+        return "category";
+    }
+
+    /** 
+     * @see org.roller.pojos.HierarchicalPersistentObject#getAncestorPropertyName()
+     */
+    public String getAncestorPropertyName()
+    {
+        return "ancestorCategory";
+    }
+    
+    //------------------------------------------------------- Simple properties
+
+    /**
+     * @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.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;
+    }
+
+    /** 
+     * Description
+     * @ejb:persistent-field 
+     * @hibernate.property column="description" non-null="true" unique="false"
+     */
+    public java.lang.String getDescription()
+    {
+        return this.description;
+    }
+    /** @ejb:persistent-field */
+    public void setDescription(java.lang.String description)
+    {
+        this.description = description;
+    }
+
+    /** 
+     * @ejb:persistent-field 
+     * @hibernate.property column="image" non-null="true" unique="false"
+     */
+    public java.lang.String getImage()
+    {
+        return this.image;
+    }
+    /** @ejb:persistent-field */
+    public void setImage(java.lang.String image)
+    {
+        this.image = image;
+    }
+
+    /**
+     * Get path in category hierarhcy.
+     */
+    public String getPath()
+    {
+        if (null == cachedPath)
+        {
+            try
+            {
+                cachedPath = RollerFactory.getRoller().getWeblogManager().getPath(this);
+            }
+            catch (RollerException e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+        return cachedPath;
+    }
+
+    //------------------------------------------------------------ Associations
+
+    /** 
+     * @ejb:persistent-field
+     *  
+     * @hibernate.many-to-one column="websiteid" cascade="none" not-null="true"
+     */
+    public WebsiteData getWebsite()
+    {
+        return mWebsite;
+    }
+    /** @ejb:persistent-field */
+    public void setWebsite(WebsiteData website)
+    {
+        mWebsite = website;
+    }
+
+//    /** 
+//     * @ejb:persistent-field
+//     *  
+//     * @hibernate.many-to-one column="websiteid" cascade="none" not-null="true"
+//     */
+//    public WeblogCategoryAssoc getWeblogCategoryAssoc()
+//    {
+//        return mWeblogCategoryAssoc;
+//    }
+//    /** @ejb:persistent-field */
+//    public void setWeblogCategoryAssoc(WebsiteData website)
+//    {
+//        WeblogCategoryAssoc = weblogCategoryAssoc;
+//    }
+
+    /** Return parent category, or null if category is root of hierarchy. */
+    public WeblogCategoryData getParent() throws RollerException
+    {
+        if (mNewParent != null)
+        {
+            // Category has new parent, so return that
+            return (WeblogCategoryData)mNewParent;
+        }
+        else if (getParentAssoc() != null)
+        {
+            // Return parent found in database
+            return ((WeblogCategoryAssoc)getParentAssoc()).getAncestorCategory();
+        }
+        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 getWeblogCategories() throws RollerException
+    {
+        if (mWeblogCategories == null)
+        {
+            mWeblogCategories = new LinkedList();
+            List childAssocs = getChildAssocs();
+            Iterator childIter = childAssocs.iterator();
+            while (childIter.hasNext())
+            {
+                WeblogCategoryAssoc assoc =
+                    (WeblogCategoryAssoc) childIter.next();
+                mWeblogCategories.add(assoc.getCategory());
+            }
+        }
+        return mWeblogCategories;
+    }
+
+    public boolean descendentOf(WeblogCategoryData ancestor) 
+        throws RollerException
+    {
+        return RollerFactory.getRoller().getWeblogManager().isDescendentOf(this, ancestor);
+    }
+    
+    /** 
+     * Determine if category is in use. Returns true if any weblog entries 
+     * use this category or any of it's subcategories.
+     */
+    public boolean isInUse() 
+    {
+        try
+        {
+            return RollerFactory.getRoller().getWeblogManager().isWeblogCategoryInUse(this);
+        }
+        catch (RollerException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+    
+    /** TODO: fix form generation so this is not needed. */
+    public void setInUse(boolean dummy) {}
+
+    //------------------------------------------------------------------------
+
+    /** 
+     * @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
+    {
+        WeblogManager wmgr = RollerFactory.getRoller().getWeblogManager();
+        return wmgr.createWeblogCategoryAssoc(
+            (WeblogCategoryData)object, 
+            (WeblogCategoryData)associatedObject, 
+            relation);
+    }
+
+    //------------------------------------------------------------------------
+    
+    /** 
+     * Move all weblog entries that exist in this category and all
+     * subcategories of this category to a single new category.
+     */ 
+    public void moveContents(WeblogCategoryData dest) throws RollerException
+    {
+        Iterator entries = retrieveWeblogEntries(true).iterator();
+        while (entries.hasNext())
+        {
+            WeblogEntryData entry = (WeblogEntryData) entries.next();
+            entry.setCategory(dest);
+            entry.save();
+        }
+    }
+    
+    /** 
+     * Retrieve all weblog entries in this category and, optionally, include
+     * weblog entries all sub-categories.
+     * @param subcats True if entries from sub-categories are to be returned.
+     * @return List of WeblogEntryData objects.
+     * @throws RollerException
+     */ 
+    public List retrieveWeblogEntries(boolean subcats) 
+        throws RollerException
+    {
+        WeblogManager wmgr = RollerFactory.getRoller().getWeblogManager();
+        return wmgr.retrieveWeblogEntries(this, subcats);
+    }
+
+    //-------------------------------------------------------- Good citizenship
+
+    public String toString()
+    {
+        StringBuffer str = new StringBuffer("{");
+
+        str.append(
+            "id="
+                + id
+                + " "
+                + "name="
+                + name
+                + " "
+                + "description="
+                + description
+                + " "
+                + "image="
+                + image);
+        str.append('}');
+
+        return (str.toString());
+    }
+
+    public boolean equals(Object pOther)
+    {
+        if (pOther == null) return false;
+        if (pOther instanceof WeblogCategoryData)
+        {
+            WeblogCategoryData lTest = (WeblogCategoryData) pOther;
+            boolean lEquals = true;
+            lEquals = PojoUtil.equals(lEquals, this.id, lTest.id);
+            lEquals = PojoUtil.equals(lEquals, this.mWebsite.getId(), lTest.mWebsite.getId());
+            lEquals = PojoUtil.equals(lEquals, this.name, lTest.name);
+            lEquals = PojoUtil.equals(lEquals, this.description, lTest.description);
+            lEquals = PojoUtil.equals(lEquals, this.image, lTest.image);
+            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.mWebsite != null) ? this.mWebsite.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.image != null) ? this.image.hashCode() : 0);
+        return result;
+    }
+    
+    /** 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().getWeblogManager().getWeblogCategoryParentAssoc(this);
+    }
+
+    /** 
+     * @see org.roller.pojos.HierarchicalPersistentObject#getChildAssocs()
+     */
+    protected List getChildAssocs() throws RollerException
+    {
+        return RollerFactory.getRoller().getWeblogManager().getWeblogCategoryChildAssocs(this);
+    }
+
+    /** 
+     * @see org.roller.pojos.HierarchicalPersistentObject#getAllDescendentAssocs()
+     */
+    public List getAllDescendentAssocs() throws RollerException
+    {
+        return RollerFactory.getRoller().getWeblogManager().getAllWeblogCategoryDecscendentAssocs(this);
+    }
+
+    /** 
+     * @see org.roller.pojos.HierarchicalPersistentObject#getAncestorAssocs()
+     */
+    public List getAncestorAssocs() throws RollerException
+    {
+        return RollerFactory.getRoller().getWeblogManager().getWeblogCategoryAncestorAssocs(this);
+    }
+
+    public boolean canSave() throws RollerException
+    {
+        Roller roller = RollerFactory.getRoller();
+        if (roller.getUser().equals(UserData.SYSTEM_USER)) 
+        {
+            return true;
+        }
+        if (roller.getUser().equals(getWebsite().getUser()))
+        {
+            return true;
+        }
+        return false;
+    }
+
+}

Added: incubator/roller/trunk/src/org/roller/pojos/WeblogEntryComparator.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/pojos/WeblogEntryComparator.java?rev=189695&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/pojos/WeblogEntryComparator.java (added)
+++ incubator/roller/trunk/src/org/roller/pojos/WeblogEntryComparator.java Wed Jun  8 20:18:46 2005
@@ -0,0 +1 @@
+/*
 * Created on Apr 16, 2004
 */
package org.roller.pojos;

import java.io.Serializable;
import java.util.Comparator;

/**
 * Sorts WeblogEntryData objects in reverse chronological order
 * (most recently published entries first).  If they happen to
 * have the same pubTime, then sort alphabetically by title.
 * 
 * @author lance.lavandowska
 */
public class WeblogEntryComparator implements Comparator, Serializable
{
    static final long serialVersionUID = -9067148992322255150L;
    
    public int compare(Object val1, Object val2)
    throws ClassCastException
    {
        WeblogEntryData entry1 = (WeblogEntryData)val1;
        WeblogEntryData entry2 = (WeblogEntryData)val2;
        long pubTime1 = entry1.getPubTime().getTime();
        long pubTime2 = entry2.getPubTime().getTime();

        if (pubTime1 > pubTime2)
        {
            return -1;
        }
        else if (pubTime1 < pubTime2)
        {
            return 1;
        }

        // if pubTimes are the same, return
        // results of String.compareTo() on Title
        return entry1.getTitle().compareTo(entry2.getTitle());
    }
}
\ No newline at end of file