head	1.10;
access;
symbols
	TIGRIS_0_9_2_4:1.7
	TIGRIS_0_9_2_3:1.7
	HELM_PEER_PORT_BRANCH:1.9.0.2
	TURBINE_PEER:1.9
	TIGRIS_0_9_2_1:1.9
	TIGRIS_0_9_2:1.7.0.2;
locks; strict;
comment	@# @;


1.10
date	2001.02.21.04.14.34;	author edk;	state dead;
branches;
next	1.9;

1.9
date	2001.01.26.18.29.11;	author edk;	state Exp;
branches
	1.9.2.1;
next	1.8;

1.8
date	2001.01.26.05.24.08;	author edk;	state dead;
branches;
next	1.7;

1.7
date	2001.01.18.17.28.21;	author leonardr;	state Exp;
branches;
next	1.6;

1.6
date	2001.01.12.05.54.52;	author dlr;	state Exp;
branches;
next	1.5;

1.5
date	2001.01.12.02.01.02;	author leonardr;	state Exp;
branches;
next	1.4;

1.4
date	2001.01.10.23.03.41;	author leonardr;	state Exp;
branches;
next	1.3;

1.3
date	2001.01.10.01.52.19;	author leonardr;	state Exp;
branches;
next	1.2;

1.2
date	2001.01.06.18.50.39;	author jrobbins;	state Exp;
branches;
next	1.1;

1.1
date	2001.01.02.17.19.57;	author leonardr;	state Exp;
branches;
next	;

1.9.2.1
date	2001.01.28.01.02.20;	author dlr;	state dead;
branches;
next	;


desc
@@


1.10
log
@these appear to have been subsummed by the peer port
@
text
@/* ================================================================
 * Copyright (c) 2000 CollabNet.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * 3. The end-user documentation included with the redistribution, if
 * any, must include the following acknowlegement: "This product includes
 * software developed by CollabNet (http://www.collab.net/)."
 * Alternately, this acknowlegement may appear in the software itself, if
 * and wherever such third-party acknowlegements normally appear.
 * 
 * 4. The hosted project names must not be used to endorse or promote
 * products derived from this software without prior written
 * permission. For written permission, please contact info@@collab.net.
 * 
 * 5. Products derived from this software may not use the "Tigris" name
 * nor may "Tigris" appear in their names without prior written
 * permission of CollabNet.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL COLLABNET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ====================================================================
 * 
 * This software consists of voluntary contributions made by many
 * individuals on behalf of CollabNet.
 */

package org.tigris.helm.tool.paginate;

import java.util.*;
import java.net.URLEncoder;
import java.sql.*;

import gnu.regexp.*;

import org.webmacro.util.Log;
import org.webmacro.servlet.WebContext;

import com.workingdogs.village.*;

import org.joist.database.*;

/**
 * An abstract class describing a list which can be paginated.
 *
 * @@author <a href="mailto:leonardr@@collab.net">Leonard Richardson</a>
 * @@version $Id: PaginatableDatabaseBackedList.java,v 1.9 2001/01/26 18:29:11 edk Exp $
 */
abstract public class PaginatableDatabaseBackedList extends PaginatableList
{   
    protected Connection connection;
    protected DataManager dMgr;

    protected String baseQuery;
    protected Criterion searchCriterion;
    protected String orderBy;

    protected boolean dirty;

    protected boolean specialCriterion;

    public static final Map filterableFields = new HashMap();

    private static Log log = new Log("PList", "PaginatableList");
    private static final boolean debug = true;

    public Map getFilterableFields()
    {
        return filterableFields;
    }
   
    /**
     * A basic constructor.
     */
    public PaginatableDatabaseBackedList
        (Connection connection, DataManager dMgr, Integer itemsPerPage, 
         String baseQuery, Criterion criterion, String orderBy)
    {
        this.connection = connection;
        this.dMgr = dMgr;
        this.itemsPerPage = itemsPerPage.intValue();
        this.baseQuery = baseQuery;
        if (criterion != null && criterion.getMatchType() == Criterion.SPECIAL_MATCH)
        {
            this.searchCriterion = makeSimpleSearchCriterion(criterion.getValue());
            this.specialCriterion = true;
        } else {
            this.searchCriterion = criterion;
            this.specialCriterion = false;
        }
        this.orderBy = orderBy;
        clear();
        dirty = true;
    }

    public String toString()
    {
        StringBuffer d = new StringBuffer();
        d.append("\nPaginatableDatabaseBackedList subclass with query \"");
        d.append(baseQuery).append("\", criterion \"");
        d.append(searchCriterion == null ? "null" : searchCriterion.toString());
        d.append("\", order clause \"").append(orderBy);
        d.append("\", currently holding ").append(size());
        d.append(" entries.\n");
        return d.toString();
    }

    /**
     * Changes the extra criteria used to filter records, and marks
     * the record list as dirty so that the next page request will hit
     * the database.  
     */
    public void changeCriterion(Criterion c)
    {
        this.searchCriterion = c;
        dirty = true;
    }

    /**
     * Changes the extra criteria used to filter records, and marks
     * the record list as dirty so that the next page request will hit
     * the database.  
     */
    public Criterion makeSimpleSearchCriterion(String value)
    {
        Map mapToUse = getFilterableFields();
        Criterion c = null;
        if (mapToUse != null)
        {
            for (Iterator i = mapToUse.keySet().iterator(); i.hasNext();)
            {
                String key = (String)i.next();
                log.info("Key: " + key);
                String fieldName = (String)mapToUse.get(key);
                log.info("FieldName: " + fieldName);
                Criterion newCrit = new Criterion
                    (fieldName, Criterion.CONTAINING_MATCH, value);
                if (c == null)
                {
                    c = newCrit;
                } else {
                    c.or(newCrit);
                }
            }
        }
        return c;
    }    

    /**
     * Returns the field, if any, which should be used to display alphabetic
     * guides in the navbar.
     */
    public String alphabetizedByField()
    {
        return null;
    }

    /**
     * Retrieves records from the database if neccessary, and turns
     * the requested record range into business objects.
     */
    public List getPage(Integer page)
        throws DataSetException, SQLException
    {
        return objectifyRecords(getPageRecords(page));
    }

    /**
     * Retrieves records from the database if neccessary, and returns a
     * List of the records corresponding to the requested page.
     */
    public List getPageRecords(Integer page)
        throws DataSetException, SQLException
    {
        List records = null;
        int pageNo = page.intValue();
        if (dirty == true)
        {
            retrieveRecords();
        }

        int itemsOnThisPage = itemsPerPage;
        if (itemsOnThisPage == 0)
        {
            itemsOnThisPage = size();
        }

        if (isEmpty())
        {
            records = new ArrayList();
        } else {
            int start = firstItem(page);
            int finish = lastItem(page);
            records = subList(start, finish);
        }
        return records;
    }
    
    /**
     * Makes a guide to the given page for use in the navbar.
     */
    public String makeGuide(Integer page)
        throws DataSetException, SQLException
    {
        String guideField = alphabetizedByField();
        if (guideField == null) return "";
        List records = getPageRecords(page);
        StringBuffer guide = new StringBuffer("(");
        String firstVal = guideLetter((Record)records.get(0));
        String lastVal = guideLetter((Record)records.get(records.size()-1));
        guide.append(firstVal);
        if (!firstVal.equals(lastVal))
        {
            guide.append("-").append(lastVal);
        }
        guide.append(")");
        return guide.toString();
    }

    /**
     * Gets the first letter of the appropriate field.
     */
    private String guideLetter(Record r)
        throws DataSetException, SQLException
    {
        return r.getValue(alphabetizedByField()).asString().substring(0,1).toUpperCase();
    }

    /**
     * Ensure that the link describes the search criterion properly.
     */
    public String appendQueryString()
    {
        StringBuffer extra = new StringBuffer();
        if (searchCriterion != null)
        {
            if (specialCriterion && searchCriterion.getValue() != null)
            {
                extra.append(URLEncoder.encode(Criterion.SIMPLE_FILTER_VALUE))
                    .append("=").append(searchCriterion.getValue());
            }
            else
            {
                if (searchCriterion != null)
                {
                    extra.append(searchCriterion.toQueryString());
                }
                
                if (extra.length() > 0)
                {
                    extra.append("&FILTER+CHECK=TRUE");
                }
            }
        }        
        return extra.toString();
    }
    
    /**
     * retrieveRecords should set dirty to false and turn the
     * baseQuery and criterion into a List of Record objects,
     * doing whatever additional filtering is needed.
     */
    public void retrieveRecords()
        throws DataSetException, SQLException
    {
        clear();
        addAll(runQuery());
        dirty = false;
    }

    public int numberOfItems()
        throws DataSetException, SQLException
    {
        if (dirty)
        {
            retrieveRecords();
        }
        return size();
    }

    protected List runQuery()
        throws DataSetException, SQLException
    {
        StringBuffer statement = new StringBuffer();
        /*
         * TODO: This could break in the unlikely situation that
         * "WHERE" appears in a table name or something. Make it more
         * robust.  
         */
        String connector = "WHERE";                
        int index = baseQuery.toLowerCase().indexOf("where");
        if(index != -1)
        {
            connector = "AND";
        }
        
        statement.append(baseQuery);       
        if (searchCriterion != null && !searchCriterion.toString().equals(""))
        {
            statement.append(" ").append(connector).append(" ");
            statement.append(searchCriterion.toString());        
        }
        
        if (orderBy != null && !orderBy.equals(""))
        {
            statement.append(" ORDER BY ").append(orderBy);
        }

        QueryDataSet qds = new QueryDataSet(connection, statement.toString());
        dMgr.registerToClose(qds);
        qds.fetchRecords();

        List records = new ArrayList();
        for (int i = 0; i < qds.size(); i++)
        {
            records.add(qds.getRecord(i));            
        }
        return records;
    }

    /**
     * This method takes a list of Records and turns the records of
     * the list into the appropriate type of business object.
     */
    protected abstract List objectifyRecords(List records) 
        throws DataSetException;
}
@


1.9
log
@readding all the files as part of the process of returning to the way
things were as of tuesday
@
text
@d66 1
a66 1
 * @@version $Id: PaginatableDatabaseBackedList.java,v 1.7 2001/01/18 17:28:21 leonardr Exp $
@


1.9.2.1
log
@Porting to the Turbine Peer system.  -dlr and leonardr
@
text
@d66 1
a66 1
 * @@version $Id: PaginatableDatabaseBackedList.java,v 1.9 2001/01/26 18:29:11 edk Exp $
@


1.8
log
@revert this stuff to its state as of 2001/01/24 12:42:00 GMT -- with
the following exceptions, which have some different modifications so
they'll work with changes which have happened in joist:

ProjectNewsEdit.java
SkinManager.java
SkinStyleElementValueManager.java
StyleElementManager.java
StyleManager.java

it compiles.  i dunno if it works, though.
@
text
@@


1.7
log
@Don't show SIMPLE_FILTER_VALUE in query string if there isn't a filter value
@
text
@d66 1
a66 1
 * @@version $Id: PaginatableDatabaseBackedList.java,v 1.6 2001/01/12 05:54:52 dlr Exp $
@


1.6
log
@cheaper check
@
text
@d66 1
a66 1
 * @@version $Id: PaginatableDatabaseBackedList.java,v 1.5 2001/01/12 02:01:02 leonardr Exp $
d256 1
a256 1
            if (specialCriterion)
@


1.5
log
@Propagate filter value through pages.
@
text
@d66 1
a66 1
 * @@version $Id: PaginatableDatabaseBackedList.java,v 1.4 2001/01/10 23:03:41 leonardr Exp $
d260 3
a262 1
            } else {
d268 1
a268 1
                if (!extra.equals(""))
@


1.4
log
@Allow null criteria.
@
text
@d50 1
d66 1
a66 1
 * @@version $Id: PaginatableDatabaseBackedList.java,v 1.3 2001/01/10 01:52:19 leonardr Exp $
d79 2
d105 1
d108 1
d253 1
a253 1
        String extra = "";
d256 17
a272 7
            extra = searchCriterion.toQueryString();
        }
        if (!extra.equals(""))
        {
            extra += "&FILTER+CHECK=TRUE";
        }
        return extra;
@


1.3
log
@Filter interface is much simpler now. The more complicated interface is commented out in case we need it again.
@
text
@d65 1
a65 1
 * @@version $Id: PaginatableDatabaseBackedList.java,v 1.2 2001/01/06 18:50:39 jrobbins Exp $
d99 1
a99 1
        if (criterion.getMatchType() == Criterion.SPECIAL_MATCH)
d248 5
a252 1
        String extra = searchCriterion.toQueryString();
d300 1
a300 1
        if (searchCriterion.toString() != "")
d305 2
a306 2

        if (orderBy != null && !(orderBy.equals("")))
@


1.2
log
@split one big statment into multiple ones so that stack traceback will show more precise line number
@
text
@d65 1
a65 1
 * @@version $Id: PaginatableDatabaseBackedList.java,v 1.1 2001/01/02 17:19:57 leonardr Exp $
d87 1
a87 1

d99 6
a104 1
        this.searchCriterion = criterion;
d109 1
a109 1
    
d132 30
@


1.1
log
@Split PaginatableList into subclasses PaginatableDatabaseBackedList and PaginatablePrebuiltList. If you want to do simple pagination without messing with the database, use PaginatablePrebuiltList. Note that your list will not be filterable.
@
text
@d65 1
a65 1
 * @@version $Id: PaginatableList.java,v 1.11 2000/12/30 01:03:32 leonardr Exp $
d108 6
a113 6
        d.append("\nPaginatableDatabaseBackedList subclass with query \"")
            .append(baseQuery).append("\", criterion \"")
            .append(searchCriterion.toString())
            .append("\", order clause \"").append(orderBy)
            .append("\", currently holding ").append(size())
            .append(" entries.\n");
@

