mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-15 14:03:17 +00:00
DS-2490: Add versioned DOIs and adapt DOI support to service API
This commit is contained in:
@@ -40,6 +40,9 @@ public class DOI
|
|||||||
@JoinColumn(name = "dspace_object")
|
@JoinColumn(name = "dspace_object")
|
||||||
private DSpaceObject dSpaceObject;
|
private DSpaceObject dSpaceObject;
|
||||||
|
|
||||||
|
@Column(name = "resource_type_id")
|
||||||
|
private Integer resourceTypeId;
|
||||||
|
|
||||||
@Column(name = "status")
|
@Column(name = "status")
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
@@ -67,11 +70,20 @@ public class DOI
|
|||||||
public DSpaceObject getDSpaceObject() {
|
public DSpaceObject getDSpaceObject() {
|
||||||
return dSpaceObject;
|
return dSpaceObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDSpaceObject(DSpaceObject dSpaceObject) {
|
public void setDSpaceObject(DSpaceObject dSpaceObject) {
|
||||||
this.dSpaceObject = dSpaceObject;
|
this.dSpaceObject = dSpaceObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getResourceTypeId() {
|
||||||
|
return this.resourceTypeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResourceTypeId(Integer resourceTypeId)
|
||||||
|
{
|
||||||
|
this.resourceTypeId = resourceTypeId;
|
||||||
|
}
|
||||||
|
|
||||||
public Integer getStatus() {
|
public Integer getStatus() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@ import org.dspace.content.DSpaceObject;
|
|||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
import org.dspace.content.factory.ContentServiceFactory;
|
||||||
import org.dspace.content.service.ItemService;
|
import org.dspace.content.service.ItemService;
|
||||||
|
import org.dspace.core.Constants;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.identifier.doi.DOIConnector;
|
import org.dspace.identifier.doi.DOIConnector;
|
||||||
import org.dspace.identifier.doi.DOIIdentifierException;
|
import org.dspace.identifier.doi.DOIIdentifierException;
|
||||||
@@ -63,6 +64,7 @@ public class DOIIdentifierProvider
|
|||||||
|
|
||||||
static final String CFG_PREFIX = "identifier.doi.prefix";
|
static final String CFG_PREFIX = "identifier.doi.prefix";
|
||||||
static final String CFG_NAMESPACE_SEPARATOR = "identifier.doi.namespaceseparator";
|
static final String CFG_NAMESPACE_SEPARATOR = "identifier.doi.namespaceseparator";
|
||||||
|
static final char SLASH = '/';
|
||||||
|
|
||||||
// Metadata field name elements
|
// Metadata field name elements
|
||||||
// TODO: move these to MetadataSchema or some such?
|
// TODO: move these to MetadataSchema or some such?
|
||||||
@@ -83,11 +85,11 @@ public class DOIIdentifierProvider
|
|||||||
@Autowired(required = true)
|
@Autowired(required = true)
|
||||||
protected DOIService doiService;
|
protected DOIService doiService;
|
||||||
@Autowired(required = true)
|
@Autowired(required = true)
|
||||||
protected ItemService itemService;
|
|
||||||
@Autowired(required = true)
|
|
||||||
protected ContentServiceFactory contentServiceFactory;
|
protected ContentServiceFactory contentServiceFactory;
|
||||||
|
@Autowired(required = true)
|
||||||
|
protected ItemService itemService;
|
||||||
|
|
||||||
private DOIIdentifierProvider() {
|
protected DOIIdentifierProvider() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -165,10 +167,7 @@ public class DOIIdentifierProvider
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
doiService.formatIdentifier(identifier);
|
doiService.formatIdentifier(identifier);
|
||||||
} catch (IdentifierException e) {
|
} catch (IdentifierException | IllegalArgumentException ex) {
|
||||||
return false;
|
|
||||||
} catch (IllegalArgumentException e)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -182,7 +181,7 @@ public class DOIIdentifierProvider
|
|||||||
String doi = mint(context, dso);
|
String doi = mint(context, dso);
|
||||||
// register tries to reserve doi if it's not already.
|
// register tries to reserve doi if it's not already.
|
||||||
// So we don't have to reserve it here.
|
// So we don't have to reserve it here.
|
||||||
this.register(context, dso, doi);
|
register(context, dso, doi);
|
||||||
return doi;
|
return doi;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,9 +346,7 @@ public class DOIIdentifierProvider
|
|||||||
throws IdentifierException, IllegalArgumentException, SQLException
|
throws IdentifierException, IllegalArgumentException, SQLException
|
||||||
{
|
{
|
||||||
String doi = doiService.formatIdentifier(identifier);
|
String doi = doiService.formatIdentifier(identifier);
|
||||||
DOI doiRow = null;
|
DOI doiRow = loadOrCreateDOI(context, dso, doi);
|
||||||
|
|
||||||
doiRow = loadOrCreateDOI(context, dso, doi);
|
|
||||||
|
|
||||||
if (DELETED.equals(doiRow.getStatus()) ||
|
if (DELETED.equals(doiRow.getStatus()) ||
|
||||||
TO_BE_DELETED.equals(doiRow.getStatus()))
|
TO_BE_DELETED.equals(doiRow.getStatus()))
|
||||||
@@ -768,68 +765,97 @@ public class DOIIdentifierProvider
|
|||||||
*
|
*
|
||||||
* @param context
|
* @param context
|
||||||
* @param dso The DSpaceObject the DOI should be loaded or created for.
|
* @param dso The DSpaceObject the DOI should be loaded or created for.
|
||||||
* @param doi A DOI or null if a DOI should be generated. The generated DOI
|
* @param doiIdentifier A DOI or null if a DOI should be generated. The generated DOI
|
||||||
* can be found in the appropriate column for the TableRow.
|
* can be found in the appropriate column for the TableRow.
|
||||||
* @return The database row of the object.
|
* @return The database row of the object.
|
||||||
* @throws SQLException In case of an error using the database.
|
* @throws SQLException In case of an error using the database.
|
||||||
* @throws DOIIdentifierException If {@code doi} is not part of our prefix or
|
* @throws DOIIdentifierException If {@code doi} is not part of our prefix or
|
||||||
* DOI is registered for another object already.
|
* DOI is registered for another object already.
|
||||||
*/
|
*/
|
||||||
protected DOI loadOrCreateDOI(Context context, DSpaceObject dso, String doi)
|
protected DOI loadOrCreateDOI(Context context, DSpaceObject dso, String doiIdentifier)
|
||||||
throws SQLException, DOIIdentifierException
|
throws SQLException, DOIIdentifierException
|
||||||
{
|
{
|
||||||
DOI doiRow = null;
|
DOI doi = null;
|
||||||
if (null != doi)
|
if (null != doiIdentifier)
|
||||||
{
|
{
|
||||||
// we expect DOIs to have the DOI-Scheme except inside the doi table:
|
// we expect DOIs to have the DOI-Scheme except inside the doi table:
|
||||||
doi = doi.substring(DOI.SCHEME.length());
|
doiIdentifier = doiIdentifier.substring(DOI.SCHEME.length());
|
||||||
|
|
||||||
// check if DOI is already in Database
|
// check if DOI is already in Database
|
||||||
doiRow = doiService.findByDoi(context, doi);
|
doi = doiService.findByDoi(context, doiIdentifier);
|
||||||
if (null != doiRow)
|
if (null != doi)
|
||||||
{
|
{
|
||||||
// check if DOI already belongs to dso
|
if (doi.getDSpaceObject() == null)
|
||||||
if (ObjectUtils.equals(doiRow.getDSpaceObject(), dso))
|
|
||||||
{
|
{
|
||||||
return doiRow;
|
// doi was deleted, check resource type
|
||||||
}
|
if (doi.getResourceTypeId() != null
|
||||||
else
|
&& doi.getResourceTypeId() != dso.getType())
|
||||||
{
|
{
|
||||||
throw new DOIIdentifierException("Trying to create a DOI " +
|
// doi was assigend to another resource type. Don't
|
||||||
"that is already reserved for another object.",
|
// reactivate it
|
||||||
DOIIdentifierException.DOI_ALREADY_EXISTS);
|
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);
|
||||||
|
} else {
|
||||||
|
// reassign doi
|
||||||
|
// nothing to do here, doi will br reassigned after this
|
||||||
|
// if-else-if-else-...-block
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 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()))
|
||||||
|
{
|
||||||
|
return doi;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("Trying to create a DOI " +
|
||||||
|
"that is already reserved for another object.",
|
||||||
|
DOIIdentifierException.DOI_ALREADY_EXISTS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check prefix
|
// check prefix
|
||||||
if (!doi.startsWith(this.getPrefix() + "/"))
|
if (!doiIdentifier.startsWith(this.getPrefix() + "/"))
|
||||||
{
|
{
|
||||||
throw new DOIIdentifierException("Trying to create a DOI " +
|
throw new DOIIdentifierException("Trying to create a DOI " +
|
||||||
"that's not part of our Namespace!",
|
"that's not part of our Namespace!",
|
||||||
DOIIdentifierException.FOREIGN_DOI);
|
DOIIdentifierException.FOREIGN_DOI);
|
||||||
}
|
}
|
||||||
// prepare new doiRow
|
if (doi == null)
|
||||||
doiRow = doiService.create(context);
|
{
|
||||||
|
// prepare new doiRow
|
||||||
|
doi = doiService.create(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We need to generate a new DOI.
|
// We need to generate a new DOI.
|
||||||
doiRow = doiService.create(context);
|
doi = doiService.create(context);
|
||||||
|
doiIdentifier = this.getPrefix() + "/" + this.getNamespaceSeparator() +
|
||||||
doi = this.getPrefix() + "/" + this.getNamespaceSeparator() +
|
doi.getId();
|
||||||
doiRow.getId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
doiRow.setDoi(doi);
|
// prepare new doiRow
|
||||||
doiRow.setDSpaceObject(dso);
|
doi.setDoi(doiIdentifier);
|
||||||
doiRow.setStatus(null);
|
doi.setDSpaceObject(dso);
|
||||||
|
doi.setResourceTypeId(dso.getType());
|
||||||
|
doi.setStatus(null);
|
||||||
try {
|
try {
|
||||||
doiService.update(context, doiRow);
|
doiService.update(context, doi);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException("Cannot save DOI to databse for unkown reason.");
|
throw new RuntimeException("Cannot save DOI to databse for unkown reason.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return doiRow;
|
return doi;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -850,7 +876,7 @@ public class DOIIdentifierProvider
|
|||||||
List<MetadataValue> metadata = itemService.getMetadata(item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null);
|
List<MetadataValue> metadata = itemService.getMetadata(item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null);
|
||||||
for (MetadataValue id : metadata)
|
for (MetadataValue id : metadata)
|
||||||
{
|
{
|
||||||
if (id.getValue().startsWith(DOI.RESOLVER + "/10.")) {
|
if (id.getValue().startsWith(DOI.RESOLVER + String.valueOf(SLASH) + PREFIX + String.valueOf(SLASH) + NAMESPACE_SEPARATOR)) {
|
||||||
return doiService.DOIFromExternalFormat(id.getValue());
|
return doiService.DOIFromExternalFormat(id.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -922,12 +948,6 @@ public class DOIIdentifierProvider
|
|||||||
itemService.clearMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null);
|
itemService.clearMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null);
|
||||||
itemService.addMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null,
|
itemService.addMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null,
|
||||||
remainder);
|
remainder);
|
||||||
try {
|
itemService.update(context, item);
|
||||||
itemService.update(context, item);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw e;
|
|
||||||
} catch (AuthorizeException e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -115,4 +115,11 @@ public class DOIServiceImpl implements DOIService {
|
|||||||
public List<DOI> getDOIsByStatus(Context context, List<Integer> statuses) throws SQLException{
|
public List<DOI> getDOIsByStatus(Context context, List<Integer> statuses) throws SQLException{
|
||||||
return doiDAO.findByStatus(context, statuses);
|
return doiDAO.findByStatus(context, statuses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DOI> getSimilarDOIsNotInState(Context context, String doiPattern, List<Integer> statuses, boolean dsoIsNotNull)
|
||||||
|
throws SQLException
|
||||||
|
{
|
||||||
|
return doiDAO.findSimilarNotInState(context, doiPattern, statuses, dsoIsNotNull);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,355 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.identifier;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.dspace.authorize.AuthorizeException;
|
||||||
|
import org.dspace.content.DSpaceObject;
|
||||||
|
import org.dspace.content.Item;
|
||||||
|
import org.dspace.content.MetadataValue;
|
||||||
|
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.services.ConfigurationService;
|
||||||
|
import org.dspace.versioning.Version;
|
||||||
|
import org.dspace.versioning.VersionHistory;
|
||||||
|
import org.dspace.versioning.service.VersionHistoryService;
|
||||||
|
import org.dspace.versioning.service.VersioningService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Marsa Haoua
|
||||||
|
* @author Pascal-Nicolas Becker (dspace at pascal dash becker dot de)
|
||||||
|
*/
|
||||||
|
public class VersionedDOIIdentifierProvider extends DOIIdentifierProvider
|
||||||
|
{
|
||||||
|
/** log4j category */
|
||||||
|
private static Logger log = Logger.getLogger(VersionedDOIIdentifierProvider.class);
|
||||||
|
|
||||||
|
private DOIConnector connector;
|
||||||
|
|
||||||
|
static final char DOT = '.';
|
||||||
|
private static final String pattern = "\\d+\\" + String.valueOf(DOT) +"\\d+";
|
||||||
|
|
||||||
|
@Autowired(required = true)
|
||||||
|
private VersioningService versioningService;
|
||||||
|
@Autowired(required = true)
|
||||||
|
private VersionHistoryService versionHistoryService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String mint(Context context, DSpaceObject dso)
|
||||||
|
throws IdentifierException
|
||||||
|
{
|
||||||
|
if (!(dso instanceof Item))
|
||||||
|
{
|
||||||
|
throw new IdentifierException("Currently only Items are supported for DOIs.");
|
||||||
|
}
|
||||||
|
Item item = (Item) dso;
|
||||||
|
|
||||||
|
VersionHistory history = null;
|
||||||
|
try {
|
||||||
|
history = versionHistoryService.findByItem(context, item);
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
throw new RuntimeException("A problem occured while accessing the database.", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
String doi = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
doi = getDOIByObject(context, dso);
|
||||||
|
if (doi != null)
|
||||||
|
{
|
||||||
|
return doi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SQLException ex)
|
||||||
|
{
|
||||||
|
log.error("Error while attemping to retrieve information about a DOI for "
|
||||||
|
+ 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() + ".", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check whether we have a DOI in the metadata and if we have to remove it
|
||||||
|
String metadataDOI = getDOIOutOfObject(dso);
|
||||||
|
if (metadataDOI != null)
|
||||||
|
{
|
||||||
|
// check whether doi and version number matches
|
||||||
|
String bareDOI = getBareDOI(metadataDOI);
|
||||||
|
int versionNumber;
|
||||||
|
try {
|
||||||
|
versionNumber = versionHistoryService.getVersion(context, history, item).getVersionNumber();
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
String versionedDOI = bareDOI;
|
||||||
|
if (versionNumber > 1)
|
||||||
|
{
|
||||||
|
versionedDOI = bareDOI
|
||||||
|
.concat(String.valueOf(DOT))
|
||||||
|
.concat(String.valueOf(versionNumber));
|
||||||
|
}
|
||||||
|
if (!metadataDOI.equalsIgnoreCase(versionedDOI))
|
||||||
|
{
|
||||||
|
log.debug("Will remove DOI " + metadataDOI
|
||||||
|
+ " from item metadata, as it should become " + versionedDOI + ".");
|
||||||
|
// remove old versioned DOIs
|
||||||
|
try {
|
||||||
|
removePreviousVersionDOIsOutOfObject(context, item, metadataDOI);
|
||||||
|
} catch (AuthorizeException ex) {
|
||||||
|
throw new RuntimeException("Trying to remove an old DOI from a versioned item, but wasn't authorized to.", ex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.debug("DOI " + doi + " matches version number " + versionNumber + ".");
|
||||||
|
// 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);
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
throw new RuntimeException("A problem with the database connection occured.", ex);
|
||||||
|
}
|
||||||
|
return versionedDOI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
if(history != null)
|
||||||
|
{
|
||||||
|
// versioning is currently supported for items only
|
||||||
|
// if we have a history, we have a item
|
||||||
|
doi = makeIdentifierBasedOnHistory(context, dso, history);
|
||||||
|
} else {
|
||||||
|
doi = loadOrCreateDOI(context, dso, null).getDoi();
|
||||||
|
}
|
||||||
|
} catch(SQLException ex) {
|
||||||
|
log.error("SQLException while creating a new DOI: ", ex);
|
||||||
|
throw new IdentifierException(ex);
|
||||||
|
} catch (AuthorizeException ex) {
|
||||||
|
log.error("AuthorizationException while creating a new DOI: ", ex);
|
||||||
|
throw new IdentifierException(ex);
|
||||||
|
}
|
||||||
|
return doi;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void register(Context context, DSpaceObject dso, String identifier)
|
||||||
|
throws IdentifierException
|
||||||
|
{
|
||||||
|
if (!(dso instanceof Item))
|
||||||
|
{
|
||||||
|
throw new IdentifierException("Currently only Items are supported for DOIs.");
|
||||||
|
}
|
||||||
|
Item item = (Item) dso;
|
||||||
|
|
||||||
|
if (StringUtils.isEmpty(identifier))
|
||||||
|
{
|
||||||
|
identifier = mint(context, dso);
|
||||||
|
}
|
||||||
|
String doiIdentifier = doiService.formatIdentifier(identifier);
|
||||||
|
|
||||||
|
DOI doi = null;
|
||||||
|
|
||||||
|
// search DOI in our db
|
||||||
|
try
|
||||||
|
{
|
||||||
|
doi = loadOrCreateDOI(context, dso, doiIdentifier);
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
log.error("Error in databse connection: " + ex.getMessage());
|
||||||
|
throw new RuntimeException("Error in database conncetion.", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DELETED.equals(doi.getStatus()) ||
|
||||||
|
TO_BE_DELETED.equals(doi.getStatus()))
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("You tried to register a DOI that "
|
||||||
|
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check status of DOI
|
||||||
|
if (IS_REGISTERED.equals(doi.getStatus()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String metadataDOI = getDOIOutOfObject(dso);
|
||||||
|
if (!StringUtils.isEmpty(metadataDOI)
|
||||||
|
&& !metadataDOI.equalsIgnoreCase(doiIdentifier))
|
||||||
|
{
|
||||||
|
// remove doi of older version from the metadata
|
||||||
|
try {
|
||||||
|
removePreviousVersionDOIsOutOfObject(context, item, metadataDOI);
|
||||||
|
} catch (AuthorizeException ex) {
|
||||||
|
throw new RuntimeException("Trying to remove an old DOI from a versioned item, but wasn't authorized to.", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// change status of DOI
|
||||||
|
doi.setStatus(TO_BE_REGISTERED);
|
||||||
|
try {
|
||||||
|
doiService.update(context, doi);
|
||||||
|
}
|
||||||
|
catch (SQLException ex)
|
||||||
|
{
|
||||||
|
log.warn("SQLException while changing status of DOI {} to be registered.", ex);
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getBareDOI(String identifier)
|
||||||
|
throws DOIIdentifierException
|
||||||
|
{
|
||||||
|
doiService.formatIdentifier(identifier);
|
||||||
|
String doiPrefix = DOI.SCHEME.concat(getPrefix())
|
||||||
|
.concat(String.valueOf(SLASH))
|
||||||
|
.concat(getNamespaceSeparator());
|
||||||
|
String doiPostfix = identifier.substring(doiPrefix.length());
|
||||||
|
if (doiPostfix.matches(pattern) && doiPostfix.lastIndexOf(DOT) != -1)
|
||||||
|
{
|
||||||
|
return doiPrefix.concat(doiPostfix.substring(0, doiPostfix.lastIndexOf(DOT)));
|
||||||
|
}
|
||||||
|
// if the pattern does not match, we are already working on a bare handle.
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDOIPostfix(String identifier)
|
||||||
|
throws DOIIdentifierException{
|
||||||
|
|
||||||
|
String doiPrefix = DOI.SCHEME.concat(getPrefix()).concat(String.valueOf(SLASH)).concat(getNamespaceSeparator());
|
||||||
|
String doiPostfix = null;
|
||||||
|
if(null != identifier){
|
||||||
|
doiPostfix = identifier.substring(doiPrefix.length());
|
||||||
|
}
|
||||||
|
return doiPostfix;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should never return null!
|
||||||
|
protected String makeIdentifierBasedOnHistory(Context context, DSpaceObject dso, VersionHistory history)
|
||||||
|
throws AuthorizeException, SQLException, DOIIdentifierException
|
||||||
|
{
|
||||||
|
// Mint foreach new version an identifier like: 12345/100.versionNumber
|
||||||
|
// use the bare handle (g.e. 12345/100) for the first version.
|
||||||
|
|
||||||
|
// currently versioning is supported for items only
|
||||||
|
if (!(dso instanceof Item))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Cannot create versioned handle for objects other then item: Currently versioning supports items only.");
|
||||||
|
}
|
||||||
|
Item item = (Item)dso;
|
||||||
|
Version version = versionHistoryService.getVersion(context, history, item);
|
||||||
|
|
||||||
|
String previousVersionDOI = null;
|
||||||
|
for (Version v : versioningService.getVersionsByHistory(context, history))
|
||||||
|
{
|
||||||
|
previousVersionDOI = getDOIByObject(context, v.getItem());
|
||||||
|
if (null != previousVersionDOI)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previousVersionDOI == null)
|
||||||
|
{
|
||||||
|
// We need to generate a new DOI.
|
||||||
|
DOI doi = doiService.create(context);
|
||||||
|
|
||||||
|
// as we reuse the DOI ID, we do not have to check whether the DOI exists already.
|
||||||
|
String identifier = this.getPrefix() + "/" + this.getNamespaceSeparator() +
|
||||||
|
doi.getId().toString();
|
||||||
|
|
||||||
|
if (version.getVersionNumber() > 1)
|
||||||
|
{
|
||||||
|
identifier.concat(String.valueOf(DOT).concat(String.valueOf(version.getVersionNumber())));
|
||||||
|
}
|
||||||
|
|
||||||
|
doi.setDoi(identifier);
|
||||||
|
doi.setResourceTypeId(dso.getType());
|
||||||
|
doi.setDSpaceObject(dso);
|
||||||
|
doi.setStatus(null);
|
||||||
|
doiService.update(context, doi);
|
||||||
|
return doi.getDoi();
|
||||||
|
}
|
||||||
|
assert(previousVersionDOI != null);
|
||||||
|
|
||||||
|
String identifier = getBareDOI(previousVersionDOI);
|
||||||
|
|
||||||
|
if (version.getVersionNumber() > 1)
|
||||||
|
{
|
||||||
|
identifier = identifier.concat(String.valueOf(DOT)).concat(String.valueOf(versionHistoryService.getVersion(context, history, item).getVersionNumber()));
|
||||||
|
}
|
||||||
|
|
||||||
|
loadOrCreateDOI(context, dso, identifier);
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removePreviousVersionDOIsOutOfObject(Context c, Item item, String oldDoi)
|
||||||
|
throws IdentifierException, AuthorizeException
|
||||||
|
{
|
||||||
|
if (StringUtils.isEmpty(oldDoi))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Old DOI must be neither empty nor null!");
|
||||||
|
}
|
||||||
|
|
||||||
|
String bareDoi = getBareDOI(doiService.formatIdentifier(oldDoi));
|
||||||
|
String bareDoiRef = doiService.DOIToExternalForm(bareDoi);
|
||||||
|
|
||||||
|
List<MetadataValue> identifiers = itemService.getMetadata(item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, Item.ANY);
|
||||||
|
// We have to remove all DOIs referencing previous versions. To do that,
|
||||||
|
// we store all identifiers we do not know in an array list, clear
|
||||||
|
// dc.identifier.uri and add the safed identifiers.
|
||||||
|
// The list of identifiers to safe won't get larger then the number of
|
||||||
|
// existing identifiers.
|
||||||
|
ArrayList<String> newIdentifiers = new ArrayList<String>(identifiers.size());
|
||||||
|
boolean changed = false;
|
||||||
|
for (MetadataValue identifier : identifiers)
|
||||||
|
{
|
||||||
|
if (!StringUtils.startsWithIgnoreCase(identifier.getValue(), bareDoiRef))
|
||||||
|
{
|
||||||
|
newIdentifiers.add(identifier.getValue());
|
||||||
|
} else {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// reset the metadata if neccessary.
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
itemService.clearMetadata(c, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, Item.ANY);
|
||||||
|
itemService.addMetadata(c, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null, newIdentifiers);
|
||||||
|
itemService.update(c, item);
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
throw new RuntimeException("A problem with the database connection occured.", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setDOIConnector(DOIConnector connector)
|
||||||
|
{
|
||||||
|
super.setDOIConnector(connector);
|
||||||
|
this.connector = connector;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setConfigurationService(ConfigurationService configurationService) {
|
||||||
|
super.setConfigurationService(configurationService);
|
||||||
|
this.configurationService = configurationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -27,6 +27,9 @@ public interface DOIDAO extends GenericDAO<DOI>
|
|||||||
public DOI findByDoi(Context context, String doi) throws SQLException;
|
public DOI findByDoi(Context context, String doi) throws SQLException;
|
||||||
|
|
||||||
public DOI findDOIByDSpaceObject(Context context, DSpaceObject dso, List<Integer> statusToExclude) throws SQLException;
|
public DOI findDOIByDSpaceObject(Context context, DSpaceObject dso, List<Integer> statusToExclude) throws SQLException;
|
||||||
|
|
||||||
|
public List<DOI> findSimilarNotInState(Context context, String doi, List<Integer> statuses, boolean dsoNotNull)
|
||||||
|
throws SQLException;
|
||||||
|
|
||||||
public List<DOI> findByStatus(Context context, List<Integer> statuses) throws SQLException;
|
public List<DOI> findByStatus(Context context, List<Integer> statuses) throws SQLException;
|
||||||
|
|
||||||
|
@@ -69,6 +69,28 @@ public class DOIDAOImpl extends AbstractHibernateDAO<DOI> implements DOIDAO
|
|||||||
for (Integer status : statuses) {
|
for (Integer status : statuses) {
|
||||||
statusQuery.add(Restrictions.eq("status", status));
|
statusQuery.add(Restrictions.eq("status", status));
|
||||||
}
|
}
|
||||||
|
criteria.add(statusQuery);
|
||||||
|
return list(criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DOI> findSimilarNotInState(Context context, String doi, List<Integer> excludedStatuses, boolean dsoNotNull)
|
||||||
|
throws SQLException
|
||||||
|
{
|
||||||
|
// SELECT * FROM Doi WHERE doi LIKE ? AND resource_type_id = ? AND resource_id IS NOT NULL AND status != ? AND status != ?
|
||||||
|
Criteria criteria = createCriteria(context, DOI.class);
|
||||||
|
Conjunction conjunctionAnd = Restrictions.and();
|
||||||
|
Disjunction statusQuery = Restrictions.or();
|
||||||
|
for (Integer status : excludedStatuses) {
|
||||||
|
statusQuery.add(Restrictions.ne("status", status));
|
||||||
|
}
|
||||||
|
conjunctionAnd.add(Restrictions.like("doi", doi));
|
||||||
|
conjunctionAnd.add(statusQuery);
|
||||||
|
if (dsoNotNull)
|
||||||
|
{
|
||||||
|
conjunctionAnd.add(Restrictions.isNotNull("dSpaceObject"));
|
||||||
|
}
|
||||||
|
criteria.add(conjunctionAnd);
|
||||||
return list(criteria);
|
return list(criteria);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -68,4 +68,16 @@ public interface DOIService {
|
|||||||
throws DOIIdentifierException;
|
throws DOIIdentifierException;
|
||||||
|
|
||||||
public List<DOI> getDOIsByStatus(Context context, List<Integer> statuses) throws SQLException;
|
public List<DOI> getDOIsByStatus(Context context, List<Integer> statuses) throws SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all DOIs that are similar to the specified pattern ant not in the specified states.
|
||||||
|
* @param context DSpace context
|
||||||
|
* @param doiPattern The pattern, e.g. "10.5072/123.%"
|
||||||
|
* @param statuses The statuses the DOI should <b>not</b> be in, @{link DOIIdentifierProvider.DELETED}.
|
||||||
|
* @param dsoIsNotNull Boolean whether all DOIs should be excluded where the DSpaceObject is NULL.
|
||||||
|
* @return null or a list of DOIs
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
public List<DOI> getSimilarDOIsNotInState(Context context, String doiPattern, List<Integer> statuses, boolean dsoIsNotNull)
|
||||||
|
throws SQLException;
|
||||||
}
|
}
|
||||||
|
@@ -22,10 +22,11 @@
|
|||||||
scope="singleton"/>
|
scope="singleton"/>
|
||||||
|
|
||||||
<!-- provider for using the versioned handle identifier instead of the default one. -->
|
<!-- provider for using the versioned handle identifier instead of the default one. -->
|
||||||
<!--<bean id="org.dspace.identifier.HandleIdentifierProvider" class="org.dspace.identifier.VersionedHandleIdentifierProvider"-->
|
<!--
|
||||||
<!--scope="singleton">-->
|
<bean id="org.dspace.identifier.HandleIdentifierProvider" class="org.dspace.identifier.VersionedHandleIdentifierProvider" scope="singleton">
|
||||||
<!--<property name="configurationService" ref="org.dspace.services.ConfigurationService"/>-->
|
<property name="configurationService" ref="org.dspace.services.ConfigurationService"/>
|
||||||
<!--</bean>-->
|
</bean>
|
||||||
|
-->
|
||||||
|
|
||||||
<!-- provider to mint and register DOIs with DSpace.
|
<!-- provider to mint and register DOIs with DSpace.
|
||||||
To mint DOIs you need a registration agency. The DOIIdentifierProvider
|
To mint DOIs you need a registration agency. The DOIIdentifierProvider
|
||||||
@@ -33,8 +34,12 @@
|
|||||||
a DOIConnector that handles all API calls to your DOI registration
|
a DOIConnector that handles all API calls to your DOI registration
|
||||||
agency. Please configure a DOIConnector as well! -->
|
agency. Please configure a DOIConnector as well! -->
|
||||||
|
|
||||||
<!-- In order to mint DOIs with DSpace, get an agreement with a DOI registration
|
<!-- In order to mint DOIs with DSpace, get an agreement with a DOI
|
||||||
agency, take a look into dspace.cfg, and uncomment this.
|
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.
|
||||||
|
-->
|
||||||
|
<!--
|
||||||
<bean id="org.dspace.identifier.DOIIdentifierProvider"
|
<bean id="org.dspace.identifier.DOIIdentifierProvider"
|
||||||
class="org.dspace.identifier.DOIIdentifierProvider"
|
class="org.dspace.identifier.DOIIdentifierProvider"
|
||||||
scope="singleton">
|
scope="singleton">
|
||||||
@@ -44,6 +49,16 @@
|
|||||||
ref="org.dspace.identifier.doi.DOIConnector" />
|
ref="org.dspace.identifier.doi.DOIConnector" />
|
||||||
</bean>
|
</bean>
|
||||||
-->
|
-->
|
||||||
|
<!--
|
||||||
|
<bean id="org.dspace.identifier.DOIIdentifierProvider"
|
||||||
|
class="org.dspace.identifier.VersionedDOIIdentifierProvider"
|
||||||
|
scope="singleton">
|
||||||
|
<property name="configurationService"
|
||||||
|
ref="org.dspace.services.ConfigurationService" />
|
||||||
|
<property name="DOIConnector"
|
||||||
|
ref="org.dspace.identifier.doi.DOIConnector" />
|
||||||
|
</bean>
|
||||||
|
-->
|
||||||
|
|
||||||
<!-- The DOIConnector will handle the API calls to your DOI registration
|
<!-- The DOIConnector will handle the API calls to your DOI registration
|
||||||
agency for the DOIIdentifierProvider. If your registration agency
|
agency for the DOIIdentifierProvider. If your registration agency
|
||||||
|
Reference in New Issue
Block a user