[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.sql.SQLException;
import java.util.HashMap;
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.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.InstallItemService;
import org.dspace.content.service.ItemService;
@@ -20,8 +27,12 @@ import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.embargo.service.EmbargoService;
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.service.IdentifierService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.springframework.beans.factory.annotation.Autowired;
/**
@@ -42,9 +53,11 @@ public class InstallItemServiceImpl implements InstallItemService {
protected IdentifierService identifierService;
@Autowired(required = true)
protected ItemService itemService;
@Autowired(required = false)
Logger log = LogManager.getLogger(InstallItemServiceImpl.class);
protected InstallItemServiceImpl() {
}
@Override
@@ -59,11 +72,17 @@ public class InstallItemServiceImpl implements InstallItemService {
AuthorizeException {
Item item = is.getItem();
Collection collection = is.getCollection();
// Get map of filters to use for identifier types
Map<Class<? extends Identifier>, Filter> filters = FilterUtils.getIdentifierFilters("install");
try {
if (suppliedHandle == null) {
identifierService.register(c, item);
// Register with the filters we've set up
identifierService.register(c, item, filters);
} 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);
// Continue to register just a DOI
identifierService.register(c, item, DOI.class, filters.get(DOI.class));
}
} catch (IdentifierException 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.service.AuthorizeService;
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.ItemService;
import org.dspace.content.service.WorkspaceItemService;
@@ -32,8 +34,12 @@ import org.dspace.core.Context;
import org.dspace.core.LogHelper;
import org.dspace.eperson.EPerson;
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.factory.IdentifierServiceFactory;
import org.dspace.identifier.service.DOIService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.workflow.WorkflowItem;
import org.dspace.workflow.WorkflowService;
@@ -61,6 +67,8 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService {
protected ItemService itemService;
@Autowired(required = true)
protected WorkflowService workflowService;
@Autowired(required = true)
protected DOIService doiService;
protected WorkspaceItemServiceImpl() {
@@ -169,7 +177,15 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService {
if (DSpaceServicesFactory.getInstance().getConfigurationService()
.getBooleanProperty("identifiers.submission.register", false)) {
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) {
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 {
private LogicalStatement statement;
private String name;
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 {
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.core.Context;
import org.springframework.beans.factory.BeanNameAware;
/**
* 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
* @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
* @param context DSpace context
@@ -32,4 +33,6 @@ public interface Filter extends LogicalStatement {
*/
@Override
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.dspace.content.DSpaceObject;
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.Curator;
import org.dspace.identifier.DOIIdentifierProvider;
@@ -46,8 +49,6 @@ public class RegisterDOI extends AbstractCurationTask {
@Override
public void init(Curator curator, String taskId) throws IOException {
super.init(curator, taskId);
// Get 'skip filter' behaviour from configuration, with a default value of 'true'
skipFilter = configurationService.getBooleanProperty(PLUGIN_PREFIX + ".skip-filter", true);
// Get distribution behaviour from configuration, with a default value of 'false'
distributed = configurationService.getBooleanProperty(PLUGIN_PREFIX + ".distributed", false);
log.debug("PLUGIN_PREFIX = " + PLUGIN_PREFIX + ", skipFilter = " + skipFilter +
@@ -118,8 +119,9 @@ public class RegisterDOI extends AbstractCurationTask {
String doi = null;
// Attempt DOI registration and report successes and failures
try {
log.debug("Registering DOI with skipFilter = " + skipFilter);
doi = provider.register(Curator.curationContext(), item, skipFilter);
Filter filter = FilterUtils.getFilterFromConfiguration("identifiers.submission.filter.curation",
new TrueFilter());
doi = provider.register(Curator.curationContext(), item, filter);
if (doi != null) {
String message = "New DOI minted in database for item " + item.getHandle() + ": " + doi
+ ". This DOI will be registered online with the DOI provider when the queue is next run";

View File

@@ -21,6 +21,7 @@ import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.logic.Filter;
import org.dspace.content.logic.LogicalStatementException;
import org.dspace.content.logic.TrueFilter;
import org.dspace.content.service.ItemService;
import org.dspace.core.Constants;
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>
*
* @author Pascal-Nicolas Becker
* @author Kim Shepherd
*/
public class DOIIdentifierProvider extends FilteredIdentifierProvider {
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 DOI_ELEMENT = "identifier";
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;
// The DOI is queued for reservation with the service provider
public static final Integer TO_BE_RESERVED = 2;
// The DOI has been registered online
public static final Integer IS_REGISTERED = 3;
// The DOI has been reserved online
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;
// The DOI is registered and requires an updated metadata record to be sent to the service provider
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;
// The DOI will be deleted locally and marked as deleted in the DOI service provider
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;
// 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)
protected DOIService doiService;
@@ -89,8 +104,6 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
@Autowired(required = true)
protected ItemService itemService;
protected Filter filterService;
/**
* Empty / default constructor for Spring
*/
@@ -153,16 +166,6 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
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
* {@link org.dspace.identifier.DOI}.
@@ -206,7 +209,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
@Override
public String register(Context context, DSpaceObject dso)
throws IdentifierException {
return register(context, dso, false);
return register(context, dso, this.filter);
}
/**
@@ -219,29 +222,29 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
@Override
public void register(Context context, DSpaceObject dso, String identifier)
throws IdentifierException {
register(context, dso, identifier, false);
register(context, dso, identifier, this.filter);
}
/**
* Register a new DOI for a given DSpaceObject
* @param context - DSpace context
* @param dso - DSpaceObject identified by the new DOI
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration
* @param filter - Logical item filter to determine whether this identifier should be registered
* @throws IdentifierException
*/
@Override
public String register(Context context, DSpaceObject dso, boolean skipFilter)
public String register(Context context, DSpaceObject dso, Filter filter)
throws IdentifierException {
if (!(dso instanceof Item)) {
// DOI are currently assigned only to Item
return null;
}
String doi = mint(context, dso, skipFilter);
String doi = mint(context, dso, filter);
// register tries to reserve doi if it's not already.
// So we don't have to reserve it here.
register(context, dso, doi, skipFilter);
register(context, dso, doi, filter);
return doi;
}
@@ -250,11 +253,11 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
* @param context - DSpace context
* @param dso - DSpaceObject identified by the new DOI
* @param identifier - String containing the DOI to register
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration
* @param filter - Logical item filter to determine whether this identifier should be registered
* @throws IdentifierException
*/
@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 {
if (!(dso instanceof Item)) {
// DOI are currently assigned only to Item
@@ -265,7 +268,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
// search DOI in our db
try {
doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
doiRow = loadOrCreateDOI(context, dso, doi, filter);
} catch (SQLException ex) {
log.error("Error in databse connection: " + ex.getMessage());
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);
}
// Check status of DOI
if (IS_REGISTERED.equals(doiRow.getStatus())) {
return;
}
@@ -290,6 +292,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
log.warn("SQLException while changing status of DOI {} to be registered.", doi);
throw new RuntimeException(sqle);
}
}
/**
@@ -309,7 +312,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
@Override
public void reserve(Context context, DSpaceObject dso, String identifier)
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 dso - DSpaceObject identified by this DOI
* @param identifier - String containing the DOI to reserve
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing reservation
* @param filter - Logical item filter to determine whether this identifier should be reserved
* @throws IdentifierException
* @throws IllegalArgumentException
*/
@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 {
String doi = doiService.formatIdentifier(identifier);
DOI doiRow = null;
try {
// if the doi is in our db already loadOrCreateDOI just returns.
// if it is not loadOrCreateDOI safes the doi.
doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
doiRow = loadOrCreateDOI(context, dso, doi, filter);
} catch (SQLException sqle) {
throw new RuntimeException(sqle);
}
@@ -359,7 +360,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
*/
public void reserveOnline(Context context, DSpaceObject dso, String identifier)
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 dso - DSpaceObject identified by this DOI
* @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 IllegalArgumentException
* @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 {
String doi = doiService.formatIdentifier(identifier);
// 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())) {
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)
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 dso - DSpaceObject identified by this DOI
* @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 IllegalArgumentException
* @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 {
log.debug("registerOnline: skipFilter is " + skipFilter);
String doi = doiService.formatIdentifier(identifier);
// get TableRow and ensure DOI belongs to dso regarding our db
DOI doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
DOI doiRow = loadOrCreateDOI(context, dso, doi, filter);
if (DELETED.equals(doiRow.getStatus()) || TO_BE_DELETED.equals(doiRow.getStatus())) {
throw new DOIIdentifierException("You tried to register a DOI that "
@@ -435,7 +435,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
} catch (DOIIdentifierException die) {
// do we have to reserve DOI before we can register it?
if (die.getCode() == DOIIdentifierException.RESERVE_FIRST) {
this.reserveOnline(context, dso, identifier, skipFilter);
this.reserveOnline(context, dso, identifier, filter);
connector.registerDOI(context, dso, doi);
} else {
throw die;
@@ -471,17 +471,22 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
throws IdentifierException, IllegalArgumentException, SQLException {
String doi = doiService.formatIdentifier(identifier);
boolean skipFilter = false;
// Use the default filter unless we find the object
Filter updateFilter = this.filter;
if (doiService.findDOIByDSpaceObject(context, dso) != null) {
// We can skip the filter here since we know the DOI already exists for the item
log.debug("updateMetadata: found DOIByDSpaceObject: " +
doiService.findDOIByDSpaceObject(context, dso).getDoi());
skipFilter = true;
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())) {
throw new DOIIdentifierException("You tried to register a DOI that "
@@ -571,19 +576,19 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
@Override
public String mint(Context context, DSpaceObject dso)
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
* @param context - DSpace context
* @param dso - DSpaceObject identified by the new identifier
* @param skipFilter - boolean indicating whether to skip any filtering of items before minting.
* @param filter - Logical item filter to determine whether this identifier should be registered
* @return a String containing the new identifier
* @throws IdentifierException
*/
@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;
try {
@@ -597,7 +602,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
}
if (null == doi) {
try {
DOI doiRow = loadOrCreateDOI(context, dso, null, skipFilter);
DOI doiRow = loadOrCreateDOI(context, dso, null, filter);
doi = DOI.SCHEME + doiRow.getDoi();
} catch (SQLException e) {
@@ -895,7 +900,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
*/
protected DOI loadOrCreateDOI(Context context, DSpaceObject dso, String doiIdentifier)
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 dso - DSpaceObject to identify
* @param doiIdentifier - DOI to load or create (null to mint a new one)
* @param skipFilter - Whether or not to skip the filters for the checkMintable() check
* @param filter - Logical item filter to determine whether this identifier should be registered
* @return
* @throws SQLException
* @throws DOIIdentifierException
* @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 {
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?
// check if DOI already belongs to dso
if (dso.getID().equals(doi.getDSpaceObject().getID())) {
// Before we return this, check the filter
checkMintable(context, filter, dso);
return doi;
} else {
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
// filter is in place to prevent the creation of new DOIs for certain items.
if (skipFilter) {
log.warn("loadOrCreateDOI: Skipping default item filter");
} else {
// Find out if we're allowed to create a DOI
// throws an exception if creation of a new DOI is prohibited by a filter
checkMintable(context, dso);
}
// Check if this item is eligible for minting. An IdentifierNotApplicableException will be thrown if not.
checkMintable(context, filter, dso);
// check prefix
if (!doiIdentifier.startsWith(this.getPrefix() + "/")) {
@@ -984,15 +984,8 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
doi = doiService.create(context);
}
} else {
// We need to generate a new DOI. Before doing so, we should check if a
// filter is in place to prevent the creation of new DOIs for certain items.
if (skipFilter) {
log.warn("loadOrCreateDOI: Skipping default item filter");
} else {
// Find out if we're allowed to create a DOI
// throws an exception if creation of a new DOI is prohibited by a filter
checkMintable(context, dso);
}
// Check if this item is eligible for minting. An IdentifierNotApplicableException will be thrown if not.
checkMintable(context, filter, dso);
doi = doiService.create(context);
doiIdentifier = this.getPrefix() + "/" + this.getNamespaceSeparator() +
@@ -1002,7 +995,7 @@ public class DOIIdentifierProvider extends FilteredIdentifierProvider {
// prepare new doiRow
doi.setDoi(doiIdentifier);
doi.setDSpaceObject(dso);
doi.setStatus(null);
doi.setStatus(MINTED);
try {
doiService.update(context, doi);
} 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
* @param context
* @param filter Logical item filter to apply
* @param dso The item to be evaluated
* @throws DOIIdentifierNotApplicableException
*/
@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 (this.filterService != null && contentServiceFactory
.getDSpaceObjectService(dso).getTypeText(dso).equals("ITEM")) {
if (contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso).equals("ITEM")) {
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);
if (!result) {
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) {
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)");
}
}
/**
* 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.logic.Filter;
import org.dspace.content.logic.TrueFilter;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
/**
* 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 {
protected Filter filterService;
protected Filter filter = new TrueFilter();
/**
* Setter for spring to set the filter service from the property in configuration XML
* @param filterService - an object implementing the org.dspace.content.logic.Filter interface
* Setter for spring to set the default filter from the property in configuration XML
* @param filter - an object implementing the org.dspace.content.logic.Filter interface
*/
@Autowired
public void setFilterService(Filter filterService) {
this.filterService = filterService;
public void setFilter(Filter filter) {
this.filter = filter;
if (this.filter == null) {
this.filter = new TrueFilter();
}
}
/**
* Register a new identifier for a given DSpaceObject
* @param context - DSpace context
* @param dso - DSpaceObject to use for identifier registration
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration
* @param filter - Logical item filter to determine whether this identifier should be registered
* @return identifier
* @throws IdentifierException
*/
public abstract String register(Context context, DSpaceObject dso, boolean skipFilter)
public abstract String register(Context context, DSpaceObject dso, Filter filter)
throws IdentifierException;
/**
@@ -51,10 +53,10 @@ public abstract class FilteredIdentifierProvider extends IdentifierProvider {
* @param context - DSpace context
* @param dso - DSpaceObject identified by the new identifier
* @param identifier - String containing the identifier to register
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration
* @param filter - Logical item filter to determine whether this identifier should be registered
* @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;
/**
@@ -62,23 +64,23 @@ public abstract class FilteredIdentifierProvider extends IdentifierProvider {
* @param context - DSpace context
* @param dso - DSpaceObject identified by this identifier
* @param identifier - String containing the identifier to reserve
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing reservation
* @param filter - Logical item filter to determine whether this identifier should be reserved
* @throws IdentifierException
* @throws IllegalArgumentException
* @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;
/**
* Mint a new identifier in DSpace - this is usually the first step of registration
* @param context - DSpace context
* @param dso - DSpaceObject identified by the new identifier
* @param skipFilter - boolean indicating whether to skip any filtering of items before minting.
* @param filter - Logical item filter to determine whether this identifier should be registered
* @return a String containing the new identifier
* @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
@@ -88,5 +90,13 @@ public abstract class FilteredIdentifierProvider extends IdentifierProvider {
*/
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.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
@@ -17,6 +18,8 @@ import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject;
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.handle.service.HandleService;
import org.dspace.identifier.service.IdentifierService;
@@ -98,7 +101,7 @@ public class IdentifierServiceImpl implements IdentifierService {
@Override
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
// Next resolve all other services
for (IdentifierProvider service : providers) {
@@ -112,6 +115,98 @@ public class IdentifierServiceImpl implements IdentifierService {
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
public void register(Context context, DSpaceObject object, String identifier)
throws AuthorizeException, SQLException, IdentifierException {

View File

@@ -18,6 +18,7 @@ import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.MetadataValue;
import org.dspace.content.logic.Filter;
import org.dspace.core.Context;
import org.dspace.identifier.doi.DOIConnector;
import org.dspace.identifier.doi.DOIIdentifierException;
@@ -49,7 +50,12 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
protected VersionHistoryService versionHistoryService;
@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 {
if (!(dso instanceof Item)) {
throw new IdentifierException("Currently only Items are supported for DOIs.");
@@ -79,6 +85,9 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
+ " 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
String metadataDOI = getDOIOutOfObject(dso);
if (metadataDOI != null) {
@@ -111,7 +120,7 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
// ensure DOI exists in our database as well and return.
// this also checks that the doi is not assigned to another dso already.
try {
loadOrCreateDOI(context, dso, versionedDOI);
loadOrCreateDOI(context, dso, versionedDOI, filter);
} catch (SQLException ex) {
log.error(
"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
doi = makeIdentifierBasedOnHistory(context, dso, history);
} else {
doi = loadOrCreateDOI(context, dso, null).getDoi();
doi = loadOrCreateDOI(context, dso, null, filter).getDoi();
}
} catch (SQLException ex) {
log.error("SQLException while creating a new DOI: ", ex);
@@ -140,7 +149,12 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
}
@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 {
if (!(dso instanceof Item)) {
throw new IdentifierException("Currently only Items are supported for DOIs.");
@@ -220,8 +234,14 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
return doiPostfix;
}
// Should never return null!
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 {
// Mint foreach new version an identifier like: 12345/100.versionNumber
// use the bare handle (g.e. 12345/100) for the first version.
@@ -244,6 +264,9 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
}
if (previousVersionDOI == null) {
// Before continuing with any new DOI creation, apply the filter
checkMintable(context, filter, dso);
// We need to generate a new DOI.
DOI doi = doiService.create(context);
@@ -269,7 +292,7 @@ public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider {
String.valueOf(versionHistoryService.getVersion(context, history, item).getVersionNumber()));
}
loadOrCreateDOI(context, dso, identifier);
loadOrCreateDOI(context, dso, identifier, filter);
return identifier;
}

View File

@@ -7,23 +7,32 @@
*/
package org.dspace.identifier.doi;
import java.sql.SQLException;
import org.apache.logging.log4j.Logger;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.logic.Filter;
import org.dspace.content.logic.FilterUtils;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.event.Consumer;
import org.dspace.event.Event;
import org.dspace.identifier.DOI;
import org.dspace.identifier.DOIIdentifierProvider;
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.utils.DSpace;
import org.dspace.workflow.factory.WorkflowServiceFactory;
/**
* @author Pascal-Nicolas Becker (p dot becker at tu hyphen berlin dot de)
* @author Kim Shepherd
*/
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);
ConfigurationService configurationService;
@Override
public void initialize() throws Exception {
// nothing to do
// we can ask spring to give as a properly setuped instance of
// DOIIdentifierProvider. Doing so we don't have to configure it and
// 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;
}
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 (ContentServiceFactory.getInstance().getWorkspaceItemService().findByItem(ctx, item) != null
|| WorkflowServiceFactory.getInstance().getWorkflowItemService().findByItem(ctx, item) != null) {
// ignore workflow and workspace items, DOI will be minted when item is installed
if (inProgress && !identifiersInSubmission) {
// ignore workflow and workspace items, DOI will be minted and updated when item is installed
// UNLESS special pending filter is set
return;
}
*/
DOIIdentifierProvider provider = new DSpace().getSingletonService(
DOIIdentifierProvider.class);
String doi = null;
DOI doi = null;
try {
doi = provider.lookup(ctx, dso);
} catch (IdentifierNotFoundException ex) {
doi = doiService.findDOIByDSpaceObject(ctx, dso);
} catch (SQLException ex) {
// nothing to do here, next if clause will stop us from processing
// items without dois.
}
if (doi == null) {
// if the item is workflow or workspace, there is a special case here - the ShowIdentifersStep
// needs this consumer to reserve DOIs in the event that the item now meets criteria for a pre-mint
if (ContentServiceFactory.getInstance().getWorkspaceItemService().findByItem(ctx, item) != null
|| WorkflowServiceFactory.getInstance().getWorkflowItemService().findByItem(ctx, item) != null) {
if (DSpaceServicesFactory.getInstance().getConfigurationService()
.getBooleanProperty("identifiers.submission.register", false)) {
try {
String newDoi = provider.mint(ctx, item);
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());
// No DOI. The only time something should be minted is if we have enabled submission reg'n and
// it passes the workspace filter. We also need to update status to PENDING straight after.
if (inProgress) {
provider.mint(ctx, dso, workspaceFilter);
DOI newDoi = doiService.findDOIByDSpaceObject(ctx, dso);
if (newDoi != null) {
newDoi.setStatus(DOIIdentifierProvider.PENDING);
doiService.update(ctx, newDoi);
}
} else {
log.debug("DOIConsumer cannot handles items without DOIs, skipping: "
+ event.toString());
return;
log.debug("DOIConsumer cannot handles items without DOIs, skipping: " + event.toString());
}
} else if (ContentServiceFactory.getInstance().getWorkspaceItemService().findByItem(ctx, item) != null
|| WorkflowServiceFactory.getInstance().getWorkflowItemService().findByItem(ctx, item) != null) {
if (DSpaceServicesFactory.getInstance().getConfigurationService()
.getBooleanProperty("identifiers.submission.register", false)) {
// 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.
} else {
// If in progress, we can also switch PENDING and MINTED status depending on the latest filter
// evaluation
if (inProgress) {
try {
provider.checkMintable(ctx, item);
} catch (DOIIdentifierNotApplicableException e) {
log.debug("Consumer deleting DOI for in-progress item: " + doi);
provider.delete(ctx, item, doi);
return;
// Check the filter
provider.checkMintable(ctx, workspaceFilter, dso);
// If we made it here, the existing doi should be back to PENDING
if (DOIIdentifierProvider.MINTED.equals(doi.getStatus())) {
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 {
log.debug("Consumer skipping mint for item as it is in-progress and" +
"identifiers.submission.register=false: " + item.getID());
try {
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);
}
}
}
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);
ctx.commit();
}
}

View File

@@ -30,6 +30,9 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.content.DSpaceObject;
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.core.Constants;
import org.dspace.core.Context;
@@ -61,7 +64,8 @@ public class DOIOrganiser {
protected ItemService itemService;
protected DOIService doiService;
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
@@ -76,7 +80,7 @@ public class DOIOrganiser {
this.itemService = ContentServiceFactory.getInstance().getItemService();
this.doiService = IdentifierServiceFactory.getInstance().getDOIService();
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.");
options.addOption("d", "delete-all", false,
"Perform online deletion for all identifiers queued for deletion.");
options.addOption("q", "quiet", false,
"Turn the command line output off.");
options.addOption(null, "skip-filter", false,
"Skip the configured item filter when registering or reserving.");
Option filterDoi = Option.builder().optionalArg(true).longOpt("filter").hasArg().argName("filterName")
.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()
.longOpt("register-doi")
@@ -203,10 +208,12 @@ public class DOIOrganiser {
}
DOIService doiService = IdentifierServiceFactory.getInstance().getDOIService();
// Should we skip the filter?
if (line.hasOption("skip-filter")) {
System.out.println("Skipping the item filter");
organiser.skipFilter = true;
// Do we get a filter?
if (line.hasOption("filter")) {
String filter = line.getOptionValue("filter");
if (null != filter) {
organiser.filter = FilterUtils.getFilterFromConfiguration(filter);
}
}
if (line.hasOption('s')) {
@@ -394,19 +401,18 @@ public class DOIOrganiser {
/**
* Register DOI with the provider
* @param doiRow - doi to register
* @param skipFilter - whether filters should be skipped before registration
* @param filter - logical item filter to override
* @throws SQLException
* @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();
if (Constants.ITEM != dso.getType()) {
throw new IllegalArgumentException("Currenty DSpace supports DOIs for Items only.");
}
try {
provider.registerOnline(context, dso,
DOI.SCHEME + doiRow.getDoi());
provider.registerOnline(context, dso, DOI.SCHEME + doiRow.getDoi(), filter);
if (!quiet) {
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
* @throws SQLException
* @throws DOIIdentifierException
*/
public void register(DOI doiRow) throws SQLException, DOIIdentifierException {
if (this.skipFilter) {
System.out.println("Skipping the filter for " + doiRow.getDoi());
}
register(doiRow, this.skipFilter);
register(doiRow, this.filter);
}
/**
* Reserve DOI with the provider, always applying (ie. never skipping) any configured filters
* Reserve DOI with the provider,
* @param doiRow - doi to reserve
* @throws SQLException
* @throws DOIIdentifierException
*/
public void reserve(DOI doiRow) {
if (this.skipFilter) {
System.out.println("Skipping the filter for " + doiRow.getDoi());
}
reserve(doiRow, this.skipFilter);
reserve(doiRow, this.filter);
}
/**
@@ -497,14 +497,14 @@ public class DOIOrganiser {
* @throws SQLException
* @throws DOIIdentifierException
*/
public void reserve(DOI doiRow, boolean skipFilter) {
public void reserve(DOI doiRow, Filter filter) {
DSpaceObject dso = doiRow.getDSpaceObject();
if (Constants.ITEM != dso.getType()) {
throw new IllegalArgumentException("Currently DSpace supports DOIs for Items only.");
}
try {
provider.reserveOnline(context, dso, DOI.SCHEME + doiRow.getDoi(), skipFilter);
provider.reserveOnline(context, dso, DOI.SCHEME + doiRow.getDoi(), filter);
if (!quiet) {
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
if (null == doiRow) {
doi = provider.mint(context, dso, this.skipFilter);
doi = provider.mint(context, dso, this.filter);
doiRow = doiService.findByDoi(context,
doi.substring(DOI.SCHEME.length()));
return doiRow;
@@ -723,7 +723,7 @@ public class DOIOrganiser {
doiRow = doiService.findDOIByDSpaceObject(context, dso);
if (null == doiRow) {
doi = provider.mint(context, dso, this.skipFilter);
doi = provider.mint(context, dso, this.filter);
doiRow = doiService.findByDoi(context,
doi.substring(DOI.SCHEME.length()));
}

View File

@@ -9,9 +9,11 @@ package org.dspace.identifier.service;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject;
import org.dspace.content.logic.Filter;
import org.dspace.core.Context;
import org.dspace.identifier.Identifier;
import org.dspace.identifier.IdentifierException;
@@ -103,6 +105,40 @@ public interface IdentifierService {
*/
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).
* 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.logic.DefaultFilter;
import org.dspace.content.logic.LogicalStatement;
import org.dspace.content.logic.TrueFilter;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.content.service.ItemService;
@@ -128,7 +129,7 @@ public class DOIIdentifierProviderTest
provider.itemService = itemService;
provider.setConfigurationService(config);
provider.setDOIConnector(connector);
provider.setFilterService(null);
provider.setFilter(null);
} catch (AuthorizeException ex) {
log.error("Authorization Error in init", ex);
fail("Authorization Error in init: " + ex.getMessage());
@@ -504,7 +505,7 @@ public class DOIIdentifierProviderTest
String doi = null;
try {
// get a DOI (skipping any filters)
doi = provider.mint(context, item, true);
doi = provider.mint(context, item);
} catch (IdentifierException e) {
e.printStackTrace(System.err);
fail("Got an IdentifierException: " + e.getMessage());
@@ -544,23 +545,18 @@ public class DOIIdentifierProviderTest
Item item = newItem();
boolean wasFiltered = false;
try {
// Temporarily set the provider to have a filter that always returns false for an item
// (therefore, the item should be 'filtered' out and not apply to this minting request)
// Mint this with the filter
DefaultFilter doiFilter = new DefaultFilter();
LogicalStatement alwaysFalse = (context, i) -> false;
doiFilter.setStatement(alwaysFalse);
provider.setFilterService(doiFilter);
// get a DOI with the method that applies filters by default
provider.mint(context, item);
provider.mint(context, item, doiFilter);
} catch (DOIIdentifierNotApplicableException e) {
// This is what we wanted to see - we can return safely
wasFiltered = true;
} catch (IdentifierException e) {
e.printStackTrace();
fail("Got an IdentifierException: " + e.getMessage());
} finally {
// Set filter service back to null
provider.setFilterService(null);
}
// Fail the test if the filter didn't throw a "not applicable" exception
assertTrue("DOI minting attempt was not filtered by filter service", wasFiltered);
@@ -583,17 +579,14 @@ public class DOIIdentifierProviderTest
DefaultFilter doiFilter = new DefaultFilter();
LogicalStatement alwaysTrue = (context, i) -> true;
doiFilter.setStatement(alwaysTrue);
provider.setFilterService(doiFilter);
// get a DOI with the method that applies filters by default
doi = provider.mint(context, item);
doi = provider.mint(context, item, doiFilter);
} catch (DOIIdentifierNotApplicableException e) {
// This is what we wanted to see - we can return safely
wasFiltered = true;
} catch (IdentifierException e) {
e.printStackTrace();
fail("Got an IdentifierException: " + e.getMessage());
} finally {
provider.setFilterService(null);
}
// If the attempt was filtered, fail
assertFalse("DOI minting attempt was incorrectly filtered by filter service", wasFiltered);
@@ -665,7 +658,7 @@ public class DOIIdentifierProviderTest
Item item = newItem();
// 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:
// 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,
method = "getBundles"
),
//@LinkRest(
// name = ItemRest.IDENTIFIERS,
// method = "getIdentifiers"
//),
@LinkRest(
name = ItemRest.MAPPED_COLLECTIONS,
method = "getMappedCollections"
@@ -57,6 +61,7 @@ public class ItemRest extends DSpaceObjectRest {
public static final String ACCESS_STATUS = "accessStatus";
public static final String BUNDLES = "bundles";
public static final String IDENTIFIERS = "identifiers";
public static final String MAPPED_COLLECTIONS = "mappedCollections";
public static final String OWNING_COLLECTION = "owningCollection";
public static final String RELATIONSHIPS = "relationships";

View File

@@ -20,6 +20,10 @@ public class DataIdentifiers implements SectionData {
String doi;
List<String> otherIdentifiers;
public DataIdentifiers() {
}
public String getHandle() {
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.WorkspaceItemService;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
@@ -92,6 +96,9 @@ public class ItemRestRepository extends DSpaceObjectRestRepository<Item, ItemRes
@Autowired
RelationshipTypeService relationshipTypeService;
@Autowired
IdentifierService identifierService;
@Autowired
private UriListHandlerService uriListHandlerService;
@@ -357,6 +364,44 @@ public class ItemRestRepository extends DSpaceObjectRestRepository<Item, ItemRes
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
protected ItemRest createAndReturn(Context context, List<String> stringList)
throws AuthorizeException, SQLException, RepositoryMethodNotImplementedException {

View File

@@ -7,6 +7,7 @@
*/
package org.dspace.app.rest.submit.step;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
@@ -26,6 +27,7 @@ import org.dspace.core.Context;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService;
import org.dspace.identifier.DOI;
import org.dspace.identifier.DOIIdentifierProvider;
import org.dspace.identifier.Handle;
import org.dspace.identifier.IdentifierException;
import org.dspace.identifier.factory.IdentifierServiceFactory;
@@ -90,20 +92,31 @@ public class ShowIdentifiersStep extends AbstractProcessingStep {
IdentifierServiceFactory.getInstance().getIdentifierService();
// Attempt to look up handle and DOI identifiers for this item
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
List<String> otherIdentifiers = new ArrayList<>();
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);
}
}
// If we got a DOI, format it to its external form
if (StringUtils.isNotEmpty(doi)) {
if (StringUtils.isNotEmpty(doiString)) {
try {
doi = IdentifierServiceFactory.getInstance().getDOIService().DOIToExternalForm(doi);
doiString = IdentifierServiceFactory.getInstance().getDOIService().DOIToExternalForm(doiString);
} catch (IdentifierException e) {
log.error("Error formatting DOI: " + doi);
}
@@ -114,7 +127,7 @@ public class ShowIdentifiersStep extends AbstractProcessingStep {
}
// Populate bean with data and return
result.setDoi(doi);
result.setDoi(doiString);
result.setHandle(handle);
result.setOtherIdentifiers(otherIdentifiers);

View File

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

View File

@@ -5,7 +5,35 @@
# 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
# in the DOI Consumer? Setting this property to 'true' is recommended
# Should DOIs be minted for (future) registration at workspace item creation?
# 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
#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"/>
<!-- 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
handle for every new version.
-->
@@ -42,7 +42,7 @@
a DOIConnector that handles all API calls to your DOI registration
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
the DOIIdentifierProvider or the VersionedDOIIdentifierProvider,
depending on whether you have Item Level Versioning activated or not.
@@ -55,6 +55,7 @@
ref="org.dspace.services.ConfigurationService" />
<property name="DOIConnector"
ref="org.dspace.identifier.doi.DOIConnector" />
<property name="filter" ref="doi-filter" />
</bean>
-->
<!--
@@ -78,11 +79,11 @@
ref="org.dspace.services.ConfigurationService" />
<property name="DOIConnector"
ref="org.dspace.identifier.doi.DOIConnector" />
<property name="filterService" ref="openaire_filter" />
<property name="filter" ref="doi-filter" />
</bean>
-->
<!-- The DOIConnector will handle the API calls to your DOI registration
agency for the DOIIdentifierProvider. If your registration agency
tells you to use the DataCite API directly, you can use the
@@ -105,9 +106,9 @@
<!-- 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.
When generateDataciteXML is enabled, EZIDIdentifierProvider uses
When generateDataciteXML is enabled, EZIDIdentifierProvider uses
dspace.cfg:crosswalk.dissemination.DataCite.stylesheet XSL configuration for metadata mapping
-->
<!-- Uncomment to enable DOI using EZID

View File

@@ -20,7 +20,7 @@
<!-- default-autowire-candidates="*Service,*DAO,javax.sql.DataSource"> -->
<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 condition beans below for use as sub-statements in operator and filter beans
@@ -168,6 +168,17 @@
</property>
</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
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
@@ -195,11 +206,15 @@
<bean class="org.dspace.content.logic.operator.And">
<property name="statements">
<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 -->
<bean class="org.dspace.content.logic.operator.Not">
<property name="statements">
<ref bean="dc-identifier-uri-contains-doi_condition"/>
</property>
<property name="statements" ref="dc-identifier-uri-contains-doi_condition"/>
</bean>
<!-- Create DOIs for items only that do have at least one bitstream. -->
<ref bean="has-at-least-one-bitstream_condition"/>
@@ -226,16 +241,12 @@
<!-- A very simple demonstration filter, using the metadata match condition -->
<bean id="simple-demo_filter" class="org.dspace.content.logic.DefaultFilter">
<property name="statement">
<ref bean="title-contains-demo_condition"/>
</property>
<property name="statement" ref="title-contains-demo_condition"/>
</bean>
<!-- A very simple filter for items with at least one bitstream -->
<bean id="has-bitstream_filter" class="org.dspace.content.logic.DefaultFilter">
<property name="statement">
<ref bean="has-at-least-one-bitstream_condition"/>
</property>
<property name="statement" ref="has-at-least-one-bitstream_condition"/>
</bean>
<!--
@@ -335,5 +346,27 @@
</property>
</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>