mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-08 02:24:18 +00:00
1849 lines
59 KiB
Java
1849 lines
59 KiB
Java
/**
|
|
* 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.content;
|
|
|
|
import org.apache.log4j.Logger;
|
|
import org.dspace.app.util.AuthorizeUtil;
|
|
import org.dspace.authorize.AuthorizeConfiguration;
|
|
import org.dspace.authorize.AuthorizeException;
|
|
import org.dspace.authorize.AuthorizeManager;
|
|
import org.dspace.authorize.ResourcePolicy;
|
|
import org.dspace.browse.BrowseException;
|
|
import org.dspace.browse.IndexBrowse;
|
|
import org.dspace.browse.ItemCountException;
|
|
import org.dspace.browse.ItemCounter;
|
|
import org.dspace.core.*;
|
|
import org.dspace.eperson.Group;
|
|
import org.dspace.event.Event;
|
|
import org.dspace.handle.HandleManager;
|
|
import org.dspace.storage.rdbms.DatabaseManager;
|
|
import org.dspace.storage.rdbms.TableRow;
|
|
import org.dspace.storage.rdbms.TableRowIterator;
|
|
import org.dspace.workflow.WorkflowItem;
|
|
import org.dspace.xmlworkflow.storedcomponents.CollectionRole;
|
|
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
|
|
|
import java.io.Serializable;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.sql.PreparedStatement;
|
|
import java.sql.ResultSet;
|
|
import java.sql.SQLException;
|
|
import java.util.*;
|
|
|
|
/**
|
|
* Class representing a collection.
|
|
* <P>
|
|
* The collection's metadata (name, introductory text etc), workflow groups, and
|
|
* default group of submitters are loaded into memory. Changes to metadata are
|
|
* not written to the database until <code>update</code> is called. If you
|
|
* create or remove a workflow group, the change is only reflected in the
|
|
* database after calling <code>update</code>. The default group of
|
|
* submitters is slightly different - creating or removing this has instant
|
|
* effect.
|
|
*
|
|
* @author Robert Tansley
|
|
* @version $Revision$
|
|
*/
|
|
public class Collection extends DSpaceObject
|
|
{
|
|
/** log4j category */
|
|
private static final Logger log = Logger.getLogger(Collection.class);
|
|
|
|
/** The table row corresponding to this item */
|
|
private final TableRow collectionRow;
|
|
|
|
/** The logo bitstream */
|
|
private Bitstream logo;
|
|
|
|
/** The item template */
|
|
private Item template;
|
|
|
|
/** Our Handle */
|
|
private String handle;
|
|
|
|
/** Flag set when data is modified, for events */
|
|
private boolean modified;
|
|
|
|
/**
|
|
* Groups corresponding to workflow steps - NOTE these start from one, so
|
|
* workflowGroups[0] corresponds to workflow_step_1.
|
|
*/
|
|
private final Group[] workflowGroup;
|
|
|
|
/** The default group of submitters */
|
|
private Group submitters;
|
|
|
|
/** The default group of administrators */
|
|
private Group admins;
|
|
|
|
// Keys for accessing Collection metadata
|
|
public static final String COPYRIGHT_TEXT = "copyright_text";
|
|
public static final String INTRODUCTORY_TEXT = "introductory_text";
|
|
public static final String SHORT_DESCRIPTION = "short_description";
|
|
public static final String SIDEBAR_TEXT = "side_bar_text";
|
|
public static final String PROVENANCE_TEXT = "provenance_description";
|
|
|
|
/**
|
|
* Construct a collection with the given table row
|
|
*
|
|
* @param context
|
|
* the context this object exists in
|
|
* @param row
|
|
* the corresponding row in the table
|
|
* @throws SQLException
|
|
*/
|
|
Collection(Context context, TableRow row) throws SQLException
|
|
{
|
|
super(context);
|
|
|
|
// Ensure that my TableRow is typed.
|
|
if (null == row.getTable())
|
|
row.setTable("collection");
|
|
|
|
collectionRow = row;
|
|
|
|
// Get the logo bitstream
|
|
if (collectionRow.isColumnNull("logo_bitstream_id"))
|
|
{
|
|
logo = null;
|
|
}
|
|
else
|
|
{
|
|
logo = Bitstream.find(ourContext, collectionRow
|
|
.getIntColumn("logo_bitstream_id"));
|
|
}
|
|
|
|
// Get the template item
|
|
if (collectionRow.isColumnNull("template_item_id"))
|
|
{
|
|
template = null;
|
|
}
|
|
else
|
|
{
|
|
template = Item.find(ourContext, collectionRow
|
|
.getIntColumn("template_item_id"));
|
|
}
|
|
|
|
// Get the relevant groups
|
|
workflowGroup = new Group[3];
|
|
|
|
workflowGroup[0] = groupFromColumn("workflow_step_1");
|
|
workflowGroup[1] = groupFromColumn("workflow_step_2");
|
|
workflowGroup[2] = groupFromColumn("workflow_step_3");
|
|
|
|
submitters = groupFromColumn("submitter");
|
|
admins = groupFromColumn("admin");
|
|
|
|
// Get our Handle if any
|
|
handle = HandleManager.findHandle(context, this);
|
|
|
|
// Cache ourselves
|
|
context.cache(this, row.getIntColumn("collection_id"));
|
|
|
|
modified = false;
|
|
clearDetails();
|
|
}
|
|
|
|
/**
|
|
* Get a collection from the database. Loads in the metadata
|
|
*
|
|
* @param context
|
|
* DSpace context object
|
|
* @param id
|
|
* ID of the collection
|
|
*
|
|
* @return the collection, or null if the ID is invalid.
|
|
* @throws SQLException
|
|
*/
|
|
public static Collection find(Context context, int id) throws SQLException
|
|
{
|
|
// First check the cache
|
|
Collection fromCache = (Collection) context.fromCache(Collection.class,
|
|
id);
|
|
|
|
if (fromCache != null)
|
|
{
|
|
return fromCache;
|
|
}
|
|
|
|
TableRow row = DatabaseManager.find(context, "collection", id);
|
|
|
|
if (row == null)
|
|
{
|
|
if (log.isDebugEnabled())
|
|
{
|
|
log.debug(LogManager.getHeader(context, "find_collection",
|
|
"not_found,collection_id=" + id));
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// not null, return Collection
|
|
if (log.isDebugEnabled())
|
|
{
|
|
log.debug(LogManager.getHeader(context, "find_collection",
|
|
"collection_id=" + id));
|
|
}
|
|
|
|
return new Collection(context, row);
|
|
}
|
|
|
|
/**
|
|
* Create a new collection, with a new ID. This method is not public, and
|
|
* does not check authorisation.
|
|
*
|
|
* @param context
|
|
* DSpace context object
|
|
*
|
|
* @return the newly created collection
|
|
* @throws SQLException
|
|
* @throws AuthorizeException
|
|
*/
|
|
static Collection create(Context context) throws SQLException,
|
|
AuthorizeException
|
|
{
|
|
return create(context, null);
|
|
}
|
|
|
|
/**
|
|
* Create a new collection, with a new ID. This method is not public, and
|
|
* does not check authorisation.
|
|
*
|
|
* @param context
|
|
* DSpace context object
|
|
*
|
|
* @param handle the pre-determined Handle to assign to the new community
|
|
* @return the newly created collection
|
|
* @throws SQLException
|
|
* @throws AuthorizeException
|
|
*/
|
|
static Collection create(Context context, String handle) throws SQLException,
|
|
AuthorizeException
|
|
{
|
|
TableRow row = DatabaseManager.create(context, "collection");
|
|
Collection c = new Collection(context, row);
|
|
|
|
try
|
|
{
|
|
c.handle = (handle == null) ?
|
|
HandleManager.createHandle(context, c) :
|
|
HandleManager.createHandle(context, c, handle);
|
|
}
|
|
catch(IllegalStateException ie)
|
|
{
|
|
//If an IllegalStateException is thrown, then an existing object is already using this handle
|
|
//Remove the collection we just created -- as it is incomplete
|
|
try
|
|
{
|
|
if(c!=null)
|
|
{
|
|
c.delete();
|
|
}
|
|
} catch(Exception e) { }
|
|
|
|
//pass exception on up the chain
|
|
throw ie;
|
|
}
|
|
|
|
// create the default authorization policy for collections
|
|
// of 'anonymous' READ
|
|
Group anonymousGroup = Group.find(context, 0);
|
|
|
|
ResourcePolicy myPolicy = ResourcePolicy.create(context);
|
|
myPolicy.setResource(c);
|
|
myPolicy.setAction(Constants.READ);
|
|
myPolicy.setGroup(anonymousGroup);
|
|
myPolicy.update();
|
|
|
|
// now create the default policies for submitted items
|
|
myPolicy = ResourcePolicy.create(context);
|
|
myPolicy.setResource(c);
|
|
myPolicy.setAction(Constants.DEFAULT_ITEM_READ);
|
|
myPolicy.setGroup(anonymousGroup);
|
|
myPolicy.update();
|
|
|
|
myPolicy = ResourcePolicy.create(context);
|
|
myPolicy.setResource(c);
|
|
myPolicy.setAction(Constants.DEFAULT_BITSTREAM_READ);
|
|
myPolicy.setGroup(anonymousGroup);
|
|
myPolicy.update();
|
|
|
|
context.addEvent(new Event(Event.CREATE, Constants.COLLECTION,
|
|
c.getID(), c.handle, c.getIdentifiers(context)));
|
|
|
|
log.info(LogManager.getHeader(context, "create_collection",
|
|
"collection_id=" + row.getIntColumn("collection_id"))
|
|
+ ",handle=" + c.handle);
|
|
|
|
return c;
|
|
}
|
|
|
|
/**
|
|
* Get all collections in the system. These are alphabetically sorted by
|
|
* collection name.
|
|
*
|
|
* @param context
|
|
* DSpace context object
|
|
*
|
|
* @return the collections in the system
|
|
* @throws SQLException
|
|
*/
|
|
public static Collection[] findAll(Context context) throws SQLException
|
|
{
|
|
TableRowIterator tri = null;
|
|
List<Collection> collections = null;
|
|
List<Serializable> params = new ArrayList<Serializable>();
|
|
StringBuffer query = new StringBuffer(
|
|
"SELECT c.*" +
|
|
"FROM collection c " +
|
|
"LEFT JOIN metadatavalue m ON (" +
|
|
"m.resource_id = c.collection_id AND " +
|
|
"m.resource_type_id = ? AND " +
|
|
"m.metadata_field_id = ?" +
|
|
")"
|
|
);
|
|
|
|
if (DatabaseManager.isOracle())
|
|
{
|
|
query.append(" ORDER BY cast(m.text_value as varchar2(128))");
|
|
}
|
|
else
|
|
{
|
|
query.append(" ORDER BY m.text_value");
|
|
}
|
|
|
|
params.add(Constants.COLLECTION);
|
|
params.add(
|
|
MetadataField.findByElement(
|
|
context,
|
|
MetadataSchema.find(context, MetadataSchema.DC_SCHEMA).getSchemaID(),
|
|
"title",
|
|
null
|
|
).getFieldID()
|
|
);
|
|
|
|
try
|
|
{
|
|
tri = DatabaseManager.query(
|
|
context, query.toString(), params.toArray()
|
|
);
|
|
|
|
collections = new ArrayList<Collection>();
|
|
|
|
while (tri.hasNext())
|
|
{
|
|
TableRow row = tri.next();
|
|
|
|
// First check the cache
|
|
Collection fromCache = (Collection) context.fromCache(
|
|
Collection.class, row.getIntColumn("collection_id"));
|
|
|
|
if (fromCache != null)
|
|
{
|
|
collections.add(fromCache);
|
|
}
|
|
else
|
|
{
|
|
collections.add(new Collection(context, row));
|
|
}
|
|
}
|
|
}
|
|
catch (SQLException e)
|
|
{
|
|
log.error("Find all Collections - ", e);
|
|
throw e;
|
|
}
|
|
finally
|
|
{
|
|
// close the TableRowIterator to free up resources
|
|
if (tri != null)
|
|
{
|
|
tri.close();
|
|
}
|
|
}
|
|
|
|
Collection[] collectionArray = new Collection[collections.size()];
|
|
collectionArray = (Collection[]) collections.toArray(collectionArray);
|
|
|
|
return collectionArray;
|
|
}
|
|
|
|
/**
|
|
* Get all collections in the system. Adds support for limit and offset.
|
|
* @param context
|
|
* @param limit
|
|
* @param offset
|
|
* @return
|
|
* @throws SQLException
|
|
*/
|
|
public static Collection[] findAll(Context context, Integer limit, Integer offset) throws SQLException
|
|
{
|
|
TableRowIterator tri = null;
|
|
List<Collection> collections = null;
|
|
List<Serializable> params = new ArrayList<Serializable>();
|
|
StringBuffer query = new StringBuffer(
|
|
"SELECT c.*" +
|
|
"FROM collection c " +
|
|
"LEFT JOIN metadatavalue m ON (" +
|
|
"m.resource_id = c.collection_id AND " +
|
|
"m.resource_type_id = ? AND " +
|
|
"m.metadata_field_id = ?" +
|
|
")"
|
|
);
|
|
|
|
if (DatabaseManager.isOracle())
|
|
{
|
|
query.append(" ORDER BY cast(m.text_value as varchar2(128))");
|
|
}
|
|
else
|
|
{
|
|
query.append(" ORDER BY m.text_value");
|
|
}
|
|
|
|
params.add(Constants.COLLECTION);
|
|
params.add(
|
|
MetadataField.findByElement(
|
|
context,
|
|
MetadataSchema.find(context, MetadataSchema.DC_SCHEMA).getSchemaID(),
|
|
"title",
|
|
null
|
|
).getFieldID()
|
|
);
|
|
|
|
DatabaseManager.applyOffsetAndLimit(query, params, offset, limit);
|
|
|
|
try
|
|
{
|
|
tri = DatabaseManager.query(
|
|
context, query.toString(), params.toArray()
|
|
);
|
|
|
|
collections = new ArrayList<Collection>();
|
|
|
|
while (tri.hasNext())
|
|
{
|
|
TableRow row = tri.next();
|
|
|
|
// First check the cache
|
|
Collection fromCache = (Collection) context.fromCache(
|
|
Collection.class, row.getIntColumn("collection_id"));
|
|
|
|
if (fromCache != null)
|
|
{
|
|
collections.add(fromCache);
|
|
}
|
|
else
|
|
{
|
|
collections.add(new Collection(context, row));
|
|
}
|
|
}
|
|
}
|
|
catch (SQLException e)
|
|
{
|
|
log.error("Find all Collections offset/limit - ", e);
|
|
throw e;
|
|
}
|
|
finally
|
|
{
|
|
// close the TableRowIterator to free up resources
|
|
if (tri != null)
|
|
{
|
|
tri.close();
|
|
}
|
|
}
|
|
|
|
Collection[] collectionArray = new Collection[collections.size()];
|
|
collectionArray = (Collection[]) collections.toArray(collectionArray);
|
|
|
|
return collectionArray;
|
|
}
|
|
|
|
/**
|
|
* Get the in_archive items in this collection. The order is indeterminate.
|
|
*
|
|
* @return an iterator over the items in the collection.
|
|
* @throws SQLException
|
|
*/
|
|
public ItemIterator getItems() throws SQLException
|
|
{
|
|
String myQuery = "SELECT item.* FROM item, collection2item WHERE "
|
|
+ "item.item_id=collection2item.item_id AND "
|
|
+ "collection2item.collection_id= ? "
|
|
+ "AND item.in_archive='1'";
|
|
|
|
TableRowIterator rows = DatabaseManager.queryTable(ourContext, "item",
|
|
myQuery,getID());
|
|
|
|
return new ItemIterator(ourContext, rows);
|
|
}
|
|
|
|
/**
|
|
* Get the in_archive items in this collection. The order is indeterminate.
|
|
* Provides the ability to use limit and offset, for efficient paging.
|
|
* @param limit Max number of results in set
|
|
* @param offset Number of results to jump ahead by. 100 = 100th result is first, not 100th page.
|
|
* @return an iterator over the items in the collection.
|
|
* @throws SQLException
|
|
*/
|
|
public ItemIterator getItems(Integer limit, Integer offset) throws SQLException
|
|
{
|
|
String myQuery = "SELECT item.* FROM item, collection2item WHERE "
|
|
+ "item.item_id=collection2item.item_id AND "
|
|
+ "collection2item.collection_id= ? "
|
|
+ "AND item.in_archive='1' limit ? offset ?";
|
|
|
|
TableRowIterator rows = DatabaseManager.queryTable(ourContext, "item",
|
|
myQuery,getID(), limit, offset);
|
|
|
|
return new ItemIterator(ourContext, rows);
|
|
}
|
|
|
|
/**
|
|
* Get all the items in this collection. The order is indeterminate.
|
|
*
|
|
* @return an iterator over the items in the collection.
|
|
* @throws SQLException
|
|
*/
|
|
public ItemIterator getAllItems() throws SQLException
|
|
{
|
|
String myQuery = "SELECT item.* FROM item, collection2item WHERE "
|
|
+ "item.item_id=collection2item.item_id AND "
|
|
+ "collection2item.collection_id= ? ";
|
|
|
|
TableRowIterator rows = DatabaseManager.queryTable(ourContext, "item",
|
|
myQuery,getID());
|
|
|
|
return new ItemIterator(ourContext, rows);
|
|
}
|
|
|
|
/**
|
|
* Get the internal ID of this collection
|
|
*
|
|
* @return the internal identifier
|
|
*/
|
|
public int getID()
|
|
{
|
|
return collectionRow.getIntColumn("collection_id");
|
|
}
|
|
|
|
/**
|
|
* @see org.dspace.content.DSpaceObject#getHandle()
|
|
*/
|
|
public String getHandle()
|
|
{
|
|
if(handle == null) {
|
|
try {
|
|
handle = HandleManager.findHandle(this.ourContext, this);
|
|
} catch (SQLException e) {
|
|
// TODO Auto-generated catch block
|
|
//e.printStackTrace();
|
|
}
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
/**
|
|
* Get the value of a metadata field
|
|
*
|
|
* @param field
|
|
* the name of the metadata field to get
|
|
*
|
|
* @return the value of the metadata field
|
|
*
|
|
* @exception IllegalArgumentException
|
|
* if the requested metadata field doesn't exist
|
|
*/
|
|
@Deprecated
|
|
public String getMetadata(String field)
|
|
{
|
|
String[] MDValue = getMDValueByLegacyField(field);
|
|
String value = getMetadataFirstValue(MDValue[0], MDValue[1], MDValue[2], Item.ANY);
|
|
return value == null ? "" : value;
|
|
}
|
|
|
|
/**
|
|
* Set a metadata value
|
|
*
|
|
* @param field
|
|
* the name of the metadata field to get
|
|
* @param value
|
|
* value to set the field to
|
|
*
|
|
* @exception IllegalArgumentException
|
|
* if the requested metadata field doesn't exist
|
|
* @exception MissingResourceException
|
|
*/
|
|
@Deprecated
|
|
public void setMetadata(String field, String value) throws MissingResourceException {
|
|
if ((field.trim()).equals("name") && (value == null || value.trim().equals("")))
|
|
{
|
|
try
|
|
{
|
|
value = I18nUtil.getMessage("org.dspace.workflow.WorkflowManager.untitled");
|
|
}
|
|
catch (MissingResourceException e)
|
|
{
|
|
value = "Untitled";
|
|
}
|
|
}
|
|
|
|
String[] MDValue = getMDValueByLegacyField(field);
|
|
|
|
/*
|
|
* Set metadata field to null if null
|
|
* and trim strings to eliminate excess
|
|
* whitespace.
|
|
*/
|
|
if(value == null)
|
|
{
|
|
clearMetadata(MDValue[0], MDValue[1], MDValue[2], Item.ANY);
|
|
modifiedMetadata = true;
|
|
}
|
|
else
|
|
{
|
|
setMetadataSingleValue(MDValue[0], MDValue[1], MDValue[2], null, value);
|
|
}
|
|
|
|
addDetails(field);
|
|
}
|
|
|
|
public String getName()
|
|
{
|
|
String value = getMetadataFirstValue(MetadataSchema.DC_SCHEMA, "title", null, Item.ANY);
|
|
return value == null ? "" : value;
|
|
}
|
|
|
|
/**
|
|
* Get the logo for the collection. <code>null</code> is returned if the
|
|
* collection does not have a logo.
|
|
*
|
|
* @return the logo of the collection, or <code>null</code>
|
|
*/
|
|
public Bitstream getLogo()
|
|
{
|
|
return logo;
|
|
}
|
|
|
|
/**
|
|
* Give the collection a logo. Passing in <code>null</code> removes any
|
|
* existing logo. You will need to set the format of the new logo bitstream
|
|
* before it will work, for example to "JPEG". Note that
|
|
* <code>update</code> will need to be called for the change to take
|
|
* effect. Setting a logo and not calling <code>update</code> later may
|
|
* result in a previous logo lying around as an "orphaned" bitstream.
|
|
*
|
|
* @param is the stream to use as the new logo
|
|
*
|
|
* @return the new logo bitstream, or <code>null</code> if there is no
|
|
* logo (<code>null</code> was passed in)
|
|
* @throws AuthorizeException
|
|
* @throws IOException
|
|
* @throws SQLException
|
|
*/
|
|
public Bitstream setLogo(InputStream is) throws AuthorizeException,
|
|
IOException, SQLException
|
|
{
|
|
// Check authorisation
|
|
// authorized to remove the logo when DELETE rights
|
|
// authorized when canEdit
|
|
if (!((is == null) && AuthorizeManager.authorizeActionBoolean(
|
|
ourContext, this, Constants.DELETE)))
|
|
{
|
|
canEdit(true);
|
|
}
|
|
|
|
// First, delete any existing logo
|
|
if (!collectionRow.isColumnNull("logo_bitstream_id"))
|
|
{
|
|
logo.delete();
|
|
}
|
|
|
|
if (is == null)
|
|
{
|
|
collectionRow.setColumnNull("logo_bitstream_id");
|
|
logo = null;
|
|
|
|
log.info(LogManager.getHeader(ourContext, "remove_logo",
|
|
"collection_id=" + getID()));
|
|
}
|
|
else
|
|
{
|
|
Bitstream newLogo = Bitstream.create(ourContext, is);
|
|
collectionRow.setColumn("logo_bitstream_id", newLogo.getID());
|
|
logo = newLogo;
|
|
|
|
// now create policy for logo bitstream
|
|
// to match our READ policy
|
|
List<ResourcePolicy> policies = AuthorizeManager.getPoliciesActionFilter(ourContext, this, Constants.READ);
|
|
AuthorizeManager.addPolicies(ourContext, policies, newLogo);
|
|
|
|
log.info(LogManager.getHeader(ourContext, "set_logo",
|
|
"collection_id=" + getID() + "logo_bitstream_id="
|
|
+ newLogo.getID()));
|
|
}
|
|
|
|
modified = true;
|
|
return logo;
|
|
}
|
|
|
|
/**
|
|
* Create a workflow group for the given step if one does not already exist.
|
|
* Returns either the newly created group or the previously existing one.
|
|
* Note that while the new group is created in the database, the association
|
|
* between the group and the collection is not written until
|
|
* <code>update</code> is called.
|
|
*
|
|
* @param step
|
|
* the step (1-3) of the workflow to create or get the group for
|
|
*
|
|
* @return the workflow group associated with this collection
|
|
* @throws SQLException
|
|
* @throws AuthorizeException
|
|
*/
|
|
public Group createWorkflowGroup(int step) throws SQLException,
|
|
AuthorizeException
|
|
{
|
|
// Check authorisation - Must be an Admin to create Workflow Group
|
|
AuthorizeUtil.authorizeManageWorkflowsGroup(ourContext, this);
|
|
|
|
if (workflowGroup[step - 1] == null)
|
|
{
|
|
//turn off authorization so that Collection Admins can create Collection Workflow Groups
|
|
ourContext.turnOffAuthorisationSystem();
|
|
Group g = Group.create(ourContext);
|
|
ourContext.restoreAuthSystemState();
|
|
|
|
g.setName("COLLECTION_" + getID() + "_WORKFLOW_STEP_" + step);
|
|
g.update();
|
|
setWorkflowGroup(step, g);
|
|
|
|
AuthorizeManager.addPolicy(ourContext, this, Constants.ADD, g);
|
|
}
|
|
|
|
return workflowGroup[step - 1];
|
|
}
|
|
|
|
/**
|
|
* Set the workflow group corresponding to a particular workflow step.
|
|
* <code>null</code> can be passed in if there should be no associated
|
|
* group for that workflow step; any existing group is NOT deleted.
|
|
*
|
|
* @param step
|
|
* the workflow step (1-3)
|
|
* @param g
|
|
* the new workflow group, or <code>null</code>
|
|
*/
|
|
public void setWorkflowGroup(int step, Group g)
|
|
{
|
|
workflowGroup[step - 1] = g;
|
|
|
|
if (g == null)
|
|
{
|
|
collectionRow.setColumnNull("workflow_step_" + step);
|
|
}
|
|
else
|
|
{
|
|
collectionRow.setColumn("workflow_step_" + step, g.getID());
|
|
}
|
|
modified = true;
|
|
}
|
|
|
|
/**
|
|
* Get the the workflow group corresponding to a particular workflow step.
|
|
* This returns <code>null</code> if there is no group associated with
|
|
* this collection for the given step.
|
|
*
|
|
* @param step
|
|
* the workflow step (1-3)
|
|
*
|
|
* @return the group of reviewers or <code>null</code>
|
|
*/
|
|
public Group getWorkflowGroup(int step)
|
|
{
|
|
return workflowGroup[step - 1];
|
|
}
|
|
|
|
/**
|
|
* Create a default submitters group if one does not already exist. Returns
|
|
* either the newly created group or the previously existing one. Note that
|
|
* other groups may also be allowed to submit to this collection by the
|
|
* authorization system.
|
|
*
|
|
* @return the default group of submitters associated with this collection
|
|
* @throws SQLException
|
|
* @throws AuthorizeException
|
|
*/
|
|
public Group createSubmitters() throws SQLException, AuthorizeException
|
|
{
|
|
// Check authorisation - Must be an Admin to create Submitters Group
|
|
AuthorizeUtil.authorizeManageSubmittersGroup(ourContext, this);
|
|
|
|
if (submitters == null)
|
|
{
|
|
//turn off authorization so that Collection Admins can create Collection Submitters
|
|
ourContext.turnOffAuthorisationSystem();
|
|
submitters = Group.create(ourContext);
|
|
ourContext.restoreAuthSystemState();
|
|
|
|
submitters.setName("COLLECTION_" + getID() + "_SUBMIT");
|
|
submitters.update();
|
|
}
|
|
|
|
// register this as the submitter group
|
|
collectionRow.setColumn("submitter", submitters.getID());
|
|
|
|
AuthorizeManager.addPolicy(ourContext, this, Constants.ADD, submitters);
|
|
|
|
modified = true;
|
|
return submitters;
|
|
}
|
|
|
|
/**
|
|
* Remove the submitters group, if no group has already been created
|
|
* then return without error. This will merely dereference the current
|
|
* submitters group from the collection so that it may be deleted
|
|
* without violating database constraints.
|
|
*/
|
|
public void removeSubmitters() throws SQLException, AuthorizeException
|
|
{
|
|
// Check authorisation - Must be an Admin to delete Submitters Group
|
|
AuthorizeUtil.authorizeManageSubmittersGroup(ourContext, this);
|
|
|
|
// just return if there is no administrative group.
|
|
if (submitters == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Remove the link to the collection table.
|
|
collectionRow.setColumnNull("submitter");
|
|
submitters = null;
|
|
|
|
modified = true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the default group of submitters, if there is one. Note that the
|
|
* authorization system may allow others to submit to the collection, so
|
|
* this is not necessarily a definitive list of potential submitters.
|
|
* <P>
|
|
* The default group of submitters for collection 100 is the one called
|
|
* <code>collection_100_submit</code>.
|
|
*
|
|
* @return the default group of submitters, or <code>null</code> if there
|
|
* is no default group.
|
|
*/
|
|
public Group getSubmitters()
|
|
{
|
|
return submitters;
|
|
}
|
|
|
|
/**
|
|
* Create a default administrators group if one does not already exist.
|
|
* Returns either the newly created group or the previously existing one.
|
|
* Note that other groups may also be administrators.
|
|
*
|
|
* @return the default group of editors associated with this collection
|
|
* @throws SQLException
|
|
* @throws AuthorizeException
|
|
*/
|
|
public Group createAdministrators() throws SQLException, AuthorizeException
|
|
{
|
|
// Check authorisation - Must be an Admin to create more Admins
|
|
AuthorizeUtil.authorizeManageAdminGroup(ourContext, this);
|
|
|
|
if (admins == null)
|
|
{
|
|
//turn off authorization so that Community Admins can create Collection Admins
|
|
ourContext.turnOffAuthorisationSystem();
|
|
admins = Group.create(ourContext);
|
|
ourContext.restoreAuthSystemState();
|
|
|
|
admins.setName("COLLECTION_" + getID() + "_ADMIN");
|
|
admins.update();
|
|
}
|
|
|
|
AuthorizeManager.addPolicy(ourContext, this,
|
|
Constants.ADMIN, admins);
|
|
|
|
// register this as the admin group
|
|
collectionRow.setColumn("admin", admins.getID());
|
|
|
|
modified = true;
|
|
return admins;
|
|
}
|
|
|
|
/**
|
|
* Remove the administrators group, if no group has already been created
|
|
* then return without error. This will merely dereference the current
|
|
* administrators group from the collection so that it may be deleted
|
|
* without violating database constraints.
|
|
*/
|
|
public void removeAdministrators() throws SQLException, AuthorizeException
|
|
{
|
|
// Check authorisation - Must be an Admin of the parent community to delete Admin Group
|
|
AuthorizeUtil.authorizeRemoveAdminGroup(ourContext, this);
|
|
|
|
// just return if there is no administrative group.
|
|
if (admins == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Remove the link to the collection table.
|
|
collectionRow.setColumnNull("admin");
|
|
admins = null;
|
|
|
|
modified = true;
|
|
}
|
|
|
|
/**
|
|
* Get the default group of administrators, if there is one. Note that the
|
|
* authorization system may allow others to be administrators for the
|
|
* collection.
|
|
* <P>
|
|
* The default group of administrators for collection 100 is the one called
|
|
* <code>collection_100_admin</code>.
|
|
*
|
|
* @return group of administrators, or <code>null</code> if there is no
|
|
* default group.
|
|
*/
|
|
public Group getAdministrators()
|
|
{
|
|
return admins;
|
|
}
|
|
|
|
/**
|
|
* Get the license that users must grant before submitting to this
|
|
* collection. If the collection does not have a specific license, the
|
|
* site-wide default is returned.
|
|
*
|
|
* @return the license for this collection
|
|
*/
|
|
public String getLicense()
|
|
{
|
|
String license = getMetadata("license");
|
|
|
|
if (license == null || license.trim().equals(""))
|
|
{
|
|
// Fallback to site-wide default
|
|
license = LicenseManager.getDefaultSubmissionLicense();
|
|
}
|
|
|
|
return license;
|
|
}
|
|
|
|
/**
|
|
* Get the license that users must grant before submitting to this
|
|
* collection.
|
|
*
|
|
* @return the license for this collection
|
|
*/
|
|
public String getLicenseCollection()
|
|
{
|
|
return getMetadata("license");
|
|
}
|
|
|
|
/**
|
|
* Find out if the collection has a custom license
|
|
*
|
|
* @return <code>true</code> if the collection has a custom license
|
|
*/
|
|
public boolean hasCustomLicense()
|
|
{
|
|
String license = getMetadata("license");
|
|
|
|
return !( license == null || license.trim().equals("") );
|
|
}
|
|
|
|
/**
|
|
* Set the license for this collection. Passing in <code>null</code> means
|
|
* that the site-wide default will be used.
|
|
*
|
|
* @param license
|
|
* the license, or <code>null</code>
|
|
*/
|
|
public void setLicense(String license) {
|
|
setMetadata("license",license);
|
|
}
|
|
|
|
/**
|
|
* Get the template item for this collection. <code>null</code> is
|
|
* returned if the collection does not have a template. Submission
|
|
* mechanisms may copy this template to provide a convenient starting point
|
|
* for a submission.
|
|
*
|
|
* @return the item template, or <code>null</code>
|
|
*/
|
|
public Item getTemplateItem() throws SQLException
|
|
{
|
|
return template;
|
|
}
|
|
|
|
/**
|
|
* Create an empty template item for this collection. If one already exists,
|
|
* no action is taken. Caution: Make sure you call <code>update</code> on
|
|
* the collection after doing this, or the item will have been created but
|
|
* the collection record will not refer to it.
|
|
*
|
|
* @throws SQLException
|
|
* @throws AuthorizeException
|
|
*/
|
|
public void createTemplateItem() throws SQLException, AuthorizeException
|
|
{
|
|
// Check authorisation
|
|
AuthorizeUtil.authorizeManageTemplateItem(ourContext, this);
|
|
|
|
if (template == null)
|
|
{
|
|
template = Item.create(ourContext);
|
|
collectionRow.setColumn("template_item_id", template.getID());
|
|
|
|
log.info(LogManager.getHeader(ourContext, "create_template_item",
|
|
"collection_id=" + getID() + ",template_item_id="
|
|
+ template.getID()));
|
|
}
|
|
modified = true;
|
|
}
|
|
|
|
/**
|
|
* Remove the template item for this collection, if there is one. Note that
|
|
* since this has to remove the old template item ID from the collection
|
|
* record in the database, the collection record will be changed, including
|
|
* any other changes made; in other words, this method does an
|
|
* <code>update</code>.
|
|
*
|
|
* @throws SQLException
|
|
* @throws AuthorizeException
|
|
* @throws IOException
|
|
*/
|
|
public void removeTemplateItem() throws SQLException, AuthorizeException,
|
|
IOException
|
|
{
|
|
// Check authorisation
|
|
AuthorizeUtil.authorizeManageTemplateItem(ourContext, this);
|
|
|
|
collectionRow.setColumnNull("template_item_id");
|
|
DatabaseManager.update(ourContext, collectionRow);
|
|
|
|
if (template != null)
|
|
{
|
|
log.info(LogManager.getHeader(ourContext, "remove_template_item",
|
|
"collection_id=" + getID() + ",template_item_id="
|
|
+ template.getID()));
|
|
// temporarily turn off auth system, we have already checked the permission on the top of the method
|
|
// check it again will fail because we have already broken the relation between the collection and the item
|
|
ourContext.turnOffAuthorisationSystem();
|
|
template.delete();
|
|
ourContext.restoreAuthSystemState();
|
|
template = null;
|
|
}
|
|
|
|
ourContext.addEvent(new Event(Event.MODIFY, Constants.COLLECTION,
|
|
getID(), "remove_template_item", getIdentifiers(ourContext)));
|
|
}
|
|
|
|
/**
|
|
* Add an item to the collection. This simply adds a relationship between
|
|
* the item and the collection - it does nothing like set an issue date,
|
|
* remove a personal workspace item etc. This has instant effect;
|
|
* <code>update</code> need not be called.
|
|
*
|
|
* @param item
|
|
* item to add
|
|
* @throws SQLException
|
|
* @throws AuthorizeException
|
|
*/
|
|
public void addItem(Item item) throws SQLException, AuthorizeException
|
|
{
|
|
// Check authorisation
|
|
AuthorizeManager.authorizeAction(ourContext, this, Constants.ADD);
|
|
|
|
log.info(LogManager.getHeader(ourContext, "add_item", "collection_id="
|
|
+ getID() + ",item_id=" + item.getID()));
|
|
|
|
// Create mapping
|
|
TableRow row = DatabaseManager.row("collection2item");
|
|
|
|
row.setColumn("collection_id", getID());
|
|
row.setColumn("item_id", item.getID());
|
|
|
|
DatabaseManager.insert(ourContext, row);
|
|
|
|
ourContext.addEvent(new Event(Event.ADD, Constants.COLLECTION, getID(),
|
|
Constants.ITEM, item.getID(), item.getHandle(),
|
|
getIdentifiers(ourContext)));
|
|
}
|
|
|
|
/**
|
|
* Remove an item. If the item is then orphaned, it is deleted.
|
|
*
|
|
* @param item
|
|
* item to remove
|
|
* @throws SQLException
|
|
* @throws AuthorizeException
|
|
* @throws IOException
|
|
*/
|
|
public void removeItem(Item item) throws SQLException, AuthorizeException,
|
|
IOException
|
|
{
|
|
// Check authorisation
|
|
AuthorizeManager.authorizeAction(ourContext, this, Constants.REMOVE);
|
|
|
|
// will the item be an orphan? is it in other collections?
|
|
TableRow row = DatabaseManager.querySingle(ourContext,
|
|
"SELECT COUNT(DISTINCT collection_id) AS num FROM collection2item WHERE item_id= ? ",
|
|
item.getID());
|
|
boolean orphan = (row.getLongColumn("num") == 1);
|
|
|
|
log.info(LogManager.getHeader(ourContext, "remove_item",
|
|
"collection_id=" + getID() + ",item_id=" + item.getID()));
|
|
|
|
// First, remove its association with this collection
|
|
DatabaseManager.updateQuery(ourContext,
|
|
"DELETE FROM collection2item WHERE collection_id= ? "+
|
|
"AND item_id= ? ",
|
|
getID(), item.getID());
|
|
|
|
// Then, if it is an orphaned Item, delete it
|
|
if (orphan)
|
|
{
|
|
item.delete();
|
|
}
|
|
|
|
ourContext.addEvent(new Event(Event.REMOVE, Constants.COLLECTION,
|
|
getID(), Constants.ITEM, item.getID(), item.getHandle(),
|
|
getIdentifiers(ourContext)));
|
|
}
|
|
|
|
/**
|
|
* Update the collection metadata (including logo and workflow groups) to
|
|
* the database. Inserts if this is a new collection.
|
|
*
|
|
* @throws SQLException
|
|
* @throws IOException
|
|
* @throws AuthorizeException
|
|
*/
|
|
@Override
|
|
public void update() throws SQLException, AuthorizeException
|
|
{
|
|
// Check authorisation
|
|
canEdit(true);
|
|
|
|
log.info(LogManager.getHeader(ourContext, "update_collection",
|
|
"collection_id=" + getID()));
|
|
|
|
DatabaseManager.update(ourContext, collectionRow);
|
|
|
|
if (modified)
|
|
{
|
|
ourContext.addEvent(new Event(Event.MODIFY, Constants.COLLECTION,
|
|
getID(), null, getIdentifiers(ourContext)));
|
|
modified = false;
|
|
}
|
|
if (modifiedMetadata)
|
|
{
|
|
updateMetadata();
|
|
clearDetails();
|
|
}
|
|
}
|
|
|
|
public boolean canEditBoolean() throws java.sql.SQLException
|
|
{
|
|
return canEditBoolean(true);
|
|
}
|
|
|
|
public boolean canEditBoolean(boolean useInheritance) throws java.sql.SQLException
|
|
{
|
|
try
|
|
{
|
|
canEdit(useInheritance);
|
|
|
|
return true;
|
|
}
|
|
catch (AuthorizeException e)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public void canEdit() throws AuthorizeException, SQLException
|
|
{
|
|
canEdit(true);
|
|
}
|
|
|
|
public void canEdit(boolean useInheritance) throws AuthorizeException, SQLException
|
|
{
|
|
Community[] parents = getCommunities();
|
|
|
|
for (int i = 0; i < parents.length; i++)
|
|
{
|
|
if (AuthorizeManager.authorizeActionBoolean(ourContext, parents[i],
|
|
Constants.WRITE, useInheritance))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (AuthorizeManager.authorizeActionBoolean(ourContext, parents[i],
|
|
Constants.ADD, useInheritance))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
AuthorizeManager.authorizeAction(ourContext, this, Constants.WRITE, useInheritance);
|
|
}
|
|
|
|
/**
|
|
* Delete the collection, including the metadata and logo. Items that are
|
|
* then orphans are deleted. Groups associated with this collection
|
|
* (workflow participants and submitters) are NOT deleted.
|
|
*
|
|
* @throws SQLException
|
|
* @throws AuthorizeException
|
|
* @throws IOException
|
|
*/
|
|
void delete() throws SQLException, AuthorizeException, IOException
|
|
{
|
|
log.info(LogManager.getHeader(ourContext, "delete_collection",
|
|
"collection_id=" + getID()));
|
|
|
|
ourContext.addEvent(new Event(Event.DELETE, Constants.COLLECTION,
|
|
getID(), getHandle(), getIdentifiers(ourContext)));
|
|
|
|
// remove subscriptions - hmm, should this be in Subscription.java?
|
|
DatabaseManager.updateQuery(ourContext,
|
|
"DELETE FROM subscription WHERE collection_id= ? ",
|
|
getID());
|
|
|
|
// Remove Template Item
|
|
removeTemplateItem();
|
|
|
|
// Remove items
|
|
ItemIterator items = getAllItems();
|
|
|
|
try
|
|
{
|
|
while (items.hasNext())
|
|
{
|
|
Item item = items.next();
|
|
IndexBrowse ib = new IndexBrowse(ourContext);
|
|
|
|
if (item.isOwningCollection(this))
|
|
{
|
|
// the collection to be deleted is the owning collection, thus remove
|
|
// the item from all collections it belongs to
|
|
Collection[] collections = item.getCollections();
|
|
for (int i=0; i< collections.length; i++)
|
|
{
|
|
//notify Browse of removing item.
|
|
ib.itemRemoved(item);
|
|
// Browse.itemRemoved(ourContext, itemId);
|
|
collections[i].removeItem(item);
|
|
}
|
|
|
|
}
|
|
// the item was only mapped to this collection, so just remove it
|
|
else
|
|
{
|
|
//notify Browse of removing item mapping.
|
|
ib.indexItem(item);
|
|
// Browse.itemChanged(ourContext, item);
|
|
removeItem(item);
|
|
}
|
|
}
|
|
}
|
|
catch (BrowseException e)
|
|
{
|
|
log.error("caught exception: ", e);
|
|
throw new IOException(e.getMessage(), e);
|
|
}
|
|
finally
|
|
{
|
|
if (items != null)
|
|
{
|
|
items.close();
|
|
}
|
|
}
|
|
|
|
// Delete bitstream logo
|
|
setLogo(null);
|
|
|
|
// Remove all authorization policies
|
|
AuthorizeManager.removeAllPolicies(ourContext, this);
|
|
|
|
if(ConfigurationManager.getProperty("workflow","workflow.framework").equals("xmlworkflow")){
|
|
// Remove any xml_WorkflowItems
|
|
XmlWorkflowItem[] xmlWfarray = XmlWorkflowItem
|
|
.findByCollection(ourContext, this);
|
|
|
|
for (XmlWorkflowItem aXmlWfarray : xmlWfarray) {
|
|
// remove the workflowitem first, then the item
|
|
Item myItem = aXmlWfarray.getItem();
|
|
aXmlWfarray.deleteWrapper();
|
|
myItem.delete();
|
|
}
|
|
}else{
|
|
// Remove any WorkflowItems
|
|
WorkflowItem[] wfarray = WorkflowItem
|
|
.findByCollection(ourContext, this);
|
|
|
|
for (WorkflowItem aWfarray : wfarray) {
|
|
// remove the workflowitem first, then the item
|
|
Item myItem = aWfarray.getItem();
|
|
aWfarray.deleteWrapper();
|
|
myItem.delete();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Remove any WorkspaceItems
|
|
WorkspaceItem[] wsarray = WorkspaceItem.findByCollection(ourContext,
|
|
this);
|
|
|
|
for (WorkspaceItem aWsarray : wsarray) {
|
|
aWsarray.deleteAll();
|
|
}
|
|
|
|
// get rid of the content count cache if it exists
|
|
try
|
|
{
|
|
ItemCounter ic = new ItemCounter(ourContext);
|
|
ic.remove(this);
|
|
}
|
|
catch (ItemCountException e)
|
|
{
|
|
// FIXME: upside down exception handling due to lack of good
|
|
// exception framework
|
|
throw new IllegalStateException(e.getMessage(), e);
|
|
}
|
|
|
|
// Remove any Handle
|
|
HandleManager.unbindHandle(ourContext, this);
|
|
|
|
if(ConfigurationManager.getProperty("workflow","workflow.framework").equals("xmlworkflow")){
|
|
// delete all CollectionRoles for this Collection
|
|
for (CollectionRole collectionRole : CollectionRole.findByCollection(ourContext, this.getID())) {
|
|
collectionRole.delete();
|
|
}
|
|
}
|
|
|
|
// Remove from cache
|
|
ourContext.removeCached(this, getID());
|
|
|
|
// Delete collection row
|
|
DatabaseManager.delete(ourContext, collectionRow);
|
|
|
|
// Remove any workflow groups - must happen after deleting collection
|
|
Group g = null;
|
|
|
|
g = getWorkflowGroup(1);
|
|
|
|
if (g != null)
|
|
{
|
|
g.delete();
|
|
}
|
|
|
|
g = getWorkflowGroup(2);
|
|
|
|
if (g != null)
|
|
{
|
|
g.delete();
|
|
}
|
|
|
|
g = getWorkflowGroup(3);
|
|
|
|
if (g != null)
|
|
{
|
|
g.delete();
|
|
}
|
|
|
|
// Remove default administrators group
|
|
g = getAdministrators();
|
|
|
|
if (g != null)
|
|
{
|
|
g.delete();
|
|
}
|
|
|
|
// Remove default submitters group
|
|
g = getSubmitters();
|
|
|
|
if (g != null)
|
|
{
|
|
g.delete();
|
|
}
|
|
|
|
removeMetadataFromDatabase();
|
|
}
|
|
|
|
/**
|
|
* Get the communities this collection appears in
|
|
*
|
|
* @return array of <code>Community</code> objects
|
|
* @throws SQLException
|
|
*/
|
|
public Community[] getCommunities() throws SQLException
|
|
{
|
|
// Get the bundle table rows
|
|
TableRowIterator tri = DatabaseManager.queryTable(ourContext,"community",
|
|
"SELECT community.* FROM community, community2collection WHERE " +
|
|
"community.community_id=community2collection.community_id " +
|
|
"AND community2collection.collection_id= ? ",
|
|
getID());
|
|
|
|
// Build a list of Community objects
|
|
List<Community> communities = new ArrayList<Community>();
|
|
|
|
try
|
|
{
|
|
while (tri.hasNext())
|
|
{
|
|
TableRow row = tri.next();
|
|
|
|
// First check the cache
|
|
Community owner = (Community) ourContext.fromCache(Community.class,
|
|
row.getIntColumn("community_id"));
|
|
|
|
if (owner == null)
|
|
{
|
|
owner = new Community(ourContext, row);
|
|
}
|
|
|
|
communities.add(owner);
|
|
|
|
// now add any parent communities
|
|
Community[] parents = owner.getAllParents();
|
|
communities.addAll(Arrays.asList(parents));
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
// close the TableRowIterator to free up resources
|
|
if (tri != null)
|
|
{
|
|
tri.close();
|
|
}
|
|
}
|
|
|
|
Community[] communityArray = new Community[communities.size()];
|
|
communityArray = (Community[]) communities.toArray(communityArray);
|
|
|
|
return communityArray;
|
|
}
|
|
|
|
/**
|
|
* Return <code>true</code> if <code>other</code> is the same Collection
|
|
* as this object, <code>false</code> otherwise
|
|
*
|
|
* @param other
|
|
* object to compare to
|
|
*
|
|
* @return <code>true</code> if object passed in represents the same
|
|
* collection as this object
|
|
*/
|
|
@Override
|
|
public boolean equals(Object other)
|
|
{
|
|
if (other == null)
|
|
{
|
|
return false;
|
|
}
|
|
if (getClass() != other.getClass())
|
|
{
|
|
return false;
|
|
}
|
|
final Collection otherCollection = (Collection) other;
|
|
if (this.getID() != otherCollection.getID())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode()
|
|
{
|
|
int hash = 7;
|
|
hash = 89 * hash + (this.collectionRow != null ? this.collectionRow.hashCode() : 0);
|
|
return hash;
|
|
}
|
|
|
|
|
|
/**
|
|
* Utility method for reading in a group from a group ID in a column. If the
|
|
* column is null, null is returned.
|
|
*
|
|
* @param col
|
|
* the column name to read
|
|
* @return the group referred to by that column, or null
|
|
* @throws SQLException
|
|
*/
|
|
private Group groupFromColumn(String col) throws SQLException
|
|
{
|
|
if (collectionRow.isColumnNull(col))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return Group.find(ourContext, collectionRow.getIntColumn(col));
|
|
}
|
|
|
|
/**
|
|
* return type found in Constants
|
|
*
|
|
* @return int Constants.COLLECTION
|
|
*/
|
|
public int getType()
|
|
{
|
|
return Constants.COLLECTION;
|
|
}
|
|
|
|
/**
|
|
* return an array of collections that user has a given permission on
|
|
* (useful for trimming 'select to collection' list) or figuring out which
|
|
* collections a person is an editor for.
|
|
*
|
|
* @param context
|
|
* @param comm
|
|
* (optional) restrict search to a community, else null
|
|
* @param actionID
|
|
* of the action
|
|
*
|
|
* @return Collection [] of collections with matching permissions
|
|
* @throws SQLException
|
|
*/
|
|
public static Collection[] findAuthorized(Context context, Community comm,
|
|
int actionID) throws java.sql.SQLException
|
|
{
|
|
List<Collection> myResults = new ArrayList<Collection>();
|
|
|
|
Collection[] myCollections = null;
|
|
|
|
if (comm != null)
|
|
{
|
|
myCollections = comm.getCollections();
|
|
}
|
|
else
|
|
{
|
|
myCollections = Collection.findAll(context);
|
|
}
|
|
|
|
// now build a list of collections you have authorization for
|
|
for (int i = 0; i < myCollections.length; i++)
|
|
{
|
|
if (AuthorizeManager.authorizeActionBoolean(context,
|
|
myCollections[i], actionID))
|
|
{
|
|
myResults.add(myCollections[i]);
|
|
}
|
|
}
|
|
|
|
myCollections = new Collection[myResults.size()];
|
|
myCollections = (Collection[]) myResults.toArray(myCollections);
|
|
|
|
return myCollections;
|
|
}
|
|
|
|
public static Collection[] findAuthorizedOptimized(Context context, int actionID) throws java.sql.SQLException
|
|
{
|
|
if(! ConfigurationManager.getBooleanProperty("org.dspace.content.Collection.findAuthorizedPerformanceOptimize", true)) {
|
|
// Fallback to legacy query if config says so. The rationale could be that a site found a bug.
|
|
return findAuthorized(context, null, actionID);
|
|
}
|
|
|
|
List<Collection> myResults = new ArrayList<Collection>();
|
|
|
|
if(AuthorizeManager.isAdmin(context))
|
|
{
|
|
return findAll(context);
|
|
}
|
|
|
|
//Check eperson->policy
|
|
Collection[] directToCollection = findDirectMapped(context, actionID);
|
|
for (int i = 0; i< directToCollection.length; i++)
|
|
{
|
|
if(!myResults.contains(directToCollection[i]))
|
|
{
|
|
myResults.add(directToCollection[i]);
|
|
}
|
|
}
|
|
|
|
//Check eperson->groups->policy
|
|
Collection[] groupToCollection = findGroupMapped(context, actionID);
|
|
|
|
for (int i = 0; i< groupToCollection.length; i++)
|
|
{
|
|
if(!myResults.contains(groupToCollection[i]))
|
|
{
|
|
myResults.add(groupToCollection[i]);
|
|
}
|
|
}
|
|
|
|
//Check eperson->groups->groups->policy->collection
|
|
//i.e. Malcolm Litchfield is a member of OSU_Press_Embargo,
|
|
// which is a member of: COLLECTION_24_ADMIN, COLLECTION_24_SUBMIT
|
|
Collection[] group2GroupToCollection = findGroup2GroupMapped(context, actionID);
|
|
|
|
for (int i = 0; i< group2GroupToCollection.length; i++)
|
|
{
|
|
if(!myResults.contains(group2GroupToCollection[i]))
|
|
{
|
|
myResults.add(group2GroupToCollection[i]);
|
|
}
|
|
}
|
|
|
|
//TODO Check eperson->groups->groups->policy->community
|
|
|
|
|
|
//TODO Check eperson->groups->policy->community
|
|
// i.e. Typical Community Admin -- name.# > COMMUNITY_10_ADMIN > Ohio State University Press
|
|
|
|
//Check eperson->comm-admin
|
|
Collection[] group2commCollections = findGroup2CommunityMapped(context);
|
|
for (int i = 0; i< group2commCollections.length; i++)
|
|
{
|
|
if(!myResults.contains(group2commCollections[i]))
|
|
{
|
|
myResults.add(group2commCollections[i]);
|
|
}
|
|
}
|
|
|
|
|
|
// Return the collections, sorted alphabetically
|
|
Collections.sort(myResults, new CollectionComparator());
|
|
|
|
Collection[] myCollections = new Collection[myResults.size()];
|
|
myCollections = (Collection[]) myResults.toArray(myCollections);
|
|
|
|
return myCollections;
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
* counts items in this collection
|
|
*
|
|
* @return total items
|
|
*/
|
|
public int countItems()
|
|
throws SQLException
|
|
{
|
|
int itemcount = 0;
|
|
PreparedStatement statement = null;
|
|
ResultSet rs = null;
|
|
|
|
try
|
|
{
|
|
String query = "SELECT count(*) FROM collection2item, item WHERE "
|
|
+ "collection2item.collection_id = ? "
|
|
+ "AND collection2item.item_id = item.item_id "
|
|
+ "AND in_archive ='1' AND item.withdrawn='0' ";
|
|
|
|
statement = ourContext.getDBConnection().prepareStatement(query);
|
|
statement.setInt(1,getID());
|
|
|
|
rs = statement.executeQuery();
|
|
if (rs != null)
|
|
{
|
|
rs.next();
|
|
itemcount = rs.getInt(1);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
if (rs != null)
|
|
{
|
|
try { rs.close(); } catch (SQLException sqle) { }
|
|
}
|
|
|
|
if (statement != null)
|
|
{
|
|
try { statement.close(); } catch (SQLException sqle) { }
|
|
}
|
|
}
|
|
|
|
return itemcount;
|
|
}
|
|
|
|
public DSpaceObject getAdminObject(int action) throws SQLException
|
|
{
|
|
DSpaceObject adminObject = null;
|
|
Community community = null;
|
|
Community[] communities = getCommunities();
|
|
if (communities != null && communities.length > 0)
|
|
{
|
|
community = communities[0];
|
|
}
|
|
|
|
switch (action)
|
|
{
|
|
case Constants.REMOVE:
|
|
if (AuthorizeConfiguration.canCollectionAdminPerformItemDeletion())
|
|
{
|
|
adminObject = this;
|
|
}
|
|
else if (AuthorizeConfiguration.canCommunityAdminPerformItemDeletion())
|
|
{
|
|
adminObject = community;
|
|
}
|
|
break;
|
|
|
|
case Constants.DELETE:
|
|
if (AuthorizeConfiguration.canCommunityAdminPerformSubelementDeletion())
|
|
{
|
|
adminObject = community;
|
|
}
|
|
break;
|
|
default:
|
|
adminObject = this;
|
|
break;
|
|
}
|
|
return adminObject;
|
|
}
|
|
|
|
@Override
|
|
public DSpaceObject getParentObject() throws SQLException
|
|
{
|
|
Community[] communities = this.getCommunities();
|
|
if (communities != null && (communities.length > 0 && communities[0] != null))
|
|
{
|
|
return communities[0];
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void updateLastModified()
|
|
{
|
|
//Also fire a modified event since the collection HAS been modified
|
|
ourContext.addEvent(new Event(Event.MODIFY, Constants.COLLECTION,
|
|
getID(), null, getIdentifiers(ourContext)));
|
|
}
|
|
|
|
//TODO replace hard-coded action_id's with constants...
|
|
public static Collection[] findDirectMapped(Context context, int actionID) throws java.sql.SQLException
|
|
{
|
|
//eperson_id -> resourcepolicy.eperson_id
|
|
TableRowIterator tri = DatabaseManager.query(context,
|
|
"SELECT * FROM collection, resourcepolicy, eperson " +
|
|
"WHERE resourcepolicy.resource_id = collection.collection_id AND " +
|
|
"eperson.eperson_id = resourcepolicy.eperson_id AND "+
|
|
"resourcepolicy.resource_type_id = 3 AND "+
|
|
"( resourcepolicy.action_id = 3 OR resourcepolicy.action_id = 11 ) AND "+
|
|
"eperson.eperson_id = ?", context.getCurrentUser().getID());
|
|
return produceCollectionsFromQuery(context, tri);
|
|
}
|
|
|
|
public static Collection[] findGroupMapped(Context context, int actionID) throws java.sql.SQLException
|
|
{
|
|
//eperson_id -> resourcepolicy.eperson_id
|
|
TableRowIterator tri = DatabaseManager.query(context,
|
|
"SELECT * FROM collection, resourcepolicy, eperson, epersongroup2eperson " +
|
|
"WHERE resourcepolicy.resource_id = collection.collection_id AND "+
|
|
"eperson.eperson_id = epersongroup2eperson.eperson_id AND "+
|
|
"epersongroup2eperson.eperson_group_id = resourcepolicy.epersongroup_id AND "+
|
|
"resourcepolicy.resource_type_id = 3 AND "+
|
|
"( resourcepolicy.action_id = 3 OR resourcepolicy.action_id = 11 ) AND "+
|
|
"eperson.eperson_id = ?", context.getCurrentUser().getID());
|
|
return produceCollectionsFromQuery(context, tri);
|
|
}
|
|
|
|
public static Collection[] findGroup2GroupMapped(Context context, int actionID) throws SQLException {
|
|
TableRowIterator tri = DatabaseManager.query(context,
|
|
"SELECT \n" +
|
|
" * \n" +
|
|
"FROM \n" +
|
|
" public.eperson, \n" +
|
|
" public.epersongroup2eperson, \n" +
|
|
" public.epersongroup, \n" +
|
|
" public.group2group, \n" +
|
|
" public.resourcepolicy rp_parent, \n" +
|
|
" public.collection\n" +
|
|
"WHERE \n" +
|
|
" epersongroup2eperson.eperson_id = eperson.eperson_id AND\n" +
|
|
" epersongroup.eperson_group_id = epersongroup2eperson.eperson_group_id AND\n" +
|
|
" group2group.child_id = epersongroup.eperson_group_id AND\n" +
|
|
" rp_parent.epersongroup_id = group2group.parent_id AND\n" +
|
|
" collection.collection_id = rp_parent.resource_id AND\n" +
|
|
" eperson.eperson_id = ? AND \n" +
|
|
" (rp_parent.action_id = 3 OR \n" +
|
|
" rp_parent.action_id = 11 \n" +
|
|
" ) AND rp_parent.resource_type_id = 3;", context.getCurrentUser().getID());
|
|
return produceCollectionsFromQuery(context, tri);
|
|
}
|
|
|
|
public static Collection[] findGroup2CommunityMapped(Context context) throws SQLException {
|
|
TableRowIterator tri = DatabaseManager.query(context,
|
|
"SELECT \n" +
|
|
" * \n" +
|
|
"FROM \n" +
|
|
" public.eperson, \n" +
|
|
" public.epersongroup2eperson, \n" +
|
|
" public.epersongroup, \n" +
|
|
" public.community, \n" +
|
|
" public.resourcepolicy\n" +
|
|
"WHERE \n" +
|
|
" epersongroup2eperson.eperson_id = eperson.eperson_id AND\n" +
|
|
" epersongroup.eperson_group_id = epersongroup2eperson.eperson_group_id AND\n" +
|
|
" resourcepolicy.epersongroup_id = epersongroup.eperson_group_id AND\n" +
|
|
" resourcepolicy.resource_id = community.community_id AND\n" +
|
|
" ( resourcepolicy.action_id = 3 OR \n" +
|
|
" resourcepolicy.action_id = 11) AND \n" +
|
|
" resourcepolicy.resource_type_id = 4 AND eperson.eperson_id = ?", context.getCurrentUser().getID());
|
|
|
|
return produceCollectionsFromCommunityQuery(context, tri);
|
|
}
|
|
|
|
public static class CollectionComparator implements Comparator<Collection> {
|
|
@Override
|
|
public int compare(Collection collection1, Collection collection2) {
|
|
return collection1.getName().compareTo(collection2.getName());
|
|
}
|
|
}
|
|
|
|
public static Collection[] produceCollectionsFromQuery(Context context, TableRowIterator tri) throws SQLException {
|
|
List<Collection> collections = new ArrayList<Collection>();
|
|
|
|
while(tri.hasNext()) {
|
|
TableRow row = tri.next();
|
|
Collection collection = Collection.find(context, row.getIntColumn("collection_id"));
|
|
collections.add(collection);
|
|
}
|
|
|
|
return collections.toArray(new Collection[0]);
|
|
}
|
|
|
|
public static Collection[] produceCollectionsFromCommunityQuery(Context context, TableRowIterator tri) throws SQLException {
|
|
List<Collection> collections = new ArrayList<Collection>();
|
|
|
|
while(tri.hasNext()) {
|
|
TableRow commRow = tri.next();
|
|
Community community = Community.find(context, commRow.getIntColumn("community_id"));
|
|
|
|
Collection[] comCollections = community.getCollections();
|
|
for(Collection collection : comCollections) {
|
|
collections.add(collection);
|
|
}
|
|
|
|
//ugh, handle that communities has subcommunities...
|
|
//TODO community.getAllCollections();
|
|
|
|
}
|
|
return collections.toArray(new Collection[0]);
|
|
}
|
|
}
|