[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

@@ -13,7 +13,7 @@
scope="singleton"/> scope="singleton"/>
<!-- If you enabled versioning, you should use one of the versioned <!-- If you enabled versioning, you should use one of the versioned
handle identifier provider instead of the default one. handle identifier provider instead of the default one.
The VersionedHandleIdentifierProvider creates a new versioned The VersionedHandleIdentifierProvider creates a new versioned
handle for every new version. handle for every new version.
--> -->
@@ -42,7 +42,7 @@
a DOIConnector that handles all API calls to your DOI registration a DOIConnector that handles all API calls to your DOI registration
agency. Please configure a DOIConnector as well! --> agency. Please configure a DOIConnector as well! -->
<!-- In order to mint DOIs with DSpace, get an agreement with a DOI <!-- In order to mint DOIs with DSpace, get an agreement with a DOI
registration agency, take a look into dspace.cfg, and activate either registration agency, take a look into dspace.cfg, and activate either
the DOIIdentifierProvider or the VersionedDOIIdentifierProvider, the DOIIdentifierProvider or the VersionedDOIIdentifierProvider,
depending on whether you have Item Level Versioning activated or not. depending on whether you have Item Level Versioning activated or not.
@@ -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,11 +79,11 @@
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>
--> -->
<!-- The DOIConnector will handle the API calls to your DOI registration <!-- The DOIConnector will handle the API calls to your DOI registration
agency for the DOIIdentifierProvider. If your registration agency agency for the DOIIdentifierProvider. If your registration agency
tells you to use the DataCite API directly, you can use the tells you to use the DataCite API directly, you can use the
@@ -105,9 +106,9 @@
<!-- Provider to mint and register DOIs using EZID as the registrar. <!-- Provider to mint and register DOIs using EZID as the registrar.
--> -->
<!-- <!--
Set generateDataciteXML to true to send metadata in DataCite xml schema for EZID DOI mint requests. Set generateDataciteXML to true to send metadata in DataCite xml schema for EZID DOI mint requests.
When generateDataciteXML is enabled, EZIDIdentifierProvider uses When generateDataciteXML is enabled, EZIDIdentifierProvider uses
dspace.cfg:crosswalk.dissemination.DataCite.stylesheet XSL configuration for metadata mapping dspace.cfg:crosswalk.dissemination.DataCite.stylesheet XSL configuration for metadata mapping
--> -->
<!-- Uncomment to enable DOI using EZID <!-- Uncomment to enable DOI using EZID

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>