Merge pull request #43 from atmire/dspace3-embargo

[DS-895] Advanced Embargo Project
This commit is contained in:
Mark Diggory
2012-08-16 02:20:32 -07:00
116 changed files with 10913 additions and 665 deletions

View File

@@ -7,6 +7,7 @@
*/
package org.dspace.app.util;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -30,7 +31,7 @@ import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
* @author Robert Tansley
* @version $Revision$
*/
public class SubmissionInfo
public class SubmissionInfo extends HashMap
{
/** log4j logger */
private static Logger log = Logger.getLogger(SubmissionInfo.class);

View File

@@ -8,15 +8,12 @@
package org.dspace.authorize;
import java.sql.SQLException;
import java.util.Date;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.content.ItemIterator;
import org.dspace.content.*;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.eperson.Group;
@@ -24,7 +21,7 @@ import org.dspace.eperson.Group;
/**
* Was Hack/Tool to set policies for items, bundles, and bitstreams. Now has
* helpful method, setPolicies();
*
*
* @author dstuve
* @version $Revision$
*/
@@ -38,7 +35,7 @@ public class PolicySet
if (argv.length < 6)
{
System.out
.println("Args: containerType containerID contentType actionID groupID command [filter]");
.println("Args: containerType containerID contentType actionID groupID command [filter]");
System.out.println("container=COLLECTION command = ADD|REPLACE");
return;
@@ -55,7 +52,7 @@ public class PolicySet
String filter = null;
if ( argv.length == 7 )
{
filter = argv[6];
filter = argv[6];
}
if (command.equals("REPLACE"))
@@ -77,11 +74,11 @@ public class PolicySet
c.complete();
System.exit(0);
}
/**
* Useful policy wildcard tool. Can set entire collections' contents'
* policies
*
*
* @param c
* current context
* @param containerType
@@ -106,18 +103,44 @@ public class PolicySet
* if current user is not authorized to change these policies
*/
public static void setPolicies(Context c, int containerType,
int containerID, int contentType, int actionID, int groupID,
boolean isReplace, boolean clearOnly) throws SQLException,
int containerID, int contentType, int actionID, int groupID,
boolean isReplace, boolean clearOnly) throws SQLException,
AuthorizeException
{
setPoliciesFilter(c, containerType,containerID, contentType, actionID, groupID, isReplace, clearOnly, null, null, null, null, null);
}
/**
*
* @param c
* @param containerType
* @param containerID
* @param contentType
* @param actionID
* @param groupID
* @param isReplace
* @param clearOnly
* @param name
* @param description
* @param startDate
* @param endDate
* @throws SQLException
* @throws AuthorizeException
*/
public static void setPolicies(Context c, int containerType,
int containerID, int contentType, int actionID, int groupID,
boolean isReplace, boolean clearOnly,
String name, String description, Date startDate, Date endDate) throws SQLException, AuthorizeException
{
setPoliciesFilter(c, containerType, containerID, contentType,
actionID, groupID, isReplace, clearOnly, null);
actionID, groupID, isReplace, clearOnly, null, name, description, startDate, endDate);
}
/**
* Useful policy wildcard tool. Can set entire collections' contents'
* policies
*
*
* @param c
* current context
* @param containerType
@@ -144,9 +167,49 @@ public class PolicySet
* if current user is not authorized to change these policies
*/
public static void setPoliciesFilter(Context c, int containerType,
int containerID, int contentType, int actionID, int groupID,
boolean isReplace, boolean clearOnly, String filter) throws SQLException,
AuthorizeException
int containerID, int contentType, int actionID, int groupID,
boolean isReplace, boolean clearOnly, String filter) throws SQLException,AuthorizeException
{
setPoliciesFilter(c, containerType,containerID, contentType, actionID, groupID, isReplace, clearOnly, filter, null, null, null, null);
}
/**
* Useful policy wildcard tool. Can set entire collections' contents'
* policies
*
* @param c
* current context
* @param containerType
* type, Constants.ITEM or Constants.COLLECTION
* @param containerID
* ID of container (DB primary key)
* @param contentType
* type (BUNDLE, ITEM, or BITSTREAM)
* @param actionID
* action ID
* @param groupID
* group ID (database key)
* @param isReplace
* if <code>true</code>, existing policies are removed first,
* otherwise add to existing policies
* @param clearOnly
* if <code>true</code>, just delete policies for matching
* objects
* @param filter
* if non-null, only process bitstreams whose names contain filter
* @param name
* @param description
* @param startDate
* @param endDate
* @throws SQLException
* if database problem
* @throws AuthorizeException
* if current user is not authorized to change these policies
*/
public static void setPoliciesFilter(Context c, int containerType,
int containerID, int contentType, int actionID, int groupID,
boolean isReplace, boolean clearOnly, String filter,
String name, String description, Date startDate, Date endDate) throws SQLException, AuthorizeException
{
if (containerType == Constants.COLLECTION)
{
@@ -171,14 +234,23 @@ public class PolicySet
if (!clearOnly)
{
// now add the policy
ResourcePolicy rp = ResourcePolicy.create(c);
rp.setResource(myitem);
rp.setAction(actionID);
rp.setGroup(group);
// before create a new policy check if an identical policy is already in place
if(!AuthorizeManager.isAnIdenticalPolicyAlreadyInPlace(c, myitem, groupID, actionID, -1)){
// now add the policy
ResourcePolicy rp = ResourcePolicy.create(c);
rp.update();
rp.setResource(myitem);
rp.setAction(actionID);
rp.setGroup(group);
rp.setRpName(name);
rp.setRpDescription(description);
rp.setStartDate(startDate);
rp.setEndDate(endDate);
rp.update();
}
}
}
}
@@ -194,24 +266,32 @@ public class PolicySet
for (int j = 0; j < bundles.length; j++)
{
Bundle t = bundles[j]; // t for target
Bundle bundle = bundles[j]; // t for target
// is this a replace? delete policies first
if (isReplace || clearOnly)
{
AuthorizeManager.removeAllPolicies(c, t);
AuthorizeManager.removeAllPolicies(c, bundle);
}
if (!clearOnly)
{
// now add the policy
ResourcePolicy rp = ResourcePolicy.create(c);
// before create a new policy check if an identical policy is already in place
if(!AuthorizeManager.isAnIdenticalPolicyAlreadyInPlace(c, bundle, groupID, actionID, -1)){
// now add the policy
ResourcePolicy rp = ResourcePolicy.create(c);
rp.setResource(t);
rp.setAction(actionID);
rp.setGroup(group);
rp.setResource(bundle);
rp.setAction(actionID);
rp.setGroup(group);
rp.update();
rp.setRpName(name);
rp.setRpDescription(description);
rp.setStartDate(startDate);
rp.setEndDate(endDate);
rp.update();
}
}
}
}
@@ -235,27 +315,35 @@ public class PolicySet
for (int k = 0; k < bitstreams.length; k++)
{
Bitstream t = bitstreams[k]; // t for target
Bitstream bitstream = bitstreams[k]; // t for target
if ( filter == null ||
t.getName().indexOf( filter ) != -1 )
bitstream.getName().indexOf( filter ) != -1 )
{
// is this a replace? delete policies first
if (isReplace || clearOnly)
{
AuthorizeManager.removeAllPolicies(c, t);
AuthorizeManager.removeAllPolicies(c, bitstream);
}
if (!clearOnly)
{
// before create a new policy check if an identical policy is already in place
if(!AuthorizeManager.isAnIdenticalPolicyAlreadyInPlace(c, bitstream, groupID, actionID, -1)){
// now add the policy
ResourcePolicy rp = ResourcePolicy.create(c);
rp.setResource(t);
rp.setResource(bitstream);
rp.setAction(actionID);
rp.setGroup(group);
rp.setRpName(name);
rp.setRpDescription(description);
rp.setStartDate(startDate);
rp.setEndDate(endDate);
rp.update();
}
}
}
}

View File

@@ -8,6 +8,7 @@
package org.dspace.authorize;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import org.apache.log4j.Logger;
@@ -27,6 +28,14 @@ import org.dspace.storage.rdbms.TableRow;
*/
public class ResourcePolicy
{
public static String TYPE_SUBMISSION = "TYPE_SUBMISSION";
public static String TYPE_WORKFLOW = "TYPE_WORKFLOW";
public static String TYPE_CUSTOM= "TYPE_CUSTOM";
public static String TYPE_INHERITED= "TYPE_INHERITED";
/** log4j logger */
private static Logger log = Logger.getLogger(ResourcePolicy.class);
@@ -451,4 +460,26 @@ public class ResourcePolicy
// FIXME: Check authorisation
DatabaseManager.update(myContext, myRow);
}
public String getRpName(){
return myRow.getStringColumn("rpname");
}
public void setRpName(String name){
myRow.setColumn("rpname", name);
}
public String getRpType(){
return myRow.getStringColumn("rptype");
}
public void setRpType(String type){
myRow.setColumn("rptype", type);
}
public String getRpDescription(){
return myRow.getStringColumn("rpdescription");
}
public void setRpDescription(String description){
myRow.setColumn("rpdescription", description);
}
}

View File

@@ -61,6 +61,8 @@ public final class BrowseIndex
/** additional 'internal' tables that are always defined */
private static BrowseIndex itemIndex = new BrowseIndex("bi_item");
private static BrowseIndex withdrawnIndex = new BrowseIndex("bi_withdrawn");
private static BrowseIndex privateIndex = new BrowseIndex("bi_private");
/**
* Ensure no one else can create these
@@ -750,6 +752,12 @@ public final class BrowseIndex
{
return BrowseIndex.withdrawnIndex;
}
public static BrowseIndex getPrivateBrowseIndex()
{
return BrowseIndex.privateIndex;
}
/**
* Take a string representation of a metadata field, and return it as an array.
@@ -790,7 +798,7 @@ public final class BrowseIndex
*/
public boolean isInternalIndex()
{
return (this == itemIndex || this == withdrawnIndex);
return (this == itemIndex || this == withdrawnIndex || this == privateIndex);
}
/**

View File

@@ -286,6 +286,7 @@ public class IndexBrowse
dao.pruneExcess(BrowseIndex.getItemBrowseIndex().getTableName(), false);
dao.pruneExcess(BrowseIndex.getWithdrawnBrowseIndex().getTableName(), true);
dao.pruneExcess(BrowseIndex.getPrivateBrowseIndex().getTableName(), true);
}
private void pruneDistinctIndex(BrowseIndex bi, List<Integer> removedIds) throws BrowseException
@@ -351,6 +352,7 @@ public class IndexBrowse
// Record doesn't exist - ensure that it doesn't exist in the withdrawn index,
// and add it to the archived item index
dao.deleteByItemID(BrowseIndex.getWithdrawnBrowseIndex().getTableName(), item.getID());
dao.deleteByItemID(BrowseIndex.getPrivateBrowseIndex().getTableName(), item.getID());
dao.insertIndex(BrowseIndex.getItemBrowseIndex().getTableName(), item.getID(), sortMap);
}
@@ -358,20 +360,35 @@ public class IndexBrowse
}
else if (item.isWithdrawn())
{
// Try to update an existing record in the withdrawn index
if (!dao.updateIndex(BrowseIndex.getWithdrawnBrowseIndex().getTableName(), item.getID(), sortMap))
{
// Record doesn't exist - ensure that it doesn't exist in the item index,
// and add it to the withdrawn item index
dao.deleteByItemID(BrowseIndex.getItemBrowseIndex().getTableName(), item.getID());
dao.insertIndex(BrowseIndex.getWithdrawnBrowseIndex().getTableName(), item.getID(), sortMap);
// Private items are marked as withdrawn as well. check before if they are private...
Item dsoItem = Item.find(context, item.getID());
if (!dsoItem.isDiscoverable()){
if (!dao.updateIndex(BrowseIndex.getPrivateBrowseIndex().getTableName(), item.getID(), sortMap)) {
dao.deleteByItemID(BrowseIndex.getItemBrowseIndex().getTableName(), item.getID());
dao.insertIndex(BrowseIndex.getPrivateBrowseIndex().getTableName(), item.getID(), sortMap);
}
}
else{
// Try to update an existing record in the withdrawn index
if (!dao.updateIndex(BrowseIndex.getWithdrawnBrowseIndex().getTableName(), item.getID(), sortMap))
{
// Record doesn't exist - ensure that it doesn't exist in the item index,
// and add it to the withdrawn item index
dao.deleteByItemID(BrowseIndex.getItemBrowseIndex().getTableName(), item.getID());
dao.insertIndex(BrowseIndex.getWithdrawnBrowseIndex().getTableName(), item.getID(), sortMap);
}
}
}
else
{
// This item shouldn't exist in either index - ensure that it is removed
dao.deleteByItemID(BrowseIndex.getItemBrowseIndex().getTableName(), item.getID());
dao.deleteByItemID(BrowseIndex.getWithdrawnBrowseIndex().getTableName(), item.getID());
dao.deleteByItemID(BrowseIndex.getPrivateBrowseIndex().getTableName(), item.getID());
}
// Update the community mappings if they are required, or remove them if they aren't
@@ -607,6 +624,7 @@ public class IndexBrowse
// Remove from the item indexes (archive and withdrawn)
dao.deleteByItemID(BrowseIndex.getItemBrowseIndex().getTableName(), itemID);
dao.deleteByItemID(BrowseIndex.getWithdrawnBrowseIndex().getTableName(), itemID);
dao.deleteByItemID(BrowseIndex.getPrivateBrowseIndex().getTableName(), itemID);
dao.deleteCommunityMappings(itemID);
return true;
@@ -883,7 +901,7 @@ public class IndexBrowse
dropItemTables(BrowseIndex.getItemBrowseIndex());
dropItemTables(BrowseIndex.getWithdrawnBrowseIndex());
dropItemTables(BrowseIndex.getPrivateBrowseIndex());
if (execute())
{
context.commit();
@@ -940,6 +958,7 @@ public class IndexBrowse
createItemTables(BrowseIndex.getItemBrowseIndex(), sortCols);
createItemTables(BrowseIndex.getWithdrawnBrowseIndex(), sortCols);
createItemTables(BrowseIndex.getPrivateBrowseIndex(), sortCols);
if (execute())
{

View File

@@ -74,13 +74,9 @@ public class InstallItem
populateHandleMetadata(item, handle);
// this is really just to flush out fatal embargo metadata
// problems before we set inArchive.
DCDate liftDate = EmbargoManager.getEmbargoDate(c, item);
populateMetadata(c, item);
populateMetadata(c, item, liftDate);
return finishItem(c, item, is, liftDate);
return finishItem(c, item, is);
}
@@ -147,7 +143,7 @@ public class InstallItem
String provDescription = "Restored into DSpace on "+ now + " (GMT).";
item.addDC("description", "provenance", "en", provDescription);
return finishItem(c, item, is, null);
return finishItem(c, item, is);
}
private static void populateHandleMetadata(Item item, String handle)
@@ -173,7 +169,7 @@ public class InstallItem
}
private static void populateMetadata(Context c, Item item, DCDate embargoLiftDate)
private static void populateMetadata(Context c, Item item)
throws SQLException, IOException, AuthorizeException
{
// create accession date
@@ -182,9 +178,11 @@ public class InstallItem
// add date available if not under embargo, otherwise it will
// be set when the embargo is lifted.
if (embargoLiftDate == null)
// this will flush out fatal embargo metadata
// problems before we set inArchive.
if (EmbargoManager.getEmbargoTermsAsDate(c, item) == null)
{
item.addDC("date", "available", null, now.toString());
item.addDC("date", "available", null, now.toString());
}
// create issue date if not present
@@ -212,7 +210,7 @@ public class InstallItem
// final housekeeping when adding new Item to archive
// common between installing and "restoring" items.
private static Item finishItem(Context c, Item item, InProgressSubmission is, DCDate embargoLiftDate)
private static Item finishItem(Context c, Item item, InProgressSubmission is)
throws SQLException, IOException, AuthorizeException
{
// create collection2item mapping
@@ -221,8 +219,13 @@ public class InstallItem
// set owning collection
item.setOwningCollection(is.getCollection());
// set in_archive=true
item.setArchived(true);
// set in_archive=true only if the user didn't specify that it is a private item
if(item.isDiscoverable()){
item.setArchived(true);
}
else{ // private item is withdrawn as well
item.withdraw();
}
// save changes ;-)
item.update();
@@ -239,10 +242,7 @@ public class InstallItem
item.inheritCollectionDefaultPolicies(is.getCollection());
// set embargo lift date and take away read access if indicated.
if (embargoLiftDate != null)
{
EmbargoManager.setEmbargo(c, item, embargoLiftDate);
}
EmbargoManager.setEmbargo(c, item);
return item;
}

View File

@@ -186,6 +186,9 @@ public class Item extends DSpaceObject
TableRow row = DatabaseManager.create(context, "item");
Item i = new Item(context, row);
// set discoverable to true (default)
i.setDiscoverable(true);
// Call update to give the item a last modified date. OK this isn't
// amazingly efficient but creates don't happen that often.
context.turnOffAuthorisationSystem();
@@ -251,6 +254,11 @@ public class Item extends DSpaceObject
return itemRow.getIntColumn("item_id");
}
/**
* @see org.dspace.content.DSpaceObject#getHandle()
*/
@@ -287,6 +295,16 @@ public class Item extends DSpaceObject
return itemRow.getBooleanColumn("withdrawn");
}
/**
* Find out if the item is discoverable
*
* @return true if the item is discoverable
*/
public boolean isDiscoverable()
{
return itemRow.getBooleanColumn("discoverable");
}
/**
* Get the date the item was last modified, or the current date if
* last_modified is null
@@ -328,6 +346,18 @@ public class Item extends DSpaceObject
modified = true;
}
/**
* Set the "discoverable" flag. This is public and only
*
* @param discoverable
* new value for the flag
*/
public void setDiscoverable(boolean discoverable)
{
itemRow.setColumn("discoverable", discoverable);
modified = true;
}
/**
* Set the owning Collection for the item
*
@@ -1735,6 +1765,12 @@ public class Item extends DSpaceObject
itemRow.setColumn("withdrawn", false);
}
if (itemRow.isColumnNull("discoverable"))
{
itemRow.setColumn("discoverable", false);
}
DatabaseManager.update(ourContext, itemRow);
if (dublinCoreChanged)
@@ -1838,9 +1874,8 @@ public class Item extends DSpaceObject
ourContext.addEvent(new Event(Event.MODIFY, Constants.ITEM, getID(), "WITHDRAW"));
// and all of our authorization policies
// FIXME: not very "multiple-inclusion" friendly
AuthorizeManager.removeAllPolicies(ourContext, this);
// remove all authorization policies, saving the custom ones
AuthorizeManager.removeAllPoliciesByDSOAndTypeNotEqualsTo(ourContext, this, ResourcePolicy.TYPE_CUSTOM);
// Write log
log.info(LogManager.getHeader(ourContext, "withdraw_item", "user="
@@ -2188,51 +2223,79 @@ public class Item extends DSpaceObject
public void inheritCollectionDefaultPolicies(Collection c)
throws java.sql.SQLException, AuthorizeException
{
List<ResourcePolicy> policies;
adjustItemPolicies(c);
adjustBundleBitstreamPolicies(c);
// remove the submit authorization policies
// and replace them with the collection's default READ policies
policies = AuthorizeManager.getPoliciesActionFilter(ourContext, c,
Constants.DEFAULT_ITEM_READ);
log.debug(LogManager.getHeader(ourContext, "item_inheritCollectionDefaultPolicies",
"item_id=" + getID()));
}
// MUST have default policies
if (policies.size() < 1)
{
throw new java.sql.SQLException("Collection " + c.getID()
+ " (" + c.getHandle() + ")"
+ " has no default item READ policies");
}
public void adjustBundleBitstreamPolicies(Collection c) throws SQLException, AuthorizeException {
// change the action to just READ
// just don't call update on the resourcepolicies!!!
for (ResourcePolicy rp : policies)
{
rp.setAction(Constants.READ);
}
List<ResourcePolicy> defaultCollectionPolicies = AuthorizeManager.getPoliciesActionFilter(ourContext, c, Constants.DEFAULT_BITSTREAM_READ);
replaceAllItemPolicies(policies);
policies = AuthorizeManager.getPoliciesActionFilter(ourContext, c,
Constants.DEFAULT_BITSTREAM_READ);
if (policies.size() < 1)
{
throw new java.sql.SQLException("Collection " + c.getID()
if (defaultCollectionPolicies.size() < 1){
throw new SQLException("Collection " + c.getID()
+ " (" + c.getHandle() + ")"
+ " has no default bitstream READ policies");
}
// change the action to just READ
// just don't call update on the resourcepolicies!!!
for (ResourcePolicy rp : policies)
// remove all policies from bundles, add new ones
// Remove bundles
Bundle[] bunds = getBundles();
for (int i = 0; i < bunds.length; i++){
Bundle mybundle = bunds[i];
// if come from InstallItem: remove all submission/workflow policies
AuthorizeManager.removeAllPoliciesByDSOAndType(ourContext, mybundle, ResourcePolicy.TYPE_SUBMISSION);
AuthorizeManager.removeAllPoliciesByDSOAndType(ourContext, mybundle, ResourcePolicy.TYPE_WORKFLOW);
List<ResourcePolicy> policiesBundleToAdd = filterPoliciesToAdd(defaultCollectionPolicies, mybundle);
AuthorizeManager.addPolicies(ourContext, policiesBundleToAdd, mybundle);
for(Bitstream bitstream : mybundle.getBitstreams()){
// if come from InstallItem: remove all submission/workflow policies
AuthorizeManager.removeAllPoliciesByDSOAndType(ourContext, bitstream, ResourcePolicy.TYPE_SUBMISSION);
AuthorizeManager.removeAllPoliciesByDSOAndType(ourContext, bitstream, ResourcePolicy.TYPE_WORKFLOW);
List<ResourcePolicy> policiesBitstreamToAdd = filterPoliciesToAdd(defaultCollectionPolicies, bitstream);
AuthorizeManager.addPolicies(ourContext, policiesBitstreamToAdd, bitstream);
}
}
}
public void adjustItemPolicies(Collection c) throws SQLException, AuthorizeException {
// read collection's default READ policies
List<ResourcePolicy> defaultCollectionPolicies = AuthorizeManager.getPoliciesActionFilter(ourContext, c, Constants.DEFAULT_ITEM_READ);
// MUST have default policies
if (defaultCollectionPolicies.size() < 1)
{
rp.setAction(Constants.READ);
throw new SQLException("Collection " + c.getID()
+ " (" + c.getHandle() + ")"
+ " has no default item READ policies");
}
replaceAllBitstreamPolicies(policies);
// if come from InstallItem: remove all submission/workflow policies
AuthorizeManager.removeAllPoliciesByDSOAndType(ourContext, this, ResourcePolicy.TYPE_SUBMISSION);
AuthorizeManager.removeAllPoliciesByDSOAndType(ourContext, this, ResourcePolicy.TYPE_WORKFLOW);
log.debug(LogManager.getHeader(ourContext, "item_inheritCollectionDefaultPolicies",
"item_id=" + getID()));
// add default policies only if not already in place
List<ResourcePolicy> policiesToAdd = filterPoliciesToAdd(defaultCollectionPolicies, this);
AuthorizeManager.addPolicies(ourContext, policiesToAdd, this);
}
private List<ResourcePolicy> filterPoliciesToAdd(List<ResourcePolicy> defaultCollectionPolicies, DSpaceObject dso) throws SQLException {
List<ResourcePolicy> policiesToAdd = new ArrayList<ResourcePolicy>();
for (ResourcePolicy rp : defaultCollectionPolicies){
rp.setAction(Constants.READ);
// if an identical policy is already in place don't add it
if(!AuthorizeManager.isAnIdenticalPolicyAlreadyInPlace(ourContext, dso, rp)){
rp.setRpType(ResourcePolicy.TYPE_INHERITED);
policiesToAdd.add(rp);
}
}
return policiesToAdd;
}
/**

View File

@@ -16,6 +16,7 @@ import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.Context;
@@ -153,84 +154,84 @@ public class WorkspaceItem implements InProgressSubmission
EPerson e = c.getCurrentUser();
// read permission
AuthorizeManager.addPolicy(c, i, Constants.READ, e);
AuthorizeManager.addPolicy(c, i, Constants.READ, e, ResourcePolicy.TYPE_SUBMISSION);
if (ConfigurationManager.getProperty("workflow", "workflow.framework").equals("originalworkflow")) {
if (step1group != null)
{
AuthorizeManager.addPolicy(c, i, Constants.READ, step1group);
AuthorizeManager.addPolicy(c, i, Constants.READ, step1group, ResourcePolicy.TYPE_WORKFLOW);
}
if (step2group != null)
{
AuthorizeManager.addPolicy(c, i, Constants.READ, step2group);
AuthorizeManager.addPolicy(c, i, Constants.READ, step2group, ResourcePolicy.TYPE_WORKFLOW);
}
if (step3group != null)
{
AuthorizeManager.addPolicy(c, i, Constants.READ, step3group);
AuthorizeManager.addPolicy(c, i, Constants.READ, step3group, ResourcePolicy.TYPE_WORKFLOW);
}
}
// write permission
AuthorizeManager.addPolicy(c, i, Constants.WRITE, e);
AuthorizeManager.addPolicy(c, i, Constants.WRITE, e, ResourcePolicy.TYPE_SUBMISSION);
if (ConfigurationManager.getProperty("workflow", "workflow.framework").equals("originalworkflow")) {
if (step1group != null)
{
AuthorizeManager.addPolicy(c, i, Constants.WRITE, step1group);
AuthorizeManager.addPolicy(c, i, Constants.WRITE, step1group, ResourcePolicy.TYPE_WORKFLOW);
}
if (step2group != null)
{
AuthorizeManager.addPolicy(c, i, Constants.WRITE, step2group);
AuthorizeManager.addPolicy(c, i, Constants.WRITE, step2group, ResourcePolicy.TYPE_WORKFLOW);
}
if (step3group != null)
{
AuthorizeManager.addPolicy(c, i, Constants.WRITE, step3group);
AuthorizeManager.addPolicy(c, i, Constants.WRITE, step3group, ResourcePolicy.TYPE_WORKFLOW);
}
}
// add permission
AuthorizeManager.addPolicy(c, i, Constants.ADD, e);
AuthorizeManager.addPolicy(c, i, Constants.ADD, e, ResourcePolicy.TYPE_SUBMISSION);
if (ConfigurationManager.getProperty("workflow", "workflow.framework").equals("originalworkflow")) {
if (step1group != null)
{
AuthorizeManager.addPolicy(c, i, Constants.ADD, step1group);
AuthorizeManager.addPolicy(c, i, Constants.ADD, step1group, ResourcePolicy.TYPE_WORKFLOW);
}
if (step2group != null)
{
AuthorizeManager.addPolicy(c, i, Constants.ADD, step2group);
AuthorizeManager.addPolicy(c, i, Constants.ADD, step2group, ResourcePolicy.TYPE_WORKFLOW);
}
if (step3group != null)
{
AuthorizeManager.addPolicy(c, i, Constants.ADD, step3group);
AuthorizeManager.addPolicy(c, i, Constants.ADD, step3group, ResourcePolicy.TYPE_WORKFLOW);
}
}
// remove contents permission
AuthorizeManager.addPolicy(c, i, Constants.REMOVE, e);
AuthorizeManager.addPolicy(c, i, Constants.REMOVE, e, ResourcePolicy.TYPE_SUBMISSION);
if (ConfigurationManager.getProperty("workflow", "workflow.framework").equals("originalworkflow")) {
if (step1group != null)
{
AuthorizeManager.addPolicy(c, i, Constants.REMOVE, step1group);
AuthorizeManager.addPolicy(c, i, Constants.REMOVE, step1group, ResourcePolicy.TYPE_WORKFLOW);
}
if (step2group != null)
{
AuthorizeManager.addPolicy(c, i, Constants.REMOVE, step2group);
AuthorizeManager.addPolicy(c, i, Constants.REMOVE, step2group, ResourcePolicy.TYPE_WORKFLOW);
}
if (step3group != null)
{
AuthorizeManager.addPolicy(c, i, Constants.REMOVE, step3group);
AuthorizeManager.addPolicy(c, i, Constants.REMOVE, step3group, ResourcePolicy.TYPE_WORKFLOW);
}
}

View File

@@ -32,10 +32,10 @@ public class DefaultEmbargoLifter implements EmbargoLifter
* this Item back on.
*
* @param context the DSpace context
* @param item the item to embargo
* @param item the item to embargo
*/
public void liftEmbargo(Context context, Item item)
throws SQLException, AuthorizeException, IOException
throws SQLException, AuthorizeException, IOException
{
// remove the item's policies and replace them with
// the defaults from the collection

View File

@@ -9,17 +9,16 @@ package org.dspace.embargo;
import java.sql.SQLException;
import java.io.IOException;
import java.util.Date;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.content.DCDate;
import org.dspace.content.Item;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.*;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context;
import org.dspace.core.Constants;
import org.dspace.eperson.Group;
import org.dspace.license.CreativeCommons;
/**
@@ -79,21 +78,62 @@ public class DefaultEmbargoSetter implements EmbargoSetter
public void setEmbargo(Context context, Item item)
throws SQLException, AuthorizeException, IOException
{
DCDate liftDate = EmbargoManager.getEmbargoTermsAsDate(context, item);
for (Bundle bn : item.getBundles())
{
// Skip the LICENSE and METADATA bundles, they stay world-readable
String bnn = bn.getName();
if (!(bnn.equals(Constants.LICENSE_BUNDLE_NAME) || bnn.equals(Constants.METADATA_BUNDLE_NAME) || bnn.equals(CreativeCommons.CC_BUNDLE_NAME)))
{
AuthorizeManager.removePoliciesActionFilter(context, bn, Constants.READ);
//AuthorizeManager.removePoliciesActionFilter(context, bn, Constants.READ);
generatePolicies(context, liftDate.toDate(), null, bn, item.getOwningCollection());
for (Bitstream bs : bn.getBitstreams())
{
AuthorizeManager.removePoliciesActionFilter(context, bs, Constants.READ);
//AuthorizeManager.removePoliciesActionFilter(context, bs, Constants.READ);
generatePolicies(context, liftDate.toDate(), null, bs, item.getOwningCollection());
}
}
}
}
protected void generatePolicies(Context context, Date embargoDate,
String reason, DSpaceObject dso, Collection owningCollection) throws SQLException, AuthorizeException {
// add only embargo policy
if(embargoDate!=null){
Group[] authorizedGroups = AuthorizeManager.getAuthorizedGroups(context, owningCollection, Constants.DEFAULT_ITEM_READ);
// look for anonymous
boolean isAnonymousInPlace=false;
for(Group g : authorizedGroups){
if(g.getID()==0){
isAnonymousInPlace=true;
}
}
if(!isAnonymousInPlace){
// add policies for all the groups
for(Group g : authorizedGroups){
ResourcePolicy rp = AuthorizeManager.createOrModifyPolicy(null, context, null, g.getID(), null, embargoDate, Constants.READ, reason, dso);
if(rp!=null)
rp.update();
}
}
else{
// add policy just for anonymous
ResourcePolicy rp = AuthorizeManager.createOrModifyPolicy(null, context, null, 0, null, embargoDate, Constants.READ, reason, dso);
if(rp!=null)
rp.update();
}
}
}
/**
* Check that embargo is properly set on Item: no read access to bitstreams.
*

View File

@@ -18,12 +18,7 @@ import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DCDate;
import org.dspace.content.DCValue;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.ItemIterator;
import org.dspace.content.MetadataSchema;
import org.dspace.content.*;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.Context;
@@ -81,14 +76,13 @@ public class EmbargoManager
*
* @param context the DSpace context
* @param item the item to embargo
* @param lift date on which the embargo is to be lifted.
*/
public static void setEmbargo(Context context, Item item, DCDate lift)
public static void setEmbargo(Context context, Item item)
throws SQLException, AuthorizeException, IOException
{
init();
// if lift is null, we might be restoring an item from an AIP
DCDate myLift = lift;
DCDate myLift = getEmbargoTermsAsDate(context, item);
if (myLift == null)
{
if ((myLift = recoverEmbargoDate(item)) == null)
@@ -104,7 +98,9 @@ public class EmbargoManager
item.clearMetadata(lift_schema, lift_element, lift_qualifier, Item.ANY);
item.addMetadata(lift_schema, lift_element, lift_qualifier, null, slift);
log.info("Set embargo on Item "+item.getHandle()+", expires on: "+slift);
setter.setEmbargo(context, item);
item.update();
}
finally
@@ -128,7 +124,7 @@ public class EmbargoManager
* @param item the item to embargo
* @return lift date on which the embargo is to be lifted, or null if none
*/
public static DCDate getEmbargoDate(Context context, Item item)
public static DCDate getEmbargoTermsAsDate(Context context, Item item)
throws SQLException, AuthorizeException, IOException
{
init();
@@ -178,7 +174,9 @@ public class EmbargoManager
throws SQLException, AuthorizeException, IOException
{
init();
lifter.liftEmbargo(context, item);
// new version of Embargo policies remain in place.
//lifter.liftEmbargo(context, item);
item.clearMetadata(lift_schema, lift_element, lift_qualifier, Item.ANY);
// set the dc.date.available value to right now
@@ -218,6 +216,7 @@ public class EmbargoManager
*/
public static void main(String argv[])
{
init();
int status = 0;
@@ -234,6 +233,10 @@ public class EmbargoManager
"Function: ONLY check the state of embargoed Items, do NOT lift any embargoes.");
options.addOption("l", "lift", false,
"Function: ONLY lift embargoes, do NOT check the state of any embargoed Items.");
options.addOption("a", "adjust", false,
"Function: Adjust bitstreams policies");
options.addOption("h", "help", false, "help");
CommandLine line = null;
try
@@ -339,37 +342,42 @@ public class EmbargoManager
if (lift.length > 0)
{
DCDate liftDate = new DCDate(lift[0].value);
// need to survive any failure on a single item, go on to process the rest.
try
{
DCDate liftDate = new DCDate(lift[0].value);
log.debug("Testing embargo on item="+item.getHandle()+", date="+liftDate.toString());
if (liftDate.toDate().before(now))
{
if (line.hasOption('v'))
if (line.hasOption('a')){
setter.setEmbargo(context, item);
}
else{
log.debug("Testing embargo on item="+item.getHandle()+", date="+liftDate.toString());
if (liftDate.toDate().before(now))
{
System.err.println("Lifting embargo from Item handle=" + item.getHandle() + ", lift date=" + lift[0].value);
}
if (line.hasOption('n'))
{
if (!line.hasOption('q'))
if (line.hasOption('v'))
{
System.err.println("DRY RUN: would have lifted embargo from Item handle=" + item.getHandle() + ", lift date=" + lift[0].value);
System.err.println("Lifting embargo from Item handle=" + item.getHandle() + ", lift date=" + lift[0].value);
}
if (line.hasOption('n'))
{
if (!line.hasOption('q'))
{
System.err.println("DRY RUN: would have lifted embargo from Item handle=" + item.getHandle() + ", lift date=" + lift[0].value);
}
}
else if (!line.hasOption('c'))
{
liftEmbargo(context, item);
}
}
else if (!line.hasOption('c'))
else if (!line.hasOption('l'))
{
liftEmbargo(context, item);
if (line.hasOption('v'))
{
System.err.println("Checking current embargo on Item handle=" + item.getHandle() + ", lift date=" + lift[0].value);
}
setter.checkEmbargo(context, item);
}
}
else if (!line.hasOption('l'))
{
if (line.hasOption('v'))
{
System.err.println("Checking current embargo on Item handle=" + item.getHandle() + ", lift date=" + lift[0].value);
}
setter.checkEmbargo(context, item);
}
}
catch (Exception e)
{
@@ -382,6 +390,8 @@ public class EmbargoManager
return status;
}
// initialize - get plugins and MD field settings from config
private static void init()
{
@@ -433,7 +443,7 @@ public class EmbargoManager
String sa[] = field.split("\\.", 3);
return sa.length > 2 ? sa[2] : null;
}
// return the lift date assigned when embargo was set, or null, if either:
// it was never under embargo, or the lift date has passed.
private static DCDate recoverEmbargoDate(Item item) {
@@ -448,6 +458,7 @@ public class EmbargoManager
liftDate = null;
}
}
return liftDate;
return liftDate;
}
}

View File

@@ -0,0 +1,305 @@
/**
* 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.submit.step;
import org.apache.commons.lang.time.DateUtils;
import org.apache.log4j.Logger;
import org.dspace.app.util.SubmissionInfo;
import org.dspace.app.util.Util;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.content.Collection;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.handle.HandleManager;
import org.dspace.submit.AbstractProcessingStep;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Date;
/**
* This class manages the access step during the submission
*
* @author Fabio Bolognesi (fabio at atmire dot com)
* @author Mark Diggory (markd at atmire dot com)
* @author Ben Bosman (ben at atmire dot com)
*
*/
public class AccessStep extends AbstractProcessingStep
{
public static final int STATUS_ERROR_FORMAT_DATE = 1;
public static final int STATUS_ERROR_MISSING_DATE = 2;
public static final int STATUS_ERROR_SELECT_GROUP = 3;
public static final int STATUS_DUPLICATED_POLICY = 4;
public static final int EDIT_POLICY_STATUS_DUPLICATED_POLICY=5;
// edit file information
public static final int STATUS_EDIT_POLICY = 10;
public static final String SUB_INFO_SELECTED_RP = "SUB_INFO_SELECTED_RP";
/** log4j logger */
private static Logger log = Logger.getLogger(AccessStep.class);
// OPERATIONS
public static final String FORM_EDIT_BUTTON_CANCEL = "submit_edit_cancel";
public static final String FORM_EDIT_BUTTON_SAVE = "submit_save";
public static final String FORM_ACCESS_BUTTON_ADD = "submit_add_policy";
/**
* Do any processing of the information input by the user, and/or perform
* step processing (if no user interaction required)
* <P>
* It is this method's job to save any data to the underlying database, as
* necessary, and return error messages (if any) which can then be processed
* by the appropriate user interface (JSP-UI or XML-UI)
* <P>
* NOTE: If this step is a non-interactive step (i.e. requires no UI), then
* it should perform *all* of its processing in this method!
*
* @param context
* current DSpace context
* @param request
* current servlet request object
* @param response
* current servlet response object
* @param subInfo
* submission info object
* @return Status or error flag which will be processed by
* doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned,
* no errors occurred!)
*/
public int doProcessing(Context context, HttpServletRequest request,
HttpServletResponse response, SubmissionInfo subInfo)
throws ServletException, IOException, SQLException,
AuthorizeException{
String buttonPressed = Util.getSubmitButton(request, CANCEL_BUTTON);
// get reference to item
Item item = subInfo.getSubmissionItem().getItem();
int groupID = 0;
if(request.getParameter("group_id")!=null){
try{
groupID=Integer.parseInt(request.getParameter("group_id"));
}catch (NumberFormatException nfe){
return STATUS_ERROR_SELECT_GROUP;
}
}
String name = request.getParameter("name");
String reason = request.getParameter("reason");
// SELECTED OPERATION: go to EditPolicyForm
if(wasEditPolicyPressed(context, buttonPressed, subInfo))
return STATUS_EDIT_POLICY;
// SELECTED OPERATION: Remove Policies
if(wasRemovePolicyPressed(buttonPressed)){
removePolicy(context, buttonPressed);
context.commit();
return STATUS_COMPLETE;
}
// SELECTED OPERATION: Save or Cancel EditPolicy.
if(comeFromEditPolicy(request)) {
return saveOrCancelEditPolicy(context, request, subInfo, buttonPressed, item, name, groupID, reason);
}
// SELECTED OPERATION: ADD Policy
if(wasAddPolicyPressed(buttonPressed)){
int result=-1;
if( (result = checkForm(request))!=0){
return result;
}
// handle private checkbox
item.setDiscoverable(true);
if(request.getParameter("private_option")!=null){
item.setDiscoverable(false);
}
Date dateStartDate = getEmbargoUntil(request);
ResourcePolicy rp = null;
if( (rp=AuthorizeManager.createOrModifyPolicy(null, context, name, groupID, null, dateStartDate, org.dspace.core.Constants.READ, reason, item))==null){
return STATUS_DUPLICATED_POLICY;
}
rp.update();
context.commit();
return STATUS_COMPLETE;
}
// if arrive here Next, Previous or Save has been pressed
boolean isAdvancedFormEnabled= ConfigurationManager.getBooleanProperty("xmlui.submission.restrictstep.enableAdvancedForm", false);
// if it is a simple form we should create the policy for Anonymous
// if Anonymous does not have right on this collection, create policies for any other groups with
// DEFAULT_ITEM_READ specified.
if(!isAdvancedFormEnabled){
AuthorizeManager.generateAutomaticPolicies(context, getEmbargoUntilDate(request), reason, item, (Collection)HandleManager.resolveToObject(context, subInfo.getCollectionHandle()));
}
// else{
// Date dateStartDate = getEmbargoUntil(request);
// createOrModifyPolicy(null, context, name, groupID, null, dateStartDate, org.dspace.core.Constants.READ, reason, item);
// }
item.setDiscoverable(true);
if(request.getParameter("private_option")!=null){
item.setDiscoverable(false);
}
item.update();
context.commit();
return STATUS_COMPLETE;
}
public static boolean wasEditPolicyPressed(Context context, String buttonPressed, SubmissionInfo subInfo) throws SQLException {
if (buttonPressed.startsWith("submit_edit_edit_policies_") && !buttonPressed.equals(FORM_EDIT_BUTTON_CANCEL)){
String idPolicy = buttonPressed.substring("submit_edit_edit_policies_".length());
ResourcePolicy rp = ResourcePolicy.find(context, Integer.parseInt(idPolicy));
subInfo.put(SUB_INFO_SELECTED_RP, rp);
return true;
}
return false;
}
public static boolean wasAddPolicyPressed(String buttonPressed) throws SQLException {
return (buttonPressed.equalsIgnoreCase(FORM_ACCESS_BUTTON_ADD));
}
public static boolean wasRemovePolicyPressed(String buttonPressed) throws SQLException {
return (buttonPressed.startsWith("submit_delete_edit_policies_"));
}
public static boolean comeFromEditPolicy(HttpServletRequest request) throws SQLException {
return (request.getParameter("policy_id") != null);
}
public static int saveOrCancelEditPolicy(Context context, HttpServletRequest request, SubmissionInfo subInfo, String buttonPressed, DSpaceObject dso, String name, int groupID, String reason) throws AuthorizeException, SQLException {
if (buttonPressed.equals(FORM_EDIT_BUTTON_CANCEL)){
return STATUS_COMPLETE;
}
else if (buttonPressed.equals(FORM_EDIT_BUTTON_SAVE)){
String idPolicy = request.getParameter("policy_id");
ResourcePolicy resourcePolicy = ResourcePolicy.find(context, Integer.parseInt(idPolicy));
subInfo.put(SUB_INFO_SELECTED_RP, resourcePolicy);
Date dateStartDate = getEmbargoUntil(request);
if( (resourcePolicy=AuthorizeManager.createOrModifyPolicy(resourcePolicy, context, name, groupID, null, dateStartDate, Constants.READ, reason, dso))==null){
return EDIT_POLICY_STATUS_DUPLICATED_POLICY;
}
resourcePolicy.update();
context.commit();
}
return STATUS_COMPLETE;
}
public static void removePolicy(Context context, String buttonPressed) throws SQLException {
String idPolicy = buttonPressed.substring("submit_delete_edit_policies_".length());
ResourcePolicy rp = ResourcePolicy.find(context, Integer.parseInt(idPolicy));
rp.delete();
}
public static int checkForm(HttpServletRequest request){
String selectedRadio=null;
String dateEmbargoUntil = request.getParameter("embargo_until_date");
// RADIO_OPEN_ACCESS_ITEM_VISIBLE=0;
// RADIO_OPEN_ACCESS_ITEM_EMBARGOED=1;
if((selectedRadio=request.getParameter("open_access_radios"))!=null && Integer.parseInt(selectedRadio)==1
&& (dateEmbargoUntil==null || dateEmbargoUntil.equals(""))){
return STATUS_ERROR_MISSING_DATE;
}
if(dateEmbargoUntil !=null && !dateEmbargoUntil.equals("")){
Date startDate = getEmbargoUntilDate(request);
if(startDate==null){
return STATUS_ERROR_FORMAT_DATE;
}
}
return 0;
}
public static Date getEmbargoUntil(HttpServletRequest request) {
// RADIO_OPEN_ACCESS_ITEM_VISIBLE=0;
// RADIO_OPEN_ACCESS_ITEM_EMBARGOED=1;
String selectedRadio;
Date dateStartDate=null;
if((selectedRadio=request.getParameter("open_access_radios"))!=null && Integer.parseInt(selectedRadio)==1){
Date startDate = getEmbargoUntilDate(request);
if(startDate!=null) dateStartDate=startDate;
}
return dateStartDate;
}
private static Date getEmbargoUntilDate(HttpServletRequest request) {
Date startDate = null;
try {
startDate = DateUtils.parseDate(request.getParameter("embargo_until_date"), new String[]{"yyyy-MM-dd", "yyyy-MM", "yyyy"});
} catch (Exception e) {
//Ignore start date is already null
}
return startDate;
}
/**
* Retrieves the number of pages that this "step" extends over. This method
* is used to build the progress bar.
* <P>
* This method may just return 1 for most steps (since most steps consist of
* a single page). But, it should return a number greater than 1 for any
* "step" which spans across a number of HTML pages. For example, the
* configurable "Describe" step (configured using input-forms.xml) overrides
* this method to return the number of pages that are defined by its
* configuration file.
* <P>
* Steps which are non-interactive (i.e. they do not display an interface to
* the user) should return a value of 1, so that they are only processed
* once!
*
* @param request
* The HTTP Request
* @param subInfo
* The current submission information object
*
* @return the number of pages in this step
*/
public int getNumberOfPages(HttpServletRequest request,
SubmissionInfo subInfo) throws ServletException
{
return 1;
}
}

View File

@@ -0,0 +1,821 @@
/**
* 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.submit.step;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Date;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.time.DateUtils;
import org.apache.log4j.Logger;
import org.dspace.app.util.SubmissionInfo;
import org.dspace.app.util.Util;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.content.*;
import org.dspace.core.Context;
import org.dspace.core.ConfigurationManager;
import org.dspace.curate.Curator;
import org.dspace.handle.HandleManager;
import org.dspace.submit.AbstractProcessingStep;
/**
* Upload step for DSpace. Processes the actual upload of files
* for an item being submitted into DSpace.
* <P>
* This class performs all the behind-the-scenes processing that
* this particular step requires. This class's methods are utilized
* by both the JSP-UI and the Manakin XML-UI
*
* @see org.dspace.app.util.SubmissionConfig
* @see org.dspace.app.util.SubmissionStepConfig
* @see org.dspace.submit.AbstractProcessingStep
*
* @author Tim Donohue
* @version $Revision$
*/
public class UploadWithEmbargoStep extends AbstractProcessingStep
{
/** Button to upload a file * */
public static final String SUBMIT_UPLOAD_BUTTON = "submit_upload";
/** Button to skip uploading a file * */
public static final String SUBMIT_SKIP_BUTTON = "submit_skip";
/** Button to submit more files * */
public static final String SUBMIT_MORE_BUTTON = "submit_more";
/** Button to cancel editing of file info * */
public static final String CANCEL_EDIT_BUTTON = "submit_edit_cancel";
/***************************************************************************
* STATUS / ERROR FLAGS (returned by doProcessing() if an error occurs or
* additional user interaction may be required)
*
* (Do NOT use status of 0, since it corresponds to STATUS_COMPLETE flag
* defined in the JSPStepManager class)
**************************************************************************/
// integrity error occurred
public static final int STATUS_INTEGRITY_ERROR = 1;
// error in uploading file
public static final int STATUS_UPLOAD_ERROR = 2;
// error - no files uploaded!
public static final int STATUS_NO_FILES_ERROR = 5;
// format of uploaded file is unknown
public static final int STATUS_UNKNOWN_FORMAT = 10;
// virus checker unavailable ?
public static final int STATUS_VIRUS_CHECKER_UNAVAILABLE = 14;
// file failed virus check
public static final int STATUS_CONTAINS_VIRUS = 16;
// edit file information
public static final int STATUS_EDIT_BITSTREAM = 20;
// return from editing file information
public static final int STATUS_EDIT_COMPLETE = 25;
public static final int STATUS_EDIT_POLICIES = 30;
public static final int STATUS_EDIT_POLICIES_ERROR_SELECT_GROUP = 31;
public static final int STATUS_EDIT_POLICIES_DUPLICATED_POLICY = 32;
public static final int STATUS_EDIT_POLICY_ERROR_SELECT_GROUP = 33;
public static final int STATUS_EDIT_POLICY_DUPLICATED_POLICY = 34;
/** log4j logger */
private static Logger log = Logger.getLogger(UploadStep.class);
/** is the upload required? */
private boolean fileRequired = ConfigurationManager.getBooleanProperty("webui.submit.upload.required", true);
/**
* Do any processing of the information input by the user, and/or perform
* step processing (if no user interaction required)
* <P>
* It is this method's job to save any data to the underlying database, as
* necessary, and return error messages (if any) which can then be processed
* by the appropriate user interface (JSP-UI or XML-UI)
* <P>
* NOTE: If this step is a non-interactive step (i.e. requires no UI), then
* it should perform *all* of its processing in this method!
*
* @param context
* current DSpace context
* @param request
* current servlet request object
* @param response
* current servlet response object
* @param subInfo
* submission info object
* @return Status or error flag which will be processed by
* doPostProcessing() below! (if STATUS_COMPLETE or 0 is returned,
* no errors occurred!)
*/
public int doProcessing(Context context, HttpServletRequest request,
HttpServletResponse response, SubmissionInfo subInfo)
throws ServletException, IOException, SQLException,
AuthorizeException
{
// get button user pressed
String buttonPressed = Util.getSubmitButton(request, NEXT_BUTTON);
// get reference to item
Item item = subInfo.getSubmissionItem().getItem();
// -----------------------------------
// Step #0: Upload new files (if any)
// -----------------------------------
String contentType = request.getContentType();
// if multipart form, then we are uploading a file
if ((contentType != null)
&& (contentType.indexOf("multipart/form-data") != -1))
{
// This is a multipart request, so it's a file upload
// (return any status messages or errors reported)
int status = processUploadFile(context, request, response, subInfo);
// if error occurred, return immediately
if (status != STATUS_COMPLETE)
{
return status;
}
}
// if user pressed jump-to button in process bar,
// return success (so that jump will occur)
if (buttonPressed.startsWith(PROGRESS_BAR_PREFIX))
{
// check if a file is required to be uploaded
if (fileRequired && !item.hasUploadedFiles())
{
return STATUS_NO_FILES_ERROR;
}
else
{
return STATUS_COMPLETE;
}
}
// POLICIES FORM MANAGEMENT
int result = editBitstreamPolicies(request, context, subInfo, buttonPressed);
if(result != -1) return result;
// ---------------------------------------------
// Step #1: Check if this was just a request to
// edit file information.
// (or canceled editing information)
// ---------------------------------------------
// check if we're already editing a specific bitstream
if (request.getParameter("bitstream_id") != null)
{
if (buttonPressed.equals(CANCEL_EDIT_BUTTON))
{
// canceled an edit bitstream request
subInfo.setBitstream(null);
// this flag will just return us to the normal upload screen
return STATUS_EDIT_COMPLETE;
}
else
{
// load info for bitstream we are editing
Bitstream b = Bitstream.find(context, Integer.parseInt(request
.getParameter("bitstream_id")));
// save bitstream to submission info
subInfo.setBitstream(b);
}
}
else if (buttonPressed.startsWith("submit_edit_"))
{
// get ID of bitstream that was requested for editing
String bitstreamID = buttonPressed.substring("submit_edit_"
.length());
Bitstream b = Bitstream
.find(context, Integer.parseInt(bitstreamID));
// save bitstream to submission info
subInfo.setBitstream(b);
// return appropriate status flag to say we are now editing the
// bitstream
return STATUS_EDIT_BITSTREAM;
}
// ---------------------------------------------
// Step #2: Process any remove file request(s)
// ---------------------------------------------
// Remove-selected requests come from Manakin
if (buttonPressed.equalsIgnoreCase("submit_remove_selected"))
{
// this is a remove multiple request!
if (request.getParameter("remove") != null)
{
// get all files to be removed
String[] removeIDs = request.getParameterValues("remove");
// remove each file in the list
for (int i = 0; i < removeIDs.length; i++)
{
int id = Integer.parseInt(removeIDs[i]);
int status = processRemoveFile(context, item, id);
// if error occurred, return immediately
if (status != STATUS_COMPLETE)
{
return status;
}
}
// remove current bitstream from Submission Info
subInfo.setBitstream(null);
}
}
else if (buttonPressed.startsWith("submit_remove_"))
{
// A single file "remove" button must have been pressed
int id = Integer.parseInt(buttonPressed.substring(14));
int status = processRemoveFile(context, item, id);
// if error occurred, return immediately
if (status != STATUS_COMPLETE)
{
return status;
}
// remove current bitstream from Submission Info
subInfo.setBitstream(null);
}
// -------------------------------------------------
// Step #3: Check for a change in file description
// -------------------------------------------------
String fileDescription = request.getParameter("description");
if (fileDescription != null && fileDescription.length() > 0)
{
// save this file description
int status = processSaveFileDescription(context, request, response,
subInfo);
// if error occurred, return immediately
if (status != STATUS_COMPLETE)
{
return status;
}
}
// ------------------------------------------
// Step #4: Check for a file format change
// (if user had to manually specify format)
// ------------------------------------------
int formatTypeID = Util.getIntParameter(request, "format");
String formatDesc = request.getParameter("format_description");
// if a format id or description was found, then save this format!
if (formatTypeID >= 0
|| (formatDesc != null && formatDesc.length() > 0))
{
// save this specified format
int status = processSaveFileFormat(context, request, response,
subInfo);
// if error occurred, return immediately
if (status != STATUS_COMPLETE)
{
return status;
}
}
// execute only if comes from EditBitstreamStep
if(buttonPressed.equals("submit_save")){
processAccessFields(context, request, subInfo, subInfo.getBitstream());
}
// ---------------------------------------------------
// Step #5: Check if primary bitstream has changed
// -------------------------------------------------
if (request.getParameter("primary_bitstream_id") != null)
{
Bundle[] bundles = item.getBundles("ORIGINAL");
if (bundles.length > 0)
{
bundles[0].setPrimaryBitstreamID(Integer.valueOf(request
.getParameter("primary_bitstream_id")).intValue());
bundles[0].update();
}
}
// ---------------------------------------------------
// Step #6: Determine if there is an error because no
// files have been uploaded.
// ---------------------------------------------------
//check if a file is required to be uploaded
if (fileRequired && !item.hasUploadedFiles())
{
return STATUS_NO_FILES_ERROR;
}
return STATUS_COMPLETE;
}
/**
* Retrieves the number of pages that this "step" extends over. This method
* is used to build the progress bar.
* <P>
* This method may just return 1 for most steps (since most steps consist of
* a single page). But, it should return a number greater than 1 for any
* "step" which spans across a number of HTML pages. For example, the
* configurable "Describe" step (configured using input-forms.xml) overrides
* this method to return the number of pages that are defined by its
* configuration file.
* <P>
* Steps which are non-interactive (i.e. they do not display an interface to
* the user) should return a value of 1, so that they are only processed
* once!
*
* @param request
* The HTTP Request
* @param subInfo
* The current submission information object
*
* @return the number of pages in this step
*/
public int getNumberOfPages(HttpServletRequest request,
SubmissionInfo subInfo) throws ServletException
{
// Despite using many JSPs, this step only appears
// ONCE in the Progress Bar, so it's only ONE page
return 1;
}
// ****************************************************************
// ****************************************************************
// METHODS FOR UPLOADING FILES (and associated information)
// ****************************************************************
// ****************************************************************
/**
* Remove a file from an item
*
* @param context
* current DSpace context
* @param item
* Item where file should be removed from
* @param bitstreamID
* The id of bitstream representing the file to remove
* @return Status or error flag which will be processed by
* UI-related code! (if STATUS_COMPLETE or 0 is returned,
* no errors occurred!)
*/
protected int processRemoveFile(Context context, Item item, int bitstreamID)
throws IOException, SQLException, AuthorizeException
{
Bitstream bitstream;
// Try to find bitstream
try
{
bitstream = Bitstream.find(context, bitstreamID);
}
catch (NumberFormatException nfe)
{
bitstream = null;
}
if (bitstream == null)
{
// Invalid or mangled bitstream ID
// throw an error and return immediately
return STATUS_INTEGRITY_ERROR;
}
// remove bitstream from bundle..
// delete bundle if it's now empty
Bundle[] bundles = bitstream.getBundles();
bundles[0].removeBitstream(bitstream);
Bitstream[] bitstreams = bundles[0].getBitstreams();
// remove bundle if it's now empty
if (bitstreams.length < 1)
{
item.removeBundle(bundles[0]);
item.update();
}
// no errors occurred
return STATUS_COMPLETE;
}
/**
* Process the upload of a new file!
*
* @param context
* current DSpace context
* @param request
* current servlet request object
* @param response
* current servlet response object
* @param subInfo
* submission info object
*
* @return Status or error flag which will be processed by
* UI-related code! (if STATUS_COMPLETE or 0 is returned,
* no errors occurred!)
*/
protected int processUploadFile(Context context, HttpServletRequest request,
HttpServletResponse response, SubmissionInfo subInfo)
throws ServletException, IOException, SQLException,
AuthorizeException
{
boolean formatKnown = true;
boolean fileOK = false;
BitstreamFormat bf = null;
Bitstream b = null;
//NOTE: File should already be uploaded.
//Manakin does this automatically via Cocoon.
//For JSP-UI, the SubmissionController.uploadFiles() does the actual upload
Enumeration attNames = request.getAttributeNames();
//loop through our request attributes
while(attNames.hasMoreElements())
{
String attr = (String) attNames.nextElement();
//if this ends with "-path", this attribute
//represents a newly uploaded file
if(attr.endsWith("-path"))
{
//strip off the -path to get the actual parameter
//that the file was uploaded as
String param = attr.replace("-path", "");
// Load the file's path and input stream and description
String filePath = (String) request.getAttribute(param + "-path");
InputStream fileInputStream = (InputStream) request.getAttribute(param + "-inputstream");
//attempt to get description from attribute first, then direct from a parameter
String fileDescription = (String) request.getAttribute(param + "-description");
if(fileDescription==null ||fileDescription.length()==0)
{
request.getParameter("description");
}
// if information wasn't passed by User Interface, we had a problem
// with the upload
if (filePath == null || fileInputStream == null)
{
return STATUS_UPLOAD_ERROR;
}
if (subInfo == null)
{
// In any event, if we don't have the submission info, the request
// was malformed
return STATUS_INTEGRITY_ERROR;
}
// Create the bitstream
Item item = subInfo.getSubmissionItem().getItem();
// do we already have a bundle?
Bundle[] bundles = item.getBundles("ORIGINAL");
if (bundles.length < 1)
{
// set bundle's name to ORIGINAL
b = item.createSingleBitstream(fileInputStream, "ORIGINAL");
}
else
{
// we have a bundle already, just add bitstream
b = bundles[0].createBitstream(fileInputStream);
}
// Strip all but the last filename. It would be nice
// to know which OS the file came from.
String noPath = filePath;
while (noPath.indexOf('/') > -1)
{
noPath = noPath.substring(noPath.indexOf('/') + 1);
}
while (noPath.indexOf('\\') > -1)
{
noPath = noPath.substring(noPath.indexOf('\\') + 1);
}
b.setName(noPath);
b.setSource(filePath);
b.setDescription(fileDescription);
// Identify the format
bf = FormatIdentifier.guessFormat(context, b);
b.setFormat(bf);
// Update to DB
b.update();
item.update();
processAccessFields(context, request, subInfo, b);
// commit all changes to database
context.commit();
if ((bf != null) && (bf.isInternal()))
{
log.warn("Attempt to upload file format marked as internal system use only");
backoutBitstream(subInfo, b, item);
return STATUS_UPLOAD_ERROR;
}
// Check for virus
if (ConfigurationManager.getBooleanProperty("submission-curation", "virus-scan"))
{
Curator curator = new Curator();
curator.addTask("vscan").curate(item);
int status = curator.getStatus("vscan");
if (status == Curator.CURATE_ERROR)
{
backoutBitstream(subInfo, b, item);
return STATUS_VIRUS_CHECKER_UNAVAILABLE;
}
else if (status == Curator.CURATE_FAIL)
{
backoutBitstream(subInfo, b, item);
return STATUS_CONTAINS_VIRUS;
}
}
// If we got this far then everything is more or less ok.
// Comment - not sure if this is the right place for a commit here
// but I'm not brave enough to remove it - Robin.
context.commit();
// save this bitstream to the submission info, as the
// bitstream we're currently working with
subInfo.setBitstream(b);
//if format was not identified
if (bf == null)
{
return STATUS_UNKNOWN_FORMAT;
}
}//end if attribute ends with "-path"
}//end while
return STATUS_COMPLETE;
}
private void processAccessFields(Context context, HttpServletRequest request, SubmissionInfo subInfo, Bitstream b) throws SQLException, AuthorizeException {
// ResourcePolicy Management
boolean isAdvancedFormEnabled= ConfigurationManager.getBooleanProperty("xmlui.submission.restrictstep.enableAdvancedForm", false);
// if it is a simple form we should create the policy for Anonymous
// if Anonymous does not have right on this collection, create policies for any other groups with
// DEFAULT_ITEM_READ specified.
if(!isAdvancedFormEnabled){
Date startDate = null;
try {
startDate = DateUtils.parseDate(request.getParameter("embargo_until_date"), new String[]{"yyyy-MM-dd", "yyyy-MM", "yyyy"});
} catch (Exception e) {
//Ignore start date already null
}
String reason = request.getParameter("reason");
AuthorizeManager.generateAutomaticPolicies(context, startDate, reason, b, (Collection) HandleManager.resolveToObject(context, subInfo.getCollectionHandle()));
}
}
/*
If we created a new Bitstream but now realised there is a problem then remove it.
*/
private void backoutBitstream(SubmissionInfo subInfo, Bitstream b, Item item) throws SQLException, AuthorizeException, IOException
{
// remove bitstream from bundle..
// delete bundle if it's now empty
Bundle[] bnd = b.getBundles();
bnd[0].removeBitstream(b);
Bitstream[] bitstreams = bnd[0].getBitstreams();
// remove bundle if it's now empty
if (bitstreams.length < 1)
{
item.removeBundle(bnd[0]);
item.update();
}
subInfo.setBitstream(null);
}
/**
* Process input from get file type page
*
* @param context
* current DSpace context
* @param request
* current servlet request object
* @param response
* current servlet response object
* @param subInfo
* submission info object
*
* @return Status or error flag which will be processed by
* UI-related code! (if STATUS_COMPLETE or 0 is returned,
* no errors occurred!)
*/
protected int processSaveFileFormat(Context context,
HttpServletRequest request, HttpServletResponse response,
SubmissionInfo subInfo) throws ServletException, IOException,
SQLException, AuthorizeException
{
if (subInfo.getBitstream() != null)
{
// Did the user select a format?
int typeID = Util.getIntParameter(request, "format");
BitstreamFormat format = BitstreamFormat.find(context, typeID);
if (format != null)
{
subInfo.getBitstream().setFormat(format);
}
else
{
String userDesc = request.getParameter("format_description");
subInfo.getBitstream().setUserFormatDescription(userDesc);
}
// update database
subInfo.getBitstream().update();
}
else
{
return STATUS_INTEGRITY_ERROR;
}
return STATUS_COMPLETE;
}
/**
* Process input from the "change file description" page
*
* @param context
* current DSpace context
* @param request
* current servlet request object
* @param response
* current servlet response object
* @param subInfo
* submission info object
*
* @return Status or error flag which will be processed by
* UI-related code! (if STATUS_COMPLETE or 0 is returned,
* no errors occurred!)
*/
protected int processSaveFileDescription(Context context,
HttpServletRequest request, HttpServletResponse response,
SubmissionInfo subInfo) throws ServletException, IOException,
SQLException, AuthorizeException
{
if (subInfo.getBitstream() != null)
{
subInfo.getBitstream().setDescription(
request.getParameter("description"));
subInfo.getBitstream().update();
context.commit();
}
else
{
return STATUS_INTEGRITY_ERROR;
}
return STATUS_COMPLETE;
}
private int editBitstreamPolicies(HttpServletRequest request, Context context, SubmissionInfo subInfo, String buttonPressed)
throws SQLException, AuthorizeException {
// FORM: EditBitstreamPolicies SELECTED OPERATION: Return
if (buttonPressed.equals("bitstream_list_submit_return")){
return STATUS_COMPLETE;
}
// FORM: UploadStep SELECTED OPERATION: go to EditBitstreamPolicies
else if (buttonPressed.startsWith("submit_editPolicy_")){
String bitstreamID = buttonPressed.substring("submit_editPolicy_".length());
Bitstream b = Bitstream.find(context, Integer.parseInt(bitstreamID));
subInfo.setBitstream(b);
return STATUS_EDIT_POLICIES;
}
// FORM: EditBitstreamPolicies SELECTED OPERATION: Add New Policy.
else if (buttonPressed.startsWith(AccessStep.FORM_ACCESS_BUTTON_ADD)){
Bitstream b = Bitstream.find(context, Integer.parseInt(request.getParameter("bitstream_id")));
subInfo.setBitstream(b);
int result=-1;
if( (result = AccessStep.checkForm(request))!=0){
return result;
}
Date dateStartDate = AccessStep.getEmbargoUntil(request);
String reason = request.getParameter("reason");
String name = request.getParameter("name");
int groupID = 0;
if(request.getParameter("group_id")!=null){
try{
groupID=Integer.parseInt(request.getParameter("group_id"));
}catch (NumberFormatException nfe){
return STATUS_EDIT_POLICIES_ERROR_SELECT_GROUP;
}
}
ResourcePolicy rp = null;
if( (rp= AuthorizeManager.createOrModifyPolicy(null, context, name, groupID, null, dateStartDate, org.dspace.core.Constants.READ, reason, b))==null){
return STATUS_EDIT_POLICIES_DUPLICATED_POLICY;
}
rp.update();
context.commit();
return STATUS_EDIT_POLICIES;
}
// FORM: EditBitstreamPolicies SELECTED OPERATION: go to EditPolicyForm
else if(org.dspace.submit.step.AccessStep.wasEditPolicyPressed(context, buttonPressed, subInfo)){
Bitstream b = Bitstream.find(context, Integer.parseInt(request.getParameter("bitstream_id")));
subInfo.setBitstream(b);
return org.dspace.submit.step.AccessStep.STATUS_EDIT_POLICY;
}
// FORM: EditPolicy SELECTED OPERATION: Save or Cancel.
else if(org.dspace.submit.step.AccessStep.comeFromEditPolicy(request)) {
Bitstream b = Bitstream.find(context, Integer.parseInt(request.getParameter("bitstream_id")));
subInfo.setBitstream(b);
String reason = request.getParameter("reason");
String name = request.getParameter("name");
int groupID = 0;
if(request.getParameter("group_id")!=null){
try{
groupID=Integer.parseInt(request.getParameter("group_id"));
}catch (NumberFormatException nfe){
return STATUS_EDIT_POLICIES_ERROR_SELECT_GROUP;
}
}
if(org.dspace.submit.step.AccessStep.saveOrCancelEditPolicy(context, request,
subInfo, buttonPressed, b, name, groupID, reason)==org.dspace.submit.step.AccessStep.EDIT_POLICY_STATUS_DUPLICATED_POLICY)
return STATUS_EDIT_POLICY_DUPLICATED_POLICY;
return STATUS_EDIT_POLICIES;
}
// FORM: EditBitstreamPolicies SELECTED OPERATION: Remove Policies
if(org.dspace.submit.step.AccessStep.wasRemovePolicyPressed(buttonPressed)){
Bitstream b = Bitstream.find(context, Integer.parseInt(request.getParameter("bitstream_id")));
subInfo.setBitstream(b);
org.dspace.submit.step.AccessStep.removePolicy(context, buttonPressed);
context.commit();
return STATUS_EDIT_POLICIES;
}
return -1;
}
}