/*
* FlowGroupUtils.java
*
* Version: $Revision: 3980 $
*
* Date: $Date: 2009-06-26 17:07:25 +0000 (Fri, 26 Jun 2009) $
*
* Copyright (c) 2002, Hewlett-Packard Company and Massachusetts
* Institute of Technology. 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 Hewlett-Packard Company nor the name of the
* Massachusetts Institute of Technology nor the names of their
* 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.app.xmlui.aspect.administrative;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.dspace.app.xmlui.utils.UIException;
import org.dspace.app.xmlui.wing.Message;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.content.Collection;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
/**
* Utility methods to processes actions on Groups. These methods are used
* exclusivly from the administrative flow scripts.
*
* @author scott phillips
*/
public class FlowGroupUtils {
/** Language Strings */
private static final Message T_edit_group_success_notice =
new Message("default","xmlui.administrative.FlowGroupUtils.edit_group_success_notice");
private static final Message T_delete_group_success_notice =
new Message("default","xmlui.administrative.FlowGroupUtils.delete_group_success_notice");
/**
* Return the current name for the given group ID.
* @param context The current DSpace context.
* @param groupID The group id.
* @return The group's name.
*/
public static String getName(Context context, int groupID) throws SQLException
{
if (groupID < 0)
return "New Group";
Group group = Group.find(context,groupID);
if (group == null)
return "New Group";
return group.getName();
}
/**
* Return the list of current epeople ID's that are a member of this group.
*
* @param context The current DSpace context
* @param groupID The group's id.
* @return An array of ids.
*/
public static String[] getEPeopleMembers(Context context, int groupID) throws SQLException
{
// New group, just return an empty list
if (groupID < 0)
return new String[0];
Group group = Group.find(context,groupID);
if (group == null)
return new String[0];
EPerson[] epeople = group.getMembers();
String[] epeopleIDs = new String[epeople.length];
for (int i=0; i < epeople.length; i++)
epeopleIDs[i] = String.valueOf(epeople[i].getID());
return epeopleIDs;
}
/**
* Return the list of current group id's that are a member of this group.
*
* @param context The current DSpace context
* @param groupID The group's id.
* @return An array of ids.
*/
public static String[] getGroupMembers(Context context, int groupID) throws SQLException
{
if (groupID < 0)
return new String[0];
Group group = Group.find(context,groupID);
if (group == null)
return new String[0];
Group[] groups = group.getMemberGroups();
String[] groupIDs = new String[groups.length];
for (int i=0; i < groups.length; i++)
groupIDs[i] = String.valueOf(groups[i].getID());
return groupIDs;
}
/**
* Add the given id to the list and return a new list.
*
* @param list The current array
* @param id The new element
* @return A new combined array.
*/
public static String[] addMember(String[] list, String id)
{
// FIXME: this is terribly ineffecient.
List<String> newList = new ArrayList<String>(Arrays.asList(list));
newList.add(id);
return newList.toArray(new String[newList.size()]);
}
/**
* Remove all instances of the given id from the member list.
*
* @param list The current array
* @param id The id to remove
* @return A new combined array.
*/
public static String[] removeMember(String[] list, String id)
{
// FIXME: this is terribly ineffecient.
List<String> newList = new ArrayList<String>(Arrays.asList(list));
newList.remove(id);
return newList.toArray(new String[newList.size()]);
}
/**
* Save the group. If the name has been changed then it will be updated, if any
* members have been added or removed then they are updated.
*
* If the groupID is -1 then a new group is created.
*
* @param context The current dspace context
* @param groupID The group id, or -1 for a new group.
* @param newName The group's new name.
* @param newEPeopleIDsArray All epeople members
* @param newGroupIDsArray All group members.
* @return A result
*/
public static FlowResult processSaveGroup(Context context, int groupID, String newName, String[] newEPeopleIDsArray, String[] newGroupIDsArray) throws SQLException, AuthorizeException, UIException
{
FlowResult result = new FlowResult();
// Decode the name incase it uses non-ascii characters.
try
{
newName = URLDecoder.decode(newName, Constants.DEFAULT_ENCODING);
}
catch (UnsupportedEncodingException uee)
{
throw new UIException(uee);
}
Group group = null;
if (groupID == -1)
{
// First check if the name is blank.
if (newName == null || newName.length() == 0)
{
// Group's can not have blank names.
result.setContinue(false);
result.addError("group_name");
result.setOutcome(false);
result.setMessage(new Message("default","The group name may not be blank."));
return result;
}
// Create a new group, check if the newName is allready in use.
Group potentialDuplicate = Group.findByName(context,newName);
if (potentialDuplicate == null)
{
// All good, create the new group.
group = Group.create(context);
group.setName(newName);
}
else
{
// The name is allready in use, return in error.
result.setContinue(false);
result.addError("group_name");
result.addError("group_name_duplicate");
result.setOutcome(false);
result.setMessage(new Message("default","The group name is allready in use"));
return result;
}
}
else
{
group = Group.find(context,groupID);
String name = group.getName();
// Only update the name if there has been a change.
if (newName != null && newName.length() > 0 && !name.equals(newName))
{
// The group name is to be updated, check if the newName is allready in use.
Group potentialDuplicate = Group.findByName(context,newName);
if (potentialDuplicate == null)
{
// All good, update the name
group.setName(newName);
}
else
{
// The name is allready in use, return in error.
result.setContinue(false);
result.addError("group_name");
result.addError("group_name_duplicate");
result.setOutcome(false);
result.setMessage(new Message("default","The group name is allready in use"));
return result;
}
}
}
// Second, Prepare to check members by turning arrays into lists
List<Integer> newEPeopleIDs = new ArrayList<Integer>();
for (String epeopleID : newEPeopleIDsArray)
newEPeopleIDs.add(Integer.valueOf(epeopleID));
List<Integer> newGroupIDs = new ArrayList<Integer>();
for (String _groupID : newGroupIDsArray)
newGroupIDs.add(Integer.valueOf(_groupID));
// Third, check if there are any members to remove
// i.e. scan the list on the group against the ids.
for (EPerson epersonMember : group.getMembers())
{
if (!newEPeopleIDs.contains(epersonMember.getID()))
{
// The current eperson is not contained in the new list.
group.removeMember(epersonMember);
}
else
{
// If they are still in the list then remove them
// from the list of people to add.
newEPeopleIDs.remove((Object)epersonMember.getID());
}
}
for (Group groupMember : group.getMemberGroups())
{
if (!newGroupIDs.contains(groupMember.getID()))
{
// The current group is not contained in the new list.
group.removeMember(groupMember);
}
else
{
// If they are still in the list then remove them
// from the list of groups to add.
newGroupIDs.remove((Object)group.getID());
}
}
// Third, check if there are any members to add
// i.e. scan the list of ids against the group.
for (Integer epersonID : newEPeopleIDs)
{
EPerson eperson = EPerson.find(context, epersonID);
group.addMember(eperson);
}
for (Integer _groupID : newGroupIDs)
{
Group _group = Group.find(context, _groupID);
group.addMember(_group);
}
// Last, create the result flow
group.update();
context.commit();
// Let's record our group id incase we created a new one.
result.setParameter("groupID", group.getID());
result.setContinue(true);
result.setOutcome(true);
result.setMessage(T_edit_group_success_notice);
return result;
}
/**
* Remove the specified groups. It is assumed that the user has allready confirm this selection.
*
* @param context The current DSpace context
* @param groupIDs A list of groups to be removed.
* @return A results object.
*/
public static FlowResult processDeleteGroups(Context context, String[] groupIDs) throws SQLException, AuthorizeException, IOException
{
FlowResult result = new FlowResult();
result.setContinue(true);
for (String id : groupIDs)
{
Group groupDeleted = Group.find(context, Integer.valueOf(id));
// If this group is related to a collection, then un-link it.
int collectionId = getCollectionId(groupDeleted.getName());
Role role = getCollectionRole(groupDeleted.getName());
if (collectionId != -1 && role != Role.none)
{
Collection collection = Collection.find(context, collectionId);
if (collection != null)
{
if (role == Role.Administrators)
{
collection.removeAdministrators();
collection.update();
}
else if (role == Role.Submitters)
{
collection.removeSubmitters();
collection.update();
}
else if (role == Role.WorkflowStep1)
{
collection.setWorkflowGroup(1, null);
collection.update();
}
else if (role == Role.WorkflowStep2)
{
collection.setWorkflowGroup(2, null);
collection.update();
}
else if (role == Role.WorkflowStep3)
{
collection.setWorkflowGroup(3, null);
collection.update();
}
else if (role == Role.DefaultRead)
{
// Nothing special needs to happen.
}
}
}
groupDeleted.delete();
}
result.setOutcome(true);
result.setMessage(T_delete_group_success_notice);
return result;
}
/**
* The collection prefix, all groups which are specific to
* a collection start with this.
*/
private static final String COLLECTION_PREFIX = "COLLECTION_";
/**
* These are the possible collection suffixes, all groups which are
* specific to a collection will end with one of these. The collection
* id should be inbetween the prefix and the suffix.
*
* Note: the order of these suffixes are important, see getCollectionRole()
*/
private static final String[] COLLECTION_SUFFIXES = {"_SUBMIT","_ADMIN","_WFSTEP_1","_WORKFLOW_STEP_1","_WFSTEP_2","_WORKFLOW_STEP_2","_WFSTEP_3","_WORKFLOW_STEP_3","_DEFAULT_ITEM_READ"};
/**
* Extracts the collection id that may be immbedded in the given group name.
*
* @param groupName - the name of a group (ie group.getName())
* @return the integer collection id or -1 if the group is not that of a collection
*/
public static int getCollectionId(String groupName)
{
if (groupName != null && groupName.startsWith(COLLECTION_PREFIX))
{
for (String suffix : COLLECTION_SUFFIXES)
{
if (groupName.endsWith(suffix))
{
String idString = groupName.substring(COLLECTION_PREFIX.length());
idString = idString.substring(0, idString.length() - suffix.length());
int collectionID = -1;
try {
collectionID = Integer.valueOf(idString);
return collectionID;
// All good, we were able to ah
}
catch (NumberFormatException nfe)
{
// Somethnig went wrong, just ignore the exception and
// continue searching for a collection id
} // try & catch
} // if it ends with a proper suffix.
} // for each possible suffix
} // if it starts with COLLECTION_
return -1;
}
public enum Role {Administrators, Submitters, WorkflowStep1, WorkflowStep2, WorkflowStep3, DefaultRead, none};
public static Role getCollectionRole(String groupName)
{
if (groupName != null && groupName.startsWith(COLLECTION_PREFIX))
{
for (String suffix : COLLECTION_SUFFIXES)
{
if (groupName.endsWith(suffix))
{
if (COLLECTION_SUFFIXES[0].equals(suffix))
return Role.Submitters;
else if (COLLECTION_SUFFIXES[1].equals(suffix))
return Role.Administrators;
else if (COLLECTION_SUFFIXES[2].equals(suffix))
return Role.WorkflowStep1;
else if (COLLECTION_SUFFIXES[3].equals(suffix))
return Role.WorkflowStep1;
else if (COLLECTION_SUFFIXES[4].equals(suffix))
return Role.WorkflowStep2;
else if (COLLECTION_SUFFIXES[5].equals(suffix))
return Role.WorkflowStep2;
else if (COLLECTION_SUFFIXES[6].equals(suffix))
return Role.WorkflowStep3;
else if (COLLECTION_SUFFIXES[7].equals(suffix))
return Role.WorkflowStep3;
else if (COLLECTION_SUFFIXES[8].equals(suffix))
return Role.DefaultRead;
} // if it ends with a proper suffix.
} // for each possible suffix
} // if it starts with COLLECTION_
return Role.none;
}
/**
* The community prefix: all groups which are specific to
* a community start with this.
*/
private static final String COMMUNITY_PREFIX = "COMMUNITY_";
/**
* These are the possible community suffixes. All groups which are
* specific to a collection will end with one of these. The collection
* id should be between the prefix and the suffix.
*
* Note: the order of these suffixes are important, see getCollectionRole()
*/
private static final String[] COMMUNITY_SUFFIXES = {"_ADMIN"};
/**
* Extracts the community id that may be embedded in the given group name.
*
* @param groupName - the name of a group (ie group.getName())
* @return the integer community id or -1 if the group is not that of a community
*/
public static int getCommunityId(String groupName)
{
if (groupName != null && groupName.startsWith(COMMUNITY_PREFIX))
{
for (String suffix : COMMUNITY_SUFFIXES)
{
if (groupName.endsWith(suffix))
{
String idString = groupName.substring(COMMUNITY_PREFIX.length());
idString = idString.substring(0, idString.length() - suffix.length());
int communityID = -1;
try {
communityID = Integer.valueOf(idString);
return communityID;
}
catch (NumberFormatException nfe)
{}
} // if it ends with a proper suffix.
} // for each possible suffix
} // if it starts with COLLECTION_
return -1;
}
public static Role getCommunityRole(String groupName)
{
if (groupName != null && groupName.startsWith(COMMUNITY_PREFIX))
{
for (String suffix : COMMUNITY_SUFFIXES)
{
if (groupName.endsWith(suffix))
{
if (COLLECTION_SUFFIXES[0].equals(suffix))
return Role.Submitters;
else if (COLLECTION_SUFFIXES[1].equals(suffix))
return Role.Administrators;
else if (COLLECTION_SUFFIXES[2].equals(suffix))
return Role.WorkflowStep1;
else if (COLLECTION_SUFFIXES[3].equals(suffix))
return Role.WorkflowStep1;
else if (COLLECTION_SUFFIXES[4].equals(suffix))
return Role.WorkflowStep2;
else if (COLLECTION_SUFFIXES[5].equals(suffix))
return Role.WorkflowStep2;
else if (COLLECTION_SUFFIXES[6].equals(suffix))
return Role.WorkflowStep3;
else if (COLLECTION_SUFFIXES[7].equals(suffix))
return Role.WorkflowStep3;
else if (COLLECTION_SUFFIXES[8].equals(suffix))
return Role.DefaultRead;
} // if it ends with a proper suffix.
} // for each possible suffix
} // if it starts with COMMUNITY_
return Role.none;
}
}