[TLC-249] Refactor to support better filter usage, PENDING and MINTED status

This commit is contained in:
Kim Shepherd
2022-08-15 16:07:26 +12:00
parent 8fcda7f03a
commit 20aeedfdb3
27 changed files with 995 additions and 227 deletions

View File

@@ -9,10 +9,17 @@ package org.dspace.content;
import java.io.IOException; import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.logic.Filter;
import org.dspace.content.logic.FilterUtils;
import org.dspace.content.logic.TrueFilter;
import org.dspace.content.service.CollectionService; import org.dspace.content.service.CollectionService;
import org.dspace.content.service.InstallItemService; import org.dspace.content.service.InstallItemService;
import org.dspace.content.service.ItemService; import org.dspace.content.service.ItemService;
@@ -20,8 +27,12 @@ import org.dspace.core.Constants;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.embargo.service.EmbargoService; import org.dspace.embargo.service.EmbargoService;
import org.dspace.event.Event; import org.dspace.event.Event;
import org.dspace.identifier.DOI;
import org.dspace.identifier.Handle;
import org.dspace.identifier.Identifier;
import org.dspace.identifier.IdentifierException; import org.dspace.identifier.IdentifierException;
import org.dspace.identifier.service.IdentifierService; import org.dspace.identifier.service.IdentifierService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
/** /**
@@ -42,9 +53,11 @@ public class InstallItemServiceImpl implements InstallItemService {
protected IdentifierService identifierService; protected IdentifierService identifierService;
@Autowired(required = true) @Autowired(required = true)
protected ItemService itemService; protected ItemService itemService;
@Autowired(required = false)
Logger log = LogManager.getLogger(InstallItemServiceImpl.class);
protected InstallItemServiceImpl() { protected InstallItemServiceImpl() {
} }
@Override @Override
@@ -59,11 +72,17 @@ public class InstallItemServiceImpl implements InstallItemService {
AuthorizeException { AuthorizeException {
Item item = is.getItem(); Item item = is.getItem();
Collection collection = is.getCollection(); Collection collection = is.getCollection();
// Get map of filters to use for identifier types
Map<Class<? extends Identifier>, Filter> filters = FilterUtils.getIdentifierFilters("install");
try { try {
if (suppliedHandle == null) { if (suppliedHandle == null) {
identifierService.register(c, item); // Register with the filters we've set up
identifierService.register(c, item, filters);
} else { } else {
// This will register the handle but a pending DOI won't be compatible and so won't be registered
identifierService.register(c, item, suppliedHandle); identifierService.register(c, item, suppliedHandle);
// Continue to register just a DOI
identifierService.register(c, item, DOI.class, filters.get(DOI.class));
} }
} catch (IdentifierException e) { } catch (IdentifierException e) {
throw new RuntimeException("Can't create an Identifier!", e); throw new RuntimeException("Can't create an Identifier!", e);

View File

@@ -24,6 +24,8 @@ import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.ResourcePolicy; import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.AuthorizeService; import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.dao.WorkspaceItemDAO; import org.dspace.content.dao.WorkspaceItemDAO;
import org.dspace.content.logic.Filter;
import org.dspace.content.logic.FilterUtils;
import org.dspace.content.service.CollectionService; import org.dspace.content.service.CollectionService;
import org.dspace.content.service.ItemService; import org.dspace.content.service.ItemService;
import org.dspace.content.service.WorkspaceItemService; import org.dspace.content.service.WorkspaceItemService;
@@ -32,8 +34,12 @@ import org.dspace.core.Context;
import org.dspace.core.LogHelper; import org.dspace.core.LogHelper;
import org.dspace.eperson.EPerson; import org.dspace.eperson.EPerson;
import org.dspace.event.Event; import org.dspace.event.Event;
import org.dspace.identifier.DOI;
import org.dspace.identifier.DOIIdentifierProvider;
import org.dspace.identifier.Identifier;
import org.dspace.identifier.IdentifierException; import org.dspace.identifier.IdentifierException;
import org.dspace.identifier.factory.IdentifierServiceFactory; import org.dspace.identifier.factory.IdentifierServiceFactory;
import org.dspace.identifier.service.DOIService;
import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.workflow.WorkflowItem; import org.dspace.workflow.WorkflowItem;
import org.dspace.workflow.WorkflowService; import org.dspace.workflow.WorkflowService;
@@ -61,6 +67,8 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService {
protected ItemService itemService; protected ItemService itemService;
@Autowired(required = true) @Autowired(required = true)
protected WorkflowService workflowService; protected WorkflowService workflowService;
@Autowired(required = true)
protected DOIService doiService;
protected WorkspaceItemServiceImpl() { protected WorkspaceItemServiceImpl() {
@@ -169,7 +177,15 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService {
if (DSpaceServicesFactory.getInstance().getConfigurationService() if (DSpaceServicesFactory.getInstance().getConfigurationService()
.getBooleanProperty("identifiers.submission.register", false)) { .getBooleanProperty("identifiers.submission.register", false)) {
try { try {
IdentifierServiceFactory.getInstance().getIdentifierService().register(context, item); // Get map of filters to use for identifier types
Map<Class<? extends Identifier>, Filter> filters = FilterUtils.getIdentifierFilters("workspace");
IdentifierServiceFactory.getInstance().getIdentifierService().register(context, item, filters);
// Look for a DOI and move it to PENDING
DOI doi = doiService.findDOIByDSpaceObject(context, item);
if (doi != null) {
doi.setStatus(DOIIdentifierProvider.PENDING);
doiService.update(context, doi);
}
} catch (IdentifierException e) { } catch (IdentifierException e) {
log.error("Could not register identifier(s) for item {}: {}", item.getID(), e.getMessage()); log.error("Could not register identifier(s) for item {}: {}", item.getID(), e.getMessage());
} }

View File

@@ -22,6 +22,7 @@ import org.dspace.core.Context;
*/ */
public class DefaultFilter implements Filter { public class DefaultFilter implements Filter {
private LogicalStatement statement; private LogicalStatement statement;
private String name;
private final static Logger log = LogManager.getLogger(); private final static Logger log = LogManager.getLogger();
/** /**
@@ -44,4 +45,15 @@ public class DefaultFilter implements Filter {
public boolean getResult(Context context, Item item) throws LogicalStatementException { public boolean getResult(Context context, Item item) throws LogicalStatementException {
return this.statement.getResult(context, item); return this.statement.getResult(context, item);
} }
@Override
public void setBeanName(String name) {
log.debug("Initialize bean " + name);
this.name = name;
}
@Override
public String getName() {
return name;
}
} }

View File

@@ -9,6 +9,7 @@ package org.dspace.content.logic;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.springframework.beans.factory.BeanNameAware;
/** /**
* The interface for Filter currently doesn't add anything to LogicalStatement but inherits from it * The interface for Filter currently doesn't add anything to LogicalStatement but inherits from it
@@ -22,7 +23,7 @@ import org.dspace.core.Context;
* @author Kim Shepherd * @author Kim Shepherd
* @see org.dspace.content.logic.DefaultFilter * @see org.dspace.content.logic.DefaultFilter
*/ */
public interface Filter extends LogicalStatement { public interface Filter extends LogicalStatement, BeanNameAware {
/** /**
* Get the result of logical evaluation for an item * Get the result of logical evaluation for an item
* @param context DSpace context * @param context DSpace context
@@ -32,4 +33,6 @@ public interface Filter extends LogicalStatement {
*/ */
@Override @Override
boolean getResult(Context context, Item item) throws LogicalStatementException; boolean getResult(Context context, Item item) throws LogicalStatementException;
String getName();
} }

View File

@@ -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.content.logic;
import java.util.HashMap;
import java.util.Map;
import org.dspace.identifier.DOI;
import org.dspace.identifier.Handle;
import org.dspace.identifier.Identifier;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.springframework.beans.factory.annotation.Autowired;
/**
* General utility methods for logical item filtering
*
* @author Kim Shepherd
*/
public class FilterUtils {
@Autowired(required = true)
ConfigurationService configurationService;
/**
* Get a Filter by name
* @param property DSpace configuration property name (Apache Commons config)
* @return Filter or null
*/
public static Filter getFilterFromConfiguration(String property) {
String filterName = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty(property);
if (filterName != null) {
return DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(filterName, Filter.class);
}
return null;
}
/**
* Get a Filter by name
* @param property DSpace configuration property name (Apache Commons config)
* @return Filter or null
*/
public static Filter getFilterFromConfiguration(String property, Filter defaultFilter) {
Filter filter = getFilterFromConfiguration(property);
if (filter != null) {
return filter;
}
return defaultFilter;
}
/**
* Get a map of identifier types and filters to use when creating workspace or archived items
* @return
*/
public static Map<Class<? extends Identifier>, Filter> getIdentifierFilters(String status) {
if (status == null) {
status = "install";
}
Map<Class<? extends Identifier>, Filter> filters = new HashMap<>();
// Put DOI 'can we create DOI on install / workspace?' filter
Filter filter = FilterUtils.getFilterFromConfiguration("identifiers.submission.filter." + status);
// A null filter should be handled safely by the identifier provier (default, or "always true")
filters.put(DOI.class, filter);
// This won't have an affect until handle providers implement filtering, but is an example of
// how the filters can be used for other types
filters.put(Handle.class, new TrueFilter());
return filters;
}
}

View File

@@ -0,0 +1,41 @@
/**
* 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.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.content.Item;
import org.dspace.core.Context;
/**
* Extremely simple filter that always returns true!
* Useful to pass to methods that expect a filter, in order to effectively say "all items".
* This could be configured in Spring XML but it is more stable and reliable to have it hard-coded here
* so that any broken configuration doesn't silently break parts of DSpace that expect it to work.
*
* @author Kim Shepherd
*/
public class TrueFilter implements Filter {
private String name;
private final static Logger log = LogManager.getLogger();
public boolean getResult(Context context, Item item) throws LogicalStatementException {
return true;
}
@Override
public void setBeanName(String name) {
log.debug("Initialize bean " + name);
this.name = name;
}
@Override
public String getName() {
return name;
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.logging.log4j.LogManager;
import org.apache.logging.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 IsArchivedCondition extends AbstractCondition {
private final static Logger log = LogManager.getLogger();
/**
* 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.isArchived());
return item.isArchived();
}
}

View File

@@ -13,6 +13,9 @@ import java.sql.SQLException;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.content.logic.Filter;
import org.dspace.content.logic.FilterUtils;
import org.dspace.content.logic.TrueFilter;
import org.dspace.curate.AbstractCurationTask; import org.dspace.curate.AbstractCurationTask;
import org.dspace.curate.Curator; import org.dspace.curate.Curator;
import org.dspace.identifier.DOIIdentifierProvider; import org.dspace.identifier.DOIIdentifierProvider;
@@ -46,8 +49,6 @@ public class RegisterDOI extends AbstractCurationTask {
@Override @Override
public void init(Curator curator, String taskId) throws IOException { public void init(Curator curator, String taskId) throws IOException {
super.init(curator, taskId); 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' // Get distribution behaviour from configuration, with a default value of 'false'
distributed = configurationService.getBooleanProperty(PLUGIN_PREFIX + ".distributed", false); distributed = configurationService.getBooleanProperty(PLUGIN_PREFIX + ".distributed", false);
log.debug("PLUGIN_PREFIX = " + PLUGIN_PREFIX + ", skipFilter = " + skipFilter + log.debug("PLUGIN_PREFIX = " + PLUGIN_PREFIX + ", skipFilter = " + skipFilter +
@@ -118,8 +119,9 @@ public class RegisterDOI extends AbstractCurationTask {
String doi = null; String doi = null;
// Attempt DOI registration and report successes and failures // Attempt DOI registration and report successes and failures
try { try {
log.debug("Registering DOI with skipFilter = " + skipFilter); Filter filter = FilterUtils.getFilterFromConfiguration("identifiers.submission.filter.curation",
doi = provider.register(Curator.curationContext(), item, skipFilter); new TrueFilter());
doi = provider.register(Curator.curationContext(), item, filter);
if (doi != null) { if (doi != null) {
String message = "New DOI minted in database for item " + item.getHandle() + ": " + doi 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"; + ". This DOI will be registered online with the DOI provider when the queue is next run";

View File

@@ -21,6 +21,7 @@ import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.logic.Filter; import org.dspace.content.logic.Filter;
import org.dspace.content.logic.LogicalStatementException; import org.dspace.content.logic.LogicalStatementException;
import org.dspace.content.logic.TrueFilter;
import org.dspace.content.service.ItemService; import org.dspace.content.service.ItemService;
import org.dspace.core.Constants; import org.dspace.core.Constants;
import org.dspace.core.Context; import org.dspace.core.Context;
@@ -44,6 +45,7 @@ import org.springframework.beans.factory.annotation.Autowired;
* <p>Any identifier a method of this class returns is a string in the following format: doi:10.123/456.</p> * <p>Any identifier a method of this class returns is a string in the following format: doi:10.123/456.</p>
* *
* @author Pascal-Nicolas Becker * @author Pascal-Nicolas Becker
* @author Kim Shepherd
*/ */
public class DOIIdentifierProvider extends FilteredIdentifierProvider { public class DOIIdentifierProvider extends FilteredIdentifierProvider {
private static final Logger log = LoggerFactory.getLogger(DOIIdentifierProvider.class); private static final Logger log = LoggerFactory.getLogger(DOIIdentifierProvider.class);
@@ -71,16 +73,29 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
public static final String MD_SCHEMA = "dc"; public static final String MD_SCHEMA = "dc";
public static final String DOI_ELEMENT = "identifier"; public static final String DOI_ELEMENT = "identifier";
public static final String DOI_QUALIFIER = "uri"; public static final String DOI_QUALIFIER = "uri";
// The DOI is queued for registered with the service provider
public static final Integer TO_BE_REGISTERED = 1; public static final Integer TO_BE_REGISTERED = 1;
// The DOI is queued for reservation with the service provider
public static final Integer TO_BE_RESERVED = 2; public static final Integer TO_BE_RESERVED = 2;
// The DOI has been registered online
public static final Integer IS_REGISTERED = 3; public static final Integer IS_REGISTERED = 3;
// The DOI has been reserved online
public static final Integer IS_RESERVED = 4; public static final Integer IS_RESERVED = 4;
// The DOI is reserved and requires an updated metadata record to be sent to the service provider
public static final Integer UPDATE_RESERVED = 5; public static final Integer UPDATE_RESERVED = 5;
// The DOI is registered and requires an updated metadata record to be sent to the service provider
public static final Integer UPDATE_REGISTERED = 6; public static final Integer UPDATE_REGISTERED = 6;
// The DOI metadata record should be updated before performing online registration
public static final Integer UPDATE_BEFORE_REGISTRATION = 7; public static final Integer UPDATE_BEFORE_REGISTRATION = 7;
// The DOI will be deleted locally and marked as deleted in the DOI service provider
public static final Integer TO_BE_DELETED = 8; public static final Integer TO_BE_DELETED = 8;
// The DOI has been deleted and is no longer associated with an item
public static final Integer DELETED = 9; public static final Integer DELETED = 9;
// The DOI is created in the database and is waiting for either successful filter check on item install or
// manual intervention by an administrator to proceed to reservation or registration
public static final Integer PENDING = 10;
// The DOI is created in the database, but no more context is known
public static final Integer MINTED = 11;
@Autowired(required = true) @Autowired(required = true)
protected DOIService doiService; protected DOIService doiService;
@@ -89,8 +104,6 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
@Autowired(required = true) @Autowired(required = true)
protected ItemService itemService; protected ItemService itemService;
protected Filter filterService;
/** /**
* Empty / default constructor for Spring * Empty / default constructor for Spring
*/ */
@@ -153,16 +166,6 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
this.connector = 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
*/
@Override
public void setFilterService(Filter filterService) {
this.filterService = filterService;
}
/** /**
* This identifier provider supports identifiers of type * This identifier provider supports identifiers of type
* {@link org.dspace.identifier.DOI}. * {@link org.dspace.identifier.DOI}.
@@ -206,7 +209,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
@Override @Override
public String register(Context context, DSpaceObject dso) public String register(Context context, DSpaceObject dso)
throws IdentifierException { throws IdentifierException {
return register(context, dso, false); return register(context, dso, this.filter);
} }
/** /**
@@ -219,29 +222,29 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
@Override @Override
public void register(Context context, DSpaceObject dso, String identifier) public void register(Context context, DSpaceObject dso, String identifier)
throws IdentifierException { throws IdentifierException {
register(context, dso, identifier, false); register(context, dso, identifier, this.filter);
} }
/** /**
* Register a new DOI for a given DSpaceObject * Register a new DOI for a given DSpaceObject
* @param context - DSpace context * @param context - DSpace context
* @param dso - DSpaceObject identified by the new DOI * @param dso - DSpaceObject identified by the new DOI
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration * @param filter - Logical item filter to determine whether this identifier should be registered
* @throws IdentifierException * @throws IdentifierException
*/ */
@Override @Override
public String register(Context context, DSpaceObject dso, boolean skipFilter) public String register(Context context, DSpaceObject dso, Filter filter)
throws IdentifierException { throws IdentifierException {
if (!(dso instanceof Item)) { if (!(dso instanceof Item)) {
// DOI are currently assigned only to Item // DOI are currently assigned only to Item
return null; return null;
} }
String doi = mint(context, dso, skipFilter); String doi = mint(context, dso, filter);
// register tries to reserve doi if it's not already. // register tries to reserve doi if it's not already.
// So we don't have to reserve it here. // So we don't have to reserve it here.
register(context, dso, doi, skipFilter); register(context, dso, doi, filter);
return doi; return doi;
} }
@@ -250,11 +253,11 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
* @param context - DSpace context * @param context - DSpace context
* @param dso - DSpaceObject identified by the new DOI * @param dso - DSpaceObject identified by the new DOI
* @param identifier - String containing the DOI to register * @param identifier - String containing the DOI to register
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration * @param filter - Logical item filter to determine whether this identifier should be registered
* @throws IdentifierException * @throws IdentifierException
*/ */
@Override @Override
public void register(Context context, DSpaceObject dso, String identifier, boolean skipFilter) public void register(Context context, DSpaceObject dso, String identifier, Filter filter)
throws IdentifierException { throws IdentifierException {
if (!(dso instanceof Item)) { if (!(dso instanceof Item)) {
// DOI are currently assigned only to Item // DOI are currently assigned only to Item
@@ -265,7 +268,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
// search DOI in our db // search DOI in our db
try { try {
doiRow = loadOrCreateDOI(context, dso, doi, skipFilter); doiRow = loadOrCreateDOI(context, dso, doi, filter);
} catch (SQLException ex) { } catch (SQLException ex) {
log.error("Error in databse connection: " + ex.getMessage()); log.error("Error in databse connection: " + ex.getMessage());
throw new RuntimeException("Error in database conncetion.", ex); throw new RuntimeException("Error in database conncetion.", ex);
@@ -277,7 +280,6 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED); + "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
} }
// Check status of DOI
if (IS_REGISTERED.equals(doiRow.getStatus())) { if (IS_REGISTERED.equals(doiRow.getStatus())) {
return; return;
} }
@@ -290,6 +292,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
log.warn("SQLException while changing status of DOI {} to be registered.", doi); log.warn("SQLException while changing status of DOI {} to be registered.", doi);
throw new RuntimeException(sqle); throw new RuntimeException(sqle);
} }
} }
/** /**
@@ -309,7 +312,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
@Override @Override
public void reserve(Context context, DSpaceObject dso, String identifier) public void reserve(Context context, DSpaceObject dso, String identifier)
throws IdentifierException, IllegalArgumentException { throws IdentifierException, IllegalArgumentException {
reserve(context, dso, identifier, false); reserve(context, dso, identifier, this.filter);
} }
/** /**
@@ -317,20 +320,18 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
* @param context - DSpace context * @param context - DSpace context
* @param dso - DSpaceObject identified by this DOI * @param dso - DSpaceObject identified by this DOI
* @param identifier - String containing the DOI to reserve * @param identifier - String containing the DOI to reserve
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing reservation * @param filter - Logical item filter to determine whether this identifier should be reserved
* @throws IdentifierException * @throws IdentifierException
* @throws IllegalArgumentException * @throws IllegalArgumentException
*/ */
@Override @Override
public void reserve(Context context, DSpaceObject dso, String identifier, boolean skipFilter) public void reserve(Context context, DSpaceObject dso, String identifier, Filter filter)
throws IdentifierException, IllegalArgumentException { throws IdentifierException, IllegalArgumentException {
String doi = doiService.formatIdentifier(identifier); String doi = doiService.formatIdentifier(identifier);
DOI doiRow = null; DOI doiRow = null;
try { try {
// if the doi is in our db already loadOrCreateDOI just returns. doiRow = loadOrCreateDOI(context, dso, doi, filter);
// if it is not loadOrCreateDOI safes the doi.
doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
} catch (SQLException sqle) { } catch (SQLException sqle) {
throw new RuntimeException(sqle); throw new RuntimeException(sqle);
} }
@@ -359,7 +360,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
*/ */
public void reserveOnline(Context context, DSpaceObject dso, String identifier) public void reserveOnline(Context context, DSpaceObject dso, String identifier)
throws IdentifierException, IllegalArgumentException, SQLException { throws IdentifierException, IllegalArgumentException, SQLException {
reserveOnline(context, dso, identifier, false); reserveOnline(context, dso, identifier, this.filter);
} }
/** /**
@@ -367,16 +368,16 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
* @param context - DSpace context * @param context - DSpace context
* @param dso - DSpaceObject identified by this DOI * @param dso - DSpaceObject identified by this DOI
* @param identifier - String containing the DOI to reserve * @param identifier - String containing the DOI to reserve
* @param skipFilter - skip the filters for {@link checkMintable(Context, DSpaceObject)} * @param filter - Logical item filter to determine whether this identifier should be reserved online
* @throws IdentifierException * @throws IdentifierException
* @throws IllegalArgumentException * @throws IllegalArgumentException
* @throws SQLException * @throws SQLException
*/ */
public void reserveOnline(Context context, DSpaceObject dso, String identifier, boolean skipFilter) public void reserveOnline(Context context, DSpaceObject dso, String identifier, Filter filter)
throws IdentifierException, IllegalArgumentException, SQLException { throws IdentifierException, IllegalArgumentException, SQLException {
String doi = doiService.formatIdentifier(identifier); String doi = doiService.formatIdentifier(identifier);
// get TableRow and ensure DOI belongs to dso regarding our db // get TableRow and ensure DOI belongs to dso regarding our db
DOI doiRow = loadOrCreateDOI(context, dso, doi, skipFilter); DOI doiRow = loadOrCreateDOI(context, dso, doi, filter);
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 " throw new DOIIdentifierException("You tried to reserve a DOI that "
@@ -402,7 +403,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
public void registerOnline(Context context, DSpaceObject dso, String identifier) public void registerOnline(Context context, DSpaceObject dso, String identifier)
throws IdentifierException, IllegalArgumentException, SQLException { throws IdentifierException, IllegalArgumentException, SQLException {
registerOnline(context, dso, identifier, false); registerOnline(context, dso, identifier, this.filter);
} }
@@ -411,18 +412,17 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
* @param context - DSpace context * @param context - DSpace context
* @param dso - DSpaceObject identified by this DOI * @param dso - DSpaceObject identified by this DOI
* @param identifier - String containing the DOI to register * @param identifier - String containing the DOI to register
* @param skipFilter - skip filters for {@link checkMintable(Context, DSpaceObject)} * @param filter - Logical item filter to determine whether this identifier should be registered online
* @throws IdentifierException * @throws IdentifierException
* @throws IllegalArgumentException * @throws IllegalArgumentException
* @throws SQLException * @throws SQLException
*/ */
public void registerOnline(Context context, DSpaceObject dso, String identifier, boolean skipFilter) public void registerOnline(Context context, DSpaceObject dso, String identifier, Filter filter)
throws IdentifierException, IllegalArgumentException, SQLException { throws IdentifierException, IllegalArgumentException, SQLException {
log.debug("registerOnline: skipFilter is " + skipFilter);
String doi = doiService.formatIdentifier(identifier); String doi = doiService.formatIdentifier(identifier);
// get TableRow and ensure DOI belongs to dso regarding our db // get TableRow and ensure DOI belongs to dso regarding our db
DOI doiRow = loadOrCreateDOI(context, dso, doi, skipFilter); DOI doiRow = loadOrCreateDOI(context, dso, doi, filter);
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 " throw new DOIIdentifierException("You tried to register a DOI that "
@@ -435,7 +435,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
} catch (DOIIdentifierException die) { } catch (DOIIdentifierException die) {
// do we have to reserve DOI before we can register it? // do we have to reserve DOI before we can register it?
if (die.getCode() == DOIIdentifierException.RESERVE_FIRST) { if (die.getCode() == DOIIdentifierException.RESERVE_FIRST) {
this.reserveOnline(context, dso, identifier, skipFilter); this.reserveOnline(context, dso, identifier, filter);
connector.registerDOI(context, dso, doi); connector.registerDOI(context, dso, doi);
} else { } else {
throw die; throw die;
@@ -471,17 +471,22 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
throws IdentifierException, IllegalArgumentException, SQLException { throws IdentifierException, IllegalArgumentException, SQLException {
String doi = doiService.formatIdentifier(identifier); String doi = doiService.formatIdentifier(identifier);
// Use the default filter unless we find the object
boolean skipFilter = false; Filter updateFilter = this.filter;
if (doiService.findDOIByDSpaceObject(context, dso) != null) { if (doiService.findDOIByDSpaceObject(context, dso) != null) {
// We can skip the filter here since we know the DOI already exists for the item // We can skip the filter here since we know the DOI already exists for the item
log.debug("updateMetadata: found DOIByDSpaceObject: " + log.debug("updateMetadata: found DOIByDSpaceObject: " +
doiService.findDOIByDSpaceObject(context, dso).getDoi()); doiService.findDOIByDSpaceObject(context, dso).getDoi());
skipFilter = true; updateFilter = new TrueFilter();
} }
DOI doiRow = loadOrCreateDOI(context, dso, doi, skipFilter); DOI doiRow = loadOrCreateDOI(context, dso, doi, updateFilter);
if (PENDING.equals(doiRow.getStatus())) {
log.info("Not updating metadata for PENDING doi: " + doi);
return;
}
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 " throw new DOIIdentifierException("You tried to register a DOI that "
@@ -571,19 +576,19 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
@Override @Override
public String mint(Context context, DSpaceObject dso) public String mint(Context context, DSpaceObject dso)
throws IdentifierException { throws IdentifierException {
return mint(context, dso, false); return mint(context, dso, this.filter);
} }
/** /**
* Mint a new DOI in DSpace - this is usually the first step of registration * Mint a new DOI in DSpace - this is usually the first step of registration
* @param context - DSpace context * @param context - DSpace context
* @param dso - DSpaceObject identified by the new identifier * @param dso - DSpaceObject identified by the new identifier
* @param skipFilter - boolean indicating whether to skip any filtering of items before minting. * @param filter - Logical item filter to determine whether this identifier should be registered
* @return a String containing the new identifier * @return a String containing the new identifier
* @throws IdentifierException * @throws IdentifierException
*/ */
@Override @Override
public String mint(Context context, DSpaceObject dso, boolean skipFilter) throws IdentifierException { public String mint(Context context, DSpaceObject dso, Filter filter) throws IdentifierException {
String doi = null; String doi = null;
try { try {
@@ -597,7 +602,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
} }
if (null == doi) { if (null == doi) {
try { try {
DOI doiRow = loadOrCreateDOI(context, dso, null, skipFilter); DOI doiRow = loadOrCreateDOI(context, dso, null, filter);
doi = DOI.SCHEME + doiRow.getDoi(); doi = DOI.SCHEME + doiRow.getDoi();
} catch (SQLException e) { } catch (SQLException e) {
@@ -895,7 +900,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
*/ */
protected DOI loadOrCreateDOI(Context context, DSpaceObject dso, String doiIdentifier) protected DOI loadOrCreateDOI(Context context, DSpaceObject dso, String doiIdentifier)
throws SQLException, DOIIdentifierException, IdentifierNotApplicableException { throws SQLException, DOIIdentifierException, IdentifierNotApplicableException {
return loadOrCreateDOI(context, dso, doiIdentifier, false); return loadOrCreateDOI(context, dso, doiIdentifier, this.filter);
} }
/** /**
@@ -910,13 +915,13 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
* @param context - DSpace context * @param context - DSpace context
* @param dso - DSpaceObject to identify * @param dso - DSpaceObject to identify
* @param doiIdentifier - DOI to load or create (null to mint a new one) * @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 * @param filter - Logical item filter to determine whether this identifier should be registered
* @return * @return
* @throws SQLException * @throws SQLException
* @throws DOIIdentifierException * @throws DOIIdentifierException
* @throws org.dspace.identifier.IdentifierNotApplicableException passed through. * @throws org.dspace.identifier.IdentifierNotApplicableException passed through.
*/ */
protected DOI loadOrCreateDOI(Context context, DSpaceObject dso, String doiIdentifier, boolean skipFilter) protected DOI loadOrCreateDOI(Context context, DSpaceObject dso, String doiIdentifier, Filter filter)
throws SQLException, DOIIdentifierException, IdentifierNotApplicableException { throws SQLException, DOIIdentifierException, IdentifierNotApplicableException {
DOI doi = null; DOI doi = null;
@@ -954,6 +959,8 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
// doi is assigned to a DSO; is it assigned to our specific dso? // doi is assigned to a DSO; is it assigned to our specific dso?
// check if DOI already belongs to dso // check if DOI already belongs to dso
if (dso.getID().equals(doi.getDSpaceObject().getID())) { if (dso.getID().equals(doi.getDSpaceObject().getID())) {
// Before we return this, check the filter
checkMintable(context, filter, dso);
return doi; return doi;
} else { } else {
throw new DOIIdentifierException("Trying to create a DOI " + throw new DOIIdentifierException("Trying to create a DOI " +
@@ -963,15 +970,8 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
} }
} }
// we did not find the doi in the database or shall reassign it. Before doing so, we should check if a // Check if this item is eligible for minting. An IdentifierNotApplicableException will be thrown if not.
// filter is in place to prevent the creation of new DOIs for certain items. checkMintable(context, filter, dso);
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 // check prefix
if (!doiIdentifier.startsWith(this.getPrefix() + "/")) { if (!doiIdentifier.startsWith(this.getPrefix() + "/")) {
@@ -984,15 +984,8 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
doi = doiService.create(context); doi = doiService.create(context);
} }
} else { } else {
// We need to generate a new DOI. Before doing so, we should check if a // Check if this item is eligible for minting. An IdentifierNotApplicableException will be thrown if not.
// filter is in place to prevent the creation of new DOIs for certain items. checkMintable(context, filter, dso);
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); doi = doiService.create(context);
doiIdentifier = this.getPrefix() + "/" + this.getNamespaceSeparator() + doiIdentifier = this.getPrefix() + "/" + this.getNamespaceSeparator() +
@@ -1002,7 +995,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
// prepare new doiRow // prepare new doiRow
doi.setDoi(doiIdentifier); doi.setDoi(doiIdentifier);
doi.setDSpaceObject(dso); doi.setDSpaceObject(dso);
doi.setStatus(null); doi.setStatus(MINTED);
try { try {
doiService.update(context, doi); doiService.update(context, doi);
} catch (SQLException e) { } catch (SQLException e) {
@@ -1102,20 +1095,26 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
/** /**
* Checks to see if an item can have a DOI minted, using the configured logical filter * Checks to see if an item can have a DOI minted, using the configured logical filter
* @param context * @param context
* @param filter Logical item filter to apply
* @param dso The item to be evaluated * @param dso The item to be evaluated
* @throws DOIIdentifierNotApplicableException * @throws DOIIdentifierNotApplicableException
*/ */
@Override @Override
public void checkMintable(Context context, DSpaceObject dso) throws DOIIdentifierNotApplicableException { public void checkMintable(Context context, Filter filter, DSpaceObject dso)
throws DOIIdentifierNotApplicableException {
if (filter == null) {
// If a null filter was passed and we have a good default filter to apply, apply it.
// Otherwise set to TrueFilter which means "no filtering"
filter = Objects.requireNonNullElseGet(this.filter, TrueFilter::new);
}
// If the check fails, an exception will be thrown to be caught by the calling method // If the check fails, an exception will be thrown to be caught by the calling method
if (this.filterService != null && contentServiceFactory if (contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso).equals("ITEM")) {
.getDSpaceObjectService(dso).getTypeText(dso).equals("ITEM")) {
try { try {
boolean result = filterService.getResult(context, (Item) dso); boolean result = filter.getResult(context, (Item) dso);
log.debug("Result of filter for " + dso.getHandle() + " is " + result); log.debug("Result of filter for " + dso.getHandle() + " is " + result);
if (!result) { if (!result) {
throw new DOIIdentifierNotApplicableException("Item " + dso.getHandle() + throw new DOIIdentifierNotApplicableException("Item " + dso.getHandle() +
" was evaluated as 'false' by the item filter, not minting"); " was evaluated as 'false' by the item filter, not minting");
} }
} catch (LogicalStatementException e) { } catch (LogicalStatementException e) {
log.error("Error evaluating item with logical filter: " + e.getLocalizedMessage()); log.error("Error evaluating item with logical filter: " + e.getLocalizedMessage());
@@ -1125,4 +1124,16 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
log.debug("DOI Identifier Provider: filterService is null (ie. don't prevent DOI minting)"); log.debug("DOI Identifier Provider: filterService is null (ie. don't prevent DOI minting)");
} }
} }
/**
* 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 {
checkMintable(context, this.filter, dso);
}
} }

View File

@@ -12,8 +12,8 @@ import java.sql.SQLException;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.logic.Filter; import org.dspace.content.logic.Filter;
import org.dspace.content.logic.TrueFilter;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
/** /**
* This abstract class adds extra method signatures so that implementing IdentifierProviders can * This abstract class adds extra method signatures so that implementing IdentifierProviders can
@@ -24,26 +24,28 @@ import org.springframework.beans.factory.annotation.Autowired;
*/ */
public abstract class FilteredIdentifierProvider extends IdentifierProvider { public abstract class FilteredIdentifierProvider extends IdentifierProvider {
protected Filter filterService; protected Filter filter = new TrueFilter();
/** /**
* Setter for spring to set the filter service from the property in configuration XML * Setter for spring to set the default filter from the property in configuration XML
* @param filterService - an object implementing the org.dspace.content.logic.Filter interface * @param filter - an object implementing the org.dspace.content.logic.Filter interface
*/ */
@Autowired public void setFilter(Filter filter) {
public void setFilterService(Filter filterService) { this.filter = filter;
this.filterService = filterService; if (this.filter == null) {
this.filter = new TrueFilter();
}
} }
/** /**
* Register a new identifier for a given DSpaceObject * Register a new identifier for a given DSpaceObject
* @param context - DSpace context * @param context - DSpace context
* @param dso - DSpaceObject to use for identifier registration * @param dso - DSpaceObject to use for identifier registration
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration * @param filter - Logical item filter to determine whether this identifier should be registered
* @return identifier * @return identifier
* @throws IdentifierException * @throws IdentifierException
*/ */
public abstract String register(Context context, DSpaceObject dso, boolean skipFilter) public abstract String register(Context context, DSpaceObject dso, Filter filter)
throws IdentifierException; throws IdentifierException;
/** /**
@@ -51,10 +53,10 @@ public abstract class FilteredIdentifierProvider extends IdentifierProvider {
* @param context - DSpace context * @param context - DSpace context
* @param dso - DSpaceObject identified by the new identifier * @param dso - DSpaceObject identified by the new identifier
* @param identifier - String containing the identifier to register * @param identifier - String containing the identifier to register
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration * @param filter - Logical item filter to determine whether this identifier should be registered
* @throws IdentifierException * @throws IdentifierException
*/ */
public abstract void register(Context context, DSpaceObject dso, String identifier, boolean skipFilter) public abstract void register(Context context, DSpaceObject dso, String identifier, Filter filter)
throws IdentifierException; throws IdentifierException;
/** /**
@@ -62,23 +64,23 @@ public abstract class FilteredIdentifierProvider extends IdentifierProvider {
* @param context - DSpace context * @param context - DSpace context
* @param dso - DSpaceObject identified by this identifier * @param dso - DSpaceObject identified by this identifier
* @param identifier - String containing the identifier to reserve * @param identifier - String containing the identifier to reserve
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing reservation * @param filter - Logical item filter to determine whether this identifier should be reserved
* @throws IdentifierException * @throws IdentifierException
* @throws IllegalArgumentException * @throws IllegalArgumentException
* @throws SQLException * @throws SQLException
*/ */
public abstract void reserve(Context context, DSpaceObject dso, String identifier, boolean skipFilter) public abstract void reserve(Context context, DSpaceObject dso, String identifier, Filter filter)
throws IdentifierException, IllegalArgumentException, SQLException; throws IdentifierException, IllegalArgumentException, SQLException;
/** /**
* Mint a new identifier in DSpace - this is usually the first step of registration * Mint a new identifier in DSpace - this is usually the first step of registration
* @param context - DSpace context * @param context - DSpace context
* @param dso - DSpaceObject identified by the new identifier * @param dso - DSpaceObject identified by the new identifier
* @param skipFilter - boolean indicating whether to skip any filtering of items before minting. * @param filter - Logical item filter to determine whether this identifier should be registered
* @return a String containing the new identifier * @return a String containing the new identifier
* @throws IdentifierException * @throws IdentifierException
*/ */
public abstract String mint(Context context, DSpaceObject dso, boolean skipFilter) throws IdentifierException; public abstract String mint(Context context, DSpaceObject dso, Filter filter) throws IdentifierException;
/** /**
* Check configured item filters to see if this identifier is allowed to be minted * Check configured item filters to see if this identifier is allowed to be minted
@@ -88,5 +90,13 @@ public abstract class FilteredIdentifierProvider extends IdentifierProvider {
*/ */
public abstract void checkMintable(Context context, DSpaceObject dso) throws IdentifierException; public abstract void checkMintable(Context context, DSpaceObject dso) throws IdentifierException;
/**
* Check configured item filters to see if this identifier is allowed to be minted
* @param context - DSpace context
* @param filter - Logical item filter
* @param dso - DSpaceObject to be inspected
* @throws IdentifierException
*/
public abstract void checkMintable(Context context, Filter filter, DSpaceObject dso) throws IdentifierException;
} }

View File

@@ -10,6 +10,7 @@ package org.dspace.identifier;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@@ -17,6 +18,8 @@ import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.logic.Filter;
import org.dspace.content.logic.TrueFilter;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.handle.service.HandleService; import org.dspace.handle.service.HandleService;
import org.dspace.identifier.service.IdentifierService; import org.dspace.identifier.service.IdentifierService;
@@ -98,7 +101,7 @@ public class IdentifierServiceImpl implements IdentifierService {
@Override @Override
public void register(Context context, DSpaceObject dso) public void register(Context context, DSpaceObject dso)
throws AuthorizeException, SQLException, IdentifierException { throws AuthorizeException, SQLException, IdentifierException {
//We need to commit our context because one of the providers might require the handle created above //We need to commit our context because one of the providers might require the handle created above
// Next resolve all other services // Next resolve all other services
for (IdentifierProvider service : providers) { for (IdentifierProvider service : providers) {
@@ -112,6 +115,98 @@ public class IdentifierServiceImpl implements IdentifierService {
contentServiceFactory.getDSpaceObjectService(dso).update(context, dso); contentServiceFactory.getDSpaceObjectService(dso).update(context, dso);
} }
@Override
public void register(Context context, DSpaceObject dso, Class<? extends Identifier> type, Filter filter)
throws AuthorizeException, SQLException, IdentifierException {
//We need to commit our context because one of the providers might require the handle created above
// Next resolve all other services
boolean registered = false;
for (IdentifierProvider service : providers) {
if (service.supports(type)) {
try {
if (service instanceof FilteredIdentifierProvider) {
FilteredIdentifierProvider filteredService = (FilteredIdentifierProvider)service;
filteredService.register(context, dso, filter);
} else {
service.register(context, dso);
}
registered = true;
} catch (IdentifierNotApplicableException e) {
log.warn("Identifier not registered (inapplicable): " + e.getMessage());
}
}
}
if (!registered) {
throw new IdentifierException("Cannot register identifier: Didn't "
+ "find a provider that supports this identifier.");
}
//Update our item / collection / community
contentServiceFactory.getDSpaceObjectService(dso).update(context, dso);
}
@Override
public void register(Context context, DSpaceObject dso, Class<? extends Identifier> type)
throws AuthorizeException, SQLException, IdentifierException {
//We need to commit our context because one of the providers might require the handle created above
// Next resolve all other services
boolean registered = false;
for (IdentifierProvider service : providers) {
if (service.supports(type)) {
try {
service.register(context, dso);
registered = true;
} catch (IdentifierNotApplicableException e) {
log.warn("Identifier not registered (inapplicable): " + e.getMessage());
}
}
}
if (!registered) {
throw new IdentifierException("Cannot register identifier: Didn't "
+ "find a provider that supports this identifier.");
}
//Update our item / collection / community
contentServiceFactory.getDSpaceObjectService(dso).update(context, dso);
}
@Override
public void register(Context context, DSpaceObject dso, Map<Class<? extends Identifier>, Filter> typeFilters)
throws AuthorizeException, SQLException, IdentifierException {
//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 {
// If the service supports filtering, look through the map and the first supported class
// we find, set the filter and break. If no filter was seen for this type, just let the provider
// use its own implementation.
if (service instanceof FilteredIdentifierProvider) {
FilteredIdentifierProvider filteredService = (FilteredIdentifierProvider)service;
Filter filter = null;
for (Class<? extends Identifier> type : typeFilters.keySet()) {
if (service.supports(type)) {
filter = typeFilters.get(type);
break;
}
}
if (filter != null) {
// Pass the found filter to the provider
filteredService.register(context, dso, filter);
} else {
// Let the provider use the default filter / behaviour
filteredService.register(context, dso);
}
} else {
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);
}
@Override @Override
public void register(Context context, DSpaceObject object, String identifier) public void register(Context context, DSpaceObject object, String identifier)
throws AuthorizeException, SQLException, IdentifierException { throws AuthorizeException, SQLException, IdentifierException {

View File

@@ -18,6 +18,7 @@ import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.content.MetadataValue; import org.dspace.content.MetadataValue;
import org.dspace.content.logic.Filter;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.identifier.doi.DOIConnector; import org.dspace.identifier.doi.DOIConnector;
import org.dspace.identifier.doi.DOIIdentifierException; import org.dspace.identifier.doi.DOIIdentifierException;
@@ -49,7 +50,12 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
protected VersionHistoryService versionHistoryService; protected VersionHistoryService versionHistoryService;
@Override @Override
public String mint(Context context, DSpaceObject dso) public String mint(Context context, DSpaceObject dso) throws IdentifierException {
return mint(context, dso, this.filter);
}
@Override
public String mint(Context context, DSpaceObject dso, Filter filter)
throws IdentifierException { throws IdentifierException {
if (!(dso instanceof Item)) { if (!(dso instanceof Item)) {
throw new IdentifierException("Currently only Items are supported for DOIs."); throw new IdentifierException("Currently only Items are supported for DOIs.");
@@ -79,6 +85,9 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
+ " with ID " + dso.getID() + ".", ex); + " with ID " + dso.getID() + ".", ex);
} }
// Make a call to the filter here to throw an exception instead of carrying on with removal + creation
checkMintable(context, filter, dso);
// check whether we have a DOI in the metadata and if we have to remove it // check whether we have a DOI in the metadata and if we have to remove it
String metadataDOI = getDOIOutOfObject(dso); String metadataDOI = getDOIOutOfObject(dso);
if (metadataDOI != null) { if (metadataDOI != null) {
@@ -111,7 +120,7 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
// ensure DOI exists in our database as well and return. // ensure DOI exists in our database as well and return.
// this also checks that the doi is not assigned to another dso already. // this also checks that the doi is not assigned to another dso already.
try { try {
loadOrCreateDOI(context, dso, versionedDOI); loadOrCreateDOI(context, dso, versionedDOI, filter);
} catch (SQLException ex) { } catch (SQLException ex) {
log.error( log.error(
"A problem with the database connection occurd while processing DOI " + versionedDOI + ".", ex); "A problem with the database connection occurd while processing DOI " + versionedDOI + ".", ex);
@@ -127,7 +136,7 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
// if we have a history, we have a item // if we have a history, we have a item
doi = makeIdentifierBasedOnHistory(context, dso, history); doi = makeIdentifierBasedOnHistory(context, dso, history);
} else { } else {
doi = loadOrCreateDOI(context, dso, null).getDoi(); doi = loadOrCreateDOI(context, dso, null, filter).getDoi();
} }
} catch (SQLException ex) { } catch (SQLException ex) {
log.error("SQLException while creating a new DOI: ", ex); log.error("SQLException while creating a new DOI: ", ex);
@@ -140,7 +149,12 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
} }
@Override @Override
public void register(Context context, DSpaceObject dso, String identifier) public void register(Context context, DSpaceObject dso, String identifier) throws IdentifierException {
register(context, dso, identifier, this.filter);
}
@Override
public void register(Context context, DSpaceObject dso, String identifier, Filter filter)
throws IdentifierException { throws IdentifierException {
if (!(dso instanceof Item)) { if (!(dso instanceof Item)) {
throw new IdentifierException("Currently only Items are supported for DOIs."); throw new IdentifierException("Currently only Items are supported for DOIs.");
@@ -220,8 +234,14 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
return doiPostfix; return doiPostfix;
} }
// Should never return null!
protected String makeIdentifierBasedOnHistory(Context context, DSpaceObject dso, VersionHistory history) protected String makeIdentifierBasedOnHistory(Context context, DSpaceObject dso, VersionHistory history)
throws AuthorizeException, SQLException, DOIIdentifierException, IdentifierNotApplicableException {
return makeIdentifierBasedOnHistory(context, dso, history, this.filter);
}
// Should never return null!
protected String makeIdentifierBasedOnHistory(Context context, DSpaceObject dso, VersionHistory history,
Filter filter)
throws AuthorizeException, SQLException, DOIIdentifierException, IdentifierNotApplicableException { throws AuthorizeException, SQLException, DOIIdentifierException, IdentifierNotApplicableException {
// Mint foreach new version an identifier like: 12345/100.versionNumber // Mint foreach new version an identifier like: 12345/100.versionNumber
// use the bare handle (g.e. 12345/100) for the first version. // use the bare handle (g.e. 12345/100) for the first version.
@@ -244,6 +264,9 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
} }
if (previousVersionDOI == null) { if (previousVersionDOI == null) {
// Before continuing with any new DOI creation, apply the filter
checkMintable(context, filter, dso);
// We need to generate a new DOI. // We need to generate a new DOI.
DOI doi = doiService.create(context); DOI doi = doiService.create(context);
@@ -269,7 +292,7 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
String.valueOf(versionHistoryService.getVersion(context, history, item).getVersionNumber())); String.valueOf(versionHistoryService.getVersion(context, history, item).getVersionNumber()));
} }
loadOrCreateDOI(context, dso, identifier); loadOrCreateDOI(context, dso, identifier, filter);
return identifier; return identifier;
} }

View File

@@ -7,23 +7,32 @@
*/ */
package org.dspace.identifier.doi; package org.dspace.identifier.doi;
import java.sql.SQLException;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.logic.Filter;
import org.dspace.content.logic.FilterUtils;
import org.dspace.core.Constants; import org.dspace.core.Constants;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.event.Consumer; import org.dspace.event.Consumer;
import org.dspace.event.Event; import org.dspace.event.Event;
import org.dspace.identifier.DOI;
import org.dspace.identifier.DOIIdentifierProvider; import org.dspace.identifier.DOIIdentifierProvider;
import org.dspace.identifier.IdentifierException; import org.dspace.identifier.IdentifierException;
import org.dspace.identifier.IdentifierNotFoundException; import org.dspace.identifier.IdentifierNotApplicableException;
import org.dspace.identifier.factory.IdentifierServiceFactory;
import org.dspace.identifier.service.DOIService;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.utils.DSpace; import org.dspace.utils.DSpace;
import org.dspace.workflow.factory.WorkflowServiceFactory; import org.dspace.workflow.factory.WorkflowServiceFactory;
/** /**
* @author Pascal-Nicolas Becker (p dot becker at tu hyphen berlin dot de) * @author Pascal-Nicolas Becker (p dot becker at tu hyphen berlin dot de)
* @author Kim Shepherd
*/ */
public class DOIConsumer implements Consumer { public class DOIConsumer implements Consumer {
/** /**
@@ -31,12 +40,15 @@ public class DOIConsumer implements Consumer {
*/ */
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(DOIConsumer.class); private static Logger log = org.apache.logging.log4j.LogManager.getLogger(DOIConsumer.class);
ConfigurationService configurationService;
@Override @Override
public void initialize() throws Exception { public void initialize() throws Exception {
// nothing to do // nothing to do
// we can ask spring to give as a properly setuped instance of // we can ask spring to give as a properly setuped instance of
// DOIIdentifierProvider. Doing so we don't have to configure it and // DOIIdentifierProvider. Doing so we don't have to configure it and
// can load it in consume method as this is not very expensive. // can load it in consume method as this is not very expensive.
configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
} }
@@ -63,77 +75,73 @@ public class DOIConsumer implements Consumer {
return; return;
} }
Item item = (Item) dso; Item item = (Item) dso;
DOIIdentifierProvider provider = new DSpace().getSingletonService(DOIIdentifierProvider.class);
boolean inProgress = (ContentServiceFactory.getInstance().getWorkspaceItemService().findByItem(ctx, item)
!= null || WorkflowServiceFactory.getInstance().getWorkflowItemService().findByItem(ctx, item) != null);
boolean identifiersInSubmission = configurationService.getBooleanProperty("identifiers.submission.register",
false);
DOIService doiService = IdentifierServiceFactory.getInstance().getDOIService();
Filter workspaceFilter = null;
if (identifiersInSubmission) {
workspaceFilter = FilterUtils.getFilterFromConfiguration("identifiers.submission.filter.workspace");
}
/* if (inProgress && !identifiersInSubmission) {
if (ContentServiceFactory.getInstance().getWorkspaceItemService().findByItem(ctx, item) != null // ignore workflow and workspace items, DOI will be minted and updated when item is installed
|| WorkflowServiceFactory.getInstance().getWorkflowItemService().findByItem(ctx, item) != null) { // UNLESS special pending filter is set
// ignore workflow and workspace items, DOI will be minted when item is installed
return; return;
} }
*/ DOI doi = null;
DOIIdentifierProvider provider = new DSpace().getSingletonService(
DOIIdentifierProvider.class);
String doi = null;
try { try {
doi = provider.lookup(ctx, dso); doi = doiService.findDOIByDSpaceObject(ctx, dso);
} catch (IdentifierNotFoundException ex) { } catch (SQLException ex) {
// nothing to do here, next if clause will stop us from processing // nothing to do here, next if clause will stop us from processing
// items without dois. // items without dois.
} }
if (doi == null) { if (doi == null) {
// if the item is workflow or workspace, there is a special case here - the ShowIdentifersStep // No DOI. The only time something should be minted is if we have enabled submission reg'n and
// needs this consumer to reserve DOIs in the event that the item now meets criteria for a pre-mint // it passes the workspace filter. We also need to update status to PENDING straight after.
if (ContentServiceFactory.getInstance().getWorkspaceItemService().findByItem(ctx, item) != null if (inProgress) {
|| WorkflowServiceFactory.getInstance().getWorkflowItemService().findByItem(ctx, item) != null) { provider.mint(ctx, dso, workspaceFilter);
if (DSpaceServicesFactory.getInstance().getConfigurationService() DOI newDoi = doiService.findDOIByDSpaceObject(ctx, dso);
.getBooleanProperty("identifiers.submission.register", false)) { if (newDoi != null) {
try { newDoi.setStatus(DOIIdentifierProvider.PENDING);
String newDoi = provider.mint(ctx, item); doiService.update(ctx, newDoi);
if (newDoi != null) {
provider.reserve(ctx, item, newDoi);
log.debug("Consumer minting and reserving new DOI for in-progress item: " + newDoi);
} else {
return;
}
} catch (DOIIdentifierNotApplicableException e) {
log.debug("Consumer skipping mint for item as it was filtered out: " + item.getID());
}
} else {
log.debug("Consumer skipping mint for item as it is in-progress and" +
"identifiers.submission.register=false: " + item.getID());
} }
} else { } else {
log.debug("DOIConsumer cannot handles items without DOIs, skipping: " log.debug("DOIConsumer cannot handles items without DOIs, skipping: " + event.toString());
+ event.toString());
return;
} }
} else if (ContentServiceFactory.getInstance().getWorkspaceItemService().findByItem(ctx, item) != null } else {
|| WorkflowServiceFactory.getInstance().getWorkflowItemService().findByItem(ctx, item) != null) { // If in progress, we can also switch PENDING and MINTED status depending on the latest filter
if (DSpaceServicesFactory.getInstance().getConfigurationService() // evaluation
.getBooleanProperty("identifiers.submission.register", false)) { if (inProgress) {
// We have a DOI for an in-progress submission item -- if the filter says "no", we should delete
// the minted DOI so it doesn't get registered on item install.
try { try {
provider.checkMintable(ctx, item); // Check the filter
} catch (DOIIdentifierNotApplicableException e) { provider.checkMintable(ctx, workspaceFilter, dso);
log.debug("Consumer deleting DOI for in-progress item: " + doi); // If we made it here, the existing doi should be back to PENDING
provider.delete(ctx, item, doi); if (DOIIdentifierProvider.MINTED.equals(doi.getStatus())) {
return; doi.setStatus(DOIIdentifierProvider.PENDING);
}
} catch (IdentifierNotApplicableException e) {
// Set status to MINTED if configured to downgrade existing DOIs
if (configurationService
.getBooleanProperty("identifiers.submission.strip_pending_during_submission", true)) {
doi.setStatus(DOIIdentifierProvider.MINTED);
}
} }
doiService.update(ctx, doi);
} else { } else {
log.debug("Consumer skipping mint for item as it is in-progress and" + try {
"identifiers.submission.register=false: " + item.getID()); provider.updateMetadata(ctx, dso, doi.getDoi());
} catch (IllegalArgumentException ex) {
// should not happen, as we got the DOI from the DOIProvider
log.warn("DOIConsumer caught an IdentifierException.", ex);
} catch (IdentifierException ex) {
log.warn("DOIConsumer cannot update metadata for Item with ID "
+ item.getID() + " and DOI " + doi + ".", ex);
}
} }
} ctx.commit();
try {
provider.updateMetadata(ctx, dso, doi);
} catch (IllegalArgumentException ex) {
// should not happen, as we got the DOI from the DOIProvider
log.warn("DOIConsumer caught an IdentifierException.", ex);
} catch (IdentifierException ex) {
log.warn("DOIConsumer cannot update metadata for Item with ID "
+ item.getID() + " and DOI " + doi + ".", ex);
} }
} }

View File

@@ -30,6 +30,9 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.logic.Filter;
import org.dspace.content.logic.FilterUtils;
import org.dspace.content.logic.TrueFilter;
import org.dspace.content.service.ItemService; import org.dspace.content.service.ItemService;
import org.dspace.core.Constants; import org.dspace.core.Constants;
import org.dspace.core.Context; import org.dspace.core.Context;
@@ -61,7 +64,8 @@ public class DOIOrganiser {
protected ItemService itemService; protected ItemService itemService;
protected DOIService doiService; protected DOIService doiService;
protected ConfigurationService configurationService; protected ConfigurationService configurationService;
protected boolean skipFilter; // This filter will override the default provider filter / behaviour
protected Filter filter;
/** /**
* Constructor to be called within the main() method * Constructor to be called within the main() method
@@ -76,7 +80,7 @@ public class DOIOrganiser {
this.itemService = ContentServiceFactory.getInstance().getItemService(); this.itemService = ContentServiceFactory.getInstance().getItemService();
this.doiService = IdentifierServiceFactory.getInstance().getDOIService(); this.doiService = IdentifierServiceFactory.getInstance().getDOIService();
this.configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); this.configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
this.skipFilter = false; this.filter = new TrueFilter();
} }
/** /**
@@ -121,12 +125,13 @@ public class DOIOrganiser {
"Perform online metadata update for all identifiers queued for metadata update."); "Perform online metadata update for all identifiers queued for metadata update.");
options.addOption("d", "delete-all", false, options.addOption("d", "delete-all", false,
"Perform online deletion for all identifiers queued for deletion."); "Perform online deletion for all identifiers queued for deletion.");
options.addOption("q", "quiet", false, options.addOption("q", "quiet", false,
"Turn the command line output off."); "Turn the command line output off.");
options.addOption(null, "skip-filter", false, Option filterDoi = Option.builder().optionalArg(true).longOpt("filter").hasArg().argName("filterName")
"Skip the configured item filter when registering or reserving."); .desc("Use the specified filter name instead of the provider's filter. Defaults to a special " +
"'always true' filter to force operations").build();
options.addOption(filterDoi);
Option registerDoi = Option.builder() Option registerDoi = Option.builder()
.longOpt("register-doi") .longOpt("register-doi")
@@ -203,10 +208,12 @@ public class DOIOrganiser {
} }
DOIService doiService = IdentifierServiceFactory.getInstance().getDOIService(); DOIService doiService = IdentifierServiceFactory.getInstance().getDOIService();
// Should we skip the filter? // Do we get a filter?
if (line.hasOption("skip-filter")) { if (line.hasOption("filter")) {
System.out.println("Skipping the item filter"); String filter = line.getOptionValue("filter");
organiser.skipFilter = true; if (null != filter) {
organiser.filter = FilterUtils.getFilterFromConfiguration(filter);
}
} }
if (line.hasOption('s')) { if (line.hasOption('s')) {
@@ -394,19 +401,18 @@ public class DOIOrganiser {
/** /**
* Register DOI with the provider * Register DOI with the provider
* @param doiRow - doi to register * @param doiRow - doi to register
* @param skipFilter - whether filters should be skipped before registration * @param filter - logical item filter to override
* @throws SQLException * @throws SQLException
* @throws DOIIdentifierException * @throws DOIIdentifierException
*/ */
public void register(DOI doiRow, boolean skipFilter) throws SQLException, DOIIdentifierException { public void register(DOI doiRow, Filter filter) throws SQLException, DOIIdentifierException {
DSpaceObject dso = doiRow.getDSpaceObject(); DSpaceObject dso = doiRow.getDSpaceObject();
if (Constants.ITEM != dso.getType()) { if (Constants.ITEM != dso.getType()) {
throw new IllegalArgumentException("Currenty DSpace supports DOIs for Items only."); throw new IllegalArgumentException("Currenty DSpace supports DOIs for Items only.");
} }
try { try {
provider.registerOnline(context, dso, provider.registerOnline(context, dso, DOI.SCHEME + doiRow.getDoi(), filter);
DOI.SCHEME + doiRow.getDoi());
if (!quiet) { if (!quiet) {
System.out.println("This identifier: " System.out.println("This identifier: "
@@ -466,29 +472,23 @@ public class DOIOrganiser {
} }
/** /**
* Register DOI with the provider, always applying (ie. never skipping) any configured filters * Register DOI with the provider
* @param doiRow - doi to register * @param doiRow - doi to register
* @throws SQLException * @throws SQLException
* @throws DOIIdentifierException * @throws DOIIdentifierException
*/ */
public void register(DOI doiRow) throws SQLException, DOIIdentifierException { public void register(DOI doiRow) throws SQLException, DOIIdentifierException {
if (this.skipFilter) { register(doiRow, this.filter);
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 * Reserve DOI with the provider,
* @param doiRow - doi to reserve * @param doiRow - doi to reserve
* @throws SQLException * @throws SQLException
* @throws DOIIdentifierException * @throws DOIIdentifierException
*/ */
public void reserve(DOI doiRow) { public void reserve(DOI doiRow) {
if (this.skipFilter) { reserve(doiRow, this.filter);
System.out.println("Skipping the filter for " + doiRow.getDoi());
}
reserve(doiRow, this.skipFilter);
} }
/** /**
@@ -497,14 +497,14 @@ public class DOIOrganiser {
* @throws SQLException * @throws SQLException
* @throws DOIIdentifierException * @throws DOIIdentifierException
*/ */
public void reserve(DOI doiRow, boolean skipFilter) { public void reserve(DOI doiRow, Filter filter) {
DSpaceObject dso = doiRow.getDSpaceObject(); DSpaceObject dso = doiRow.getDSpaceObject();
if (Constants.ITEM != dso.getType()) { if (Constants.ITEM != dso.getType()) {
throw new IllegalArgumentException("Currently DSpace supports DOIs for Items only."); throw new IllegalArgumentException("Currently DSpace supports DOIs for Items only.");
} }
try { try {
provider.reserveOnline(context, dso, DOI.SCHEME + doiRow.getDoi(), skipFilter); provider.reserveOnline(context, dso, DOI.SCHEME + doiRow.getDoi(), filter);
if (!quiet) { 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.");
@@ -699,7 +699,7 @@ public class DOIOrganiser {
//Check if this Item has an Identifier, mint one if it doesn't //Check if this Item has an Identifier, mint one if it doesn't
if (null == doiRow) { if (null == doiRow) {
doi = provider.mint(context, dso, this.skipFilter); doi = provider.mint(context, dso, this.filter);
doiRow = doiService.findByDoi(context, doiRow = doiService.findByDoi(context,
doi.substring(DOI.SCHEME.length())); doi.substring(DOI.SCHEME.length()));
return doiRow; return doiRow;
@@ -723,7 +723,7 @@ public class DOIOrganiser {
doiRow = doiService.findDOIByDSpaceObject(context, dso); doiRow = doiService.findDOIByDSpaceObject(context, dso);
if (null == doiRow) { if (null == doiRow) {
doi = provider.mint(context, dso, this.skipFilter); doi = provider.mint(context, dso, this.filter);
doiRow = doiService.findByDoi(context, doiRow = doiService.findByDoi(context,
doi.substring(DOI.SCHEME.length())); doi.substring(DOI.SCHEME.length()));
} }

View File

@@ -9,9 +9,11 @@ package org.dspace.identifier.service;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.Map;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.logic.Filter;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.identifier.Identifier; import org.dspace.identifier.Identifier;
import org.dspace.identifier.IdentifierException; import org.dspace.identifier.IdentifierException;
@@ -103,6 +105,40 @@ public interface IdentifierService {
*/ */
void register(Context context, DSpaceObject dso) throws AuthorizeException, SQLException, IdentifierException; void register(Context context, DSpaceObject dso) throws AuthorizeException, SQLException, IdentifierException;
/**
* @param context The relevant DSpace Context.
* @param dso DSpace object to be registered
* @param typeFilters If a service supports a given Identifier implementation, apply the associated filter
* @throws AuthorizeException if authorization error
* @throws SQLException if database error
* @throws IdentifierException if identifier error
*/
void register(Context context, DSpaceObject dso, Map<Class<? extends Identifier>, Filter> typeFilters)
throws AuthorizeException, SQLException, IdentifierException;
/**
* @param context The relevant DSpace Context.
* @param dso DSpace object to be registered
* @param type Type of identifier to register
* @param filter If a service supports a given Identifier implementation, apply this specific filter
* @throws AuthorizeException if authorization error
* @throws SQLException if database error
* @throws IdentifierException if identifier error
*/
void register(Context context, DSpaceObject dso, Class<? extends Identifier> type, Filter filter)
throws AuthorizeException, SQLException, IdentifierException;
/**
* @param context The relevant DSpace Context.
* @param dso DSpace object to be registered
* @param type Type of identifier to register
* @throws AuthorizeException if authorization error
* @throws SQLException if database error
* @throws IdentifierException if identifier error
*/
void register(Context context, DSpaceObject dso, Class<? extends Identifier> type)
throws AuthorizeException, SQLException, IdentifierException;
/** /**
* Used to Register a specific Identifier (for example a Handle, hdl:1234.5/6). * Used to Register a specific Identifier (for example a Handle, hdl:1234.5/6).
* The provider is responsible for detecting and processing the appropriate * The provider is responsible for detecting and processing the appropriate

View File

@@ -36,6 +36,7 @@ import org.dspace.content.WorkspaceItem;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.logic.DefaultFilter; import org.dspace.content.logic.DefaultFilter;
import org.dspace.content.logic.LogicalStatement; import org.dspace.content.logic.LogicalStatement;
import org.dspace.content.logic.TrueFilter;
import org.dspace.content.service.CollectionService; import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService; import org.dspace.content.service.CommunityService;
import org.dspace.content.service.ItemService; import org.dspace.content.service.ItemService;
@@ -128,7 +129,7 @@ public class DOIIdentifierProviderTest
provider.itemService = itemService; provider.itemService = itemService;
provider.setConfigurationService(config); provider.setConfigurationService(config);
provider.setDOIConnector(connector); provider.setDOIConnector(connector);
provider.setFilterService(null); provider.setFilter(null);
} catch (AuthorizeException ex) { } catch (AuthorizeException ex) {
log.error("Authorization Error in init", ex); log.error("Authorization Error in init", ex);
fail("Authorization Error in init: " + ex.getMessage()); fail("Authorization Error in init: " + ex.getMessage());
@@ -504,7 +505,7 @@ public class DOIIdentifierProviderTest
String doi = null; String doi = null;
try { try {
// get a DOI (skipping any filters) // get a DOI (skipping any filters)
doi = provider.mint(context, item, true); doi = provider.mint(context, item);
} catch (IdentifierException e) { } catch (IdentifierException e) {
e.printStackTrace(System.err); e.printStackTrace(System.err);
fail("Got an IdentifierException: " + e.getMessage()); fail("Got an IdentifierException: " + e.getMessage());
@@ -544,23 +545,18 @@ public class DOIIdentifierProviderTest
Item item = newItem(); Item item = newItem();
boolean wasFiltered = false; boolean wasFiltered = false;
try { try {
// Temporarily set the provider to have a filter that always returns false for an item // Mint this with the filter
// (therefore, the item should be 'filtered' out and not apply to this minting request)
DefaultFilter doiFilter = new DefaultFilter(); DefaultFilter doiFilter = new DefaultFilter();
LogicalStatement alwaysFalse = (context, i) -> false; LogicalStatement alwaysFalse = (context, i) -> false;
doiFilter.setStatement(alwaysFalse); doiFilter.setStatement(alwaysFalse);
provider.setFilterService(doiFilter);
// get a DOI with the method that applies filters by default // get a DOI with the method that applies filters by default
provider.mint(context, item); provider.mint(context, item, doiFilter);
} catch (DOIIdentifierNotApplicableException e) { } catch (DOIIdentifierNotApplicableException e) {
// This is what we wanted to see - we can return safely // This is what we wanted to see - we can return safely
wasFiltered = true; wasFiltered = true;
} catch (IdentifierException e) { } catch (IdentifierException e) {
e.printStackTrace(); e.printStackTrace();
fail("Got an IdentifierException: " + e.getMessage()); 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 // Fail the test if the filter didn't throw a "not applicable" exception
assertTrue("DOI minting attempt was not filtered by filter service", wasFiltered); assertTrue("DOI minting attempt was not filtered by filter service", wasFiltered);
@@ -583,17 +579,14 @@ public class DOIIdentifierProviderTest
DefaultFilter doiFilter = new DefaultFilter(); DefaultFilter doiFilter = new DefaultFilter();
LogicalStatement alwaysTrue = (context, i) -> true; LogicalStatement alwaysTrue = (context, i) -> true;
doiFilter.setStatement(alwaysTrue); doiFilter.setStatement(alwaysTrue);
provider.setFilterService(doiFilter);
// get a DOI with the method that applies filters by default // get a DOI with the method that applies filters by default
doi = provider.mint(context, item); doi = provider.mint(context, item, doiFilter);
} catch (DOIIdentifierNotApplicableException e) { } catch (DOIIdentifierNotApplicableException e) {
// This is what we wanted to see - we can return safely // This is what we wanted to see - we can return safely
wasFiltered = true; wasFiltered = true;
} catch (IdentifierException e) { } catch (IdentifierException e) {
e.printStackTrace(); e.printStackTrace();
fail("Got an IdentifierException: " + e.getMessage()); fail("Got an IdentifierException: " + e.getMessage());
} finally {
provider.setFilterService(null);
} }
// If the attempt was filtered, fail // If the attempt was filtered, fail
assertFalse("DOI minting attempt was incorrectly filtered by filter service", wasFiltered); assertFalse("DOI minting attempt was incorrectly filtered by filter service", wasFiltered);
@@ -665,7 +658,7 @@ public class DOIIdentifierProviderTest
Item item = newItem(); Item item = newItem();
// Register, skipping the filter // Register, skipping the filter
String doi = provider.register(context, item, true); String doi = provider.register(context, item, new TrueFilter());
// we want the created DOI to be returned in the following format: // we want the created DOI to be returned in the following format:
// doi:10.<prefix>/<suffix>. // doi:10.<prefix>/<suffix>.

View File

@@ -0,0 +1,144 @@
/**
* 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.app.rest;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.converter.MetadataConverter;
import org.dspace.app.rest.model.IdentifierRest;
import org.dspace.app.rest.model.IdentifiersRest;
import org.dspace.app.rest.model.ItemRest;
import org.dspace.app.rest.repository.ItemRestRepository;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Item;
import org.dspace.content.logic.TrueFilter;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.identifier.DOI;
import org.dspace.identifier.DOIIdentifierProvider;
import org.dspace.identifier.IdentifierException;
import org.dspace.identifier.IdentifierNotFoundException;
import org.dspace.identifier.service.DOIService;
import org.dspace.identifier.service.IdentifierService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ControllerUtils;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* Controller to register identifiers
*/
@RestController
@RequestMapping("/api/" + ItemRest.CATEGORY + "/" + ItemRest.PLURAL_NAME + REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID
+ "/" + IdentifiersRest.PLURAL_NAME)
public class ItemIdentifierController {
@Autowired
ConverterService converter;
@Autowired
ItemService itemService;
@Autowired
ItemRestRepository itemRestRepository;
@Autowired
MetadataConverter metadataConverter;
@Autowired
IdentifierService identifierService;
@Autowired
DOIService doiService;
@Autowired
Utils utils;
public IdentifiersRest get(@PathVariable UUID uuid, HttpServletRequest request,
HttpServletResponse response)
throws SQLException, AuthorizeException {
Context context = ContextUtil.obtainContext(request);
Item item = itemService.find(context, uuid);
if (item == null) {
throw new ResourceNotFoundException("Could not find item with id " + uuid);
}
IdentifiersRest identifiersRest = new IdentifiersRest();
List<IdentifierRest> identifierRests = new ArrayList<>();
DOI doi = doiService.findDOIByDSpaceObject(context, item);
String handle = HandleServiceFactory.getInstance().getHandleService().findHandle(context, item);
try {
if (doi != null) {
String doiUrl = doiService.DOIToExternalForm(doi.getDoi());
IdentifierRest identifierRest = new IdentifierRest(doiUrl, "doi", String.valueOf(doi.getStatus()));
identifierRests.add(identifierRest);
}
if (handle != null) {
identifierRests.add(new IdentifierRest(handle, "handle", null));
}
} catch (IdentifierException e) {
throw new IllegalStateException("Failed to register identifier: " + e.getMessage());
}
return identifiersRest;
}
/**
* Method to register an identifier for an item.
*
* @return OK
*/
@RequestMapping(method = RequestMethod.POST)
@PreAuthorize("hasPermission(#uuid, 'ITEM', 'ADMIN')")
public ResponseEntity<RepresentationModel<?>> registerIdentifierForItem(@PathVariable UUID uuid,
HttpServletRequest request,
HttpServletResponse response)
throws SQLException, AuthorizeException {
Context context = ContextUtil.obtainContext(request);
Item item = itemService.find(context, uuid);
if (item == null) {
throw new ResourceNotFoundException("Could not find item with id " + uuid);
}
String identifier = null;
try {
DOIIdentifierProvider doiIdentifierProvider = DSpaceServicesFactory.getInstance().getServiceManager()
.getServiceByName("org.dspace.identifier.DOIIdentifierProvider", DOIIdentifierProvider.class);
doiIdentifierProvider.register(context, item, new TrueFilter());
if (context != null) {
context.commit();
}
} catch (IdentifierNotFoundException e) {
return ControllerUtils.toEmptyResponse(HttpStatus.NO_CONTENT);
} catch (IdentifierException e) {
throw new IllegalStateException("Failed to register identifier: " + identifier);
}
return ControllerUtils.toEmptyResponse(HttpStatus.CREATED);
}
}

View File

@@ -0,0 +1,67 @@
/**
* 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
* <p>
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.model;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Implementation of IdentifierRest REST resource, representing some DSpace identifier
* for use with the REST API
*
* @author Kim Shepherd <kim@shepherd.nz>
*/
public class IdentifierRest implements RestModel {
// Set names used in component wiring
public static final String NAME = "identifier";
public static final String PLURAL_NAME = "identifiers";
private String value;
private String identifierType;
private String identifierStatus;
// Empty constructor
public IdentifierRest() {
}
public IdentifierRest(String value, String identifierType, String identifierStatus) {
this.value = value;
this.identifierType = identifierType;
this.identifierStatus = identifierStatus;
}
// Return name for getType()
@Override
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public String getType() {
return NAME;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getIdentifierType() {
return identifierType;
}
public void setIdentifierType(String identifierType) {
this.identifierType = identifierType;
}
public String getIdentifierStatus() {
return identifierStatus;
}
public void setIdentifierStatus(String identifierStatus) {
this.identifierStatus = identifierStatus;
}
}

View File

@@ -0,0 +1,47 @@
/**
* 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
* <p>
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.model;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Implementation of IdentifierRest REST resource, representing a list of all identifiers
* for use with the REST API
*
* @author Kim Shepherd <kim@shepherd.nz>
*/
public class IdentifiersRest implements RestModel {
// Set names used in component wiring
public static final String NAME = "identifier";
public static final String PLURAL_NAME = "identifiers";
private List<IdentifierRest> identifiers;
// Empty constructor
public IdentifiersRest() {
identifiers = new ArrayList<>();
}
// Return name for getType()
@Override
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public String getType() {
return NAME;
}
public List<IdentifierRest> getIdentifiers() {
return identifiers;
}
public void setIdentifiers(List<IdentifierRest> identifiers) {
this.identifiers = identifiers;
}
}

View File

@@ -25,6 +25,10 @@ import com.fasterxml.jackson.annotation.JsonProperty;
name = ItemRest.BUNDLES, name = ItemRest.BUNDLES,
method = "getBundles" method = "getBundles"
), ),
//@LinkRest(
// name = ItemRest.IDENTIFIERS,
// method = "getIdentifiers"
//),
@LinkRest( @LinkRest(
name = ItemRest.MAPPED_COLLECTIONS, name = ItemRest.MAPPED_COLLECTIONS,
method = "getMappedCollections" method = "getMappedCollections"
@@ -57,6 +61,7 @@ public class ItemRest extends DSpaceObjectRest {
public static final String ACCESS_STATUS = "accessStatus"; public static final String ACCESS_STATUS = "accessStatus";
public static final String BUNDLES = "bundles"; public static final String BUNDLES = "bundles";
public static final String IDENTIFIERS = "identifiers";
public static final String MAPPED_COLLECTIONS = "mappedCollections"; public static final String MAPPED_COLLECTIONS = "mappedCollections";
public static final String OWNING_COLLECTION = "owningCollection"; public static final String OWNING_COLLECTION = "owningCollection";
public static final String RELATIONSHIPS = "relationships"; public static final String RELATIONSHIPS = "relationships";

View File

@@ -20,6 +20,10 @@ public class DataIdentifiers implements SectionData {
String doi; String doi;
List<String> otherIdentifiers; List<String> otherIdentifiers;
public DataIdentifiers() {
}
public String getHandle() { public String getHandle() {
return handle; return handle;
} }

View File

@@ -45,6 +45,10 @@ import org.dspace.content.service.RelationshipService;
import org.dspace.content.service.RelationshipTypeService; import org.dspace.content.service.RelationshipTypeService;
import org.dspace.content.service.WorkspaceItemService; import org.dspace.content.service.WorkspaceItemService;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.identifier.IdentifierException;
import org.dspace.identifier.VersionedHandleIdentifierProviderWithCanonicalHandles;
import org.dspace.identifier.service.IdentifierService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.util.UUIDUtils; import org.dspace.util.UUIDUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@@ -92,6 +96,9 @@ public class ItemRestRepository extends DSpaceObjectRestRepository<Item, ItemRes
@Autowired @Autowired
RelationshipTypeService relationshipTypeService; RelationshipTypeService relationshipTypeService;
@Autowired
IdentifierService identifierService;
@Autowired @Autowired
private UriListHandlerService uriListHandlerService; private UriListHandlerService uriListHandlerService;
@@ -357,6 +364,44 @@ public class ItemRestRepository extends DSpaceObjectRestRepository<Item, ItemRes
return bundle; return bundle;
} }
/**
* Register an identifier for an item
* @param context
* @param item
* @param identifier
* @return
* @throws SQLException
* @throws AuthorizeException
* @throws IdentifierException
*/
@PreAuthorize("hasPermission(#uuid, 'ITEM', 'ADMIN')")
public boolean registerIdentifier(Context context, Item item, String identifier)
throws SQLException, AuthorizeException, IdentifierException {
if (item != null) {
if (identifier != null) {
// Try to register the supplied identifier
identifierService.register(context, item, identifier);
return item.equals(identifierService.resolve(context, identifier));
} else {
DSpaceServicesFactory.getInstance().getServiceManager()
.getServicesByType(VersionedHandleIdentifierProviderWithCanonicalHandles.class);
// Call plain 'register' which will mint a new DOI, handle, etc if needed
// this NOT compatible with versioned handle provider with canonical handles
boolean compatible = DSpaceServicesFactory.getInstance().getServiceManager()
.getServicesByType(VersionedHandleIdentifierProviderWithCanonicalHandles.class).isEmpty();
if (compatible) {
// Register without a supplied identifier
identifierService.register(context, item);
return true;
} else {
log.error("This register method is NOT compatible with" +
"VersionedHandleIdentifierProviderWithCanonicalHandles");
}
}
}
return false;
}
@Override @Override
protected ItemRest createAndReturn(Context context, List<String> stringList) protected ItemRest createAndReturn(Context context, List<String> stringList)
throws AuthorizeException, SQLException, RepositoryMethodNotImplementedException { throws AuthorizeException, SQLException, RepositoryMethodNotImplementedException {

View File

@@ -7,6 +7,7 @@
*/ */
package org.dspace.app.rest.submit.step; package org.dspace.app.rest.submit.step;
import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@@ -26,6 +27,7 @@ import org.dspace.core.Context;
import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService; import org.dspace.handle.service.HandleService;
import org.dspace.identifier.DOI; import org.dspace.identifier.DOI;
import org.dspace.identifier.DOIIdentifierProvider;
import org.dspace.identifier.Handle; import org.dspace.identifier.Handle;
import org.dspace.identifier.IdentifierException; import org.dspace.identifier.IdentifierException;
import org.dspace.identifier.factory.IdentifierServiceFactory; import org.dspace.identifier.factory.IdentifierServiceFactory;
@@ -90,20 +92,31 @@ public class ShowIdentifiersStep extends AbstractProcessingStep {
IdentifierServiceFactory.getInstance().getIdentifierService(); IdentifierServiceFactory.getInstance().getIdentifierService();
// Attempt to look up handle and DOI identifiers for this item // Attempt to look up handle and DOI identifiers for this item
String handle = identifierService.lookup(context, obj.getItem(), Handle.class); String handle = identifierService.lookup(context, obj.getItem(), Handle.class);
String doi = identifierService.lookup(context, obj.getItem(), DOI.class); String simpleDoi = identifierService.lookup(context, obj.getItem(), DOI.class);
DOI doi = null;
String doiString = null;
try {
doi = IdentifierServiceFactory.getInstance().getDOIService().findDOIByDSpaceObject(context, obj.getItem());
if (doi != null && !DOIIdentifierProvider.MINTED.equals(doi.getStatus())
&& !DOIIdentifierProvider.MINTED.equals(doi.getStatus())) {
doiString = doi.getDoi();
}
} catch (SQLException e) {
log.error(e.getMessage());
}
// Look up all identifiers and if they're not the DOI or handle, add them to the 'other' list // Look up all identifiers and if they're not the DOI or handle, add them to the 'other' list
List<String> otherIdentifiers = new ArrayList<>(); List<String> otherIdentifiers = new ArrayList<>();
for (String identifier : identifierService.lookup(context, obj.getItem())) { for (String identifier : identifierService.lookup(context, obj.getItem())) {
if (!StringUtils.equals(doi, identifier) && !StringUtils.equals(handle, identifier)) { if (!StringUtils.equals(simpleDoi, identifier) && !StringUtils.equals(handle, identifier)) {
otherIdentifiers.add(identifier); otherIdentifiers.add(identifier);
} }
} }
// If we got a DOI, format it to its external form // If we got a DOI, format it to its external form
if (StringUtils.isNotEmpty(doi)) { if (StringUtils.isNotEmpty(doiString)) {
try { try {
doi = IdentifierServiceFactory.getInstance().getDOIService().DOIToExternalForm(doi); doiString = IdentifierServiceFactory.getInstance().getDOIService().DOIToExternalForm(doiString);
} catch (IdentifierException e) { } catch (IdentifierException e) {
log.error("Error formatting DOI: " + doi); log.error("Error formatting DOI: " + doi);
} }
@@ -114,7 +127,7 @@ public class ShowIdentifiersStep extends AbstractProcessingStep {
} }
// Populate bean with data and return // Populate bean with data and return
result.setDoi(doi); result.setDoi(doiString);
result.setHandle(handle); result.setHandle(handle);
result.setOtherIdentifiers(otherIdentifiers); result.setOtherIdentifiers(otherIdentifiers);

View File

@@ -240,7 +240,7 @@
<!--<step id="sample"/> --> <!--<step id="sample"/> -->
<step id="collection"/> <step id="collection"/>
<step id="identifiers"/>
<!--Step will be to Describe the item. --> <!--Step will be to Describe the item. -->
<step id="traditionalpageone"/> <step id="traditionalpageone"/>
<step id="traditionalpagetwo"/> <step id="traditionalpagetwo"/>

View File

@@ -5,7 +5,35 @@
# as the Show Identifiers step which can "pre-mint" DOIs and Handles # # as the Show Identifiers step which can "pre-mint" DOIs and Handles #
#----------------------------------------------------------------------# #----------------------------------------------------------------------#
# Should identifiers be registered in the Show Identifiers step and minted / updated / deleted as appropriate # Should DOIs be minted for (future) registration at workspace item creation?
# in the DOI Consumer? Setting this property to 'true' is recommended # A DOI created at this stage will be in a 'PENDING' status while in workspace and workflow.
# At the time of item install, the DOI filter (if any) will be applied and if the item matches the filter, the DOI
# status will be updated to TO_BE_REGISTERED. An administrator can also manually progress the DOI status, overriding
# any filters, in the item status page.
# This option doesn't require the Show Identifiers submission step to be visible.
# Default: false # Default: false
#identifiers.submission.register = false #identifiers.submission.register = true
# This configuration property can be set to a filter name to determine if a PENDING DOI for an item
# should be queued for registration. If the filter doesn't match, the DOI will stay in PENDING or MINTED status
# so that the identifier itself persists in case it is considered for registration in the future.
# See doi-filter and other example filters in item-filters.xml.
# Default (always_true_filter)
#identifiers.submission.filter.install = doi-filter
# This optional configuration property can be set to a filter name, in case there are some initial rules to apply
# when first deciding whether a DOI should be be created for a new workspace item with a PENDING status.
# This filter is only applied if identifiers.submission.register is true.
# This filter is updated as submission data is saved.
# Default: (always_true_filter)
#identifiers.submission.filter.workspace = always_true_filter
# If true, the workspace filter will be applied as submission data is saved. If the filter no longer
# matches the item, the DOI will be shifted into a MINTED status and not displayed in the submission section.
# If false, then once a DOI has been created with PENDING status it will remain that way until final item install
# Default: true
#identifiers.submission.strip_pending_during_submission = true
# This configuration property can be set to a filter name to determine if an item processed by RegisterDOI curation
# task should be eligible for a DOI
#identifiers.submission.filter.curation = always_true_filter

View File

@@ -55,6 +55,7 @@
ref="org.dspace.services.ConfigurationService" /> ref="org.dspace.services.ConfigurationService" />
<property name="DOIConnector" <property name="DOIConnector"
ref="org.dspace.identifier.doi.DOIConnector" /> ref="org.dspace.identifier.doi.DOIConnector" />
<property name="filter" ref="doi-filter" />
</bean> </bean>
--> -->
<!-- <!--
@@ -78,7 +79,7 @@
ref="org.dspace.services.ConfigurationService" /> ref="org.dspace.services.ConfigurationService" />
<property name="DOIConnector" <property name="DOIConnector"
ref="org.dspace.identifier.doi.DOIConnector" /> ref="org.dspace.identifier.doi.DOIConnector" />
<property name="filterService" ref="openaire_filter" /> <property name="filter" ref="doi-filter" />
</bean> </bean>
--> -->

View File

@@ -20,7 +20,7 @@
<!-- default-autowire-candidates="*Service,*DAO,javax.sql.DataSource"> --> <!-- default-autowire-candidates="*Service,*DAO,javax.sql.DataSource"> -->
<context:annotation-config /> <!-- allows us to use spring annotations in beans --> <context:annotation-config /> <!-- allows us to use spring annotations in beans -->
<bean id="always_true_filter" class="org.dspace.content.logic.TrueFilter"/>
<!-- DEFINE CONDITIONS <!-- DEFINE CONDITIONS
Define condition beans below for use as sub-statements in operator and filter beans Define condition beans below for use as sub-statements in operator and filter beans
@@ -168,6 +168,17 @@
</property> </property>
</bean> </bean>
<bean id="is-archived_condition" class="org.dspace.content.logic.condition.IsArchivedCondition">
<property name="parameters">
<map></map>
</property>
</bean>
<bean id="is-withdrawn_condition" class="org.dspace.content.logic.condition.IsWithdrawnCondition">
<property name="parameters">
<map></map>
</property>
</bean>
<!-- DEFINE OPERATORS <!-- DEFINE OPERATORS
Operators can be defined too, if a particular AND or OR statement needs to be re-used a lot, though 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 it may be easier in most cases to turn that into a filter and reference the filter in other sub-statements
@@ -195,11 +206,15 @@
<bean class="org.dspace.content.logic.operator.And"> <bean class="org.dspace.content.logic.operator.And">
<property name="statements"> <property name="statements">
<list> <list>
<!-- Make sure the item is archived -->
<ref bean="is-archived_condition"/>
<!-- Make sure the item is not withdrawn -->
<bean class="org.dspace.content.logic.operator.Not">
<property name="statements" ref="is-withdrawn_condition"/>
</bean>
<!-- Don't create new DOIs for items that already have one --> <!-- Don't create new DOIs for items that already have one -->
<bean class="org.dspace.content.logic.operator.Not"> <bean class="org.dspace.content.logic.operator.Not">
<property name="statements"> <property name="statements" ref="dc-identifier-uri-contains-doi_condition"/>
<ref bean="dc-identifier-uri-contains-doi_condition"/>
</property>
</bean> </bean>
<!-- Create DOIs for items only that do have at least one bitstream. --> <!-- Create DOIs for items only that do have at least one bitstream. -->
<ref bean="has-at-least-one-bitstream_condition"/> <ref bean="has-at-least-one-bitstream_condition"/>
@@ -226,16 +241,12 @@
<!-- A very simple demonstration filter, using the metadata match condition --> <!-- A very simple demonstration filter, using the metadata match condition -->
<bean id="simple-demo_filter" class="org.dspace.content.logic.DefaultFilter"> <bean id="simple-demo_filter" class="org.dspace.content.logic.DefaultFilter">
<property name="statement"> <property name="statement" ref="title-contains-demo_condition"/>
<ref bean="title-contains-demo_condition"/>
</property>
</bean> </bean>
<!-- A very simple filter for items with at least one bitstream --> <!-- A very simple filter for items with at least one bitstream -->
<bean id="has-bitstream_filter" class="org.dspace.content.logic.DefaultFilter"> <bean id="has-bitstream_filter" class="org.dspace.content.logic.DefaultFilter">
<property name="statement"> <property name="statement" ref="has-at-least-one-bitstream_condition"/>
<ref bean="has-at-least-one-bitstream_condition"/>
</property>
</bean> </bean>
<!-- <!--
@@ -335,5 +346,27 @@
</property> </property>
</bean> </bean>
<bean id="example-doi_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>
</list>
</property>
</bean>
</property>
</bean>
</beans> </beans>