roller-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From snoopd...@apache.org
Subject svn commit: r327589 [21/72] - in /incubator/roller/branches/roller_1.x: ./ 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...
Date Fri, 21 Oct 2005 21:46:28 GMT
Added: incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/HibernateWeblogManagerImpl.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/HibernateWeblogManagerImpl.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/HibernateWeblogManagerImpl.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/HibernateWeblogManagerImpl.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,807 @@
+/*
+ * Created on Jun 16, 2004
+ */
+package org.roller.business.hibernate;
+
+import net.sf.hibernate.Criteria;
+import net.sf.hibernate.HibernateException;
+import net.sf.hibernate.Session;
+import net.sf.hibernate.expression.Expression;
+import net.sf.hibernate.expression.Junction;
+import net.sf.hibernate.expression.Order;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.roller.RollerException;
+import org.roller.business.PersistenceStrategy;
+import org.roller.business.WeblogManagerImpl;
+import org.roller.model.Roller;
+import org.roller.model.RollerFactory;
+import org.roller.pojos.Assoc;
+import org.roller.pojos.CommentData;
+import org.roller.pojos.RefererData;
+import org.roller.pojos.WeblogCategoryAssoc;
+import org.roller.pojos.WeblogCategoryData;
+import org.roller.pojos.WeblogEntryData;
+import org.roller.pojos.WebsiteData;
+import org.roller.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Hibernate queries.
+ * @author David M Johnson
+ */
+public class HibernateWeblogManagerImpl extends WeblogManagerImpl
+{
+    static final long serialVersionUID = -3730860865389981439L;
+    
+    private static Log mLogger =
+        LogFactory.getFactory().getInstance(HibernateWeblogManagerImpl.class);
+
+    /**
+     * @param strategy
+     * @param roller
+     */
+    public HibernateWeblogManagerImpl(PersistenceStrategy strategy)
+    {
+        super(strategy);
+        mLogger.debug("Instantiating Weblog Manager");
+    }
+    
+    public List getComments(String entryId, boolean nospam) throws RollerException
+    {
+        if (entryId == null)
+            throw new RollerException("entryId is null");
+
+        try
+        {
+            Session session = ((HibernateStrategy)mStrategy).getSession();
+            Criteria criteria = session.createCriteria(CommentData.class);
+            criteria.createAlias("weblogEntry","e");
+            criteria.add(Expression.eq("e.id", entryId));
+            if (nospam)
+            {
+                criteria.add(
+                    Expression.not(Expression.eq("spam", Boolean.TRUE)));
+            }
+            criteria.addOrder(Order.asc("postTime"));            
+            return criteria.list();
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }
+    }
+
+
+    /* 
+     * @see org.roller.model.WeblogManager#getNextEntry(org.roller.pojos.WeblogEntryData)
+     */
+    public List getNextPrevEntries(
+            WeblogEntryData current, String catName, int maxEntries, boolean next)
+        throws RollerException
+    {
+        if (catName != null && catName.trim().equals("/"))
+        {
+            catName = null;
+        }
+        Junction conjunction = Expression.conjunction();        
+        conjunction.add(Expression.eq("website", current.getWebsite()));
+        conjunction.add(Expression.eq("publishEntry", Boolean.TRUE));
+        
+        if (next)
+        {
+            conjunction.add(Expression.gt("pubTime", current.getPubTime()));
+        }
+        else
+        {
+            conjunction.add(Expression.lt("pubTime", current.getPubTime()));
+        }
+        
+        if (catName != null)
+        {
+            WeblogCategoryData category = 
+                getWeblogCategoryByPath(current.getWebsite(), null, catName);
+            if (category != null)
+            {
+                conjunction.add(Expression.eq("category", category));
+            }
+            else
+            {
+                throw new RollerException("Cannot find category: "+catName);
+            }
+        }
+
+        try
+        {
+            Session session = ((HibernateStrategy)mStrategy).getSession();
+            Criteria criteria = session.createCriteria(WeblogEntryData.class);
+            criteria.addOrder(Order.desc("pubTime"));
+            criteria.add(conjunction);
+            criteria.setMaxResults(maxEntries);
+            List results = criteria.list();
+            return results;
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }
+    }
+    
+    /**
+     * @see org.roller.model.WeblogManager#getRootWeblogCategory(org.roller.pojos.WebsiteData)
+     */
+    public WeblogCategoryData getRootWeblogCategory(WebsiteData website)
+        throws RollerException
+    {
+        if (website == null)
+            throw new RollerException("website is null");
+
+        try
+        {
+            Session session = ((HibernateStrategy)mStrategy).getSession();
+            Criteria criteria = session.createCriteria(WeblogCategoryAssoc.class);
+            criteria.createAlias("category","c");
+            
+            criteria.add(Expression.eq("c.website", website));
+            criteria.add(Expression.isNull("ancestorCategory"));
+            criteria.add(Expression.eq("relation", WeblogCategoryAssoc.PARENT));
+            
+            criteria.setMaxResults(1);    
+            
+            List list = criteria.list();
+            return ((WeblogCategoryAssoc)list.get(0)).getCategory();
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }
+    }
+    
+    /** 
+     * @see org.roller.model.WeblogManager#getWeblogCategories(
+     * org.roller.pojos.WebsiteData, boolean)
+     */
+    public List getWeblogCategories(WebsiteData website, boolean includeRoot) 
+        throws RollerException
+    {
+        if (website == null)
+            throw new RollerException("website is null");
+        
+        if (includeRoot) return getWeblogCategories(website);
+
+        try
+        {
+            Session session = ((HibernateStrategy)mStrategy).getSession();
+            Criteria criteria = session.createCriteria(WeblogCategoryAssoc.class); 
+            criteria.createAlias("category", "c");
+            criteria.add(Expression.eq("c.website", website));
+            criteria.add(Expression.isNotNull("ancestorCategory"));
+            criteria.add(Expression.eq("relation", "PARENT"));
+            Iterator assocs = criteria.list().iterator();
+            List cats = new ArrayList();
+            while (assocs.hasNext())
+            {
+                WeblogCategoryAssoc assoc = (WeblogCategoryAssoc) assocs.next();
+                cats.add(assoc.getCategory());
+            }
+            return cats;
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }
+    }
+    
+    public List getWeblogCategories(WebsiteData website) throws RollerException
+    {
+        if (website == null)
+            throw new RollerException("website is null");
+
+        try
+        {
+            Session session = ((HibernateStrategy)mStrategy).getSession();
+            Criteria criteria = session.createCriteria(WeblogCategoryData.class);            
+            criteria.add(Expression.eq("website", website));            
+            return criteria.list();
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }
+    }
+    
+    /** 
+     * @see org.roller.model.WeblogManager#getWeblogEntries(
+     * java.lang.String, 
+     * java.util.Date, 
+     * java.util.Date, 
+     * java.lang.String, 
+     * java.lang.String, 
+     * java.lang.Integer)
+     */
+    public List getWeblogEntries(
+                    WebsiteData website, 
+                    Date    startDate, 
+                    Date    endDate, 
+                    String  catName, 
+                    String  status, 
+                    Integer maxEntries,
+                    Boolean pinned) throws RollerException
+    {
+        WeblogCategoryData cat = null;        
+        if (StringUtils.isNotEmpty(catName) && website != null)
+        {    
+           cat = getWeblogCategoryByPath(website, catName);
+           if (cat == null) catName = null;
+        }
+        if (catName != null && catName.trim().equals("/"))
+        {
+            catName = null;
+        }
+                    
+        try
+        {
+            Session session = ((HibernateStrategy)mStrategy).getSession();
+            Criteria criteria = session.createCriteria(WeblogEntryData.class);
+            
+            if (website != null)
+            {
+                criteria.add(Expression.eq("website", website));
+            }
+            else 
+            {
+                criteria.createAlias("website","w");
+                criteria.add(Expression.eq("w.isEnabled", Boolean.TRUE));
+            }
+    
+            if (startDate != null)
+            {
+                criteria.add(
+                    Expression.ge("pubTime", startDate));
+            }
+            
+            if (endDate != null)
+            {
+                criteria.add(
+                    Expression.le("pubTime", endDate));
+            }
+                            
+            if (cat != null && website != null)
+            {
+                criteria.add(Expression.eq("category", cat));
+            }
+            
+            if (status != null && status.equals(DRAFT_ONLY))
+            {
+                criteria.add(
+                    Expression.eq("publishEntry", Boolean.FALSE));
+            }        
+            else if (status != null && status.equals(PUB_ONLY))
+            {
+                criteria.add(
+                    Expression.eq("publishEntry", Boolean.TRUE));
+            }
+
+            if (pinned != null)
+            {
+                criteria.add(Expression.eq("pinnedToMain", pinned));
+            }
+                            
+            criteria.addOrder(Order.desc("pubTime"));
+            
+            if (maxEntries != null) 
+            {
+                criteria.setMaxResults(maxEntries.intValue());
+            }            
+            return criteria.list();
+        }
+        catch (HibernateException e)
+        {
+            mLogger.error(e);
+            throw new RollerException(e);
+        }
+    }
+    
+    /** 
+     * Use Hibernate directly because Roller's Query API does too much allocation.
+     */
+    public WeblogEntryData getWeblogEntryByAnchor(
+                    WebsiteData website, String anchor) throws RollerException
+    {
+        if (website == null)
+            throw new RollerException("Website is null");
+
+        if (anchor == null)
+            throw new RollerException("Anchor is null");
+
+        Session session = ((HibernateStrategy)mStrategy).getSession();
+        Criteria criteria = session.createCriteria(WeblogEntryData.class);
+        criteria.add(Expression.conjunction()
+                        .add(Expression.eq("website",website))
+                        .add(Expression.eq("anchor",anchor)));
+        criteria.addOrder(Order.desc("pubTime"));
+        criteria.setMaxResults(1);
+        try
+        {
+            List list = criteria.list();
+            return list.size()!=0 ? (WeblogEntryData)list.get(0) : null;
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }
+    }
+    /**
+     * Gets the Date of the latest Entry publish time.
+     *
+     * @param userName User name of weblog or null for all users
+     * @param catName 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
+    {
+        WeblogCategoryData cat = null;
+        Roller mRoller = RollerFactory.getRoller();
+        if (userName != null) 
+        {
+            WebsiteData website = mRoller.getUserManager().getWebsite(userName);
+            if (catName != null && website != null)
+            {    
+               cat = getWeblogCategoryByPath(website, null, catName);
+               if (cat == null) catName = null;
+            }
+            if (catName != null && catName.trim().equals("/"))
+            {
+                catName = null;
+            }
+        }
+        
+        Session session = ((HibernateStrategy)mStrategy).getSession();
+        Criteria criteria = session.createCriteria(WeblogEntryData.class);
+        criteria.add(Expression.eq("publishEntry", Boolean.TRUE));
+        criteria.add(Expression.le("pubTime", new Date()));
+
+        try
+        {
+            if ( userName != null )
+            {
+                WebsiteData website = mRoller.getUserManager().getWebsite(userName);
+                criteria.add(Expression.eq("website", website));
+            }
+
+            if ( cat != null )
+            {
+                criteria.add(Expression.eq("category", cat));
+            }
+            
+            criteria.addOrder(Order.desc("pubTime"));
+            criteria.setMaxResults(1);        
+            List list = criteria.list();
+            if (list.size() > 0)
+            {
+                return ((WeblogEntryData)list.get(0)).getPubTime();
+            }
+            else
+            {
+                return null;
+            }
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }
+    }
+
+    public void moveWeblogCategoryContents(String srcId, String destId)
+        throws RollerException
+    {
+        WeblogCategoryData srcCd =
+            (WeblogCategoryData) mStrategy.load(
+                srcId, WeblogCategoryData.class);
+        
+        WeblogCategoryData destCd =
+            (WeblogCategoryData) mStrategy.load(
+                destId, WeblogCategoryData.class);
+        
+        if (destCd.descendentOf(srcCd))
+        {
+            throw new RollerException(
+                    "ERROR cannot move parent category into it's own child");
+        }
+        
+        // get all entries in category and subcats
+        List results = retrieveWeblogEntries(srcCd, true);    
+
+        // Loop through entries in src cat, assign them to dest cat
+        Iterator iter = results.iterator();
+        WebsiteData website = destCd.getWebsite();
+        while (iter.hasNext())
+        {
+            WeblogEntryData entry = (WeblogEntryData) iter.next();
+            entry.setCategory(destCd);
+            entry.setWebsite(website);
+            entry.save();
+        }
+        
+        // Make sure website's default and bloggerapi categories 
+        // are valid after the move
+        
+        if (srcCd.getWebsite().getDefaultCategory().getId().equals(srcId)
+            || srcCd.getWebsite().getDefaultCategory().descendentOf(srcCd)) 
+        {
+            srcCd.getWebsite().setDefaultCategory(destCd);
+        }
+        
+        if (srcCd.getWebsite().getBloggerCategory().getId().equals(srcId)
+            || srcCd.getWebsite().getBloggerCategory().descendentOf(srcCd)) 
+        {
+            srcCd.getWebsite().setBloggerCategory(destCd);
+        }
+    }
+    
+    public List retrieveWeblogEntries(WeblogCategoryData cat, boolean subcats) 
+        throws RollerException
+    {                
+        try
+        {
+            Session session = ((HibernateStrategy)mStrategy).getSession();
+            List entries = new LinkedList();
+            
+            if (subcats)
+            {   
+                // Get entries in subcategories
+                Criteria assocsQuery = 
+                    session.createCriteria(WeblogCategoryAssoc.class);
+                assocsQuery.add(Expression.eq("ancestorCategory", cat));                
+                Iterator assocs = assocsQuery.list().iterator();                
+                while (assocs.hasNext())
+                {
+                    WeblogCategoryAssoc assoc = (WeblogCategoryAssoc)assocs.next();
+                    Criteria entriesQuery = 
+                        session.createCriteria(WeblogEntryData.class);
+                    entriesQuery.add(
+                        Expression.eq("category", assoc.getCategory()));
+                    Iterator entryIter = entriesQuery.list().iterator();
+                    while (entryIter.hasNext())
+                    {
+                        WeblogEntryData entry = (WeblogEntryData)entryIter.next();
+                        entries.add(entry);
+                    }
+                }                
+            }
+            
+            // Get entries in category
+            Criteria entriesQuery = 
+                session.createCriteria(WeblogEntryData.class);
+            entriesQuery.add(Expression.eq("category", cat));                
+            Iterator entryIter = entriesQuery.list().iterator();
+            while (entryIter.hasNext())
+            {
+                WeblogEntryData entry = (WeblogEntryData)entryIter.next();
+                entries.add(entry);
+            }
+            return entries;
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }
+    }
+
+    /** 
+     * @see org.roller.model.WeblogManager#removeWeblogEntryContents(
+     * org.roller.pojos.WeblogEntryData)
+     */
+    public void removeWeblogEntryContents(WeblogEntryData entry) 
+        throws RollerException
+    {        
+        try
+        {
+            Session session = ((HibernateStrategy)mStrategy).getSession();
+            
+            // remove referers
+            Criteria refererQuery = session.createCriteria(RefererData.class);
+            refererQuery.add(Expression.eq("weblogEntry", entry));
+            List entries = refererQuery.list();
+            for (Iterator iter = entries.iterator(); iter.hasNext();) 
+            {
+                RefererData referer = (RefererData) iter.next();
+                referer.remove();
+            }
+            
+            // remove comments
+            /*
+            Criteria commentQuery = session.createCriteria(RefererData.class);
+            commentQuery.add(Expression.eq("weblogEntry", entry));
+            List comments = commentQuery.list();
+            */
+            List comments = RollerFactory.getRoller().getWeblogManager().getComments(entry.getId(), false);
+            for (Iterator iter = comments.iterator(); iter.hasNext();) 
+            {
+                CommentData comment = (CommentData) iter.next();
+                comment.remove();
+            }
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }
+    }
+
+    /** 
+     * @see org.roller.model.WeblogManager#createAnchor(
+     * org.roller.pojos.WeblogEntryData)
+     */
+    public String createAnchor(WeblogEntryData entry) throws RollerException
+    {        
+        try
+        {
+            // Check for uniqueness of anchor
+            String base = entry.createAnchorBase();
+            String name = base;
+            int count = 0;
+
+            while (true)
+            {
+                if (count > 0)
+                {
+                    name = base + count;
+                }
+                
+                Session session = ((HibernateStrategy)mStrategy).getSession();
+                Criteria criteria = session.createCriteria(WeblogEntryData.class);
+                criteria.add(Expression.eq("website", entry.getWebsite()));
+                criteria.add(Expression.eq("anchor", name));
+                             
+                List results = criteria.list();
+                
+                if (results.size() < 1)
+                {
+                    break;
+                }
+                else
+                {
+                    count++;
+                }
+            }
+            return name;
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }
+    }
+
+    /** 
+     * @see org.roller.model.WeblogManager#checkWeblogCategoryName(org.roller.pojos.WeblogCategoryData)
+     */
+    public boolean isDuplicateWeblogCategoryName(WeblogCategoryData cat) 
+        throws RollerException
+    {        
+        // ensure that no sibling categories share the same name
+        WeblogCategoryData parent = 
+            null == cat.getId() ? (WeblogCategoryData)cat.getNewParent() : cat.getParent();
+           
+        if (null != parent) // don't worry about root
+        {
+            List sameNames;
+            try
+            {
+                Session session = ((HibernateStrategy)mStrategy).getSession();
+                Criteria criteria = session.createCriteria(WeblogCategoryAssoc.class);
+                criteria.createAlias("category", "c");
+                criteria.add(Expression.eq("c.name", cat.getName()));
+                criteria.add(Expression.eq("ancestorCategory", parent));
+                criteria.add(Expression.eq("relation", Assoc.PARENT));
+                sameNames = criteria.list();
+            }
+            catch (HibernateException e)
+            {
+                throw new RollerException(e);        
+            }
+            if (sameNames.size() > 1) 
+            {
+                return true;        
+            }           
+        }
+        return false;
+    }
+
+    /** 
+     * @see org.roller.model.WeblogManager#isWeblogCategoryInUse(org.roller.pojos.WeblogCategoryData)
+     */
+    public boolean isWeblogCategoryInUse(WeblogCategoryData cat) 
+        throws RollerException
+    {
+        try
+        {
+            Session session = ((HibernateStrategy)mStrategy).getSession();
+            Criteria criteria = session.createCriteria(WeblogEntryData.class);
+            criteria.add(Expression.eq("category", cat));   
+            criteria.setMaxResults(1); 
+            int entryCount = criteria.list().size();
+            
+            if (entryCount > 0)
+            {
+                return true;
+            }
+            
+            Iterator cats = cat.getWeblogCategories().iterator();
+            while (cats.hasNext())
+            {
+                WeblogCategoryData childCat = (WeblogCategoryData)cats.next();
+                if (childCat.isInUse())
+                {
+                    return true;
+                }
+            }
+            
+            if (cat.getWebsite().getBloggerCategory().equals(cat))
+            {
+                return true;
+            }
+            
+            if (cat.getWebsite().getDefaultCategory().equals(cat))
+            {
+                return true;
+            }
+            
+            return false;
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }
+    }
+
+    public boolean isDescendentOf(
+            WeblogCategoryData child, WeblogCategoryData ancestor)
+            throws RollerException
+    {
+        boolean ret = false;
+        try
+        {
+            Session session = ((HibernateStrategy)mStrategy).getSession();
+            Criteria criteria = session.createCriteria(WeblogCategoryAssoc.class);
+            criteria.add(Expression.eq("category", child));
+            criteria.add(Expression.eq("ancestorCategory", ancestor));
+            ret = criteria.list().size() > 0;
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);        
+        }
+        return ret;
+    }
+    
+    /** 
+     * @see org.roller.model.WeblogManager#getWeblogCategoryParentAssoc(
+     * org.roller.pojos.WeblogCategoryData)
+     */
+    public Assoc getWeblogCategoryParentAssoc(WeblogCategoryData cat) 
+        throws RollerException
+    {
+        try
+        {
+            Session session = ((HibernateStrategy)mStrategy).getSession();
+            Criteria criteria = session.createCriteria(WeblogCategoryAssoc.class);
+            criteria.add(Expression.eq("category", cat));
+            criteria.add(Expression.eq("relation", Assoc.PARENT));
+            List parents = criteria.list();
+            if (parents.size() > 1)
+            {
+                throw new RollerException("ERROR: more than one parent");
+            }
+            else if (parents.size() == 1)
+            {
+                return (Assoc) parents.get(0);
+            }
+            else
+            {
+                return null;
+            }
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }
+    }
+
+    /** 
+     * @see org.roller.model.WeblogManager#getWeblogCategoryChildAssocs(
+     * org.roller.pojos.WeblogCategoryData)
+     */
+    public List getWeblogCategoryChildAssocs(WeblogCategoryData cat) 
+        throws RollerException
+    {
+        try
+        {
+            Session session = ((HibernateStrategy)mStrategy).getSession();
+            Criteria criteria = session.createCriteria(WeblogCategoryAssoc.class);
+            criteria.add(Expression.eq("ancestorCategory", cat));
+            criteria.add(Expression.eq("relation", Assoc.PARENT));
+            return criteria.list();
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }
+    }
+
+    /** 
+     * @see org.roller.model.WeblogManager#getAllWeblogCategoryDecscendentAssocs(
+     * org.roller.pojos.WeblogCategoryData)
+     */
+    public List getAllWeblogCategoryDecscendentAssocs(WeblogCategoryData cat) 
+        throws RollerException
+    {
+        try
+        {
+            Session session = ((HibernateStrategy)mStrategy).getSession();
+            Criteria criteria = session.createCriteria(WeblogCategoryAssoc.class);
+            criteria.add(Expression.eq("ancestorCategory", cat));
+            return criteria.list();
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }
+    }
+
+    /** 
+     * @see org.roller.model.WeblogManager#getWeblogCategoryAncestorAssocs(org.roller.pojos.WeblogCategoryData)
+     */
+    public List getWeblogCategoryAncestorAssocs(WeblogCategoryData cat) 
+        throws RollerException
+    {
+        try
+        {
+            Session session = ((HibernateStrategy)mStrategy).getSession();
+            Criteria criteria = session.createCriteria(WeblogCategoryAssoc.class);
+            criteria.add(Expression.eq("category", cat));
+            return criteria.list();
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }
+    }
+    
+    /**
+     * Get the maxCount most recent non-spam Comments.  If a Website is presented 
+     * only Comments for that site will be returned.
+     * 
+     * @author lance.lavandowska
+     */
+    public List getRecentComments(WebsiteData website, int maxCount) throws RollerException
+    {
+        try
+        {
+            Session session = ((HibernateStrategy)mStrategy).getSession();
+            Criteria criteria = session.createCriteria(CommentData.class);
+            criteria.add( /* no spam ! */
+                Expression.not(Expression.eq("spam", Boolean.TRUE)));
+            if (website != null) 
+            {
+                criteria.createAlias("weblogEntry","e");
+                criteria.add(Expression.eq("e.website", website));
+            }
+            criteria.addOrder(Order.desc("postTime"));
+            criteria.setMaxResults(maxCount); 
+            return criteria.list();
+        }
+        catch (HibernateException e)
+        {
+            throw new RollerException(e);
+        }        
+    }
+
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/Messages.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/Messages.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/Messages.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/Messages.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,49 @@
+/*
+ * Created on Sep 14, 2003
+ */
+package org.roller.business.hibernate;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * @author dmj
+ */
+public class Messages
+{
+
+    private static final String BUNDLE_NAME = 
+        "org.roller.business.hibernate.messages"; //$NON-NLS-1$
+
+    private static final ResourceBundle RESOURCE_BUNDLE =
+        ResourceBundle.getBundle(BUNDLE_NAME);
+
+    private Messages()
+    {
+    }
+    
+    public static String formatString(String key, String[] args) {
+        return MessageFormat.format(getString(key), (Object[])args);    
+    }
+    
+    public static String formatString(String key, String arg0, String arg1) {
+        return MessageFormat.format(getString(key), (Object[])new String[]{arg0,arg1});            
+    }
+    
+    public static String formatString(String key, String arg) {
+        return MessageFormat.format(getString(key), (Object[])new String[]{arg});            
+    }
+    
+    public static String getString(String key)
+    {
+        try
+        {
+            return RESOURCE_BUNDLE.getString(key);
+        }
+        catch (MissingResourceException e)
+        {
+            return '!' + key + '!';
+        }
+    }
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/messages.properties
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/messages.properties?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/messages.properties (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/messages.properties Fri Oct 21 14:27:36 2005
@@ -0,0 +1,21 @@
+
+HibernateStrategy.openedSession=OPENED session:  
+HibernateStrategy.closedSession=OPENED session:  
+
+HibernateStrategy.exceptionOpeningSession=EXCEPTION opening session
+HibernateStrategy.exceptionClosingSession=EXCEPTION closing session
+
+HibernateStrategy.exceptionStoring=EXCEPTION storing object, id={0}, class={1}
+HibernateStrategy.exceptionRetrieving=EXCEPTION retrieving object, id={0}, class={1}
+HibernateStrategy.exceptionRemoving=EXCEPTION removing object, id={0}, class={1}
+
+HibernateStrategy.duringQuery=During QUERY
+
+HibernateStrategy.nullNotValidId=NULL is not a valid id
+HibernateStrategy.nullNotValidClass=NULL is not a valid class
+HibernateStrategy.nullNotValidQuery=NULL is not a valid query
+HibernateStrategy.nullNotValidArgArray=NULL is not a valid arg array
+HibernateStrategy.nullNotValidArrayType=NULL is not a valid type array
+
+HibernateStrategy.nullPassedIn=NULL passed into storeValueObject()
+

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/package.html?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/package.html (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/hibernate/package.html Fri Oct 21 14:27:36 2005
@@ -0,0 +1,9 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title></title>
+</head>
+<body>
+Concrete and Hibernate-based implementaitons of business layer interfaces.
+</body>
+</html>

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/package.html?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/package.html (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/package.html Fri Oct 21 14:27:36 2005
@@ -0,0 +1,27 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title></title>
+</head>
+<body>
+Abstract implementation of the business layer interfaces.
+
+<p>At this level we avoid dependance on specific persistence engines 
+(e.g. Hibernate). We do this by using an interface named 
+{@link org.roller.business.PersistenceStrategy PersistenceStrategy} 
+to store, retrieve and remove 
+{@link org.roller.pojos.PersistentObject PersistentObjects}.</p>
+
+<img src="roller-persistence.png" 
+    alt="diagram of Roller persistence object and strategy" />
+
+<p>The diagram below illustrates the dependency relationships between the 
+{@link org.roller.pojos org.roller.pojos}, 
+{@link org.roller.model org.roller.model}, and 
+org.roller.business packages.</p>
+
+<img src="roller-services-impl.png" 
+    alt="diagram of Roller business and persistence layers" />
+
+</body>
+</html>

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/roller-persistence.png
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/roller-persistence.png?rev=327589&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_1.x/src/org/roller/business/roller-persistence.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/roller-services-impl.png
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/roller-services-impl.png?rev=327589&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_1.x/src/org/roller/business/roller-services-impl.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/search/FieldConstants.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/search/FieldConstants.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/search/FieldConstants.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/search/FieldConstants.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,33 @@
+/*
+ * Created on Jul 19, 2003
+ *
+ * Authored by: Mindaugas Idzelis  (min@idzelis.com)
+ */
+package org.roller.business.search;
+
+
+/**
+ * @author aim4min
+ *
+ * To change the template for this generated type comment go to
+ * Window>Preferences>Java>Code Generation>Code and Comments
+ */
+public final class FieldConstants
+{
+    //~ Static fields/initializers =============================================
+
+    public static final String ANCHOR = "anchor";
+    public static final String UPDATED = "updated";
+    public static final String ID = "id";
+    public static final String USERNAME = "username";
+    public static final String CATEGORY = "cat";
+    public static final String TITLE = "title";
+    public static final String PUBLISHED = "published";
+    public static final String CONTENT = "content";
+    public static final String CONTENT_STORED = "content_stored";
+    public static final String C_CONTENT = "comment";
+    public static final String C_EMAIL = "email";
+    public static final String C_NAME = "name";
+    public static final String CONSTANT = "constant";
+    public static final String CONSTANT_V = "v"; //must be lowercase, or match the transform rules of the analyzer
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/search/IndexUtil.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/search/IndexUtil.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/search/IndexUtil.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/search/IndexUtil.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,49 @@
+/*
+ * Created on Jul 20, 2003
+ *
+ * Authored by: Mindaugas Idzelis  (min@idzelis.com)
+ */
+package org.roller.business.search;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.Token;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.index.Term;
+import org.roller.business.IndexManagerImpl;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+/**
+ * @author aim4min
+ *
+ * Class containing helper methods. 
+ */
+public class IndexUtil {
+
+	/**
+	 * Create a lucene term from the first token of the input string. 
+	 * 
+	 * @param field The lucene document field to create a term with
+	 * @param input The input you wish to convert into a term
+	 * @return Lucene search term
+	 */
+	public static final Term getTerm(String field, String input) {
+		if (input==null || field==null) return null;
+		Analyzer analyer = IndexManagerImpl.getAnalyzer();
+		TokenStream tokens = analyer.tokenStream(field,
+			new StringReader(input));
+		
+		Token token = null;
+		Term term = null;
+		try {
+			token = tokens.next();
+		} catch (IOException e) {}
+		if (token!=null) {
+			String termt = token.termText();
+			term = new Term(field,termt);
+		}
+		return term;
+	}
+
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/AddEntryOperation.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/AddEntryOperation.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/AddEntryOperation.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/AddEntryOperation.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,73 @@
+/*
+ * Created on Jul 16, 2003
+ *
+ * Authored by: Mindaugas Idzelis  (min@idzelis.com)
+ */
+package org.roller.business.search.operations;
+
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.index.IndexWriter;
+import org.roller.business.IndexManagerImpl;
+import org.roller.model.Roller;
+import org.roller.model.RollerFactory;
+import org.roller.pojos.WeblogEntryData;
+
+
+/**
+ * @author aim4min
+ *
+ * An operation that adds a new log entry into the index.
+ */
+public class AddEntryOperation extends WriteToIndexOperation
+{
+    //~ Static fields/initializers =============================================
+
+    private static Log mLogger =
+        LogFactory.getFactory().getInstance(AddEntryOperation.class);
+
+    //~ Instance fields ========================================================
+
+    private WeblogEntryData data;
+
+    //~ Constructors ===========================================================
+
+    /**
+     * Adds a web log entry into the index.
+     */
+    public AddEntryOperation(IndexManagerImpl mgr, WeblogEntryData data)
+    {
+        super(mgr);
+        this.data = data;
+    }
+
+    //~ Methods ================================================================
+
+    /* (non-Javadoc)
+     * @see java.lang.Runnable#run()
+     */
+    public void doRun()
+    {    	
+        IndexWriter writer = beginWriting();
+        Roller roller = RollerFactory.getRoller();
+        try
+        {
+            if (writer != null)
+            {
+                writer.addDocument(getDocument(data));
+            }
+        }
+        catch (IOException e)
+        {
+            mLogger.error("Problems adding doc to index", e);
+        }
+        finally
+        {
+            if (roller != null) roller.release();
+            endWriting();
+        }    	
+    }
+    
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/IndexOperation.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/IndexOperation.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/IndexOperation.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/IndexOperation.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1 @@
+/*
 * Created on Jul 16, 2003
 * Authored by: Mindaugas Idzelis  (min@idzelis.com)
 */
package org.roller.business.search.operations;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.roller.business.IndexManagerImpl;
import org.roller.business.search.FieldConstants;
import org.roller.pojos.CommentData;
import org.roller.pojos.WeblogCategoryData;
import org.roller.pojos.WeblogEntryData;
import org.roller.util.Utilities;

/**
 * @author aim4min
 * 
 * This is the base class for all index operation. These operations include:
 * 
 * SearchOperation AddWeblogOperation RemoveWeblogOperation
 * RebuildUserIndexOperation
 *  
 */
public abstract class IndexOperation implements Runnable
{
    private static Log mLogger =
        LogFactory.getFactory().getInstance(IndexOperation.class);

    //~ Instance fields
    // ========================================================
    protected IndexManagerImpl manager;

    private IndexReader reader;

    private IndexWriter writer;

    //~ Constructors
    // ===========================================================

    public IndexOperation(IndexManagerImpl manager)
    {
        this.manager = manager;
    }

    //~ Methods
    // ================================================================

    protected Document getDocument(WeblogEntryData data)
    {
        StringBuffer commentEmail = new StringBuffer();
        StringBuffer commentContent = new StringBuffer();
        StringBuffer commentName = new StringBuffer();

        List comments = data.getComments();
        if (comments != null)
        {
            for (Iterator cItr = comments.iterator(); cItr.hasNext();)
            {
                CommentData comment = (CommentData) cItr.next();
                if (comment.getSpam() == null
                        || !comment.getSpam().booleanValue())
                {
                    if (comment.getContent() != null)
                    {
                        commentContent.append(comment.getContent());
                        commentContent.append(",");
                    }
                    if (comment.getEmail() != null)
                    {
                        commentEmail.append(comment.getEmail());
                        commentEmail.append(",");
                    }
                    if (comment.getName() != null)
                    {
                        commentName.append(comment.getName());
                        commentName.append(",");
                    }
                }
            }
        }

        Document doc = new Document();
        doc.add(Field.Keyword(FieldConstants.ID, data.getId()));
        doc.add(Field.UnIndexed(FieldConstants.ANCHOR, data.getAnchor()));
        doc.add(Field.Text(FieldConstants.USERNAME, data.getWebsite().getUser()
                .getUserName()));
        doc.add(Field.Text(FieldConstants.TITLE, data.getTitle()));

        // index the entry text, but don't store it - moved to end of block
        doc.add(Field.UnStored(FieldConstants.CONTENT, data.getText()));

        // store an abbreviated version of the entry text, but don't index
        doc.add(Field.UnIndexed(FieldConstants.CONTENT_STORED, Utilities
                .truncateNicely(Utilities.removeHTML(data.getText()), 240, 260,
                        "...")));

        doc.add(Field.Keyword(FieldConstants.UPDATED, data.getUpdateTime()
                .toString()));
        doc.add(Field.Keyword(FieldConstants.PUBLISHED, data.getPubTime()
                .toString()));

        // index Comments
        doc.add(Field.UnStored(FieldConstants.C_CONTENT, commentContent
                .toString()));
        doc
                .add(Field.UnStored(FieldConstants.C_EMAIL, commentEmail
                        .toString()));
        doc.add(Field.UnStored(FieldConstants.C_NAME, commentName.toString()));

        doc.add(Field.UnStored(FieldConstants.CONSTANT,
                FieldConstants.CONSTANT_V));

        // index Category
        WeblogCategoryData categorydata = data.getCategory();
        Field category = (categorydata == null) ? Field.UnStored(
                FieldConstants.CATEGORY, "") : Field.Text(
                FieldConstants.CATEGORY, categorydata.getName());
        doc.add(category);

        return doc;
    }

    protected IndexReader beginDeleting()
    {
        try
        {
            reader = IndexReader.open(manager.getIndexDirectory());
        }
        catch (IOException e)
        {
        }

        return reader;
    }

    protected void endDeleting()
    {
        if (reader != null)
        {
            try
            {
                reader.close();
            }
            catch (IOException e)
            {
            }
        }
    }

    protected IndexWriter beginWriting()
    {
        try
        {
            writer = new IndexWriter(manager.getIndexDirectory(),
                    IndexManagerImpl.getAnalyzer(), false);
        }
        catch (IOException e)
        {
            mLogger.error("ERROR creating writer");
        }

        return writer;
    }

    protected void endWriting()
    {
        if (writer != null)
        {
            try
            {
                writer.close();
            }
            catch (IOException e)
            {
                mLogger.error("ERROR closing writer",e);
            }
        }
    }

    public void run()
    {
        doRun();
    }

    protected abstract void doRun();
}
\ No newline at end of file

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/ReIndexEntryOperation.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/ReIndexEntryOperation.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/ReIndexEntryOperation.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/ReIndexEntryOperation.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,92 @@
+/*
+ * Created on Jul 16, 2003
+ *
+ * Authored by: Mindaugas Idzelis  (min@idzelis.com)
+ */
+package org.roller.business.search.operations;
+
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.Term;
+import org.roller.business.IndexManagerImpl;
+import org.roller.business.search.FieldConstants;
+import org.roller.model.Roller;
+import org.roller.model.RollerFactory;
+import org.roller.pojos.WeblogEntryData;
+
+/**
+ * @author aim4min
+ *
+ * An operation that adds a new log entry into the index.
+ */
+public class ReIndexEntryOperation extends WriteToIndexOperation
+{
+    //~ Static fields/initializers =============================================
+
+    private static Log mLogger =
+        LogFactory.getFactory().getInstance(AddEntryOperation.class);
+
+    //~ Instance fields ========================================================
+
+    private WeblogEntryData data;
+
+    //~ Constructors ===========================================================
+
+    /**
+     * Adds a web log entry into the index.
+     */
+    public ReIndexEntryOperation(IndexManagerImpl mgr, WeblogEntryData data)
+    {
+        super(mgr);
+        this.data = data;
+    }
+
+    //~ Methods ================================================================
+
+    /* (non-Javadoc)
+     * @see java.lang.Runnable#run()
+     */
+    public void doRun()
+    {    	
+        IndexReader reader = beginDeleting();
+        try
+        {
+            if (reader != null)
+            {
+                Term term = new Term(FieldConstants.ID, data.getId());
+                reader.delete(term);
+            }
+        }
+        catch (IOException e)
+        {
+            mLogger.error("Error deleting doc from index", e);
+        }
+        finally
+        {
+            endDeleting();
+        }
+        
+        IndexWriter writer = beginWriting();
+        Roller roller = RollerFactory.getRoller();
+        try
+        {
+            if (writer != null)
+            {
+                writer.addDocument(getDocument(data));
+            }
+        }
+        catch (IOException e)
+        {
+            mLogger.error("Problems adding doc to index", e);
+        }
+        finally
+        {
+            if (roller != null) roller.release();
+            endWriting();
+        }    	
+    }    
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/ReadFromIndexOperation.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/ReadFromIndexOperation.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/ReadFromIndexOperation.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/ReadFromIndexOperation.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,47 @@
+
+package org.roller.business.search.operations;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.roller.business.IndexManagerImpl;
+
+/**
+ * @author aim4min
+ */
+public abstract class ReadFromIndexOperation extends IndexOperation
+{
+
+    /**
+     * @param manager
+     */
+    public ReadFromIndexOperation(IndexManagerImpl mgr)
+    {
+        super(mgr);
+    }
+
+    private static Log mLogger = LogFactory.getFactory().getInstance(
+            ReadFromIndexOperation.class);
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.lang.Runnable#run()
+     */
+    public final void run()
+    {
+        try
+        {
+            manager.getReadWriteLock().readLock().acquire();
+            doRun();
+        }
+        catch (InterruptedException e)
+        {
+            mLogger.info("Error acquiring read lock on index", e);
+        }
+        finally
+        {
+            manager.getReadWriteLock().readLock().release();
+        }
+    }
+
+}
\ No newline at end of file

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/RebuildUserIndexOperation.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/RebuildUserIndexOperation.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/RebuildUserIndexOperation.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/RebuildUserIndexOperation.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,156 @@
+/*
+ * Created on Jul 16, 2003
+ *
+ * Authored by: Mindaugas Idzelis  (min@idzelis.com)
+ */
+package org.roller.business.search.operations;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.Term;
+import org.roller.RollerException;
+import org.roller.business.IndexManagerImpl;
+import org.roller.business.search.FieldConstants;
+import org.roller.business.search.IndexUtil;
+import org.roller.model.Roller;
+import org.roller.model.RollerFactory;
+import org.roller.model.WeblogManager;
+import org.roller.pojos.WeblogEntryData;
+import org.roller.pojos.WebsiteData;
+
+
+/**
+ * @author aim4min
+ *
+ * An index operation that rebuilds a given users index (or all indexes.)
+ */
+public class RebuildUserIndexOperation extends WriteToIndexOperation
+{
+    //~ Static fields/initializers =============================================
+
+    private static Log mLogger =
+        LogFactory.getFactory().getInstance(RebuildUserIndexOperation.class);
+
+    //~ Instance fields ========================================================
+
+    private WebsiteData website;
+
+    //~ Constructors ===========================================================
+
+    /**
+     * Create a new operation that will recreate an index.
+     *
+     * @param website The website to rebuild the index for, or null for all users.
+     */
+    public RebuildUserIndexOperation(IndexManagerImpl mgr, WebsiteData website)
+    {
+        super(mgr);
+        this.website = website;
+    }
+
+    //~ Methods ================================================================
+
+    /* (non-Javadoc)
+     * @see java.lang.Runnable#run()
+     */
+    public void doRun()
+    {
+        Date start = new Date();
+
+        IndexReader reader = beginDeleting();
+
+        try
+        {
+            if (reader != null)
+            {
+                String userName = null;
+                if (website != null && website.getUser() != null)
+                {
+                    userName = website.getUser().getUserName();
+                }
+                Term tUsername =
+                    IndexUtil.getTerm(FieldConstants.USERNAME, userName);
+
+                if (tUsername != null)
+                {
+                    reader.delete(tUsername);
+                }
+                else
+                {
+                    Term all =
+                        IndexUtil.getTerm(FieldConstants.CONSTANT,
+                                          FieldConstants.CONSTANT_V);
+                    reader.delete(all);
+                }
+            }
+        }
+        catch (IOException e)
+        {
+            mLogger.info("Problems deleting doc from index", e);
+        }
+        finally
+        {
+            endDeleting();
+        }
+
+        IndexWriter writer = beginWriting();
+
+        Roller roller = RollerFactory.getRoller();
+        try
+        {
+            roller.begin();
+            if (writer != null)
+            {
+                WeblogManager weblogManager = roller.getWeblogManager();
+
+                List entries = weblogManager .getWeblogEntries(
+                    website,                 // userName
+                    null,                   // startDate
+                    new Date(),             // endDate // don't index 'future' entries
+                    null,                   // catName
+                    WeblogManager.PUB_ONLY, // status
+                    null);    
+
+                for (Iterator wbItr = entries.iterator(); wbItr.hasNext();) 
+                {
+                    WeblogEntryData entry = (WeblogEntryData) wbItr.next();
+                    writer.addDocument(getDocument(entry));
+                    mLogger.debug(
+                       MessageFormat.format("Indexed entry {0}: {1}",
+                       new Object[] {entry.getPubTime(), entry.getAnchor()}));
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            mLogger.error("ERROR adding doc to index", e);
+        }
+        finally
+        {
+            endWriting();
+            if (roller != null) roller.release();
+        }
+
+        Date end = new Date();
+        double length = (end.getTime() - start.getTime()) / (double) 1000;
+
+        if (website == null)
+        {
+            mLogger.info(
+               "Completed rebuilding index for all users in '" + length + "' secs");
+        }
+        else
+        {
+            mLogger.info("Completed rebuilding index for '" +
+                 website.getUser().getUserName() + "' in '" + length + "' seconds");
+        }
+    }
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/RemoveEntryOperation.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/RemoveEntryOperation.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/RemoveEntryOperation.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/RemoveEntryOperation.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,73 @@
+/*
+ * Created on Jul 16, 2003
+ * Authored by: Mindaugas Idzelis  (min@idzelis.com)
+ *
+ */
+package org.roller.business.search.operations;
+
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.roller.business.IndexManagerImpl;
+import org.roller.business.search.FieldConstants;
+import org.roller.pojos.WeblogEntryData;
+
+
+/**
+ * @author aim4min
+ *
+ * An operation that removes the weblog from the index.
+ */
+public class RemoveEntryOperation extends WriteToIndexOperation
+{
+    //~ Static fields/initializers =============================================
+
+    private static Log mLogger =
+        LogFactory.getFactory().getInstance(RemoveEntryOperation.class);
+
+    //~ Instance fields ========================================================
+
+    private WeblogEntryData data;
+
+    //~ Constructors ===========================================================
+
+    /**
+     *
+     */
+    public RemoveEntryOperation(IndexManagerImpl mgr, WeblogEntryData data)
+    {
+        super(mgr);
+        this.data = data;
+    }
+
+    //~ Methods ================================================================
+
+    /* (non-Javadoc)
+     * @see java.lang.Runnable#run()
+     */
+    public void doRun()
+    {
+        IndexReader reader = beginDeleting();
+        try
+        {
+            if (reader != null)
+            {
+                Term term = new Term(FieldConstants.ID, data.getId());
+                reader.delete(term);
+            }
+        }
+        catch (IOException e)
+        {
+            mLogger.error("Error deleting doc from index", e);
+        }
+        finally
+        {
+            endDeleting();
+        }
+    }
+
+ 
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/RemoveUserIndexOperation.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/RemoveUserIndexOperation.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/RemoveUserIndexOperation.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/RemoveUserIndexOperation.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,97 @@
+/*
+ * Created on Jul 16, 2003
+ *
+ * Authored by: Mindaugas Idzelis  (min@idzelis.com)
+ */
+package org.roller.business.search.operations;
+
+import java.io.IOException;
+import java.util.Date;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.roller.business.IndexManagerImpl;
+import org.roller.business.search.FieldConstants;
+import org.roller.business.search.IndexUtil;
+import org.roller.pojos.UserData;
+
+
+/**
+ * @author aim4min
+ *
+ * An index operation that rebuilds a given users index (or all indexes.)
+ */
+public class RemoveUserIndexOperation extends WriteToIndexOperation
+{
+    //~ Static fields/initializers =============================================
+
+    private static Log mLogger =
+        LogFactory.getFactory().getInstance(RemoveUserIndexOperation.class);
+
+    //~ Instance fields ========================================================
+
+    private UserData user;
+
+    //~ Constructors ===========================================================
+
+    /**
+     * Create a new operation that will recreate an index.
+     *
+     * @param website The website to rebuild the index for, or null for all users.
+     */
+    public RemoveUserIndexOperation(IndexManagerImpl mgr, UserData user)
+    {
+        super(mgr);
+        this.user = user;
+    }
+
+    //~ Methods ================================================================
+
+    /* (non-Javadoc)
+     * @see java.lang.Runnable#run()
+     */
+    public void doRun()
+    {
+        Date start = new Date();
+
+        IndexReader reader = beginDeleting();
+
+        try
+        {
+            if (reader != null)
+            {
+                String userName = null;
+                if (user != null)
+                {
+                    userName = user.getUserName();
+                }
+                Term tUsername =
+                    IndexUtil.getTerm(FieldConstants.USERNAME, userName);
+
+                if (tUsername != null)
+                {
+                    reader.delete(tUsername);
+                }
+            }
+        }
+        catch (IOException e)
+        {
+            mLogger.info("Problems deleting doc from index", e);
+        }
+        finally
+        {
+            endDeleting();
+        }
+
+        Date end = new Date();
+        double length = (end.getTime() - start.getTime()) / (double) 1000;
+
+        if (user != null)
+        {
+            mLogger.info("Completed deleting indices for '" +
+                            user.getUserName() + "' in '" + length + "' seconds");
+        }
+    }
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/SearchOperation.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/SearchOperation.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/SearchOperation.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/SearchOperation.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,162 @@
+/*
+ * Created on Jul 18, 2003
+ * Authored by: Mindaugas Idzelis  (min@idzelis.com)
+ */
+package org.roller.business.search.operations;
+
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.queryParser.MultiFieldQueryParser;
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Hits;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.TermQuery;
+import org.roller.business.IndexManagerImpl;
+import org.roller.business.search.FieldConstants;
+import org.roller.business.search.IndexUtil;
+import org.roller.model.IndexManager;
+
+
+/**
+ * @author aim4min
+ *
+ * An operation that searches the index.
+ */
+public class SearchOperation extends ReadFromIndexOperation
+{
+    //~ Static fields/initializers =============================================
+
+    private static Log mLogger =
+        LogFactory.getFactory().getInstance(SearchOperation.class);
+        
+    private static String[] SEARCH_FIELDS = new String[]{
+        FieldConstants.CONTENT, FieldConstants.TITLE, 
+        FieldConstants.C_CONTENT, FieldConstants.CATEGORY
+    };
+    
+    private static Sort SORTER = new Sort( new SortField(
+        FieldConstants.PUBLISHED, SortField.STRING, true) );
+
+    //~ Instance fields ========================================================
+
+    private String term;
+    private String username;
+    private String category;
+    private Hits searchresults;
+    private String parseError;
+
+    //~ Constructors ===========================================================
+
+    /**
+     * Create a new operation that searches the index.
+     */
+    public SearchOperation(IndexManager mgr)
+    {
+        // TODO: finish moving  IndexManager to backend, so this cast is not needed
+        super((IndexManagerImpl)mgr); 
+    }
+
+    //~ Methods ================================================================
+
+    public void setTerm(String term)
+    {
+        this.term = term;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Runnable#run()
+     */
+    public void doRun()
+    {
+        searchresults = null;
+      		
+        IndexSearcher searcher = null;
+
+        try
+        {
+            IndexReader reader = manager.getSharedIndexReader();
+            searcher = new IndexSearcher(reader);
+
+            Query query =
+                MultiFieldQueryParser.parse(
+                    term, SEARCH_FIELDS, new StandardAnalyzer());
+
+            Term tUsername =
+                IndexUtil.getTerm(FieldConstants.USERNAME, username);
+
+            if (tUsername != null)
+            {
+                BooleanQuery bQuery = new BooleanQuery();
+                bQuery.add(query, true, false);
+                bQuery.add(new TermQuery(tUsername), true, false);
+                query = bQuery;
+            }
+            
+            Term tCategory =
+                IndexUtil.getTerm(FieldConstants.CATEGORY, category);
+
+            if (tCategory != null)
+            {
+                BooleanQuery bQuery = new BooleanQuery();
+                bQuery.add(query, true, false);
+                bQuery.add(new TermQuery(tCategory), true, false);
+                query = bQuery;
+            }
+            searchresults = searcher.search(query, null/*Filter*/, SORTER);
+        }
+        catch (IOException e)
+        {
+            mLogger.error("Error searching index", e);
+            parseError = e.getMessage();
+        }
+        catch (ParseException e)
+        {
+            // who cares?
+            parseError = e.getMessage();
+        }
+        // don't need to close the reader, since we didn't do any writing!
+    }
+
+    public Hits getResults()
+    {
+        return searchresults;
+    }
+    
+    public int getResultsCount()
+    {
+        if (searchresults == null) return -1;
+        
+        return searchresults.length();
+    }
+    
+    public String getParseError()
+    {
+        return parseError;
+    }
+
+    /**
+     * @param string
+     */
+    public void setUsername(String username)
+    {
+        this.username = username;
+    }
+
+    /**
+     * @param parameter
+     */
+    public void setCategory(String category)
+    {
+        this.category = category;
+    }
+
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/WriteToIndexOperation.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/WriteToIndexOperation.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/WriteToIndexOperation.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/WriteToIndexOperation.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,54 @@
+/*
+ * Created on Aug 12, 2003
+ *
+ * To change the template for this generated file go to
+ * Window>Preferences>Java>Code Generation>Code and Comments
+ */
+package org.roller.business.search.operations;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.roller.business.IndexManagerImpl;
+
+/**
+ * @author aim4min
+ *
+ * To change the template for this generated type comment go to
+ * Window>Preferences>Java>Code Generation>Code and Comments
+ */
+public abstract class WriteToIndexOperation extends IndexOperation {
+
+	/**
+     * @param manager
+     */
+    public WriteToIndexOperation(IndexManagerImpl mgr)
+    {
+        super(mgr);
+    }
+
+    private static Log mLogger =
+		LogFactory.getFactory().getInstance(WriteToIndexOperation.class);
+		  
+	/* (non-Javadoc)
+	 * @see java.lang.Runnable#run()
+	 */
+	public void run() 
+    {
+		try 
+        {
+            manager.getReadWriteLock().writeLock().acquire();
+            mLogger.info("Starting search index operation");
+            doRun();
+            mLogger.info("Search index operation complete");
+		} 
+        catch (InterruptedException e) 
+        {
+			mLogger.error("Error acquiring write lock on index", e);
+		} 
+        finally 
+        {
+			manager.getReadWriteLock().writeLock().release();
+		}
+        manager.resetSharedReader();
+	}
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/package.html?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/package.html (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/search/operations/package.html Fri Oct 21 14:27:36 2005
@@ -0,0 +1,9 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title></title>
+</head>
+<body>
+Lucene-based search operations to be executed by ThreadManager.<br>
+</body>
+</html>

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/search/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/search/package.html?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/search/package.html (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/search/package.html Fri Oct 21 14:27:36 2005
@@ -0,0 +1,9 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title></title>
+</head>
+<body>
+Utilities needed by implementation of search interface.
+</body>
+</html>

Added: incubator/roller/branches/roller_1.x/src/org/roller/business/utils/ConsistencyCheck.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/business/utils/ConsistencyCheck.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/business/utils/ConsistencyCheck.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/business/utils/ConsistencyCheck.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,315 @@
+
+package org.roller.business.utils;
+
+import java.io.FileInputStream;
+import java.sql.*;
+import java.util.*;
+
+/**
+ * Roller database consistency checker.<br />
+ * Don't run this unless you know what you are doing!</br >
+ * 
+ * <p>Configuration:<br />
+ * 
+ * Program looks in current directory for db.properties file with database
+ * connection properties driverClassName and connectionUrl. 
+ * 
+ * Program expects JDBC driver jar to be on classpath.</p>
+ * 
+ * <p>Usage:<br />
+ * 
+ * java -cp ./WEB-INF/lib/rollerbeans.jar org.roller.business.utils.ConsistencyCheck<br />
+ * 
+ * <br />Options:<br />
+ * -v Verbose<br />
+ * -d Delete orphans</p>
+ */
+public class ConsistencyCheck 
+{
+    /** 
+     * Consistency checker, find and optionally delete orphans. 
+     */
+    public static void main(String[] args) throws Exception
+    {
+        Properties props = new Properties();
+        props.load(new FileInputStream("rollerdb.properties"));
+        Connection con = createConnection(props,"");
+        
+        boolean delete = false;
+        boolean verbose = false;
+        if (args.length > 0) 
+        {
+            if ("-purge".equals(args[0])) 
+            {
+                delete = true;
+            }
+            else if ("-v".equals(args[0]))
+            {
+                verbose = true;
+            }
+        }        
+        
+        findAndDeleteOrphans(con, delete, verbose);
+    }
+    
+    /** 
+     * Create connection based on properties:<br/>
+     * - driverClassName<br/>
+     * - connectionUrl<br/>
+     * - userName<br/>
+     * - password<br/>
+     */
+    public static Connection createConnection(Properties props, String prefix) 
+        throws Exception
+    {
+        Connection con = null;
+        if (prefix == null) 
+        {
+            prefix = "";
+        }
+        String driverClassName = props.getProperty(prefix+"driverClassName");
+        String connectionUrl = props.getProperty(prefix+"connectionUrl");
+        String userName = props.getProperty(prefix+"userName");
+        String password = props.getProperty(prefix+"password");
+        
+        Class.forName(driverClassName);
+        if (userName != null && password != null)
+        {
+           con = DriverManager.getConnection(connectionUrl, userName, password);
+        }
+        else
+        {
+           con = DriverManager.getConnection(connectionUrl);
+        }
+        return con;
+    }
+    
+    /** Find and optionally delete all safely deletable orphans. */
+    public static void findAndDeleteOrphans(Connection con, boolean delete, boolean verbose) 
+        throws SQLException
+    {
+        // websites with bad user?
+        findOrphans(con, "website", "userid", "rolleruser", delete, verbose);
+        
+        // userroles with bad user?
+        findOrphans(con, "userrole", "userid", "rolleruser", delete, verbose);
+        
+        // folders with bad website?
+        findOrphans(con, "folder", "websiteid", "website", delete, verbose);
+        
+        // bookmarks with bad folder?
+        findOrphans(con, "bookmark", "folderid", "folder", delete, verbose);
+        
+        // weblogcategories with bad website?
+        findOrphans(con, "weblogcategory", "websiteid", "website", delete, verbose);
+        
+        // weblogcategoryassocs with bad category?
+        findOrphans(con, "weblogcategoryassoc", "categoryid", "weblogcategory", delete, verbose);
+        
+        // weblog entries with bad website?
+        findOrphans(con, "weblogentry", "websiteid", "website", delete, verbose);
+                
+        // comments with bad weblogentry?
+        findOrphans(con, "comment", "entryid", "weblogentry", delete, verbose);
+        
+        // Referers with bad website?
+        findOrphans(con, "referer", "websiteid", "website", delete, verbose);
+        
+        // Referers with bad website?
+        findOrphans(con, "referer", "entryid", "weblogentry", delete, verbose);              
+        
+        if (delete)
+        {
+            correctWeblogEntries(con);
+            correctWebsites(con);
+            correctFolderTrees(con, delete);
+        }
+    }
+    
+    /**
+     * @param con
+     * @param delete
+     */
+    private static void correctFolderTrees(Connection con, boolean delete) throws SQLException
+    {
+        PreparedStatement rootStatement = con.prepareStatement(
+            "select a.id from folder as f, folderassoc as a where "+
+            "f.websiteid=? and f.id=a.folderid and "+
+            "a.relation='PARENT' and a.ancestorid is null");
+        PreparedStatement childrenStatement = con.prepareStatement(
+            "select id from folderassoc where ancestorid=?");
+
+        // loop through all websites
+        Statement websitesStatement = con.createStatement();
+        ResultSet websitesResultSet = 
+            websitesStatement.executeQuery("select id from website");
+        while (websitesResultSet.next()) 
+        {
+            String websiteId = websitesResultSet.getString(1);
+            //debug("Website "+websiteId);
+            
+            // find root folder(s)
+            List rootIds = new LinkedList();
+            rootStatement.clearParameters();
+            rootStatement.setString(1, websiteId);
+            ResultSet rootResultSet = rootStatement.executeQuery();
+            while (rootResultSet.next())
+            {
+                rootIds.add(rootResultSet.getString(1));
+            }
+            if (rootIds.size() > 1) 
+            {
+                // too many roots, need to figure out which are bogus
+                Iterator rootIter = rootIds.iterator();
+                while (rootIter.hasNext())
+                {
+                    String rootId = (String)rootIter.next();
+                    childrenStatement.clearParameters();
+                    childrenStatement.setString(1, rootId);
+                    ResultSet childrenResultSet = childrenStatement.executeQuery();
+                    List childIds = new LinkedList();
+                    while (childrenResultSet.next()) 
+                    {
+                        childIds.add(childrenResultSet.getString(1));
+                    }
+                    if (childIds.size() == 0)
+                    {
+                        debug("Folder "+rootId+" in website "+websiteId+"is a bogus root folder!");
+                    }
+                }
+            }
+            else if (rootIds.size() == 0)
+            {
+                debug("Website "+websiteId+" has no root folder!");
+            }
+        }
+    }
+
+    private static void correctWeblogEntries(Connection con) throws SQLException
+    {
+        List entries = findOrphans(con, "weblogentry", "categoryid", "weblogcategory", false, false);
+        Iterator entryIter = entries.iterator();
+        while (entryIter.hasNext())
+        {
+            String entryid = (String) entryIter.next();
+            Statement websiteSt = con.createStatement();
+            ResultSet websiteRs = websiteSt.executeQuery(
+                "select websiteid from weblogentry where id="+entryid);
+            websiteRs.first();
+            String websiteid = websiteRs.getString(0);
+            
+            String rootid = getRootCategoryId(con, websiteid);
+            Statement st = con.createStatement();
+            st.executeUpdate("update weblogentry set categoryid='"+rootid+"' "
+                           +" where id='"+entryid+"'");
+        }   
+    }
+    
+    public static void correctWebsites(Connection con) throws SQLException
+    {
+        List websites = findOrphans(con, "website", "defaultcatid", "weblogcategory", false, false);
+        Iterator websiteIter = websites.iterator();
+        while (websiteIter.hasNext())
+        {
+            String websiteid = (String) websiteIter.next();
+            String rootid = getRootCategoryId(con, websiteid);
+            Statement st = con.createStatement();
+            st.executeUpdate("update website set defaultcatid='"+rootid+"' "
+                    +" where id='"+websiteid+"'");
+        }
+    
+        websites = findOrphans(con, "website", "bloggercatid", "weblogcategory", false, false);
+        websiteIter = websites.iterator();
+        while (websiteIter.hasNext())
+        {
+            String websiteid = (String) websiteIter.next();
+            String rootid = getRootCategoryId(con, websiteid);
+            Statement st = con.createStatement();
+            st.executeUpdate("update website set bloggercatid='"+rootid+"' "
+                            +"where id='"+websiteid+"'");
+        }
+    }
+    
+    public static String getRootCategoryId(Connection con, String websiteid)
+        throws SQLException
+    {
+        Statement st = con.createStatement();
+        String query = 
+            "select c.id from weblogcategory as c, weblogcategoryassoc as a "
+            +"where a.categoryid=c.id and a.ancestorid is null "
+            +"and c.websiteid ='"+websiteid+"'";
+        //System.out.println(query);
+        ResultSet rs = st.executeQuery(query);        
+        rs.next();
+        return rs.getString(1);
+    }
+    
+    /** Find orphans, records in a manytable that refer to a onetable that 
+     * no longer exists.
+     * @param con       Database connection to be used.
+     * @param manytable Name of the manytable.
+     * @param fkname    Name of the foreign key field in the manytable.
+     * @param onetable  Name of the onetable.
+     * @param delete    True if orphans in manytable are to be deleted.
+     * @return          List of orphans found (will be empty if delete is true.
+     * @throws SQLException
+     */
+    public static List findOrphans(
+        Connection con, String manytable, String fkname, String onetable, boolean delete, boolean verbose) 
+        throws SQLException
+    {
+        List orphans = new LinkedList();
+        
+        Statement stall = con.createStatement();
+        ResultSet rsall = stall.executeQuery(
+            "select id,"+fkname+" as fk from "+manytable);
+        while (rsall.next()) 
+        {
+            String id = rsall.getString("id");
+            String fk = rsall.getString("fk");
+            if (fk != null)
+            {
+                Statement stone = con.createStatement();
+                ResultSet rsone = stone.executeQuery(
+                    "select id from "+onetable+" where id='"+fk+"' limit 1");
+                if (!rsone.next()) 
+                {
+                    orphans.add(id);  
+                    System.out.println("   Found orphan in "+manytable+" id="+id); 
+                }                
+            }
+        } 
+        
+        if (!delete)
+        {
+            debug("Orphans found in "+manytable+" = "+orphans.size());
+            if (verbose)
+            {
+                Iterator iter = orphans.iterator();
+                while (iter.hasNext())
+                {
+                    String id = (String) iter.next();
+                    debug("   "+manytable+" id="+id);
+                }
+            }
+        }
+        else
+        {
+            debug("Deleting orphans found in "+manytable+" count = "+orphans.size());            
+            Iterator iter = orphans.iterator();
+            while (iter.hasNext())
+            {
+                String id = (String) iter.next();
+                Statement stdel = con.createStatement();
+                stdel.executeUpdate("delete from "+manytable+" where id='"+id+"'");
+            }
+            orphans = new LinkedList();
+        }
+        return orphans;
+    }
+    
+    private static void debug(String msg) 
+    {
+        System.out.println("DEBUG: "+msg);   
+    }
+}



Mime
View raw message