Package org.dspace.eperson

Source Code of org.dspace.eperson.Group

/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
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 org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeConfiguration;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.content.*;
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$
*/
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 final Logger log = Logger.getLogger(Group.class);

    /** ID of Anonymous Group */
    public static final int ANONYMOUS_ID = 0;

    /** ID of Administrator Group */
    public static final int ADMIN_ID = 1;

    /** The row in the table representing this object */
    private final 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;


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

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

        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(ourContext,"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) ourContext.fromCache(
                                EPerson.class, r.getIntColumn("eperson_id"));

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

                // now get Group objects
                tri = DatabaseManager.queryTable(ourContext,"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) ourContext.fromCache(Group.class,
                                r.getIntColumn("eperson_group_id"));

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

            }
            catch (Exception e)
            {
                throw new IllegalStateException(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, g.getIdentifiers(context)));

        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 getMetadataFirstValue(MetadataSchema.DC_SCHEMA, "title", null, Item.ANY);
    }

    /**
     * set name of group
     *
     * @param name
     *            new group name
     */
    public void setName(String name) {
        setMetadataSingleValue(MetadataSchema.DC_SCHEMA, "title", null, null, 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;

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

    /**
     * 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;

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

    /**
     * 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;
            ourContext.addEvent(new Event(Event.REMOVE, Constants.GROUP, getID(), Constants.EPERSON, e.getID(), e.getEmail(), getIdentifiers(ourContext)));
        }
    }

    /**
     * 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;
            ourContext.addEvent(new Event(Event.REMOVE, Constants.GROUP, getID(), Constants.GROUP, g.getID(), g.getName(), getIdentifiers(ourContext)));
        }
    }

    /**
     * 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() == Group.ANONYMOUS_ID)
        {
            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
     */
    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
     * @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<Integer> i = myGroups.iterator();

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

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

    /**
     * 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(Integer.valueOf(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(Integer.valueOf(special.getID()));
            }
        }

        // all the users are members of the anonymous group
        groupIDs.add(Integer.valueOf(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!

        StringBuilder groupQuery = new StringBuilder();
        groupQuery.append("SELECT * FROM group2groupcache WHERE ");

        Iterator<Integer> i = groupIDs.iterator();

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

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

        // was member of at least one group
        // NOTE: even through the query is built dynamically, all data is
        // separated into the parameters array.
        TableRowIterator tri = DatabaseManager.queryTable(c, "group2groupcache",
                groupQuery.toString(),
                parameters);

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

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

                groupIDs.add(Integer.valueOf(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<Integer> i = myEpeople.iterator();

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

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

    /**
     * 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(Integer.valueOf(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<Integer> i = groupIDs.iterator();

        // don't forget to add the current group to this query!
        parameters[idx++] = Integer.valueOf(g.getID());

        StringBuilder epersonQuery = new StringBuilder();
        epersonQuery.append("SELECT * FROM epersongroup2eperson WHERE ");
        epersonQuery.append("eperson_group_id= ? ");

        if (i.hasNext())
        {
            epersonQuery.append(" OR ");
        }
       
        while (i.hasNext())
        {
            int groupID = (i.next()).intValue();
            parameters[idx++] = Integer.valueOf(groupID);
           
            epersonQuery.append("eperson_group_id= ? ");
            if (i.hasNext())
            {
                epersonQuery.append(" OR ");
            }
        }

        //get all the EPerson IDs
        // Note: even through the query is dynamically built all data is separated
        // into the parameters array.
        tri = DatabaseManager.queryTable(c, "epersongroup2eperson",
                epersonQuery.toString(),
                parameters);

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

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

                epeopleIDs.add(Integer.valueOf(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(Integer.valueOf(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 the named Group, or null if not found
     */
    public static Group findByName(Context context, String name)
            throws SQLException
    {
        String query = "select * from epersongroup e " +
                "LEFT JOIN metadatavalue m on (m.resource_id = e.eperson_group_id and m.resource_type_id = ? and m.metadata_field_id = ?) " +
                "where ";
        if(DatabaseManager.isOracle()) {
            query += " dbms_lob.substr(m.text_value) = ?";
        }else{
            query += " m.text_value = ?";

        }
        TableRow row = DatabaseManager.querySingle(context, query,
                Constants.GROUP,
                MetadataField.findByElement(context, MetadataSchema.find(context, MetadataSchema.DC_SCHEMA).getSchemaID(), "title", null).getFieldID(),
                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
            {
                // Force the row to be a Group row, as it has all epersongroup
                // columns but also some others, so could not be typed using
                // querySingleTable.
                row.setTable("epersongroup");
                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 = "e.eperson_group_id";

            break;

        case NAME:
            s = "m_text_value";

            break;

        default:
            s = "m_text_value";
        }

        // 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.query(
                context,
                "select e.* from epersongroup e " +
                        "LEFT JOIN metadatavalue m on (m.resource_id = e.eperson_group_id and m.resource_type_id = ? and m.metadata_field_id = ?) " +
                        "order by ?",
                Constants.GROUP,
                MetadataField.findByElement(context, MetadataSchema.find(context, MetadataSchema.DC_SCHEMA).getSchemaID(), "title", null).getFieldID(),
                s
        );


        try
        {
            List<TableRow> gRows = rows.toList();

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

            for (int i = 0; i < gRows.size(); i++)
            {
                TableRow row = 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 " +
                "LEFT JOIN metadatavalue m on (m.resource_id = epersongroup.eperson_group_id and m.resource_type_id = ? and m.metadata_field_id = ?) " +
                "WHERE LOWER(m.text_value) LIKE LOWER(?) OR eperson_group_id = ? ");

        if(DatabaseManager.isOracle()){
            queryBuf.append(" ORDER BY cast(m.text_value as varchar2(128))");
        }else{
            queryBuf.append(" ORDER BY m.text_value");
        }
        queryBuf.append(" ASC");

        // Add offset and limit restrictions - Oracle requires special code
        if (DatabaseManager.isOracle())
        {
            // 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 = Integer.valueOf(-1);
    }

        // Create the parameter array, including limit and offset if part of the query

        int metadataFieldId = MetadataField.findByElement(context, MetadataSchema.find(context, MetadataSchema.DC_SCHEMA).getSchemaID(), "title", null).getFieldID();

        Object[] paramArr = new Object[]{Constants.GROUP, metadataFieldId, params, int_param};
        if (limit > 0 && offset > 0)
        {
            paramArr = new Object[]{Constants.GROUP, metadataFieldId,params, int_param, limit, offset};
        }
        else if (limit > 0)
        {
            paramArr = new Object[]{Constants.GROUP, metadataFieldId,params, int_param, limit};
        }
        else if (offset > 0)
        {
            paramArr = new Object[]{Constants.GROUP, metadataFieldId,params, int_param, offset};
        }

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

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

            for (int i = 0; i < groupRows.size(); i++)
            {
                TableRow row = 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 matching the query
     */
    public static int searchResultCount(Context context, String query)
      throws SQLException
  {
    String params = "%"+query.toLowerCase()+"%";
    String dbquery = "SELECT count(*) as gcount FROM epersongroup " +
                "LEFT JOIN metadatavalue m on (m.resource_id = epersongroup.eperson_group_id and m.resource_type_id = ? and m.metadata_field_id = ?) " +
                "WHERE LOWER(m.text_value) 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 = Integer.valueOf(-1);
    }
   
    // Get all the epeople that match the query
    TableRow row = DatabaseManager.querySingle(
                context,
                dbquery,
                new Object[] {
                        Constants.GROUP,
                        MetadataField.findByElement(context, MetadataSchema.find(context, MetadataSchema.DC_SCHEMA).getSchemaID(), "title", null).getFieldID(),
                        params,
                        int_param
                }
        );
   
    // use getIntColumn for Oracle count data
    Long count;
        if (DatabaseManager.isOracle())
        {
            count = Long.valueOf(row.getIntColumn("gcount"));
        }
        else  //getLongColumn works for postgres
        {
            count = Long.valueOf(row.getLongColumn("gcount"));
        }

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

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

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

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

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

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

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

        // Delete the Dublin Core
        removeMetadataFromDatabase();

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

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

        epeople.clear();

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

    }

    /**
     * @throws SQLException
     */
    private void deleteEpersonGroup2WorkspaceItem() throws SQLException
    {
        DatabaseManager.updateQuery(ourContext,
                "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.
     */
    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(ourContext, myRow);

        if (modifiedMetadata)
        {
            updateMetadata();
            clearDetails();
        }

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

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

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

                TableRow mappingRow = DatabaseManager.row("epersongroup2eperson");
                mappingRow.setColumn("eperson_id", e.getID());
                mappingRow.setColumn("eperson_group_id", getID());
                DatabaseManager.insert(ourContext, mappingRow);
            }

            epeopleChanged = false;
        }

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

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

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

                TableRow mappingRow = DatabaseManager.row("group2group");
                mappingRow.setColumn("parent_id", getID());
                mappingRow.setColumn("child_id", g.getID());
                DatabaseManager.insert(ourContext, mappingRow);
            }

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

            groupsChanged = false;
        }

        log.info(LogManager.getHeader(ourContext, "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 obj
     *            object to compare to
     *
     * @return <code>true</code> if object passed in represents the same group
     *         as this object
     */
     @Override
     public boolean equals(Object obj)
     {
         if (obj == null)
         {
             return false;
         }
         if (getClass() != obj.getClass())
         {
             return false;
         }
         final Group other = (Group) obj;
         if(this.getID() != other.getID())
         {
             return false;
         }
         return true;
     }

     @Override
     public int hashCode()
     {
         int hash = 7;
         hash = 59 * hash + (this.myRow != null ? this.myRow.hashCode() : 0);
         return hash;
     }



    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(ourContext, "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 = Integer.valueOf(row.getIntColumn("parent_id"));
                Integer childID = Integer.valueOf(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
        for (Map.Entry<Integer, Set<Integer>> parent : parents.entrySet())
        {
            Set<Integer> myChildren = getChildren(parents, parent.getKey());
            parent.getValue().addAll(myChildren);
        }

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

        // write out new one
        for (Map.Entry<Integer, Set<Integer>> parent : parents.entrySet())
        {
            int parentID = parent.getKey().intValue();

            for (Integer child : parent.getValue())
            {
                TableRow row = DatabaseManager.row("group2groupcache");

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

                DatabaseManager.insert(ourContext, 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<Integer> i = children.iterator();

        while (i.hasNext())
        {
            Integer childID = 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 administrator 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(
                            ourContext,
                            "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(ourContext, 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 related to a community and community administrator allowed
            // to manage it?
            else if (AuthorizeConfiguration.canCommunityAdminManageAdminGroup())
            {
                qResult = DatabaseManager.querySingle(ourContext,
                        "SELECT community_id FROM community "
                                + "WHERE admin = ?", getID());

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

    @Override
    public void updateLastModified()
    {

    }

    /**
     * Main script used to set the group names for anonymous group & admin group, only to be called once on DSpace fresh_install
     * @param args not used
     * @throws SQLException database exception
     * @throws AuthorizeException should not occur since we disable authentication for this method.
     */
    public static void main(String[] args) throws SQLException, AuthorizeException {
        Context context = new Context();
        context.turnOffAuthorisationSystem();

        initDefaultGroupNames(context);

        //Clear the events to avoid the consumers which aren't needed at this time
        context.getEvents().clear();
        context.complete();
    }

    /**
     * Initializes the group names for anymous & administrator
     * @param context the dspace context
     * @throws SQLException database exception
     * @throws AuthorizeException
     */
    public static void initDefaultGroupNames(Context context) throws SQLException, AuthorizeException {
        // Check for Anonymous group. If not found, create it
        Group anonymousGroup = Group.find(context, ANONYMOUS_ID);
        if(anonymousGroup==null)
        {
            anonymousGroup = Group.create(context);
        }
        anonymousGroup.setName("Anonymous");
        anonymousGroup.update();

        // Check for Administrator group. If not found, create it
        Group adminGroup = Group.find(context, ADMIN_ID);
        if(adminGroup==null)
        {
            adminGroup = Group.create(context);
        }
        adminGroup.setName("Administrator");
        adminGroup.update();
    }
}
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.