head	1.42;
access;
symbols
	TIGRIS_1_1_0RC2:1.4
	TIGRIS_1_1_0RC1:1.4
	TIGRIS_1_1:1.4.0.4
	TIGRIS_1_0_8:1.4
	TIGRIS_1_0_8RC3:1.4
	TIGRIS_1_0_8RC2:1.4
	TIGRIS_1_0_8RC1:1.4
	TIGRIS_1_0_7:1.4
	TIGRIS_1_0_7RC3:1.4
	TIGRIS_1_0_7RC2:1.4
	TIGRIS_1_0_7RC1:1.4
	TIGRIS_1_0_6:1.4
	TIGRIS_1_0_6RC5:1.4
	TIGRIS_1_0_6RC4:1.4
	TIGRIS_1_0_6RC3:1.4
	TIGRIS_1_0_6RC2:1.4
	TIGRIS_1_0_6RC1:1.4
	TIGRIS_1_0_5:1.4
	TIGRIS_1_0_5RC6:1.4
	TIGRIS_1_0_5RC5:1.4
	TIGRIS_1_0_5RC4:1.4
	TIGRIS_1_0_5RC3:1.4
	TIGRIS_1_0_5RC2:1.4
	TIGRIS_1_0_5RC1:1.4
	TIGRIS_1_0_4:1.4
	TIGRIS_1_0_3:1.4
	TIGRIS_1_0_2:1.4
	TIGRIS_1_0_1:1.4
	TIGRIS_1_0:1.4.0.6
	TIGRIS_1_0_0:1.4
	TIGRIS_1_0_0_RC1:1.4.0.2;
locks; strict;
comment	@# @;


1.42
date	2001.08.11.09.08.03;	author dlr;	state Exp;
branches;
next	1.41;

1.41
date	2001.07.02.20.55.20;	author leonardr;	state Exp;
branches;
next	1.40;

1.40
date	2001.06.29.00.57.49;	author leonardr;	state Exp;
branches;
next	1.39;

1.39
date	2001.06.22.19.32.12;	author leonardr;	state Exp;
branches;
next	1.38;

1.38
date	2001.06.18.22.12.20;	author leonardr;	state Exp;
branches;
next	1.37;

1.37
date	2001.06.16.00.22.58;	author leonardr;	state Exp;
branches;
next	1.36;

1.36
date	2001.06.15.21.22.19;	author leonardr;	state Exp;
branches;
next	1.35;

1.35
date	2001.06.15.20.23.08;	author leonardr;	state Exp;
branches;
next	1.34;

1.34
date	2001.06.15.17.11.19;	author leonardr;	state Exp;
branches;
next	1.33;

1.33
date	2001.06.14.21.15.21;	author leonardr;	state Exp;
branches;
next	1.32;

1.32
date	2001.06.13.17.51.09;	author leonardr;	state Exp;
branches;
next	1.31;

1.31
date	2001.06.13.01.44.37;	author leonardr;	state Exp;
branches;
next	1.30;

1.30
date	2001.06.12.23.10.43;	author leonardr;	state Exp;
branches;
next	1.29;

1.29
date	2001.06.09.01.02.15;	author leonardr;	state Exp;
branches;
next	1.28;

1.28
date	2001.06.09.00.04.20;	author leonardr;	state Exp;
branches;
next	1.27;

1.27
date	2001.06.08.21.57.03;	author leonardr;	state Exp;
branches;
next	1.26;

1.26
date	2001.06.08.21.52.09;	author leonardr;	state Exp;
branches;
next	1.25;

1.25
date	2001.06.08.17.18.16;	author leonardr;	state Exp;
branches;
next	1.24;

1.24
date	2001.06.07.02.57.24;	author leonardr;	state Exp;
branches;
next	1.23;

1.23
date	2001.06.06.22.34.56;	author leonardr;	state Exp;
branches;
next	1.22;

1.22
date	2001.05.30.20.15.25;	author leonardr;	state Exp;
branches;
next	1.21;

1.21
date	2001.05.30.00.27.02;	author leonardr;	state Exp;
branches;
next	1.20;

1.20
date	2001.05.25.01.45.28;	author leonardr;	state Exp;
branches;
next	1.19;

1.19
date	2001.05.23.01.50.13;	author dlr;	state Exp;
branches;
next	1.18;

1.18
date	2001.05.23.01.07.40;	author leonardr;	state Exp;
branches;
next	1.17;

1.17
date	2001.05.23.00.35.00;	author leonardr;	state Exp;
branches;
next	1.16;

1.16
date	2001.05.21.21.06.01;	author leonardr;	state Exp;
branches;
next	1.15;

1.15
date	2001.05.11.19.38.55;	author leonardr;	state Exp;
branches;
next	1.14;

1.14
date	2001.04.20.21.19.40;	author leonardr;	state Exp;
branches;
next	1.13;

1.13
date	2001.04.20.15.30.21;	author dlr;	state Exp;
branches;
next	1.12;

1.12
date	2001.04.19.03.58.04;	author leonardr;	state Exp;
branches;
next	1.11;

1.11
date	2001.04.18.22.39.19;	author dlr;	state Exp;
branches;
next	1.10;

1.10
date	2001.04.18.22.00.10;	author leonardr;	state Exp;
branches;
next	1.9;

1.9
date	2001.04.18.21.20.05;	author leonardr;	state Exp;
branches;
next	1.8;

1.8
date	2001.04.12.04.41.05;	author leonardr;	state Exp;
branches;
next	1.7;

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

1.6
date	2001.04.06.23.28.49;	author leonardr;	state Exp;
branches;
next	1.5;

1.5
date	2001.04.04.02.52.07;	author dlr;	state Exp;
branches;
next	1.4;

1.4
date	2001.03.27.16.31.07;	author edk;	state Exp;
branches;
next	1.3;

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

1.2
date	2001.03.07.01.53.22;	author lucas;	state Exp;
branches;
next	1.1;

1.1
date	2001.03.07.01.13.15;	author lucas;	state Exp;
branches;
next	;


desc
@@


1.42
log
@Upgrading to Turbine 3.0-dev, Fulcrum 1.0, and Torque 1.0.
@
text
@/* ================================================================
 * Copyright (c) 2000-2001 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.om;

import java.util.*;

import com.workingdogs.village.Record;

import org.apache.torque.util.Criteria;
import org.apache.commons.util.BufferCache;
import org.apache.turbine.util.Log;
import org.apache.commons.util.exception.NestableException;

import org.tigris.helm.DoesNotExist;
import org.tigris.helm.AlreadyExists;
import org.tigris.helm.om.profile.*;
import org.tigris.helm.tool.*;

import org.tigris.helm.tool.paginate.PeerBackedList;
import org.tigris.helm.security.AccessControlList;
import org.tigris.helm.tool.cache.RegisterableCache;
import org.tigris.helm.tool.cache.TableTrackingBufferCache;

/**
 * Extension of generated Peer BaseProjectPeer.
 *
 * @@author <a href="mailto:dlr@@collab.net">Daniel Rall</a>
 * @@author <a href="mailto:leonardr@@collab.net">Leonard Richardson</a>
 */
public class ProjectPeer extends BaseProjectPeer
{
    /**
     * Flag indicating whether in debug mode.
     */
    private static final boolean DEBUG = true;

    /**
     * Cache of projects.
     */
    private static ProjectCache cache;

    //
    // Special data structures and methods for paginating lists of projects.
    //     

    public static Map filterableFields = new HashMap(3);
    
    /**
     * How objects of this type should be ordered in lists.
     */
    public static final String DEFAULT_ORDER_BY = NAME;

    //
    // Constants and methods used in dealing with special host and
    // domain projects.
    //

    /**
     * The special name of the project representing the host.
     */
    public static final String HOST_PROJECT_NAME = "**HOST";

    /**
     * The default project name.  Note that this is used (to avoid magic
     * strings) in dealing with anzu, where <code>www</code> means something
     * similar.
     */
    public static final String DEFAULT_PROJECT_NAME = "www";

    /**
     * The descrition of the default project.
     */
    public static final String DEFAULT_PROJECT_DESCRIP =
        "Web publishing module";

    /**
     * Static initializer; initializes the filterableFields data structure
     * and the project cache.
     */
    static
    { 
        filterableFields.put("Project Name", ProjectPeer.NAME);
        filterableFields.put("Summary", ProjectPeer.SHORT_DESCRIPTION);
        filterableFields.put("Description", ProjectPeer.LONG_DESCRIPTION);

        try
        {
            cache = new ProjectCache();
        }
        catch (Exception e)
        {
            Log.error("", e);
            throw new RuntimeException("Unable to create project cache: " +
                                       e.getMessage());
        }        
    }

    /**
     * Overridden BasePeer method to do a delete and then to send out
     * an appropriate CacheInvalidationEvent.
     */
    public static void doDelete(Criteria c)
        throws Exception
    {
        BaseProjectPeer.doDelete(c);
        uncache(Project.class);
    }
    
    //
    // Special projects
    //

    /**
     * Returns the special project representing the host.
     */
    public static Host getHost()
    {
        Host h = null;
        if (cache == null)
        {
            h = getHostDirectly();
        }
        else
        {
            h = cache.hostProject;        
            if (h == null)
            {
                synchronized(cache)
                {
                    h = cache.hostProject;
                    if (h == null)
                    {
                        h = getHostDirectly();
                        cache.hostProject = h;
                    }
                }
            }
        }
        return h;
    }

    /**
     * Retrieves the host representation, throwing an error if it's
     * not there.
     */
    private static Host getHostDirectly()
    {
        Host h = null;
        Criteria c = new Criteria(1).add(TYPE, Project.HOST_TYPE);
        try 
        {
            h = (Host)PeerTool.getFirstBO
                (doSelect(c), "Host representation");            
        }
        catch (Exception e)
        {
            throw new Error
                ("Could not locate host DB representation: " 
                 + e.getMessage());            
        }        
        return h;
    }

    /**
     * Get the named domain.
     */
    public static Domain getDomain(String name)
        throws DoesNotExist, Exception
    {
        Domain d = (Domain)cache.domains.get(name);
        if (d == null)
        {
            synchronized(cache.domains)
            {
                d = (Domain)cache.domains.get(name);
                if (d == null)
                {
                    Criteria c = new Criteria(2).add(TYPE, Project.DOMAIN_TYPE)
                        .add(NAME, name);
                    d = (Domain)PeerTool.getFirstBO
                        (doSelect(c), "Domain " + name);                    
                    cache.domains.put(name, d);
                }
            }
        }
        return d;
    }

    //
    // Ways of retrieving Project objects.
    //

    public static Project getInstance(String projectID)
        throws Exception
    {
        Project project = (Project)cache.projects.get(projectID);
        if (project == null)
        {
            synchronized (cache.projects)
            {
                project = (Project)cache.projects.get(projectID);
                if (project == null)
                {
                    Criteria c = new Criteria(1).add(PROJECT_ID, projectID);
                    project = (Project)PeerTool.getFirstBO
                        (ProjectPeer.doSelect(c), "Project with ID " 
                         + projectID);
                    List key = cache.makeProjectKey(project);

                    cache.projectsByDomainAndName.put(key, project);
                    cache.projects.put(projectID, project);
                }
            }
        }
        return project;
    }
        
    /**
     * Get an instance of a project by name and domain.
     */
    public static Project getInstanceByName(Domain domain, String name)
        throws DoesNotExist, Exception
    {
        List key = cache.makeProjectKey(domain, name);

        Project p = null;        
        if (cache == null || cache.projectsByDomainAndName == null)
        {
            p = getInstanceByNameDirectly(domain, name);
        }
        else
        {
            synchronized(cache.projectsByDomainAndName)
            {            
                p = (Project)cache.projectsByDomainAndName.get(key);
                if (p == null)
                {
                    p = getInstanceByNameDirectly(domain, name);
                    cache.projectsByDomainAndName.put(key, p);
                    cache.projects.put(p.getID(), p);
                }
            }   
        }
        return p;
    }

    /**
     * Retrieves a project matching the key from the database. Does not
     * use a cache.
     */
    private static Project getInstanceByNameDirectly (Domain domain, 
                                                      String name)
        throws DoesNotExist, Exception
    {
        List children = domain.getPermissionedChildren();
        Project instance = null;
        for (Iterator i = children.iterator(); i.hasNext();)
        {
            Project p = (Project)i.next();
            if (p.getName().equals(name))
            {
                instance = p;
                break;
            }
        }
        if (instance == null)
        {
            throw new DoesNotExist("Project " + name + " in domain " 
                                   + domain.getName());
        }
        return instance;
    }

    /**
     * Gets a project instance in the given domain with the given alias URL.
     */
    public static Project getInstanceByAliasURL(Domain domain, String aliasURL)
        throws DoesNotExist, Exception
    {
        Criteria c = domain.getProjectsInDomainCriteria()
            .add(ALIAS_URL, aliasURL);
        List p = ProjectPeer.doSelect(c);
        return (Project)PeerTool.getFirstBO(p, "Project with alias URL " +
                                            aliasURL, domain);
    }

    /**
     * Tries to get a project instance by name and then by ID.
     */
    public static Project getInstanceByIdentifier
        (Domain domain, String identifier)
        throws DoesNotExist, Exception
    {
        Project p = null;
        try 
        {
            p = getInstanceByName(domain, identifier);
        }
        catch (DoesNotExist e)
        {
            p = getInstance(identifier);
        }
        return p;
    }   

    /**
     * Get a list of projects matching a base Criteria and a filter
     * criteria, filtering the list further by removing projects
     * that cannot be viewed by the user whose ACL is passed in.
     */
    public static PeerBackedList getProjects
        (Integer itemsPerPage, Criteria base, Criteria filter, 
         AccessControlList acl)
        throws Exception
    {
        if (base == null) base = new Criteria();

        return new PeerBackedList(acl, ProjectPeer.class, 
                                  itemsPerPage, base, filter);
    }

    /**
     * Turns a string containing tokenized project designants into a list
     * of the corresponding projects.
     */
    public static List parseDesignantList(String designantString,
                                          Domain domain, List errors)
        throws Exception
    {
        List designants = new ArrayList();
        StringTokenizer tok = new StringTokenizer(designantString);
        while (tok.hasMoreTokens())
        {
            String element = (String)tok.nextToken();

            //Get a record for the supposed project any way by name
            //and by ID. If both fail, add the nonexistant project to
            //the list of validation errors.
            try
            {
                designants.add(getInstanceByIdentifier(domain, element));
            }
            catch (DoesNotExist e)
            {
                errors.add(e.getMessage());
            }
        }

        return designants;
    }

    //
    // Utility methods.
    // 

     /**
      * Throws an exception if a project with the given name exists
      * in the given domain.
      */
     public static void assertProjectNonexistance(Domain domain, String name)
         throws AlreadyExists, Exception
     {
         try {
             Project ignore = ProjectPeer.getInstanceByName(domain, name);
         }
         catch (DoesNotExist good) {
             return;
         }
         throw new AlreadyExists("A project called " + name,
                                 "domain named " + domain.getName());
     }


    ////////////////////////////////////////////////////////////////
    // Project retrieval
    ////////////////////////////////////////////////////////////////

    /**
     * A cache of project objects.
     */
    static class ProjectCache extends RegisterableCache
    {
        /**
         * Registered name of this cache.
         */
        private static final String NAME = "Project cache";

        /**
         * Cached instance of the host project.
         */
        Host hostProject;

        /**
         * Cache, keyed by name, of domains.
         */
        BufferCache domains;

        /**
         * Cache of projects keyed by ID.
         */
        TableTrackingBufferCache projects;
        
        /**
         * Cache, keyed by domain and name, of projects.
         */
        TableTrackingBufferCache projectsByDomainAndName;

        /**
         * Minimum size of the project caches.
         */
        private static final int MINIMUM_CACHE_SIZE = 50;
        
        /**
         * Registers with the {@@link org.tigris.helm.tool.cache.CacheRegistry}.
         */
        public ProjectCache()
            throws Exception
        {
            super(NAME, Project.class);
            domains = new BufferCache(1);
            projects = makeCache();
            projectsByDomainAndName = makeCache();
        }

        /**
         * Creates a TableTrackingBufferCache for this cache to use.
         */
        private TableTrackingBufferCache makeCache()
            throws Exception
        {
            return new TableTrackingBufferCache
                (TABLE_NAME, Attribute.FRACTIONAL_PROJECT_CACHE_SIZE,
                 MINIMUM_CACHE_SIZE);
        }

        /**
         * Makes a key suitable for putting into projectsByDomainAndName.
         */
        private static List makeProjectKey(Project project)
            throws Exception
        {
            return makeProjectKey(project.getDomain(), project.getName());
        }

        /**
         * Makes a key suitable for putting into projectsByDomainAndName.
         */
        private static List makeProjectKey(Domain domain, String name)
        {
            List key = new ArrayList(2);
            key.add(domain);
            key.add(name);
            return key;
        }

        public String describeContents()
        {            
            StringBuffer buf = new StringBuffer("\n ");            
            buf.append(projects.describeParameters());
            if (hostProject == null)
            {
                buf.append("Host project not cached.");
            }
            else
            {
                buf.append("Host project: ").append(hostProject.getID());
            }
            buf.append("\n\n");

            buf.append(" Cached domains:\n");
            Object[] domainKeys = domains.keySet().toArray();            
            for (int i = 0; i < domainKeys.length; i++)
            {
                String key = (String)domainKeys[i];
                Domain d = (Domain)domains.get(key);
                buf.append("  ").append(key).append(": ").append(d.getID())
                    .append('\n');
            }                
            buf.append('\n');

            buf.append(" Cached projects by ID:\n");
            Object[] projectKeys = projects.keySet().toArray();
            for (int i = 0; i < projectKeys.length; i++)
            {
                String key = (String) projectKeys[i];
                buf.append("  ").append(key).append('\n');
            }                
            buf.append('\n')
                .append(" Cached projects by domain/name:\n");
            projectKeys = projectsByDomainAndName.keySet().toArray();
            for (int i = 0; i < projectKeys.length; i++)
            {
                List key = (List)projectKeys[i];
                Domain domain = (Domain)key.get(0);
                String projectName = (String)key.get(1);
                buf.append("  ").append(domain.getName()+"/"+projectName)
                    .append('\n');
            }
            return buf.toString();
        }

        /**
         * Invalidates the cache.
         */
        public void invalidate()
            throws Exception
        {
            if (DEBUG)
            {
                Log.debug("About to invalidate " + NAME + ":");
                Log.debug(describeContents());
            }
            super.invalidate();
            hostProject = null;
            projects.invalidate();
            projectsByDomainAndName.invalidate();
        } 
    }   

    //Deprecated methods.
    /**
     * @@deprecated Use getHost() instead.
     */
    public static Host getHostProject()
    {
        return getHost();
    }

    /**
     * @@deprecated Domain object is now a subclass of ProjectGroup;
     * there's no need for this method at all.
     */
    public static Domain getDomainProject(Domain domain)
    {
        return domain;
    }

}

@


1.41
log
@Corrected JavaDoc.
@
text
@d53 2
a54 3
import org.apache.turbine.om.*;
import org.apache.turbine.util.db.Criteria;
import org.apache.turbine.util.BufferCache;
d56 1
a56 1
import org.apache.turbine.util.TurbineException;
@


1.40
log
@Implemented basic project group and category nesting.
@
text
@d208 1
a208 1
    
d210 1
a210 1
     * Get the project group for all projects in the specified domain.
@


1.39
log
@Added method for getting large numbers of project instances from a list of identifiers.
@
text
@d300 17
a316 5
        Criteria c = domain.getProjectsInDomainCriteria()
            .add(NAME, name);
        
        return (Project)PeerTool.getFirstBO
            (doSelect(c), "Project named " + name, domain);
@


1.38
log
@Huge patch of the day: Got rid of redundant HELM_DOMAIN table. The project representation of the domain and the host is now the canonical one. Host and Domain now subclass ProjectGroup. The canonical representation of a project's membership in a domain group is now the corresponding mapping in HELM_PROJECT_PROJECTGROUP. Schema changes: No more HELM_DOMAIN table (obviously); no more DOMAIN_ID in HELM_PROJECT; HELM_USER and HELM_VC_VIEW now have foreign keys in HELM_PROJECT instead of HELM_DOMAIN.
@
text
@d321 19
d353 30
@


1.37
log
@TTBC-bearing RegisterableCaches now describe the behavior of their TTBCs.
@
text
@d55 1
d104 1
a104 2
     * The special name of projects which represent all projects in a
     * domain.
d106 1
a106 9
    public static final String DOMAIN_PROJECT_NAME =
        "*All projects in domain";

    /**
     * The special name of the project representing all projects on
     * the host.  
     */
    public static final String HOST_PROJECT_NAME = 
        "**All projects on host";
d137 1
d158 4
a161 1
    public static ProjectGroup getHostProject()
d163 2
a164 2
        Project p = null;
        try 
d166 3
a168 4
            p = getInstanceByName(DomainPeer.getHostDomain(), 
                                  HOST_PROJECT_NAME);
        } 
        catch (Exception e)
d170 13
a182 2
            Log.error("", e);
            throw new Error("Could not locate special host project group: " + e.getMessage());            
d184 1
a184 1
        return (ProjectGroup)p;
d186 1
a186 1
    
d188 2
a189 1
     * Get the project group for all projects in the specified domain.
d191 1
a191 1
    public static ProjectGroup getDomainProject(Domain domain)
d193 3
a195 2
        Project p = null;
        if (domain.isHost())
d197 2
a198 1
            return getHostProject();
a199 4
        try 
        {
            p = getInstanceByName(domain, DOMAIN_PROJECT_NAME);
        } 
d203 27
a229 2
                ("Could not locate special project group for " +
                 domain.getName());
d231 1
a231 1
        return (ProjectGroup)p;
d296 1
a296 1
        private static Project getInstanceByNameDirectly (Domain domain, 
d300 1
a300 2
        Criteria c = new Criteria(2)
            .add(DOMAIN_ID, domain.getID())
d307 3
a309 1

d313 2
a314 3
        Criteria c = new Criteria()
            .add(ALIAS_URL, aliasURL)
            .add(DOMAIN_ID, domain.getID());
d362 3
a364 40
     /**
      * Retrieves a List containing all regular projects for a domain.
      *
      * @@param  domainID      The domain for which to get projects.
      * @@return a List
      *
      */
     public List getProjectsForDomain (String domainID)
         throws Exception
     {
         return getProjectsForDomainType(domainID, Project.REGULAR_TYPE);
     }

     /**
      * Retrieves a List containing all category projects for a domain.
      *
      * @@param  domainID      The domain for which to get categories.
      * @@return a List
      */
     public List getCategoriesForDomain (String domainID)
         throws Exception
     {
         return getProjectsForDomainType(domainID, Project.CATEGORY_TYPE);
     }

     /**
      * Retrieves a List containing all projects for a domain and
      * a given type.
      *
      * @@param  domainID      The domain for which to get projects.
      * @@param  type          The type of project to get.
      * @@return a List
      */
     public List getProjectsForDomainType (String domainID, String type)
         throws Exception
     {
         Criteria c = new Criteria().add(DOMAIN_ID, domainID).add(TYPE, type);
         return doSelect(c);
     }        

d375 6
a380 1
        ProjectGroup hostProject;
d404 1
d453 12
a464 1
            
d503 19
@


1.36
log
@Allow getInstanceByName to succeed even when the cache is null
(because it now gets called as part of cache initialization).
@
text
@d442 1
a442 1
        {
d444 1
@


1.35
log
@Rearranged attribute constants and added generic host attribute-editing interface to AdminUtils.
@
text
@d242 1
a242 1
        synchronized(cache.projectsByDomainAndName)
d244 14
a257 12
            p = (Project)cache.projectsByDomainAndName.get(key);
            if (p == null)
            {
                Criteria c = new Criteria()
                    .add(DOMAIN_ID, domain.getID())
                    .add(NAME, name);
                
                p = (Project)PeerTool.getFirstBO
                    (doSelect(c), "Project named " + name, domain);
                cache.projectsByDomainAndName.put(key, p);
                cache.projects.put(p.getID(), p);
            }
d262 17
a397 6

        /**
         * Size of the project caches as percentages of the size of the
         * table they're tracking.
         */
        private double fractionalCacheSize;
a405 3
            fractionalCacheSize = Double.parseDouble
                (AttributePeer.getHostAttribute
                 (Attribute.FRACTIONAL_PROJECT_CACHE_SIZE));
d417 1
a417 1
                (TABLE_NAME, fractionalCacheSize,
a418 11
        }

        /**
         * Sets the fractional size of the caches.
         */
        public void setFractionalSize(double newSize)
            throws Exception
        {
            fractionalCacheSize = newSize;
            projects.setFractionalSize(fractionalCacheSize);
            projectsByDomainAndName.setFractionalSize(fractionalCacheSize);
@


1.34
log
@Added code to handle the default fractional size of TableTrackingBufferCaches as host attributes.
@
text
@d395 1
a395 1
                 (AttributePeer.FRACTIONAL_PROJECT_CACHE_SIZE));
@


1.33
log
@Put TableTrackingBufferCache into practice; hopefully I can soon replace it with something smarter.
@
text
@d384 1
a384 1
        private static final double FRACTIONAL_CACHE_SIZE = .3;
d393 27
a419 11
            TableTrackingBufferCache[] caches = 
            {
                projects, 
                projectsByDomainAndName
            };
            for (int i = 0; i < caches.length; i++)
            {
                caches[i] = new TableTrackingBufferCache
                    (ProjectPeer.TABLE_NAME, FRACTIONAL_CACHE_SIZE,
                     MINIMUM_CACHE_SIZE);
            }
@


1.32
log
@Uncache with the BO class as descriptor, not the Peer class.
@
text
@a49 1
import java.rmi.RemoteException;
a54 1
import org.apache.turbine.util.BufferCache;
d66 1
d143 1
a143 1
        catch (RemoteException e)
d361 1
a361 1
         * Cache of projects keyed by ID.
d363 1
a363 1
        Map projects;
d366 1
a366 1
         * Cached instance of the host project.
d368 1
a368 1
        ProjectGroup hostProject;
d373 6
a378 1
        Map projectsByDomainAndName;
d381 2
a382 1
         * Size of the project caches.
d384 1
a384 1
        private static final int SIZE_OF_PROJECT_CACHE = 50;
d390 1
a390 1
            throws RemoteException
d393 11
a403 2
            projects = new BufferCache(SIZE_OF_PROJECT_CACHE);
            projectsByDomainAndName = new BufferCache(SIZE_OF_PROJECT_CACHE);
a405 1

d470 1
a470 1
            }                   
d473 2
a474 2
            projects.clear();
            projectsByDomainAndName.clear();
@


1.31
log
@Put the ID instead of the project object into the criteria, hmm?
@
text
@d159 1
a159 1
        uncache(ProjectPeer.class);
@


1.30
log
@PeerBackedList performance boost and refactoring. This may be more complicated than it needs to be; rather than getting ever-increasing proportions of the table, it might be faster in most cases to get the whole table, so long as you stop processing results when the list is full enough.
@
text
@d220 1
a220 1
                    Criteria c = new Criteria(1).add(PROJECT_ID, project);
@


1.29
log
@Got rid of the ugly and unneccessary asGroup() and getGroupInstance() methods.
@
text
@d284 2
a285 13
        PeerBackedList l = new PeerBackedList(ProjectPeer.class, 
                                              itemsPerPage, base, filter);
        List toRemove = new ArrayList();
        for (Iterator i = l.iterator(); i.hasNext();)
        {
            Project p = (Project)i.next();
            if (!p.isViewableBy(acl))
            {
                toRemove.add(p);
            }           
        }
        l.removeAll(toRemove);
        return l;
@


1.28
log
@Use PeerTool so as to get the use of DoesNotExist.
@
text
@a271 24
    //
    // Ways of retrieving ProjectGroup objects.
    //
    public static ProjectGroup getGroupInstance(String projectID)
        throws Exception
    {
        Criteria c = new Criteria().add(PROJECT_ID, projectID);
        List p = doSelect(c);
        return (ProjectGroup)PeerTool.getFirstBO
            (p, "Project group with ID " + projectID);
    }

    public static ProjectGroup getGroupInstanceByName(Domain domain,
                                                      String name)
        throws Exception
    {
        Criteria c = new Criteria()
            .add(NAME, name)
            .add(DOMAIN_ID, domain.getID());
        List p = doSelect(c);
        return (ProjectGroup)PeerTool.getFirstBO
            (p, "Project group named " + name, domain);
    }

@


1.27
log
@Added call to super.
@
text
@d220 4
a223 2
                    project = retrieveByPK(new NumberKey(projectID));

@


1.26
log
@Added ability for caches to keep track of number of invalidations.
@
text
@d491 1
@


1.25
log
@Added general records-in-table method.
@
text
@d390 5
d420 1
a420 1
            super("Project cache", Project.class);
d484 1
d488 1
a488 1
                Log.debug("Invalidating project cache:");
@


1.24
log
@Added simple method to determine the number of projects on the system.
@
text
@a160 9

    /**
     * Returns the total number of projects on the system.
     */
    protected static int numberOfProjects()
        throws Exception
    {
        return doSelect(NO_CRITERIA).size();
    }
@


1.23
log
@Canonicalized key for cache to avoid cast exceptions.
@
text
@d52 2
a58 1
import org.apache.turbine.util.TurbineException;
d160 9
@


1.22
log
@Big cleanup of cache self-descriptions. Also added an admin tool to do manual selective cache invalidation.
@
text
@d221 1
a221 3
                    List key = new ArrayList(2);
                    key.add(project.getDomain().getName());
                    key.add(project.getName());
d230 1
a230 1

d237 1
a237 3
        List key = new ArrayList(2);
        key.add(domain);
        key.add(name);
d417 21
@


1.21
log
@Properly key cache entries.
@
text
@d425 1
a425 1
            StringBuffer buf = new StringBuffer();
d432 1
a432 1
                buf.append("Host project: " + hostProject.getID());
d434 1
a434 1
            buf.append("\n");
d436 1
a436 1
            buf.append("Cached projects by ID: ");
d441 1
a441 2
                if (i > 0) buf.append(", ");
                buf.append(key);
d443 2
a444 2
            buf.append("\n")
                .append("Cached projects by domain/name: ");
d451 2
a452 2
                if (i > 0) buf.append(", ");
                buf.append(domain.getName()+"/"+projectName);
@


1.20
log
@Finally got rid of REQUESTABLE and DENOTES_OWNER fields in HELM_ROLE.
@
text
@d220 6
a225 2
                    cache.projectsByDomainAndName.put(project.getDomain(), 
                                                      project);
@


1.19
log
@Ported Helm from WebMacro to Velocity.
@
text
@d430 1
a430 1
            buf.append("\n\n");
@


1.18
log
@Cache projects by domain properly.
@
text
@d56 2
@


1.17
log
@Cleanup of caching and cache invalidation.
@
text
@d249 1
a249 1
                cache.projectsByDomainAndName.put(domain, p);
d443 1
a443 1
                List key = (List) projectKeys[i];
@


1.16
log
@Moved clustering features out of RMI and into the database.
@
text
@d412 1
a412 1
            super(Project.class);
d417 35
d453 1
a453 1
         * Invalidates  the cache.
d459 3
a461 30
                StringBuffer buf =
                    new StringBuffer("Project invalidating ID cache: ");
                Object[] projectKeys = projects.keySet().toArray();
                for (int i = 0; i < projectKeys.length; i++)
                {
                    String key = (String) projectKeys[i];
                    if (i > 0) buf.append(", ");
                    buf.append(key);
                    projects.remove(key);
                }
                Log.debug(buf.toString());
                
                buf.append("\n")
                    .append("Project invalidating domain/name cache: ");
                projectKeys = projects.keySet().toArray();
                for (int i = 0; i < projectKeys.length; i++)
                {
                    List key = (List) projectKeys[i];
                    Domain domain = (Domain)key.get(0);
                    String projectName = (String)key.get(1);
                    if (i > 0) buf.append(", ");
                    buf.append(domain.getName()+"/"+projectName);
                    projectsByDomainAndName.remove(key);
                }
                Log.debug(buf.toString());
            }
            else
            {
                projects.clear();
            }
d463 4
a466 4
        }
    
    }
    
d468 1
@


1.15
log
@A Heartbreaking Patch of Staggering Genius: adds capacity (but no interface) for deeply nested projects, categories, and project groups. As a side effect, gets rid of the hacky special 'all public projects in domain' group. There are probably bugs in this, and some of those bugs are probably security holes, so watch out.
@
text
@d412 1
a412 1
            super(ProjectPeer.class);
d418 1
a418 5
         * Invalidates some portion of the cache.
         *
         * @@param invalidationDescriptor Description of the invalidation that 
         *                               should occur, or <code>null</code> for
         *                               complete invalidation.
d420 1
a420 1
        public void invalidate(Object invalidationDescriptor)
d422 1
a422 1
            if (invalidationDescriptor == null)
d424 4
a427 1
                if (DEBUG)
d429 4
a432 25
                    StringBuffer buf =
                        new StringBuffer("Project invalidating ID cache: ");
                    Object[] projectKeys = projects.keySet().toArray();
                    for (int i = 0; i < projectKeys.length; i++)
                    {
                        String key = (String) projectKeys[i];
                        if (i > 0) buf.append(", ");
                        buf.append(key);
                        projects.remove(key);
                    }
                    Log.debug(buf.toString());

                    buf.append("\n")
                        .append("Project invalidating domain/name cache: ");
                    projectKeys = projects.keySet().toArray();
                    for (int i = 0; i < projectKeys.length; i++)
                    {
                        List key = (List) projectKeys[i];
                        Domain domain = (Domain)key.get(0);
                        String projectName = (String)key.get(1);
                        if (i > 0) buf.append(", ");
                        buf.append(domain.getName()+"/"+projectName);
                        projectsByDomainAndName.remove(key);
                    }
                    Log.debug(buf.toString());
d434 6
a439 1
                else
d441 6
a446 1
                    projects.clear();
d448 1
a448 1
                hostProject = null;
d450 1
a450 10
        }
    
        /**
         * This cache is invalidated whenever a Project is changed.
         */
        protected final boolean affectedByInvalidation
            (Object invalidationDescriptor)
        {
            boolean affects = false;
            if (invalidationDescriptor == null)
d452 1
a452 1
                affects = true;
d454 1
a454 9
            else if (invalidationDescriptor instanceof String)
            {
                String objectClassName = (String)invalidationDescriptor;
                if (objectClassName.equals(Project.class.getName()))
                {
                    affects = true;
                }
            }
            return affects;
d456 1
@


1.14
log
@Send CacheInvalidationEvents on deletes, and on saves of objects which are not themselves cached but which invalidate other caches when they are changed.
@
text
@a100 7
     * The special name of projects which represent all public
     * projects in a domain.  
     */
    public static final String DOMAIN_PUBLIC_PROJECT_NAME = 
        "*All public projects in domain";

    /**
d173 2
a174 1
            throw new Error("Could not locate special host project group.");
a196 20
                 domain.getName());
        }
        return (ProjectGroup)p;
    }

    public static ProjectGroup getPublicDomainProject(Domain domain)
    {
        if (domain.isHost())
        {
            return getHostProject();
        }
        Project p = null;
        try 
        {
            p = getInstanceByName(domain, DOMAIN_PUBLIC_PROJECT_NAME);
        } 
        catch (Exception e)
        {
            throw new Error
                ("Could not locate special public project group for " +
@


1.13
log
@Added semi-selective cache invalidation which invalidates particular caches on a write instead of all the caches.
@
text
@d154 11
@


1.12
log
@Guess we need that code after all.
@
text
@d477 14
a490 1
            else
d492 5
a496 3
                throw new UnsupportedOperationException
                    ("ProjectCache.invalidate() does not " + 
                     "currently support a descriptor");
d498 1
d501 1
a501 1

@


1.11
log
@SequencedHashtable, BufferCache, and BaseUnicastRemoteService have been moved into Turbine.  Changed references accordingly.
@
text
@d180 4
d199 4
@


1.10
log
@Cache projects by domain and name. This lets us cache the common hit
for the www project, and get rid of the caches for special host and
domain projects.
@
text
@d54 1
@


1.9
log
@Removed useless and unused methods.
@
text
@d151 1
a151 7
        }
        cache.projects = new BufferCache(50);
        cache.specialProjectsByDomain = new BufferCache(2);
        cache.specialPublicProjectsByDomain = new BufferCache(2);

        // Cache the host project.
        getHostProject();
d160 2
a161 1
        if (cache.hostProject == null)
d163 6
a168 10
            Criteria c = new Criteria().add(TYPE, Project.HOST_TYPE);
            try 
            {
                cache.hostProject =
                    (ProjectGroup)PeerTool.getFirstBO(ProjectPeer.doSelect(c), "");
            }
            catch (Exception e) 
            {
                throw new Error("Could not locate host project!");
            }
d170 1
a170 1
        return cache.hostProject;
a176 1
        throws Exception
d178 2
a179 2
        ProjectGroup p = null;
        if (domain.isHost()) 
d181 3
a183 3
            p = getHostProject();
        }
        else 
d185 3
a187 18
            p = (ProjectGroup)cache.specialProjectsByDomain.get(domain);
            if (p == null)
            {
                synchronized(cache.specialProjectsByDomain)
                {
                    try 
                    {                    
                        p = getGroupInstanceByName(domain, DOMAIN_PROJECT_NAME);
                    }
                    catch (DoesNotExist e) 
                    {
                        throw new Error
                            ("Could not locate special project group for " +
                             domain.getName());
                    }
                    cache.specialProjectsByDomain.put(domain, p);
                }
            }
d189 1
a189 1
        return p;
a192 1
        throws Exception
d194 2
a195 2
        ProjectGroup p = null;
        if (domain.isHost()) 
d197 3
a199 3
            p = getHostProject();
        }
        else 
d201 3
a203 19
            synchronized(cache.specialPublicProjectsByDomain)
            {
                p = (ProjectGroup)cache.specialPublicProjectsByDomain.get(domain);
                if (p == null)
                {
                    try 
                    {                    
                        p = getGroupInstanceByName(domain, 
                                                   DOMAIN_PUBLIC_PROJECT_NAME);
                    }
                    catch (DoesNotExist e) 
                    {
                        throw new Error
                            ("Could not locate special public project group for " +
                             domain.getName());
                    }
                    cache.specialPublicProjectsByDomain.put(domain, p);
                }
            }
d205 1
a205 1
        return p;
d224 2
d233 3
d239 21
a259 5
        Criteria c = new Criteria()
            .add(NAME, name)
            .add(DOMAIN_ID, domain.getID());
        List p = ProjectPeer.doSelect(c);
        return (Project)PeerTool.getFirstBO(p, "Project named " + name, domain);
d403 1
a403 2
         * Cache, keyed by domain, of the special project representing that
         * domain.
d405 2
a406 2
        Map specialProjectsByDomain;
        
d408 1
a408 2
         * Cache, keyed by domain, of the special project representing that
         * domain.
d410 2
a411 2
        Map specialPublicProjectsByDomain;

d419 2
d437 1
a437 1
                        new StringBuffer("Project invalidating cache: ");
d447 14
a466 2
                specialProjectsByDomain.clear();
                specialPublicProjectsByDomain.clear();
@


1.8
log
@Added debugging code and moved RARPeer and ProjectPeer to the new caching system.
@
text
@a370 35
    /**
     * Gets a project name for a project ID.
     *
     * @@param projectID The database key to obtain the name for.
     * @@return          The project name.
     *
     * @@exception DoesNotExist If the projectID is invalid.
     * @@exception Exception    If a database error occurs.
     *
     * @@deprecated You'd have to be a total retard to need this method.
     */
    public static final String getProjectName(String projectID)
        throws DoesNotExist, Exception
    {
        return getInstance(projectID).getName();
    }

    /**
     * Gets a project ID for a project name.
     *
     * @@param projectID The project name to obtain the name for.
     * @@return          The project ID.
     *
     * @@exception DoesNotExist If the domain or name are invalid.
     * @@exception Exception    If a database error occurs.
     *
     * @@deprecated You'd have to be a total retard to need this method.
     */
    public static final String getProjectID(Domain domain, String name)
        throws DoesNotExist, Exception
    {
        return getInstanceByName(domain, name).getID();
    }


@


1.7
log
@How about getting the project from the correct cache.
@
text
@d50 1
d63 1
d74 5
d81 1
a81 1
    private static Map projects = new BufferCache(50);
a93 11
    /**
     * Removes a project from the cache.
     */
    public static void uncache(Project project)
    {
        if (projects.containsKey(project.getID()))
        {
            projects.remove(project.getID());
        }
    }

a99 19
     * Cached instance of the host project.
     */
    public static final ProjectGroup hostProject;

    /**
     * Cache, keyed by domain, of the special project representing that
     * domain.
     */
    public static final BufferCache specialProjectsByDomain = 
        new BufferCache(2);

    /**
     * Cache, keyed by domain, of the special project representing that
     * domain.
     */
    public static final BufferCache specialPublicProjectsByDomain = 
        new BufferCache(2);

    /**
a132 1

d135 1
a135 1
     * and obtains the host project.
d143 1
a143 2
        Criteria c = new Criteria().add(TYPE, Project.HOST_TYPE);
        try 
d145 1
a145 2
            hostProject =
                (ProjectGroup)PeerTool.getFirstBO(ProjectPeer.doSelect(c), "");
d147 1
a147 1
        catch (Exception e) 
d149 2
a150 1
            throw new Error("Could not locate host project!");
d152 6
a164 1
        throws Exception
d166 14
a179 1
        return hostProject;
d195 1
a195 1
            p = (ProjectGroup)specialProjectsByDomain.get(domain);
d198 1
a198 1
                synchronized(specialProjectsByDomain)
d210 1
a210 1
                    specialProjectsByDomain.put(domain, p);
d227 1
a227 1
            synchronized(specialPublicProjectsByDomain)
d229 1
a229 1
                p = (ProjectGroup)specialPublicProjectsByDomain.get(domain);
d243 1
a243 1
                    specialPublicProjectsByDomain.put(domain, p);
d257 1
a257 1
        Project project = (Project) projects.get(projectID);
d260 1
a260 1
            synchronized (projects)
d262 1
a262 1
                project = (Project) projects.get(projectID);
d266 1
a266 1
                    projects.put(projectID, project);
d445 75
@


1.6
log
@Added caching of special projects; hopefully this is a stopgap measure until a good general project cacher is in place. Prelimenary tests show what this saves at least 3 DB hits per request, and over 20 hits on a start page request.
@
text
@d236 1
a236 1
                p = (ProjectGroup)specialProjectsByDomain.get(domain);
@


1.5
log
@Clean up and JavaDoc.
@
text
@a87 10
     * Static initializer; initializes the filterableFields data structure.
     */
    static
    { 
        filterableFields.put("Project Name", ProjectPeer.NAME);
        filterableFields.put("Summary", ProjectPeer.SHORT_DESCRIPTION);
        filterableFields.put("Description", ProjectPeer.LONG_DESCRIPTION);
    }

    /**
d104 19
d155 23
d186 1
a186 9
        Criteria c = new Criteria().add(TYPE, Project.HOST_TYPE);
        try {
            ProjectGroup host =
                (ProjectGroup)PeerTool.getFirstBO(ProjectPeer.doSelect(c), "");
            return host;
        }
        catch (DoesNotExist e) {
            throw new Error("Could not locate host project!");
        }
d196 2
a197 1
        if (domain.isHost()) {
d200 19
a218 7
        else {
            try {
                p = getGroupInstanceByName(domain, DOMAIN_PROJECT_NAME);
            }
            catch (DoesNotExist e) {
                throw new Error("Could not locate special project group for " +
                                domain.getName());
d227 2
a228 1
        if (domain.isHost())
d230 1
a230 1
            return getHostProject();
d232 21
a252 8
        ProjectGroup p = null;
        try {
            p = getGroupInstanceByName(domain, DOMAIN_PUBLIC_PROJECT_NAME);
        }
        catch (DoesNotExist e) {
            throw new Error
                ("Could not locate special public project group for " +
                 domain.getName());
@


1.4
log
@User was making use of ProjectPeer.DEFAULT_PROJECT this in one place
to deal with aliases (generally they go in the 'www' project).  Mention
that as one of the uses for DEFAULT_PROJECT, since it's one of the
complications which might need to be addressed if this were ever changed.
@
text
@a70 1

d80 1
a80 1
    public static Map filterableFields = new HashMap();
d95 1
a95 1
    };
d136 2
a137 1
     * strings) in dealing with anzu, where 'www' means something similar.
@


1.3
log
@Implemented caching of Project objects.
@
text
@d136 2
a137 1
     * The default project name.
@


1.2
log
@Corrected regex madness for Torque upgrade.  -dlr
@
text
@d58 1
a58 1
import org.tigris.helm.tool.PeerTool;
d72 5
d98 11
d212 14
a225 1
        return ProjectPeer.retrieveByPK(new NumberKey(projectID));
@


1.1
log
@Moved in from peer package to handle Torque changes. -dlr
@
text
@a56 4
import org.tigris.helm.om.Domain;
import org.tigris.helm.om.Project;
import org.tigris.helm.om.ProjectGroup;
import org.tigris.helm.om.ProjectType;
@

