Package org.dspace.eperson

Source Code of org.dspace.eperson.Group

/*
* Group.java
*
* Version: $Revision: 4903 $
*
* Date: $Date: 2010-05-10 08:29:50 +0000 (Mon, 10 May 2010) $
*
* Copyright (c) 2002-2009, The DSpace Foundation.  All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - 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.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS 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 THE COPYRIGHT
* HOLDERS OR 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.
*/
package org.dspace.eperson;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.io.IOException;

import org.apache.log4j.Logger;
import org.dspace.app.util.AuthorizeUtil;
import org.dspace.authorize.AuthorizeConfiguration;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.event.Event;
import org.dspace.storage.rdbms.DatabaseManager;
import org.dspace.storage.rdbms.TableRow;
import org.dspace.storage.rdbms.TableRowIterator;

/**
* Class representing a group of e-people.
*
* @author David Stuve
* @version $Revision: 4903 $
*/
public class Group extends DSpaceObject
{
    // findAll sortby types
    public static final int ID = 0; // sort by ID

    public static final int NAME = 1; // sort by NAME (default)

    /** log4j logger */
    private static Logger log = Logger.getLogger(Group.class);

    /** Our context */
    private Context myContext;

    /** The row in the table representing this object */
    private TableRow myRow;

    /** lists of epeople and groups in the group */
    private List<EPerson> epeople = new ArrayList<EPerson>();

    private List<Group> groups = new ArrayList<Group>();

    /** lists that need to be written out again */
    private boolean epeopleChanged = false;

    private boolean groupsChanged = false;

    /** is this just a stub, or is all data loaded? */
    private boolean isDataLoaded = false;

    /** Flag set when metadata is modified, for events */
    private boolean modifiedMetadata;

    /**
     * Construct a Group from a given context and tablerow
     *
     * @param context
     * @param row
     */
    Group(Context context, TableRow row) throws SQLException
    {
        myContext = context;
        myRow = row;

        // Cache ourselves
        context.cache(this, row.getIntColumn("eperson_group_id"));

        modifiedMetadata = false;
        clearDetails();
    }

    /**
     * Populate Group with eperson and group objects
     *
     * @throws SQLException
     */
    public void loadData()
    {
        // only populate if not already populated
        if (!isDataLoaded)
        {
            // naughty thing to do - swallowing SQL exception and throwing it as
            // a RuntimeException - a hack to avoid changing the API all over
            // the place
            try
            {
                // get epeople objects
                TableRowIterator tri = DatabaseManager.queryTable(myContext,"eperson",
                                "SELECT eperson.* FROM eperson, epersongroup2eperson WHERE " +
                                "epersongroup2eperson.eperson_id=eperson.eperson_id AND " +
                                "epersongroup2eperson.eperson_group_id= ?",
                                myRow.getIntColumn("eperson_group_id"));

                try
                {
                    while (tri.hasNext())
                    {
                        TableRow r = (TableRow) tri.next();

                        // First check the cache
                        EPerson fromCache = (EPerson) myContext.fromCache(
                                EPerson.class, r.getIntColumn("eperson_id"));

                        if (fromCache != null)
                        {
                            epeople.add(fromCache);
                        }
                        else
                        {
                            epeople.add(new EPerson(myContext, r));
                        }
                    }
                }
                finally
                {
                    // close the TableRowIterator to free up resources
                    if (tri != null)
                        tri.close();
                }

                // now get Group objects
                tri = DatabaseManager.queryTable(myContext,"epersongroup",
                                "SELECT epersongroup.* FROM epersongroup, group2group WHERE " +
                                "group2group.child_id=epersongroup.eperson_group_id AND "+
                                "group2group.parent_id= ? ",
                                myRow.getIntColumn("eperson_group_id"));

                try
                {
                    while (tri.hasNext())
                    {
                        TableRow r = (TableRow) tri.next();

                        // First check the cache
                        Group fromCache = (Group) myContext.fromCache(Group.class,
                                r.getIntColumn("eperson_group_id"));

                        if (fromCache != null)
                        {
                            groups.add(fromCache);
                        }
                        else
                        {
                            groups.add(new Group(myContext, r));
                        }
                    }
                }
                finally
                {
                    // close the TableRowIterator to free up resources
                    if (tri != null)
                        tri.close();
                }

            }
            catch (Exception e)
            {
                throw new RuntimeException(e);
            }
            isDataLoaded = true;
        }
    }

    /**
     * Create a new group
     *
     * @param context
     *            DSpace context object
     */
    public static Group create(Context context) throws SQLException,
            AuthorizeException
    {
        // FIXME - authorization?
        if (!AuthorizeManager.isAdmin(context))
        {
            throw new AuthorizeException(
                    "You must be an admin to create an EPerson Group");
        }

        // Create a table row
        TableRow row = DatabaseManager.create(context, "epersongroup");

        Group g = new Group(context, row);

        log.info(LogManager.getHeader(context, "create_group", "group_id="
                + g.getID()));

        context.addEvent(new Event(Event.CREATE, Constants.GROUP, g.getID(), null));

        return g;
    }

    /**
     * get the ID of the group object
     *
     * @return id
     */
    public int getID()
    {
        return myRow.getIntColumn("eperson_group_id");
    }

    /**
     * get name of group
     *
     * @return name
     */
    public String getName()
    {
        return myRow.getStringColumn("name");
    }

    /**
     * set name of group
     *
     * @param name
     *            new group name
     */
    public void setName(String name)
    {
        myRow.setColumn("name", name);
        modifiedMetadata = true;
        addDetails("name");
    }

    /**
     * add an eperson member
     *
     * @param e
     *            eperson
     */
    public void addMember(EPerson e)
    {
        loadData(); // make sure Group has data loaded

        if (isMember(e))
        {
            return;
        }

        epeople.add(e);
        epeopleChanged = true;

        myContext.addEvent(new Event(Event.ADD, Constants.GROUP, getID(), Constants.EPERSON, e.getID(), e.getEmail()));
    }

    /**
     * add group to this group
     *
     * @param g
     */
    public void addMember(Group g)
    {
        loadData(); // make sure Group has data loaded

        // don't add if it's already a member
        // and don't add itself
        if (isMember(g) || getID()==g.getID())
        {
            return;
        }

        groups.add(g);
        groupsChanged = true;

        myContext.addEvent(new Event(Event.ADD, Constants.GROUP, getID(), Constants.GROUP, g.getID(), g.getName()));
    }

    /**
     * remove an eperson from a group
     *
     * @param e
     *            eperson
     */
    public void removeMember(EPerson e)
    {
        loadData(); // make sure Group has data loaded

        if (epeople.remove(e))
        {
            epeopleChanged = true;
            myContext.addEvent(new Event(Event.REMOVE, Constants.GROUP, getID(), Constants.EPERSON, e.getID(), e.getEmail()));
        }
    }

    /**
     * remove group from this group
     *
     * @param g
     */
    public void removeMember(Group g)
    {
        loadData(); // make sure Group has data loaded

        if (groups.remove(g))
        {
            groupsChanged = true;
            myContext.addEvent(new Event(Event.REMOVE, Constants.GROUP, getID(), Constants.GROUP, g.getID(), g.getName()));
        }
    }

    /**
     * check to see if an eperson is a direct member.
     * If the eperson is a member via a subgroup will be returned <code>false</code>
     *
     * @param e
     *            eperson to check membership
     */
    public boolean isMember(EPerson e)
    {
        // special, group 0 is anonymous
        if (getID() == 0)
        {
            return true;
        }

        loadData(); // make sure Group has data loaded

        return epeople.contains(e);
    }

    /**
     * check to see if g is a direct group member.
     * If g is a subgroup via another group will be returned <code>false</code>
     *
     * @param g
     *            group to check
     * @return
     */
    public boolean isMember(Group g)
    {
        loadData(); // make sure Group has data loaded

        return groups.contains(g);
    }

    /**
     * fast check to see if an eperson is a member called with eperson id, does
     * database lookup without instantiating all of the epeople objects and is
     * thus a static method
     *
     * @param c
     *            context
     * @param groupid
     *            group ID to check
     */
    public static boolean isMember(Context c, int groupid) throws SQLException
    {
        // special, everyone is member of group 0 (anonymous)
        if (groupid == 0)
        {
            return true;
        }

        EPerson currentuser = c.getCurrentUser();

        return epersonInGroup(c, groupid, currentuser);
    }

    /**
     * Get all of the groups that an eperson is a member of
     *
     * @param c
     * @param e
     * @return
     * @throws SQLException
     */
    public static Group[] allMemberGroups(Context c, EPerson e)
            throws SQLException
    {
        List<Group> groupList = new ArrayList<Group>();

        Set<Integer> myGroups = allMemberGroupIDs(c, e);
        // now convert those Integers to Groups
        Iterator i = myGroups.iterator();

        while (i.hasNext())
        {
            groupList.add(Group.find(c, ((Integer) i.next()).intValue()));
        }

        return (Group[]) groupList.toArray(new Group[0]);
    }

    /**
     * get Set of Integers all of the group memberships for an eperson
     *
     * @param c
     * @param e
     * @return Set of Integer groupIDs
     * @throws SQLException
     */
    public static Set<Integer> allMemberGroupIDs(Context c, EPerson e)
            throws SQLException
    {
        Set<Integer> groupIDs = new HashSet<Integer>();
       
        if (e != null)
        {
            // two queries - first to get groups eperson is a member of
            // second query gets parent groups for groups eperson is a member of

            TableRowIterator tri = DatabaseManager.queryTable(c,
                    "epersongroup2eperson",
                    "SELECT * FROM epersongroup2eperson WHERE eperson_id= ?", e
                            .getID());

            try
            {
                while (tri.hasNext())
                {
                    TableRow row = tri.next();

                    int childID = row.getIntColumn("eperson_group_id");

                    groupIDs.add(new Integer(childID));
                }
            }
            finally
            {
                // close the TableRowIterator to free up resources
                if (tri != null)
                    tri.close();
            }
        }
        // Also need to get all "Special Groups" user is a member of!
        // Otherwise, you're ignoring the user's membership to these groups!
        // However, we only do this is we are looking up the special groups
        // of the current user, as we cannot look up the special groups
        // of a user who is not logged in.
        if ((c.getCurrentUser() == null) || (((c.getCurrentUser() != null) && (c.getCurrentUser().getID() == e.getID()))))
        {
            Group[] specialGroups = c.getSpecialGroups();
            for(Group special : specialGroups)
            {
                groupIDs.add(new Integer(special.getID()));
            }
        }

        // all the users are members of the anonymous group
        groupIDs.add(new Integer(0));
       
        // now we have all owning groups, also grab all parents of owning groups
        // yes, I know this could have been done as one big query and a union,
        // but doing the Oracle port taught me to keep to simple SQL!

        String groupQuery = "";

        Iterator i = groupIDs.iterator();

        // Build a list of query parameters
        Object[] parameters = new Object[groupIDs.size()];
        int idx = 0;
        while (i.hasNext())
        {
            int groupID = ((Integer) i.next()).intValue();

            parameters[idx++] = new Integer(groupID);
           
            groupQuery += "child_id= ? ";
            if (i.hasNext())
                groupQuery += " OR ";
        }

        // was member of at least one group
        // NOTE: even through the query is built dynamicaly all data is seperated into the
        // the parameters array.
        TableRowIterator tri = DatabaseManager.queryTable(c, "group2groupcache",
                "SELECT * FROM group2groupcache WHERE " + groupQuery,
                parameters);

        try
        {
            while (tri.hasNext())
            {
                TableRow row = tri.next();

                int parentID = row.getIntColumn("parent_id");

                groupIDs.add(new Integer(parentID));
            }
        }
        finally
        {
            // close the TableRowIterator to free up resources
            if (tri != null)
                tri.close();
        }

        return groupIDs;
    }
   
   
    /**
     * Get all of the epeople who are a member of the
     * specified group, or a member of a sub-group of the
     * specified group, etc.
     *
     * @param c  
     *          DSpace context
     * @param g  
     *          Group object
     * @return   Array of EPerson objects
     * @throws SQLException
     */
    public static EPerson[] allMembers(Context c, Group g)
            throws SQLException
    {
        List<EPerson> epersonList = new ArrayList<EPerson>();

        Set<Integer> myEpeople = allMemberIDs(c, g);
        // now convert those Integers to EPerson objects
        Iterator i = myEpeople.iterator();

        while (i.hasNext())
        {
            epersonList.add(EPerson.find(c, ((Integer) i.next()).intValue()));
        }

        return (EPerson[]) epersonList.toArray(new EPerson[0]);
    }

    /**
     * Get Set of all Integers all of the epeople
     * members for a group
     *
     * @param c
     *          DSpace context
     * @param g
     *          Group object
     * @return Set of Integer epersonIDs
     * @throws SQLException
     */
    public static Set<Integer> allMemberIDs(Context c, Group g)
            throws SQLException
    {
        // two queries - first to get all groups which are a member of this group
        // second query gets all members of each group in the first query
        Set<Integer> epeopleIDs = new HashSet<Integer>();
       
        // Get all groups which are a member of this group
        TableRowIterator tri = DatabaseManager.queryTable(c, "group2groupcache",
                "SELECT * FROM group2groupcache WHERE parent_id= ? ",
                g.getID());
       
        Set<Integer> groupIDs = new HashSet<Integer>();

        try
        {
            while (tri.hasNext())
            {
                TableRow row = tri.next();

                int childID = row.getIntColumn("child_id");

                groupIDs.add(new Integer(childID));
            }
        }
        finally
        {
            // close the TableRowIterator to free up resources
            if (tri != null)
                tri.close();
        }

        // now we have all the groups (including this one)
        // it is time to find all the EPeople who belong to those groups
        // and filter out all duplicates

        Object[] parameters = new Object[groupIDs.size()+1];
        int idx = 0;
        Iterator i = groupIDs.iterator();

        // don't forget to add the current group to this query!
        parameters[idx++] = new Integer(g.getID());
        String epersonQuery = "eperson_group_id= ? ";
        if (i.hasNext())
            epersonQuery += " OR ";
       
        while (i.hasNext())
        {
            int groupID = ((Integer) i.next()).intValue();
            parameters[idx++] = new Integer(groupID);
           
            epersonQuery += "eperson_group_id= ? ";
            if (i.hasNext())
                epersonQuery += " OR ";
        }

        //get all the EPerson IDs
        // Note: even through the query is dynamicaly built all data is seperated
        // into the parameters array.
        tri = DatabaseManager.queryTable(c, "epersongroup2eperson",
                "SELECT * FROM epersongroup2eperson WHERE " + epersonQuery,
                parameters);

        try
        {
            while (tri.hasNext())
            {
                TableRow row = tri.next();

                int epersonID = row.getIntColumn("eperson_id");

                epeopleIDs.add(new Integer(epersonID));
            }
        }
        finally
        {
            // close the TableRowIterator to free up resources
            if (tri != null)
                tri.close();
        }

        return epeopleIDs;
    }

    private static boolean epersonInGroup(Context c, int groupID, EPerson e)
            throws SQLException
    {
        Set<Integer> groupIDs = Group.allMemberGroupIDs(c, e);

        return groupIDs.contains(new Integer(groupID));
    }

    /**
     * find the group by its ID
     *
     * @param context
     * @param id
     */
    public static Group find(Context context, int id) throws SQLException
    {
        // First check the cache
        Group fromCache = (Group) context.fromCache(Group.class, id);

        if (fromCache != null)
        {
            return fromCache;
        }

        TableRow row = DatabaseManager.find(context, "epersongroup", id);

        if (row == null)
        {
            return null;
        }
        else
        {
            return new Group(context, row);
        }
    }

    /**
     * Find the group by its name - assumes name is unique
     *
     * @param context
     * @param name
     *
     * @return Group
     */
    public static Group findByName(Context context, String name)
            throws SQLException
    {
        TableRow row = DatabaseManager.findByUnique(context, "epersongroup",
                "name", name);

        if (row == null)
        {
            return null;
        }
        else
        {
            // First check the cache
            Group fromCache = (Group) context.fromCache(Group.class, row
                    .getIntColumn("eperson_group_id"));

            if (fromCache != null)
            {
                return fromCache;
            }
            else
            {
                return new Group(context, row);
            }
        }
    }

    /**
     * Finds all groups in the site
     *
     * @param context
     *            DSpace context
     * @param sortField
     *            field to sort by -- Group.ID or Group.NAME
     *
     * @return array of all groups in the site
     */
    public static Group[] findAll(Context context, int sortField)
            throws SQLException
    {
        String s;

        switch (sortField)
        {
        case ID:
            s = "eperson_group_id";

            break;

        case NAME:
            s = "name";

            break;

        default:
            s = "name";
        }

        // NOTE: The use of 's' in the order by clause can not cause an sql
        // injection because the string is derived from constant values above.
        TableRowIterator rows = DatabaseManager.queryTable(
            context, "epersongroup",
                "SELECT * FROM epersongroup ORDER BY "+s);

        try
        {
            List gRows = rows.toList();

            Group[] groups = new Group[gRows.size()];

            for (int i = 0; i < gRows.size(); i++)
            {
                TableRow row = (TableRow) gRows.get(i);

                // First check the cache
                Group fromCache = (Group) context.fromCache(Group.class, row
                        .getIntColumn("eperson_group_id"));

                if (fromCache != null)
                {
                    groups[i] = fromCache;
                }
                else
                {
                    groups[i] = new Group(context, row);
                }
            }

            return groups;
        }
        finally
        {
            if (rows != null)
                rows.close();
        }
    }
   
   
    /**
     * Find the groups that match the search query across eperson_group_id or name
     *
     * @param context
     *            DSpace context
     * @param query
     *            The search string
     *
     * @return array of Group objects
     */
    public static Group[] search(Context context, String query)
        throws SQLException
  {
      return search(context, query, -1, -1);
  }
   
    /**
     * Find the groups that match the search query across eperson_group_id or name
     *
     * @param context
     *            DSpace context
     * @param query
     *            The search string
     * @param offset
     *            Inclusive offset
     * @param limit
     *            Maximum number of matches returned
     *
     * @return array of Group objects
     */
    public static Group[] search(Context context, String query, int offset, int limit)
        throws SQLException
  {
    String params = "%"+query.toLowerCase()+"%";
        StringBuffer queryBuf = new StringBuffer();
    queryBuf.append("SELECT * FROM epersongroup WHERE LOWER(name) LIKE LOWER(?) OR eperson_group_id = ? ORDER BY name ASC ");
   
        // Add offset and limit restrictions - Oracle requires special code
        if ("oracle".equals(ConfigurationManager.getProperty("db.name")))
        {
            // First prepare the query to generate row numbers
            if (limit > 0 || offset > 0)
            {
                queryBuf.insert(0, "SELECT /*+ FIRST_ROWS(n) */ rec.*, ROWNUM rnum  FROM (");
                queryBuf.append(") ");
            }

            // Restrict the number of rows returned based on the limit
            if (limit > 0)
            {
                queryBuf.append("rec WHERE rownum<=? ");
                // If we also have an offset, then convert the limit into the maximum row number
                if (offset > 0)
                    limit += offset;
            }

            // Return only the records after the specified offset (row number)
            if (offset > 0)
            {
                queryBuf.insert(0, "SELECT * FROM (");
                queryBuf.append(") WHERE rnum>?");
            }
        }
        else
        {
            if (limit > 0)
                queryBuf.append(" LIMIT ? ");

            if (offset > 0)
                queryBuf.append(" OFFSET ? ");
        }

        String dbquery = queryBuf.toString();

        // When checking against the eperson-id, make sure the query can be made into a number
    Integer int_param;
    try {
      int_param = Integer.valueOf(query);
    }
    catch (NumberFormatException e) {
      int_param = new Integer(-1);
    }

        // Create the parameter array, including limit and offset if part of the query
        Object[] paramArr = new Object[]{params, int_param};
        if (limit > 0 && offset > 0)
            paramArr = new Object[] {params, int_param,limit,offset};
        else if (limit > 0)
            paramArr = new Object[] {params, int_param,limit};
        else if (offset > 0)
            paramArr = new Object[] {params, int_param,offset};

        TableRowIterator rows =
      DatabaseManager.query(context, dbquery, paramArr);

        try
        {
            List groupRows = rows.toList();
            Group[] groups = new Group[groupRows.size()];

            for (int i = 0; i < groupRows.size(); i++)
            {
                TableRow row = (TableRow) groupRows.get(i);

                // First check the cache
                Group fromCache = (Group) context.fromCache(Group.class, row
                        .getIntColumn("eperson_group_id"));

                if (fromCache != null)
                {
                    groups[i] = fromCache;
                }
                else
                {
                    groups[i] = new Group(context, row);
                }
            }
            return groups;
        }
        finally
        {
            if (rows != null)
                rows.close();
        }
  }

    /**
     * Returns the total number of groups returned by a specific query, without the overhead
     * of creating the Group objects to store the results.
     *
     * @param context
     *            DSpace context
     * @param query
     *            The search string
     *
     * @return the number of groups mathching the query
     */
    public static int searchResultCount(Context context, String query)
      throws SQLException
  {
    String params = "%"+query.toLowerCase()+"%";
    String dbquery = "SELECT count(*) as gcount FROM epersongroup WHERE LOWER(name) LIKE LOWER(?) OR eperson_group_id = ? ";
   
    // When checking against the eperson-id, make sure the query can be made into a number
    Integer int_param;
    try {
      int_param = Integer.valueOf(query);
    }
    catch (NumberFormatException e) {
      int_param = new Integer(-1);
    }
   
    // Get all the epeople that match the query
    TableRow row = DatabaseManager.querySingle(context, dbquery, new Object[] {params, int_param});
   
    // use getIntColumn for Oracle count data
    Long count;
        if ("oracle".equals(ConfigurationManager.getProperty("db.name")))
        {
            count = new Long(row.getIntColumn("gcount"));
        }
        else  //getLongColumn works for postgres
        {
            count = new Long(row.getLongColumn("gcount"));
        }

    return count.intValue();
  }
   
   
    /**
     * Delete a group
     *
     */
    public void delete() throws SQLException
    {
        // FIXME: authorizations

        myContext.addEvent(new Event(Event.DELETE, Constants.GROUP, getID(), getName()));

        // Remove from cache
        myContext.removeCached(this, getID());

        // Remove any ResourcePolicies that reference this group
        AuthorizeManager.removeGroupPolicies(myContext, getID());

        // Remove any group memberships first
        DatabaseManager.updateQuery(myContext,
                "DELETE FROM EPersonGroup2EPerson WHERE eperson_group_id= ? ",
                getID());

        // remove any group2groupcache entries
        DatabaseManager.updateQuery(myContext,
                "DELETE FROM group2groupcache WHERE parent_id= ? OR child_id= ? ",
                getID(),getID());

        // Now remove any group2group assignments
        DatabaseManager.updateQuery(myContext,
                "DELETE FROM group2group WHERE parent_id= ? OR child_id= ? ",
                getID(),getID());

        // don't forget the new table
        deleteEpersonGroup2WorkspaceItem();

        // Remove ourself
        DatabaseManager.delete(myContext, myRow);

        epeople.clear();

        log.info(LogManager.getHeader(myContext, "delete_group", "group_id="
                + getID()));
    }

    /**
     * @throws SQLException
     */
    private void deleteEpersonGroup2WorkspaceItem() throws SQLException
    {
        DatabaseManager.updateQuery(myContext,
                "DELETE FROM EPersonGroup2WorkspaceItem WHERE eperson_group_id= ? ",
                getID());
    }

    /**
     * Return EPerson members of a Group
     */
    public EPerson[] getMembers()
    {
        loadData(); // make sure all data is loaded

        EPerson[] myArray = new EPerson[epeople.size()];
        myArray = (EPerson[]) epeople.toArray(myArray);

        return myArray;
    }
  
    /**
     * Return Group members of a Group
     *
     * @return
     */
    public Group[] getMemberGroups()
    {
        loadData(); // make sure all data is loaded

        Group[] myArray = new Group[groups.size()];
        myArray = (Group[]) groups.toArray(myArray);

        return myArray;
    }
   
    /**
     * Return true if group has no direct or indirect members
     */
    public boolean isEmpty()
    {
        loadData(); // make sure all data is loaded
       
        // the only fast check available is on epeople...
        boolean hasMembers = (epeople.size() != 0);
       
        if (hasMembers)
        {
            return false;
        }
        else
        {
            // well, groups is never null...
            for (Group subGroup : groups){
                hasMembers = !subGroup.isEmpty();
                if (hasMembers){
                    return false;
                }
            }
            return !hasMembers;
        }
    }

    /**
     * Update the group - writing out group object and EPerson list if necessary
     */
    public void update() throws SQLException, AuthorizeException
    {
        // FIXME: Check authorisation
        DatabaseManager.update(myContext, myRow);

        if (modifiedMetadata)
        {
            myContext.addEvent(new Event(Event.MODIFY_METADATA, Constants.GROUP, getID(), getDetails()));
            modifiedMetadata = false;
            clearDetails();
        }

        // Redo eperson mappings if they've changed
        if (epeopleChanged)
        {
            // Remove any existing mappings
            DatabaseManager.updateQuery(myContext,
                    "delete from epersongroup2eperson where eperson_group_id= ? ",
                    getID());

            // Add new mappings
            Iterator i = epeople.iterator();

            while (i.hasNext())
            {
                EPerson e = (EPerson) i.next();

                TableRow mappingRow = DatabaseManager.create(myContext,
                        "epersongroup2eperson");
                mappingRow.setColumn("eperson_id", e.getID());
                mappingRow.setColumn("eperson_group_id", getID());
                DatabaseManager.update(myContext, mappingRow);
            }

            epeopleChanged = false;
        }

        // Redo Group mappings if they've changed
        if (groupsChanged)
        {
            // Remove any existing mappings
            DatabaseManager.updateQuery(myContext,
                    "delete from group2group where parent_id= ? ",
                    getID());

            // Add new mappings
            Iterator i = groups.iterator();

            while (i.hasNext())
            {
                Group g = (Group) i.next();

                TableRow mappingRow = DatabaseManager.create(myContext,
                        "group2group");
                mappingRow.setColumn("parent_id", getID());
                mappingRow.setColumn("child_id", g.getID());
                DatabaseManager.update(myContext, mappingRow);
            }

            // groups changed, now change group cache
            rethinkGroupCache();

            groupsChanged = false;
        }

        log.info(LogManager.getHeader(myContext, "update_group", "group_id="
                + getID()));
    }

    /**
     * Return <code>true</code> if <code>other</code> is the same Group as
     * this object, <code>false</code> otherwise
     *
     * @param other
     *            object to compare to
     *
     * @return <code>true</code> if object passed in represents the same group
     *         as this object
     */
    public boolean equals(Object other)
    {
        if (!(other instanceof Group))
        {
            return false;
        }

        return (getID() == ((Group) other).getID());
    }

    public int getType()
    {
        return Constants.GROUP;
    }

    public String getHandle()
    {
        return null;
    }

    /**
     * Regenerate the group cache AKA the group2groupcache table in the database -
     * meant to be called when a group is added or removed from another group
     *
     */
    private void rethinkGroupCache() throws SQLException
    {
        // read in the group2group table
        TableRowIterator tri = DatabaseManager.queryTable(myContext, "group2group",
                "SELECT * FROM group2group");

        Map<Integer,Set<Integer>> parents = new HashMap<Integer,Set<Integer>>();

        try
        {
            while (tri.hasNext())
            {
                TableRow row = (TableRow) tri.next();

                Integer parentID = new Integer(row.getIntColumn("parent_id"));
                Integer childID = new Integer(row.getIntColumn("child_id"));

                // if parent doesn't have an entry, create one
                if (!parents.containsKey(parentID))
                {
                    Set<Integer> children = new HashSet<Integer>();

                    // add child id to the list
                    children.add(childID);
                    parents.put(parentID, children);
                }
                else
                {
                    // parent has an entry, now add the child to the parent's record
                    // of children
                    Set<Integer> children =  parents.get(parentID);
                    children.add(childID);
                }
            }
        }
        finally
        {
            // close the TableRowIterator to free up resources
            if (tri != null)
                tri.close();
        }

        // now parents is a hash of all of the IDs of groups that are parents
        // and each hash entry is a hash of all of the IDs of children of those
        // parent groups
        // so now to establish all parent,child relationships we can iterate
        // through the parents hash

        Iterator i = parents.keySet().iterator();

        while (i.hasNext())
        {
            Integer parentID = (Integer) i.next();

            Set<Integer> myChildren = getChildren(parents, parentID);

            Iterator j = myChildren.iterator();

            while (j.hasNext())
            {
                // child of a parent
                Integer childID = (Integer) j.next();

                ((Set<Integer>) parents.get(parentID)).add(childID);
            }
        }

        // empty out group2groupcache table
        DatabaseManager.updateQuery(myContext,
                "DELETE FROM group2groupcache WHERE id >= 0");

        // write out new one
        Iterator pi = parents.keySet().iterator(); // parent iterator

        while (pi.hasNext())
        {
            Integer parent = (Integer) pi.next();

            Set<Integer> children =  parents.get(parent);
            Iterator ci = children.iterator(); // child iterator

            while (ci.hasNext())
            {
                Integer child = (Integer) ci.next();

                TableRow row = DatabaseManager.create(myContext,
                        "group2groupcache");

                int parentID = parent.intValue();
                int childID = child.intValue();

                row.setColumn("parent_id", parentID);
                row.setColumn("child_id", childID);

                DatabaseManager.update(myContext, row);
            }
        }
    }

    /**
     * Used recursively to generate a map of ALL of the children of the given
     * parent
     *
     * @param parents
     *            Map of parent,child relationships
     * @param parent
     *            the parent you're interested in
     * @return Map whose keys are all of the children of a parent
     */
    private Set<Integer> getChildren(Map<Integer,Set<Integer>> parents, Integer parent)
    {
        Set<Integer> myChildren = new HashSet<Integer>();

        // degenerate case, this parent has no children
        if (!parents.containsKey(parent))
            return myChildren;

        // got this far, so we must have children
        Set<Integer> children =  parents.get(parent);

        // now iterate over all of the children
        Iterator i = children.iterator();

        while (i.hasNext())
        {
            Integer childID = (Integer) i.next();

            // add this child's ID to our return set
            myChildren.add(childID);

            // and now its children
            myChildren.addAll(getChildren(parents, childID));
        }

        return myChildren;
    }
   
    public DSpaceObject getParentObject() throws SQLException
    {
        // could a collection/community admin manage related groups?
        // check before the configuration options could give a performance gain
        // if all group management are disallowed
        if (AuthorizeConfiguration.canCollectionAdminManageAdminGroup()
                || AuthorizeConfiguration.canCollectionAdminManageSubmitters()
                || AuthorizeConfiguration.canCollectionAdminManageWorkflows()
                || AuthorizeConfiguration.canCommunityAdminManageAdminGroup()
                || AuthorizeConfiguration
                        .canCommunityAdminManageCollectionAdminGroup()
                || AuthorizeConfiguration
                        .canCommunityAdminManageCollectionSubmitters()
                || AuthorizeConfiguration
                        .canCommunityAdminManageCollectionWorkflows())
        {
            // is this a collection related group?
            TableRow qResult = DatabaseManager
                    .querySingle(
                            myContext,
                            "SELECT collection_id, workflow_step_1, workflow_step_2, " +
                            " workflow_step_3, submitter, admin FROM collection "
                                    + " WHERE workflow_step_1 = ? OR "
                                    + " workflow_step_2 = ? OR "
                                    + " workflow_step_3 = ? OR "
                                    + " submitter =  ? OR " + " admin = ?",
                            getID(), getID(), getID(), getID(), getID());
            if (qResult != null)
            {
                Collection collection = Collection.find(myContext, qResult
                        .getIntColumn("collection_id"));
               
                if ((qResult.getIntColumn("workflow_step_1") == getID() ||
                        qResult.getIntColumn("workflow_step_2") == getID() ||
                        qResult.getIntColumn("workflow_step_3") == getID()))
                {
                    if (AuthorizeConfiguration.canCollectionAdminManageWorkflows())
                    {
                        return collection;
                    }
                    else if (AuthorizeConfiguration.canCommunityAdminManageCollectionWorkflows())
                    {
                        return collection.getParentObject();
                    }
                }
                if (qResult.getIntColumn("submitter") == getID())
                {
                    if (AuthorizeConfiguration.canCollectionAdminManageSubmitters())
                    {
                        return collection;
                    }
                    else if (AuthorizeConfiguration.canCommunityAdminManageCollectionSubmitters())
                    {
                        return collection.getParentObject();
                    }
                }
                if (qResult.getIntColumn("admin") == getID())
                {
                    if (AuthorizeConfiguration.canCollectionAdminManageAdminGroup())
                    {
                        return collection;
                    }
                    else if (AuthorizeConfiguration.canCommunityAdminManageCollectionAdminGroup())
                    {
                        return collection.getParentObject();
                    }
                }
            }
            // is the group releated to a community and community admin allowed
            // to manage it?
            else if (AuthorizeConfiguration.canCommunityAdminManageAdminGroup())
            {
                qResult = DatabaseManager.querySingle(myContext,
                        "SELECT community_id FROM community "
                                + "WHERE admin = ?", getID());

                if (qResult != null)
                {
                    Community community = Community.find(myContext, qResult
                            .getIntColumn("community_id"));
                    return community;
                }
            }
        }
        return null;
    }
}
TOP

Related Classes of org.dspace.eperson.Group

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.