mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
Merge branch 'main' of https://github.com/DSpace/DSpace into feature-issue2816-openaire-funding-external-lookup
This commit is contained in:
@@ -927,6 +927,13 @@
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.stefanbirkner</groupId>
|
||||
<artifactId>system-rules</artifactId>
|
||||
<version>1.19.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@@ -60,7 +60,6 @@ public class Harvest {
|
||||
options.addOption("p", "purge", false, "delete all items in the collection");
|
||||
options.addOption("r", "run", false, "run the standard harvest procedure");
|
||||
options.addOption("g", "ping", false, "test the OAI server and set");
|
||||
options.addOption("o", "once", false, "run the harvest procedure with specified parameters");
|
||||
options.addOption("s", "setup", false, "Set the collection up for harvesting");
|
||||
options.addOption("S", "start", false, "start the harvest loop");
|
||||
options.addOption("R", "reset", false, "reset harvest status on all collections");
|
||||
@@ -97,9 +96,6 @@ public class Harvest {
|
||||
HelpFormatter myhelp = new HelpFormatter();
|
||||
myhelp.printHelp("Harvest\n", options);
|
||||
System.out.println("\nPING OAI server: Harvest -g -a oai_source -i oai_set_id");
|
||||
System.out.println(
|
||||
"RUNONCE harvest with arbitrary options: Harvest -o -e eperson -c collection -t harvest_type -a " +
|
||||
"oai_source -i oai_set_id -m metadata_format");
|
||||
System.out.println(
|
||||
"SETUP a collection for harvesting: Harvest -s -c collection -t harvest_type -a oai_source -i " +
|
||||
"oai_set_id -m metadata_format");
|
||||
@@ -125,9 +121,6 @@ public class Harvest {
|
||||
if (line.hasOption('g')) {
|
||||
command = "ping";
|
||||
}
|
||||
if (line.hasOption('o')) {
|
||||
command = "runOnce";
|
||||
}
|
||||
if (line.hasOption('S')) {
|
||||
command = "start";
|
||||
}
|
||||
@@ -246,6 +239,10 @@ public class Harvest {
|
||||
}
|
||||
|
||||
pingResponder(oaiSource, oaiSetID, metadataKey);
|
||||
} else {
|
||||
System.out.println("Error - your command '" + command + "' was not recoginzed properly");
|
||||
System.out.println(" (run with -h flag for details)");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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.logic;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* The default filter, a very simple implementation of Filter / LogicalStatement
|
||||
* The idea is to have this as a wrapper / root class for all logical operations, so it takes a single
|
||||
* statement as a property (unlike an operator) and takes no parameters (unlike a condition)
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class DefaultFilter implements Filter {
|
||||
private LogicalStatement statement;
|
||||
private static Logger log = Logger.getLogger(Filter.class);
|
||||
|
||||
/**
|
||||
* Set statement from Spring configuration in item-filters.xml
|
||||
* Be aware that this is singular not plural. A filter can have one sub-statement only.
|
||||
*
|
||||
* @param statement LogicalStatement of this filter (operator, condition, or another filter)
|
||||
*/
|
||||
public void setStatement(LogicalStatement statement) {
|
||||
this.statement = statement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result of logical evaluation for an item
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
return this.statement.getResult(context, item);
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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.logic;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* The interface for Filter currently doesn't add anything to LogicalStatement but inherits from it
|
||||
* just to keep naming / reflection clean, and in case Filters should do anything additional in future.
|
||||
* We need this as filters have to be specified in the spring configuration (item-filters.xml).
|
||||
* Filters are the top level elements of the logic. Only logical statements that implement this interface
|
||||
* are allowed to be the root element of a spring configuration (item-filters.xml) of this logic framework.
|
||||
* A filter is just helping to differentiate between logical statement that can be used as root elements and
|
||||
* logical statement that shouldn't be use as root element. A filter may contain only one substatement.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
* @see org.dspace.content.logic.DefaultFilter
|
||||
*/
|
||||
public interface Filter extends LogicalStatement {
|
||||
/**
|
||||
* Get the result of logical evaluation for an item
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
boolean getResult(Context context, Item item) throws LogicalStatementException;
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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.logic;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* The base interface used by all logic classes: all operators and conditions are logical statements.
|
||||
* All statements must accept an Item object and return a boolean result.
|
||||
* The philosophy is that because Filter, Condition, Operator classes implement getResult(), they can all be
|
||||
* used as sub-statements in other Filters and Operators.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface LogicalStatement {
|
||||
/**
|
||||
* Get the result of logical evaluation for an item
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean result of evaluation
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
boolean getResult(Context context, Item item) throws LogicalStatementException;
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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.logic;
|
||||
|
||||
/**
|
||||
* Exception for errors encountered while evaluating logical statements
|
||||
* defined as spring beans.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class LogicalStatementException extends RuntimeException {
|
||||
|
||||
public LogicalStatementException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public LogicalStatementException(String s, Throwable t) {
|
||||
super(s, t);
|
||||
}
|
||||
|
||||
public LogicalStatementException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public LogicalStatementException(Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* 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.logic;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.cli.PosixParser;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.handle.factory.HandleServiceFactory;
|
||||
import org.dspace.handle.service.HandleService;
|
||||
import org.dspace.kernel.ServiceManager;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
|
||||
/**
|
||||
* A command-line runner used for testing a logical filter against an item, or all items
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class TestLogicRunner {
|
||||
|
||||
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(TestLogicRunner.class);
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
private TestLogicRunner() { }
|
||||
|
||||
/**
|
||||
* Main runner method for CLI usage
|
||||
* @param argv array of command-line arguments
|
||||
*/
|
||||
public static void main(String[] argv) {
|
||||
System.out.println("Starting impl of main() test spring logic item filter");
|
||||
|
||||
// initialize options
|
||||
Options options = new Options();
|
||||
|
||||
options.addOption("h", "help", false, "Help");
|
||||
options.addOption("l", "list", false, "List filters");
|
||||
options.addOption("f", "filter", true, "Use filter <filter>");
|
||||
options.addOption("i","item", true, "Run filter over item <handle>");
|
||||
options.addOption("a","all", false, "Run filter over all items");
|
||||
|
||||
// initialize parser
|
||||
CommandLineParser parser = new PosixParser();
|
||||
CommandLine line = null;
|
||||
HelpFormatter helpformater = new HelpFormatter();
|
||||
|
||||
try {
|
||||
line = parser.parse(options, argv);
|
||||
} catch (ParseException ex) {
|
||||
System.out.println(ex.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if (line.hasOption("help")) {
|
||||
helpformater.printHelp("\nTest the DSpace logical item filters\n", options);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
// Create a context
|
||||
Context c = new Context(Context.Mode.READ_ONLY);
|
||||
//c.turnOffAuthorisationSystem();
|
||||
ServiceManager manager = DSpaceServicesFactory.getInstance().getServiceManager();
|
||||
|
||||
if (line.hasOption("list")) {
|
||||
// Lit filters and exit
|
||||
List<Filter> filters = manager.getServicesByType(Filter.class);
|
||||
for (Filter filter : filters) {
|
||||
System.out.println(filter.getClass().toString());
|
||||
}
|
||||
System.out.println("See item-filters.xml spring config for filter names");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
Filter filter;
|
||||
|
||||
if (line.hasOption("filter")) {
|
||||
String filterName = line.getOptionValue("filter");
|
||||
filter = manager.getServiceByName(filterName, Filter.class);
|
||||
if (filter == null) {
|
||||
System.out.println("Error loading filter: " + filterName);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if (line.hasOption("item")) {
|
||||
String handle = line.getOptionValue("item");
|
||||
|
||||
HandleService handleService = HandleServiceFactory.getInstance().getHandleService();
|
||||
try {
|
||||
DSpaceObject dso = handleService.resolveToObject(c, handle);
|
||||
if (Constants.typeText[dso.getType()].equals("ITEM")) {
|
||||
Item item = (Item) dso;
|
||||
System.out.println(filter.getResult(c, item));
|
||||
} else {
|
||||
System.out.println(handle + " is not an ITEM");
|
||||
}
|
||||
} catch (SQLException | LogicalStatementException e) {
|
||||
System.out.println("Error encountered processing item " + handle + ": " + e.getMessage());
|
||||
}
|
||||
|
||||
} else if (line.hasOption("all")) {
|
||||
ItemService itemService = ContentServiceFactory.getInstance().getItemService();
|
||||
try {
|
||||
Iterator<Item> itemIterator = itemService.findAll(c);
|
||||
while (itemIterator.hasNext()) {
|
||||
Item i = itemIterator.next();
|
||||
System.out.println(
|
||||
"Testing '" + filter + "' on item " + i.getHandle() + " ('" + i.getName() + "')"
|
||||
);
|
||||
System.out.println(filter.getResult(c, i));
|
||||
|
||||
}
|
||||
} catch (SQLException | LogicalStatementException e) {
|
||||
System.out.println("Error encountered processing items: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
helpformater.printHelp("\nTest the DSpace logical item filters\n", options);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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.logic.condition;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.handle.service.HandleService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Abstract class for conditions, to implement the basic getter and setter parameters
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public abstract class AbstractCondition implements Condition {
|
||||
|
||||
// Parameters map (injected, required -- see setter annotation)
|
||||
private Map<String, Object> parameters;
|
||||
|
||||
// Declare and instantiate spring services
|
||||
//@Autowired(required = true)
|
||||
protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
|
||||
//@Autowired(required = true)
|
||||
protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
|
||||
@Autowired(required = true)
|
||||
protected HandleService handleService;
|
||||
|
||||
// Logging
|
||||
Logger log = LogManager.getLogger(AbstractCondition.class);
|
||||
|
||||
/**
|
||||
* Get parameters set by spring configuration in item-filters.xml
|
||||
* These could be any kind of map that the extending condition class needs for evaluation
|
||||
* @return map of parameters
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getParameters() throws LogicalStatementException {
|
||||
return this.parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set parameters - used by Spring when creating beans from item-filters.xml
|
||||
* These could be any kind of map that the extending condition class needs for evaluation
|
||||
* @param parameters
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Autowired(required = true)
|
||||
@Override
|
||||
public void setParameters(Map<String, Object> parameters) throws LogicalStatementException {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result of logical evaluation for an item
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
if (item == null) {
|
||||
log.error("Error evaluating item. Passed item is null, returning false");
|
||||
return false;
|
||||
}
|
||||
if (context == null) {
|
||||
throw new IllegalStateException("Context is null");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItemService(ItemService itemService) {
|
||||
this.itemService = itemService;
|
||||
}
|
||||
}
|
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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.logic.condition;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.content.Bundle;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* A condition to evaluate an item based on how many bitstreams it has in a particular bundle
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class BitstreamCountCondition extends AbstractCondition {
|
||||
/**
|
||||
* Return true if bitstream count is within bounds of min and/or max parameters
|
||||
* Return false if out of bounds
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean result of evaluation
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
|
||||
// This super call just throws some useful exceptions if required objects are null
|
||||
super.getResult(context, item);
|
||||
|
||||
int min = -1;
|
||||
if (getParameters().get("min") != null) {
|
||||
min = Integer.parseInt((String)getParameters().get("min"));
|
||||
}
|
||||
int max = -1;
|
||||
if (getParameters().get("max") != null) {
|
||||
max = Integer.parseInt((String)getParameters().get("max"));
|
||||
}
|
||||
String bundleName = (String)getParameters().get("bundle");
|
||||
if (min < 0 && max < 0) {
|
||||
throw new LogicalStatementException("Either min or max parameter must be 0 or bigger.");
|
||||
}
|
||||
|
||||
List<Bundle> bundles;
|
||||
int count = 0;
|
||||
|
||||
if (bundleName != null) {
|
||||
bundles = item.getBundles(bundleName);
|
||||
} else {
|
||||
bundles = item.getBundles();
|
||||
}
|
||||
|
||||
for (Bundle bundle : bundles) {
|
||||
count += bundle.getBitstreams().size();
|
||||
}
|
||||
|
||||
if (min < 0) {
|
||||
return (count <= max);
|
||||
}
|
||||
if (max < 0) {
|
||||
return (count >= min);
|
||||
}
|
||||
return (count <= max && count >= min);
|
||||
}
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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.logic.condition;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.logic.LogicalStatement;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* The Condition interface
|
||||
*
|
||||
* A condition is one logical statement testing an item for any idea. A condition is always a logical statements. An
|
||||
* operator is not a condition but also a logical statement.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public interface Condition extends LogicalStatement {
|
||||
|
||||
/**
|
||||
* Set parameters - used by Spring
|
||||
* @param parameters
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
void setParameters(Map<String, Object> parameters) throws LogicalStatementException;
|
||||
|
||||
/**
|
||||
* Get parameters set by Spring in item-filters.xml
|
||||
* These could be any kind of map that the extending condition class needs for evaluation
|
||||
* @return map of parameters
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
Map<String, Object> getParameters() throws LogicalStatementException;
|
||||
|
||||
/**
|
||||
* Get the result of logical evaluation for an item
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
boolean getResult(Context context, Item item) throws LogicalStatementException;
|
||||
|
||||
public void setItemService(ItemService itemService);
|
||||
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* 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.logic.condition;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* A condition that accepts a list of collection handles and returns true
|
||||
* if the item belongs to any of them.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class InCollectionCondition extends AbstractCondition {
|
||||
private static Logger log = LogManager.getLogger(InCollectionCondition.class);
|
||||
|
||||
/**
|
||||
* Return true if item is in one of the specified collections
|
||||
* Return false if not
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean result of evaluation
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
|
||||
List<String> collectionHandles = (List<String>)getParameters().get("collections");
|
||||
|
||||
// Look for the handle among an archived item's collections - this test will only work after submission
|
||||
// and archival is complete
|
||||
List<Collection> itemCollections = item.getCollections();
|
||||
for (Collection collection : itemCollections) {
|
||||
if (collectionHandles.contains(collection.getHandle())) {
|
||||
log.debug("item " + item.getHandle() + " is in collection "
|
||||
+ collection.getHandle() + ", returning true");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Look for the parent object of the item. This is important as the item.getOwningCollection method
|
||||
// may return null, even though the item itself does have a parent object, at the point of archival
|
||||
try {
|
||||
DSpaceObject parent = itemService.getParentObject(context, item);
|
||||
if (parent != null) {
|
||||
log.debug("Got parent DSO for item: " + parent.getID().toString());
|
||||
log.debug("Parent DSO handle: " + parent.getHandle());
|
||||
if (collectionHandles.contains(parent.getHandle())) {
|
||||
log.debug("item " + item.getHandle() + " is in collection "
|
||||
+ parent.getHandle() + ", returning true");
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
log.debug("Parent DSO is null...");
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error("Error obtaining parent DSO", e);
|
||||
throw new LogicalStatementException(e);
|
||||
}
|
||||
|
||||
// If we reach this statement, the item did not appear in any of the collections from the parameters
|
||||
log.debug("item " + item.getHandle() + " not found in the passed collection handle list");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* 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.logic.condition;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* A condition that accepts a list of community handles and returns true
|
||||
* if the item belongs to any of them.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class InCommunityCondition extends AbstractCondition {
|
||||
private static Logger log = Logger.getLogger(InCommunityCondition.class);
|
||||
|
||||
/**
|
||||
* Return true if item is in one of the specified collections
|
||||
* Return false if not
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean result of evaluation
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
|
||||
List<String> communityHandles = (List<String>)getParameters().get("communities");
|
||||
List<Collection> itemCollections = item.getCollections();
|
||||
|
||||
// Check communities of item.getCollections() - this will only see collections if the item is archived
|
||||
for (Collection collection : itemCollections) {
|
||||
try {
|
||||
List<Community> communities = collection.getCommunities();
|
||||
for (Community community : communities) {
|
||||
if (communityHandles.contains(community.getHandle())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new LogicalStatementException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Look for the parent object of the item. This is important as the item.getOwningCollection method
|
||||
// may return null, even though the item itself does have a parent object, at the point of archival
|
||||
try {
|
||||
DSpaceObject parent = itemService.getParentObject(context, item);
|
||||
if (parent instanceof Collection) {
|
||||
log.debug("Got parent DSO for item: " + parent.getID().toString());
|
||||
log.debug("Parent DSO handle: " + parent.getHandle());
|
||||
try {
|
||||
// Now iterate communities of this parent collection
|
||||
Collection collection = (Collection)parent;
|
||||
List<Community> communities = collection.getCommunities();
|
||||
for (Community community : communities) {
|
||||
if (communityHandles.contains(community.getHandle())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new LogicalStatementException(e);
|
||||
}
|
||||
} else {
|
||||
log.debug("Parent DSO is null or is not a Collection...");
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error("Error obtaining parent DSO", e);
|
||||
throw new LogicalStatementException(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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.logic.condition;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* A condition that returns true if the item is withdrawn
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class IsWithdrawnCondition extends AbstractCondition {
|
||||
private static Logger log = Logger.getLogger(IsWithdrawnCondition.class);
|
||||
|
||||
/**
|
||||
* Return true if item is withdrawn
|
||||
* Return false if not
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean result of evaluation
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
log.debug("Result of isWithdrawn is " + item.isWithdrawn());
|
||||
return item.isWithdrawn();
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 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.logic.condition;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* A condition that returns true if a pattern (regex) matches any value
|
||||
* in a given metadata field
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class MetadataValueMatchCondition extends AbstractCondition {
|
||||
|
||||
private static Logger log = Logger.getLogger(MetadataValueMatchCondition.class);
|
||||
|
||||
/**
|
||||
* Return true if any value for a specified field in the item matches a specified regex pattern
|
||||
* Return false if not
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean result of evaluation
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
String field = (String)getParameters().get("field");
|
||||
if (field == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String[] fieldParts = field.split("\\.");
|
||||
String schema = (fieldParts.length > 0 ? fieldParts[0] : null);
|
||||
String element = (fieldParts.length > 1 ? fieldParts[1] : null);
|
||||
String qualifier = (fieldParts.length > 2 ? fieldParts[2] : null);
|
||||
|
||||
List<MetadataValue> values = itemService.getMetadata(item, schema, element, qualifier, Item.ANY);
|
||||
for (MetadataValue value : values) {
|
||||
if (getParameters().get("pattern") instanceof String) {
|
||||
String pattern = (String)getParameters().get("pattern");
|
||||
log.debug("logic for " + item.getHandle() + ": pattern passed is " + pattern
|
||||
+ ", checking value " + value.getValue());
|
||||
Pattern p = Pattern.compile(pattern);
|
||||
Matcher m = p.matcher(value.getValue());
|
||||
if (m.find()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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.logic.condition;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* A condition that returns true if any pattern in a list of patterns matches any value
|
||||
* in a given metadata field
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class MetadataValuesMatchCondition extends AbstractCondition {
|
||||
|
||||
private static Logger log = Logger.getLogger(MetadataValuesMatchCondition.class);
|
||||
|
||||
/**
|
||||
* Return true if any value for a specified field in the item matches any of the specified regex patterns
|
||||
* Return false if not
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean result of evaluation
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
String field = (String)getParameters().get("field");
|
||||
if (field == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String[] fieldParts = field.split("\\.");
|
||||
String schema = (fieldParts.length > 0 ? fieldParts[0] : null);
|
||||
String element = (fieldParts.length > 1 ? fieldParts[1] : null);
|
||||
String qualifier = (fieldParts.length > 2 ? fieldParts[2] : null);
|
||||
|
||||
List<MetadataValue> values = itemService.getMetadata(item, schema, element, qualifier, Item.ANY);
|
||||
for (MetadataValue value : values) {
|
||||
if (getParameters().get("patterns") instanceof List) {
|
||||
List<String> patternList = (List<String>)getParameters().get("patterns");
|
||||
// If the list is empty, just return true and log error?
|
||||
log.error("No patterns were passed for metadata value matching, defaulting to 'true'");
|
||||
if (patternList == null) {
|
||||
return true;
|
||||
}
|
||||
for (String pattern : patternList) {
|
||||
log.debug("logic for " + item.getHandle() + ": pattern passed is " + pattern
|
||||
+ ", checking value " + value.getValue());
|
||||
Pattern p = Pattern.compile(pattern);
|
||||
Matcher m = p.matcher(value.getValue());
|
||||
if (m.find()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 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.logic.condition;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.authorize.ResourcePolicy;
|
||||
import org.dspace.authorize.factory.AuthorizeServiceFactory;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* A condition that accepts a group and action parameter and returns true if the group
|
||||
* can perform the action on a given item
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class ReadableByGroupCondition extends AbstractCondition {
|
||||
private static Logger log = Logger.getLogger(ReadableByGroupCondition.class);
|
||||
|
||||
// Authorize service
|
||||
AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
|
||||
|
||||
/**
|
||||
* Return true if this item allows a specified action (eg READ, WRITE, ADD) by a specified group
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean result of evaluation
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
|
||||
String group = (String)getParameters().get("group");
|
||||
String action = (String)getParameters().get("action");
|
||||
|
||||
try {
|
||||
List<ResourcePolicy> policies = authorizeService
|
||||
.getPoliciesActionFilter(context, item, Constants.getActionID(action));
|
||||
for (ResourcePolicy policy : policies) {
|
||||
if (policy.getGroup().getName().equals(group)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error("Error trying to read policies for " + item.getHandle() + ": " + e.getMessage());
|
||||
throw new LogicalStatementException(e);
|
||||
}
|
||||
log.debug("item " + item.getHandle() + " not readable by anonymous group");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 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.logic.operator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.logic.LogicalStatement;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* Abstract class for an operator.
|
||||
* An operator contains a list of logical statements (conditions or more operators) and depending on the kind
|
||||
* of operator (AND, OR, NOT, etc.) the results of some or all sub-statements are evaluated and returned
|
||||
* as a logical result
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public abstract class AbstractOperator implements LogicalStatement {
|
||||
|
||||
private List<LogicalStatement> statements = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Get sub-statements for this operator
|
||||
* @return list of sub-statements
|
||||
*/
|
||||
public List<LogicalStatement> getStatements() {
|
||||
return statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set sub-statements for this operator, as defined in item-filters.xml
|
||||
* @param statements list of logical statements
|
||||
*/
|
||||
public void setStatements(List<LogicalStatement> statements) {
|
||||
this.statements = statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public AbstractOperator() {}
|
||||
|
||||
/**
|
||||
* Constructor to create operator from some predefined statements
|
||||
* @param statements
|
||||
*/
|
||||
public AbstractOperator(List<LogicalStatement> statements) {
|
||||
this.statements = statements;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean result of evaluation (of sub-statements)
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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.logic.operator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.logic.LogicalStatement;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* An operator that implements AND by evaluating sub-statements and only returning
|
||||
* true if all sub-statements return true
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class And extends AbstractOperator {
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public And() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that accepts predefined list of statements as defined in item-filters.xml
|
||||
* @param statements List of logical statements
|
||||
*/
|
||||
And(List<LogicalStatement> statements) {
|
||||
super(statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if ALL statements return true
|
||||
* Return false otherwise
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean result of AND
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
|
||||
for (LogicalStatement statement : getStatements()) {
|
||||
if (!statement.getResult(context, item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* 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.logic.operator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.logic.LogicalStatement;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* An operator that implements NAND by negating an AND operation
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class Nand extends AbstractOperator {
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public Nand() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that accepts predefined list of statements as defined in item-filters.xml
|
||||
* @param statements List of logical statements
|
||||
*/
|
||||
public Nand(List<LogicalStatement> statements) {
|
||||
super(statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the result of AND'ing all sub-statements is false (ie. a NOT(AND())
|
||||
* Return false if not
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean result of NAND
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
return !(new And(getStatements()).getResult(context, item));
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* 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.logic.operator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.logic.LogicalStatement;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* An operator that implements NIR by negating an OR operation
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class Nor extends AbstractOperator {
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public Nor() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that accepts predefined list of statements as defined in item-filters.xml
|
||||
* @param statements List of logical statements
|
||||
*/
|
||||
public Nor(List<LogicalStatement> statements) {
|
||||
super(statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the result of OR'ing the sub-statements is false
|
||||
* Return false otherwise
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean result of NOR
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
return !(new Or(getStatements()).getResult(context, item));
|
||||
}
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* 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.logic.operator;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.logic.LogicalStatement;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* An operator that implements NOT by simply negating a statement
|
||||
* Note that this operator doesn't actually implement the 'AbstractOperator' interface because
|
||||
* we only want one sub-statement. So it's actually just a simple implementation of LogicalStatement.
|
||||
* Not can have one sub-statement only, while and, or, nor, ... can have multiple sub-statements.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class Not implements LogicalStatement {
|
||||
|
||||
private LogicalStatement statement;
|
||||
|
||||
/**
|
||||
* Get sub-statement (note: singular! even though we keep the method name) for this operator
|
||||
* @return list of sub-statements
|
||||
*/
|
||||
public LogicalStatement getStatements() {
|
||||
return statement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set sub-statement (note: singular!) for this operator, as defined in item-filters.xml
|
||||
* @param statement a single statement to apply to NOT operation
|
||||
*/
|
||||
public void setStatements(LogicalStatement statement) {
|
||||
this.statement = statement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public Not() {}
|
||||
|
||||
/**
|
||||
* Constructor that accepts predefined list of statements as defined in item-filters.xml
|
||||
* @param statement Single logical statement
|
||||
*/
|
||||
public Not(LogicalStatement statement) {
|
||||
this.statement = statement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the result of the sub-statement is false
|
||||
* Return false otherwise
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean result of NOT
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
return !statement.getResult(context, item);
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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.logic.operator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.logic.LogicalStatement;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* An operator that implements OR by evaluating sub-statements and returns
|
||||
* true if one or more sub-statements return true
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class Or extends AbstractOperator {
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public Or() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that accepts predefined list of statements as defined in item-filters.xml
|
||||
* @param statements List of logical statements
|
||||
*/
|
||||
public Or(List<LogicalStatement> statements) {
|
||||
super(statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if any sub-statement returns true
|
||||
* Return false otherwise
|
||||
* @param context DSpace context
|
||||
* @param item Item to evaluate
|
||||
* @return boolean result of OR
|
||||
* @throws LogicalStatementException
|
||||
*/
|
||||
@Override
|
||||
public boolean getResult(Context context, Item item) throws LogicalStatementException {
|
||||
|
||||
for (LogicalStatement statement : getStatements()) {
|
||||
if (statement.getResult(context, item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -183,7 +183,7 @@ public class PackageUtils {
|
||||
Item item, Collection collection)
|
||||
throws SQLException, IOException, AuthorizeException {
|
||||
if (license == null) {
|
||||
license = collection.getLicenseCollection();
|
||||
license = collectionService.getLicense(collection);
|
||||
}
|
||||
InputStream lis = new ByteArrayInputStream(license.getBytes());
|
||||
|
||||
|
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* 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.ctask.general;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.curate.AbstractCurationTask;
|
||||
import org.dspace.curate.Curator;
|
||||
import org.dspace.identifier.DOIIdentifierProvider;
|
||||
import org.dspace.identifier.IdentifierException;
|
||||
import org.dspace.identifier.doi.DOIIdentifierNotApplicableException;
|
||||
import org.dspace.utils.DSpace;
|
||||
|
||||
/**
|
||||
* This curation task will register a DOI for an item, optionally ignoring any logical filtering applied
|
||||
* to normal identifier registration and DOI service operation.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
*/
|
||||
public class RegisterDOI extends AbstractCurationTask {
|
||||
// Curation task status
|
||||
private int status = Curator.CURATE_SUCCESS;
|
||||
// The skipFilter boolean has a default value of 'true', as per intended operation
|
||||
private boolean skipFilter = true;
|
||||
// The distributed boolean has a default value of 'false' for safest operation
|
||||
private boolean distributed = false;
|
||||
// Prefix for configuration module
|
||||
private static final String PLUGIN_PREFIX = "doi-curation";
|
||||
// Logger
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(RegisterDOI.class);
|
||||
// DOI provider
|
||||
private DOIIdentifierProvider provider;
|
||||
|
||||
/**
|
||||
* Initialise the curation task and read configuration, instantiate the DOI provider
|
||||
*/
|
||||
@Override
|
||||
public void init(Curator curator, String taskId) throws IOException {
|
||||
super.init(curator, taskId);
|
||||
// Get 'skip filter' behaviour from configuration, with a default value of 'true'
|
||||
skipFilter = configurationService.getBooleanProperty(PLUGIN_PREFIX + ".skip-filter", true);
|
||||
// Get distribution behaviour from configuration, with a default value of 'false'
|
||||
distributed = configurationService.getBooleanProperty(PLUGIN_PREFIX + ".distributed", false);
|
||||
log.debug("PLUGIN_PREFIX = " + PLUGIN_PREFIX + ", skipFilter = " + skipFilter +
|
||||
", distributed = " + distributed);
|
||||
// Instantiate DOI provider singleton
|
||||
provider = new DSpace().getSingletonService(DOIIdentifierProvider.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the abstract 'perform' method to either distribute, or perform single-item
|
||||
* depending on configuration. By default, the task is *not* distributed, since that could be unsafe
|
||||
* and the original purpose of this task is to essentially implement a "Register DOI" button on the Edit Item page.
|
||||
* @param dso DSpaceObject for which to register a DOI (must be item)
|
||||
* @return status indicator
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public int perform(DSpaceObject dso) throws IOException {
|
||||
// Check distribution configuration
|
||||
if (distributed) {
|
||||
// This task is configured for distributed use. Call distribute() and let performItem handle
|
||||
// the main processing.
|
||||
distribute(dso);
|
||||
} else {
|
||||
// This task is NOT configured for distributed use (default). Instead process a single item directly
|
||||
if (dso instanceof Item) {
|
||||
Item item = (Item) dso;
|
||||
performRegistration(item);
|
||||
} else {
|
||||
log.warn("DOI registration attempted on non-item DSpace Object: " + dso.getID());
|
||||
}
|
||||
return status;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when the task is distributed (ie. called on a set of items or over a whole structure)
|
||||
* @param item the DSpace Item
|
||||
*/
|
||||
@Override
|
||||
protected void performItem(Item item) {
|
||||
performRegistration(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared 'perform' code between perform() and performItem() - a curation wrapper for the register() method
|
||||
* @param item the item for which to register a DOI
|
||||
*/
|
||||
private void performRegistration(Item item) {
|
||||
// Request DOI registration and report results
|
||||
String doi = register(item);
|
||||
String result = "DOI registration task performed on " + item.getHandle() + ".";
|
||||
if (doi != null) {
|
||||
result += " DOI: (" + doi + ")";
|
||||
} else {
|
||||
result += " DOI was null, either item was filtered or an error was encountered.";
|
||||
}
|
||||
setResult(result);
|
||||
report(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the DOIIdentifierProvider.register call, with skipFilter passed as per config and defaults
|
||||
* @param item The item for which to register a DOI
|
||||
*/
|
||||
private String register(Item item) {
|
||||
String doi = null;
|
||||
// Attempt DOI registration and report successes and failures
|
||||
try {
|
||||
log.debug("Registering DOI with skipFilter = " + skipFilter);
|
||||
doi = provider.register(Curator.curationContext(), item, skipFilter);
|
||||
if (doi != null) {
|
||||
String message = "New DOI minted in database for item " + item.getHandle() + ": " + doi
|
||||
+ ". This DOI will be registered online with the DOI provider when the queue is next run";
|
||||
report(message);
|
||||
} else {
|
||||
log.error("Got a null DOI after registering...");
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
// Exception obtaining context
|
||||
log.error("Error obtaining curator context: " + e.getMessage());
|
||||
status = Curator.CURATE_ERROR;
|
||||
} catch (DOIIdentifierNotApplicableException e) {
|
||||
// Filter returned 'false' so DOI was not registered. This is normal behaviour when filter is running.
|
||||
log.info("Item was filtered from DOI registration: " + e.getMessage());
|
||||
String message = "Item " + item.getHandle() + " was skipped from DOI registration because it matched " +
|
||||
"the item filter configured in identifier-services.xml.";
|
||||
report(message);
|
||||
status = Curator.CURATE_SUCCESS;
|
||||
} catch (IdentifierException e) {
|
||||
// Any other identifier exception is probably a true error
|
||||
log.error("Error registering identifier: " + e.getMessage());
|
||||
status = Curator.CURATE_ERROR;
|
||||
}
|
||||
|
||||
return doi;
|
||||
}
|
||||
|
||||
}
|
@@ -37,7 +37,6 @@ import org.hibernate.proxy.HibernateProxyHelper;
|
||||
* Class representing an e-person.
|
||||
*
|
||||
* @author David Stuve
|
||||
* @version $Revision$
|
||||
*/
|
||||
@Entity
|
||||
@Cacheable
|
||||
@@ -381,6 +380,13 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport {
|
||||
return digestAlgorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the digest algorithm used to hash the password. You should also
|
||||
* set the {@link setPassword password hash} and the
|
||||
* {@link setDigestAlgorithm digest algorithm}.
|
||||
*
|
||||
* @param digestAlgorithm
|
||||
*/
|
||||
void setDigestAlgorithm(String digestAlgorithm) {
|
||||
this.digestAlgorithm = digestAlgorithm;
|
||||
}
|
||||
@@ -389,6 +395,13 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport {
|
||||
return salt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the salt used when hashing the password. You should also set the
|
||||
* {@link setPassword password hash} and the {@link setDigestAlgorithm
|
||||
* digest algorithm}.
|
||||
*
|
||||
* @param salt
|
||||
*/
|
||||
void setSalt(String salt) {
|
||||
this.salt = salt;
|
||||
}
|
||||
@@ -397,6 +410,12 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the <strong>hash of a</strong> password. You should also set the
|
||||
* {@link setSalt salt} and the {@link setDigestAlgorithm digest algorithm}.
|
||||
*
|
||||
* @param password
|
||||
*/
|
||||
void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@ import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -28,6 +29,8 @@ import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||
import org.dspace.eperson.service.EPersonService;
|
||||
import org.dspace.util.ConsoleService;
|
||||
import org.dspace.util.ConsoleServiceImpl;
|
||||
|
||||
public class EPersonCLITool {
|
||||
|
||||
@@ -57,13 +60,22 @@ public class EPersonCLITool {
|
||||
|
||||
private static final Option OPT_NEW_EMAIL = new Option("i", "newEmail", true, "new email address");
|
||||
private static final Option OPT_NEW_NETID = new Option("I", "newNetid", true, "new network ID");
|
||||
private static final Option OPT_NEW_PASSWORD
|
||||
= new Option("w", "newPassword", false, "prompt for new password");
|
||||
|
||||
private static final EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
|
||||
static final String ERR_PASSWORD_EMPTY = "The new password may not be empty.";
|
||||
static final String ERR_PASSWORD_NOMATCH = "Passwords do not match. Password not set";
|
||||
|
||||
private static final EPersonService ePersonService
|
||||
= EPersonServiceFactory.getInstance().getEPersonService();
|
||||
|
||||
private static ConsoleService consoleService
|
||||
= new ConsoleServiceImpl();
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
private EPersonCLITool() { }
|
||||
EPersonCLITool() { }
|
||||
|
||||
/**
|
||||
* Tool for manipulating user accounts.
|
||||
@@ -110,7 +122,6 @@ public class EPersonCLITool {
|
||||
new HelpFormatter().printHelp("user [options]", globalOptions);
|
||||
context.abort();
|
||||
status = 1;
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
if (context.isValid()) {
|
||||
@@ -120,6 +131,8 @@ public class EPersonCLITool {
|
||||
System.err.println(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
System.exit(status);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,11 +190,11 @@ public class EPersonCLITool {
|
||||
EPerson eperson = null;
|
||||
try {
|
||||
eperson = ePersonService.create(context);
|
||||
} catch (SQLException ex) {
|
||||
} catch (SQLException | AuthorizeException ex) {
|
||||
context.abort();
|
||||
System.err.println(ex.getMessage());
|
||||
return 1;
|
||||
} catch (AuthorizeException ex) { /* XXX SNH */ }
|
||||
}
|
||||
eperson.setCanLogIn(true);
|
||||
eperson.setSelfRegistered(false);
|
||||
|
||||
@@ -204,11 +217,11 @@ public class EPersonCLITool {
|
||||
try {
|
||||
ePersonService.update(context, eperson);
|
||||
System.out.printf("Created EPerson %s\n", eperson.getID().toString());
|
||||
} catch (SQLException ex) {
|
||||
} catch (SQLException | AuthorizeException ex) {
|
||||
context.abort();
|
||||
System.err.println(ex.getMessage());
|
||||
return 1;
|
||||
} catch (AuthorizeException ex) { /* XXX SNH */ }
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -315,6 +328,7 @@ public class EPersonCLITool {
|
||||
options.addOption(OPT_CAN_LOGIN);
|
||||
options.addOption(OPT_NEW_EMAIL);
|
||||
options.addOption(OPT_NEW_NETID);
|
||||
options.addOption(OPT_NEW_PASSWORD);
|
||||
|
||||
options.addOption("h", "help", false, "explain --modify options");
|
||||
|
||||
@@ -334,11 +348,14 @@ public class EPersonCLITool {
|
||||
|
||||
// Modify!
|
||||
EPerson eperson = null;
|
||||
String userName = null;
|
||||
try {
|
||||
if (command.hasOption(OPT_NETID.getOpt())) {
|
||||
eperson = ePersonService.findByNetid(context, command.getOptionValue(OPT_NETID.getOpt()));
|
||||
userName = command.getOptionValue(OPT_NETID.getOpt());
|
||||
eperson = ePersonService.findByNetid(context, userName);
|
||||
} else if (command.hasOption(OPT_EMAIL.getOpt())) {
|
||||
eperson = ePersonService.findByEmail(context, command.getOptionValue(OPT_EMAIL.getOpt()));
|
||||
userName = command.getOptionValue(OPT_EMAIL.getOpt());
|
||||
eperson = ePersonService.findByEmail(context, userName);
|
||||
} else {
|
||||
System.err.println("No EPerson selected");
|
||||
return 1;
|
||||
@@ -361,6 +378,25 @@ public class EPersonCLITool {
|
||||
eperson.setNetid(command.getOptionValue(OPT_NEW_NETID.getOpt()));
|
||||
modified = true;
|
||||
}
|
||||
if (command.hasOption(OPT_NEW_PASSWORD.getOpt())) {
|
||||
char[] password1 = consoleService.readPassword(
|
||||
"Enter new password for user '%s': ", userName);
|
||||
char[] password2 = consoleService.readPassword(
|
||||
"Enter new password again to verify: ");
|
||||
if (password1.length <= 0 || password2.length <= 0) {
|
||||
System.err.println(ERR_PASSWORD_EMPTY);
|
||||
} else if (Arrays.equals(password1, password2)) {
|
||||
PasswordHash newHashedPassword = new PasswordHash(String.valueOf(password1));
|
||||
Arrays.fill(password1, '\0'); // Obliterate cleartext passwords
|
||||
Arrays.fill(password2, '\0');
|
||||
eperson.setPassword(newHashedPassword.getHashString());
|
||||
eperson.setSalt(newHashedPassword.getSaltString());
|
||||
eperson.setDigestAlgorithm(newHashedPassword.getAlgorithm());
|
||||
modified = true;
|
||||
} else {
|
||||
System.err.println(ERR_PASSWORD_NOMATCH);
|
||||
}
|
||||
}
|
||||
if (command.hasOption(OPT_GIVENNAME.getOpt())) {
|
||||
eperson.setFirstName(context, command.getOptionValue(OPT_GIVENNAME.getOpt()));
|
||||
modified = true;
|
||||
@@ -387,15 +423,16 @@ public class EPersonCLITool {
|
||||
eperson.setCanLogIn(Boolean.valueOf(command.getOptionValue(OPT_CAN_LOGIN.getOpt())));
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (modified) {
|
||||
try {
|
||||
ePersonService.update(context, eperson);
|
||||
System.out.printf("Modified EPerson %s\n", eperson.getID().toString());
|
||||
} catch (SQLException ex) {
|
||||
} catch (SQLException | AuthorizeException ex) {
|
||||
context.abort();
|
||||
System.err.println(ex.getMessage());
|
||||
return 1;
|
||||
} catch (AuthorizeException ex) { /* XXX SNH */ }
|
||||
}
|
||||
} else {
|
||||
System.out.println("No changes.");
|
||||
}
|
||||
@@ -407,6 +444,7 @@ public class EPersonCLITool {
|
||||
/**
|
||||
* Command to list known EPersons.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static int cmdList(Context context, String[] argv) {
|
||||
// XXX ideas:
|
||||
// specific user/netid
|
||||
@@ -427,4 +465,13 @@ public class EPersonCLITool {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the ConsoleService for testing.
|
||||
*
|
||||
* @param service new ConsoleService to be used henceforth.
|
||||
*/
|
||||
void setConsoleService(ConsoleService service) {
|
||||
consoleService = service;
|
||||
}
|
||||
}
|
||||
|
@@ -19,11 +19,14 @@ import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.logic.Filter;
|
||||
import org.dspace.content.logic.LogicalStatementException;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.identifier.doi.DOIConnector;
|
||||
import org.dspace.identifier.doi.DOIIdentifierException;
|
||||
import org.dspace.identifier.doi.DOIIdentifierNotApplicableException;
|
||||
import org.dspace.identifier.service.DOIService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -42,8 +45,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
*
|
||||
* @author Pascal-Nicolas Becker
|
||||
*/
|
||||
public class DOIIdentifierProvider
|
||||
extends IdentifierProvider {
|
||||
public class DOIIdentifierProvider extends FilteredIdentifierProvider {
|
||||
private static final Logger log = LoggerFactory.getLogger(DOIIdentifierProvider.class);
|
||||
|
||||
/**
|
||||
@@ -87,6 +89,11 @@ public class DOIIdentifierProvider
|
||||
@Autowired(required = true)
|
||||
protected ItemService itemService;
|
||||
|
||||
protected Filter filterService;
|
||||
|
||||
/**
|
||||
* Empty / default constructor for Spring
|
||||
*/
|
||||
protected DOIIdentifierProvider() {
|
||||
}
|
||||
|
||||
@@ -103,6 +110,10 @@ public class DOIIdentifierProvider
|
||||
*/
|
||||
private String NAMESPACE_SEPARATOR;
|
||||
|
||||
/**
|
||||
* Get DOI prefix from configuration
|
||||
* @return a String containing the DOI prefix
|
||||
*/
|
||||
protected String getPrefix() {
|
||||
if (null == this.PREFIX) {
|
||||
this.PREFIX = this.configurationService.getProperty(CFG_PREFIX);
|
||||
@@ -116,6 +127,10 @@ public class DOIIdentifierProvider
|
||||
return this.PREFIX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get namespace separator from configuration
|
||||
* @return a String containing the namespace separator
|
||||
*/
|
||||
protected String getNamespaceSeparator() {
|
||||
if (null == this.NAMESPACE_SEPARATOR) {
|
||||
this.NAMESPACE_SEPARATOR = this.configurationService.getProperty(CFG_NAMESPACE_SEPARATOR);
|
||||
@@ -126,11 +141,27 @@ public class DOIIdentifierProvider
|
||||
return this.NAMESPACE_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DOI connector, which is the component that commuincates with the remote registration service
|
||||
* (eg. DataCite, EZID, Crossref)
|
||||
* Spring will use this setter to set the DOI connector from the configured property in identifier-services.xml
|
||||
*
|
||||
* @param connector a DOIConnector
|
||||
*/
|
||||
@Autowired(required = true)
|
||||
public void setDOIConnector(DOIConnector connector) {
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Filter to use when testing items to see if a DOI should be registered
|
||||
* Spring will use this setter to set the filter from the configured property in identifier-services.xml
|
||||
* @param filterService - an object implementing the org.dspace.content.logic.Filter interface
|
||||
*/
|
||||
public void setFilterService(Filter filterService) {
|
||||
this.filterService = filterService;
|
||||
}
|
||||
|
||||
/**
|
||||
* This identifier provider supports identifiers of type
|
||||
* {@link org.dspace.identifier.DOI}.
|
||||
@@ -164,23 +195,65 @@ public class DOIIdentifierProvider
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register a new identifier for a given DSpaceObject, never skipping or ignoring any configured filter
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject to use for identifier registration
|
||||
* @return identifier
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
@Override
|
||||
public String register(Context context, DSpaceObject dso)
|
||||
throws IdentifierException {
|
||||
return register(context, dso, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a specified DOI for a given DSpaceObject, never skipping or ignoring any configured filter
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by the new DOI
|
||||
* @param identifier - String containing the identifier to register
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
@Override
|
||||
public void register(Context context, DSpaceObject dso, String identifier)
|
||||
throws IdentifierException {
|
||||
register(context, dso, identifier, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new DOI for a given DSpaceObject
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by the new DOI
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
@Override
|
||||
public String register(Context context, DSpaceObject dso, boolean skipFilter)
|
||||
throws IdentifierException {
|
||||
if (!(dso instanceof Item)) {
|
||||
// DOI are currently assigned only to Item
|
||||
return null;
|
||||
}
|
||||
String doi = mint(context, dso);
|
||||
|
||||
String doi = mint(context, dso, skipFilter);
|
||||
|
||||
// register tries to reserve doi if it's not already.
|
||||
// So we don't have to reserve it here.
|
||||
register(context, dso, doi);
|
||||
register(context, dso, doi, skipFilter);
|
||||
return doi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a specified DOI for a given DSpaceObject
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by the new DOI
|
||||
* @param identifier - String containing the DOI to register
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
@Override
|
||||
public void register(Context context, DSpaceObject dso, String identifier)
|
||||
public void register(Context context, DSpaceObject dso, String identifier, boolean skipFilter)
|
||||
throws IdentifierException {
|
||||
if (!(dso instanceof Item)) {
|
||||
// DOI are currently assigned only to Item
|
||||
@@ -191,7 +264,7 @@ public class DOIIdentifierProvider
|
||||
|
||||
// search DOI in our db
|
||||
try {
|
||||
doiRow = loadOrCreateDOI(context, dso, doi);
|
||||
doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
|
||||
} catch (SQLException ex) {
|
||||
log.error("Error in databse connection: " + ex.getMessage());
|
||||
throw new RuntimeException("Error in database conncetion.", ex);
|
||||
@@ -234,6 +307,22 @@ public class DOIIdentifierProvider
|
||||
*/
|
||||
@Override
|
||||
public void reserve(Context context, DSpaceObject dso, String identifier)
|
||||
throws IdentifierException, IllegalArgumentException {
|
||||
reserve(context, dso, identifier, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve a specified DOI for a given DSpaceObject
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by this DOI
|
||||
* @param identifier - String containing the DOI to reserve
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing reservation
|
||||
* @throws IdentifierException
|
||||
* @throws IllegalArgumentException
|
||||
* @throws SQLException
|
||||
*/
|
||||
@Override
|
||||
public void reserve(Context context, DSpaceObject dso, String identifier, boolean skipFilter)
|
||||
throws IdentifierException, IllegalArgumentException {
|
||||
String doi = doiService.formatIdentifier(identifier);
|
||||
DOI doiRow = null;
|
||||
@@ -241,7 +330,7 @@ public class DOIIdentifierProvider
|
||||
try {
|
||||
// if the doi is in our db already loadOrCreateDOI just returns.
|
||||
// if it is not loadOrCreateDOI safes the doi.
|
||||
doiRow = loadOrCreateDOI(context, dso, doi);
|
||||
doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
|
||||
} catch (SQLException sqle) {
|
||||
throw new RuntimeException(sqle);
|
||||
}
|
||||
@@ -258,14 +347,37 @@ public class DOIIdentifierProvider
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual online / API interaction required to reserve the DOI online
|
||||
* always applying filters if they are configured
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by this DOI
|
||||
* @param identifier - String containing the DOI to reserve
|
||||
* @throws IdentifierException
|
||||
* @throws IllegalArgumentException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void reserveOnline(Context context, DSpaceObject dso, String identifier)
|
||||
throws IdentifierException, IllegalArgumentException, SQLException {
|
||||
reserveOnline(context, dso, identifier, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual online / API interaction required to reserve the DOI online
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by this DOI
|
||||
* @param identifier - String containing the DOI to reserve
|
||||
* @throws IdentifierException
|
||||
* @throws IllegalArgumentException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void reserveOnline(Context context, DSpaceObject dso, String identifier, boolean skipFilter)
|
||||
throws IdentifierException, IllegalArgumentException, SQLException {
|
||||
String doi = doiService.formatIdentifier(identifier);
|
||||
// get TableRow and ensure DOI belongs to dso regarding our db
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, doi);
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
|
||||
|
||||
if (DELETED.equals(doiRow.getStatus()) ||
|
||||
TO_BE_DELETED.equals(doiRow.getStatus())) {
|
||||
if (DELETED.equals(doiRow.getStatus()) || TO_BE_DELETED.equals(doiRow.getStatus())) {
|
||||
throw new DOIIdentifierException("You tried to reserve a DOI that "
|
||||
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
|
||||
}
|
||||
@@ -276,14 +388,41 @@ public class DOIIdentifierProvider
|
||||
doiService.update(context, doiRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual online / API interaction required to register the DOI online
|
||||
* always applying filters if they are configured
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by this DOI
|
||||
* @param identifier - String containing the DOI to register
|
||||
* @throws IdentifierException
|
||||
* @throws IllegalArgumentException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void registerOnline(Context context, DSpaceObject dso, String identifier)
|
||||
throws IdentifierException, IllegalArgumentException, SQLException {
|
||||
|
||||
registerOnline(context, dso, identifier, false);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual online / API interaction required to register the DOI online
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by this DOI
|
||||
* @param identifier - String containing the DOI to register
|
||||
* @throws IdentifierException
|
||||
* @throws IllegalArgumentException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void registerOnline(Context context, DSpaceObject dso, String identifier, boolean skipFilter)
|
||||
throws IdentifierException, IllegalArgumentException, SQLException {
|
||||
log.debug("registerOnline: skipFilter is " + skipFilter);
|
||||
|
||||
String doi = doiService.formatIdentifier(identifier);
|
||||
// get TableRow and ensure DOI belongs to dso regarding our db
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, doi);
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
|
||||
|
||||
if (DELETED.equals(doiRow.getStatus()) ||
|
||||
TO_BE_DELETED.equals(doiRow.getStatus())) {
|
||||
if (DELETED.equals(doiRow.getStatus()) || TO_BE_DELETED.equals(doiRow.getStatus())) {
|
||||
throw new DOIIdentifierException("You tried to register a DOI that "
|
||||
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
|
||||
}
|
||||
@@ -294,7 +433,7 @@ public class DOIIdentifierProvider
|
||||
} catch (DOIIdentifierException die) {
|
||||
// do we have to reserve DOI before we can register it?
|
||||
if (die.getCode() == DOIIdentifierException.RESERVE_FIRST) {
|
||||
this.reserveOnline(context, dso, identifier);
|
||||
this.reserveOnline(context, dso, identifier, skipFilter);
|
||||
connector.registerDOI(context, dso, doi);
|
||||
} else {
|
||||
throw die;
|
||||
@@ -314,13 +453,35 @@ public class DOIIdentifierProvider
|
||||
doiService.update(context, doiRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update metadata for a registered object
|
||||
* If the DOI for hte item already exists, *always* skip the filter since it should only be used for
|
||||
* allowing / disallowing reservation and registration, not metadata updates or deletions
|
||||
*
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by this DOI
|
||||
* @param identifier - String containing the DOI to reserve
|
||||
* @throws IdentifierException
|
||||
* @throws IllegalArgumentException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void updateMetadata(Context context, DSpaceObject dso, String identifier)
|
||||
throws IdentifierException, IllegalArgumentException, SQLException {
|
||||
String doi = doiService.formatIdentifier(identifier);
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, doi);
|
||||
|
||||
if (DELETED.equals(doiRow.getStatus()) ||
|
||||
TO_BE_DELETED.equals(doiRow.getStatus())) {
|
||||
String doi = doiService.formatIdentifier(identifier);
|
||||
|
||||
boolean skipFilter = false;
|
||||
|
||||
if (doiService.findDOIByDSpaceObject(context, dso) != null) {
|
||||
// We can skip the filter here since we know the DOI already exists for the item
|
||||
log.debug("updateMetadata: found DOIByDSpaceObject: " +
|
||||
doiService.findDOIByDSpaceObject(context, dso).getDoi());
|
||||
skipFilter = true;
|
||||
}
|
||||
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
|
||||
|
||||
if (DELETED.equals(doiRow.getStatus()) || TO_BE_DELETED.equals(doiRow.getStatus())) {
|
||||
throw new DOIIdentifierException("You tried to register a DOI that "
|
||||
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
|
||||
}
|
||||
@@ -338,6 +499,18 @@ public class DOIIdentifierProvider
|
||||
doiService.update(context, doiRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update metadata for a registered object in the DOI Connector to update the agency records
|
||||
* If the DOI for hte item already exists, *always* skip the filter since it should only be used for
|
||||
* allowing / disallowing reservation and registration, not metadata updates or deletions
|
||||
*
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by this DOI
|
||||
* @param identifier - String containing the DOI to reserve
|
||||
* @throws IdentifierException
|
||||
* @throws IllegalArgumentException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void updateMetadataOnline(Context context, DSpaceObject dso, String identifier)
|
||||
throws IdentifierException, SQLException {
|
||||
String doi = doiService.formatIdentifier(identifier);
|
||||
@@ -348,12 +521,10 @@ public class DOIIdentifierProvider
|
||||
doiRow = doiService.findByDoi(context, doi.substring(DOI.SCHEME.length()));
|
||||
} catch (SQLException sqle) {
|
||||
log.warn("SQLException while searching a DOI in our db.", sqle);
|
||||
throw new RuntimeException("Unable to retrieve information about " +
|
||||
"a DOI out of database.", sqle);
|
||||
throw new RuntimeException("Unable to retrieve information about a DOI out of database.", sqle);
|
||||
}
|
||||
if (null == doiRow) {
|
||||
log.error("Cannot update metadata for DOI {}: unable to find it in "
|
||||
+ "our db.", doi);
|
||||
log.error("Cannot update metadata for DOI {}: unable to find it in our db.", doi);
|
||||
throw new DOIIdentifierException("Unable to find DOI.",
|
||||
DOIIdentifierException.DOI_DOES_NOT_EXIST);
|
||||
}
|
||||
@@ -368,8 +539,7 @@ public class DOIIdentifierProvider
|
||||
DOIIdentifierException.MISMATCH);
|
||||
}
|
||||
|
||||
if (DELETED.equals(doiRow.getStatus()) ||
|
||||
TO_BE_DELETED.equals(doiRow.getStatus())) {
|
||||
if (DELETED.equals(doiRow.getStatus()) || TO_BE_DELETED.equals(doiRow.getStatus())) {
|
||||
throw new DOIIdentifierException("You tried to update the metadata"
|
||||
+ "of a DOI that is marked as DELETED.",
|
||||
DOIIdentifierException.DOI_IS_DELETED);
|
||||
@@ -388,38 +558,66 @@ public class DOIIdentifierProvider
|
||||
doiService.update(context, doiRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mint a new DOI in DSpace - this is usually the first step of registration
|
||||
* Always apply filters if they are configured
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by the new identifier
|
||||
* @return a String containing the new identifier
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
@Override
|
||||
public String mint(Context context, DSpaceObject dso)
|
||||
throws IdentifierException {
|
||||
return mint(context, dso, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mint a new DOI in DSpace - this is usually the first step of registration
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by the new identifier
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before minting.
|
||||
* @return a String containing the new identifier
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
@Override
|
||||
public String mint(Context context, DSpaceObject dso, boolean skipFilter) throws IdentifierException {
|
||||
|
||||
String doi = null;
|
||||
try {
|
||||
doi = getDOIByObject(context, dso);
|
||||
} catch (SQLException e) {
|
||||
log.error("Error while attemping to retrieve information about a DOI for "
|
||||
+ contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso
|
||||
.getID() + ".");
|
||||
+ contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso.getID() + ".");
|
||||
throw new RuntimeException("Error while attempting to retrieve " +
|
||||
"information about a DOI for " + contentServiceFactory
|
||||
.getDSpaceObjectService(dso).getTypeText(dso) +
|
||||
"information about a DOI for " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
|
||||
" with ID " + dso.getID() + ".", e);
|
||||
}
|
||||
if (null == doi) {
|
||||
try {
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, null);
|
||||
DOI doiRow = loadOrCreateDOI(context, dso, null, skipFilter);
|
||||
doi = DOI.SCHEME + doiRow.getDoi();
|
||||
|
||||
} catch (SQLException e) {
|
||||
log.error("Error while creating new DOI for Object of " +
|
||||
"ResourceType {} with id {}.", dso.getType(), dso.getID());
|
||||
throw new RuntimeException("Error while attempting to create a " +
|
||||
"new DOI for " + contentServiceFactory.getDSpaceObjectService(dso)
|
||||
.getTypeText(dso) + " with ID " +
|
||||
"new DOI for " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " +
|
||||
dso.getID() + ".", e);
|
||||
}
|
||||
}
|
||||
return doi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve an identifier to a DSpaceObject, if it is registered
|
||||
* @param context - DSpace context
|
||||
* @param identifier - to be resolved.
|
||||
* @param attributes - additional information for resolving {@code identifier}.
|
||||
* @return a DSpaceObject identified by the identifier string
|
||||
* @throws IdentifierNotFoundException
|
||||
* @throws IdentifierNotResolvableException
|
||||
*/
|
||||
@Override
|
||||
public DSpaceObject resolve(Context context, String identifier, String... attributes)
|
||||
throws IdentifierNotFoundException, IdentifierNotResolvableException {
|
||||
@@ -437,13 +635,20 @@ public class DOIIdentifierProvider
|
||||
return dso;
|
||||
} catch (SQLException sqle) {
|
||||
log.error("SQLException while searching a DOI in our db.", sqle);
|
||||
throw new RuntimeException("Unable to retrieve information about " +
|
||||
"a DOI out of database.", sqle);
|
||||
throw new RuntimeException("Unable to retrieve information about a DOI out of database.", sqle);
|
||||
} catch (IdentifierException e) {
|
||||
throw new IdentifierNotResolvableException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up a DOI identifier for a given DSpaceObject
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject to look up
|
||||
* @return a String containing the DOI
|
||||
* @throws IdentifierNotFoundException
|
||||
* @throws IdentifierNotResolvableException
|
||||
*/
|
||||
@Override
|
||||
public String lookup(Context context, DSpaceObject dso)
|
||||
throws IdentifierNotFoundException, IdentifierNotResolvableException {
|
||||
@@ -455,15 +660,20 @@ public class DOIIdentifierProvider
|
||||
}
|
||||
|
||||
if (null == doi) {
|
||||
throw new IdentifierNotFoundException("No DOI for DSpaceObject of type "
|
||||
+ contentServiceFactory.getDSpaceObjectService(dso)
|
||||
.getTypeText(dso) + " with ID " + dso
|
||||
.getID() + " found.");
|
||||
throw new IdentifierNotFoundException("No DOI for DSpaceObject of type " +
|
||||
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
|
||||
" with ID " + dso.getID() + " found.");
|
||||
}
|
||||
|
||||
return doi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all DOIs for a DSpaceObject
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject to have all its DOIs deleted
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
@Override
|
||||
public void delete(Context context, DSpaceObject dso)
|
||||
throws IdentifierException {
|
||||
@@ -475,12 +685,11 @@ public class DOIIdentifierProvider
|
||||
doi = getDOIByObject(context, dso);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
log.error("Error while attemping to retrieve information about a DOI for "
|
||||
+ contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso
|
||||
.getID() + ".", ex);
|
||||
log.error("Error while attemping to retrieve information about a DOI for " +
|
||||
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
|
||||
" with ID " + dso.getID() + ".", ex);
|
||||
throw new RuntimeException("Error while attempting to retrieve " +
|
||||
"information about a DOI for " + contentServiceFactory
|
||||
.getDSpaceObjectService(dso).getTypeText(dso) +
|
||||
"information about a DOI for " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
|
||||
" with ID " + dso.getID() + ".", ex);
|
||||
}
|
||||
|
||||
@@ -493,25 +702,30 @@ public class DOIIdentifierProvider
|
||||
doi = getDOIOutOfObject(dso);
|
||||
}
|
||||
} catch (AuthorizeException ex) {
|
||||
log.error("Error while removing a DOI out of the metadata of an "
|
||||
+ contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso
|
||||
.getID() + ".", ex);
|
||||
throw new RuntimeException("Error while removing a DOI out of the "
|
||||
+ "metadata of an " + contentServiceFactory.getDSpaceObjectService(dso)
|
||||
.getTypeText(dso) + " with ID "
|
||||
+ dso.getID() + ".", ex);
|
||||
log.error("Error while removing a DOI out of the metadata of an " +
|
||||
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
|
||||
" with ID " + dso.getID() + ".", ex);
|
||||
throw new RuntimeException("Error while removing a DOI out of the metadata of an " +
|
||||
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
|
||||
" with ID " + dso.getID() + ".", ex);
|
||||
|
||||
} catch (SQLException ex) {
|
||||
log.error("Error while removing a DOI out of the metadata of an "
|
||||
+ contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso
|
||||
.getID() + ".", ex);
|
||||
throw new RuntimeException("Error while removing a DOI out of the "
|
||||
+ "metadata of an " + contentServiceFactory.getDSpaceObjectService(dso)
|
||||
.getTypeText(dso) + " with ID "
|
||||
+ dso.getID() + ".", ex);
|
||||
log.error("Error while removing a DOI out of the metadata of an " +
|
||||
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
|
||||
" with ID " + dso.getID() + ".", ex);
|
||||
throw new RuntimeException("Error while removing a DOI out of the " +
|
||||
"metadata of an " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
|
||||
" with ID " + dso.getID() + ".", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a specific DOI for a given DSpaceObject
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject to be de-identified.
|
||||
* @param identifier - String containing identifier to delete
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
@Override
|
||||
public void delete(Context context, DSpaceObject dso, String identifier)
|
||||
throws IdentifierException {
|
||||
@@ -567,8 +781,13 @@ public class DOIIdentifierProvider
|
||||
// DOIS. But it is possible to mark a DOI as "inactive".
|
||||
}
|
||||
|
||||
public void deleteOnline(Context context, String identifier)
|
||||
throws DOIIdentifierException {
|
||||
/**
|
||||
* Delete a specific DOI in the registration agency records via the DOI Connector
|
||||
* @param context - DSpace context
|
||||
* @param identifier - String containing identifier to delete
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
public void deleteOnline(Context context, String identifier) throws DOIIdentifierException {
|
||||
String doi = doiService.formatIdentifier(identifier);
|
||||
DOI doiRow = null;
|
||||
|
||||
@@ -583,8 +802,7 @@ public class DOIIdentifierProvider
|
||||
DOIIdentifierException.DOI_DOES_NOT_EXIST);
|
||||
}
|
||||
if (!TO_BE_DELETED.equals(doiRow.getStatus())) {
|
||||
log.error("This identifier: {} couldn't be deleted. "
|
||||
+ "Delete it first from metadata.",
|
||||
log.error("This identifier: {} couldn't be deleted. Delete it first from metadata.",
|
||||
DOI.SCHEME + doiRow.getDoi());
|
||||
throw new IllegalArgumentException("Couldn't delete this identifier:"
|
||||
+ DOI.SCHEME + doiRow.getDoi()
|
||||
@@ -603,13 +821,12 @@ public class DOIIdentifierProvider
|
||||
|
||||
/**
|
||||
* Returns a DSpaceObject depending on its DOI.
|
||||
*
|
||||
* @param context The relevant DSpace Context.
|
||||
* @param context the context
|
||||
* @param identifier The DOI in a format that is accepted by
|
||||
* {@link org.dspace.identifier.service.DOIService#formatIdentifier(String)}.
|
||||
* @return Null if the DOI couldn't be found or the associated DSpaceObject.
|
||||
* @throws SQLException if database error
|
||||
* @throws DOIIdentifierException If {@code identifier} is null or an empty string.
|
||||
* @throws IdentifierException If {@code identifier} is null or an empty string.
|
||||
* @throws IllegalArgumentException If the identifier couldn't be recognized as DOI.
|
||||
*/
|
||||
public DSpaceObject getObjectByDOI(Context context, String identifier)
|
||||
@@ -622,8 +839,7 @@ public class DOIIdentifierProvider
|
||||
}
|
||||
|
||||
if (doiRow.getDSpaceObject() == null) {
|
||||
log.error("Found DOI " + doi +
|
||||
" in database, but no assigned Object could be found.");
|
||||
log.error("Found DOI " + doi + " in database, but no assigned Object could be found.");
|
||||
throw new IllegalStateException("Found DOI " + doi +
|
||||
" in database, but no assigned Object could be found.");
|
||||
}
|
||||
@@ -640,8 +856,7 @@ public class DOIIdentifierProvider
|
||||
* @return The DOI as String or null if DOI was not found.
|
||||
* @throws SQLException if database error
|
||||
*/
|
||||
public String getDOIByObject(Context context, DSpaceObject dso)
|
||||
throws SQLException {
|
||||
public String getDOIByObject(Context context, DSpaceObject dso) throws SQLException {
|
||||
// String sql = "SELECT * FROM Doi WHERE resource_type_id = ? " +
|
||||
// "AND resource_id = ? AND ((status != ? AND status != ?) OR status IS NULL)";
|
||||
|
||||
@@ -651,13 +866,10 @@ public class DOIIdentifierProvider
|
||||
}
|
||||
|
||||
if (doiRow.getDoi() == null) {
|
||||
log.error("A DOI with an empty doi column was found in the database. DSO-Type: "
|
||||
+ contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ", ID: " + dso
|
||||
.getID() + ".");
|
||||
throw new IllegalStateException("A DOI with an empty doi column " +
|
||||
"was found in the database. DSO-Type: " + contentServiceFactory
|
||||
.getDSpaceObjectService(dso).getTypeText(dso) +
|
||||
", ID: " + dso.getID() + ".");
|
||||
log.error("A DOI with an empty doi column was found in the database. DSO-Type: " +
|
||||
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ", ID: " + dso.getID() + ".");
|
||||
throw new IllegalStateException("A DOI with an empty doi column was found in the database. DSO-Type: " +
|
||||
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ", ID: " + dso.getID() + ".");
|
||||
}
|
||||
|
||||
return DOI.SCHEME + doiRow.getDoi();
|
||||
@@ -679,8 +891,31 @@ public class DOIIdentifierProvider
|
||||
* DOI is registered for another object already.
|
||||
*/
|
||||
protected DOI loadOrCreateDOI(Context context, DSpaceObject dso, String doiIdentifier)
|
||||
throws SQLException, DOIIdentifierException {
|
||||
throws SQLException, DOIIdentifierException, IdentifierNotApplicableException {
|
||||
return loadOrCreateDOI(context, dso, doiIdentifier, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load DOI from database, or create one if it doesn't yet exist
|
||||
* We need to distinguish several cases. LoadOrCreate can be called with a specifid identifier to load or create.
|
||||
* It can also be used to create a new unspecified identifier. In the latter case doiIdentifier is set null.
|
||||
* If doiIdentifier is set, we know which doi we should try to load or create, but even in sucha situation
|
||||
* we might be able to find it in the database or might have to create it.
|
||||
*
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject to identify
|
||||
* @param doiIdentifier - DOI to load or create (null to mint a new one)
|
||||
* @param skipFilter - Whether or not to skip the filters for the checkMintable() check
|
||||
* @return
|
||||
* @throws SQLException
|
||||
* @throws DOIIdentifierException
|
||||
*/
|
||||
protected DOI loadOrCreateDOI(Context context, DSpaceObject dso, String doiIdentifier, boolean skipFilter)
|
||||
throws SQLException, DOIIdentifierException, IdentifierNotApplicableException {
|
||||
|
||||
DOI doi = null;
|
||||
|
||||
// Was an identifier specified that we shall try to load or create if it is not existing yet?
|
||||
if (null != doiIdentifier) {
|
||||
// we expect DOIs to have the DOI-Scheme except inside the doi table:
|
||||
doiIdentifier = doiIdentifier.substring(DOI.SCHEME.length());
|
||||
@@ -692,7 +927,7 @@ public class DOIIdentifierProvider
|
||||
// doi was deleted, check resource type
|
||||
if (doi.getResourceTypeId() != null
|
||||
&& doi.getResourceTypeId() != dso.getType()) {
|
||||
// doi was assigend to another resource type. Don't
|
||||
// doi was assigned to another resource type. Don't
|
||||
// reactivate it
|
||||
throw new DOIIdentifierException("Cannot reassing "
|
||||
+ "previously deleted DOI " + doiIdentifier
|
||||
@@ -707,6 +942,7 @@ public class DOIIdentifierProvider
|
||||
// reassign doi
|
||||
// nothing to do here, doi will br reassigned after this
|
||||
// if-else-if-else-...-block
|
||||
// will check if a filter prohibits creation of DOIs after this if-else-block
|
||||
}
|
||||
} else {
|
||||
// doi is assigned to a DSO; is it assigned to our specific dso?
|
||||
@@ -721,6 +957,16 @@ public class DOIIdentifierProvider
|
||||
}
|
||||
}
|
||||
|
||||
// we did not find the doi in the database or shall reassign it. Before doing so, we should check if a
|
||||
// filter is in place to prevent the creation of new DOIs for certain items.
|
||||
if (skipFilter) {
|
||||
log.warn("loadOrCreateDOI: Skipping default item filter");
|
||||
} else {
|
||||
// Find out if we're allowed to create a DOI
|
||||
// throws an exception if creation of a new DOI is prohibited by a filter
|
||||
checkMintable(context, dso);
|
||||
}
|
||||
|
||||
// check prefix
|
||||
if (!doiIdentifier.startsWith(this.getPrefix() + "/")) {
|
||||
throw new DOIIdentifierException("Trying to create a DOI " +
|
||||
@@ -732,7 +978,16 @@ public class DOIIdentifierProvider
|
||||
doi = doiService.create(context);
|
||||
}
|
||||
} else {
|
||||
// We need to generate a new DOI.
|
||||
// We need to generate a new DOI. Before doing so, we should check if a
|
||||
// filter is in place to prevent the creation of new DOIs for certain items.
|
||||
if (skipFilter) {
|
||||
log.warn("loadOrCreateDOI: Skipping default item filter");
|
||||
} else {
|
||||
// Find out if we're allowed to create a DOI
|
||||
// throws an exception if creation of a new DOI is prohibited by a filter
|
||||
checkMintable(context, dso);
|
||||
}
|
||||
|
||||
doi = doiService.create(context);
|
||||
doiIdentifier = this.getPrefix() + "/" + this.getNamespaceSeparator() +
|
||||
doi.getID();
|
||||
@@ -745,7 +1000,7 @@ public class DOIIdentifierProvider
|
||||
try {
|
||||
doiService.update(context, doi);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("Cannot save DOI to databse for unkown reason.");
|
||||
throw new RuntimeException("Cannot save DOI to database for unknown reason.");
|
||||
}
|
||||
|
||||
return doi;
|
||||
@@ -758,13 +1013,11 @@ public class DOIIdentifierProvider
|
||||
* @return The DOI or null if no DOI was found.
|
||||
* @throws DOIIdentifierException if identifier error
|
||||
*/
|
||||
public String getDOIOutOfObject(DSpaceObject dso)
|
||||
throws DOIIdentifierException {
|
||||
public String getDOIOutOfObject(DSpaceObject dso) throws DOIIdentifierException {
|
||||
// FIXME
|
||||
if (!(dso instanceof Item)) {
|
||||
throw new IllegalArgumentException("We currently support DOIs for "
|
||||
+ "Items only, not for " + contentServiceFactory
|
||||
.getDSpaceObjectService(dso).getTypeText(dso) + ".");
|
||||
throw new IllegalArgumentException("We currently support DOIs for Items only, not for " +
|
||||
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ".");
|
||||
}
|
||||
Item item = (Item) dso;
|
||||
|
||||
@@ -792,14 +1045,13 @@ public class DOIIdentifierProvider
|
||||
throws SQLException, AuthorizeException, IdentifierException {
|
||||
// FIXME
|
||||
if (!(dso instanceof Item)) {
|
||||
throw new IllegalArgumentException("We currently support DOIs for "
|
||||
+ "Items only, not for " + contentServiceFactory
|
||||
.getDSpaceObjectService(dso).getTypeText(dso) + ".");
|
||||
throw new IllegalArgumentException("We currently support DOIs for Items only, not for " +
|
||||
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ".");
|
||||
}
|
||||
Item item = (Item) dso;
|
||||
|
||||
itemService
|
||||
.addMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null, doiService.DOIToExternalForm(doi));
|
||||
itemService.addMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null,
|
||||
doiService.DOIToExternalForm(doi));
|
||||
try {
|
||||
itemService.update(context, item);
|
||||
} catch (SQLException | AuthorizeException ex) {
|
||||
@@ -821,9 +1073,8 @@ public class DOIIdentifierProvider
|
||||
throws AuthorizeException, SQLException, IdentifierException {
|
||||
// FIXME
|
||||
if (!(dso instanceof Item)) {
|
||||
throw new IllegalArgumentException("We currently support DOIs for "
|
||||
+ "Items only, not for " + contentServiceFactory
|
||||
.getDSpaceObjectService(dso).getTypeText(dso) + ".");
|
||||
throw new IllegalArgumentException("We currently support DOIs for Items only, not for " +
|
||||
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ".");
|
||||
}
|
||||
Item item = (Item) dso;
|
||||
|
||||
@@ -841,4 +1092,31 @@ public class DOIIdentifierProvider
|
||||
remainder);
|
||||
itemService.update(context, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if an item can have a DOI minted, using the configured logical filter
|
||||
* @param context
|
||||
* @param dso The item to be evaluated
|
||||
* @throws DOIIdentifierNotApplicableException
|
||||
*/
|
||||
@Override
|
||||
public void checkMintable(Context context, DSpaceObject dso) throws DOIIdentifierNotApplicableException {
|
||||
// If the check fails, an exception will be thrown to be caught by the calling method
|
||||
if (this.filterService != null && contentServiceFactory
|
||||
.getDSpaceObjectService(dso).getTypeText(dso).equals("ITEM")) {
|
||||
try {
|
||||
boolean result = filterService.getResult(context, (Item) dso);
|
||||
log.debug("Result of filter for " + dso.getHandle() + " is " + result);
|
||||
if (!result) {
|
||||
throw new DOIIdentifierNotApplicableException("Item " + dso.getHandle() +
|
||||
" was evaluated as 'false' by the item filter, not minting");
|
||||
}
|
||||
} catch (LogicalStatementException e) {
|
||||
log.error("Error evaluating item with logical filter: " + e.getLocalizedMessage());
|
||||
throw new DOIIdentifierNotApplicableException(e);
|
||||
}
|
||||
} else {
|
||||
log.debug("DOI Identifier Provider: filterService is null (ie. don't prevent DOI minting)");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* 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.identifier;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.logic.Filter;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* This abstract class adds extra method signatures so that implementing IdentifierProviders can
|
||||
* handle "skip filter" booleans, so that any configured filters can be skipped and DOI registration forced.
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
* @version $Revision$
|
||||
*/
|
||||
public abstract class FilteredIdentifierProvider extends IdentifierProvider {
|
||||
|
||||
protected Filter filterService;
|
||||
|
||||
/**
|
||||
* Setter for spring to set the filter service from the property in configuration XML
|
||||
* @param filterService - an object implementing the org.dspace.content.logic.Filter interface
|
||||
*/
|
||||
@Autowired
|
||||
public void setFilterService(Filter filterService) {
|
||||
this.filterService = filterService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new identifier for a given DSpaceObject
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject to use for identifier registration
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration
|
||||
* @return identifier
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
public abstract String register(Context context, DSpaceObject dso, boolean skipFilter)
|
||||
throws IdentifierException;
|
||||
|
||||
/**
|
||||
* Register a specified identifier for a given DSpaceObject
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by the new identifier
|
||||
* @param identifier - String containing the identifier to register
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
public abstract void register(Context context, DSpaceObject dso, String identifier, boolean skipFilter)
|
||||
throws IdentifierException;
|
||||
|
||||
/**
|
||||
* Reserve a specified identifier for a given DSpaceObject (eg. reserving a DOI online with a registration agency)
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by this identifier
|
||||
* @param identifier - String containing the identifier to reserve
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing reservation
|
||||
* @throws IdentifierException
|
||||
* @throws IllegalArgumentException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public abstract void reserve(Context context, DSpaceObject dso, String identifier, boolean skipFilter)
|
||||
throws IdentifierException, IllegalArgumentException, SQLException;
|
||||
|
||||
/**
|
||||
* Mint a new identifier in DSpace - this is usually the first step of registration
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject identified by the new identifier
|
||||
* @param skipFilter - boolean indicating whether to skip any filtering of items before minting.
|
||||
* @return a String containing the new identifier
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
public abstract String mint(Context context, DSpaceObject dso, boolean skipFilter) throws IdentifierException;
|
||||
|
||||
/**
|
||||
* Check configured item filters to see if this identifier is allowed to be minted
|
||||
* @param context - DSpace context
|
||||
* @param dso - DSpaceObject to be inspected
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
public abstract void checkMintable(Context context, DSpaceObject dso) throws IdentifierException;
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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.identifier;
|
||||
|
||||
/**
|
||||
*
|
||||
* Thrown when an identifier should not be applied to an item, eg. when it has been filtered by an item filter
|
||||
*
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
*/
|
||||
public class IdentifierNotApplicableException extends IdentifierException {
|
||||
|
||||
public IdentifierNotApplicableException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public IdentifierNotApplicableException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public IdentifierNotApplicableException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public IdentifierNotApplicableException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@@ -66,10 +66,14 @@ public class IdentifierServiceImpl implements IdentifierService {
|
||||
public void reserve(Context context, DSpaceObject dso)
|
||||
throws AuthorizeException, SQLException, IdentifierException {
|
||||
for (IdentifierProvider service : providers) {
|
||||
try {
|
||||
String identifier = service.mint(context, dso);
|
||||
if (!StringUtils.isEmpty(identifier)) {
|
||||
service.reserve(context, dso, identifier);
|
||||
}
|
||||
} catch (IdentifierNotApplicableException e) {
|
||||
log.warn("Identifier not reserved (inapplicable): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
//Update our item
|
||||
contentServiceFactory.getDSpaceObjectService(dso).update(context, dso);
|
||||
@@ -81,7 +85,11 @@ public class IdentifierServiceImpl implements IdentifierService {
|
||||
// Next resolve all other services
|
||||
for (IdentifierProvider service : providers) {
|
||||
if (service.supports(identifier)) {
|
||||
try {
|
||||
service.reserve(context, dso, identifier);
|
||||
} catch (IdentifierNotApplicableException e) {
|
||||
log.warn("Identifier not reserved (inapplicable): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
//Update our item
|
||||
@@ -94,7 +102,11 @@ public class IdentifierServiceImpl implements IdentifierService {
|
||||
//We need to commit our context because one of the providers might require the handle created above
|
||||
// Next resolve all other services
|
||||
for (IdentifierProvider service : providers) {
|
||||
try {
|
||||
service.register(context, dso);
|
||||
} catch (IdentifierNotApplicableException e) {
|
||||
log.warn("Identifier not registered (inapplicable): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
//Update our item / collection / community
|
||||
contentServiceFactory.getDSpaceObjectService(dso).update(context, dso);
|
||||
@@ -108,8 +120,12 @@ public class IdentifierServiceImpl implements IdentifierService {
|
||||
boolean registered = false;
|
||||
for (IdentifierProvider service : providers) {
|
||||
if (service.supports(identifier)) {
|
||||
try {
|
||||
service.register(context, object, identifier);
|
||||
registered = true;
|
||||
} catch (IdentifierNotApplicableException e) {
|
||||
log.warn("Identifier not registered (inapplicable): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!registered) {
|
||||
@@ -152,8 +168,7 @@ public class IdentifierServiceImpl implements IdentifierService {
|
||||
if (!StringUtils.isEmpty(result)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
try {
|
||||
log.debug("Got an identifier from "
|
||||
+ service.getClass().getCanonicalName() + ".");
|
||||
log.debug("Got an identifier from " + service.getClass().getCanonicalName() + ".");
|
||||
} catch (NullPointerException ex) {
|
||||
log.debug(ex.getMessage(), ex);
|
||||
}
|
||||
@@ -178,7 +193,7 @@ public class IdentifierServiceImpl implements IdentifierService {
|
||||
if (!identifiers.contains(handle)
|
||||
&& !identifiers.contains("hdl:" + handle)
|
||||
&& !identifiers.contains(handleService.getCanonicalForm(handle))) {
|
||||
// The VerionedHandleIdentifierProvider gets loaded by default
|
||||
// The VersionedHandleIdentifierProvider gets loaded by default
|
||||
// it returns handles without any scheme (neither hdl: nor http:).
|
||||
// If the VersionedHandleIdentifierProvider is not loaded,
|
||||
// we adds the handle in way it would.
|
||||
@@ -224,8 +239,7 @@ public class IdentifierServiceImpl implements IdentifierService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Context context, DSpaceObject dso)
|
||||
throws AuthorizeException, SQLException, IdentifierException {
|
||||
public void delete(Context context, DSpaceObject dso) throws AuthorizeException, SQLException, IdentifierException {
|
||||
for (IdentifierProvider service : providers) {
|
||||
try {
|
||||
service.delete(context, dso);
|
||||
|
@@ -222,7 +222,7 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
|
||||
|
||||
// Should never return null!
|
||||
protected String makeIdentifierBasedOnHistory(Context context, DSpaceObject dso, VersionHistory history)
|
||||
throws AuthorizeException, SQLException, DOIIdentifierException {
|
||||
throws AuthorizeException, SQLException, DOIIdentifierException, IdentifierNotApplicableException {
|
||||
// Mint foreach new version an identifier like: 12345/100.versionNumber
|
||||
// use the bare handle (g.e. 12345/100) for the first version.
|
||||
|
||||
|
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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.identifier.doi;
|
||||
|
||||
import org.dspace.identifier.IdentifierNotApplicableException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Thrown when an identifier should not be applied to an item, eg. when it has been filtered by an item filter
|
||||
*
|
||||
*
|
||||
* @author Kim Shepherd
|
||||
*/
|
||||
public class DOIIdentifierNotApplicableException extends IdentifierNotApplicableException {
|
||||
|
||||
public DOIIdentifierNotApplicableException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public DOIIdentifierNotApplicableException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DOIIdentifierNotApplicableException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public DOIIdentifierNotApplicableException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@@ -61,7 +61,13 @@ public class DOIOrganiser {
|
||||
protected ItemService itemService;
|
||||
protected DOIService doiService;
|
||||
protected ConfigurationService configurationService;
|
||||
protected boolean skipFilter;
|
||||
|
||||
/**
|
||||
* Constructor to be called within the main() method
|
||||
* @param context - DSpace context
|
||||
* @param provider - DOI identifier provider to use
|
||||
*/
|
||||
public DOIOrganiser(Context context, DOIIdentifierProvider provider) {
|
||||
this.context = context;
|
||||
this.provider = provider;
|
||||
@@ -70,8 +76,13 @@ public class DOIOrganiser {
|
||||
this.itemService = ContentServiceFactory.getInstance().getItemService();
|
||||
this.doiService = IdentifierServiceFactory.getInstance().getDOIService();
|
||||
this.configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
this.skipFilter = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main command-line runner method as with other DSpace launcher commands
|
||||
* @param args - the command line arguments to parse as parameters
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
LOG.debug("Starting DOI organiser ");
|
||||
|
||||
@@ -83,7 +94,6 @@ public class DOIOrganiser {
|
||||
|
||||
DOIOrganiser organiser = new DOIOrganiser(context,
|
||||
new DSpace().getSingletonService(DOIIdentifierProvider.class));
|
||||
|
||||
// run command line interface
|
||||
runCLI(context, organiser, args);
|
||||
|
||||
@@ -97,7 +107,7 @@ public class DOIOrganiser {
|
||||
}
|
||||
|
||||
public static void runCLI(Context context, DOIOrganiser organiser, String[] args) {
|
||||
// initlize options
|
||||
// initialize options
|
||||
Options options = new Options();
|
||||
|
||||
options.addOption("h", "help", false, "Help");
|
||||
@@ -115,6 +125,9 @@ public class DOIOrganiser {
|
||||
options.addOption("q", "quiet", false,
|
||||
"Turn the command line output off.");
|
||||
|
||||
options.addOption(null, "skip-filter", false,
|
||||
"Skip the configured item filter when registering or reserving.");
|
||||
|
||||
Option registerDoi = Option.builder()
|
||||
.longOpt("register-doi")
|
||||
.hasArg()
|
||||
@@ -157,7 +170,6 @@ public class DOIOrganiser {
|
||||
|
||||
options.addOption(delete);
|
||||
|
||||
|
||||
// initialize parser
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
CommandLine line = null;
|
||||
@@ -170,7 +182,6 @@ public class DOIOrganiser {
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
|
||||
// process options
|
||||
// user asks for help
|
||||
if (line.hasOption('h') || 0 == line.getOptions().length) {
|
||||
@@ -192,9 +203,13 @@ public class DOIOrganiser {
|
||||
}
|
||||
|
||||
DOIService doiService = IdentifierServiceFactory.getInstance().getDOIService();
|
||||
// Should we skip the filter?
|
||||
if (line.hasOption("skip-filter")) {
|
||||
System.out.println("Skipping the item filter");
|
||||
organiser.skipFilter = true;
|
||||
}
|
||||
|
||||
if (line.hasOption('s')) {
|
||||
|
||||
try {
|
||||
List<DOI> dois = doiService
|
||||
.getDOIsByStatus(context, Arrays.asList(DOIIdentifierProvider.TO_BE_RESERVED));
|
||||
@@ -214,7 +229,6 @@ public class DOIOrganiser {
|
||||
}
|
||||
|
||||
if (line.hasOption('r')) {
|
||||
|
||||
try {
|
||||
List<DOI> dois = doiService
|
||||
.getDOIsByStatus(context, Arrays.asList(DOIIdentifierProvider.TO_BE_REGISTERED));
|
||||
@@ -229,11 +243,12 @@ public class DOIOrganiser {
|
||||
} catch (SQLException ex) {
|
||||
System.err.println("Error in database connection:" + ex.getMessage());
|
||||
ex.printStackTrace(System.err);
|
||||
} catch (DOIIdentifierException ex) {
|
||||
System.err.println("Error registering DOI identifier:" + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (line.hasOption('u')) {
|
||||
|
||||
try {
|
||||
List<DOI> dois = doiService.getDOIsByStatus(context, Arrays.asList(
|
||||
DOIIdentifierProvider.UPDATE_BEFORE_REGISTRATION,
|
||||
@@ -255,7 +270,6 @@ public class DOIOrganiser {
|
||||
}
|
||||
|
||||
if (line.hasOption('d')) {
|
||||
|
||||
try {
|
||||
List<DOI> dois = doiService
|
||||
.getDOIsByStatus(context, Arrays.asList(DOIIdentifierProvider.TO_BE_DELETED));
|
||||
@@ -277,7 +291,6 @@ public class DOIOrganiser {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (line.hasOption("reserve-doi")) {
|
||||
String identifier = line.getOptionValue("reserve-doi");
|
||||
|
||||
@@ -339,7 +352,14 @@ public class DOIOrganiser {
|
||||
|
||||
}
|
||||
|
||||
public void list(String processName, PrintStream out, PrintStream err, Integer... status) {
|
||||
/**
|
||||
* list DOIs queued for reservation or registration
|
||||
* @param processName - process name for display
|
||||
* @param out - output stream (eg. STDOUT)
|
||||
* @param err - error output stream (eg. STDERR)
|
||||
* @param status - status codes
|
||||
*/
|
||||
public void list(String processName, PrintStream out, PrintStream err, Integer ... status) {
|
||||
String indent = " ";
|
||||
if (null == out) {
|
||||
out = System.out;
|
||||
@@ -371,7 +391,14 @@ public class DOIOrganiser {
|
||||
}
|
||||
}
|
||||
|
||||
public void register(DOI doiRow) throws SQLException {
|
||||
/**
|
||||
* Register DOI with the provider
|
||||
* @param doiRow - doi to register
|
||||
* @param skipFilter - whether filters should be skipped before registration
|
||||
* @throws SQLException
|
||||
* @throws DOIIdentifierException
|
||||
*/
|
||||
public void register(DOI doiRow, boolean skipFilter) throws SQLException, DOIIdentifierException {
|
||||
DSpaceObject dso = doiRow.getDSpaceObject();
|
||||
if (Constants.ITEM != dso.getType()) {
|
||||
throw new IllegalArgumentException("Currenty DSpace supports DOIs for Items only.");
|
||||
@@ -438,20 +465,49 @@ public class DOIOrganiser {
|
||||
}
|
||||
}
|
||||
|
||||
public void reserve(DOI doiRow) throws SQLException {
|
||||
/**
|
||||
* Register DOI with the provider, always applying (ie. never skipping) any configured filters
|
||||
* @param doiRow - doi to register
|
||||
* @throws SQLException
|
||||
* @throws DOIIdentifierException
|
||||
*/
|
||||
public void register(DOI doiRow) throws SQLException, DOIIdentifierException {
|
||||
if (this.skipFilter) {
|
||||
System.out.println("Skipping the filter for " + doiRow.getDoi());
|
||||
}
|
||||
register(doiRow, this.skipFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve DOI with the provider, always applying (ie. never skipping) any configured filters
|
||||
* @param doiRow - doi to reserve
|
||||
* @throws SQLException
|
||||
* @throws DOIIdentifierException
|
||||
*/
|
||||
public void reserve(DOI doiRow) {
|
||||
if (this.skipFilter) {
|
||||
System.out.println("Skipping the filter for " + doiRow.getDoi());
|
||||
}
|
||||
reserve(doiRow, this.skipFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve DOI with the provider
|
||||
* @param doiRow - doi to reserve
|
||||
* @throws SQLException
|
||||
* @throws DOIIdentifierException
|
||||
*/
|
||||
public void reserve(DOI doiRow, boolean skipFilter) {
|
||||
DSpaceObject dso = doiRow.getDSpaceObject();
|
||||
if (Constants.ITEM != dso.getType()) {
|
||||
throw new IllegalArgumentException("Currenty DSpace supports DOIs for Items only.");
|
||||
throw new IllegalArgumentException("Currently DSpace supports DOIs for Items only.");
|
||||
}
|
||||
|
||||
try {
|
||||
provider.reserveOnline(context, dso,
|
||||
DOI.SCHEME + doiRow.getDoi());
|
||||
provider.reserveOnline(context, dso, DOI.SCHEME + doiRow.getDoi(), skipFilter);
|
||||
|
||||
if (!quiet) {
|
||||
System.out.println("This identifier : "
|
||||
+ DOI.SCHEME + doiRow.getDoi()
|
||||
+ " is successfully reserved.");
|
||||
System.out.println("This identifier : " + DOI.SCHEME + doiRow.getDoi() + " is successfully reserved.");
|
||||
}
|
||||
} catch (IdentifierException ex) {
|
||||
if (!(ex instanceof DOIIdentifierException)) {
|
||||
@@ -477,16 +533,14 @@ public class DOIOrganiser {
|
||||
.codeToString(doiIdentifierException.getCode()), ex);
|
||||
|
||||
if (!quiet) {
|
||||
System.err.println("It wasn't possible to reserve this identifier: "
|
||||
+ DOI.SCHEME + doiRow.getDoi());
|
||||
System.err.println("It wasn't possible to reserve this identifier: " + DOI.SCHEME + doiRow.getDoi());
|
||||
}
|
||||
} catch (IllegalArgumentException ex) {
|
||||
LOG.error("Database table DOI contains a DOI that is not valid: "
|
||||
+ DOI.SCHEME + doiRow.getDoi() + "!", ex);
|
||||
|
||||
if (!quiet) {
|
||||
System.err.println("It wasn't possible to reserve this identifier: "
|
||||
+ DOI.SCHEME + doiRow.getDoi());
|
||||
System.err.println("It wasn't possible to reserve this identifier: " + DOI.SCHEME + doiRow.getDoi());
|
||||
}
|
||||
throw new IllegalStateException("Database table DOI contains a DOI "
|
||||
+ " that is not valid: "
|
||||
@@ -495,19 +549,21 @@ public class DOIOrganiser {
|
||||
LOG.error("Error while trying to get data from database", ex);
|
||||
|
||||
if (!quiet) {
|
||||
System.err.println("It wasn't possible to reserve this identifier: "
|
||||
+ DOI.SCHEME + doiRow.getDoi());
|
||||
System.err.println("It wasn't possible to reserve this identifier: " + DOI.SCHEME + doiRow.getDoi());
|
||||
}
|
||||
throw new RuntimeException("Error while trying to get data from database", ex);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update metadata for a DOI
|
||||
* @param doiRow - DOI to update
|
||||
*/
|
||||
public void update(DOI doiRow) {
|
||||
DSpaceObject dso = doiRow.getDSpaceObject();
|
||||
if (Constants.ITEM != dso.getType()) {
|
||||
throw new IllegalArgumentException("Currenty DSpace supports DOIs "
|
||||
+ "for Items only.");
|
||||
throw new IllegalArgumentException("Currently DSpace supports DOIs for Items only.");
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -541,8 +597,7 @@ public class DOIOrganiser {
|
||||
.codeToString(doiIdentifierException.getCode()), ex);
|
||||
|
||||
if (!quiet) {
|
||||
System.err.println("It wasn't possible to update this identifier: "
|
||||
+ DOI.SCHEME + doiRow.getDoi());
|
||||
System.err.println("It wasn't possible to update this identifier: " + DOI.SCHEME + doiRow.getDoi());
|
||||
}
|
||||
|
||||
} catch (IllegalArgumentException ex) {
|
||||
@@ -550,8 +605,7 @@ public class DOIOrganiser {
|
||||
+ DOI.SCHEME + doiRow.getDoi() + "!", ex);
|
||||
|
||||
if (!quiet) {
|
||||
System.err.println("It wasn't possible to update this identifier: "
|
||||
+ DOI.SCHEME + doiRow.getDoi());
|
||||
System.err.println("It wasn't possible to update this identifier: " + DOI.SCHEME + doiRow.getDoi());
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Database table DOI contains a DOI "
|
||||
@@ -562,8 +616,12 @@ public class DOIOrganiser {
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(String identifier)
|
||||
throws SQLException {
|
||||
/**
|
||||
* Delete a DOI
|
||||
* @param identifier - DOI to delete
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void delete(String identifier) throws SQLException {
|
||||
String doi = null;
|
||||
DOI doiRow = null;
|
||||
|
||||
@@ -575,8 +633,7 @@ public class DOIOrganiser {
|
||||
doi.substring(DOI.SCHEME.length()));
|
||||
|
||||
if (null == doiRow) {
|
||||
throw new IllegalStateException("You specified a valid DOI,"
|
||||
+ " that is not stored in our database.");
|
||||
throw new IllegalStateException("You specified a valid DOI, that is not stored in our database.");
|
||||
}
|
||||
provider.deleteOnline(context, doi);
|
||||
|
||||
@@ -642,15 +699,14 @@ public class DOIOrganiser {
|
||||
|
||||
//Check if this Item has an Identifier, mint one if it doesn't
|
||||
if (null == doiRow) {
|
||||
doi = provider.mint(context, dso);
|
||||
doi = provider.mint(context, dso, this.skipFilter);
|
||||
doiRow = doiService.findByDoi(context,
|
||||
doi.substring(DOI.SCHEME.length()));
|
||||
return doiRow;
|
||||
}
|
||||
return doiRow;
|
||||
} else {
|
||||
throw new IllegalStateException("You specified an ItemID, "
|
||||
+ "that is not stored in our database.");
|
||||
throw new IllegalStateException("You specified an ItemID, that is not stored in our database.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -667,7 +723,7 @@ public class DOIOrganiser {
|
||||
doiRow = doiService.findDOIByDSpaceObject(context, dso);
|
||||
|
||||
if (null == doiRow) {
|
||||
doi = provider.mint(context, dso);
|
||||
doi = provider.mint(context, dso, this.skipFilter);
|
||||
doiRow = doiService.findByDoi(context,
|
||||
doi.substring(DOI.SCHEME.length()));
|
||||
}
|
||||
@@ -680,8 +736,7 @@ public class DOIOrganiser {
|
||||
doiRow = doiService.findByDoi(context,
|
||||
doi.substring(DOI.SCHEME.length()));
|
||||
if (null == doiRow) {
|
||||
throw new IllegalStateException("You specified a valid DOI,"
|
||||
+ " that is not stored in our database.");
|
||||
throw new IllegalStateException("You specified a valid DOI, that is not stored in our database.");
|
||||
}
|
||||
} catch (DOIIdentifierException ex) {
|
||||
// Identifier was not recognized as DOI.
|
||||
@@ -699,6 +754,14 @@ public class DOIOrganiser {
|
||||
return doiRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an alert email to the configured recipient when DOI operations encounter an error
|
||||
* @param action - action being attempted (eg. reserve, register, update)
|
||||
* @param dso - DSpaceObject associated with the DOI
|
||||
* @param doi - DOI for this operation
|
||||
* @param reason - failure reason or error message
|
||||
* @throws IOException
|
||||
*/
|
||||
private void sendAlertMail(String action, DSpaceObject dso, String doi, String reason)
|
||||
throws IOException {
|
||||
String recipient = configurationService.getProperty("alert.recipient");
|
||||
@@ -728,6 +791,9 @@ public class DOIOrganiser {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this runner to be in quiet mode, suppressing console output
|
||||
*/
|
||||
private void setQuiet() {
|
||||
this.quiet = true;
|
||||
}
|
||||
|
17
dspace-api/src/main/java/org/dspace/util/ConsoleService.java
Normal file
17
dspace-api/src/main/java/org/dspace/util/ConsoleService.java
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* 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.util;
|
||||
|
||||
/**
|
||||
* Make System.console mock-able for testing.
|
||||
*
|
||||
* @author Mark H. Wood <mwood@iupui.edu>
|
||||
*/
|
||||
public interface ConsoleService {
|
||||
public char[] readPassword(String prompt, Object... args);
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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.util;
|
||||
|
||||
/**
|
||||
* Standard implementation of console IO using {@code System.console()}.
|
||||
*
|
||||
* @author Mark H. Wood <mwood@iupui.edu>
|
||||
*/
|
||||
public class ConsoleServiceImpl
|
||||
implements ConsoleService {
|
||||
@Override
|
||||
public char[] readPassword(String prompt, Object... args) {
|
||||
return System.console().readPassword(prompt, args);
|
||||
}
|
||||
}
|
@@ -0,0 +1,652 @@
|
||||
/**
|
||||
* 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.logic;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.AbstractUnitTest;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.factory.AuthorizeServiceFactory;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Bundle;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataField;
|
||||
import org.dspace.content.MetadataSchemaEnum;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.logic.condition.BitstreamCountCondition;
|
||||
import org.dspace.content.logic.condition.Condition;
|
||||
import org.dspace.content.logic.condition.InCollectionCondition;
|
||||
import org.dspace.content.logic.condition.InCommunityCondition;
|
||||
import org.dspace.content.logic.condition.IsWithdrawnCondition;
|
||||
import org.dspace.content.logic.condition.MetadataValueMatchCondition;
|
||||
import org.dspace.content.logic.condition.MetadataValuesMatchCondition;
|
||||
import org.dspace.content.logic.condition.ReadableByGroupCondition;
|
||||
import org.dspace.content.logic.operator.And;
|
||||
import org.dspace.content.logic.operator.Nand;
|
||||
import org.dspace.content.logic.operator.Nor;
|
||||
import org.dspace.content.logic.operator.Not;
|
||||
import org.dspace.content.logic.operator.Or;
|
||||
import org.dspace.content.service.BitstreamService;
|
||||
import org.dspace.content.service.BundleService;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.CommunityService;
|
||||
import org.dspace.content.service.InstallItemService;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.content.service.MetadataFieldService;
|
||||
import org.dspace.content.service.MetadataValueService;
|
||||
import org.dspace.content.service.WorkspaceItemService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||
import org.dspace.eperson.service.GroupService;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for logical filters, conditions and operators
|
||||
* @author Kim Shepherd
|
||||
*/
|
||||
public class LogicalFilterTest extends AbstractUnitTest {
|
||||
// Required services
|
||||
protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
|
||||
protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService();
|
||||
protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService();
|
||||
protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
|
||||
protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
|
||||
protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
|
||||
protected InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService();
|
||||
private MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService();
|
||||
private MetadataValueService metadataValueService = ContentServiceFactory.getInstance().getMetadataValueService();
|
||||
private AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
|
||||
private GroupService groupService = EPersonServiceFactory.getInstance().getGroupService();
|
||||
|
||||
// Logger
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(LogicalFilterTest.class);
|
||||
|
||||
// Items and repository structure for testing
|
||||
Community communityOne;
|
||||
Community communityTwo;
|
||||
Collection collectionOne;
|
||||
Collection collectionTwo;
|
||||
Item itemOne;
|
||||
Item itemTwo;
|
||||
Item itemThree;
|
||||
|
||||
// Some simple statement lists for testing
|
||||
List<LogicalStatement> trueStatements;
|
||||
List<LogicalStatement> trueFalseStatements;
|
||||
List<LogicalStatement> falseStatements;
|
||||
LogicalStatement trueStatementOne;
|
||||
LogicalStatement falseStatementOne;
|
||||
|
||||
// Field and values used to set title metadata
|
||||
String element = "title";
|
||||
String qualifier = null;
|
||||
MetadataField metadataField;
|
||||
|
||||
/**
|
||||
* This method will be run before every test as per @Before. It will
|
||||
* initialize resources required for the tests.
|
||||
*
|
||||
* Other methods can be annotated with @Before here or in subclasses
|
||||
* but no execution order is guaranteed
|
||||
*/
|
||||
@Before
|
||||
@Override
|
||||
public void init() {
|
||||
super.init();
|
||||
try {
|
||||
context.turnOffAuthorisationSystem();
|
||||
// Set up logical statement lists for operator testing
|
||||
setUpStatements();
|
||||
// Set up DSpace resources for condition and filter testing
|
||||
// Set up first community, collection and item
|
||||
this.communityOne = communityService.create(null, context);
|
||||
this.collectionOne = collectionService.create(context, communityOne);
|
||||
WorkspaceItem workspaceItem = workspaceItemService.create(context, collectionOne, false);
|
||||
this.itemOne = installItemService.installItem(context, workspaceItem);
|
||||
// Add one bitstream to item one, but put it in THUMBNAIL bundle
|
||||
bundleService.addBitstream(context, bundleService.create(context, itemOne, "THUMBNAIL"),
|
||||
bitstreamService.create(context,
|
||||
new ByteArrayInputStream("Item 1 Thumbnail 1".getBytes(StandardCharsets.UTF_8))));
|
||||
// Set up second community, collection and item, and third item
|
||||
this.communityTwo = communityService.create(null, context);
|
||||
this.collectionTwo = collectionService.create(context, communityTwo);
|
||||
// Item two
|
||||
workspaceItem = workspaceItemService.create(context, collectionTwo, false);
|
||||
this.itemTwo = installItemService.installItem(context, workspaceItem);
|
||||
// Add two bitstreams to item two
|
||||
Bundle bundleTwo = bundleService.create(context, itemTwo, "ORIGINAL");
|
||||
bundleService.addBitstream(context, bundleTwo, bitstreamService.create(context,
|
||||
new ByteArrayInputStream("Item 2 Bitstream 1".getBytes(StandardCharsets.UTF_8))));
|
||||
bundleService.addBitstream(context, bundleTwo, bitstreamService.create(context,
|
||||
new ByteArrayInputStream("Item 2 Bitstream 2".getBytes(StandardCharsets.UTF_8))));
|
||||
// Item three
|
||||
workspaceItem = workspaceItemService.create(context, collectionTwo, false);
|
||||
this.itemThree = installItemService.installItem(context, workspaceItem);
|
||||
// Add three bitstreams to item three
|
||||
Bundle bundleThree = bundleService.create(context, itemThree, "ORIGINAL");
|
||||
bundleService.addBitstream(context, bundleThree, bitstreamService.create(context,
|
||||
new ByteArrayInputStream("Item 3 Bitstream 1".getBytes(StandardCharsets.UTF_8))));
|
||||
bundleService.addBitstream(context, bundleThree, bitstreamService.create(context,
|
||||
new ByteArrayInputStream("Item 3 Bitstream 2".getBytes(StandardCharsets.UTF_8))));
|
||||
bundleService.addBitstream(context, bundleThree, bitstreamService.create(context,
|
||||
new ByteArrayInputStream("Item 3 Bitstream 2".getBytes(StandardCharsets.UTF_8))));
|
||||
|
||||
// Withdraw the second item for later testing
|
||||
itemService.withdraw(context, itemTwo);
|
||||
// Initialise metadata field for later testing with both items
|
||||
this.metadataField = metadataFieldService.findByElement(context,
|
||||
MetadataSchemaEnum.DC.getName(), element, qualifier);
|
||||
context.restoreAuthSystemState();
|
||||
} catch (AuthorizeException | SQLException | IOException e) {
|
||||
log.error("Error encountered during init", e);
|
||||
fail("Error encountered during init: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be run after every test as per @After. It will
|
||||
* clean resources initialized by the @Before methods.
|
||||
*
|
||||
* Other methods can be annotated with @After here or in subclasses
|
||||
* but no execution order is guaranteed
|
||||
*/
|
||||
@After
|
||||
@Override
|
||||
public void destroy() {
|
||||
context.turnOffAuthorisationSystem();
|
||||
// Delete resources
|
||||
try {
|
||||
itemService.delete(context, itemOne);
|
||||
itemService.delete(context, itemTwo);
|
||||
itemService.delete(context, itemThree);
|
||||
collectionService.delete(context, collectionOne);
|
||||
collectionService.delete(context, collectionTwo);
|
||||
communityService.delete(context, communityOne);
|
||||
communityService.delete(context, communityTwo);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
log.error("Error cleaning up test resources: " + e.getMessage());
|
||||
}
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
// Set all class members to null
|
||||
communityOne = null;
|
||||
communityTwo = null;
|
||||
collectionOne = null;
|
||||
collectionTwo = null;
|
||||
itemOne = null;
|
||||
itemTwo = null;
|
||||
itemThree = null;
|
||||
trueStatements = null;
|
||||
trueFalseStatements = null;
|
||||
falseStatements = null;
|
||||
trueStatementOne = null;
|
||||
falseStatementOne = null;
|
||||
element = null;
|
||||
qualifier = null;
|
||||
metadataField = null;
|
||||
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the AND operator with simple lists of logical statements
|
||||
*/
|
||||
@Test
|
||||
public void testAndOperator() {
|
||||
// Blank operator
|
||||
And and = new And();
|
||||
// Try tests
|
||||
try {
|
||||
// Set to True, True (expect True)
|
||||
and.setStatements(trueStatements);
|
||||
assertTrue("AND operator did not return true for a list of true statements",
|
||||
and.getResult(context, itemOne));
|
||||
// Set to True, False (expect False)
|
||||
and.setStatements(trueFalseStatements);
|
||||
assertFalse("AND operator did not return false for a list of statements with at least one false",
|
||||
and.getResult(context, itemOne));
|
||||
// Set to False, False (expect False)
|
||||
and.setStatements(falseStatements);
|
||||
assertFalse("AND operator did not return false for a list of false statements",
|
||||
and.getResult(context, itemOne));
|
||||
} catch (LogicalStatementException e) {
|
||||
log.error(e.getMessage());
|
||||
fail("LogicalStatementException thrown testing the AND operator" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the OR operator with simple lists of logical statements
|
||||
*/
|
||||
@Test
|
||||
public void testOrOperator() {
|
||||
// Blank operator
|
||||
Or or = new Or();
|
||||
// Try tests
|
||||
try {
|
||||
// Set to True, True (expect True)
|
||||
or.setStatements(trueStatements);
|
||||
assertTrue("OR operator did not return true for a list of true statements",
|
||||
or.getResult(context, itemOne));
|
||||
// Set to True, False (expect True)
|
||||
or.setStatements(trueFalseStatements);
|
||||
assertTrue("OR operator did not return true for a list of statements with at least one false",
|
||||
or.getResult(context, itemOne));
|
||||
// Set to False, False (expect False)
|
||||
or.setStatements(falseStatements);
|
||||
assertFalse("OR operator did not return false for a list of false statements",
|
||||
or.getResult(context, itemOne));
|
||||
} catch (LogicalStatementException e) {
|
||||
log.error(e.getMessage());
|
||||
fail("LogicalStatementException thrown testing the OR operator" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the NAND operator with simple lists of logical statements
|
||||
*/
|
||||
@Test
|
||||
public void testNandOperator() {
|
||||
// Blank operator
|
||||
Nand nand = new Nand();
|
||||
// Try tests
|
||||
try {
|
||||
// Set to True, True (expect False)
|
||||
nand.setStatements(trueStatements);
|
||||
assertFalse("NAND operator did not return false for a list of true statements",
|
||||
nand.getResult(context, itemOne));
|
||||
// Set to True, False (expect True)
|
||||
nand.setStatements(trueFalseStatements);
|
||||
assertTrue("NAND operator did not return true for a list of statements with at least one false",
|
||||
nand.getResult(context, itemOne));
|
||||
// Set to False, False (expect True)
|
||||
nand.setStatements(falseStatements);
|
||||
assertTrue("NAND operator did not return true for a list of false statements",
|
||||
nand.getResult(context, itemOne));
|
||||
} catch (LogicalStatementException e) {
|
||||
log.error(e.getMessage());
|
||||
fail("LogicalStatementException thrown testing the NAND operator" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the NOR operator with simple lists of logical statements
|
||||
*/
|
||||
@Test
|
||||
public void testNorOperator() {
|
||||
// Blank operator
|
||||
Nor nor = new Nor();
|
||||
// Try tests
|
||||
try {
|
||||
// Set to True, True (expect False)
|
||||
nor.setStatements(trueStatements);
|
||||
assertFalse("NOR operator did not return false for a list of true statements",
|
||||
nor.getResult(context, itemOne));
|
||||
// Set to True, False (expect False)
|
||||
nor.setStatements(trueFalseStatements);
|
||||
assertFalse("NOR operator did not return false for a list of statements with a true and a false",
|
||||
nor.getResult(context, itemOne));
|
||||
// Set to False, False (expect True)
|
||||
nor.setStatements(falseStatements);
|
||||
assertTrue("NOR operator did not return true for a list of false statements",
|
||||
nor.getResult(context, itemOne));
|
||||
} catch (LogicalStatementException e) {
|
||||
log.error(e.getMessage());
|
||||
fail("LogicalStatementException thrown testing the NOR operator" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the NOT operator with simple individual true/false statements
|
||||
*/
|
||||
@Test
|
||||
public void testNotOperator() {
|
||||
// Blank operator
|
||||
Not not = new Not();
|
||||
// Try tests
|
||||
try {
|
||||
// Set to True (expect False)
|
||||
not.setStatements(trueStatementOne);
|
||||
assertFalse("NOT operator did not return false for a true statement",
|
||||
not.getResult(context, itemOne));
|
||||
// Set to False (expect True)
|
||||
not.setStatements(falseStatementOne);
|
||||
assertTrue("NOT operator did not return true for a false statement",
|
||||
not.getResult(context, itemOne));
|
||||
} catch (LogicalStatementException e) {
|
||||
log.error(e.getMessage());
|
||||
fail("LogicalStatementException thrown testing the NOT operator" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a simple filter with a single logical statement: the MetadataValueMatchCondition
|
||||
* looking for a dc.title field beginning with "TEST", and an item that doesn't match this test
|
||||
*/
|
||||
@Test
|
||||
public void testMetadataValueMatchCondition() {
|
||||
try {
|
||||
MetadataValue metadataValueOne = metadataValueService.create(context, itemOne, metadataField);
|
||||
MetadataValue metadataValueTwo = metadataValueService.create(context, itemTwo, metadataField);
|
||||
metadataValueOne.setValue("TEST title should match the condition");
|
||||
metadataValueTwo.setValue("This title should not match the condition");
|
||||
} catch (SQLException e) {
|
||||
fail("Encountered SQL error creating metadata value on item: " + e.getMessage());
|
||||
}
|
||||
|
||||
// Instantiate new filter for testing this condition
|
||||
DefaultFilter filter = new DefaultFilter();
|
||||
|
||||
// Create condition to match pattern on dc.title metadata
|
||||
Condition condition = new MetadataValueMatchCondition();
|
||||
condition.setItemService(ContentServiceFactory.getInstance().getItemService());
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
// Match on the dc.title field
|
||||
parameters.put("field", "dc.title");
|
||||
// "Starts with "TEST" (case sensitive)
|
||||
parameters.put("pattern", "^TEST");
|
||||
// Set up condition with these parameters and add it as the sole statement to the metadata filter
|
||||
try {
|
||||
condition.setParameters(parameters);
|
||||
filter.setStatement(condition);
|
||||
// Test the filter on the first item - expected outcome is true
|
||||
assertTrue("itemOne unexpectedly did not match the 'dc.title starts with TEST' test",
|
||||
filter.getResult(context, itemOne));
|
||||
// Test the filter on the second item - expected outcome is false
|
||||
assertFalse("itemTwo unexpectedly matched the 'dc.title starts with TEST' test",
|
||||
filter.getResult(context, itemTwo));
|
||||
} catch (LogicalStatementException e) {
|
||||
log.error(e.getMessage());
|
||||
fail("LogicalStatementException thrown testing the MetadataValueMatchCondition filter" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a simple filter with a single logical statement: the MetadataValuesMatchCondition
|
||||
* looking for a dc.title field beginning with "TEST" or "ALSO", and an item that doesn't match this test
|
||||
*/
|
||||
@Test
|
||||
public void testMetadataValuesMatchCondition() {
|
||||
try {
|
||||
MetadataValue metadataValueOne = metadataValueService.create(context, itemOne, metadataField);
|
||||
MetadataValue metadataValueTwo = metadataValueService.create(context, itemTwo, metadataField);
|
||||
MetadataValue metadataValueThree = metadataValueService.create(context, itemThree, metadataField);
|
||||
metadataValueOne.setValue("TEST this title should match the condition");
|
||||
metadataValueTwo.setValue("This title should match the condition, yEs");
|
||||
metadataValueThree.setValue("This title should not match the condition");
|
||||
} catch (SQLException e) {
|
||||
fail("Encountered SQL error creating metadata value on item: " + e.getMessage());
|
||||
}
|
||||
|
||||
// Instantiate new filter for testing this condition
|
||||
DefaultFilter filter = new DefaultFilter();
|
||||
|
||||
// Create condition to match pattern on dc.title metadata
|
||||
Condition condition = new MetadataValuesMatchCondition();
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
// Match on the dc.title field
|
||||
parameters.put("field", "dc.title");
|
||||
|
||||
List<String> patterns = new ArrayList<>();
|
||||
// "Starts with "TEST" (case sensitive)
|
||||
patterns.add("^TEST");
|
||||
// "Ends with 'yes' (case insensitive)
|
||||
patterns.add("(?i)yes$");
|
||||
// Add the list of possible patterns
|
||||
parameters.put("patterns", patterns);
|
||||
|
||||
// Alternate parameters to test for a field where the item has no values
|
||||
Map<String, Object> missingParameters = new HashMap<>();
|
||||
// Match on the dc.subject field - none of our test items have this field set
|
||||
missingParameters.put("field", "dc.subject");
|
||||
// Add a pattern to the missing parameters
|
||||
missingParameters.put("patterns", new ArrayList<>().add("TEST"));
|
||||
|
||||
// Set up condition with these parameters and add it as the sole statement to the metadata filter
|
||||
try {
|
||||
condition.setParameters(parameters);
|
||||
filter.setStatement(condition);
|
||||
// Test the filter on the first item - expected outcome is true
|
||||
assertTrue("itemOne unexpectedly did not match the " +
|
||||
"'dc.title starts with TEST or ends with yes' test", filter.getResult(context, itemOne));
|
||||
// Test the filter on the second item - expected outcome is true
|
||||
assertTrue("itemTwo unexpectedly did not match the " +
|
||||
"'dc.title starts with TEST or ends with yes' test", filter.getResult(context, itemTwo));
|
||||
// Test the filter on the third item - expected outcome is false
|
||||
assertFalse("itemThree unexpectedly matched the " +
|
||||
"'dc.title starts with TEST or ends with yes' test", filter.getResult(context, itemThree));
|
||||
// Set condition and filter to use the missing field instead
|
||||
condition.setParameters(missingParameters);
|
||||
filter.setStatement(condition);
|
||||
// Test this updated filter against the first item - expected outcome is false
|
||||
assertFalse("itemOne unexpectedly matched the 'dc.subject contains TEST' test" +
|
||||
"(it has no dc.subject metadata value)", filter.getResult(context, itemOne));
|
||||
} catch (LogicalStatementException e) {
|
||||
log.error(e.getMessage());
|
||||
fail("LogicalStatementException thrown testing the MetadataValuesMatchCondition filter" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a simple filter with a single logical statement: the InCollectionCondition
|
||||
* looking for an item that is in collectionOne, and one that is not in collectionOne
|
||||
*/
|
||||
@Test
|
||||
public void testInCollectionCondition() {
|
||||
// Instantiate new filter for testing this condition
|
||||
DefaultFilter filter = new DefaultFilter();
|
||||
Condition condition = new InCollectionCondition();
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
|
||||
// Add collectionOne handle to the collections parameter - ie. we are testing to see if the item is
|
||||
// in collectionOne only
|
||||
List<String> collections = new ArrayList<>();
|
||||
collections.add(collectionOne.getHandle());
|
||||
parameters.put("collections", collections);
|
||||
|
||||
try {
|
||||
// Set parameters and condition
|
||||
condition.setParameters(parameters);
|
||||
filter.setStatement(condition);
|
||||
|
||||
// Test the filter on the first item - this item is in collectionOne: expected outcome is true
|
||||
assertTrue("itemOne unexpectedly did not match the 'item in collectionOne' test",
|
||||
filter.getResult(context, itemOne));
|
||||
// Test the filter on the second item - this item is NOT in collectionOne: expected outcome is false
|
||||
assertFalse("itemTwo unexpectedly matched the 'item in collectionOne' test",
|
||||
filter.getResult(context, itemTwo));
|
||||
} catch (LogicalStatementException e) {
|
||||
log.error(e.getMessage());
|
||||
fail("LogicalStatementException thrown testing the InCollectionCondition filter" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a simple filter with a single logical statement: the InCommunityCondition
|
||||
* looking for an item that is in communityOne, and one that is not in communityOne
|
||||
*/
|
||||
@Test
|
||||
public void testInCommunityCondition() {
|
||||
// Instantiate new filter for testing this condition
|
||||
DefaultFilter filter = new DefaultFilter();
|
||||
Condition condition = new InCommunityCondition();
|
||||
condition.setItemService(ContentServiceFactory.getInstance().getItemService());
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
|
||||
// Add communitynOne handle to the communities parameter - ie. we are testing to see if the item is
|
||||
// in communityOne only
|
||||
List<String> communities = new ArrayList<>();
|
||||
communities.add(communityOne.getHandle());
|
||||
parameters.put("communities", communities);
|
||||
|
||||
try {
|
||||
// Set parameters and condition
|
||||
condition.setParameters(parameters);
|
||||
filter.setStatement(condition);
|
||||
|
||||
// Test the filter on the first item - this item is in communityOne: expected outcome is true
|
||||
assertTrue("itemOne unexpectedly did not match the 'item in communityOne' test",
|
||||
filter.getResult(context, itemOne));
|
||||
// Test the filter on the second item - this item is NOT in communityOne: expected outcome is false
|
||||
assertFalse("itemTwo unexpectedly matched the 'item in communityOne' test",
|
||||
filter.getResult(context, itemTwo));
|
||||
} catch (LogicalStatementException e) {
|
||||
log.error(e.getMessage());
|
||||
fail("LogicalStatementException thrown testing the InCommunityCondition filter" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a simple filter with the IsWithdrawnCondition. During setup, itemTwo was withdrawn.
|
||||
*/
|
||||
@Test
|
||||
public void testIsWithdrawnCondition() {
|
||||
// Instantiate new filter for testing this condition
|
||||
DefaultFilter filter = new DefaultFilter();
|
||||
Condition condition = new IsWithdrawnCondition();
|
||||
|
||||
try {
|
||||
condition.setItemService(ContentServiceFactory.getInstance().getItemService());
|
||||
condition.setParameters(new HashMap<>());
|
||||
filter.setStatement(condition);
|
||||
|
||||
// Test the filter on itemOne - this item is not withdrawn: expected outcome is false
|
||||
assertFalse("itemOne unexpectedly matched the 'item is withdrawn' test",
|
||||
filter.getResult(context, itemOne));
|
||||
// Test the filter on itemTwo - this item was withdrawn in setup: expected outcome is true
|
||||
assertTrue("itemTwo unexpectedly did NOT match the 'item is withdrawn' test",
|
||||
filter.getResult(context, itemTwo));
|
||||
} catch (LogicalStatementException e) {
|
||||
log.error(e.getMessage());
|
||||
fail("LogicalStatementException thrown testing the IsWithdrawnCondition filter" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a simple filter with the BitstreamCountCondition.
|
||||
*/
|
||||
@Test
|
||||
public void testBitstreamCountCondition() {
|
||||
// Instantiate new filter for testing this condition
|
||||
DefaultFilter filter = new DefaultFilter();
|
||||
Condition condition = new BitstreamCountCondition();
|
||||
|
||||
try {
|
||||
condition.setItemService(ContentServiceFactory.getInstance().getItemService());
|
||||
|
||||
// Set parameters to check for items with at least 1 and at most 2 bitstreams in the ORIGINAL bundle
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
parameters.put("bundle", "ORIGINAL");
|
||||
parameters.put("min", String.valueOf(1));
|
||||
parameters.put("max", String.valueOf(2));
|
||||
condition.setParameters(parameters);
|
||||
filter.setStatement(condition);
|
||||
|
||||
// Test the filter on itemOne - this item has one THUMBNAIL but zero ORIGINAL bitstreams: expect false
|
||||
assertFalse("itemOne unexpectedly matched the '>=1 and <=2 ORIGINAL bitstreams' test" +
|
||||
" (it has zero ORIGINAL bitstreams)", filter.getResult(context, itemOne));
|
||||
// Test the filter on itemTwo - this item has two ORIGINAL bitstreams: expect true
|
||||
assertTrue("itemTwo unexpectedly did NOT match the '>=1 and <=2 ORIGINAL bitstreams' test" +
|
||||
" (it has 2 ORIGINAL bitstreams)", filter.getResult(context, itemTwo));
|
||||
// Test the filter on itemTwo - this item has three ORIGINAL bitstreams: expect false
|
||||
assertFalse("itemThree unexpectedly did NOT match the '>=1 and <=2 ORIGINAL bitstreams' test" +
|
||||
" (it has 3 ORIGINAL bitstreams)", filter.getResult(context, itemThree));
|
||||
} catch (LogicalStatementException e) {
|
||||
log.error(e.getMessage());
|
||||
fail("LogicalStatementException thrown testing the IsWithdrawnCondition filter: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a simple filter using the ReadableByGroupCondition
|
||||
*/
|
||||
@Test
|
||||
public void testReadableByGroupCondition() {
|
||||
// Instantiate new filter for testing this condition
|
||||
DefaultFilter filter = new DefaultFilter();
|
||||
Condition condition = new ReadableByGroupCondition();
|
||||
|
||||
try {
|
||||
condition.setItemService(ContentServiceFactory.getInstance().getItemService());
|
||||
|
||||
// Make item one readable by Test Group
|
||||
try {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Group g = groupService.create(context);
|
||||
groupService.setName(g, "Test Group");
|
||||
groupService.update(context, g);
|
||||
authorizeService.addPolicy(context, itemOne, Constants.READ, g);
|
||||
context.restoreAuthSystemState();
|
||||
} catch (AuthorizeException | SQLException e) {
|
||||
fail("Exception thrown adding group READ policy to item: " + itemOne + ": " + e.getMessage());
|
||||
}
|
||||
// Set parameters to check for items with Anonymous READ permission
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
parameters.put("group", "Test Group");
|
||||
parameters.put("action", "READ");
|
||||
condition.setParameters(parameters);
|
||||
filter.setStatement(condition);
|
||||
|
||||
// Test the filter on itemOne - this item was explicitly set with expected group READ policy
|
||||
assertTrue("itemOne unexpectedly did not match the 'is readable by Test Group' test",
|
||||
filter.getResult(context, itemOne));
|
||||
// Test the filter on itemTwo - this item has no policies: expect false
|
||||
assertFalse("itemTwo unexpectedly matched the 'is readable by Test Group' test",
|
||||
filter.getResult(context, itemTwo));
|
||||
} catch (LogicalStatementException e) {
|
||||
log.error(e.getMessage());
|
||||
fail("LogicalStatementException thrown testing the ReadableByGroup filter" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up some simple statements for testing out operators
|
||||
*/
|
||||
private void setUpStatements() {
|
||||
// Simple lambdas to define statements
|
||||
// The two class members are used elsewhere, as direct statements for NOT testing
|
||||
trueStatementOne = (context, item) -> true;
|
||||
LogicalStatement trueStatementTwo = (context, item) -> true;
|
||||
falseStatementOne = (context, item) -> false;
|
||||
LogicalStatement falseStatementTwo = (context, item) -> false;
|
||||
|
||||
// Create lists and add the statements
|
||||
// True, True
|
||||
trueStatements = new ArrayList<>();
|
||||
trueStatements.add(trueStatementOne);
|
||||
trueStatements.add(trueStatementTwo);
|
||||
// True, False
|
||||
trueFalseStatements = new ArrayList<>();
|
||||
trueFalseStatements.add(trueStatementOne);
|
||||
trueFalseStatements.add(falseStatementOne);
|
||||
// False, False
|
||||
falseStatements = new ArrayList<>();
|
||||
falseStatements.add(falseStatementOne);
|
||||
falseStatements.add(falseStatementTwo);
|
||||
}
|
||||
}
|
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.eperson;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.dspace.AbstractIntegrationTest;
|
||||
import org.dspace.util.FakeConsoleServiceImpl;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.contrib.java.lang.system.ExpectedSystemExit;
|
||||
import org.junit.contrib.java.lang.system.SystemErrRule;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Mark H. Wood <mwood@iupui.edu>
|
||||
*/
|
||||
public class EPersonCLIToolIT
|
||||
extends AbstractIntegrationTest {
|
||||
private static final String NEW_PASSWORD = "secret";
|
||||
private static final String BAD_PASSWORD = "not secret";
|
||||
|
||||
// Handle System.exit() from unit under test.
|
||||
@Rule
|
||||
public final ExpectedSystemExit exit = ExpectedSystemExit.none();
|
||||
|
||||
// Capture System.err() output.
|
||||
@Rule
|
||||
public final SystemErrRule sysErr = new SystemErrRule().enableLog();
|
||||
|
||||
/**
|
||||
* Test --modify --newPassword
|
||||
* @throws Exception passed through.
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("static-access")
|
||||
public void testSetPassword()
|
||||
throws Exception {
|
||||
exit.expectSystemExitWithStatus(0);
|
||||
System.out.println("main");
|
||||
|
||||
// Create a source of "console" input.
|
||||
FakeConsoleServiceImpl consoleService = new FakeConsoleServiceImpl();
|
||||
consoleService.setPassword(NEW_PASSWORD.toCharArray());
|
||||
|
||||
// Make certain that we know the eperson's email and old password hash.
|
||||
String email = eperson.getEmail();
|
||||
String oldPasswordHash = eperson.getPassword();
|
||||
|
||||
// Instantiate the unit under test.
|
||||
EPersonCLITool instance = new EPersonCLITool();
|
||||
instance.setConsoleService(consoleService);
|
||||
|
||||
// Test!
|
||||
String[] argv = {
|
||||
"--modify",
|
||||
"--email", email,
|
||||
"--newPassword"
|
||||
};
|
||||
instance.main(argv);
|
||||
|
||||
String newPasswordHash = eperson.getPassword();
|
||||
assertNotEquals("Password hash did not change", oldPasswordHash, newPasswordHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test --modify --newPassword with an empty password
|
||||
* @throws Exception passed through.
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("static-access")
|
||||
public void testSetEmptyPassword()
|
||||
throws Exception {
|
||||
exit.expectSystemExitWithStatus(0);
|
||||
System.out.println("main");
|
||||
|
||||
// Create a source of "console" input.
|
||||
FakeConsoleServiceImpl consoleService = new FakeConsoleServiceImpl();
|
||||
consoleService.setPassword(new char[0]);
|
||||
|
||||
// Make certain that we know the eperson's email and old password hash.
|
||||
String email = eperson.getEmail();
|
||||
String oldPasswordHash = eperson.getPassword();
|
||||
|
||||
// Instantiate the unit under test.
|
||||
EPersonCLITool instance = new EPersonCLITool();
|
||||
instance.setConsoleService(consoleService);
|
||||
|
||||
// Test!
|
||||
String[] argv = {
|
||||
"--modify",
|
||||
"--email", email,
|
||||
"--newPassword"
|
||||
};
|
||||
instance.main(argv);
|
||||
|
||||
String newPasswordHash = eperson.getPassword();
|
||||
assertEquals("Password hash changed", oldPasswordHash, newPasswordHash);
|
||||
|
||||
String stderr = sysErr.getLog();
|
||||
assertTrue("Standard error did not mention 'empty'",
|
||||
stderr.contains(EPersonCLITool.ERR_PASSWORD_EMPTY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test --modify --newPassword with mismatched confirmation.
|
||||
* This tests what happens when the user enters different strings at the
|
||||
* first and second new-password prompts.
|
||||
* @throws Exception passed through.
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("static-access")
|
||||
public void testSetMismatchedPassword()
|
||||
throws Exception {
|
||||
exit.expectSystemExitWithStatus(0);
|
||||
System.out.println("main");
|
||||
|
||||
// Create a source of "console" input.
|
||||
FakeConsoleServiceImpl consoleService = new FakeConsoleServiceImpl();
|
||||
consoleService.setPassword1(NEW_PASSWORD.toCharArray());
|
||||
consoleService.setPassword2(BAD_PASSWORD.toCharArray());
|
||||
|
||||
// Make certain that we know the eperson's email and old password hash.
|
||||
String email = eperson.getEmail();
|
||||
String oldPasswordHash = eperson.getPassword();
|
||||
|
||||
// Instantiate the unit under test.
|
||||
EPersonCLITool instance = new EPersonCLITool();
|
||||
instance.setConsoleService(consoleService);
|
||||
|
||||
// Test!
|
||||
String[] argv = {
|
||||
"--modify",
|
||||
"--email", email,
|
||||
"--newPassword"
|
||||
};
|
||||
instance.main(argv);
|
||||
|
||||
String newPasswordHash = eperson.getPassword();
|
||||
assertEquals("Password hash changed", oldPasswordHash, newPasswordHash);
|
||||
|
||||
String stderr = sysErr.getLog();
|
||||
assertTrue("Standard error did not indicate password mismatch",
|
||||
stderr.contains(EPersonCLITool.ERR_PASSWORD_NOMATCH));
|
||||
}
|
||||
}
|
@@ -34,12 +34,15 @@ import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.logic.DefaultFilter;
|
||||
import org.dspace.content.logic.LogicalStatement;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.CommunityService;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.content.service.WorkspaceItemService;
|
||||
import org.dspace.identifier.doi.DOIConnector;
|
||||
import org.dspace.identifier.doi.DOIIdentifierException;
|
||||
import org.dspace.identifier.doi.DOIIdentifierNotApplicableException;
|
||||
import org.dspace.identifier.factory.IdentifierServiceFactory;
|
||||
import org.dspace.identifier.service.DOIService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
@@ -125,6 +128,7 @@ public class DOIIdentifierProviderTest
|
||||
provider.itemService = itemService;
|
||||
provider.setConfigurationService(config);
|
||||
provider.setDOIConnector(connector);
|
||||
provider.setFilterService(null);
|
||||
} catch (AuthorizeException ex) {
|
||||
log.error("Authorization Error in init", ex);
|
||||
fail("Authorization Error in init: " + ex.getMessage());
|
||||
@@ -499,8 +503,8 @@ public class DOIIdentifierProviderTest
|
||||
Item item = newItem();
|
||||
String doi = null;
|
||||
try {
|
||||
// get a DOI:
|
||||
doi = provider.mint(context, item);
|
||||
// get a DOI (skipping any filters)
|
||||
doi = provider.mint(context, item, true);
|
||||
} catch (IdentifierException e) {
|
||||
e.printStackTrace(System.err);
|
||||
fail("Got an IdentifierException: " + e.getMessage());
|
||||
@@ -530,6 +534,82 @@ public class DOIIdentifierProviderTest
|
||||
assertEquals("Mint did not returned an existing DOI!", doi, retrievedDOI);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test minting a DOI with a filter that always returns false and therefore never mints the DOI
|
||||
*/
|
||||
@Test
|
||||
public void testMint_DOI_withNonMatchingFilter()
|
||||
throws SQLException, AuthorizeException, IOException, IllegalAccessException, IdentifierException,
|
||||
WorkflowException {
|
||||
Item item = newItem();
|
||||
boolean wasFiltered = false;
|
||||
try {
|
||||
// Temporarily set the provider to have a filter that always returns false for an item
|
||||
// (therefore, the item should be 'filtered' out and not apply to this minting request)
|
||||
DefaultFilter doiFilter = new DefaultFilter();
|
||||
LogicalStatement alwaysFalse = (context, i) -> false;
|
||||
doiFilter.setStatement(alwaysFalse);
|
||||
provider.setFilterService(doiFilter);
|
||||
// get a DOI with the method that applies filters by default
|
||||
provider.mint(context, item);
|
||||
} catch (DOIIdentifierNotApplicableException e) {
|
||||
// This is what we wanted to see - we can return safely
|
||||
wasFiltered = true;
|
||||
} catch (IdentifierException e) {
|
||||
e.printStackTrace();
|
||||
fail("Got an IdentifierException: " + e.getMessage());
|
||||
} finally {
|
||||
// Set filter service back to null
|
||||
provider.setFilterService(null);
|
||||
}
|
||||
// Fail the test if the filter didn't throw a "not applicable" exception
|
||||
assertTrue("DOI minting attempt was not filtered by filter service", wasFiltered);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test minting a DOI with a filter that always returns true and therefore allows the DOI to be minted
|
||||
* (this should have hte same results as base testMint_DOI, but here we use an explicit filter rather than null)
|
||||
*/
|
||||
@Test
|
||||
public void testMint_DOI_withMatchingFilter()
|
||||
throws SQLException, AuthorizeException, IOException, IllegalAccessException, IdentifierException,
|
||||
WorkflowException {
|
||||
Item item = newItem();
|
||||
String doi = null;
|
||||
boolean wasFiltered = false;
|
||||
try {
|
||||
// Temporarily set the provider to have a filter that always returns true for an item
|
||||
// (therefore, the item is allowed to have a DOI minted)
|
||||
DefaultFilter doiFilter = new DefaultFilter();
|
||||
LogicalStatement alwaysTrue = (context, i) -> true;
|
||||
doiFilter.setStatement(alwaysTrue);
|
||||
provider.setFilterService(doiFilter);
|
||||
// get a DOI with the method that applies filters by default
|
||||
doi = provider.mint(context, item);
|
||||
} catch (DOIIdentifierNotApplicableException e) {
|
||||
// This is what we wanted to see - we can return safely
|
||||
wasFiltered = true;
|
||||
} catch (IdentifierException e) {
|
||||
e.printStackTrace();
|
||||
fail("Got an IdentifierException: " + e.getMessage());
|
||||
} finally {
|
||||
provider.setFilterService(null);
|
||||
}
|
||||
// If the attempt was filtered, fail
|
||||
assertFalse("DOI minting attempt was incorrectly filtered by filter service", wasFiltered);
|
||||
|
||||
// Continue with regular minting tests
|
||||
assertNotNull("Minted DOI is null!", doi);
|
||||
assertFalse("Minted DOI is empty!", doi.isEmpty());
|
||||
try {
|
||||
doiService.formatIdentifier(doi);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail("Minted an unrecognizable DOI: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testReserve_DOI()
|
||||
throws SQLException, SQLException, AuthorizeException, IOException,
|
||||
@@ -584,7 +664,8 @@ public class DOIIdentifierProviderTest
|
||||
IdentifierException, WorkflowException, IllegalAccessException {
|
||||
Item item = newItem();
|
||||
|
||||
String doi = provider.register(context, item);
|
||||
// Register, skipping the filter
|
||||
String doi = provider.register(context, item, true);
|
||||
|
||||
// we want the created DOI to be returned in the following format:
|
||||
// doi:10.<prefix>/<suffix>.
|
||||
|
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* 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.util;
|
||||
|
||||
/**
|
||||
* A test version of ConsoleService which supplies any password input that we
|
||||
* want.
|
||||
*
|
||||
* <p>This can return different passwords on even/odd calls, to test
|
||||
* confirmation dialogs. See {@link setPassword1} and {@link setPassword2}.
|
||||
* Use {@link setPassword} to set both identically.
|
||||
*
|
||||
* @author Mark H. Wood <mwood@iupui.edu>
|
||||
*/
|
||||
public class FakeConsoleServiceImpl
|
||||
implements ConsoleService {
|
||||
private String prompt;
|
||||
private Object[] args;
|
||||
private char[] password1;
|
||||
private char[] password2;
|
||||
private int passwordCalls = 0;
|
||||
|
||||
@Override
|
||||
public char[] readPassword(String prompt, Object... args) {
|
||||
this.prompt = prompt;
|
||||
this.args = args;
|
||||
passwordCalls++;
|
||||
if (passwordCalls % 2 != 0) {
|
||||
return password1;
|
||||
} else {
|
||||
return password2;
|
||||
}
|
||||
}
|
||||
|
||||
public String getPasswordPrompt() {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return this.args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set both passwords identically.
|
||||
* @param password the password to be returned each time.
|
||||
*/
|
||||
public void setPassword(char[] password) {
|
||||
setPassword1(password);
|
||||
setPassword2(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the password returned on odd calls to {@link readPassword}.
|
||||
* @param password the password to be returned.
|
||||
*/
|
||||
public void setPassword1(char[] password) {
|
||||
password1 = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the password returned on even calls to {@link readPassword},
|
||||
* and reset the call counter.
|
||||
* @param password the password to be returned.
|
||||
*/
|
||||
public void setPassword2(char[] password) {
|
||||
password2 = password;
|
||||
passwordCalls = 0;
|
||||
}
|
||||
}
|
@@ -21,7 +21,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.dspace.app.rest.matcher.MetadataFieldMatcher;
|
||||
@@ -967,9 +970,13 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
|
||||
|
||||
@Test
|
||||
public void findAllPaginationTest() throws Exception {
|
||||
|
||||
// Determine number of metadata fields from database
|
||||
int numberOfMdFields = ContentServiceFactory.getInstance().getMetadataFieldService().findAll(context).size();
|
||||
List<MetadataField> alphabeticMdFields =
|
||||
ContentServiceFactory.getInstance()
|
||||
.getMetadataFieldService()
|
||||
.findAll(context).stream()
|
||||
.sorted(Comparator.comparing(mdf -> mdf.toString('.')))
|
||||
.collect(Collectors.toList());
|
||||
int numberOfMdFields = alphabeticMdFields.size();
|
||||
|
||||
// If we return 3 fields per page, determine number of pages we expect
|
||||
int pageSize = 3;
|
||||
@@ -983,9 +990,9 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
|
||||
.andExpect(content().contentType(contentType))
|
||||
// Metadata fields are returned alphabetically. So, look for the first 3 alphabetically
|
||||
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItems(
|
||||
MetadataFieldMatcher.matchMetadataFieldByKeys("creativework","datePublished", null),
|
||||
MetadataFieldMatcher.matchMetadataFieldByKeys("creativework", "editor", null),
|
||||
MetadataFieldMatcher.matchMetadataFieldByKeys("creativework", "keywords", null)
|
||||
MetadataFieldMatcher.matchMetadataField(alphabeticMdFields.get(0)),
|
||||
MetadataFieldMatcher.matchMetadataField(alphabeticMdFields.get(1)),
|
||||
MetadataFieldMatcher.matchMetadataField(alphabeticMdFields.get(2))
|
||||
)))
|
||||
.andExpect(jsonPath("$._links.first.href", Matchers.allOf(
|
||||
Matchers.containsString("/api/core/metadatafields?"),
|
||||
@@ -1012,9 +1019,9 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
|
||||
.andExpect(content().contentType(contentType))
|
||||
// Metadata fields are returned alphabetically. So, look for the next 3 alphabetically
|
||||
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItems(
|
||||
MetadataFieldMatcher.matchMetadataFieldByKeys("creativework","publisher", null),
|
||||
MetadataFieldMatcher.matchMetadataFieldByKeys("creativeworkseries", "issn", null),
|
||||
MetadataFieldMatcher.matchMetadataFieldByKeys("dc", "contributor", null)
|
||||
MetadataFieldMatcher.matchMetadataField(alphabeticMdFields.get(3)),
|
||||
MetadataFieldMatcher.matchMetadataField(alphabeticMdFields.get(4)),
|
||||
MetadataFieldMatcher.matchMetadataField(alphabeticMdFields.get(5))
|
||||
)))
|
||||
.andExpect(jsonPath("$._links.first.href", Matchers.allOf(
|
||||
Matchers.containsString("/api/core/metadatafields?"),
|
||||
|
@@ -22,6 +22,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -81,24 +82,14 @@ public class ScriptRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
getClient(token).perform(get("/api/system/scripts"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.scripts", containsInAnyOrder(
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(0).getName(),
|
||||
scriptConfigurations.get(0).getDescription()),
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(1).getName(),
|
||||
scriptConfigurations.get(1).getDescription()),
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(2).getName(),
|
||||
scriptConfigurations.get(2).getDescription()),
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(3).getName(),
|
||||
scriptConfigurations.get(3).getDescription()),
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(4).getName(),
|
||||
scriptConfigurations.get(4).getDescription()),
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(5).getName(),
|
||||
scriptConfigurations.get(5).getDescription()),
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(6).getName(),
|
||||
scriptConfigurations.get(6).getDescription()),
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(7).getName(),
|
||||
scriptConfigurations.get(7).getDescription())
|
||||
scriptConfigurations
|
||||
.stream()
|
||||
.map(scriptConfiguration -> ScriptMatcher.matchScript(
|
||||
scriptConfiguration.getName(),
|
||||
scriptConfiguration.getDescription()
|
||||
))
|
||||
.collect(Collectors.toList())
|
||||
)));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -113,18 +104,26 @@ public class ScriptRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void findAllScriptsPaginationTest() throws Exception {
|
||||
List<ScriptConfiguration> alphabeticScripts =
|
||||
scriptConfigurations.stream()
|
||||
.sorted(Comparator.comparing(s -> s.getClass().getName()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
int totalPages = scriptConfigurations.size();
|
||||
int lastPage = totalPages - 1;
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
// NOTE: the scripts are always returned in alphabetical order by fully qualified class name.
|
||||
getClient(token).perform(get("/api/system/scripts").param("size", "1"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.scripts", Matchers.not(Matchers.hasItem(
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(2).getName(),
|
||||
scriptConfigurations.get(2).getDescription())
|
||||
ScriptMatcher.matchScript(alphabeticScripts.get(1).getName(),
|
||||
alphabeticScripts.get(1).getDescription())
|
||||
))))
|
||||
.andExpect(jsonPath("$._embedded.scripts", hasItem(
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(5).getName(),
|
||||
scriptConfigurations.get(5).getDescription())
|
||||
ScriptMatcher.matchScript(alphabeticScripts.get(0).getName(),
|
||||
alphabeticScripts.get(0).getDescription())
|
||||
)))
|
||||
.andExpect(jsonPath("$._links.first.href", Matchers.allOf(
|
||||
Matchers.containsString("/api/system/scripts?"),
|
||||
@@ -137,22 +136,22 @@ public class ScriptRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
Matchers.containsString("page=1"), Matchers.containsString("size=1"))))
|
||||
.andExpect(jsonPath("$._links.last.href", Matchers.allOf(
|
||||
Matchers.containsString("/api/system/scripts?"),
|
||||
Matchers.containsString("page=7"), Matchers.containsString("size=1"))))
|
||||
Matchers.containsString("page=" + lastPage), Matchers.containsString("size=1"))))
|
||||
.andExpect(jsonPath("$.page.size", is(1)))
|
||||
.andExpect(jsonPath("$.page.number", is(0)))
|
||||
.andExpect(jsonPath("$.page.totalPages", is(8)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(8)));
|
||||
.andExpect(jsonPath("$.page.totalPages", is(totalPages)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(totalPages)));
|
||||
|
||||
|
||||
getClient(token).perform(get("/api/system/scripts").param("size", "1").param("page", "1"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.scripts", hasItem(
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(2).getName(),
|
||||
scriptConfigurations.get(2).getDescription())
|
||||
ScriptMatcher.matchScript(alphabeticScripts.get(1).getName(),
|
||||
alphabeticScripts.get(1).getDescription())
|
||||
)))
|
||||
.andExpect(jsonPath("$._embedded.scripts", Matchers.not(hasItem(
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(5).getName(),
|
||||
scriptConfigurations.get(5).getDescription())
|
||||
ScriptMatcher.matchScript(alphabeticScripts.get(0).getName(),
|
||||
alphabeticScripts.get(0).getDescription())
|
||||
))))
|
||||
.andExpect(jsonPath("$._links.first.href", Matchers.allOf(
|
||||
Matchers.containsString("/api/system/scripts?"),
|
||||
@@ -168,11 +167,11 @@ public class ScriptRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
Matchers.containsString("page=2"), Matchers.containsString("size=1"))))
|
||||
.andExpect(jsonPath("$._links.last.href", Matchers.allOf(
|
||||
Matchers.containsString("/api/system/scripts?"),
|
||||
Matchers.containsString("page=7"), Matchers.containsString("size=1"))))
|
||||
Matchers.containsString("page=" + lastPage), Matchers.containsString("size=1"))))
|
||||
.andExpect(jsonPath("$.page.size", is(1)))
|
||||
.andExpect(jsonPath("$.page.number", is(1)))
|
||||
.andExpect(jsonPath("$.page.totalPages", is(8)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(8)));
|
||||
.andExpect(jsonPath("$.page.totalPages", is(totalPages)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(totalPages)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -183,7 +182,15 @@ public class ScriptRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", ScriptMatcher
|
||||
.matchMockScript(
|
||||
scriptConfigurations.get(scriptConfigurations.size() - 1).getOptions())));
|
||||
scriptConfigurations
|
||||
.stream()
|
||||
.filter(scriptConfiguration
|
||||
-> scriptConfiguration.getName().equals("mock-script"))
|
||||
.findAny()
|
||||
.orElseThrow()
|
||||
.getOptions()
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@@ -7,8 +7,6 @@
|
||||
*/
|
||||
package org.dspace.sword;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
@@ -54,6 +52,12 @@ public class SWORDUrlManager {
|
||||
private final ConfigurationService configurationService
|
||||
= DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
|
||||
private String swordPath = configurationService.getProperty(
|
||||
"sword-server.path", "sword");
|
||||
|
||||
private String dspaceUrl = configurationService.getProperty(
|
||||
"dspace.server.url");
|
||||
|
||||
public SWORDUrlManager(SWORDConfiguration config, Context context) {
|
||||
this.config = config;
|
||||
this.context = context;
|
||||
@@ -307,24 +311,12 @@ public class SWORDUrlManager {
|
||||
String depositUrl = configurationService.getProperty(
|
||||
"sword-server.servicedocument.url");
|
||||
if (depositUrl == null || "".equals(depositUrl)) {
|
||||
String dspaceUrl = configurationService.getProperty(
|
||||
"dspace.server.url");
|
||||
if (dspaceUrl == null || "".equals(dspaceUrl)) {
|
||||
throw new DSpaceSWORDException(
|
||||
"Unable to construct service document urls, due to missing/invalid " +
|
||||
"config in sword.servicedocument.url and/or dspace.server.url");
|
||||
}
|
||||
|
||||
try {
|
||||
URL url = new URL(dspaceUrl);
|
||||
depositUrl = new URL(url.getProtocol(), url.getHost(),
|
||||
url.getPort(), "/sword/servicedocument").toString();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new DSpaceSWORDException(
|
||||
"Unable to construct service document urls, due to invalid dspace.server.url " +
|
||||
e.getMessage(), e);
|
||||
}
|
||||
|
||||
depositUrl = buildSWORDUrl("servicedocument");
|
||||
}
|
||||
return depositUrl;
|
||||
}
|
||||
@@ -350,24 +342,12 @@ public class SWORDUrlManager {
|
||||
String depositUrl = configurationService.getProperty(
|
||||
"sword-server.deposit.url");
|
||||
if (depositUrl == null || "".equals(depositUrl)) {
|
||||
String dspaceUrl = configurationService.getProperty(
|
||||
"dspace.server.url");
|
||||
if (dspaceUrl == null || "".equals(dspaceUrl)) {
|
||||
throw new DSpaceSWORDException(
|
||||
"Unable to construct deposit urls, due to missing/invalid config in " +
|
||||
"sword.deposit.url and/or dspace.server.url");
|
||||
}
|
||||
|
||||
try {
|
||||
URL url = new URL(dspaceUrl);
|
||||
depositUrl = new URL(url.getProtocol(), url.getHost(),
|
||||
url.getPort(), "/sword/deposit").toString();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new DSpaceSWORDException(
|
||||
"Unable to construct deposit urls, due to invalid dspace.server.url " +
|
||||
e.getMessage(), e);
|
||||
}
|
||||
|
||||
depositUrl = buildSWORDUrl("deposit");
|
||||
}
|
||||
return depositUrl;
|
||||
}
|
||||
@@ -454,24 +434,12 @@ public class SWORDUrlManager {
|
||||
String mlUrl = configurationService.getProperty(
|
||||
"sword-server", "media-link.url");
|
||||
if (StringUtils.isBlank(mlUrl)) {
|
||||
String dspaceUrl = configurationService.getProperty(
|
||||
"dspace.server.url");
|
||||
if (dspaceUrl == null || "".equals(dspaceUrl)) {
|
||||
throw new DSpaceSWORDException(
|
||||
"Unable to construct media-link urls, due to missing/invalid config in " +
|
||||
"media-link.url and/or dspace.server.url");
|
||||
}
|
||||
|
||||
try {
|
||||
URL url = new URL(dspaceUrl);
|
||||
mlUrl = new URL(url.getProtocol(), url.getHost(), url.getPort(),
|
||||
"/sword/media-link").toString();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new DSpaceSWORDException(
|
||||
"Unable to construct media-link urls, due to invalid dspace.server.url " +
|
||||
e.getMessage(), e);
|
||||
}
|
||||
|
||||
mlUrl = buildSWORDUrl("media-link");
|
||||
}
|
||||
return mlUrl;
|
||||
}
|
||||
@@ -530,4 +498,14 @@ public class SWORDUrlManager {
|
||||
throw new DSpaceSWORDException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return configured server path for SWORD url
|
||||
*
|
||||
* @param path the target SWORD endpoint
|
||||
* @return a sword URL
|
||||
*/
|
||||
private String buildSWORDUrl(String path) {
|
||||
return dspaceUrl + "/" + swordPath + "/" + path;
|
||||
}
|
||||
}
|
||||
|
@@ -7,8 +7,6 @@
|
||||
*/
|
||||
package org.dspace.sword2;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
@@ -48,6 +46,12 @@ public class SwordUrlManager {
|
||||
protected ConfigurationService configurationService =
|
||||
DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
|
||||
private String swordPath = configurationService.getProperty(
|
||||
"swordv2-server.path", "swordv2");
|
||||
|
||||
private String dspaceUrl = configurationService.getProperty(
|
||||
"dspace.server.url");
|
||||
|
||||
/**
|
||||
* the SWORD configuration
|
||||
*/
|
||||
@@ -98,23 +102,12 @@ public class SwordUrlManager {
|
||||
throws DSpaceSwordException {
|
||||
String sUrl = configurationService.getProperty("swordv2-server.url");
|
||||
if (sUrl == null || "".equals(sUrl)) {
|
||||
String dspaceUrl = configurationService
|
||||
.getProperty("dspace.server.url");
|
||||
if (dspaceUrl == null || "".equals(dspaceUrl)) {
|
||||
throw new DSpaceSwordException(
|
||||
"Unable to construct service document urls, due to missing/invalid " +
|
||||
"config in sword2.url and/or dspace.server.url");
|
||||
}
|
||||
|
||||
try {
|
||||
URL url = new URL(dspaceUrl);
|
||||
sUrl = new URL(url.getProtocol(), url.getHost(), url.getPort(),
|
||||
"/swordv2").toString();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new DSpaceSwordException(
|
||||
"Unable to construct service document urls, due to invalid dspace.server.url " +
|
||||
e.getMessage(), e);
|
||||
}
|
||||
sUrl = buildSWORDUrl("swordv2");
|
||||
}
|
||||
return sUrl;
|
||||
}
|
||||
@@ -283,7 +276,8 @@ public class SwordUrlManager {
|
||||
return dso;
|
||||
} else {
|
||||
throw new SwordError(DSpaceUriRegistry.BAD_URL,
|
||||
"Service Document request does not refer to a DSpace Collection or Community");
|
||||
"Service Document request does not refer to a DSpace Collection " +
|
||||
"or Community");
|
||||
}
|
||||
} else {
|
||||
throw new SwordError(DSpaceUriRegistry.BAD_URL,
|
||||
@@ -306,23 +300,12 @@ public class SwordUrlManager {
|
||||
String sdUrl = configurationService
|
||||
.getProperty("swordv2-server.servicedocument.url");
|
||||
if (sdUrl == null || "".equals(sdUrl)) {
|
||||
String dspaceUrl = configurationService
|
||||
.getProperty("dspace.server.url");
|
||||
if (dspaceUrl == null || "".equals(dspaceUrl)) {
|
||||
throw new DSpaceSwordException(
|
||||
"Unable to construct service document urls, due to missing/invalid " +
|
||||
"config in swordv2-server.cfg servicedocument.url and/or dspace.server.url");
|
||||
}
|
||||
|
||||
try {
|
||||
URL url = new URL(dspaceUrl);
|
||||
sdUrl = new URL(url.getProtocol(), url.getHost(), url.getPort(),
|
||||
"/swordv2/servicedocument").toString();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new DSpaceSwordException(
|
||||
"Unable to construct service document urls, due to invalid dspace.server.url " +
|
||||
e.getMessage(), e);
|
||||
}
|
||||
sdUrl = buildSWORDUrl("servicedocument");
|
||||
}
|
||||
return sdUrl;
|
||||
}
|
||||
@@ -348,24 +331,12 @@ public class SwordUrlManager {
|
||||
String depositUrl = configurationService
|
||||
.getProperty("swordv2-server.collection.url");
|
||||
if (depositUrl == null || "".equals(depositUrl)) {
|
||||
String dspaceUrl = configurationService
|
||||
.getProperty("dspace.server.url");
|
||||
if (dspaceUrl == null || "".equals(dspaceUrl)) {
|
||||
throw new DSpaceSwordException(
|
||||
"Unable to construct deposit urls, due to missing/invalid config in " +
|
||||
"swordv2-server.cfg deposit.url and/or dspace.server.url");
|
||||
}
|
||||
|
||||
try {
|
||||
URL url = new URL(dspaceUrl);
|
||||
depositUrl = new URL(url.getProtocol(), url.getHost(),
|
||||
url.getPort(), "/swordv2/collection").toString();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new DSpaceSwordException(
|
||||
"Unable to construct deposit urls, due to invalid dspace.server.url " +
|
||||
e.getMessage(), e);
|
||||
}
|
||||
|
||||
depositUrl = buildSWORDUrl("collection");
|
||||
}
|
||||
return depositUrl;
|
||||
}
|
||||
@@ -515,4 +486,14 @@ public class SwordUrlManager {
|
||||
return new IRI(this.getSwordBaseUrl() + "/edit-media/" + item.getID() +
|
||||
".atom");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return configured server path for SWORD url
|
||||
*
|
||||
* @param path the target SWORD endpoint
|
||||
* @return a sword URL
|
||||
*/
|
||||
private String buildSWORDUrl(String path) {
|
||||
return dspaceUrl + "/" + swordPath + "/" + path;
|
||||
}
|
||||
}
|
||||
|
@@ -1563,6 +1563,7 @@ include = ${module_dir}/citation-page.cfg
|
||||
include = ${module_dir}/clamav.cfg
|
||||
include = ${module_dir}/curate.cfg
|
||||
include = ${module_dir}/discovery.cfg
|
||||
include = ${module_dir}/doi-curation.cfg
|
||||
include = ${module_dir}/google-analytics.cfg
|
||||
include = ${module_dir}/healthcheck.cfg
|
||||
include = ${module_dir}/irus-statistics.cfg
|
||||
|
@@ -14,6 +14,7 @@ plugin.named.org.dspace.curate.CurationTask = org.dspace.ctask.general.RequiredM
|
||||
#plugin.named.org.dspace.curate.CurationTask = org.dspace.ctask.general.ClamScan = vscan
|
||||
#plugin.named.org.dspace.curate.CurationTask = org.dspace.ctask.general.MicrosoftTranslator = translate
|
||||
plugin.named.org.dspace.curate.CurationTask = org.dspace.ctask.general.MetadataValueLinkChecker = checklinks
|
||||
plugin.named.org.dspace.curate.CurationTask = org.dspace.ctask.general.RegisterDOI = registerdoi
|
||||
# add new tasks here (or in additional config files)
|
||||
|
||||
## task queue implementation
|
||||
|
12
dspace/config/modules/doi-curation.cfg
Normal file
12
dspace/config/modules/doi-curation.cfg
Normal file
@@ -0,0 +1,12 @@
|
||||
### DOI registration curation task configuration module
|
||||
|
||||
##
|
||||
# Should any logical filters be skipped when registering DOIs? (ie. *always* register, never filter out the item)
|
||||
# Default: true
|
||||
#doi-curation.skip-filter = true
|
||||
|
||||
##
|
||||
# Should we allow the curation task to be distributed over communities / collections of items or the whole repository?
|
||||
# This *could* be dangerous if run accidentally over more items than intended.
|
||||
# Default: false
|
||||
#doi-curation.distributed = false
|
@@ -68,6 +68,21 @@
|
||||
</bean>
|
||||
-->
|
||||
|
||||
<!-- An optional logical item filter can be included in provider configuration based
|
||||
on the filters defined in item-filters.xml, eg. -->
|
||||
<!--
|
||||
<bean id="org.dspace.identifier.DOIIdentifierProvider"
|
||||
class="org.dspace.identifier.DOIIdentifierProvider"
|
||||
scope="singleton">
|
||||
<property name="configurationService"
|
||||
ref="org.dspace.services.ConfigurationService" />
|
||||
<property name="DOIConnector"
|
||||
ref="org.dspace.identifier.doi.DOIConnector" />
|
||||
<property name="filterService" ref="openaire_filter" />
|
||||
</bean>
|
||||
-->
|
||||
|
||||
|
||||
<!-- The DOIConnector will handle the API calls to your DOI registration
|
||||
agency for the DOIIdentifierProvider. If your registration agency
|
||||
tells you to use the DataCite API directly, you can use the
|
||||
|
339
dspace/config/spring/api/item-filters.xml
Normal file
339
dspace/config/spring/api/item-filters.xml
Normal file
@@ -0,0 +1,339 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
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/
|
||||
|
||||
-->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
|
||||
>
|
||||
<!-- default-autowire-candidates="*Service,*DAO,javax.sql.DataSource"> -->
|
||||
|
||||
<context:annotation-config /> <!-- allows us to use spring annotations in beans -->
|
||||
|
||||
|
||||
<!-- DEFINE CONDITIONS
|
||||
Define condition beans below for use as sub-statements in operator and filter beans
|
||||
-->
|
||||
|
||||
<!--
|
||||
The MetadataValueMatchCondition takes a regular expression, not an exact value.
|
||||
For an exact value match (rather than 'contains'), make sure to anchor the string
|
||||
like "^Exact Match$".
|
||||
Special characters used in Java regular expressions will need escaping.
|
||||
The below condition returns true if dc.title contains "demo" (case insensitive)
|
||||
-->
|
||||
<bean id="title-contains-demo_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.title" />
|
||||
<entry key="pattern" value="(?i)demo" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="item-is-public_condition"
|
||||
class="org.dspace.content.logic.condition.ReadableByGroupCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="group" value="Anonymous" />
|
||||
<entry key="action" value="READ" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- dc.title starts with Pattern -->
|
||||
<bean id="title-starts-with-pattern_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.title" />
|
||||
<entry key="pattern" value="^Pattern" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- dc.type is exactly Journal Article -->
|
||||
<bean id="type-equals-journal-article_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.type" />
|
||||
<entry key="pattern" value="^Journal Article$" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- dc.type is exactly Dataset -->
|
||||
<bean id="type-equals-dataset_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.type" />
|
||||
<entry key="pattern" value="^Dataset$" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
A filter that checks if any value of dc.identifier.uri contains "10.12345/".
|
||||
-->
|
||||
<bean id="dc-identifier-uri-contains-doi_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.identifier.uri" />
|
||||
<entry key="pattern" value="10.12345/" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- dc.type ends with any of the listed values, as per XOAI "driverDocumentTypeCondition" -->
|
||||
<bean id="driver-document-type_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValuesMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.type" />
|
||||
<entry key="patterns">
|
||||
<list>
|
||||
<value>article$</value>
|
||||
<value>bachelorThesis$</value>
|
||||
<value>masterThesis$</value>
|
||||
<value>doctoralThesis$</value>
|
||||
<value>book$</value>
|
||||
<value>bookPart$</value>
|
||||
<value>review$</value>
|
||||
<value>conferenceObject$</value>
|
||||
<value>lecture$</value>
|
||||
<value>workingPaper$</value>
|
||||
<value>preprint$</value>
|
||||
<value>report$</value>
|
||||
<value>annotation$</value>
|
||||
<value>contributionToPeriodical$</value>
|
||||
<value>patent$</value>
|
||||
<value>dataset$</value>
|
||||
<value>other$</value>
|
||||
</list>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- is in collection 123456789/20 (note, list parameter map means multiple collections can be passed) -->
|
||||
<bean id="in-outfit-collection_condition"
|
||||
class="org.dspace.content.logic.condition.InCollectionCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="collections">
|
||||
<list>
|
||||
<value>123456789/20</value>
|
||||
</list>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- has exactly one bitstream in ORIGINAL bundle -->
|
||||
<bean id="has-one-bitstream_condition"
|
||||
class="org.dspace.content.logic.condition.BitstreamCountCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="bundle" value="ORIGINAL"/>
|
||||
<entry key="min" value="1"/>
|
||||
<entry key="max" value="1"/>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- has at least one bitstream in ORIGINAL bundle -->
|
||||
<bean id="has-at-least-one-bitstream_condition"
|
||||
class="org.dspace.content.logic.condition.BitstreamCountCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="bundle" value="ORIGINAL"/>
|
||||
<entry key="min" value="1"/>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- DEFINE OPERATORS
|
||||
Operators can be defined too, if a particular AND or OR statement needs to be re-used a lot, though
|
||||
it may be easier in most cases to turn that into a filter and reference the filter in other sub-statements
|
||||
-->
|
||||
<bean class="org.dspace.content.logic.operator.Or" id="a-common-or_statement">
|
||||
<property name="statements">
|
||||
<list>
|
||||
<ref bean="type-equals-journal-article_condition"/>
|
||||
<ref bean="type-equals-dataset_condition"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<!-- DEFINE FILTERS -->
|
||||
<!-- Note that this filter is almost the same as the above "or" bean but the advantage is we
|
||||
can reference the type_filter directly for item logic *and* as a sub-statement of other filters
|
||||
whereas the operator class can only be a sub-statement
|
||||
-->
|
||||
|
||||
<!-- Example DOI Filter. An item has to pass the filter (filter returns true) to get a DOI.
|
||||
If the filter returns false on an item, minting of a new DOI for that item is prevented. -->
|
||||
<bean id="doi-filter" class="org.dspace.content.logic.DefaultFilter">
|
||||
<property name="statement">
|
||||
<bean class="org.dspace.content.logic.operator.And">
|
||||
<property name="statements">
|
||||
<list>
|
||||
<!-- Don't create new DOIs for items that already have one -->
|
||||
<bean class="org.dspace.content.logic.operator.Not">
|
||||
<property name="statements">
|
||||
<ref bean="dc-identifier-uri-contains-doi_condition"/>
|
||||
</property>
|
||||
</bean>
|
||||
<!-- Create DOIs for items only that do have at least one bitstream. -->
|
||||
<ref bean="has-at-least-one-bitstream_condition"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="type_filter" class="org.dspace.content.logic.DefaultFilter">
|
||||
<property name="statement">
|
||||
<!-- the below is the same as referencing the above, eg:
|
||||
<ref bean="a-common-r_statement"/> -->
|
||||
<bean class="org.dspace.content.logic.operator.Or">
|
||||
<property name="statements">
|
||||
<list>
|
||||
<ref bean="type-equals-journal-article_condition"/>
|
||||
<ref bean="type-equals-dataset_condition"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- A very simple demonstration filter, using the metadata match condition -->
|
||||
<bean id="simple-demo_filter" class="org.dspace.content.logic.DefaultFilter">
|
||||
<property name="statement">
|
||||
<ref bean="title-contains-demo_condition"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- A very simple filter for items with at least one bitstream -->
|
||||
<bean id="has-bitstream_filter" class="org.dspace.content.logic.DefaultFilter">
|
||||
<property name="statement">
|
||||
<ref bean="has-at-least-one-bitstream_condition"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
a more complex example:
|
||||
title contains 'demo' AND (title starts with 'Pattern' OR item is in one of the listed collections)
|
||||
-->
|
||||
<bean id="demo_filter" class="org.dspace.content.logic.DefaultFilter">
|
||||
<property name="statement">
|
||||
<bean class="org.dspace.content.logic.operator.And">
|
||||
<!-- title contains 'demo' AND (the result of the OR substatement is true) -->
|
||||
<property name="statements">
|
||||
<list>
|
||||
<ref bean="title-contains-demo_condition"/>
|
||||
<bean class="org.dspace.content.logic.operator.Or">
|
||||
<!-- title starts with Lily OR the item in one of the listed collections -->
|
||||
<property name="statements">
|
||||
<list>
|
||||
<ref bean="title-starts-with-pattern_condition"/>
|
||||
<bean class="org.dspace.content.logic.condition.InCollectionCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="collections">
|
||||
<list>
|
||||
<value>123456789/3</value>
|
||||
<value>123456789/4</value>
|
||||
</list>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- An example of an OpenAIRE compliance filter based on the same rules in xoai.xml
|
||||
some sub-statements are defined within this bean, and some are referenced from earlier definitions
|
||||
-->
|
||||
<bean id="openaire_filter" class="org.dspace.content.logic.DefaultFilter">
|
||||
<property name="statement">
|
||||
<bean class="org.dspace.content.logic.operator.And">
|
||||
<property name="statements">
|
||||
<list>
|
||||
<!-- Has a non-empty title -->
|
||||
<bean id="has-title_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.title" />
|
||||
<entry key="pattern" value=".*" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
<!-- AND has a non-empty author -->
|
||||
<bean id="has-author_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.contributor.author" />
|
||||
<entry key="pattern" value=".*" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
<!-- AND has a valid DRIVER document type (defined earlier) -->
|
||||
<ref bean="driver-document-type_condition" />
|
||||
<!-- AND (the item is publicly accessible OR withdrawn) -->
|
||||
<bean class="org.dspace.content.logic.operator.Or">
|
||||
<property name="statements">
|
||||
<list>
|
||||
<!-- item is public, defined earlier -->
|
||||
<ref bean="item-is-public_condition" />
|
||||
<!-- OR item is withdrawn, for tombstoning -->
|
||||
<bean class="org.dspace.content.logic.condition.IsWithdrawnCondition">
|
||||
<property name="parameters"><map></map></property>
|
||||
</bean>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
<!-- AND the dc.relation is a valid OpenAIRE identifier
|
||||
(starts with "info:eu-repo/grantAgreement/") -->
|
||||
<bean id="has-openaire-relation_condition"
|
||||
class="org.dspace.content.logic.condition.MetadataValueMatchCondition">
|
||||
<property name="parameters">
|
||||
<map>
|
||||
<entry key="field" value="dc.relation" />
|
||||
<entry key="pattern" value="^info:eu-repo/grantAgreement/" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
</beans>
|
Reference in New Issue
Block a user