0001: /*
0002: * Group.java
0003: *
0004: * Version: $Revision: 2074 $
0005: *
0006: * Date: $Date: 2007-07-19 14:40:11 -0500 (Thu, 19 Jul 2007) $
0007: *
0008: * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
0009: * Institute of Technology. All rights reserved.
0010: *
0011: * Redistribution and use in source and binary forms, with or without
0012: * modification, are permitted provided that the following conditions are
0013: * met:
0014: *
0015: * - Redistributions of source code must retain the above copyright
0016: * notice, this list of conditions and the following disclaimer.
0017: *
0018: * - Redistributions in binary form must reproduce the above copyright
0019: * notice, this list of conditions and the following disclaimer in the
0020: * documentation and/or other materials provided with the distribution.
0021: *
0022: * - Neither the name of the Hewlett-Packard Company nor the name of the
0023: * Massachusetts Institute of Technology nor the names of their
0024: * contributors may be used to endorse or promote products derived from
0025: * this software without specific prior written permission.
0026: *
0027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0028: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0029: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0030: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0031: * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
0032: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
0033: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
0034: * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0035: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
0036: * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
0037: * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
0038: * DAMAGE.
0039: */
0040: package org.dspace.eperson;
0041:
0042: import java.sql.SQLException;
0043: import java.util.ArrayList;
0044: import java.util.HashMap;
0045: import java.util.HashSet;
0046: import java.util.Iterator;
0047: import java.util.List;
0048: import java.util.Map;
0049: import java.util.Set;
0050: import java.io.IOException;
0051:
0052: import org.apache.log4j.Logger;
0053: import org.dspace.authorize.AuthorizeException;
0054: import org.dspace.authorize.AuthorizeManager;
0055: import org.dspace.content.DSpaceObject;
0056: import org.dspace.core.ConfigurationManager;
0057: import org.dspace.core.Constants;
0058: import org.dspace.core.Context;
0059: import org.dspace.core.LogManager;
0060: import org.dspace.event.Event;
0061: import org.dspace.storage.rdbms.DatabaseManager;
0062: import org.dspace.storage.rdbms.TableRow;
0063: import org.dspace.storage.rdbms.TableRowIterator;
0064:
0065: /**
0066: * Class representing a group of e-people.
0067: *
0068: * @author David Stuve
0069: * @version $Revision: 2074 $
0070: */
0071: public class Group extends DSpaceObject {
0072: // findAll sortby types
0073: public static final int ID = 0; // sort by ID
0074:
0075: public static final int NAME = 1; // sort by NAME (default)
0076:
0077: /** log4j logger */
0078: private static Logger log = Logger.getLogger(Group.class);
0079:
0080: /** Our context */
0081: private Context myContext;
0082:
0083: /** The row in the table representing this object */
0084: private TableRow myRow;
0085:
0086: /** lists of epeople and groups in the group */
0087: private List<EPerson> epeople = new ArrayList<EPerson>();
0088:
0089: private List<Group> groups = new ArrayList<Group>();
0090:
0091: /** lists that need to be written out again */
0092: private boolean epeopleChanged = false;
0093:
0094: private boolean groupsChanged = false;
0095:
0096: /** is this just a stub, or is all data loaded? */
0097: private boolean isDataLoaded = false;
0098:
0099: /** Flag set when metadata is modified, for events */
0100: private boolean modifiedMetadata;
0101:
0102: /**
0103: * Construct a Group from a given context and tablerow
0104: *
0105: * @param context
0106: * @param row
0107: */
0108: Group(Context context, TableRow row) throws SQLException {
0109: myContext = context;
0110: myRow = row;
0111:
0112: // Cache ourselves
0113: context.cache(this , row.getIntColumn("eperson_group_id"));
0114:
0115: modifiedMetadata = false;
0116: clearDetails();
0117: }
0118:
0119: /**
0120: * Populate Group with eperson and group objects
0121: *
0122: * @param context
0123: * @throws SQLException
0124: */
0125: public void loadData() {
0126: // only populate if not already populated
0127: if (!isDataLoaded) {
0128: // naughty thing to do - swallowing SQL exception and throwing it as
0129: // a RuntimeException - a hack to avoid changing the API all over
0130: // the place
0131: try {
0132: // get epeople objects
0133: TableRowIterator tri = DatabaseManager
0134: .queryTable(
0135: myContext,
0136: "eperson",
0137: "SELECT eperson.* FROM eperson, epersongroup2eperson WHERE "
0138: + "epersongroup2eperson.eperson_id=eperson.eperson_id AND "
0139: + "epersongroup2eperson.eperson_group_id= ?",
0140: myRow.getIntColumn("eperson_group_id"));
0141:
0142: while (tri.hasNext()) {
0143: TableRow r = (TableRow) tri.next();
0144:
0145: // First check the cache
0146: EPerson fromCache = (EPerson) myContext
0147: .fromCache(EPerson.class, r
0148: .getIntColumn("eperson_id"));
0149:
0150: if (fromCache != null) {
0151: epeople.add(fromCache);
0152: } else {
0153: epeople.add(new EPerson(myContext, r));
0154: }
0155: }
0156:
0157: tri.close();
0158:
0159: // now get Group objects
0160: tri = DatabaseManager
0161: .queryTable(
0162: myContext,
0163: "epersongroup",
0164: "SELECT epersongroup.* FROM epersongroup, group2group WHERE "
0165: + "group2group.child_id=epersongroup.eperson_group_id AND "
0166: + "group2group.parent_id= ? ",
0167: myRow.getIntColumn("eperson_group_id"));
0168:
0169: while (tri.hasNext()) {
0170: TableRow r = (TableRow) tri.next();
0171:
0172: // First check the cache
0173: Group fromCache = (Group) myContext.fromCache(
0174: Group.class, r
0175: .getIntColumn("eperson_group_id"));
0176:
0177: if (fromCache != null) {
0178: groups.add(fromCache);
0179: } else {
0180: groups.add(new Group(myContext, r));
0181: }
0182: }
0183:
0184: tri.close();
0185:
0186: } catch (Exception e) {
0187: throw new RuntimeException(e);
0188: }
0189: isDataLoaded = true;
0190: }
0191: }
0192:
0193: /**
0194: * Create a new group
0195: *
0196: * @param context
0197: * DSpace context object
0198: */
0199: public static Group create(Context context) throws SQLException,
0200: AuthorizeException {
0201: // FIXME - authorization?
0202: if (!AuthorizeManager.isAdmin(context)) {
0203: throw new AuthorizeException(
0204: "You must be an admin to create an EPerson Group");
0205: }
0206:
0207: // Create a table row
0208: TableRow row = DatabaseManager.create(context, "epersongroup");
0209:
0210: Group g = new Group(context, row);
0211:
0212: log.info(LogManager.getHeader(context, "create_group",
0213: "group_id=" + g.getID()));
0214:
0215: context.addEvent(new Event(Event.CREATE, Constants.GROUP, g
0216: .getID(), null));
0217:
0218: return g;
0219: }
0220:
0221: /**
0222: * get the ID of the group object
0223: *
0224: * @return id
0225: */
0226: public int getID() {
0227: return myRow.getIntColumn("eperson_group_id");
0228: }
0229:
0230: /**
0231: * get name of group
0232: *
0233: * @return name
0234: */
0235: public String getName() {
0236: return myRow.getStringColumn("name");
0237: }
0238:
0239: /**
0240: * set name of group
0241: *
0242: * @param name
0243: * new group name
0244: */
0245: public void setName(String name) {
0246: myRow.setColumn("name", name);
0247: modifiedMetadata = true;
0248: addDetails("name");
0249: }
0250:
0251: /**
0252: * add an eperson member
0253: *
0254: * @param e
0255: * eperson
0256: */
0257: public void addMember(EPerson e) {
0258: loadData(); // make sure Group has data loaded
0259:
0260: if (isMember(e)) {
0261: return;
0262: }
0263:
0264: epeople.add(e);
0265: epeopleChanged = true;
0266:
0267: myContext.addEvent(new Event(Event.ADD, Constants.GROUP,
0268: getID(), Constants.EPERSON, e.getID(), e.getEmail()));
0269: }
0270:
0271: /**
0272: * add group to this group
0273: *
0274: * @param g
0275: */
0276: public void addMember(Group g) {
0277: loadData(); // make sure Group has data loaded
0278:
0279: // don't add if it's already a member
0280: if (isMember(g)) {
0281: return;
0282: }
0283:
0284: groups.add(g);
0285: groupsChanged = true;
0286:
0287: myContext.addEvent(new Event(Event.ADD, Constants.GROUP,
0288: getID(), Constants.GROUP, g.getID(), g.getName()));
0289: }
0290:
0291: /**
0292: * remove an eperson from a group
0293: *
0294: * @param e
0295: * eperson
0296: */
0297: public void removeMember(EPerson e) {
0298: loadData(); // make sure Group has data loaded
0299:
0300: if (epeople.remove(e)) {
0301: epeopleChanged = true;
0302: myContext
0303: .addEvent(new Event(Event.REMOVE, Constants.GROUP,
0304: getID(), Constants.EPERSON, e.getID(), e
0305: .getEmail()));
0306: }
0307: }
0308:
0309: /**
0310: * remove group from this group
0311: *
0312: * @param g
0313: */
0314: public void removeMember(Group g) {
0315: loadData(); // make sure Group has data loaded
0316:
0317: if (groups.remove(g)) {
0318: groupsChanged = true;
0319: myContext.addEvent(new Event(Event.REMOVE, Constants.GROUP,
0320: getID(), Constants.GROUP, g.getID(), g.getName()));
0321: }
0322: }
0323:
0324: /**
0325: * check to see if an eperson is a member
0326: *
0327: * @param e
0328: * eperson to check membership
0329: */
0330: public boolean isMember(EPerson e) {
0331: // special, group 0 is anonymous
0332: if (getID() == 0) {
0333: return true;
0334: }
0335:
0336: loadData(); // make sure Group has data loaded
0337:
0338: return epeople.contains(e);
0339: }
0340:
0341: /**
0342: * check to see if group is a member
0343: *
0344: * @param g
0345: * group to check
0346: * @return
0347: */
0348: public boolean isMember(Group g) {
0349: loadData(); // make sure Group has data loaded
0350:
0351: return groups.contains(g);
0352: }
0353:
0354: /**
0355: * fast check to see if an eperson is a member called with eperson id, does
0356: * database lookup without instantiating all of the epeople objects and is
0357: * thus a static method
0358: *
0359: * @param c
0360: * context
0361: * @param groupid
0362: * group ID to check
0363: */
0364: public static boolean isMember(Context c, int groupid)
0365: throws SQLException {
0366: // special, everyone is member of group 0 (anonymous)
0367: if (groupid == 0) {
0368: return true;
0369: }
0370:
0371: // first, check for membership if it's a special group
0372: // (special groups can be set even if person isn't authenticated)
0373: if (c.inSpecialGroup(groupid)) {
0374: return true;
0375: }
0376:
0377: EPerson currentuser = c.getCurrentUser();
0378:
0379: // only test for membership if context contains a user
0380: if (currentuser != null) {
0381: return epersonInGroup(c, groupid, currentuser);
0382: }
0383:
0384: // currentuser not set, return FALSE
0385: return false;
0386: }
0387:
0388: /**
0389: * Get all of the groups that an eperson is a member of
0390: *
0391: * @param c
0392: * @param e
0393: * @return
0394: * @throws SQLException
0395: */
0396: public static Group[] allMemberGroups(Context c, EPerson e)
0397: throws SQLException {
0398: List<Group> groupList = new ArrayList<Group>();
0399:
0400: Set<Integer> myGroups = allMemberGroupIDs(c, e);
0401: // now convert those Integers to Groups
0402: Iterator i = myGroups.iterator();
0403:
0404: while (i.hasNext()) {
0405: groupList.add(Group
0406: .find(c, ((Integer) i.next()).intValue()));
0407: }
0408:
0409: return (Group[]) groupList.toArray(new Group[0]);
0410: }
0411:
0412: /**
0413: * get Set of Integers all of the group memberships for an eperson
0414: *
0415: * @param c
0416: * @param e
0417: * @return Set of Integer groupIDs
0418: * @throws SQLException
0419: */
0420: public static Set<Integer> allMemberGroupIDs(Context c, EPerson e)
0421: throws SQLException {
0422: // two queries - first to get groups eperson is a member of
0423: // second query gets parent groups for groups eperson is a member of
0424:
0425: TableRowIterator tri = DatabaseManager
0426: .queryTable(
0427: c,
0428: "epersongroup2eperson",
0429: "SELECT * FROM epersongroup2eperson WHERE eperson_id= ?",
0430: e.getID());
0431:
0432: Set<Integer> groupIDs = new HashSet<Integer>();
0433:
0434: while (tri.hasNext()) {
0435: TableRow row = tri.next();
0436:
0437: int childID = row.getIntColumn("eperson_group_id");
0438:
0439: groupIDs.add(new Integer(childID));
0440: }
0441:
0442: tri.close();
0443:
0444: // Also need to get all "Special Groups" user is a member of!
0445: // Otherwise, you're ignoring the user's membership to these groups!
0446: Group[] specialGroups = c.getSpecialGroups();
0447: for (int j = 0; j < specialGroups.length; j++)
0448: groupIDs.add(new Integer(specialGroups[j].getID()));
0449:
0450: // now we have all owning groups, also grab all parents of owning groups
0451: // yes, I know this could have been done as one big query and a union,
0452: // but doing the Oracle port taught me to keep to simple SQL!
0453:
0454: String groupQuery = "";
0455:
0456: Iterator i = groupIDs.iterator();
0457:
0458: // Build a list of query parameters
0459: Object[] parameters = new Object[groupIDs.size()];
0460: int idx = 0;
0461: while (i.hasNext()) {
0462: int groupID = ((Integer) i.next()).intValue();
0463:
0464: parameters[idx++] = new Integer(groupID);
0465:
0466: groupQuery += "child_id= ? ";
0467: if (i.hasNext())
0468: groupQuery += " OR ";
0469: }
0470:
0471: if ("".equals(groupQuery)) {
0472: // don't do query, isn't member of any groups
0473: return groupIDs;
0474: }
0475:
0476: // was member of at least one group
0477: // NOTE: even through the query is built dynamicaly all data is seperated into the
0478: // the parameters array.
0479: tri = DatabaseManager.queryTable(c, "group2groupcache",
0480: "SELECT * FROM group2groupcache WHERE " + groupQuery,
0481: parameters);
0482:
0483: while (tri.hasNext()) {
0484: TableRow row = tri.next();
0485:
0486: int parentID = row.getIntColumn("parent_id");
0487:
0488: groupIDs.add(new Integer(parentID));
0489: }
0490:
0491: tri.close();
0492:
0493: return groupIDs;
0494: }
0495:
0496: /**
0497: * Get all of the epeople who are a member of the
0498: * specified group, or a member of a sub-group of the
0499: * specified group, etc.
0500: *
0501: * @param c
0502: * DSpace context
0503: * @param g
0504: * Group object
0505: * @return Array of EPerson objects
0506: * @throws SQLException
0507: */
0508: public static EPerson[] allMembers(Context c, Group g)
0509: throws SQLException {
0510: List<EPerson> epersonList = new ArrayList<EPerson>();
0511:
0512: Set<Integer> myEpeople = allMemberIDs(c, g);
0513: // now convert those Integers to EPerson objects
0514: Iterator i = myEpeople.iterator();
0515:
0516: while (i.hasNext()) {
0517: epersonList.add(EPerson.find(c, ((Integer) i.next())
0518: .intValue()));
0519: }
0520:
0521: return (EPerson[]) epersonList.toArray(new EPerson[0]);
0522: }
0523:
0524: /**
0525: * Get Set of all Integers all of the epeople
0526: * members for a group
0527: *
0528: * @param c
0529: * DSpace context
0530: * @param g
0531: * Group object
0532: * @return Set of Integer epersonIDs
0533: * @throws SQLException
0534: */
0535: public static Set<Integer> allMemberIDs(Context c, Group g)
0536: throws SQLException {
0537: // two queries - first to get all groups which are a member of this group
0538: // second query gets all members of each group in the first query
0539: Set<Integer> epeopleIDs = new HashSet<Integer>();
0540:
0541: // Get all groups which are a member of this group
0542: TableRowIterator tri = DatabaseManager.queryTable(c,
0543: "group2groupcache",
0544: "SELECT * FROM group2groupcache WHERE parent_id= ? ", g
0545: .getID());
0546:
0547: Set<Integer> groupIDs = new HashSet<Integer>();
0548:
0549: while (tri.hasNext()) {
0550: TableRow row = tri.next();
0551:
0552: int childID = row.getIntColumn("child_id");
0553:
0554: groupIDs.add(new Integer(childID));
0555: }
0556:
0557: tri.close();
0558:
0559: // now we have all the groups (including this one)
0560: // it is time to find all the EPeople who belong to those groups
0561: // and filter out all duplicates
0562:
0563: Object[] parameters = new Object[groupIDs.size() + 1];
0564: int idx = 0;
0565: Iterator i = groupIDs.iterator();
0566:
0567: // don't forget to add the current group to this query!
0568: parameters[idx++] = new Integer(g.getID());
0569: String epersonQuery = "eperson_group_id= ? ";
0570: if (i.hasNext())
0571: epersonQuery += " OR ";
0572:
0573: while (i.hasNext()) {
0574: int groupID = ((Integer) i.next()).intValue();
0575: parameters[idx++] = new Integer(groupID);
0576:
0577: epersonQuery += "eperson_group_id= ? ";
0578: if (i.hasNext())
0579: epersonQuery += " OR ";
0580: }
0581:
0582: //get all the EPerson IDs
0583: // Note: even through the query is dynamicaly built all data is seperated
0584: // into the parameters array.
0585: tri = DatabaseManager.queryTable(c, "epersongroup2eperson",
0586: "SELECT * FROM epersongroup2eperson WHERE "
0587: + epersonQuery, parameters);
0588:
0589: while (tri.hasNext()) {
0590: TableRow row = tri.next();
0591:
0592: int epersonID = row.getIntColumn("eperson_id");
0593:
0594: epeopleIDs.add(new Integer(epersonID));
0595: }
0596:
0597: tri.close();
0598:
0599: return epeopleIDs;
0600: }
0601:
0602: private static boolean epersonInGroup(Context c, int groupID,
0603: EPerson e) throws SQLException {
0604: Set<Integer> groupIDs = Group.allMemberGroupIDs(c, e);
0605:
0606: return groupIDs.contains(new Integer(groupID));
0607: }
0608:
0609: /**
0610: * find the group by its ID
0611: *
0612: * @param context
0613: * @param id
0614: */
0615: public static Group find(Context context, int id)
0616: throws SQLException {
0617: // First check the cache
0618: Group fromCache = (Group) context.fromCache(Group.class, id);
0619:
0620: if (fromCache != null) {
0621: return fromCache;
0622: }
0623:
0624: TableRow row = DatabaseManager
0625: .find(context, "epersongroup", id);
0626:
0627: if (row == null) {
0628: return null;
0629: } else {
0630: return new Group(context, row);
0631: }
0632: }
0633:
0634: /**
0635: * Find the group by its name - assumes name is unique
0636: *
0637: * @param context
0638: * @param name
0639: *
0640: * @return Group
0641: */
0642: public static Group findByName(Context context, String name)
0643: throws SQLException {
0644: TableRow row = DatabaseManager.findByUnique(context,
0645: "epersongroup", "name", name);
0646:
0647: if (row == null) {
0648: return null;
0649: } else {
0650: // First check the cache
0651: Group fromCache = (Group) context.fromCache(Group.class,
0652: row.getIntColumn("eperson_group_id"));
0653:
0654: if (fromCache != null) {
0655: return fromCache;
0656: } else {
0657: return new Group(context, row);
0658: }
0659: }
0660: }
0661:
0662: /**
0663: * Finds all groups in the site
0664: *
0665: * @param context
0666: * DSpace context
0667: * @param sortField
0668: * field to sort by -- Group.ID or Group.NAME
0669: *
0670: * @return array of all groups in the site
0671: */
0672: public static Group[] findAll(Context context, int sortField)
0673: throws SQLException {
0674: String s;
0675:
0676: switch (sortField) {
0677: case ID:
0678: s = "eperson_group_id";
0679:
0680: break;
0681:
0682: case NAME:
0683: s = "name";
0684:
0685: break;
0686:
0687: default:
0688: s = "name";
0689: }
0690:
0691: // NOTE: The use of 's' in the order by clause can not cause an sql
0692: // injection because the string is derived from constant values above.
0693: TableRowIterator rows = DatabaseManager.queryTable(context,
0694: "epersongroup", "SELECT * FROM epersongroup ORDER BY "
0695: + s);
0696:
0697: List gRows = rows.toList();
0698:
0699: Group[] groups = new Group[gRows.size()];
0700:
0701: for (int i = 0; i < gRows.size(); i++) {
0702: TableRow row = (TableRow) gRows.get(i);
0703:
0704: // First check the cache
0705: Group fromCache = (Group) context.fromCache(Group.class,
0706: row.getIntColumn("eperson_group_id"));
0707:
0708: if (fromCache != null) {
0709: groups[i] = fromCache;
0710: } else {
0711: groups[i] = new Group(context, row);
0712: }
0713: }
0714:
0715: return groups;
0716: }
0717:
0718: /**
0719: * Find the groups that match the search query across eperson_group_id or name
0720: *
0721: * @param context
0722: * DSpace context
0723: * @param query
0724: * The search string
0725: *
0726: * @return array of Group objects
0727: */
0728: public static Group[] search(Context context, String query)
0729: throws SQLException {
0730: return search(context, query, -1, -1);
0731: }
0732:
0733: /**
0734: * Find the groups that match the search query across eperson_group_id or name
0735: *
0736: * @param context
0737: * DSpace context
0738: * @param query
0739: * The search string
0740: * @param offset
0741: * Inclusive offset
0742: * @param limit
0743: * Maximum number of matches returned
0744: *
0745: * @return array of Group objects
0746: */
0747: public static Group[] search(Context context, String query,
0748: int offset, int limit) throws SQLException {
0749: String params = "%" + query.toLowerCase() + "%";
0750: String dbquery = "SELECT * FROM epersongroup WHERE name ILIKE ? OR eperson_group_id = ? ORDER BY name ASC ";
0751:
0752: if (offset >= 0 && limit > 0) {
0753: dbquery += "LIMIT " + limit + " OFFSET " + offset;
0754: }
0755:
0756: // When checking against the eperson-id, make sure the query can be made into a number
0757: Integer int_param;
0758: try {
0759: int_param = Integer.valueOf(query);
0760: } catch (NumberFormatException e) {
0761: int_param = new Integer(-1);
0762: }
0763:
0764: TableRowIterator rows = DatabaseManager.query(context, dbquery,
0765: new Object[] { params, int_param });
0766:
0767: List groupRows = rows.toList();
0768: Group[] groups = new Group[groupRows.size()];
0769:
0770: for (int i = 0; i < groupRows.size(); i++) {
0771: TableRow row = (TableRow) groupRows.get(i);
0772:
0773: // First check the cache
0774: Group fromCache = (Group) context.fromCache(Group.class,
0775: row.getIntColumn("eperson_group_id"));
0776:
0777: if (fromCache != null) {
0778: groups[i] = fromCache;
0779: } else {
0780: groups[i] = new Group(context, row);
0781: }
0782: }
0783: return groups;
0784: }
0785:
0786: /**
0787: * Returns the total number of groups returned by a specific query, without the overhead
0788: * of creating the Group objects to store the results.
0789: *
0790: * @param context
0791: * DSpace context
0792: * @param query
0793: * The search string
0794: *
0795: * @return the number of groups mathching the query
0796: */
0797: public static int searchResultCount(Context context, String query)
0798: throws SQLException {
0799: String params = "%" + query.toLowerCase() + "%";
0800: String dbquery = "SELECT count(*) as count FROM epersongroup WHERE name ILIKE ? OR eperson_group_id = ? ";
0801:
0802: // When checking against the eperson-id, make sure the query can be made into a number
0803: Integer int_param;
0804: try {
0805: int_param = Integer.valueOf(query);
0806: } catch (NumberFormatException e) {
0807: int_param = new Integer(-1);
0808: }
0809:
0810: // Get all the epeople that match the query
0811: TableRow row = DatabaseManager.querySingle(context, dbquery,
0812: new Object[] { params, int_param });
0813:
0814: // use getIntColumn for Oracle count data
0815: Long count;
0816: if ("oracle"
0817: .equals(ConfigurationManager.getProperty("db.name"))) {
0818: count = new Long(row.getIntColumn("count"));
0819: } else //getLongColumn works for postgres
0820: {
0821: count = new Long(row.getLongColumn("count"));
0822: }
0823:
0824: return count.intValue();
0825: }
0826:
0827: /**
0828: * Delete a group
0829: *
0830: */
0831: public void delete() throws SQLException {
0832: // FIXME: authorizations
0833:
0834: myContext.addEvent(new Event(Event.DELETE, Constants.GROUP,
0835: getID(), getName()));
0836:
0837: // Remove from cache
0838: myContext.removeCached(this , getID());
0839:
0840: // Remove any ResourcePolicies that reference this group
0841: AuthorizeManager.removeGroupPolicies(myContext, getID());
0842:
0843: // Remove any group memberships first
0844: DatabaseManager
0845: .updateQuery(
0846: myContext,
0847: "DELETE FROM EPersonGroup2EPerson WHERE eperson_group_id= ? ",
0848: getID());
0849:
0850: // remove any group2groupcache entries
0851: DatabaseManager
0852: .updateQuery(
0853: myContext,
0854: "DELETE FROM group2groupcache WHERE parent_id= ? OR child_id= ? ",
0855: getID(), getID());
0856:
0857: // Now remove any group2group assignments
0858: DatabaseManager
0859: .updateQuery(
0860: myContext,
0861: "DELETE FROM group2group WHERE parent_id= ? OR child_id= ? ",
0862: getID(), getID());
0863:
0864: // don't forget the new table
0865: deleteEpersonGroup2WorkspaceItem();
0866:
0867: // Remove ourself
0868: DatabaseManager.delete(myContext, myRow);
0869:
0870: epeople.clear();
0871:
0872: log.info(LogManager.getHeader(myContext, "delete_group",
0873: "group_id=" + getID()));
0874: }
0875:
0876: /**
0877: * @throws SQLException
0878: */
0879: private void deleteEpersonGroup2WorkspaceItem() throws SQLException {
0880: DatabaseManager
0881: .updateQuery(
0882: myContext,
0883: "DELETE FROM EPersonGroup2WorkspaceItem WHERE eperson_group_id= ? ",
0884: getID());
0885: }
0886:
0887: /**
0888: * Return EPerson members of a Group
0889: */
0890: public EPerson[] getMembers() {
0891: loadData(); // make sure all data is loaded
0892:
0893: EPerson[] myArray = new EPerson[epeople.size()];
0894: myArray = (EPerson[]) epeople.toArray(myArray);
0895:
0896: return myArray;
0897: }
0898:
0899: /**
0900: * Return Group members of a Group
0901: *
0902: * @return
0903: */
0904: public Group[] getMemberGroups() {
0905: loadData(); // make sure all data is loaded
0906:
0907: Group[] myArray = new Group[groups.size()];
0908: myArray = (Group[]) groups.toArray(myArray);
0909:
0910: return myArray;
0911: }
0912:
0913: /**
0914: * Return true if group has no members
0915: */
0916: public boolean isEmpty() {
0917: loadData(); // make sure all data is loaded
0918:
0919: if ((epeople.size() == 0) && (groups.size() == 0)) {
0920: return true;
0921: } else {
0922: return false;
0923: }
0924: }
0925:
0926: /**
0927: * Update the group - writing out group object and EPerson list if necessary
0928: */
0929: public void update() throws SQLException, AuthorizeException {
0930: // FIXME: Check authorisation
0931: DatabaseManager.update(myContext, myRow);
0932:
0933: if (modifiedMetadata) {
0934: myContext.addEvent(new Event(Event.MODIFY_METADATA,
0935: Constants.GROUP, getID(), getDetails()));
0936: modifiedMetadata = false;
0937: clearDetails();
0938: }
0939:
0940: // Redo eperson mappings if they've changed
0941: if (epeopleChanged) {
0942: // Remove any existing mappings
0943: DatabaseManager
0944: .updateQuery(
0945: myContext,
0946: "delete from epersongroup2eperson where eperson_group_id= ? ",
0947: getID());
0948:
0949: // Add new mappings
0950: Iterator i = epeople.iterator();
0951:
0952: while (i.hasNext()) {
0953: EPerson e = (EPerson) i.next();
0954:
0955: TableRow mappingRow = DatabaseManager.create(myContext,
0956: "epersongroup2eperson");
0957: mappingRow.setColumn("eperson_id", e.getID());
0958: mappingRow.setColumn("eperson_group_id", getID());
0959: DatabaseManager.update(myContext, mappingRow);
0960: }
0961:
0962: epeopleChanged = false;
0963: }
0964:
0965: // Redo Group mappings if they've changed
0966: if (groupsChanged) {
0967: // Remove any existing mappings
0968: DatabaseManager.updateQuery(myContext,
0969: "delete from group2group where parent_id= ? ",
0970: getID());
0971:
0972: // Add new mappings
0973: Iterator i = groups.iterator();
0974:
0975: while (i.hasNext()) {
0976: Group g = (Group) i.next();
0977:
0978: TableRow mappingRow = DatabaseManager.create(myContext,
0979: "group2group");
0980: mappingRow.setColumn("parent_id", getID());
0981: mappingRow.setColumn("child_id", g.getID());
0982: DatabaseManager.update(myContext, mappingRow);
0983: }
0984:
0985: // groups changed, now change group cache
0986: rethinkGroupCache();
0987:
0988: groupsChanged = false;
0989: }
0990:
0991: log.info(LogManager.getHeader(myContext, "update_group",
0992: "group_id=" + getID()));
0993: }
0994:
0995: /**
0996: * Return <code>true</code> if <code>other</code> is the same Group as
0997: * this object, <code>false</code> otherwise
0998: *
0999: * @param other
1000: * object to compare to
1001: *
1002: * @return <code>true</code> if object passed in represents the same group
1003: * as this object
1004: */
1005: public boolean equals(Object other) {
1006: if (!(other instanceof Group)) {
1007: return false;
1008: }
1009:
1010: return (getID() == ((Group) other).getID());
1011: }
1012:
1013: public int getType() {
1014: return Constants.GROUP;
1015: }
1016:
1017: public String getHandle() {
1018: return null;
1019: }
1020:
1021: /**
1022: * Regenerate the group cache AKA the group2groupcache table in the database -
1023: * meant to be called when a group is added or removed from another group
1024: *
1025: */
1026: private void rethinkGroupCache() throws SQLException {
1027: // read in the group2group table
1028: TableRowIterator tri = DatabaseManager.queryTable(myContext,
1029: "group2group", "SELECT * FROM group2group");
1030:
1031: Map<Integer, Set<Integer>> parents = new HashMap<Integer, Set<Integer>>();
1032:
1033: while (tri.hasNext()) {
1034: TableRow row = (TableRow) tri.next();
1035:
1036: Integer parentID = new Integer(row
1037: .getIntColumn("parent_id"));
1038: Integer childID = new Integer(row.getIntColumn("child_id"));
1039:
1040: // if parent doesn't have an entry, create one
1041: if (!parents.containsKey(parentID)) {
1042: Set<Integer> children = new HashSet<Integer>();
1043:
1044: // add child id to the list
1045: children.add(childID);
1046: parents.put(parentID, children);
1047: } else {
1048: // parent has an entry, now add the child to the parent's record
1049: // of children
1050: Set<Integer> children = parents.get(parentID);
1051: children.add(childID);
1052: }
1053: }
1054:
1055: tri.close();
1056:
1057: // now parents is a hash of all of the IDs of groups that are parents
1058: // and each hash entry is a hash of all of the IDs of children of those
1059: // parent groups
1060: // so now to establish all parent,child relationships we can iterate
1061: // through the parents hash
1062:
1063: Iterator i = parents.keySet().iterator();
1064:
1065: while (i.hasNext()) {
1066: Integer parentID = (Integer) i.next();
1067:
1068: Set<Integer> myChildren = getChildren(parents, parentID);
1069:
1070: Iterator j = myChildren.iterator();
1071:
1072: while (j.hasNext()) {
1073: // child of a parent
1074: Integer childID = (Integer) j.next();
1075:
1076: ((Set<Integer>) parents.get(parentID)).add(childID);
1077: }
1078: }
1079:
1080: // empty out group2groupcache table
1081: DatabaseManager.updateQuery(myContext,
1082: "DELETE FROM group2groupcache WHERE id >= 0");
1083:
1084: // write out new one
1085: Iterator pi = parents.keySet().iterator(); // parent iterator
1086:
1087: while (pi.hasNext()) {
1088: Integer parent = (Integer) pi.next();
1089:
1090: Set<Integer> children = parents.get(parent);
1091: Iterator ci = children.iterator(); // child iterator
1092:
1093: while (ci.hasNext()) {
1094: Integer child = (Integer) ci.next();
1095:
1096: TableRow row = DatabaseManager.create(myContext,
1097: "group2groupcache");
1098:
1099: int parentID = parent.intValue();
1100: int childID = child.intValue();
1101:
1102: row.setColumn("parent_id", parentID);
1103: row.setColumn("child_id", childID);
1104:
1105: DatabaseManager.update(myContext, row);
1106: }
1107: }
1108: }
1109:
1110: /**
1111: * Used recursively to generate a map of ALL of the children of the given
1112: * parent
1113: *
1114: * @param parents
1115: * Map of parent,child relationships
1116: * @param parent
1117: * the parent you're interested in
1118: * @return Map whose keys are all of the children of a parent
1119: */
1120: private Set<Integer> getChildren(
1121: Map<Integer, Set<Integer>> parents, Integer parent) {
1122: Set<Integer> myChildren = new HashSet<Integer>();
1123:
1124: // degenerate case, this parent has no children
1125: if (!parents.containsKey(parent))
1126: return myChildren;
1127:
1128: // got this far, so we must have children
1129: Set<Integer> children = parents.get(parent);
1130:
1131: // now iterate over all of the children
1132: Iterator i = children.iterator();
1133:
1134: while (i.hasNext()) {
1135: Integer childID = (Integer) i.next();
1136:
1137: // add this child's ID to our return set
1138: myChildren.add(childID);
1139:
1140: // and now its children
1141: myChildren.addAll(getChildren(parents, childID));
1142: }
1143:
1144: return myChildren;
1145: }
1146: }
|