[DS-4522](main) Item logical filters and DOI filtered provider

This commit is contained in:
Kim Shepherd
2020-03-11 12:56:42 +13:00
parent 2b4f22be65
commit d27dc96cbe
25 changed files with 1907 additions and 196 deletions

View File

@@ -19,11 +19,14 @@ import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.logic.Filter;
import org.dspace.content.logic.LogicalStatementException;
import org.dspace.content.service.ItemService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.identifier.doi.DOIConnector;
import org.dspace.identifier.doi.DOIIdentifierException;
import org.dspace.identifier.doi.DOIIdentifierNotApplicableException;
import org.dspace.identifier.service.DOIService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -42,8 +45,7 @@ import org.springframework.beans.factory.annotation.Autowired;
*
* @author Pascal-Nicolas Becker
*/
public class DOIIdentifierProvider
extends IdentifierProvider {
public class DOIIdentifierProvider extends FilteredIdentifierProvider {
private static final Logger log = LoggerFactory.getLogger(DOIIdentifierProvider.class);
/**
@@ -87,6 +89,11 @@ public class DOIIdentifierProvider
@Autowired(required = true)
protected ItemService itemService;
protected Filter filterService;
/**
* Empty / default constructor for Spring
*/
protected DOIIdentifierProvider() {
}
@@ -103,6 +110,10 @@ public class DOIIdentifierProvider
*/
private String NAMESPACE_SEPARATOR;
/**
* Get DOI prefix from configuration
* @return a String containing the DOI prefix
*/
protected String getPrefix() {
if (null == this.PREFIX) {
this.PREFIX = this.configurationService.getProperty(CFG_PREFIX);
@@ -116,6 +127,10 @@ public class DOIIdentifierProvider
return this.PREFIX;
}
/**
* Get namespace separator from configuration
* @return a String containing the namespace separator
*/
protected String getNamespaceSeparator() {
if (null == this.NAMESPACE_SEPARATOR) {
this.NAMESPACE_SEPARATOR = this.configurationService.getProperty(CFG_NAMESPACE_SEPARATOR);
@@ -126,11 +141,27 @@ public class DOIIdentifierProvider
return this.NAMESPACE_SEPARATOR;
}
/**
* Set the DOI connector, which is the component that commuincates with the remote registration service
* (eg. DataCite, EZID, Crossref)
* Spring will use this setter to set the DOI connector from the configured property in identifier-services.xml
*
* @param connector a DOIConnector
*/
@Autowired(required = true)
public void setDOIConnector(DOIConnector connector) {
this.connector = connector;
}
/**
* Set the Filter to use when testing items to see if a DOI should be registered
* Spring will use this setter to set the filter from the configured property in identifier-services.xml
* @param filterService - an object implementing the org.dspace.content.logic.Filter interface
*/
public void setFilterService(Filter filterService) {
this.filterService = filterService;
}
/**
* This identifier provider supports identifiers of type
* {@link org.dspace.identifier.DOI}.
@@ -164,23 +195,65 @@ public class DOIIdentifierProvider
return true;
}
/**
* Register a new identifier for a given DSpaceObject, never skipping or ignoring any configured filter
* @param context - DSpace context
* @param dso - DSpaceObject to use for identifier registration
* @return identifier
* @throws IdentifierException
*/
@Override
public String register(Context context, DSpaceObject dso)
throws IdentifierException {
return register(context, dso, false);
}
/**
* Register a specified DOI for a given DSpaceObject, never skipping or ignoring any configured filter
* @param context - DSpace context
* @param dso - DSpaceObject identified by the new DOI
* @param identifier - String containing the identifier to register
* @throws IdentifierException
*/
@Override
public void register(Context context, DSpaceObject dso, String identifier)
throws IdentifierException {
register(context, dso, identifier, false);
}
/**
* Register a new DOI for a given DSpaceObject
* @param context - DSpace context
* @param dso - DSpaceObject identified by the new DOI
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration
* @throws IdentifierException
*/
@Override
public String register(Context context, DSpaceObject dso, Boolean skipFilter)
throws IdentifierException {
if (!(dso instanceof Item)) {
// DOI are currently assigned only to Item
return null;
}
String doi = mint(context, dso);
String doi = mint(context, dso, skipFilter);
// register tries to reserve doi if it's not already.
// So we don't have to reserve it here.
register(context, dso, doi);
register(context, dso, doi, skipFilter);
return doi;
}
/**
* Register a specified DOI for a given DSpaceObject
* @param context - DSpace context
* @param dso - DSpaceObject identified by the new DOI
* @param identifier - String containing the DOI to register
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing registration
* @throws IdentifierException
*/
@Override
public void register(Context context, DSpaceObject dso, String identifier)
public void register(Context context, DSpaceObject dso, String identifier, Boolean skipFilter)
throws IdentifierException {
if (!(dso instanceof Item)) {
// DOI are currently assigned only to Item
@@ -191,7 +264,7 @@ public class DOIIdentifierProvider
// search DOI in our db
try {
doiRow = loadOrCreateDOI(context, dso, doi);
doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
} catch (SQLException ex) {
log.error("Error in databse connection: " + ex.getMessage());
throw new RuntimeException("Error in database conncetion.", ex);
@@ -200,7 +273,7 @@ public class DOIIdentifierProvider
if (DELETED.equals(doiRow.getStatus()) ||
TO_BE_DELETED.equals(doiRow.getStatus())) {
throw new DOIIdentifierException("You tried to register a DOI that "
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
}
// Check status of DOI
@@ -234,6 +307,22 @@ public class DOIIdentifierProvider
*/
@Override
public void reserve(Context context, DSpaceObject dso, String identifier)
throws IdentifierException, IllegalArgumentException {
reserve(context, dso, identifier, false);
}
/**
* Reserve a specified DOI for a given DSpaceObject
* @param context - DSpace context
* @param dso - DSpaceObject identified by this DOI
* @param identifier - String containing the DOI to reserve
* @param skipFilter - boolean indicating whether to skip any filtering of items before performing reservation
* @throws IdentifierException
* @throws IllegalArgumentException
* @throws SQLException
*/
@Override
public void reserve(Context context, DSpaceObject dso, String identifier, Boolean skipFilter)
throws IdentifierException, IllegalArgumentException {
String doi = doiService.formatIdentifier(identifier);
DOI doiRow = null;
@@ -241,7 +330,7 @@ public class DOIIdentifierProvider
try {
// if the doi is in our db already loadOrCreateDOI just returns.
// if it is not loadOrCreateDOI safes the doi.
doiRow = loadOrCreateDOI(context, dso, doi);
doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
} catch (SQLException sqle) {
throw new RuntimeException(sqle);
}
@@ -258,16 +347,39 @@ public class DOIIdentifierProvider
}
}
/**
* Perform the actual online / API interaction required to reserve the DOI online
* always applying filters if they are configured
* @param context - DSpace context
* @param dso - DSpaceObject identified by this DOI
* @param identifier - String containing the DOI to reserve
* @throws IdentifierException
* @throws IllegalArgumentException
* @throws SQLException
*/
public void reserveOnline(Context context, DSpaceObject dso, String identifier)
throws IdentifierException, IllegalArgumentException, SQLException {
reserveOnline(context, dso, identifier, false);
}
/**
* Perform the actual online / API interaction required to reserve the DOI online
* @param context - DSpace context
* @param dso - DSpaceObject identified by this DOI
* @param identifier - String containing the DOI to reserve
* @throws IdentifierException
* @throws IllegalArgumentException
* @throws SQLException
*/
public void reserveOnline(Context context, DSpaceObject dso, String identifier, Boolean skipFilter)
throws IdentifierException, IllegalArgumentException, SQLException {
String doi = doiService.formatIdentifier(identifier);
// get TableRow and ensure DOI belongs to dso regarding our db
DOI doiRow = loadOrCreateDOI(context, dso, doi);
DOI doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
if (DELETED.equals(doiRow.getStatus()) ||
TO_BE_DELETED.equals(doiRow.getStatus())) {
if (DELETED.equals(doiRow.getStatus()) || TO_BE_DELETED.equals(doiRow.getStatus())) {
throw new DOIIdentifierException("You tried to reserve a DOI that "
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
}
connector.reserveDOI(context, dso, doi);
@@ -276,16 +388,43 @@ public class DOIIdentifierProvider
doiService.update(context, doiRow);
}
/**
* Perform the actual online / API interaction required to register the DOI online
* always applying filters if they are configured
* @param context - DSpace context
* @param dso - DSpaceObject identified by this DOI
* @param identifier - String containing the DOI to register
* @throws IdentifierException
* @throws IllegalArgumentException
* @throws SQLException
*/
public void registerOnline(Context context, DSpaceObject dso, String identifier)
throws IdentifierException, IllegalArgumentException, SQLException {
registerOnline(context, dso, identifier, false);
}
/**
* Perform the actual online / API interaction required to register the DOI online
* @param context - DSpace context
* @param dso - DSpaceObject identified by this DOI
* @param identifier - String containing the DOI to register
* @throws IdentifierException
* @throws IllegalArgumentException
* @throws SQLException
*/
public void registerOnline(Context context, DSpaceObject dso, String identifier, Boolean skipFilter)
throws IdentifierException, IllegalArgumentException, SQLException {
log.debug("registerOnline: skipFilter is " + skipFilter.toString());
String doi = doiService.formatIdentifier(identifier);
// get TableRow and ensure DOI belongs to dso regarding our db
DOI doiRow = loadOrCreateDOI(context, dso, doi);
DOI doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
if (DELETED.equals(doiRow.getStatus()) ||
TO_BE_DELETED.equals(doiRow.getStatus())) {
if (DELETED.equals(doiRow.getStatus()) || TO_BE_DELETED.equals(doiRow.getStatus())) {
throw new DOIIdentifierException("You tried to register a DOI that "
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
}
// register DOI Online
@@ -294,7 +433,7 @@ public class DOIIdentifierProvider
} catch (DOIIdentifierException die) {
// do we have to reserve DOI before we can register it?
if (die.getCode() == DOIIdentifierException.RESERVE_FIRST) {
this.reserveOnline(context, dso, identifier);
this.reserveOnline(context, dso, identifier, skipFilter);
connector.registerDOI(context, dso, doi);
} else {
throw die;
@@ -314,15 +453,37 @@ public class DOIIdentifierProvider
doiService.update(context, doiRow);
}
/**
* Update metadata for a registered object
* If the DOI for hte item already exists, *always* skip the filter since it should only be used for
* allowing / disallowing reservation and registration, not metadata updates or deletions
*
* @param context - DSpace context
* @param dso - DSpaceObject identified by this DOI
* @param identifier - String containing the DOI to reserve
* @throws IdentifierException
* @throws IllegalArgumentException
* @throws SQLException
*/
public void updateMetadata(Context context, DSpaceObject dso, String identifier)
throws IdentifierException, IllegalArgumentException, SQLException {
String doi = doiService.formatIdentifier(identifier);
DOI doiRow = loadOrCreateDOI(context, dso, doi);
throws IdentifierException, IllegalArgumentException, SQLException {
if (DELETED.equals(doiRow.getStatus()) ||
TO_BE_DELETED.equals(doiRow.getStatus())) {
String doi = doiService.formatIdentifier(identifier);
Boolean skipFilter = false;
if (doiService.findDOIByDSpaceObject(context, dso) != null) {
// We can skip the filter here since we know the DOI already exists for the item
log.debug("updateMetadata: found DOIByDSpaceObject: " +
doiService.findDOIByDSpaceObject(context, dso).getDoi());
skipFilter = true;
}
DOI doiRow = loadOrCreateDOI(context, dso, doi, skipFilter);
if (DELETED.equals(doiRow.getStatus()) || TO_BE_DELETED.equals(doiRow.getStatus())) {
throw new DOIIdentifierException("You tried to register a DOI that "
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
}
if (IS_REGISTERED.equals(doiRow.getStatus())) {
@@ -338,8 +499,20 @@ public class DOIIdentifierProvider
doiService.update(context, doiRow);
}
/**
* Update metadata for a registered object in the DOI Connector to update the agency records
* If the DOI for hte item already exists, *always* skip the filter since it should only be used for
* allowing / disallowing reservation and registration, not metadata updates or deletions
*
* @param context - DSpace context
* @param dso - DSpaceObject identified by this DOI
* @param identifier - String containing the DOI to reserve
* @throws IdentifierException
* @throws IllegalArgumentException
* @throws SQLException
*/
public void updateMetadataOnline(Context context, DSpaceObject dso, String identifier)
throws IdentifierException, SQLException {
throws IdentifierException, SQLException {
String doi = doiService.formatIdentifier(identifier);
// ensure DOI belongs to dso regarding our db
@@ -348,31 +521,28 @@ public class DOIIdentifierProvider
doiRow = doiService.findByDoi(context, doi.substring(DOI.SCHEME.length()));
} catch (SQLException sqle) {
log.warn("SQLException while searching a DOI in our db.", sqle);
throw new RuntimeException("Unable to retrieve information about " +
"a DOI out of database.", sqle);
throw new RuntimeException("Unable to retrieve information about a DOI out of database.", sqle);
}
if (null == doiRow) {
log.error("Cannot update metadata for DOI {}: unable to find it in "
+ "our db.", doi);
log.error("Cannot update metadata for DOI {}: unable to find it in our db.", doi);
throw new DOIIdentifierException("Unable to find DOI.",
DOIIdentifierException.DOI_DOES_NOT_EXIST);
DOIIdentifierException.DOI_DOES_NOT_EXIST);
}
if (!Objects.equals(doiRow.getDSpaceObject(), dso)) {
log.error("Refuse to update metadata of DOI {} with the metadata of "
+ " an object ({}/{}) the DOI is not dedicated to.",
+ " an object ({}/{}) the DOI is not dedicated to.",
doi,
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso),
dso.getID().toString());
throw new DOIIdentifierException("Cannot update DOI metadata: "
+ "DOI and DSpaceObject does not match!",
DOIIdentifierException.MISMATCH);
+ "DOI and DSpaceObject does not match!",
DOIIdentifierException.MISMATCH);
}
if (DELETED.equals(doiRow.getStatus()) ||
TO_BE_DELETED.equals(doiRow.getStatus())) {
if (DELETED.equals(doiRow.getStatus()) || TO_BE_DELETED.equals(doiRow.getStatus())) {
throw new DOIIdentifierException("You tried to update the metadata"
+ "of a DOI that is marked as DELETED.",
DOIIdentifierException.DOI_IS_DELETED);
+ "of a DOI that is marked as DELETED.",
DOIIdentifierException.DOI_IS_DELETED);
}
connector.updateMetadata(context, dso, doi);
@@ -388,41 +558,69 @@ public class DOIIdentifierProvider
doiService.update(context, doiRow);
}
/**
* Mint a new DOI in DSpace - this is usually the first step of registration
* Always apply filters if they are configured
* @param context - DSpace context
* @param dso - DSpaceObject identified by the new identifier
* @return a String containing the new identifier
* @throws IdentifierException
*/
@Override
public String mint(Context context, DSpaceObject dso)
throws IdentifierException {
throws IdentifierException {
return mint(context, dso, false);
}
/**
* Mint a new DOI in DSpace - this is usually the first step of registration
* @param context - DSpace context
* @param dso - DSpaceObject identified by the new identifier
* @param skipFilter - boolean indicating whether to skip any filtering of items before minting
* @return a String containing the new identifier
* @throws IdentifierException
*/
@Override
public String mint(Context context, DSpaceObject dso, Boolean skipFilter) throws IdentifierException {
String doi = null;
try {
doi = getDOIByObject(context, dso);
} catch (SQLException e) {
log.error("Error while attemping to retrieve information about a DOI for "
+ contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso
.getID() + ".");
+ contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso.getID() + ".");
throw new RuntimeException("Error while attempting to retrieve " +
"information about a DOI for " + contentServiceFactory
.getDSpaceObjectService(dso).getTypeText(dso) +
" with ID " + dso.getID() + ".", e);
"information about a DOI for " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
" with ID " + dso.getID() + ".", e);
}
if (null == doi) {
try {
DOI doiRow = loadOrCreateDOI(context, dso, null);
DOI doiRow = loadOrCreateDOI(context, dso, null, skipFilter);
doi = DOI.SCHEME + doiRow.getDoi();
} catch (SQLException e) {
log.error("Error while creating new DOI for Object of " +
"ResourceType {} with id {}.", dso.getType(), dso.getID());
"ResourceType {} with id {}.", dso.getType(), dso.getID());
throw new RuntimeException("Error while attempting to create a " +
"new DOI for " + contentServiceFactory.getDSpaceObjectService(dso)
.getTypeText(dso) + " with ID " +
dso.getID() + ".", e);
"new DOI for " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " +
dso.getID() + ".", e);
}
}
return doi;
}
/**
* Resolve an identifier to a DSpaceObject, if it is registered
* @param context - DSpace context
* @param identifier - to be resolved.
* @param attributes - additional information for resolving {@code identifier}.
* @return a DSpaceObject identified by the identifier string
* @throws IdentifierNotFoundException
* @throws IdentifierNotResolvableException
*/
@Override
public DSpaceObject resolve(Context context, String identifier, String... attributes)
throws IdentifierNotFoundException, IdentifierNotResolvableException {
throws IdentifierNotFoundException, IdentifierNotResolvableException {
String doi = null;
try {
doi = doiService.formatIdentifier(identifier);
@@ -437,16 +635,23 @@ public class DOIIdentifierProvider
return dso;
} catch (SQLException sqle) {
log.error("SQLException while searching a DOI in our db.", sqle);
throw new RuntimeException("Unable to retrieve information about " +
"a DOI out of database.", sqle);
throw new RuntimeException("Unable to retrieve information about a DOI out of database.", sqle);
} catch (IdentifierException e) {
throw new IdentifierNotResolvableException(e);
}
}
/**
* Look up a DOI identifier for a given DSpaceObject
* @param context - DSpace context
* @param dso - DSpaceObject to look up
* @return a String containing the DOI
* @throws IdentifierNotFoundException
* @throws IdentifierNotResolvableException
*/
@Override
public String lookup(Context context, DSpaceObject dso)
throws IdentifierNotFoundException, IdentifierNotResolvableException {
throws IdentifierNotFoundException, IdentifierNotResolvableException {
String doi = null;
try {
doi = getDOIByObject(context, dso);
@@ -455,18 +660,23 @@ public class DOIIdentifierProvider
}
if (null == doi) {
throw new IdentifierNotFoundException("No DOI for DSpaceObject of type "
+ contentServiceFactory.getDSpaceObjectService(dso)
.getTypeText(dso) + " with ID " + dso
.getID() + " found.");
throw new IdentifierNotFoundException("No DOI for DSpaceObject of type " +
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
" with ID " + dso.getID() + " found.");
}
return doi;
}
/**
* Delete all DOIs for a DSpaceObject
* @param context - DSpace context
* @param dso - DSpaceObject to have all its DOIs deleted
* @throws IdentifierException
*/
@Override
public void delete(Context context, DSpaceObject dso)
throws IdentifierException {
throws IdentifierException {
// delete all DOIs for this Item from our database.
try {
String doi = getDOIByObject(context, dso);
@@ -475,13 +685,12 @@ public class DOIIdentifierProvider
doi = getDOIByObject(context, dso);
}
} catch (SQLException ex) {
log.error("Error while attemping to retrieve information about a DOI for "
+ contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso
.getID() + ".", ex);
log.error("Error while attemping to retrieve information about a DOI for " +
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
" with ID " + dso.getID() + ".", ex);
throw new RuntimeException("Error while attempting to retrieve " +
"information about a DOI for " + contentServiceFactory
.getDSpaceObjectService(dso).getTypeText(dso) +
" with ID " + dso.getID() + ".", ex);
"information about a DOI for " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
" with ID " + dso.getID() + ".", ex);
}
// delete all DOIs of this item out of its metadata
@@ -493,28 +702,33 @@ public class DOIIdentifierProvider
doi = getDOIOutOfObject(dso);
}
} catch (AuthorizeException ex) {
log.error("Error while removing a DOI out of the metadata of an "
+ contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso
.getID() + ".", ex);
throw new RuntimeException("Error while removing a DOI out of the "
+ "metadata of an " + contentServiceFactory.getDSpaceObjectService(dso)
.getTypeText(dso) + " with ID "
+ dso.getID() + ".", ex);
log.error("Error while removing a DOI out of the metadata of an " +
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
" with ID " + dso.getID() + ".", ex);
throw new RuntimeException("Error while removing a DOI out of the metadata of an " +
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
" with ID " + dso.getID() + ".", ex);
} catch (SQLException ex) {
log.error("Error while removing a DOI out of the metadata of an "
+ contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + " with ID " + dso
.getID() + ".", ex);
throw new RuntimeException("Error while removing a DOI out of the "
+ "metadata of an " + contentServiceFactory.getDSpaceObjectService(dso)
.getTypeText(dso) + " with ID "
+ dso.getID() + ".", ex);
log.error("Error while removing a DOI out of the metadata of an " +
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
" with ID " + dso.getID() + ".", ex);
throw new RuntimeException("Error while removing a DOI out of the " +
"metadata of an " + contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) +
" with ID " + dso.getID() + ".", ex);
}
}
/**
* Delete a specific DOI for a given DSpaceObject
* @param context - DSpace context
* @param dso - DSpaceObject to be de-identified.
* @param identifier - String containing identifier to delete
* @throws IdentifierException
*/
@Override
public void delete(Context context, DSpaceObject dso, String identifier)
throws IdentifierException {
throws IdentifierException {
String doi = doiService.formatIdentifier(identifier);
DOI doiRow = null;
@@ -528,8 +742,8 @@ public class DOIIdentifierProvider
if (null != doiRow) {
if (!Objects.equals(dso, doiRow.getDSpaceObject())) {
throw new DOIIdentifierException("Trying to delete a DOI out of "
+ "an object that is not addressed by the DOI.",
DOIIdentifierException.MISMATCH);
+ "an object that is not addressed by the DOI.",
DOIIdentifierException.MISMATCH);
}
}
@@ -539,12 +753,12 @@ public class DOIIdentifierProvider
} catch (AuthorizeException ex) {
log.error("Not authorized to delete a DOI out of an Item.", ex);
throw new DOIIdentifierException("Not authorized to delete DOI.",
ex, DOIIdentifierException.UNAUTHORIZED_METADATA_MANIPULATION);
ex, DOIIdentifierException.UNAUTHORIZED_METADATA_MANIPULATION);
} catch (SQLException ex) {
log.error("SQLException occurred while deleting a DOI out of an item: "
+ ex.getMessage());
+ ex.getMessage());
throw new RuntimeException("Error while deleting a DOI out of the " +
"metadata of an Item " + dso.getID(), ex);
"metadata of an Item " + dso.getID(), ex);
}
// change doi status in db if necessary.
@@ -567,8 +781,13 @@ public class DOIIdentifierProvider
// DOIS. But it is possible to mark a DOI as "inactive".
}
public void deleteOnline(Context context, String identifier)
throws DOIIdentifierException {
/**
* Delete a specific DOI in the registration agency records via the DOI Connector
* @param context - DSpace context
* @param identifier - String containing identifier to delete
* @throws IdentifierException
*/
public void deleteOnline(Context context, String identifier) throws DOIIdentifierException {
String doi = doiService.formatIdentifier(identifier);
DOI doiRow = null;
@@ -579,16 +798,15 @@ public class DOIIdentifierProvider
}
if (null == doiRow) {
throw new DOIIdentifierException("This identifier: " + identifier
+ " isn't in our database",
DOIIdentifierException.DOI_DOES_NOT_EXIST);
+ " isn't in our database",
DOIIdentifierException.DOI_DOES_NOT_EXIST);
}
if (!TO_BE_DELETED.equals(doiRow.getStatus())) {
log.error("This identifier: {} couldn't be deleted. "
+ "Delete it first from metadata.",
DOI.SCHEME + doiRow.getDoi());
log.error("This identifier: {} couldn't be deleted. Delete it first from metadata.",
DOI.SCHEME + doiRow.getDoi());
throw new IllegalArgumentException("Couldn't delete this identifier:"
+ DOI.SCHEME + doiRow.getDoi()
+ ". Delete it first from metadata.");
+ DOI.SCHEME + doiRow.getDoi()
+ ". Delete it first from metadata.");
}
connector.deleteDOI(context, doi);
@@ -603,17 +821,16 @@ public class DOIIdentifierProvider
/**
* Returns a DSpaceObject depending on its DOI.
*
* @param context The relevant DSpace Context.
* @param context the context
* @param identifier The DOI in a format that is accepted by
* {@link org.dspace.identifier.service.DOIService#formatIdentifier(String)}.
* @return Null if the DOI couldn't be found or the associated DSpaceObject.
* @throws SQLException if database error
* @throws DOIIdentifierException If {@code identifier} is null or an empty string.
* @throws SQLException if database error
* @throws IdentifierException If {@code identifier} is null or an empty string.
* @throws IllegalArgumentException If the identifier couldn't be recognized as DOI.
*/
public DSpaceObject getObjectByDOI(Context context, String identifier)
throws SQLException, DOIIdentifierException, IllegalArgumentException {
throws SQLException, DOIIdentifierException, IllegalArgumentException {
String doi = doiService.formatIdentifier(identifier);
DOI doiRow = doiService.findByDoi(context, doi.substring(DOI.SCHEME.length()));
@@ -622,10 +839,9 @@ public class DOIIdentifierProvider
}
if (doiRow.getDSpaceObject() == null) {
log.error("Found DOI " + doi +
" in database, but no assigned Object could be found.");
log.error("Found DOI " + doi + " in database, but no assigned Object could be found.");
throw new IllegalStateException("Found DOI " + doi +
" in database, but no assigned Object could be found.");
" in database, but no assigned Object could be found.");
}
return doiRow.getDSpaceObject();
@@ -640,8 +856,7 @@ public class DOIIdentifierProvider
* @return The DOI as String or null if DOI was not found.
* @throws SQLException if database error
*/
public String getDOIByObject(Context context, DSpaceObject dso)
throws SQLException {
public String getDOIByObject(Context context, DSpaceObject dso) throws SQLException {
// String sql = "SELECT * FROM Doi WHERE resource_type_id = ? " +
// "AND resource_id = ? AND ((status != ? AND status != ?) OR status IS NULL)";
@@ -651,13 +866,10 @@ public class DOIIdentifierProvider
}
if (doiRow.getDoi() == null) {
log.error("A DOI with an empty doi column was found in the database. DSO-Type: "
+ contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ", ID: " + dso
.getID() + ".");
throw new IllegalStateException("A DOI with an empty doi column " +
"was found in the database. DSO-Type: " + contentServiceFactory
.getDSpaceObjectService(dso).getTypeText(dso) +
", ID: " + dso.getID() + ".");
log.error("A DOI with an empty doi column was found in the database. DSO-Type: " +
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ", ID: " + dso.getID() + ".");
throw new IllegalStateException("A DOI with an empty doi column was found in the database. DSO-Type: " +
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ", ID: " + dso.getID() + ".");
}
return DOI.SCHEME + doiRow.getDoi();
@@ -679,8 +891,31 @@ public class DOIIdentifierProvider
* DOI is registered for another object already.
*/
protected DOI loadOrCreateDOI(Context context, DSpaceObject dso, String doiIdentifier)
throws SQLException, DOIIdentifierException {
return loadOrCreateDOI(context, dso, doiIdentifier, false);
}
/**
* Load DOI from database, or create one if it doesn't yet exist
* We need to distinguish several cases. LoadOrCreate can be called with a specifid identifier to load or create.
* It can also be used to create a new unspecified identifier. In the latter case doiIdentifier is set null.
* If doiIdentifier is set, we know which doi we should try to load or create, but even in sucha situation
* we might be able to find it in the database or might have to create it.
*
* @param context - DSpace context
* @param dso - DSpaceObject to identify
* @param doiIdentifier - DOI to load or create (null to mint a new one)
* @param skipFilter - Whether or not to skip the filters for the canMint() check
* @return
* @throws SQLException
* @throws DOIIdentifierException
*/
protected DOI loadOrCreateDOI(Context context, DSpaceObject dso, String doiIdentifier, Boolean skipFilter)
throws SQLException, DOIIdentifierException {
DOI doi = null;
// Was an identifier specified that we shall try to load or create if it is not existing yet?
if (null != doiIdentifier) {
// we expect DOIs to have the DOI-Scheme except inside the doi table:
doiIdentifier = doiIdentifier.substring(DOI.SCHEME.length());
@@ -692,21 +927,22 @@ public class DOIIdentifierProvider
// doi was deleted, check resource type
if (doi.getResourceTypeId() != null
&& doi.getResourceTypeId() != dso.getType()) {
// doi was assigend to another resource type. Don't
// doi was assigned to another resource type. Don't
// reactivate it
throw new DOIIdentifierException("Cannot reassing "
+ "previously deleted DOI " + doiIdentifier
+ " as the resource types of the object it was "
+ "previously assigned to and the object it "
+ "shall be assigned to now divert (was: "
+ Constants.typeText[doi.getResourceTypeId()]
+ ", trying to assign to "
+ Constants.typeText[dso.getType()] + ").",
DOIIdentifierException.DOI_IS_DELETED);
+ "previously deleted DOI " + doiIdentifier
+ " as the resource types of the object it was "
+ "previously assigned to and the object it "
+ "shall be assigned to now divert (was: "
+ Constants.typeText[doi.getResourceTypeId()]
+ ", trying to assign to "
+ Constants.typeText[dso.getType()] + ").",
DOIIdentifierException.DOI_IS_DELETED);
} else {
// reassign doi
// nothing to do here, doi will br reassigned after this
// if-else-if-else-...-block
// will check if a filter prohibits creation of DOIs after this if-else-block
}
} else {
// doi is assigned to a DSO; is it assigned to our specific dso?
@@ -715,24 +951,47 @@ public class DOIIdentifierProvider
return doi;
} else {
throw new DOIIdentifierException("Trying to create a DOI " +
"that is already reserved for another object.",
DOIIdentifierException.DOI_ALREADY_EXISTS);
"that is already reserved for another object.",
DOIIdentifierException.DOI_ALREADY_EXISTS);
}
}
}
// 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
boolean canMintDOI = canMint(context, dso);
log.debug("Called canMint(), result was " + canMintDOI +
" (and presumably an exception was not thrown)");
}
// check prefix
if (!doiIdentifier.startsWith(this.getPrefix() + "/")) {
throw new DOIIdentifierException("Trying to create a DOI " +
"that's not part of our Namespace!",
DOIIdentifierException.FOREIGN_DOI);
"that's not part of our Namespace!",
DOIIdentifierException.FOREIGN_DOI);
}
if (doi == null) {
// prepare new doiRow
doi = doiService.create(context);
}
} else {
// We need to generate a new DOI.
// We need to generate a new DOI. Before doing so, we should check if a
// filter is in place to prevent the creation of new DOIs for certain items.
if (skipFilter) {
log.warn("loadOrCreateDOI: Skipping default item filter");
} else {
// Find out if we're allowed to create a DOI
// throws an exception if creation of a new DOI is prohibeted by a filter
boolean canMintDOI = canMint(context, dso);
log.debug("Called canMint(), result was " + canMintDOI +
" (and presumably an exception was not thrown)");
}
doi = doiService.create(context);
doiIdentifier = this.getPrefix() + "/" + this.getNamespaceSeparator() +
doi.getID();
@@ -745,7 +1004,7 @@ public class DOIIdentifierProvider
try {
doiService.update(context, doi);
} catch (SQLException e) {
throw new RuntimeException("Cannot save DOI to databse for unkown reason.");
throw new RuntimeException("Cannot save DOI to database for unknown reason.");
}
return doi;
@@ -758,13 +1017,11 @@ public class DOIIdentifierProvider
* @return The DOI or null if no DOI was found.
* @throws DOIIdentifierException if identifier error
*/
public String getDOIOutOfObject(DSpaceObject dso)
throws DOIIdentifierException {
public String getDOIOutOfObject(DSpaceObject dso) throws DOIIdentifierException {
// FIXME
if (!(dso instanceof Item)) {
throw new IllegalArgumentException("We currently support DOIs for "
+ "Items only, not for " + contentServiceFactory
.getDSpaceObjectService(dso).getTypeText(dso) + ".");
throw new IllegalArgumentException("We currently support DOIs for Items only, not for " +
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ".");
}
Item item = (Item) dso;
@@ -789,17 +1046,16 @@ public class DOIIdentifierProvider
* @throws IdentifierException if identifier error
*/
protected void saveDOIToObject(Context context, DSpaceObject dso, String doi)
throws SQLException, AuthorizeException, IdentifierException {
throws SQLException, AuthorizeException, IdentifierException {
// FIXME
if (!(dso instanceof Item)) {
throw new IllegalArgumentException("We currently support DOIs for "
+ "Items only, not for " + contentServiceFactory
.getDSpaceObjectService(dso).getTypeText(dso) + ".");
throw new IllegalArgumentException("We currently support DOIs for Items only, not for " +
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ".");
}
Item item = (Item) dso;
itemService
.addMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null, doiService.DOIToExternalForm(doi));
itemService.addMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null,
doiService.DOIToExternalForm(doi));
try {
itemService.update(context, item);
} catch (SQLException | AuthorizeException ex) {
@@ -821,9 +1077,8 @@ public class DOIIdentifierProvider
throws AuthorizeException, SQLException, IdentifierException {
// FIXME
if (!(dso instanceof Item)) {
throw new IllegalArgumentException("We currently support DOIs for "
+ "Items only, not for " + contentServiceFactory
.getDSpaceObjectService(dso).getTypeText(dso) + ".");
throw new IllegalArgumentException("We currently support DOIs for Items only, not for " +
contentServiceFactory.getDSpaceObjectService(dso).getTypeText(dso) + ".");
}
Item item = (Item) dso;
@@ -838,7 +1093,39 @@ public class DOIIdentifierProvider
itemService.clearMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null);
itemService.addMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null,
remainder);
remainder);
itemService.update(context, item);
}
}
/**
* Checks to see if an item can have a DOI minted, using the configured logical filter
* @param context
* @param dso The item to be evaluated
* @return
* @throws DOIIdentifierNotApplicableException
*/
@Override
public Boolean canMint(Context context, DSpaceObject dso) throws DOIIdentifierNotApplicableException {
// Default is 'true' in the case of a null/missing filter. All we really care about is whether
// an exception was thrown or not.
log.debug("canMint is being called");
if (this.filterService != null && contentServiceFactory
.getDSpaceObjectService(dso).getTypeText(dso).equals("ITEM")) {
try {
Boolean result = filterService.getResult(context, (Item) dso);
log.debug("Result of filter for " + dso.getHandle() + " is " + result.toString());
if (!result) {
throw new DOIIdentifierNotApplicableException("Item " + dso.getHandle() +
" was evaluated as 'false' by the item filter, not minting");
}
} catch (LogicalStatementException e) {
log.error("Error evaluating item with logical filter: " + e.getLocalizedMessage());
throw new DOIIdentifierNotApplicableException(e);
}
} else {
log.debug("DOI Identifier Provider: filterService is null");
}
return true;
}
}