mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-17 23:13:10 +00:00
Merge pull request #312 from tuub/DS-1535
DS-1535: DOI support for dspace-api
This commit is contained in:
@@ -433,6 +433,11 @@
|
|||||||
<artifactId>rome-modules</artifactId>
|
<artifactId>rome-modules</artifactId>
|
||||||
<version>1.0</version>
|
<version>1.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<version>4.2.1</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>gr.ekt</groupId>
|
<groupId>gr.ekt</groupId>
|
||||||
<artifactId>biblio-transformation-engine</artifactId>
|
<artifactId>biblio-transformation-engine</artifactId>
|
||||||
|
@@ -84,6 +84,48 @@ public class HandleManager
|
|||||||
|
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to detect a handle in a URL.
|
||||||
|
* @param context DSpace context
|
||||||
|
* @param url The URL
|
||||||
|
* @return The handle or null if the handle couldn't be extracted of a URL
|
||||||
|
* or if the extracted handle couldn't be found.
|
||||||
|
* @throws SQLException If a database error occurs
|
||||||
|
*/
|
||||||
|
public static String resolveUrlToHandle(Context context, String url)
|
||||||
|
throws SQLException
|
||||||
|
{
|
||||||
|
String dspaceUrl = ConfigurationManager.getProperty("dspace.url")
|
||||||
|
+ "/handle/";
|
||||||
|
String handleResolver = ConfigurationManager.getProperty("handle.canonical.prefix");
|
||||||
|
|
||||||
|
String handle = null;
|
||||||
|
|
||||||
|
if (url.startsWith(dspaceUrl))
|
||||||
|
{
|
||||||
|
handle = url.substring(dspaceUrl.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url.startsWith(handleResolver))
|
||||||
|
{
|
||||||
|
handle = url.substring(handleResolver.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null == handle)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove trailing slashes
|
||||||
|
while (handle.startsWith("/"))
|
||||||
|
{
|
||||||
|
handle = handle.substring(1);
|
||||||
|
}
|
||||||
|
TableRow dbhandle = findHandleInternal(context, handle);
|
||||||
|
|
||||||
|
return (null == dbhandle) ? null : handle;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms handle into the canonical form <em>hdl:handle</em>.
|
* Transforms handle into the canonical form <em>hdl:handle</em>.
|
||||||
|
103
dspace-api/src/main/java/org/dspace/identifier/DOI.java
Normal file
103
dspace-api/src/main/java/org/dspace/identifier/DOI.java
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/**
|
||||||
|
* 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.util.Locale;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import org.dspace.identifier.doi.DOIIdentifierException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOI identifiers.
|
||||||
|
*
|
||||||
|
* @author Pascal-Nicolas Becker
|
||||||
|
*/
|
||||||
|
public class DOI
|
||||||
|
implements Identifier
|
||||||
|
{
|
||||||
|
public static final String SCHEME = "doi:";
|
||||||
|
public static final String RESOLVER = "http://dx.doi.org";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method helps to convert a DOI into a URL. It takes DOIs in one of
|
||||||
|
* the following formats and returns it as URL (f.e.
|
||||||
|
* http://dx.doi.org/10.123/456). Allowed formats are:
|
||||||
|
* <ul>
|
||||||
|
* <li>doi:10.123/456</li>
|
||||||
|
* <li>10.123/456</li>
|
||||||
|
* <li>http://dx.doi.org/10.123/456</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param identifier A DOI that should be returned in external form.
|
||||||
|
* @return A String containing a URL to the official DOI resolver.
|
||||||
|
* @throws IllegalArgumentException If identifier is null or an empty String.
|
||||||
|
* @throws IdentifierException If identifier could not be recognized as valid DOI.
|
||||||
|
*/
|
||||||
|
public static String DOIToExternalForm(String identifier)
|
||||||
|
throws IdentifierException
|
||||||
|
{
|
||||||
|
if (null == identifier)
|
||||||
|
throw new IllegalArgumentException("Identifier is null.", new NullPointerException());
|
||||||
|
if (identifier.isEmpty())
|
||||||
|
throw new IllegalArgumentException("Cannot format an empty identifier.");
|
||||||
|
if (identifier.startsWith(SCHEME))
|
||||||
|
return RESOLVER + "/" + identifier.substring(SCHEME.length());
|
||||||
|
if (identifier.startsWith("10.") && identifier.contains("/"))
|
||||||
|
return RESOLVER + "/" + identifier;
|
||||||
|
if (identifier.startsWith(RESOLVER + "/10."))
|
||||||
|
return identifier;
|
||||||
|
|
||||||
|
throw new IdentifierException(identifier + "does not seem to be a DOI.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String DOIFromExternalFormat(String identifier)
|
||||||
|
throws DOIIdentifierException
|
||||||
|
{
|
||||||
|
Pattern pattern = Pattern.compile("^" + RESOLVER + "/+(10\\..*)$");
|
||||||
|
Matcher matcher = pattern.matcher(identifier);
|
||||||
|
if (matcher.find())
|
||||||
|
{
|
||||||
|
return SCHEME + matcher.group(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new DOIIdentifierException("Cannot recognize DOI!",
|
||||||
|
DOIIdentifierException.UNRECOGNIZED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recognize format of DOI and return it with leading doi-Scheme.
|
||||||
|
* @param identifier Identifier to format, following format are accepted:
|
||||||
|
* f.e. 10.123/456, doi:10.123/456, http://dx.doi.org/10.123/456.
|
||||||
|
* @return Given Identifier with DOI-Scheme, f.e. doi:10.123/456.
|
||||||
|
* @throws IllegalArgumentException If identifier is empty or null.
|
||||||
|
* @throws DOIIdentifierException If DOI could not be recognized.
|
||||||
|
*/
|
||||||
|
public static String formatIdentifier(String identifier)
|
||||||
|
throws DOIIdentifierException
|
||||||
|
{
|
||||||
|
if (null == identifier) {
|
||||||
|
throw new IllegalArgumentException("Identifier is null.", new NullPointerException());
|
||||||
|
}
|
||||||
|
if (identifier.startsWith(DOI.SCHEME)) {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
if (identifier.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Cannot format an empty identifier.");
|
||||||
|
}
|
||||||
|
if (identifier.startsWith("10.") && identifier.contains("/")) {
|
||||||
|
return DOI.SCHEME + identifier;
|
||||||
|
}
|
||||||
|
if (identifier.startsWith(RESOLVER + "/10.")) {
|
||||||
|
return DOI.SCHEME + identifier.substring(18);
|
||||||
|
}
|
||||||
|
throw new DOIIdentifierException(identifier + "does not seem to be a DOI.",
|
||||||
|
DOIIdentifierException.UNRECOGNIZED);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,997 @@
|
|||||||
|
/**
|
||||||
|
* 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.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import org.dspace.authorize.AuthorizeException;
|
||||||
|
import org.dspace.content.DCValue;
|
||||||
|
import org.dspace.content.DSpaceObject;
|
||||||
|
import org.dspace.content.FormatIdentifier;
|
||||||
|
import org.dspace.content.Item;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.identifier.doi.DOIConnector;
|
||||||
|
import org.dspace.identifier.doi.DOIIdentifierException;
|
||||||
|
import org.dspace.storage.rdbms.DatabaseManager;
|
||||||
|
import org.dspace.storage.rdbms.TableRow;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide service for DOIs using DataCite.
|
||||||
|
*
|
||||||
|
* <p>This class handles reservation, registration and deletion of DOIs using
|
||||||
|
* the direct API from {@link <a href="http://www.datacite.org">DataCite</a>}.
|
||||||
|
* Please pay attention that some members of DataCite offer special services
|
||||||
|
* and want their customers to use special APIs. If you are unsure ask your
|
||||||
|
* registration agency.</p>
|
||||||
|
*
|
||||||
|
* <p>Any identifier a method of this class returns is a string in the following format: doi:10.123/456.</p>
|
||||||
|
*
|
||||||
|
* @author Pascal-Nicolas Becker
|
||||||
|
*/
|
||||||
|
public class DOIIdentifierProvider
|
||||||
|
extends IdentifierProvider
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(DOIIdentifierProvider.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A DOIConnector connects the DOIIdentifierProvider to the API of the DOI
|
||||||
|
* registration agency needed to register DOIs. To register DOIs we have to
|
||||||
|
* care about two APIs: the <link>IdentifierProvider</link> API of DSpace
|
||||||
|
* and the API of the DOI registration agency. The DOIIdentifierProvider
|
||||||
|
* manages the DOI database table, generates new DOIs, stores them as
|
||||||
|
* metadata in DSpace items and so on. To register DOIs at DOI registration
|
||||||
|
* agencies it uses a DOIConnector. A DOI connector has to register and
|
||||||
|
* reserve DOIs using the API of the DOI registration agency. If requested
|
||||||
|
* by the registration agency it has to convert and send metadata of the
|
||||||
|
* DSpace items.
|
||||||
|
*/
|
||||||
|
private DOIConnector connector;
|
||||||
|
|
||||||
|
static final String CFG_PREFIX = "identifier.doi.prefix";
|
||||||
|
static final String CFG_NAMESPACE_SEPARATOR = "identifier.doi.namespaceseparator";
|
||||||
|
|
||||||
|
// Metadata field name elements
|
||||||
|
// TODO: move these to MetadataSchema or some such?
|
||||||
|
public static final String MD_SCHEMA = "dc";
|
||||||
|
public static final String DOI_ELEMENT = "identifier";
|
||||||
|
public static final String DOI_QUALIFIER = "uri";
|
||||||
|
|
||||||
|
public static final Integer TO_BE_REGISTERED = 1;
|
||||||
|
public static final Integer TO_BE_RESERVERED = 2;
|
||||||
|
public static final Integer IS_REGISTERED = 3;
|
||||||
|
public static final Integer IS_RESERVED = 4;
|
||||||
|
public static final Integer UPDATE_RESERVERED = 5;
|
||||||
|
public static final Integer UPDATE_REGISTERED = 6;
|
||||||
|
public static final Integer UPDATE_BEFORE_REGISTERATION = 7;
|
||||||
|
public static final Integer TO_BE_DELETED = 8;
|
||||||
|
public static final Integer DELETED = 9;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prefix of DOI namespace. Set in dspace.cfg.
|
||||||
|
*/
|
||||||
|
private String PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Part of DOI to separate several applications that generate DOIs.
|
||||||
|
* E.g. it could be 'dspace/' if DOIs generated by DSpace should have the form
|
||||||
|
* prefix/dspace/uniqueString. Set it to the empty String if DSpace must
|
||||||
|
* generate DOIs directly after the DOI Prefix. Set in dspace.cfg.
|
||||||
|
*/
|
||||||
|
private String NAMESPACE_SEPARATOR;
|
||||||
|
|
||||||
|
protected String getPrefix()
|
||||||
|
{
|
||||||
|
if (null == this.PREFIX)
|
||||||
|
{
|
||||||
|
this.PREFIX = this.configurationService.getProperty(CFG_PREFIX);
|
||||||
|
if (null == this.PREFIX)
|
||||||
|
{
|
||||||
|
log.warn("Cannot find DOI prefix in configuration!");
|
||||||
|
throw new RuntimeException("Unable to load DOI prefix from "
|
||||||
|
+ "configuration. Cannot find property " +
|
||||||
|
CFG_PREFIX + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.PREFIX;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getNamespaceSeparator()
|
||||||
|
{
|
||||||
|
if (null == this.NAMESPACE_SEPARATOR)
|
||||||
|
{
|
||||||
|
this.NAMESPACE_SEPARATOR = this.configurationService.getProperty(CFG_NAMESPACE_SEPARATOR);
|
||||||
|
if (null == this.NAMESPACE_SEPARATOR)
|
||||||
|
{
|
||||||
|
this.NAMESPACE_SEPARATOR = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.NAMESPACE_SEPARATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setDOIConnector(DOIConnector connector)
|
||||||
|
{
|
||||||
|
this.connector = connector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This identifier provider supports identifiers of type
|
||||||
|
* {@link org.dspace.identifier.DOI}.
|
||||||
|
* @param identifier to check if it will be supported by this provider.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean supports(Class<? extends Identifier> identifier)
|
||||||
|
{
|
||||||
|
return DOI.class.isAssignableFrom(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This identifier provider supports identifiers in the following format:
|
||||||
|
* <ul>
|
||||||
|
* <li>doi:10.123/456</li>
|
||||||
|
* <li>10.123/456</li>
|
||||||
|
* <li>http://dx.doi.org/10.123/456</li>
|
||||||
|
* </ul>
|
||||||
|
* @param identifier to check if it is in a supported format.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean supports(String identifier)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
DOI.formatIdentifier(identifier);
|
||||||
|
} catch (IdentifierException e) {
|
||||||
|
return false;
|
||||||
|
} catch (IllegalArgumentException e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String register(Context context, DSpaceObject dso)
|
||||||
|
throws IdentifierException
|
||||||
|
{
|
||||||
|
String doi = mint(context, dso);
|
||||||
|
// register tries to reserve doi if it's not already.
|
||||||
|
// So we don't have to reserve it here.
|
||||||
|
this.register(context, dso, doi);
|
||||||
|
return doi;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void register(Context context, DSpaceObject dso, String identifier)
|
||||||
|
throws IdentifierException
|
||||||
|
{
|
||||||
|
String doi = DOI.formatIdentifier(identifier);
|
||||||
|
TableRow doiRow = null;
|
||||||
|
|
||||||
|
// search DOI in our db
|
||||||
|
try
|
||||||
|
{
|
||||||
|
doiRow = loadOrCreateDOI(context, dso, doi);
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
log.error("Error in databse connection: " + ex.getMessage());
|
||||||
|
throw new RuntimeException("Error in database conncetion.", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DELETED == doiRow.getIntColumn("status") ||
|
||||||
|
TO_BE_DELETED == doiRow.getIntColumn("status"))
|
||||||
|
{
|
||||||
|
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 == doiRow.getIntColumn("status"))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// change status of DOI
|
||||||
|
doiRow.setColumn("status", TO_BE_REGISTERED);
|
||||||
|
try {
|
||||||
|
DatabaseManager.update(context, doiRow);
|
||||||
|
context.commit();
|
||||||
|
}
|
||||||
|
catch (SQLException sqle)
|
||||||
|
{
|
||||||
|
log.warn("SQLException while changing status of DOI {} to be registered.", doi);
|
||||||
|
throw new RuntimeException(sqle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param context
|
||||||
|
* @param dso DSpaceObject the DOI should be reserved for. Some metadata of
|
||||||
|
* this object will be send to the registration agency.
|
||||||
|
* @param identifier DOI to register in a format that
|
||||||
|
* {@link FormatIdentifier(String)} accepts.
|
||||||
|
* @throws IdentifierException If the format of {@code identifier} was
|
||||||
|
* unrecognized or if it was impossible to
|
||||||
|
* reserve the DOI (registration agency denied
|
||||||
|
* for some reason, see logs).
|
||||||
|
* @throws IllegalArgumentException If {@code identifier} is a DOI already
|
||||||
|
* registered for another DSpaceObject then
|
||||||
|
* {@code dso}.
|
||||||
|
* @see IdentifierProvider.reserve(Context, DSpaceObject, String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void reserve(Context context, DSpaceObject dso, String identifier)
|
||||||
|
throws IdentifierException, IllegalArgumentException
|
||||||
|
{
|
||||||
|
String doi = DOI.formatIdentifier(identifier);
|
||||||
|
TableRow 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);
|
||||||
|
}
|
||||||
|
catch (SQLException sqle)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(sqle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!doiRow.isColumnNull("status")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
doiRow.setColumn("status", TO_BE_RESERVERED);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DatabaseManager.update(context, doiRow);
|
||||||
|
}
|
||||||
|
catch (SQLException sqle)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(sqle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reserveOnline(Context context, DSpaceObject dso, String identifier)
|
||||||
|
throws IdentifierException, IllegalArgumentException, SQLException
|
||||||
|
{
|
||||||
|
String doi = DOI.formatIdentifier(identifier);
|
||||||
|
// get TableRow and ensure DOI belongs to dso regarding our db
|
||||||
|
TableRow doiRow = loadOrCreateDOI(context, dso, doi);
|
||||||
|
|
||||||
|
if (DELETED == doiRow.getIntColumn("status") ||
|
||||||
|
TO_BE_DELETED == doiRow.getIntColumn("status"))
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("You tried to reserve a DOI that "
|
||||||
|
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if DOI is reserved at the registration agency
|
||||||
|
if (connector.isDOIReserved(context, doi))
|
||||||
|
{
|
||||||
|
// if doi is registered for this object we still should check its
|
||||||
|
// status in our database (see below).
|
||||||
|
// if it is registered for another object we should notify an admin
|
||||||
|
if (!connector.isDOIReserved(context, dso, doi))
|
||||||
|
{
|
||||||
|
log.warn("DOI {} is reserved for another object already.", doi);
|
||||||
|
throw new DOIIdentifierException(DOIIdentifierException.DOI_ALREADY_EXISTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
connector.reserveDOI(context, dso, doi);
|
||||||
|
}
|
||||||
|
|
||||||
|
doiRow.setColumn("status", IS_RESERVED);
|
||||||
|
DatabaseManager.update(context, doiRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerOnline(Context context, DSpaceObject dso, String identifier)
|
||||||
|
throws IdentifierException, IllegalArgumentException, SQLException
|
||||||
|
{
|
||||||
|
String doi = DOI.formatIdentifier(identifier);
|
||||||
|
// get TableRow and ensure DOI belongs to dso regarding our db
|
||||||
|
TableRow doiRow = loadOrCreateDOI(context, dso, doi);
|
||||||
|
|
||||||
|
if (DELETED == doiRow.getIntColumn("status") ||
|
||||||
|
TO_BE_DELETED == doiRow.getIntColumn("status"))
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("You tried to register a DOI that "
|
||||||
|
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the DOI is already registered online
|
||||||
|
if (connector.isDOIRegistered(context, doi))
|
||||||
|
{
|
||||||
|
// if doi is registered for this object we still should check its
|
||||||
|
// status in our database (see below).
|
||||||
|
// if it is registered for another object we should notify an admin
|
||||||
|
if (!connector.isDOIRegistered(context, dso, doi))
|
||||||
|
{
|
||||||
|
// DOI is reserved for another object
|
||||||
|
log.warn("DOI {} is registered for another object already.", doi);
|
||||||
|
throw new DOIIdentifierException(DOIIdentifierException.DOI_ALREADY_EXISTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// check if doi is reserved for this specific dso
|
||||||
|
if (!connector.isDOIReserved(context, dso, doi))
|
||||||
|
{
|
||||||
|
// check if doi is already reserved for another dso
|
||||||
|
if (connector.isDOIReserved(context, doi))
|
||||||
|
{
|
||||||
|
log.warn("Trying to register DOI {}, that is reserved for "
|
||||||
|
+ "another dso.", doi);
|
||||||
|
throw new DOIIdentifierException("Trying to register a DOI "
|
||||||
|
+ "that is reserved for another object.",
|
||||||
|
DOIIdentifierException.DOI_ALREADY_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
connector.reserveDOI(context, dso, doi);
|
||||||
|
}
|
||||||
|
// register DOI Online
|
||||||
|
try {
|
||||||
|
connector.registerDOI(context, dso, doi);
|
||||||
|
}
|
||||||
|
catch (DOIIdentifierException die)
|
||||||
|
{
|
||||||
|
// do we have to reserve DOI before we can register it?
|
||||||
|
if (die.getCode() == DOIIdentifierException.REGISTER_FIRST)
|
||||||
|
{
|
||||||
|
this.reserveOnline(context, dso, identifier);
|
||||||
|
connector.registerDOI(context, dso, doi);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw die;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// safe DOI as metadata of the item
|
||||||
|
try {
|
||||||
|
saveDOIToObject(context, dso, doi);
|
||||||
|
}
|
||||||
|
catch (AuthorizeException ae)
|
||||||
|
{
|
||||||
|
throw new IdentifierException("Not authorized to save a DOI as metadata of an dso!", ae);
|
||||||
|
}
|
||||||
|
catch (SQLException sqle)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(sqle);
|
||||||
|
}
|
||||||
|
|
||||||
|
doiRow.setColumn("status", IS_REGISTERED);
|
||||||
|
DatabaseManager.update(context, doiRow);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateMetadata(Context context, DSpaceObject dso, String identifier)
|
||||||
|
throws IdentifierException, IllegalArgumentException, SQLException
|
||||||
|
{
|
||||||
|
String doi = DOI.formatIdentifier(identifier);
|
||||||
|
TableRow doiRow = null;
|
||||||
|
|
||||||
|
doiRow = loadOrCreateDOI(context, dso, doi);
|
||||||
|
|
||||||
|
if (DELETED == doiRow.getIntColumn("status") ||
|
||||||
|
TO_BE_DELETED == doiRow.getIntColumn("status"))
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("You tried to register a DOI that "
|
||||||
|
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_REGISTERED == doiRow.getIntColumn("status"))
|
||||||
|
{
|
||||||
|
doiRow.setColumn("status", UPDATE_REGISTERED);
|
||||||
|
}
|
||||||
|
else if (TO_BE_REGISTERED == doiRow.getIntColumn("status"))
|
||||||
|
{
|
||||||
|
doiRow.setColumn("status", UPDATE_BEFORE_REGISTERATION);
|
||||||
|
}
|
||||||
|
else if (IS_RESERVED == doiRow.getIntColumn("status"))
|
||||||
|
{
|
||||||
|
doiRow.setColumn("status", UPDATE_RESERVERED);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseManager.update(context, doiRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateMetadataOnline(Context context, DSpaceObject dso, String identifier)
|
||||||
|
throws IdentifierException, SQLException
|
||||||
|
{
|
||||||
|
String doi = DOI.formatIdentifier(identifier);
|
||||||
|
|
||||||
|
// ensure DOI belongs to dso regarding our db
|
||||||
|
TableRow doiRow = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
doiRow = DatabaseManager.findByUnique(context, "Doi", "doi", 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);
|
||||||
|
}
|
||||||
|
if (null == doiRow)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if (doiRow.getIntColumn("resource_id") != dso.getID() ||
|
||||||
|
doiRow.getIntColumn("resource_type_id") != dso.getType())
|
||||||
|
{
|
||||||
|
log.error("Refuse to update metadata of DOI {} with the metadata of "
|
||||||
|
+ " an object ({}/{}) the DOI is not dedicated to.",
|
||||||
|
new String[] {doi, dso.getTypeText(), Integer.toString(dso.getID())});
|
||||||
|
throw new DOIIdentifierException("Cannot update DOI metadata: "
|
||||||
|
+ "DOI and DSpaceObject does not match!",
|
||||||
|
DOIIdentifierException.MISMATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DELETED == doiRow.getIntColumn("status") ||
|
||||||
|
TO_BE_DELETED == doiRow.getIntColumn("status"))
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("You tried to register a DOI that "
|
||||||
|
+ "is marked as DELETED.", DOIIdentifierException.DOI_IS_DELETED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// check if doi is reserved for this specific dso
|
||||||
|
if (connector.isDOIReserved(context, identifier))
|
||||||
|
{
|
||||||
|
// check if doi is reserved for this specific dso
|
||||||
|
if (!connector.isDOIReserved(context, dso, doi))
|
||||||
|
{
|
||||||
|
log.warn("Trying to update metadata for DOI {}, that is reserved"
|
||||||
|
+ " for another dso.", doi);
|
||||||
|
throw new DOIIdentifierException("Trying to update metadta for "
|
||||||
|
+ "a DOI that is reserved for another object.",
|
||||||
|
DOIIdentifierException.DOI_ALREADY_EXISTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connector.updateMetadata(context, dso, doi);
|
||||||
|
|
||||||
|
if (UPDATE_REGISTERED == doiRow.getIntColumn("status"))
|
||||||
|
{
|
||||||
|
doiRow.setColumn("status", IS_REGISTERED);
|
||||||
|
}
|
||||||
|
else if (UPDATE_BEFORE_REGISTERATION == doiRow.getIntColumn("status"))
|
||||||
|
{
|
||||||
|
doiRow.setColumn("status", TO_BE_REGISTERED);
|
||||||
|
}
|
||||||
|
else if (UPDATE_RESERVERED == doiRow.getIntColumn("status"))
|
||||||
|
{
|
||||||
|
doiRow.setColumn("status", IS_RESERVED);
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseManager.update(context, doiRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String mint(Context context, DSpaceObject dso)
|
||||||
|
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 "
|
||||||
|
+ dso.getTypeText() + " with ID " + dso.getID() + ".");
|
||||||
|
throw new RuntimeException("Error while attempting to retrieve " +
|
||||||
|
"information about a DOI for " + dso.getTypeText() +
|
||||||
|
" with ID " + dso.getID() + ".", e);
|
||||||
|
}
|
||||||
|
if (null == doi)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TableRow doiRow = loadOrCreateDOI(context, dso, null);
|
||||||
|
doi = DOI.SCHEME + doiRow.getStringColumn("doi");
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (SQLException e)
|
||||||
|
{
|
||||||
|
log.error("Error while creating new DOI for Object of " +
|
||||||
|
"ResourceType {} with id {}.", dso.getType(), dso.getID());
|
||||||
|
throw new RuntimeException("Error while attempting to create a " +
|
||||||
|
"new DOI for " + dso.getTypeText() + " with ID " +
|
||||||
|
dso.getID() + ".", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return doi;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DSpaceObject resolve(Context context, String identifier, String... attributes)
|
||||||
|
throws IdentifierNotFoundException, IdentifierNotResolvableException
|
||||||
|
{
|
||||||
|
String doi = null;
|
||||||
|
try {
|
||||||
|
doi = DOI.formatIdentifier(identifier);
|
||||||
|
} catch (IdentifierException e) {
|
||||||
|
throw new IdentifierNotResolvableException(e);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DSpaceObject dso = getObjectByDOI(context, doi);
|
||||||
|
if (null == dso)
|
||||||
|
{
|
||||||
|
throw new IdentifierNotFoundException();
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
catch (IdentifierException e)
|
||||||
|
{
|
||||||
|
throw new IdentifierNotResolvableException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String lookup(Context context, DSpaceObject dso)
|
||||||
|
throws IdentifierNotFoundException, IdentifierNotResolvableException
|
||||||
|
{
|
||||||
|
String doi = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
doi = getDOIByObject(context, dso);
|
||||||
|
}
|
||||||
|
catch (SQLException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Error retrieving DOI out of database.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null == doi)
|
||||||
|
{
|
||||||
|
throw new IdentifierNotFoundException("No DOI for DSpaceObject of type "
|
||||||
|
+ dso.getTypeText() + " with ID " + dso.getID() + " found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return doi;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(Context context, DSpaceObject dso)
|
||||||
|
throws IdentifierException
|
||||||
|
{
|
||||||
|
// delete all DOIs for this Item from our database.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String doi = getDOIByObject(context, dso);
|
||||||
|
while (null != doi)
|
||||||
|
{
|
||||||
|
this.delete(context, dso, doi);
|
||||||
|
doi = getDOIByObject(context, dso);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SQLException ex)
|
||||||
|
{
|
||||||
|
log.error("Error while attemping to retrieve information about a DOI for "
|
||||||
|
+ dso.getTypeText() + " with ID " + dso.getID() + ".", ex);
|
||||||
|
throw new RuntimeException("Error while attempting to retrieve " +
|
||||||
|
"information about a DOI for " + dso.getTypeText() +
|
||||||
|
" with ID " + dso.getID() + ".", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete all DOIs of this item out of its metadata
|
||||||
|
try {
|
||||||
|
String doi = getDOIOutOfObject(dso);
|
||||||
|
|
||||||
|
while (null != doi)
|
||||||
|
{
|
||||||
|
this.removeDOIFromObject(context, dso, doi);
|
||||||
|
doi = getDOIOutOfObject(dso);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (AuthorizeException ex)
|
||||||
|
{
|
||||||
|
log.error("Error while removing a DOI out of the metadata of an "
|
||||||
|
+ dso.getTypeText() + " with ID " + dso.getID() + ".", ex);
|
||||||
|
throw new RuntimeException("Error while removing a DOI out of the "
|
||||||
|
+ "metadata of an " + dso.getTypeText() + " with ID "
|
||||||
|
+ dso.getID() + ".", ex);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (SQLException ex)
|
||||||
|
{
|
||||||
|
log.error("Error while removing a DOI out of the metadata of an "
|
||||||
|
+ dso.getTypeText() + " with ID " + dso.getID() + ".", ex);
|
||||||
|
throw new RuntimeException("Error while removing a DOI out of the "
|
||||||
|
+ "metadata of an " + dso.getTypeText() + " with ID "
|
||||||
|
+ dso.getID() + ".", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(Context context, DSpaceObject dso, String identifier)
|
||||||
|
throws IdentifierException
|
||||||
|
{
|
||||||
|
String doi = DOI.formatIdentifier(identifier);
|
||||||
|
TableRow doiRow = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
doiRow = DatabaseManager.findByUnique(context, "Doi", "doi",
|
||||||
|
doi.substring(DOI.SCHEME.length()));
|
||||||
|
}
|
||||||
|
catch (SQLException sqle)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(sqle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if DOI belongs to dso
|
||||||
|
if (null != doiRow)
|
||||||
|
{
|
||||||
|
if (doiRow.getIntColumn("resource_id") != dso.getID() ||
|
||||||
|
doiRow.getIntColumn("resource_type_id") != dso.getType())
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("Trying to delete a DOI out of "
|
||||||
|
+ "an object that is not addressed by the DOI.",
|
||||||
|
DOIIdentifierException.MISMATCH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove DOI from metadata
|
||||||
|
try
|
||||||
|
{
|
||||||
|
removeDOIFromObject(context, dso, doi);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
catch (SQLException ex)
|
||||||
|
{
|
||||||
|
log.error("SQLException occured while deleting a DOI out of an item: "
|
||||||
|
+ ex.getMessage());
|
||||||
|
throw new RuntimeException("Error while deleting a DOI out of the " +
|
||||||
|
"metadata of an Item " + dso.getID(), ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// change doi status in db if necessary.
|
||||||
|
if (null != doiRow)
|
||||||
|
{
|
||||||
|
if(doiRow.isColumnNull("status"))
|
||||||
|
{
|
||||||
|
doiRow.setColumn("status", DELETED);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
doiRow.setColumn("status", TO_BE_DELETED);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
DatabaseManager.update(context, doiRow);
|
||||||
|
context.commit();
|
||||||
|
}
|
||||||
|
catch (SQLException sqle)
|
||||||
|
{
|
||||||
|
log.warn("SQLException while changing status of DOI {} to be deleted.", doi);
|
||||||
|
throw new RuntimeException(sqle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DOI is a permanent identifier. DataCite for example does not delete
|
||||||
|
// DOIS. But it is possible to mark a DOI as "inactive".
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteOnline(Context context, String identifier)
|
||||||
|
throws DOIIdentifierException
|
||||||
|
{
|
||||||
|
String doi = DOI.formatIdentifier(identifier);
|
||||||
|
TableRow doiRow = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
doiRow = DatabaseManager.findByUnique(context, "Doi", "doi",
|
||||||
|
doi.substring(DOI.SCHEME.length()));
|
||||||
|
}
|
||||||
|
catch (SQLException sqle)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(sqle);
|
||||||
|
}
|
||||||
|
if(null == doiRow)
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("This identifier: " + identifier
|
||||||
|
+ " isn't in our database",
|
||||||
|
DOIIdentifierException.DOI_DOES_NOT_EXIST);
|
||||||
|
}
|
||||||
|
if (TO_BE_DELETED != doiRow.getIntColumn("status"))
|
||||||
|
{
|
||||||
|
log.error("This identifier: {} couldn't be deleted. "
|
||||||
|
+ "Delete it first from metadata.",
|
||||||
|
DOI.SCHEME + doiRow.getStringColumn("doi"));
|
||||||
|
throw new IllegalArgumentException("Couldn't delete this identifier:"
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi")
|
||||||
|
+ ". Delete it first from metadata.");
|
||||||
|
}
|
||||||
|
connector.deleteDOI(context, doi);
|
||||||
|
|
||||||
|
doiRow.setColumn("status", DELETED);
|
||||||
|
try {
|
||||||
|
DatabaseManager.update(context, doiRow);
|
||||||
|
context.commit();
|
||||||
|
}
|
||||||
|
catch (SQLException sqle)
|
||||||
|
{
|
||||||
|
log.warn("SQLException while changing status of DOI {} deleted.", doi);
|
||||||
|
throw new RuntimeException(sqle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a DSpaceObject depending on its DOI.
|
||||||
|
* @param context the context
|
||||||
|
* @param identifier The DOI in a format that is accepted by
|
||||||
|
* {@link formatIdentifier(String)}.
|
||||||
|
* @return Null if the DOI couldn't be found or the associated DSpaceObject.
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws IdentifierException If {@code identifier} is null or an empty string.
|
||||||
|
* @throws IllegalArgumentException If the identifier couldn't be recognized as DOI.
|
||||||
|
*/
|
||||||
|
public static DSpaceObject getObjectByDOI(Context context, String identifier)
|
||||||
|
throws SQLException, DOIIdentifierException, IllegalArgumentException
|
||||||
|
{
|
||||||
|
String doi = DOI.formatIdentifier(identifier);
|
||||||
|
TableRow doiRow = DatabaseManager.findByUnique(context, "Doi", "doi",
|
||||||
|
doi.substring(DOI.SCHEME.length()));
|
||||||
|
|
||||||
|
if (null == doiRow)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doiRow.isColumnNull("resource_type_id") ||
|
||||||
|
doiRow.isColumnNull("resource_id"))
|
||||||
|
{
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return DSpaceObject.find(context,
|
||||||
|
doiRow.getIntColumn("resource_type_id"),
|
||||||
|
doiRow.getIntColumn("resource_id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search the database for a DOI, using the type and id of an DSpaceObject.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param dso DSpaceObject to find doi for. DOIs with status TO_BE_DELETED will be
|
||||||
|
* ignored.
|
||||||
|
* @return The DOI as String or null if DOI was not found.
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
public static 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)";
|
||||||
|
|
||||||
|
TableRow doiRow = DatabaseManager.querySingleTable(context, "Doi", sql,
|
||||||
|
dso.getType(), dso.getID(), DOIIdentifierProvider.TO_BE_DELETED,
|
||||||
|
DOIIdentifierProvider.DELETED);
|
||||||
|
if (null == doiRow)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doiRow.isColumnNull("doi"))
|
||||||
|
{
|
||||||
|
log.error("A DOI with an empty doi column was found in the database. DSO-Type: "
|
||||||
|
+ dso.getTypeText() + ", ID: " + dso.getID() + ".");
|
||||||
|
throw new IllegalStateException("A DOI with an empty doi column " +
|
||||||
|
"was found in the database. DSO-Type: " + dso.getTypeText() +
|
||||||
|
", ID: " + dso.getID() + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
return DOI.SCHEME + doiRow.getStringColumn("doi");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a DOI from the database or creates it if it does not exist. This
|
||||||
|
* method can be used to ensure that a DOI exists in the database and to
|
||||||
|
* load the appropriate TableRow. As protected method we don't check if the
|
||||||
|
* DOI is in a decent format, use DOI.formatIdentifier(String) if necessary.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @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
|
||||||
|
* can be found in the appropriate column for the TableRow.
|
||||||
|
* @return The database row of the object.
|
||||||
|
* @throws SQLException In case of an error using the database.
|
||||||
|
* @throws DOIIdentifierException If {@code doi} is not part of our prefix or
|
||||||
|
* DOI is registered for another object already.
|
||||||
|
*/
|
||||||
|
protected TableRow loadOrCreateDOI(Context context, DSpaceObject dso, String doi)
|
||||||
|
throws SQLException, DOIIdentifierException
|
||||||
|
{
|
||||||
|
TableRow doiRow = null;
|
||||||
|
if (null != doi)
|
||||||
|
{
|
||||||
|
// we expect DOIs to have the DOI-Scheme except inside the doi table:
|
||||||
|
doi = doi.substring(DOI.SCHEME.length());
|
||||||
|
|
||||||
|
// check if DOI is already in Database
|
||||||
|
doiRow = DatabaseManager.findByUnique(context, "Doi", "doi", doi);
|
||||||
|
if (null != doiRow)
|
||||||
|
{
|
||||||
|
// check if DOI already belongs to dso
|
||||||
|
if (doiRow.getIntColumn("resource_id") == dso.getID() &&
|
||||||
|
doiRow.getIntColumn("resource_type_id") == dso.getType())
|
||||||
|
{
|
||||||
|
return doiRow;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("Trying to create a DOI " +
|
||||||
|
"that is already reserved for another object.",
|
||||||
|
DOIIdentifierException.DOI_ALREADY_EXISTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check prefix
|
||||||
|
if (!doi.startsWith(this.getPrefix() + "/"))
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("Trying to create a DOI " +
|
||||||
|
"that's not part of our Namespace!",
|
||||||
|
DOIIdentifierException.FOREIGN_DOI);
|
||||||
|
}
|
||||||
|
// prepare new doiRow
|
||||||
|
doiRow = DatabaseManager.create(context, "Doi");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We need to generate a new DOI.
|
||||||
|
doiRow = DatabaseManager.create(context, "Doi");
|
||||||
|
|
||||||
|
doi = this.getPrefix() + "/" + this.getNamespaceSeparator() +
|
||||||
|
doiRow.getIntColumn("doi_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
doiRow.setColumn("doi", doi);
|
||||||
|
doiRow.setColumn("resource_type_id", dso.getType());
|
||||||
|
doiRow.setColumn("resource_id", dso.getID());
|
||||||
|
doiRow.setColumnNull("status");
|
||||||
|
if (0 == DatabaseManager.update(context, doiRow))
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Cannot save DOI to databse for unkown reason.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return doiRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a DOI out of the metadata of an DSpaceObject.
|
||||||
|
* @param dso
|
||||||
|
* @return The DOI or null if no DOI was found.
|
||||||
|
*/
|
||||||
|
public static String getDOIOutOfObject(DSpaceObject dso)
|
||||||
|
throws DOIIdentifierException {
|
||||||
|
// FIXME
|
||||||
|
if (!(dso instanceof Item))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("We currently support DOIs for "
|
||||||
|
+ "Items only, not for " + dso.getTypeText() + ".");
|
||||||
|
}
|
||||||
|
Item item = (Item)dso;
|
||||||
|
|
||||||
|
DCValue[] metadata = item.getMetadata(MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null);
|
||||||
|
for (DCValue id : metadata)
|
||||||
|
{
|
||||||
|
if (id.value.startsWith(DOI.RESOLVER + "/10."))
|
||||||
|
{
|
||||||
|
return DOI.DOIFromExternalFormat(id.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a DOI to the metadata of an item.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param dso DSpaceObject the DOI should be added to.
|
||||||
|
* @param doi The DOI that should be added as metadata.
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws AuthorizeException
|
||||||
|
*/
|
||||||
|
protected void saveDOIToObject(Context context, DSpaceObject dso, String doi)
|
||||||
|
throws SQLException, AuthorizeException, IdentifierException
|
||||||
|
{
|
||||||
|
// FIXME
|
||||||
|
if (!(dso instanceof Item))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("We currently support DOIs for "
|
||||||
|
+ "Items only, not for " + dso.getTypeText() + ".");
|
||||||
|
}
|
||||||
|
Item item = (Item) dso;
|
||||||
|
|
||||||
|
item.addMetadata(MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null, DOI.DOIToExternalForm(doi));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
item.update();
|
||||||
|
context.commit();
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
throw ex;
|
||||||
|
} catch (AuthorizeException ex) {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a DOI out of the metadata of a DSpaceObject.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param dso The DSpaceObject the DOI should be removed from.
|
||||||
|
* @param doi The DOI to remove out of the metadata.
|
||||||
|
* @throws AuthorizeException
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
protected void removeDOIFromObject(Context context, DSpaceObject dso, String doi)
|
||||||
|
throws AuthorizeException, SQLException, IdentifierException
|
||||||
|
{
|
||||||
|
// FIXME
|
||||||
|
if (!(dso instanceof Item))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("We currently support DOIs for "
|
||||||
|
+ "Items only, not for " + dso.getTypeText() + ".");
|
||||||
|
}
|
||||||
|
Item item = (Item)dso;
|
||||||
|
|
||||||
|
DCValue[] metadata = item.getMetadata(MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null);
|
||||||
|
List<String> remainder = new ArrayList<String>();
|
||||||
|
|
||||||
|
for (DCValue id : metadata)
|
||||||
|
{
|
||||||
|
if (!id.value.equals(DOI.DOIToExternalForm(doi)))
|
||||||
|
{
|
||||||
|
remainder.add(id.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item.clearMetadata(MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null);
|
||||||
|
item.addMetadata(MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null,
|
||||||
|
remainder.toArray(new String[remainder.size()]));
|
||||||
|
try {
|
||||||
|
item.update();
|
||||||
|
context.commit();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (AuthorizeException e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -36,23 +36,100 @@ public abstract class IdentifierProvider {
|
|||||||
this.parentService = parentService;
|
this.parentService = parentService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can this provider provide identifiers of a given type?
|
||||||
|
*
|
||||||
|
* @param identifier requested type.
|
||||||
|
* @return true if the given type is assignable from this provider's type.
|
||||||
|
*/
|
||||||
public abstract boolean supports(Class<? extends Identifier> identifier);
|
public abstract boolean supports(Class<? extends Identifier> identifier);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can this provider provide identifiers of a given type?
|
||||||
|
*
|
||||||
|
* @param identifier requested type.
|
||||||
|
* @return true if this provider can provide the named type of identifier.
|
||||||
|
*/
|
||||||
public abstract boolean supports(String identifier);
|
public abstract boolean supports(String identifier);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and apply an identifier to a DSpaceObject.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param item object to be named.
|
||||||
|
* @return existing identifier of {@code item} if it has one, else a new identifier.
|
||||||
|
* @throws IdentifierException
|
||||||
|
*/
|
||||||
public abstract String register(Context context, DSpaceObject item) throws IdentifierException;
|
public abstract String register(Context context, DSpaceObject item) throws IdentifierException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an identifier for a DSpaceObject.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param dso object to be named.
|
||||||
|
* @return existing identifier of {@code dso} if it has one, else a new identifier.
|
||||||
|
* @throws IdentifierException
|
||||||
|
*/
|
||||||
public abstract String mint(Context context, DSpaceObject dso) throws IdentifierException;
|
public abstract String mint(Context context, DSpaceObject dso) throws IdentifierException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the object named by a given identifier.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param identifier to be resolved.
|
||||||
|
* @param attributes additional information for resolving {@code identifier}.
|
||||||
|
* @return the named object.
|
||||||
|
* @throws IdentifierNotFoundException
|
||||||
|
* @throws IdentifierNotResolvableException
|
||||||
|
*/
|
||||||
public abstract DSpaceObject resolve(Context context, String identifier, String... attributes) throws IdentifierNotFoundException, IdentifierNotResolvableException;;
|
public abstract DSpaceObject resolve(Context context, String identifier, String... attributes) throws IdentifierNotFoundException, IdentifierNotResolvableException;;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the identifier for a DSpaceObject.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param object The object to be looked up.
|
||||||
|
* @return identifier for {@code object}.
|
||||||
|
* @throws IdentifierNotFoundException
|
||||||
|
* @throws IdentifierNotResolvableException
|
||||||
|
*/
|
||||||
public abstract String lookup(Context context, DSpaceObject object) throws IdentifierNotFoundException, IdentifierNotResolvableException;;
|
public abstract String lookup(Context context, DSpaceObject object) throws IdentifierNotFoundException, IdentifierNotResolvableException;;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unbind this type of identifier(s) from an object.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param dso object to lose its identity.
|
||||||
|
* @throws IdentifierException
|
||||||
|
*/
|
||||||
public abstract void delete(Context context, DSpaceObject dso) throws IdentifierException;
|
public abstract void delete(Context context, DSpaceObject dso) throws IdentifierException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unbind the given identifier from an object.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param dso object to be de-identified.
|
||||||
|
* @param identifier to be removed.
|
||||||
|
* @throws IdentifierException
|
||||||
|
*/
|
||||||
public abstract void delete(Context context, DSpaceObject dso, String identifier) throws IdentifierException;
|
public abstract void delete(Context context, DSpaceObject dso, String identifier) throws IdentifierException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an object's identifier.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param dso object to be identified.
|
||||||
|
* @param identifier to be set on the object.
|
||||||
|
* @throws IdentifierException
|
||||||
|
*/
|
||||||
public abstract void reserve(Context context, DSpaceObject dso, String identifier) throws IdentifierException;
|
public abstract void reserve(Context context, DSpaceObject dso, String identifier) throws IdentifierException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a specific identifier and apply it to an object.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param object to be identified.
|
||||||
|
* @param identifier to be created.
|
||||||
|
*/
|
||||||
public abstract void register(Context context, DSpaceObject object, String identifier) throws IdentifierException;
|
public abstract void register(Context context, DSpaceObject object, String identifier) throws IdentifierException;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,107 @@
|
|||||||
|
/**
|
||||||
|
* 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.doi;
|
||||||
|
|
||||||
|
import org.dspace.content.DSpaceObject;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A DOIConnector handles all calls to the API of your DOI registry.
|
||||||
|
*
|
||||||
|
* Please pay attention to the method {@link #purgeCachedInformation()}!
|
||||||
|
*
|
||||||
|
* @author Pascal-Nicolas Becker
|
||||||
|
*/
|
||||||
|
public interface DOIConnector {
|
||||||
|
public boolean isDOIReserved(Context context, String doi)
|
||||||
|
throws DOIIdentifierException;
|
||||||
|
|
||||||
|
public boolean isDOIReserved(Context context, DSpaceObject dso, String doi)
|
||||||
|
throws DOIIdentifierException;
|
||||||
|
|
||||||
|
public boolean isDOIRegistered(Context context, String doi)
|
||||||
|
throws DOIIdentifierException;
|
||||||
|
|
||||||
|
public boolean isDOIRegistered(Context context, DSpaceObject dso, String doi)
|
||||||
|
throws DOIIdentifierException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the DELETE-Request to the DOI registry.
|
||||||
|
*
|
||||||
|
* <p>This method sends a request to "delete" a DOI. As DOIs are persistant
|
||||||
|
* identifiers they should never be deleted. For example, if you send a HTTP
|
||||||
|
* DELETE request to the DataCite Metadata API directly, it will set the DOI
|
||||||
|
* to inactive.</p>
|
||||||
|
*
|
||||||
|
* <p>A DOIConnector does not have to check whether the DOI is reserved,
|
||||||
|
* registered or not. It will only send the request and return the answer in
|
||||||
|
* form of a boolean weather the deletion was successful or not. It may even
|
||||||
|
* throw an DOIIdentifierException in case you are not allowed to delete a
|
||||||
|
* DOI, the DOI does not exist, ... So please be sure that the deletion of a
|
||||||
|
* DOI is conform with the rules of the registry and that the DOI is in the
|
||||||
|
* appropriate state (f.e. reserved but not registered).</p>
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param doi
|
||||||
|
* @return
|
||||||
|
* @throws DOIIdentifierException
|
||||||
|
*/
|
||||||
|
public void deleteDOI(Context context, String doi)
|
||||||
|
throws DOIIdentifierException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a request to the DOI registry to reserve a DOI.
|
||||||
|
*
|
||||||
|
* Please check on your own if the DOI is already reserved or even
|
||||||
|
* registered before you try to reserve it. You can use
|
||||||
|
* {@link isDOIRegistered} and {@link isDOIReserved} for it. The
|
||||||
|
* DOIConnector won't do any tests and throws an DOIIdentifierException in
|
||||||
|
* case of any problems with the DOI you want to reserve.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param dso
|
||||||
|
* @param doi
|
||||||
|
* @return
|
||||||
|
* @throws DOIIdentifierException
|
||||||
|
*/
|
||||||
|
public void reserveDOI(Context context, DSpaceObject dso, String doi)
|
||||||
|
throws DOIIdentifierException;
|
||||||
|
/**
|
||||||
|
* Sends a request to the DOI registry to register a DOI.
|
||||||
|
*
|
||||||
|
* Please check on your own if the DOI is already reserved or even
|
||||||
|
* registered before you try to register it. You can use the methods
|
||||||
|
* {@code DOIConnector.isDOIRegistered(...)} and
|
||||||
|
* {@code DOIConnector.isDOIReserved(...)} for it. The DOIConnector won't
|
||||||
|
* do any tests and throws an DOIIdentifierException in case of any problems
|
||||||
|
* with the DOI you want to register.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param dso
|
||||||
|
* @param doi
|
||||||
|
* @return
|
||||||
|
* @throws DOIIdentifierException
|
||||||
|
*/
|
||||||
|
public void registerDOI(Context context, DSpaceObject dso, String doi)
|
||||||
|
throws DOIIdentifierException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a request to the DOI registry to update Metadate for a DOI.
|
||||||
|
* The DOIConnector won't do any tests and throws an IdentifierException
|
||||||
|
* in case of any problems with the DOI you want to update the metadata.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param dso
|
||||||
|
* @param doi
|
||||||
|
* @return
|
||||||
|
* @throws IdentifierException
|
||||||
|
*/
|
||||||
|
public void updateMetadata(Context context, DSpaceObject dso, String doi)
|
||||||
|
throws DOIIdentifierException;
|
||||||
|
}
|
@@ -0,0 +1,108 @@
|
|||||||
|
/**
|
||||||
|
* 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.doi;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.dspace.content.DSpaceObject;
|
||||||
|
import org.dspace.content.Item;
|
||||||
|
import org.dspace.core.Constants;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.event.Consumer;
|
||||||
|
import org.dspace.event.Event;
|
||||||
|
import org.dspace.identifier.DOIIdentifierProvider;
|
||||||
|
import org.dspace.identifier.IdentifierException;
|
||||||
|
import org.dspace.identifier.IdentifierNotFoundException;
|
||||||
|
import org.dspace.search.SearchConsumer;
|
||||||
|
import org.dspace.utils.DSpace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Pascal-Nicolas Becker (p dot becker at tu hyphen berlin dot de)
|
||||||
|
*/
|
||||||
|
public class DOIConsumer implements Consumer
|
||||||
|
{
|
||||||
|
/** log4j logger */
|
||||||
|
private static Logger log = Logger.getLogger(DOIConsumer.class);
|
||||||
|
|
||||||
|
@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.
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// as we use asynchronous metadata update, our updates are not very expensive.
|
||||||
|
// so we can do everything in the consume method.
|
||||||
|
@Override
|
||||||
|
public void consume(Context ctx, Event event) throws Exception {
|
||||||
|
if (event.getSubjectType() != Constants.ITEM)
|
||||||
|
{
|
||||||
|
log.warn("DOIConsumer should not have been given this kind of "
|
||||||
|
+ "subject in an event, skipping: " + event.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Event.MODIFY_METADATA != event.getEventType())
|
||||||
|
{
|
||||||
|
log.warn("DOIConsumer should not have been given this kind of "
|
||||||
|
+ "event type, skipping: " + event.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DSpaceObject dso = event.getSubject(ctx);
|
||||||
|
//FIXME
|
||||||
|
if (!(dso instanceof Item))
|
||||||
|
{
|
||||||
|
log.warn("DOIConsumer got an event whose subject was not an item, "
|
||||||
|
+ "skipping: " + event.toString());
|
||||||
|
}
|
||||||
|
Item item = (Item) dso;
|
||||||
|
|
||||||
|
DOIIdentifierProvider provider = new DSpace().getSingletonService(
|
||||||
|
DOIIdentifierProvider.class);
|
||||||
|
|
||||||
|
String doi = null;
|
||||||
|
try {
|
||||||
|
doi = provider.lookup(ctx, dso);
|
||||||
|
}
|
||||||
|
catch (IdentifierNotFoundException ex)
|
||||||
|
{
|
||||||
|
log.warn("DOIConsumer cannot handles items without DOIs, skipping: "
|
||||||
|
+ event.toString());
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void end(Context ctx) throws Exception {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish(Context ctx) throws Exception {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,175 @@
|
|||||||
|
/**
|
||||||
|
* 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.doi;
|
||||||
|
|
||||||
|
import org.dspace.identifier.IdentifierException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Pascal-Nicolas Becker (p dot becker at tu hyphen berlin dot de)
|
||||||
|
*/
|
||||||
|
public class DOIIdentifierException extends IdentifierException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default.
|
||||||
|
*/
|
||||||
|
public static final int CODE_NOT_SET = 0;
|
||||||
|
/**
|
||||||
|
* A specified DOI does not exists.
|
||||||
|
*/
|
||||||
|
public static final int DOI_DOES_NOT_EXIST = 1;
|
||||||
|
/**
|
||||||
|
* A DOI cannot be created, registered, reserved, and so on because it is
|
||||||
|
* already used for another object.
|
||||||
|
*/
|
||||||
|
public static final int DOI_ALREADY_EXISTS = 2;
|
||||||
|
/**
|
||||||
|
* A DOI cannot be created, registered, reserved and so on because it uses a
|
||||||
|
* foreign prefix.
|
||||||
|
*/
|
||||||
|
public static final int FOREIGN_DOI = 3;
|
||||||
|
/**
|
||||||
|
* We got a answer from a registration agency that could not be parsed.
|
||||||
|
* Either they changed there API or the DOIConnector does not implement it
|
||||||
|
* properly.
|
||||||
|
*/
|
||||||
|
public static final int BAD_ANSWER = 4;
|
||||||
|
/**
|
||||||
|
* The registration agency was unable to parse our request. Either they
|
||||||
|
* changed there API or the DOIConnector does not implement it properly.
|
||||||
|
*/
|
||||||
|
public static final int BAD_REQUEST = 5;
|
||||||
|
/**
|
||||||
|
* Some registration agencies request that a DOI gets reserved before it can
|
||||||
|
* be registered. This error code signals that a unreserved DOI should be
|
||||||
|
* registered and that the registration agency denied it.
|
||||||
|
*/
|
||||||
|
public static final int REGISTER_FIRST = 6;
|
||||||
|
/**
|
||||||
|
* Error while authenticating against the registration agency.
|
||||||
|
*/
|
||||||
|
public static final int AUTHENTICATION_ERROR = 7;
|
||||||
|
/**
|
||||||
|
* A internal error occurred either in the registration agency or in the
|
||||||
|
* DOIConnector.
|
||||||
|
*/
|
||||||
|
public static final int INTERNAL_ERROR = 8;
|
||||||
|
/**
|
||||||
|
* An error arose while metadata conversion.
|
||||||
|
*/
|
||||||
|
public static final int CONVERSION_ERROR = 9;
|
||||||
|
/**
|
||||||
|
* A DOI and a provided object does not match. This error occurs if you try
|
||||||
|
* to connect an object with a DOI that is reserved or registered for
|
||||||
|
* another object.
|
||||||
|
*/
|
||||||
|
public static final int MISMATCH = 10;
|
||||||
|
/**
|
||||||
|
* An identifier supplied as DOI could not be recognized.
|
||||||
|
*/
|
||||||
|
public static final int UNRECOGNIZED = 11;
|
||||||
|
/**
|
||||||
|
* DSpace did not allowed to manipulate the metadata of an DSpaceObject.
|
||||||
|
*/
|
||||||
|
public static final int UNAUTHORIZED_METADATA_MANIPULATION = 12;
|
||||||
|
/**
|
||||||
|
* You tried to reserve or register a DOI that is marked as DELETED.
|
||||||
|
*/
|
||||||
|
public static final int DOI_IS_DELETED = 13;
|
||||||
|
|
||||||
|
private int code;
|
||||||
|
|
||||||
|
// FOR DEBUGGING
|
||||||
|
public static String codeToString(int code) {
|
||||||
|
switch (code) {
|
||||||
|
case CODE_NOT_SET:
|
||||||
|
return "CODE_NOT_SET";
|
||||||
|
case DOI_DOES_NOT_EXIST:
|
||||||
|
return "DOI_DOES_NOT_EXSIT";
|
||||||
|
case DOI_ALREADY_EXISTS:
|
||||||
|
return "DOI_ALREADY_EXISTS";
|
||||||
|
case FOREIGN_DOI:
|
||||||
|
return "FOREIGN_DOI";
|
||||||
|
case BAD_ANSWER:
|
||||||
|
return "BAD_ANSWER";
|
||||||
|
case REGISTER_FIRST:
|
||||||
|
return "REGISTER_FIRST";
|
||||||
|
case AUTHENTICATION_ERROR:
|
||||||
|
return "AUTHENTICATION_ERROR";
|
||||||
|
case INTERNAL_ERROR:
|
||||||
|
return "INTERNAL_ERROR";
|
||||||
|
case CONVERSION_ERROR:
|
||||||
|
return "CONVERSION_ERROR";
|
||||||
|
case MISMATCH:
|
||||||
|
return "MISMATCH";
|
||||||
|
case UNRECOGNIZED:
|
||||||
|
return "UNRECOGNIZED";
|
||||||
|
case UNAUTHORIZED_METADATA_MANIPULATION:
|
||||||
|
return "UNAUTHORIZED_METADATA_MANIPULATION";
|
||||||
|
case DOI_IS_DELETED:
|
||||||
|
return "DELETED";
|
||||||
|
default:
|
||||||
|
return "UNKOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DOIIdentifierException() {
|
||||||
|
super();
|
||||||
|
this.code = this.CODE_NOT_SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DOIIdentifierException(int code) {
|
||||||
|
super();
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DOIIdentifierException(String message) {
|
||||||
|
super(message);
|
||||||
|
this.code = this.CODE_NOT_SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DOIIdentifierException(String message, int code) {
|
||||||
|
super(message);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DOIIdentifierException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
this.code = this.CODE_NOT_SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DOIIdentifierException(String message, Throwable cause, int code) {
|
||||||
|
super(message, cause);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DOIIdentifierException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
this.code = this.CODE_NOT_SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DOIIdentifierException(Throwable cause, int code) {
|
||||||
|
super(cause);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode()
|
||||||
|
{
|
||||||
|
return this.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage()
|
||||||
|
{
|
||||||
|
String message = super.getMessage();
|
||||||
|
if ((message == null || message.isEmpty()) && code != CODE_NOT_SET)
|
||||||
|
{
|
||||||
|
return codeToString(code);
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,936 @@
|
|||||||
|
/**
|
||||||
|
* 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.doi;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
import org.apache.commons.cli.CommandLine;
|
||||||
|
import org.apache.commons.cli.CommandLineParser;
|
||||||
|
import org.apache.commons.cli.HelpFormatter;
|
||||||
|
import org.apache.commons.cli.Option;
|
||||||
|
import org.apache.commons.cli.OptionBuilder;
|
||||||
|
import org.apache.commons.cli.Options;
|
||||||
|
import org.apache.commons.cli.ParseException;
|
||||||
|
import org.apache.commons.cli.PosixParser;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.dspace.content.DSpaceObject;
|
||||||
|
import org.dspace.content.Item;
|
||||||
|
import org.dspace.core.ConfigurationManager;
|
||||||
|
import org.dspace.core.Constants;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.core.Email;
|
||||||
|
import org.dspace.core.I18nUtil;
|
||||||
|
import org.dspace.handle.HandleManager;
|
||||||
|
import org.dspace.identifier.DOI;
|
||||||
|
import org.dspace.identifier.DOIIdentifierProvider;
|
||||||
|
import org.dspace.identifier.IdentifierException;
|
||||||
|
import org.dspace.storage.rdbms.DatabaseManager;
|
||||||
|
import org.dspace.storage.rdbms.TableRow;
|
||||||
|
import org.dspace.storage.rdbms.TableRowIterator;
|
||||||
|
import org.dspace.utils.DSpace;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Marsa Haoua
|
||||||
|
* @author Pascal-Nicolas Becker
|
||||||
|
*/
|
||||||
|
public class DOIOrganiser {
|
||||||
|
|
||||||
|
private static final Logger LOG = Logger.getLogger(DOIOrganiser.class);
|
||||||
|
|
||||||
|
private DOIIdentifierProvider provider;
|
||||||
|
private Context context;
|
||||||
|
private boolean quiet;
|
||||||
|
|
||||||
|
public DOIOrganiser(Context context, DOIIdentifierProvider provider)
|
||||||
|
{
|
||||||
|
this.context = context;
|
||||||
|
this.provider = provider;
|
||||||
|
this.quiet = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
{
|
||||||
|
LOG.debug("Starting DOI organiser ");
|
||||||
|
|
||||||
|
// setup Context
|
||||||
|
Context context = null;
|
||||||
|
try {
|
||||||
|
context = new Context();
|
||||||
|
}
|
||||||
|
catch (SQLException sqle)
|
||||||
|
{
|
||||||
|
System.err.println("Can't connect to database: " + sqle.getMessage());
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
// Started from commandline, don't use the authentication system.
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
DOIOrganiser organiser = new DOIOrganiser(context, new DSpace().getSingletonService(DOIIdentifierProvider.class));
|
||||||
|
|
||||||
|
// run command line interface
|
||||||
|
runCLI(context, organiser, args);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
context.complete();
|
||||||
|
}
|
||||||
|
catch (SQLException sqle)
|
||||||
|
{
|
||||||
|
System.err.println("Cannot save changes to database: " + sqle.getMessage());
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void runCLI(Context context, DOIOrganiser organiser, String[] args)
|
||||||
|
{
|
||||||
|
// initlize options
|
||||||
|
Options options = new Options();
|
||||||
|
|
||||||
|
options.addOption("h", "help", false, "Help");
|
||||||
|
options.addOption("l", "list", false,
|
||||||
|
"List all objects to be reserved, registered, deleted of updated ");
|
||||||
|
options.addOption("r", "register-all", false,
|
||||||
|
"Perform online registration for all identifiers queued for registration.");
|
||||||
|
options.addOption("s", "reserve-all", false,
|
||||||
|
"Perform online reservation for all identifiers queued for reservation.");
|
||||||
|
options.addOption("u", "update-all", false,
|
||||||
|
"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.");
|
||||||
|
|
||||||
|
Option registerDoi = OptionBuilder.withArgName("DOI|ItemID|handle")
|
||||||
|
.withLongOpt("register-doi")
|
||||||
|
.hasArgs(1)
|
||||||
|
.withDescription("Register a specified identifier. "
|
||||||
|
+ "You can specify the identifier by ItemID, Handle or DOI.")
|
||||||
|
.create();
|
||||||
|
|
||||||
|
options.addOption(registerDoi);
|
||||||
|
|
||||||
|
Option reserveDoi = OptionBuilder.withArgName("DOI|ItemID|handle")
|
||||||
|
.withLongOpt("reserve-doi")
|
||||||
|
.hasArgs(1)
|
||||||
|
.withDescription("Reserve a specified identifier online. "
|
||||||
|
+ "You can specify the identifier by ItemID, Handle or DOI.")
|
||||||
|
.create();
|
||||||
|
|
||||||
|
options.addOption(reserveDoi);
|
||||||
|
|
||||||
|
Option update = OptionBuilder.withArgName("DOI|ItemID|handle")
|
||||||
|
.hasArgs(1)
|
||||||
|
.withDescription("Update online an object for a given DOI identifier"
|
||||||
|
+ " or ItemID or Handle. A DOI identifier or an ItemID or a Handle is needed.\n")
|
||||||
|
.withLongOpt("update-doi")
|
||||||
|
.create();
|
||||||
|
|
||||||
|
options.addOption(update);
|
||||||
|
|
||||||
|
Option delete = OptionBuilder.withArgName("DOI identifier")
|
||||||
|
.withLongOpt("delete-doi")
|
||||||
|
.hasArgs(1)
|
||||||
|
.withDescription("Delete a specified identifier.")
|
||||||
|
.create();
|
||||||
|
|
||||||
|
options.addOption(delete);
|
||||||
|
|
||||||
|
|
||||||
|
// initialize parser
|
||||||
|
CommandLineParser parser = new PosixParser();
|
||||||
|
CommandLine line = null;
|
||||||
|
HelpFormatter helpformater = new HelpFormatter();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
line = parser.parse(options, args);
|
||||||
|
}
|
||||||
|
catch (ParseException ex)
|
||||||
|
{
|
||||||
|
LOG.fatal(ex);
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// process options
|
||||||
|
// user asks for help
|
||||||
|
if (line.hasOption('h') || 0 == line.getOptions().length)
|
||||||
|
{
|
||||||
|
helpformater.printHelp("\nDOI organiser\n", options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.hasOption('q'))
|
||||||
|
{
|
||||||
|
organiser.setQuiet();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.hasOption('l'))
|
||||||
|
{
|
||||||
|
organiser.list("reservation", null, null, DOIIdentifierProvider.TO_BE_RESERVERED);
|
||||||
|
organiser.list("registration", null, null, DOIIdentifierProvider.TO_BE_REGISTERED);
|
||||||
|
organiser.list("update", null, null,
|
||||||
|
DOIIdentifierProvider.UPDATE_BEFORE_REGISTERATION,
|
||||||
|
DOIIdentifierProvider.UPDATE_REGISTERED,
|
||||||
|
DOIIdentifierProvider.UPDATE_RESERVERED);
|
||||||
|
organiser.list("deletion", null, null, DOIIdentifierProvider.TO_BE_DELETED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.hasOption('s'))
|
||||||
|
{
|
||||||
|
TableRowIterator it = organiser
|
||||||
|
.getDOIsByStatus(DOIIdentifierProvider.TO_BE_RESERVERED);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!it.hasNext())
|
||||||
|
{
|
||||||
|
System.err.println("There are no objects in the database "
|
||||||
|
+ "that could be reserved.");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
TableRow doiRow = it.next();
|
||||||
|
DSpaceObject dso = DSpaceObject.find(
|
||||||
|
context,
|
||||||
|
doiRow.getIntColumn("resource_type_id"),
|
||||||
|
doiRow.getIntColumn("resource_id"));
|
||||||
|
organiser.reserve(doiRow, dso);
|
||||||
|
}
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
System.err.println("Error in database connection:" + ex.getMessage());
|
||||||
|
ex.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.hasOption('r'))
|
||||||
|
{
|
||||||
|
TableRowIterator it = organiser
|
||||||
|
.getDOIsByStatus(DOIIdentifierProvider.TO_BE_REGISTERED);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!it.hasNext())
|
||||||
|
{
|
||||||
|
System.err.println("There are no objects in the database "
|
||||||
|
+ "that could be registered.");
|
||||||
|
}
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
TableRow doiRow = it.next();
|
||||||
|
DSpaceObject dso = DSpaceObject.find(
|
||||||
|
context,
|
||||||
|
doiRow.getIntColumn("resource_type_id"),
|
||||||
|
doiRow.getIntColumn("resource_id"));
|
||||||
|
organiser.register(doiRow, dso);
|
||||||
|
}
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
System.err.println("Error in database connection:" + ex.getMessage());
|
||||||
|
ex.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.hasOption('u'))
|
||||||
|
{
|
||||||
|
TableRowIterator it = organiser.getDOIsByStatus(
|
||||||
|
DOIIdentifierProvider.UPDATE_BEFORE_REGISTERATION,
|
||||||
|
DOIIdentifierProvider.UPDATE_RESERVERED,
|
||||||
|
DOIIdentifierProvider.UPDATE_REGISTERED);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!it.hasNext())
|
||||||
|
{
|
||||||
|
System.err.println("There are no objects in the database "
|
||||||
|
+ "whose metadata needs an update.");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
TableRow doiRow = it.next();
|
||||||
|
DSpaceObject dso = DSpaceObject.find(
|
||||||
|
context,
|
||||||
|
doiRow.getIntColumn("resource_type_id"),
|
||||||
|
doiRow.getIntColumn("resource_id"));
|
||||||
|
organiser.update(doiRow, dso);
|
||||||
|
}
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
System.err.println("Error in database connection:" + ex.getMessage());
|
||||||
|
ex.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.hasOption('d'))
|
||||||
|
{
|
||||||
|
TableRowIterator it = organiser
|
||||||
|
.getDOIsByStatus(DOIIdentifierProvider.TO_BE_DELETED);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!it.hasNext())
|
||||||
|
{
|
||||||
|
System.err.println("There are no objects in the database "
|
||||||
|
+ "that could be deleted.");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
TableRow doiRow = it.next();
|
||||||
|
organiser.delete(doiRow.getStringColumn("doi"));
|
||||||
|
}
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
System.err.println("Error in database connection:" + ex.getMessage());
|
||||||
|
ex.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(line.hasOption("reserve-doi"))
|
||||||
|
{
|
||||||
|
String identifier = line.getOptionValue("reserve-doi");
|
||||||
|
|
||||||
|
if(null == identifier)
|
||||||
|
{
|
||||||
|
helpformater.printHelp("\nDOI organiser\n", options);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
TableRow doiRow = organiser.findTableRow(identifier);
|
||||||
|
DSpaceObject dso = DSpaceObject.find(
|
||||||
|
context,
|
||||||
|
doiRow.getIntColumn("resource_type_id"),
|
||||||
|
doiRow.getIntColumn("resource_id"));
|
||||||
|
organiser.reserve(doiRow, dso);
|
||||||
|
}
|
||||||
|
catch (SQLException ex)
|
||||||
|
{
|
||||||
|
LOG.error(ex);
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException ex)
|
||||||
|
{
|
||||||
|
LOG.error(ex);
|
||||||
|
}
|
||||||
|
catch (IllegalStateException ex)
|
||||||
|
{
|
||||||
|
LOG.error(ex);
|
||||||
|
} catch (IdentifierException ex) {
|
||||||
|
LOG.error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(line.hasOption("register-doi"))
|
||||||
|
{
|
||||||
|
String identifier = line.getOptionValue("register-doi");
|
||||||
|
|
||||||
|
if(null == identifier)
|
||||||
|
{
|
||||||
|
helpformater.printHelp("\nDOI organiser\n", options);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
TableRow doiRow = organiser.findTableRow(identifier);
|
||||||
|
DSpaceObject dso = DSpaceObject.find(
|
||||||
|
context,
|
||||||
|
doiRow.getIntColumn("resource_type_id"),
|
||||||
|
doiRow.getIntColumn("resource_id"));
|
||||||
|
organiser.register(doiRow, dso);
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
LOG.error(ex);
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
LOG.error(ex);
|
||||||
|
} catch (IllegalStateException ex) {
|
||||||
|
LOG.error(ex);
|
||||||
|
} catch (IdentifierException ex) {
|
||||||
|
LOG.error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(line.hasOption("update-doi"))
|
||||||
|
{
|
||||||
|
String identifier = line.getOptionValue('u');
|
||||||
|
|
||||||
|
if(null == identifier)
|
||||||
|
{
|
||||||
|
helpformater.printHelp("\nDOI organiser\n", options);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
TableRow doiRow = organiser.findTableRow(identifier);
|
||||||
|
DSpaceObject dso = DSpaceObject.find(
|
||||||
|
context,
|
||||||
|
doiRow.getIntColumn("resource_type_id"),
|
||||||
|
doiRow.getIntColumn("resource_id"));
|
||||||
|
organiser.update(doiRow, dso);
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
LOG.error(ex);
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
LOG.error(ex);
|
||||||
|
} catch (IllegalStateException ex) {
|
||||||
|
LOG.error(ex);
|
||||||
|
} catch (IdentifierException ex) {
|
||||||
|
LOG.error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(line.hasOption("delete-doi"))
|
||||||
|
{
|
||||||
|
String identifier = line.getOptionValue('d');
|
||||||
|
|
||||||
|
if (null == identifier)
|
||||||
|
{
|
||||||
|
helpformater.printHelp("\nDOI organiser\n", options);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
organiser.delete(identifier);
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
LOG.error(ex);
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
LOG.error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public TableRowIterator getDOIsByStatus(Integer ... status)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String sql = "SELECT * FROM Doi";
|
||||||
|
for (int i = 0; i < status.length ; i++)
|
||||||
|
{
|
||||||
|
if (0 == i)
|
||||||
|
{
|
||||||
|
sql += " WHERE ";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sql += " OR ";
|
||||||
|
}
|
||||||
|
sql += " status = ?";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.length < 1)
|
||||||
|
{
|
||||||
|
return DatabaseManager.queryTable(context, "Doi", sql);
|
||||||
|
}
|
||||||
|
return DatabaseManager.queryTable(context, "Doi", sql, status);
|
||||||
|
}
|
||||||
|
catch (SQLException ex)
|
||||||
|
{
|
||||||
|
LOG.error("Error while trying to get data from database", ex);
|
||||||
|
throw new RuntimeException("Error while trying to get data from database", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void list(String processName, PrintStream out, PrintStream err, Integer ... status)
|
||||||
|
{
|
||||||
|
String indent = " ";
|
||||||
|
if (null == out)
|
||||||
|
{
|
||||||
|
out = System.out;
|
||||||
|
}
|
||||||
|
if (null == err)
|
||||||
|
{
|
||||||
|
err = System.err;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableRowIterator it = this.getDOIsByStatus(status);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (it.hasNext())
|
||||||
|
{
|
||||||
|
out.println("DOIs queued for " + processName + ": ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.println("There are no DOIs queued for " + processName + ".");
|
||||||
|
}
|
||||||
|
while(it.hasNext())
|
||||||
|
{
|
||||||
|
TableRow doiRow = it.next();
|
||||||
|
DSpaceObject dso = DSpaceObject.find(context,
|
||||||
|
doiRow.getIntColumn("resource_type_id"),
|
||||||
|
doiRow.getIntColumn("resource_id"));
|
||||||
|
out.print(indent + DOI.SCHEME + doiRow.getStringColumn("doi"));
|
||||||
|
if (null != dso)
|
||||||
|
{
|
||||||
|
out.println(" (belongs to item with handle " + dso.getHandle() + ")");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.println(" (cannot determine handle of assigned object)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.println("");
|
||||||
|
}
|
||||||
|
catch (SQLException ex)
|
||||||
|
{
|
||||||
|
err.println("Error in database Connection: " + ex.getMessage());
|
||||||
|
ex.printStackTrace(err);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
it.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register(TableRow doiRow, DSpaceObject dso) throws SQLException
|
||||||
|
{
|
||||||
|
if (Constants.ITEM != dso.getType())
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Currenty DSpace supports DOIs for Items only.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
provider.registerOnline(context, dso,
|
||||||
|
DOI.SCHEME + doiRow.getStringColumn("doi"));
|
||||||
|
|
||||||
|
if(!quiet)
|
||||||
|
{
|
||||||
|
System.out.println("This identifier: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi")
|
||||||
|
+ " is successfully registered.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IdentifierException ex)
|
||||||
|
{
|
||||||
|
if (!(ex instanceof DOIIdentifierException))
|
||||||
|
{
|
||||||
|
LOG.error("It wasn't possible to register this identifier: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi")
|
||||||
|
+ " online. ", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
DOIIdentifierException doiIdentifierException = (DOIIdentifierException) ex;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sendAlertMail("Register", dso,
|
||||||
|
DOI.SCHEME + doiRow.getStringColumn("doi"),
|
||||||
|
doiIdentifierException.codeToString(doiIdentifierException
|
||||||
|
.getCode()));
|
||||||
|
}
|
||||||
|
catch (IOException ioe)
|
||||||
|
{
|
||||||
|
LOG.error("Couldn't send mail", ioe);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.error("It wasn't possible to register this identifier : "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi")
|
||||||
|
+ " online. Exceptions code: "
|
||||||
|
+ doiIdentifierException
|
||||||
|
.codeToString(doiIdentifierException.getCode()), ex);
|
||||||
|
|
||||||
|
if(!quiet)
|
||||||
|
{
|
||||||
|
System.err.println("It wasn't possible to register this identifier: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException ex)
|
||||||
|
{
|
||||||
|
LOG.error("Database table DOI contains a DOI that is not valid: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi") + "!", ex);
|
||||||
|
|
||||||
|
if(!quiet)
|
||||||
|
{
|
||||||
|
System.err.println("It wasn't possible to register this identifier: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi"));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Database table DOI contains a DOI "
|
||||||
|
+ " that is not valid: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi") + "!", ex);
|
||||||
|
}
|
||||||
|
catch (SQLException ex)
|
||||||
|
{
|
||||||
|
LOG.error("Error while trying to get data from database", ex);
|
||||||
|
|
||||||
|
if(!quiet)
|
||||||
|
{
|
||||||
|
System.err.println("It wasn't possible to register this identifier: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi"));
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Error while trying to get data from database", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reserve(TableRow doiRow, DSpaceObject dso) throws SQLException
|
||||||
|
{
|
||||||
|
if (Constants.ITEM != dso.getType())
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Currenty DSpace supports DOIs for Items only.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
provider.reserveOnline(context, dso,
|
||||||
|
DOI.SCHEME + doiRow.getStringColumn("doi"));
|
||||||
|
|
||||||
|
if(!quiet)
|
||||||
|
{
|
||||||
|
System.out.println("This identifier : "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi")
|
||||||
|
+ " is successfully reserved.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IdentifierException ex)
|
||||||
|
{
|
||||||
|
if (!(ex instanceof DOIIdentifierException))
|
||||||
|
{
|
||||||
|
LOG.error("It wasn't possible to register this identifier : "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi")
|
||||||
|
+ " online. ",ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
DOIIdentifierException doiIdentifierException = (DOIIdentifierException) ex;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sendAlertMail("Reserve", dso,
|
||||||
|
DOI.SCHEME + doiRow.getStringColumn("doi"),
|
||||||
|
DOIIdentifierException.codeToString(
|
||||||
|
doiIdentifierException.getCode()));
|
||||||
|
}
|
||||||
|
catch (IOException ioe)
|
||||||
|
{
|
||||||
|
LOG.error("Couldn't send mail", ioe);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.error("It wasn't possible to reserve the identifier online. "
|
||||||
|
+ " Exceptions code: "
|
||||||
|
+ DOIIdentifierException
|
||||||
|
.codeToString(doiIdentifierException.getCode()), ex);
|
||||||
|
|
||||||
|
if(!quiet)
|
||||||
|
{
|
||||||
|
System.err.println("It wasn't possible to reserve this identifier: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException ex)
|
||||||
|
{
|
||||||
|
LOG.error("Database table DOI contains a DOI that is not valid: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi") + "!", ex);
|
||||||
|
|
||||||
|
if(!quiet)
|
||||||
|
{
|
||||||
|
System.err.println("It wasn't possible to reserve this identifier: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi"));
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Database table DOI contains a DOI "
|
||||||
|
+ " that is not valid: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi") + "!", ex);
|
||||||
|
}
|
||||||
|
catch (SQLException ex)
|
||||||
|
{
|
||||||
|
LOG.error("Error while trying to get data from database", ex);
|
||||||
|
|
||||||
|
if(!quiet)
|
||||||
|
{
|
||||||
|
System.err.println("It wasn't possible to reserve this identifier: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi"));
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Error while trying to get data from database", ex);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(TableRow doiRow, DSpaceObject dso)
|
||||||
|
{
|
||||||
|
if (Constants.ITEM != dso.getType())
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Currenty DSpace supports DOIs "
|
||||||
|
+ "for Items only.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
provider.updateMetadataOnline(context, dso,
|
||||||
|
DOI.SCHEME + doiRow.getStringColumn("doi"));
|
||||||
|
|
||||||
|
if(!quiet)
|
||||||
|
{
|
||||||
|
System.out.println("Successfully updated metadata of DOI " + DOI.SCHEME
|
||||||
|
+ doiRow.getStringColumn("doi") + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IdentifierException ex)
|
||||||
|
{
|
||||||
|
if (!(ex instanceof DOIIdentifierException))
|
||||||
|
{
|
||||||
|
LOG.error("It wasn't possible to register the identifier online. ",ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
DOIIdentifierException doiIdentifierException = (DOIIdentifierException) ex;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sendAlertMail("Update", dso,
|
||||||
|
DOI.SCHEME + doiRow.getStringColumn("doi"),
|
||||||
|
doiIdentifierException.codeToString(doiIdentifierException
|
||||||
|
.getCode()));
|
||||||
|
}
|
||||||
|
catch (IOException ioe)
|
||||||
|
{
|
||||||
|
LOG.error("Couldn't send mail", ioe);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.error("It wasn't possible to update this identifier: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi")
|
||||||
|
+ " Exceptions code: "
|
||||||
|
+ doiIdentifierException
|
||||||
|
.codeToString(doiIdentifierException.getCode()), ex);
|
||||||
|
|
||||||
|
if(!quiet)
|
||||||
|
{
|
||||||
|
System.err.println("It wasn't possible to update this identifier: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException ex)
|
||||||
|
{
|
||||||
|
LOG.error("Database table DOI contains a DOI that is not valid: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi") + "!", ex);
|
||||||
|
|
||||||
|
if(!quiet)
|
||||||
|
{
|
||||||
|
System.err.println("It wasn't possible to update this identifier: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi"));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Database table DOI contains a DOI "
|
||||||
|
+ " that is not valid: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi") + "!", ex);
|
||||||
|
}
|
||||||
|
catch (SQLException ex)
|
||||||
|
{
|
||||||
|
LOG.error("It wasn't possible to connect to the Database!", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(String identifier)
|
||||||
|
throws SQLException
|
||||||
|
{
|
||||||
|
String doi = null;
|
||||||
|
TableRow doiRow = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
doi = DOI.formatIdentifier(identifier);
|
||||||
|
|
||||||
|
// If there's no exception: we found a valid DOI. :)
|
||||||
|
doiRow = DatabaseManager.findByUnique(context, "Doi", "doi",
|
||||||
|
doi.substring(DOI.SCHEME.length()));
|
||||||
|
|
||||||
|
if (null == doiRow)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("You specified a valid DOI,"
|
||||||
|
+ " that is not stored in our database.");
|
||||||
|
}
|
||||||
|
provider.deleteOnline(context, doi);
|
||||||
|
|
||||||
|
if (!quiet)
|
||||||
|
{
|
||||||
|
System.err.println("It was possible to delete this identifier: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi")
|
||||||
|
+ " online.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (DOIIdentifierException ex)
|
||||||
|
{
|
||||||
|
// Identifier was not recognized as DOI.
|
||||||
|
LOG.error("It wasn't possible to detect this identifier: "
|
||||||
|
+ identifier
|
||||||
|
+ " Exceptions code: "
|
||||||
|
+ ex.codeToString(ex.getCode()), ex);
|
||||||
|
|
||||||
|
if (!quiet)
|
||||||
|
{
|
||||||
|
System.err.println("It wasn't possible to detect this identifier: "
|
||||||
|
+ identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException ex)
|
||||||
|
{
|
||||||
|
if (!quiet)
|
||||||
|
{
|
||||||
|
System.err.println("It wasn't possible to delete this identifier: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi")
|
||||||
|
+ " online. Take a look in log file.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the TableRow in the Doi table that belongs to the specified
|
||||||
|
* DspaceObject.
|
||||||
|
*
|
||||||
|
* @param identifier Either an ItemID, a DOI or a handle. If the identifier
|
||||||
|
* contains digits only we treat it as ItemID, if not we try to find a
|
||||||
|
* matching doi or a handle (in this order).
|
||||||
|
* @return The TableRow or null if the Object does not have a DOI.
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws IllegalArgumentException If the identifier is null, an empty
|
||||||
|
* String or specifies an DSpaceObject that is not an item. We currently
|
||||||
|
* support DOIs for items only, but this may change once...
|
||||||
|
* @throws IllegalStateException If the identifier was a valid DOI that is
|
||||||
|
* not stored in our database or if it is a handle that is not bound to an
|
||||||
|
* DSpaceObject.
|
||||||
|
*/
|
||||||
|
public TableRow findTableRow(String identifier)
|
||||||
|
throws SQLException, IllegalArgumentException, IllegalStateException, IdentifierException
|
||||||
|
{
|
||||||
|
if (null == identifier || identifier.isEmpty())
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Identifier is null or empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
String sql = "SELECT * FROM Doi WHERE resource_type_id = ? AND resource_id = ? ";
|
||||||
|
TableRow doiRow = null;
|
||||||
|
String doi = null;
|
||||||
|
|
||||||
|
// detect it identifer is ItemID, handle or DOI.
|
||||||
|
// try to detect ItemID
|
||||||
|
if (identifier.matches("\\d*"))
|
||||||
|
{
|
||||||
|
Integer itemID = Integer.valueOf(identifier);
|
||||||
|
DSpaceObject dso = Item.find(context, itemID);
|
||||||
|
|
||||||
|
if (null != dso)
|
||||||
|
{
|
||||||
|
doiRow = DatabaseManager.querySingleTable(context, "Doi",
|
||||||
|
sql, Constants.ITEM, dso.getID());
|
||||||
|
|
||||||
|
//Check if this Item has an Identifier, mint one if it doesn't
|
||||||
|
if (null == doiRow)
|
||||||
|
{
|
||||||
|
doi = provider.mint(context, dso);
|
||||||
|
doiRow = DatabaseManager.findByUnique(context, "Doi", "doi",
|
||||||
|
doi.substring(DOI.SCHEME.length()));
|
||||||
|
return doiRow;
|
||||||
|
}
|
||||||
|
return doiRow;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("You specified an ItemID, "
|
||||||
|
+ "that is not stored in our database.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// detect handle
|
||||||
|
DSpaceObject dso = HandleManager.resolveToObject(context, identifier);
|
||||||
|
|
||||||
|
if (null != dso)
|
||||||
|
{
|
||||||
|
if (dso.getType() != Constants.ITEM)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Currently DSpace supports DOIs for Items only. "
|
||||||
|
+ "Cannot process specified handle as it does not identify an Item.");
|
||||||
|
}
|
||||||
|
|
||||||
|
doiRow = DatabaseManager.querySingleTable(context, "Doi", sql,
|
||||||
|
Constants.ITEM, dso.getID());
|
||||||
|
|
||||||
|
if (null == doiRow)
|
||||||
|
{
|
||||||
|
doi = provider.mint(context, dso);
|
||||||
|
doiRow = DatabaseManager.findByUnique(context, "Doi", "doi",
|
||||||
|
doi.substring(DOI.SCHEME.length()));
|
||||||
|
}
|
||||||
|
return doiRow;
|
||||||
|
}
|
||||||
|
// detect DOI
|
||||||
|
try {
|
||||||
|
doi = DOI.formatIdentifier(identifier);
|
||||||
|
// If there's no exception: we found a valid DOI. :)
|
||||||
|
doiRow = DatabaseManager.findByUnique(context, "Doi", "doi",
|
||||||
|
doi.substring(DOI.SCHEME.length()));
|
||||||
|
if (null == doiRow)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("You specified a valid DOI,"
|
||||||
|
+ " that is not stored in our database.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (DOIIdentifierException ex)
|
||||||
|
{
|
||||||
|
// Identifier was not recognized as DOI.
|
||||||
|
LOG.error("It wasn't possible to detect this identifier: "
|
||||||
|
+ identifier
|
||||||
|
+ " Exceptions code: "
|
||||||
|
+ ex.codeToString(ex.getCode()), ex);
|
||||||
|
|
||||||
|
if(!quiet)
|
||||||
|
{
|
||||||
|
System.err.println("It wasn't possible to detect this identifier: "
|
||||||
|
+ DOI.SCHEME + doiRow.getStringColumn("doi"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return doiRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendAlertMail(String action, DSpaceObject dso, String doi, String reason)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
String recipient = ConfigurationManager.getProperty("alert.recipient");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (recipient != null)
|
||||||
|
{
|
||||||
|
Email email = Email.getEmail(
|
||||||
|
I18nUtil.getEmailFilename(Locale.getDefault(), "doi_maintenance_error"));
|
||||||
|
email.addRecipient(recipient);
|
||||||
|
email.addArgument(action);
|
||||||
|
email.addArgument(new Date());
|
||||||
|
email.addArgument(dso.getTypeText());
|
||||||
|
email.addArgument(new Integer(dso.getID()));
|
||||||
|
email.addArgument(doi);
|
||||||
|
email.addArgument(reason);
|
||||||
|
email.send();
|
||||||
|
|
||||||
|
if (!quiet)
|
||||||
|
{
|
||||||
|
System.err.println("Email alert is sent.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
LOG.warn("Unable to send email alert", e);
|
||||||
|
if (!quiet)
|
||||||
|
{
|
||||||
|
System.err.println("Unable to send email alert.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setQuiet()
|
||||||
|
{
|
||||||
|
this.quiet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* 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/
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Make requests to the DOI registration angencies, f.e.to
|
||||||
|
* <a href='http://n2t.net/ezid/'>EZID</a> DOI service, and analyze the responses.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Use {@link org.dspace.identifier.doi.EZIDRequestFactory#getInstance} to configure an {@link org.dspace.identifier.doi.EZIDRequest}
|
||||||
|
* with your authority number and credentials. {@code EZIDRequest} encapsulates
|
||||||
|
* EZID's operations (lookup, create/mint, modify, delete...).
|
||||||
|
* An operation returns an {@link org.dspace.identifier.ezid.EZIDResponse} which gives easy access to
|
||||||
|
* EZID's status code and value, status of the underlying HTTP request, and
|
||||||
|
* key/value pairs found in the response body (if any).
|
||||||
|
* <p>
|
||||||
|
*/
|
||||||
|
package org.dspace.identifier.doi;
|
@@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* 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/
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Providers of durable unique identifiers (Handles, DOIs, etc.).
|
||||||
|
* Generally, subclasses of {@link org.dspace.identifier.IdentifierProvider}
|
||||||
|
* offer methods to create, delete, and resolve subclasses of
|
||||||
|
* {@link org.dspace.identifier.Identifier}. Classes outside this package
|
||||||
|
* should rely on {@link org.dspace.identifier.IdentifierService} to perform
|
||||||
|
* these operations using the most appropriate provider.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.dspace.identifier;
|
@@ -0,0 +1,711 @@
|
|||||||
|
/**
|
||||||
|
* 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.io.IOException;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import org.dspace.AbstractUnitTest;
|
||||||
|
import org.dspace.authorize.AuthorizeException;
|
||||||
|
import org.dspace.content.*;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.kernel.ServiceManager;
|
||||||
|
import org.dspace.services.ConfigurationService;
|
||||||
|
import org.dspace.storage.rdbms.DatabaseManager;
|
||||||
|
import org.dspace.storage.rdbms.TableRow;
|
||||||
|
import org.dspace.workflow.WorkflowItem;
|
||||||
|
import org.dspace.workflow.WorkflowManager;
|
||||||
|
import org.junit.*;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.junit.Assume.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link DataCiteIdentifierProvider}.
|
||||||
|
*
|
||||||
|
* @author Mark H. Wood
|
||||||
|
* @author Pascal-Nicolas Becker
|
||||||
|
*/
|
||||||
|
public class DOIIdentifierProviderTest
|
||||||
|
extends AbstractUnitTest
|
||||||
|
{
|
||||||
|
private static final String PREFIX = "10.5072";
|
||||||
|
private static final String NAMESPACE_SEPARATOR = "dspaceUnitTests-";
|
||||||
|
|
||||||
|
private static ServiceManager sm = null;
|
||||||
|
private static ConfigurationService config = null;
|
||||||
|
|
||||||
|
private static Community community;
|
||||||
|
private static Collection collection;
|
||||||
|
|
||||||
|
private static MockDOIConnector connector;
|
||||||
|
private DOIIdentifierProvider provider;
|
||||||
|
|
||||||
|
/** The most recently created test Item's ID */
|
||||||
|
private static int itemID;
|
||||||
|
|
||||||
|
public DOIIdentifierProviderTest()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void dumpMetadata(Item eyetem)
|
||||||
|
{
|
||||||
|
DCValue[] metadata = eyetem.getMetadata("dc", Item.ANY, Item.ANY, Item.ANY);
|
||||||
|
for (DCValue metadatum : metadata)
|
||||||
|
System.out.printf("Metadata: %s.%s.%s(%s) = %s\n",
|
||||||
|
metadatum.schema,
|
||||||
|
metadatum.element,
|
||||||
|
metadatum.qualifier,
|
||||||
|
metadatum.language,
|
||||||
|
metadatum.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a fresh Item, installed in the repository.
|
||||||
|
*
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws AuthorizeException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private Item newItem(Context ctx)
|
||||||
|
throws SQLException, AuthorizeException, IOException
|
||||||
|
{
|
||||||
|
ctx.turnOffAuthorisationSystem();
|
||||||
|
ctx.setCurrentUser(eperson);
|
||||||
|
|
||||||
|
WorkspaceItem wsItem = WorkspaceItem.create(ctx, collection, false);
|
||||||
|
|
||||||
|
WorkflowItem wfItem = WorkflowManager.start(ctx, wsItem);
|
||||||
|
WorkflowManager.advance(ctx, wfItem, ctx.getCurrentUser());
|
||||||
|
|
||||||
|
Item item = wfItem.getItem();
|
||||||
|
item.addMetadata("dc", "contributor", "author", null, "Author, A. N.");
|
||||||
|
item.addMetadata("dc", "title", null, null, "A Test Object");
|
||||||
|
item.addMetadata("dc", "publisher", null, null, "DSpace Test Harness");
|
||||||
|
|
||||||
|
// If DOIIdentifierProvider is configured
|
||||||
|
// (dspace/conf/spring/api/identifier-service.xml) the new created item
|
||||||
|
// gets automatically a DOI. We remove this DOI as it can make problems
|
||||||
|
// with the tests.
|
||||||
|
String sql = "DELETE FROM Doi WHERE resource_type_id = ? AND resource_id = ?";
|
||||||
|
DatabaseManager.updateQuery(context, sql, item.getType(), item.getID());
|
||||||
|
|
||||||
|
DCValue[] metadata = item.getMetadata(
|
||||||
|
DOIIdentifierProvider.MD_SCHEMA,
|
||||||
|
DOIIdentifierProvider.DOI_ELEMENT,
|
||||||
|
DOIIdentifierProvider.DOI_QUALIFIER,
|
||||||
|
null);
|
||||||
|
List<String> remainder = new ArrayList<String>();
|
||||||
|
|
||||||
|
for (DCValue id : metadata)
|
||||||
|
{
|
||||||
|
if (!id.value.startsWith(DOI.RESOLVER))
|
||||||
|
{
|
||||||
|
remainder.add(id.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item.clearMetadata(
|
||||||
|
DOIIdentifierProvider.MD_SCHEMA,
|
||||||
|
DOIIdentifierProvider.DOI_ELEMENT,
|
||||||
|
DOIIdentifierProvider.DOI_QUALIFIER,
|
||||||
|
null);
|
||||||
|
item.addMetadata(DOIIdentifierProvider.MD_SCHEMA,
|
||||||
|
DOIIdentifierProvider.DOI_ELEMENT,
|
||||||
|
DOIIdentifierProvider.DOI_QUALIFIER,
|
||||||
|
null,
|
||||||
|
remainder.toArray(new String[remainder.size()]));
|
||||||
|
|
||||||
|
item.update();
|
||||||
|
ctx.commit();
|
||||||
|
ctx.restoreAuthSystemState();
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String createDOI(Item item, Integer status, boolean metadata)
|
||||||
|
throws SQLException, IdentifierException, AuthorizeException
|
||||||
|
{
|
||||||
|
return this.createDOI(item, status, metadata, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a DOI to an item.
|
||||||
|
* @param item Item the DOI should be created for.
|
||||||
|
* @param status The status of the DOI.
|
||||||
|
* @param metadata Whether the DOI should be included in the metadata of the item.
|
||||||
|
* @param doi The doi or null if we should generate one.
|
||||||
|
* @return the DOI
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
public String createDOI(Item item, Integer status, boolean metadata, String doi)
|
||||||
|
throws SQLException, IdentifierException, AuthorizeException
|
||||||
|
{
|
||||||
|
// we need some random data. UUIDs would be bloated here
|
||||||
|
Random random = new Random();
|
||||||
|
if (null == doi)
|
||||||
|
{
|
||||||
|
doi = DOI.SCHEME + PREFIX + "/" + NAMESPACE_SEPARATOR
|
||||||
|
+ Long.toHexString(new Date().getTime()) + "-"
|
||||||
|
+ random.nextInt(997);
|
||||||
|
}
|
||||||
|
|
||||||
|
TableRow doiRow = DatabaseManager.create(context, "Doi");
|
||||||
|
doiRow.setColumn("doi", doi.substring(DOI.SCHEME.length()));
|
||||||
|
doiRow.setColumn("resource_type_id", item.getType());
|
||||||
|
doiRow.setColumn("resource_id", item.getID());
|
||||||
|
if (status == null)
|
||||||
|
{
|
||||||
|
doiRow.setColumnNull("status");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
doiRow.setColumn("status", status);
|
||||||
|
}
|
||||||
|
assumeTrue(1 == DatabaseManager.update(context, doiRow));
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
item.addMetadata(DOIIdentifierProvider.MD_SCHEMA,
|
||||||
|
DOIIdentifierProvider.DOI_ELEMENT,
|
||||||
|
DOIIdentifierProvider.DOI_QUALIFIER,
|
||||||
|
null,
|
||||||
|
DOI.DOIToExternalForm(doi));
|
||||||
|
item.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
context.commit();
|
||||||
|
return doi;
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpClass()
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
// Find the usual kernel services
|
||||||
|
sm = kernelImpl.getServiceManager();
|
||||||
|
Context ctx = new Context();
|
||||||
|
|
||||||
|
ctx.turnOffAuthorisationSystem();
|
||||||
|
ctx.setCurrentUser(eperson);
|
||||||
|
// Create an environment for our test objects to live in.
|
||||||
|
community = Community.create(null, ctx);
|
||||||
|
community.setMetadata("name", "A Test Community");
|
||||||
|
community.update();
|
||||||
|
collection = community.createCollection();
|
||||||
|
collection.setMetadata("name", "A Test Collection");
|
||||||
|
collection.update();
|
||||||
|
ctx.complete();
|
||||||
|
|
||||||
|
config = kernelImpl.getConfigurationService();
|
||||||
|
// Configure the service under test.
|
||||||
|
config.setProperty(DOIIdentifierProvider.CFG_PREFIX, PREFIX);
|
||||||
|
config.setProperty(DOIIdentifierProvider.CFG_NAMESPACE_SEPARATOR,
|
||||||
|
NAMESPACE_SEPARATOR);
|
||||||
|
// Don't try to send mail.
|
||||||
|
config.setProperty("mail.server.disabled", "true");
|
||||||
|
|
||||||
|
connector = new MockDOIConnector();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDownClass()
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
System.out.print("Tearing down\n\n");
|
||||||
|
Context ctx = new Context();
|
||||||
|
dumpMetadata(Item.find(ctx, itemID));
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
context.setCurrentUser(eperson);
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
provider = new DOIIdentifierProvider();
|
||||||
|
provider.setConfigurationService(config);
|
||||||
|
provider.setDOIConnector(connector);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown()
|
||||||
|
{
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
connector.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of supports method, of class DataCiteIdentifierProvider.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSupports_Class()
|
||||||
|
{
|
||||||
|
Class<? extends Identifier> identifier = DOI.class;
|
||||||
|
assertTrue("DOI should be supported", provider.supports(identifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSupports_valid_String()
|
||||||
|
{
|
||||||
|
String[] validDOIs = new String[]
|
||||||
|
{
|
||||||
|
"10.5072/123abc-lkj/kljl",
|
||||||
|
PREFIX + "/" + NAMESPACE_SEPARATOR + "lkjljasd1234",
|
||||||
|
DOI.SCHEME + "10.5072/123abc-lkj/kljl",
|
||||||
|
"http://dx.doi.org/10.5072/123abc-lkj/kljl",
|
||||||
|
DOI.RESOLVER + "/10.5072/123abc-lkj/kljl"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (String doi : validDOIs)
|
||||||
|
{
|
||||||
|
assertTrue("DOI should be supported", provider.supports(doi));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoes_not_support_invalid_String()
|
||||||
|
{
|
||||||
|
String[] invalidDOIs = new String[]
|
||||||
|
{
|
||||||
|
"11.5072/123abc-lkj/kljl",
|
||||||
|
"http://hdl.handle.net/handle/10.5072/123abc-lkj/kljl",
|
||||||
|
"",
|
||||||
|
null
|
||||||
|
};
|
||||||
|
|
||||||
|
for (String notADoi : invalidDOIs)
|
||||||
|
{
|
||||||
|
assertFalse("Invalid DOIs shouldn't be supported",
|
||||||
|
provider.supports(notADoi));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStore_DOI_as_item_metadata()
|
||||||
|
throws SQLException, AuthorizeException, IOException, IdentifierException
|
||||||
|
{
|
||||||
|
Item item = newItem(context);
|
||||||
|
String doi = DOI.SCHEME + PREFIX + "/" + NAMESPACE_SEPARATOR
|
||||||
|
+ Long.toHexString(new Date().getTime());
|
||||||
|
provider.saveDOIToObject(context, item, doi);
|
||||||
|
|
||||||
|
DCValue[] metadata = item.getMetadata(DOIIdentifierProvider.MD_SCHEMA,
|
||||||
|
DOIIdentifierProvider.DOI_ELEMENT,
|
||||||
|
DOIIdentifierProvider.DOI_QUALIFIER,
|
||||||
|
null);
|
||||||
|
boolean result = false;
|
||||||
|
for (DCValue id : metadata)
|
||||||
|
{
|
||||||
|
if (id.value.equals(DOI.DOIToExternalForm(doi)))
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue("Cannot store DOI as item metadata value.", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGet_DOI_out_of_item_metadata()
|
||||||
|
throws SQLException, AuthorizeException, IOException, IdentifierException
|
||||||
|
{
|
||||||
|
Item item = newItem(context);
|
||||||
|
String doi = DOI.SCHEME + PREFIX + "/" + NAMESPACE_SEPARATOR
|
||||||
|
+ Long.toHexString(new Date().getTime());
|
||||||
|
|
||||||
|
item.addMetadata(DOIIdentifierProvider.MD_SCHEMA,
|
||||||
|
DOIIdentifierProvider.DOI_ELEMENT,
|
||||||
|
DOIIdentifierProvider.DOI_QUALIFIER,
|
||||||
|
null,
|
||||||
|
DOI.DOIToExternalForm(doi));
|
||||||
|
item.update();
|
||||||
|
context.commit();
|
||||||
|
|
||||||
|
assertTrue("Failed to recognize DOI in item metadata.",
|
||||||
|
doi.equals(DOIIdentifierProvider.getDOIOutOfObject(item)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemove_DOI_from_item_metadata()
|
||||||
|
throws SQLException, AuthorizeException, IOException, IdentifierException
|
||||||
|
{
|
||||||
|
Item item = newItem(context);
|
||||||
|
String doi = DOI.SCHEME + PREFIX + "/" + NAMESPACE_SEPARATOR
|
||||||
|
+ Long.toHexString(new Date().getTime());
|
||||||
|
|
||||||
|
item.addMetadata(DOIIdentifierProvider.MD_SCHEMA,
|
||||||
|
DOIIdentifierProvider.DOI_ELEMENT,
|
||||||
|
DOIIdentifierProvider.DOI_QUALIFIER,
|
||||||
|
null,
|
||||||
|
DOI.DOIToExternalForm(doi));
|
||||||
|
item.update();
|
||||||
|
context.commit();
|
||||||
|
|
||||||
|
provider.removeDOIFromObject(context, item, doi);
|
||||||
|
|
||||||
|
DCValue[] metadata = item.getMetadata(DOIIdentifierProvider.MD_SCHEMA,
|
||||||
|
DOIIdentifierProvider.DOI_ELEMENT,
|
||||||
|
DOIIdentifierProvider.DOI_QUALIFIER,
|
||||||
|
null);
|
||||||
|
boolean foundDOI = false;
|
||||||
|
for (DCValue id : metadata)
|
||||||
|
{
|
||||||
|
if (id.value.equals(DOI.DOIToExternalForm(doi)))
|
||||||
|
{
|
||||||
|
foundDOI = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertFalse("Cannot remove DOI from item metadata.", foundDOI);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGet_DOI_by_DSpaceObject()
|
||||||
|
throws SQLException, AuthorizeException, IOException,
|
||||||
|
IllegalArgumentException, IdentifierException
|
||||||
|
{
|
||||||
|
Item item = newItem(context);
|
||||||
|
String doi = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, false);
|
||||||
|
|
||||||
|
String retrievedDOI = DOIIdentifierProvider.getDOIByObject(context, item);
|
||||||
|
|
||||||
|
assertNotNull("Failed to load DOI by DSpaceObject.", retrievedDOI);
|
||||||
|
assertTrue("Loaded wrong DOI by DSpaceObject.", doi.equals(retrievedDOI));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGet_DOI_lookup()
|
||||||
|
throws SQLException, AuthorizeException, IOException,
|
||||||
|
IllegalArgumentException, IdentifierException
|
||||||
|
{
|
||||||
|
Item item = newItem(context);
|
||||||
|
String doi = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, false);
|
||||||
|
|
||||||
|
String retrievedDOI = provider.lookup(context, (DSpaceObject) item);
|
||||||
|
|
||||||
|
assertNotNull("Failed to loookup doi.", retrievedDOI);
|
||||||
|
assertTrue("Loaded wrong DOI on lookup.", doi.equals(retrievedDOI));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGet_DSpaceObject_by_DOI()
|
||||||
|
throws SQLException, AuthorizeException, IOException,
|
||||||
|
IllegalArgumentException, IdentifierException
|
||||||
|
{
|
||||||
|
Item item = newItem(context);
|
||||||
|
String doi = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, false);
|
||||||
|
|
||||||
|
DSpaceObject dso = DOIIdentifierProvider.getObjectByDOI(context, doi);
|
||||||
|
|
||||||
|
assertNotNull("Failed to load DSpaceObject by DOI.", dso);
|
||||||
|
if (item.getType() != dso.getType() || item.getID() != dso.getID())
|
||||||
|
{
|
||||||
|
fail("Object loaded by DOI was another object then expected!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResolve_DOI()
|
||||||
|
throws SQLException, AuthorizeException, IOException,
|
||||||
|
IllegalArgumentException, IdentifierException
|
||||||
|
{
|
||||||
|
Item item = newItem(context);
|
||||||
|
String doi = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, false);
|
||||||
|
|
||||||
|
DSpaceObject dso = provider.resolve(context, doi);
|
||||||
|
|
||||||
|
assertNotNull("Failed to resolve DOI.", dso);
|
||||||
|
if (item.getType() != dso.getType() || item.getID() != dso.getID())
|
||||||
|
{
|
||||||
|
fail("Object return by DOI lookup was another object then expected!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following test seems a bit silly, but it was helpful to debug some
|
||||||
|
* problems while deleting DOIs.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testRemove_two_DOIs_from_item_metadata()
|
||||||
|
throws SQLException, AuthorizeException, IOException, IdentifierException
|
||||||
|
{
|
||||||
|
// add two DOIs.
|
||||||
|
Item item = newItem(context);
|
||||||
|
String doi1 = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, true);
|
||||||
|
String doi2 = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, true);
|
||||||
|
|
||||||
|
// remove one of it
|
||||||
|
provider.removeDOIFromObject(context, item, doi1);
|
||||||
|
|
||||||
|
// assure that the right one was removed
|
||||||
|
DCValue[] metadata = item.getMetadata(DOIIdentifierProvider.MD_SCHEMA,
|
||||||
|
DOIIdentifierProvider.DOI_ELEMENT,
|
||||||
|
DOIIdentifierProvider.DOI_QUALIFIER,
|
||||||
|
null);
|
||||||
|
boolean foundDOI1 = false;
|
||||||
|
boolean foundDOI2 = false;
|
||||||
|
for (DCValue id : metadata)
|
||||||
|
{
|
||||||
|
if (id.value.equals(DOI.DOIToExternalForm(doi1)))
|
||||||
|
{
|
||||||
|
foundDOI1 = true;
|
||||||
|
}
|
||||||
|
if (id.value.equals(DOI.DOIToExternalForm(doi2)))
|
||||||
|
{
|
||||||
|
foundDOI2 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
assertFalse("Cannot remove DOI from item metadata.", foundDOI1);
|
||||||
|
assertTrue("Removed wrong DOI from item metadata.", foundDOI2);
|
||||||
|
|
||||||
|
// remove the otherone as well.
|
||||||
|
provider.removeDOIFromObject(context, item, doi2);
|
||||||
|
|
||||||
|
// check it
|
||||||
|
metadata = item.getMetadata(DOIIdentifierProvider.MD_SCHEMA,
|
||||||
|
DOIIdentifierProvider.DOI_ELEMENT,
|
||||||
|
DOIIdentifierProvider.DOI_QUALIFIER,
|
||||||
|
null);
|
||||||
|
foundDOI1 = false;
|
||||||
|
foundDOI2 = false;
|
||||||
|
for (DCValue id : metadata)
|
||||||
|
{
|
||||||
|
if (id.value.equals(DOI.DOIToExternalForm(doi1)))
|
||||||
|
{
|
||||||
|
foundDOI1 = true;
|
||||||
|
}
|
||||||
|
if (id.value.equals(DOI.DOIToExternalForm(doi2)))
|
||||||
|
{
|
||||||
|
foundDOI2 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
assertFalse("Cannot remove DOI from item metadata.", foundDOI1);
|
||||||
|
assertFalse("Cannot remove DOI from item metadata.", foundDOI2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMintDOI() throws SQLException, AuthorizeException, IOException
|
||||||
|
{
|
||||||
|
Item item = newItem(context);
|
||||||
|
String doi = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// get a DOI:
|
||||||
|
doi = provider.mint(context, item);
|
||||||
|
}
|
||||||
|
catch(IdentifierException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
fail("Got an IdentifierException: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertNotNull("Minted DOI is null!", doi);
|
||||||
|
assertFalse("Minted DOI is empty!", doi.isEmpty());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DOI.formatIdentifier(doi);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
fail("Minted an unrecognizable DOI: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMint_returns_existing_DOI()
|
||||||
|
throws SQLException, AuthorizeException, IOException, IdentifierException
|
||||||
|
{
|
||||||
|
Item item = newItem(context);
|
||||||
|
String doi = this.createDOI(item, null, true);
|
||||||
|
|
||||||
|
String retrievedDOI = provider.mint(context, item);
|
||||||
|
|
||||||
|
assertNotNull("Minted DOI is null?!", retrievedDOI);
|
||||||
|
assertTrue("Mint did not returned an existing DOI!", doi.equals(retrievedDOI));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReserve_DOI()
|
||||||
|
throws SQLException, SQLException, AuthorizeException, IOException,
|
||||||
|
IdentifierException
|
||||||
|
{
|
||||||
|
Item item = newItem(context);
|
||||||
|
String doi = this.createDOI(item, null, true);
|
||||||
|
|
||||||
|
provider.reserve(context, item, doi);
|
||||||
|
|
||||||
|
TableRow doiRow = DatabaseManager.findByUnique(context, "Doi", "doi",
|
||||||
|
doi.substring(DOI.SCHEME.length()));
|
||||||
|
assumeNotNull(doiRow);
|
||||||
|
|
||||||
|
assertTrue("Reservation of DOI did not set the corret DOI status.",
|
||||||
|
DOIIdentifierProvider.TO_BE_RESERVERED.intValue() == doiRow.getIntColumn("status"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegister_unreserved_DOI()
|
||||||
|
throws SQLException, SQLException, AuthorizeException, IOException,
|
||||||
|
IdentifierException
|
||||||
|
{
|
||||||
|
Item item = newItem(context);
|
||||||
|
String doi = this.createDOI(item, null, true);
|
||||||
|
|
||||||
|
provider.register(context, item, doi);
|
||||||
|
|
||||||
|
TableRow doiRow = DatabaseManager.findByUnique(context, "Doi", "doi",
|
||||||
|
doi.substring(DOI.SCHEME.length()));
|
||||||
|
assumeNotNull(doiRow);
|
||||||
|
|
||||||
|
assertTrue("Registration of DOI did not set the corret DOI status.",
|
||||||
|
DOIIdentifierProvider.TO_BE_REGISTERED.intValue() == doiRow.getIntColumn("status"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegister_reserved_DOI()
|
||||||
|
throws SQLException, SQLException, AuthorizeException, IOException,
|
||||||
|
IdentifierException
|
||||||
|
{
|
||||||
|
Item item = newItem(context);
|
||||||
|
String doi = this.createDOI(item, DOIIdentifierProvider.IS_RESERVED, true);
|
||||||
|
|
||||||
|
provider.register(context, item, doi);
|
||||||
|
|
||||||
|
TableRow doiRow = DatabaseManager.findByUnique(context, "Doi", "doi",
|
||||||
|
doi.substring(DOI.SCHEME.length()));
|
||||||
|
assumeNotNull(doiRow);
|
||||||
|
|
||||||
|
assertTrue("Registration of DOI did not set the corret DOI status.",
|
||||||
|
DOIIdentifierProvider.TO_BE_REGISTERED.intValue() == doiRow.getIntColumn("status"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreate_and_Register_DOI()
|
||||||
|
throws SQLException, SQLException, AuthorizeException, IOException,
|
||||||
|
IdentifierException
|
||||||
|
{
|
||||||
|
Item item = newItem(context);
|
||||||
|
|
||||||
|
String doi = provider.register(context, item);
|
||||||
|
|
||||||
|
// we want the created DOI to be returned in the following format:
|
||||||
|
// doi:10.<prefix>/<suffix>.
|
||||||
|
String formated_doi = DOI.formatIdentifier(doi);
|
||||||
|
assertTrue("DOI was not in the expected format!", doi.equals(formated_doi));
|
||||||
|
|
||||||
|
TableRow doiRow = DatabaseManager.findByUnique(context, "Doi", "doi",
|
||||||
|
doi.substring(DOI.SCHEME.length()));
|
||||||
|
assertNotNull("Created DOI was not stored in database.", doiRow);
|
||||||
|
|
||||||
|
assertTrue("Registration of DOI did not set the corret DOI status.",
|
||||||
|
DOIIdentifierProvider.TO_BE_REGISTERED.intValue() == doiRow.getIntColumn("status"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelete_specified_DOI()
|
||||||
|
throws SQLException, AuthorizeException, IOException, IdentifierException
|
||||||
|
{
|
||||||
|
Item item = newItem(context);
|
||||||
|
String doi1 = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, true);
|
||||||
|
String doi2 = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, true);
|
||||||
|
|
||||||
|
// remove one of it
|
||||||
|
provider.delete(context, item, doi1);
|
||||||
|
|
||||||
|
// assure that the right one was removed
|
||||||
|
DCValue[] metadata = item.getMetadata(DOIIdentifierProvider.MD_SCHEMA,
|
||||||
|
DOIIdentifierProvider.DOI_ELEMENT,
|
||||||
|
DOIIdentifierProvider.DOI_QUALIFIER,
|
||||||
|
null);
|
||||||
|
boolean foundDOI1 = false;
|
||||||
|
boolean foundDOI2 = false;
|
||||||
|
for (DCValue id : metadata)
|
||||||
|
{
|
||||||
|
if (id.value.equals(DOI.DOIToExternalForm(doi1)))
|
||||||
|
{
|
||||||
|
foundDOI1 = true;
|
||||||
|
}
|
||||||
|
if (id.value.equals(DOI.DOIToExternalForm(doi2)))
|
||||||
|
{
|
||||||
|
foundDOI2 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertFalse("Cannot remove DOI from item metadata.", foundDOI1);
|
||||||
|
assertTrue("Removed wrong DOI from item metadata.", foundDOI2);
|
||||||
|
|
||||||
|
TableRow doiRow1 = DatabaseManager.findByUnique(context, "Doi", "doi",
|
||||||
|
doi1.substring(DOI.SCHEME.length()));
|
||||||
|
assumeNotNull(doiRow1);
|
||||||
|
assertTrue("Status of deleted DOI was not set correctly.",
|
||||||
|
DOIIdentifierProvider.TO_BE_DELETED.intValue() == doiRow1.getIntColumn("status"));
|
||||||
|
|
||||||
|
TableRow doiRow2 = DatabaseManager.findByUnique(context, "Doi", "doi",
|
||||||
|
doi2.substring(DOI.SCHEME.length()));
|
||||||
|
assumeNotNull(doiRow2);
|
||||||
|
assertTrue("While deleting a DOI the status of another changed.",
|
||||||
|
DOIIdentifierProvider.IS_REGISTERED.intValue() == doiRow2.getIntColumn("status"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelete_all_DOIs()
|
||||||
|
throws SQLException, AuthorizeException, IOException, IdentifierException
|
||||||
|
{
|
||||||
|
Item item = newItem(context);
|
||||||
|
String doi1 = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, true);
|
||||||
|
String doi2 = this.createDOI(item, DOIIdentifierProvider.IS_REGISTERED, true);
|
||||||
|
|
||||||
|
// remove one of it
|
||||||
|
provider.delete(context, item);
|
||||||
|
|
||||||
|
// assure that the right one was removed
|
||||||
|
DCValue[] metadata = item.getMetadata(DOIIdentifierProvider.MD_SCHEMA,
|
||||||
|
DOIIdentifierProvider.DOI_ELEMENT,
|
||||||
|
DOIIdentifierProvider.DOI_QUALIFIER,
|
||||||
|
null);
|
||||||
|
boolean foundDOI1 = false;
|
||||||
|
boolean foundDOI2 = false;
|
||||||
|
for (DCValue id : metadata)
|
||||||
|
{
|
||||||
|
if (id.value.equals(DOI.DOIToExternalForm(doi1)))
|
||||||
|
{
|
||||||
|
foundDOI1 = true;
|
||||||
|
}
|
||||||
|
if (id.value.equals(DOI.DOIToExternalForm(doi2)))
|
||||||
|
{
|
||||||
|
foundDOI2 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertFalse("Cannot remove DOI from item metadata.", foundDOI1);
|
||||||
|
assertFalse("Did not removed all DOIs from item metadata.", foundDOI2);
|
||||||
|
|
||||||
|
TableRow doiRow1 = DatabaseManager.findByUnique(context, "Doi", "doi",
|
||||||
|
doi1.substring(DOI.SCHEME.length()));
|
||||||
|
assumeNotNull(doiRow1);
|
||||||
|
assertTrue("Status of deleted DOI was not set correctly.",
|
||||||
|
DOIIdentifierProvider.TO_BE_DELETED.intValue() == doiRow1.getIntColumn("status"));
|
||||||
|
|
||||||
|
TableRow doiRow2 = DatabaseManager.findByUnique(context, "Doi", "doi",
|
||||||
|
doi1.substring(DOI.SCHEME.length()));
|
||||||
|
assumeNotNull(doiRow2);
|
||||||
|
assertTrue("Did not set the status of all deleted DOIs as expected.",
|
||||||
|
DOIIdentifierProvider.TO_BE_DELETED.intValue() == doiRow2.getIntColumn("status"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// test the following methods using the MockDOIConnector.
|
||||||
|
// updateMetadataOnline
|
||||||
|
// registerOnline
|
||||||
|
// reserveOnline
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,171 @@
|
|||||||
|
/**
|
||||||
|
* 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.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import mockit.Mock;
|
||||||
|
import mockit.MockUp;
|
||||||
|
import org.dspace.content.DSpaceObject;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.identifier.doi.DOIConnector;
|
||||||
|
import org.dspace.identifier.doi.DOIIdentifierException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Pascal-Nicolas Becker (p dot becker at tu hyphen berlin dot de)
|
||||||
|
*/
|
||||||
|
public class MockDOIConnector
|
||||||
|
extends MockUp<DOIConnector>
|
||||||
|
implements org.dspace.identifier.doi.DOIConnector
|
||||||
|
{
|
||||||
|
|
||||||
|
public Map<String, Integer> reserved;
|
||||||
|
public Map<String, Integer> registered;
|
||||||
|
|
||||||
|
public MockDOIConnector()
|
||||||
|
{
|
||||||
|
reserved = new HashMap<String, Integer>();
|
||||||
|
registered = new HashMap<String, Integer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset()
|
||||||
|
{
|
||||||
|
reserved.clear();
|
||||||
|
registered.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Mock
|
||||||
|
public boolean isDOIReserved(Context context, String doi)
|
||||||
|
throws DOIIdentifierException
|
||||||
|
{
|
||||||
|
return reserved.containsKey(doi);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Mock
|
||||||
|
public boolean isDOIReserved(Context context, DSpaceObject dso, String doi)
|
||||||
|
throws DOIIdentifierException
|
||||||
|
{
|
||||||
|
if (null == doi)
|
||||||
|
{
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
Integer itemId = reserved.get(doi);
|
||||||
|
return (itemId != null && itemId.intValue() == dso.getID()) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Mock
|
||||||
|
public boolean isDOIRegistered(Context context, String doi)
|
||||||
|
throws DOIIdentifierException
|
||||||
|
{
|
||||||
|
return registered.containsKey(doi);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Mock
|
||||||
|
public boolean isDOIRegistered(Context context, DSpaceObject dso, String doi)
|
||||||
|
throws DOIIdentifierException
|
||||||
|
{
|
||||||
|
if (null == doi)
|
||||||
|
{
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
Integer itemId = registered.get(doi);
|
||||||
|
return (itemId != null && itemId.intValue() == dso.getID()) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Mock
|
||||||
|
public void deleteDOI(Context context, String doi)
|
||||||
|
throws DOIIdentifierException
|
||||||
|
{
|
||||||
|
if (reserved.remove(doi) == null)
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("Trying to delete a DOI that was "
|
||||||
|
+ "never reserved!", DOIIdentifierException.DOI_DOES_NOT_EXIST);
|
||||||
|
}
|
||||||
|
registered.remove(doi);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Mock
|
||||||
|
public void reserveDOI(Context context, DSpaceObject dso, String doi)
|
||||||
|
throws DOIIdentifierException
|
||||||
|
{
|
||||||
|
Integer itemId = reserved.get(doi);
|
||||||
|
if (null != itemId)
|
||||||
|
{
|
||||||
|
if (dso.getID() == itemId.intValue())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("Trying to reserve a DOI that "
|
||||||
|
+ "is reserved for another object.",
|
||||||
|
DOIIdentifierException.MISMATCH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reserved.put(doi, new Integer(dso.getID()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Mock
|
||||||
|
public void registerDOI(Context context, DSpaceObject dso, String doi)
|
||||||
|
throws DOIIdentifierException
|
||||||
|
{
|
||||||
|
if (!reserved.containsKey(doi))
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("Trying to register an unreserverd "
|
||||||
|
+ "DOI.", DOIIdentifierException.REGISTER_FIRST);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reserved.get(doi).intValue() != dso.getID())
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("Trying to register a DOI that is"
|
||||||
|
+ " reserved for another item.", DOIIdentifierException.MISMATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registered.containsKey(doi))
|
||||||
|
{
|
||||||
|
if (registered.get(doi).intValue() == dso.getID())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("Trying to register a DOI that "
|
||||||
|
+ "is registered for another item.",
|
||||||
|
DOIIdentifierException.MISMATCH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registered.put(doi, new Integer(dso.getID()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Mock
|
||||||
|
public void updateMetadata(Context context, DSpaceObject dso, String doi)
|
||||||
|
throws DOIIdentifierException
|
||||||
|
{
|
||||||
|
if (!reserved.containsKey(doi))
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("Trying to update a DOI that is not "
|
||||||
|
+ "registered!", DOIIdentifierException.DOI_DOES_NOT_EXIST);
|
||||||
|
}
|
||||||
|
if (reserved.get(doi).intValue() != dso.getID())
|
||||||
|
{
|
||||||
|
throw new DOIIdentifierException("Trying to update metadata of an "
|
||||||
|
+ "unreserved DOI.", DOIIdentifierException.DOI_DOES_NOT_EXIST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
454
dspace/config/crosswalks/DIM2DataCite.xsl
Normal file
454
dspace/config/crosswalks/DIM2DataCite.xsl
Normal file
@@ -0,0 +1,454 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Document : DIM2DataCite.xsl
|
||||||
|
Created on : January 23, 2013, 1:26 PM
|
||||||
|
Author : pbecker, ffuerste
|
||||||
|
Description: Converts metadata from DSpace Intermediat Format (DIM) into
|
||||||
|
metadata following the DataCite Schema for the Publication and
|
||||||
|
Citation of Research Data, Version 2.2
|
||||||
|
-->
|
||||||
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:dspace="http://www.dspace.org/xmlns/dspace/dim"
|
||||||
|
xmlns="http://datacite.org/schema/kernel-2.2"
|
||||||
|
version="1.0">
|
||||||
|
|
||||||
|
<!-- CONFIGURATION -->
|
||||||
|
<!-- The content of the following variable will be used as element publisher. -->
|
||||||
|
<xsl:variable name="publisher">My University</xsl:variable>
|
||||||
|
<!-- The content of the following variable will be used as element contributor with contributorType datamanager. -->
|
||||||
|
<xsl:variable name="datamanager"><xsl:value-of select="$publisher" /></xsl:variable>
|
||||||
|
<!-- The content of the following variable will be used as element contributor with contributorType hostingInstitution. -->
|
||||||
|
<xsl:variable name="hostinginstitution"><xsl:value-of select="$publisher" /></xsl:variable>
|
||||||
|
<!-- Please take a look into the DataCite schema documentation if you want to know how to use these elements.
|
||||||
|
http://schema.datacite.org -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- DO NOT CHANGE ANYTHING BELOW THIS LINE EXCEPT YOU REALLY KNOW WHAT YOU ARE DOING! -->
|
||||||
|
|
||||||
|
<xsl:output method="xml" indent="yes" encoding="utf-8" />
|
||||||
|
|
||||||
|
<!-- Don't copy everything by default! -->
|
||||||
|
<xsl:template match="@* | text()" />
|
||||||
|
|
||||||
|
<xsl:template match="/dspace:dim[@dspaceType='ITEM']">
|
||||||
|
<!--
|
||||||
|
org.dspace.identifier.doi.DataCiteConnector uses this XSLT to
|
||||||
|
transform metadata for the DataCite metadata store. This crosswalk
|
||||||
|
should only be used, when it is ensured that all mandatory
|
||||||
|
properties are in the metadata of the item to export.
|
||||||
|
The classe named above respects this.
|
||||||
|
-->
|
||||||
|
<resource xmlns="http://datacite.org/schema/kernel-2.2"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://datacite.org/schema/kernel-2.2 http://schema.datacite.org/meta/kernel-2.2/metadata.xsd">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
MANDATORY PROPERTIES
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (1)
|
||||||
|
Template Call for DOI identifier.
|
||||||
|
-->
|
||||||
|
<xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='identifier' and starts-with(., 'http://dx.doi.org/')]" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (2)
|
||||||
|
Add creator information.
|
||||||
|
-->
|
||||||
|
<creators>
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="//dspace:field[@mdschema='dc' and @element='contributor' and @qualifier='author']">
|
||||||
|
<xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='contributor' and @qualifier='author']" />
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<creator>
|
||||||
|
<creatorName>(:unkn) unknown</creatorName>
|
||||||
|
</creator>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</creators>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (3)
|
||||||
|
Add Title information.
|
||||||
|
-->
|
||||||
|
<titles>
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="//dspace:field[@mdschema='dc' and @element='title']">
|
||||||
|
<xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='title']" />
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<title>(:unas) unassigned</title>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</titles>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (4)
|
||||||
|
Add Publisher information from configuration above
|
||||||
|
-->
|
||||||
|
<publisher>
|
||||||
|
<xsl:value-of select="$publisher" />
|
||||||
|
</publisher>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (5)
|
||||||
|
Add PublicationYear information
|
||||||
|
-->
|
||||||
|
<publicationYear>
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="//dspace:field[@mdschema='dc' and @element='date' and @qualifier='issued']">
|
||||||
|
<xsl:value-of select="substring(//dspace:field[@mdschema='dc' and @element='date' and @qualifier='issued'], 1, 4)" />
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:when test="//dspace:field[@mdschema='dc' and @element='date' and @qualifier='available']">
|
||||||
|
<xsl:value-of select="substring(//dspace:field[@mdschema='dc' and @element='date' and @qualifier='issued'], 1, 4)" />
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:when test="//dspace:field[@mdschema='dc' and @element='date']">
|
||||||
|
<xsl:value-of select="substring(//dspace:field[@mdschema='dc' and @element='date'], 1, 4)" />
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>0000</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</publicationYear>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
OPTIONAL PROPERTIES
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (6)
|
||||||
|
Template Call for subjects.
|
||||||
|
-->
|
||||||
|
<xsl:if test="//dspace:field[@mdschema='dc' and @element='subject']">
|
||||||
|
<subjects>
|
||||||
|
<xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='subject']" />
|
||||||
|
</subjects>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (7)
|
||||||
|
Add contributorType from configuration above.
|
||||||
|
Template Call for Contributors
|
||||||
|
-->
|
||||||
|
<contributors>
|
||||||
|
<xsl:element name="contributor">
|
||||||
|
<xsl:attribute name="contributorType">DataManager</xsl:attribute>
|
||||||
|
<xsl:element name="contributorName">
|
||||||
|
<xsl:value-of select="$datamanager"/>
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:element>
|
||||||
|
<xsl:element name="contributor">
|
||||||
|
<xsl:attribute name="contributorType">HostingInstitution</xsl:attribute>
|
||||||
|
<contributorName>
|
||||||
|
<xsl:value-of select="$hostinginstitution" />
|
||||||
|
</contributorName>
|
||||||
|
</xsl:element>
|
||||||
|
<xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='contributor'][not(@qualifier='author')]" />
|
||||||
|
</contributors>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (8)
|
||||||
|
Template Call for Dates
|
||||||
|
-->
|
||||||
|
<xsl:if test="//dspace:field[@mdschema='dc' and @element='date']" >
|
||||||
|
<dates>
|
||||||
|
<xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='date']" />
|
||||||
|
</dates>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<!-- Add language(s). -->
|
||||||
|
<xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='language' and (@qualifier='iso' or @qualifier='rfc3066')]" />
|
||||||
|
|
||||||
|
<!-- Add resource type. -->
|
||||||
|
<xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='type']" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Add alternativeIdentifiers.
|
||||||
|
This element is important as it is used to recognize for which
|
||||||
|
DSpace object a DOI is reserved for. See below for further
|
||||||
|
information.
|
||||||
|
-->
|
||||||
|
<xsl:if test="//dspace:field[@mdschema='dc' and @element='identifier' and not(starts-with(., 'http://dx.doi.org/'))]">
|
||||||
|
<xsl:element name="alternateIdentifiers">
|
||||||
|
<xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='identifier' and not(starts-with(., 'http://dx.doi.org/'))]" />
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<!-- Add sizes. -->
|
||||||
|
<!--
|
||||||
|
<xsl:if test="//dspace:field[@mdschema='dc' and @element='format' and @qualifier='extent']">
|
||||||
|
<sizes>
|
||||||
|
<xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='format' and @qualifier='extent']" />
|
||||||
|
</sizes>
|
||||||
|
</xsl:if>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Add formats. -->
|
||||||
|
<!--
|
||||||
|
<xsl:if test="//dspace:field[@mdschema='dc' and @element='format']">
|
||||||
|
<formats>
|
||||||
|
<xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='format']" />
|
||||||
|
</formats>
|
||||||
|
</xsl:if>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Add version. -->
|
||||||
|
<xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='description' and @qualifier='provenance']" />
|
||||||
|
|
||||||
|
<!-- Add rights. -->
|
||||||
|
<xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='rights']" />
|
||||||
|
|
||||||
|
<!-- Add descriptions. -->
|
||||||
|
<xsl:if test="//dspace:field[@mdschema='dc' and @element='description'][not(@qualifier='provenance')]">
|
||||||
|
<xsl:element name="descriptions">
|
||||||
|
<xsl:apply-templates select="//dspace:field[@mdschema='dc' and @element='description'][not(@qualifier='provenance')]" />
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
</resource>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Add doi identifier information. -->
|
||||||
|
<xsl:template match="dspace:field[@mdschema='dc' and @element='identifier' and starts-with(., 'http://dx.doi.org/')]">
|
||||||
|
<identifier identifierType="DOI">
|
||||||
|
<xsl:value-of select="substring(., 19)"/>
|
||||||
|
</identifier>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- DataCite (2) :: Creator -->
|
||||||
|
<xsl:template match="//dspace:field[@mdschema='dc' and @element='contributor' and @qualifier='author']">
|
||||||
|
<creator>
|
||||||
|
<creatorName>
|
||||||
|
<xsl:value-of select="." />
|
||||||
|
</creatorName>
|
||||||
|
</creator>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- DataCite (3) :: Title -->
|
||||||
|
<xsl:template match="dspace:field[@mdschema='dc' and @element='title']">
|
||||||
|
<xsl:element name="title">
|
||||||
|
<xsl:if test="@qualifier='alternative'">
|
||||||
|
<xsl:attribute name="titleType">AlternativeTitle</xsl:attribute>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:value-of select="." />
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (6), DataCite (6.1)
|
||||||
|
Adds subject and subjectScheme information
|
||||||
|
|
||||||
|
"This term is intended to be used with non-literal values as defined in the
|
||||||
|
DCMI Abstract Model (http://dublincore.org/documents/abstract-model/).
|
||||||
|
As of December 2007, the DCMI Usage Board is seeking a way to express
|
||||||
|
this intention with a formal range declaration."
|
||||||
|
(http://dublincore.org/documents/dcmi-terms/#terms-subject)
|
||||||
|
-->
|
||||||
|
<xsl:template match="//dspace:field[@mdschema='dc' and @element='subject']">
|
||||||
|
<xsl:element name="subject">
|
||||||
|
<xsl:if test="@qualifier">
|
||||||
|
<xsl:attribute name="subjectScheme"><xsl:value-of select="@qualifier" /></xsl:attribute>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:value-of select="." />
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (7), DataCite (7.1)
|
||||||
|
Adds contributor and contributorType information
|
||||||
|
-->
|
||||||
|
<xsl:template match="//dspace:field[@mdschema='dc' and @element='contributor'][not(@qualifier='author')]">
|
||||||
|
<xsl:if test="@qualifier='editor'">
|
||||||
|
<xsl:element name="contributor">
|
||||||
|
<xsl:attribute name="contributorType">Editor</xsl:attribute>
|
||||||
|
<contributorName>
|
||||||
|
<xsl:value-of select="." />
|
||||||
|
</contributorName>
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (8), DataCite (8.1)
|
||||||
|
Adds Date and dateType information
|
||||||
|
-->
|
||||||
|
<xsl:template match="//dspace:field[@mdschema='dc' and @element='date']">
|
||||||
|
<xsl:element name="date">
|
||||||
|
<xsl:if test="@qualifier='accessioned'">
|
||||||
|
<xsl:attribute name="dateType">Issued</xsl:attribute>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:if test="@qualifier='submitted'">
|
||||||
|
<xsl:attribute name="dateType">Issued</xsl:attribute>
|
||||||
|
</xsl:if>
|
||||||
|
<!-- part of DublinCore DSpace to mapping but not part of DSpace default fields
|
||||||
|
<xsl:if test="@qualifier='dateAccepted'">
|
||||||
|
<xsl:attribute name="dateType">Issued</xsl:attribute>
|
||||||
|
</xsl:if>
|
||||||
|
-->
|
||||||
|
<xsl:if test="@qualifier='issued'">
|
||||||
|
<xsl:attribute name="dateType">Issued</xsl:attribute>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:if test="@qualifier='available'">
|
||||||
|
<xsl:attribute name="dateType">Available</xsl:attribute>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:if test="@qualifier='copyright'">
|
||||||
|
<xsl:attribute name="dateType">Copyrighted</xsl:attribute>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:if test="@qualifier='created'">
|
||||||
|
<xsl:attribute name="dateType">Created</xsl:attribute>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:if test="@qualifier='updated'">
|
||||||
|
<xsl:attribute name="dateType">Updated</xsl:attribute>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:value-of select="substring(., 1, 10)" />
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (9)
|
||||||
|
Adds Language information
|
||||||
|
Transforming the language flags according to ISO 639-2/B & ISO 639-3
|
||||||
|
-->
|
||||||
|
<xsl:template match="//dspace:field[@mdschema='dc' and @element='language' and (@qualifier='iso' or @qualifier='rfc3066')]">
|
||||||
|
<xsl:for-each select=".">
|
||||||
|
<xsl:element name="language">
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="contains(string(text()), '_')">
|
||||||
|
<xsl:value-of select="translate(string(text()), '_', '-')"/>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:value-of select="string(text())"/>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (10), DataCite (10.1)
|
||||||
|
Adds resourceType and resourceTypeGeneral information
|
||||||
|
-->
|
||||||
|
<xsl:template match="//dspace:field[@mdschema='dc' and @element='type']">
|
||||||
|
<xsl:for-each select=".">
|
||||||
|
<!-- Transforming the language flags according to ISO 639-2/B & ISO 639-3 -->
|
||||||
|
<xsl:element name="resourceType">
|
||||||
|
<xsl:attribute name="resourceTypeGeneral">
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="string(text())='Animation'">Image</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Article'">Text</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Book'">Text</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Book chapter'">Text</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Dataset'">Dataset</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Learning Object'">InteractiveResource</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Image'">Image</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Image, 3-D'">Image</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Map'">Image</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Musical Score'">Sound</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Plan or blueprint'">Image</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Preprint'">Text</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Presentation'">Image</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Recording, acoustical'">Sound</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Recording, musical'">Sound</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Recording, oral'">Sound</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Software'">Software</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Technical Report'">Text</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Thesis'">Text</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Video'">Film</xsl:when>
|
||||||
|
<xsl:when test="string(text())='Working Paper'">Text</xsl:when>
|
||||||
|
<!-- FIXME -->
|
||||||
|
<xsl:when test="string(text())='Other'">Collection</xsl:when>
|
||||||
|
<!-- FIXME -->
|
||||||
|
<xsl:otherwise>Collection</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:attribute>
|
||||||
|
<xsl:value-of select="." />
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (11), DataCite (11.1)
|
||||||
|
Adds AlternativeIdentifier and alternativeIdentifierType information
|
||||||
|
Adds all identifiers except the doi.
|
||||||
|
|
||||||
|
This element is important as it is used to recognize for which DSpace
|
||||||
|
objet a DOI is reserved for. The DataCiteConnector will test all
|
||||||
|
AlternativeIdentifiers by using HandleManager.
|
||||||
|
resolveUrlToHandle(context, altId) until one is recognized or all have
|
||||||
|
been tested.
|
||||||
|
-->
|
||||||
|
<xsl:template match="//dspace:field[@mdschema='dc' and @element='identifier' and not(starts-with(., 'http://dx.doi.org/'))]">
|
||||||
|
<xsl:element name="alternateIdentifier">
|
||||||
|
<xsl:if test="@qualifier">
|
||||||
|
<xsl:attribute name="alternateIdentifierType"><xsl:value-of select="@qualifier" /></xsl:attribute>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:value-of select="." />
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (12), DataCite (12.1)
|
||||||
|
Adds RelatedIdentifier and relatedIdentifierType information
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (13)
|
||||||
|
Adds Size information
|
||||||
|
-->
|
||||||
|
<xsl:template match="//dspace:field[@mdschema='dc' and @element='format' and @qualifier='extent']">
|
||||||
|
<xsl:element name="format">
|
||||||
|
<xsl:value-of select="." />
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (14)
|
||||||
|
Adds Format information
|
||||||
|
-->
|
||||||
|
<xsl:template match="//dspace:field[@mdschema='dc' and @element='format']">
|
||||||
|
<xsl:element name="format">
|
||||||
|
<xsl:value-of select="." />
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (15)
|
||||||
|
Adds Version information
|
||||||
|
-->
|
||||||
|
<xsl:template match="//dspace:field[@mdschema='dc' and @element='description' and @qualifier='provenance']">
|
||||||
|
<xsl:if test="contains(text(),'Made available')">
|
||||||
|
<xsl:element name="version">
|
||||||
|
<xsl:value-of select="." />
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (16)
|
||||||
|
Adds Rights information
|
||||||
|
-->
|
||||||
|
<xsl:template match="//dspace:field[@mdschema='dc' and @element='rights']">
|
||||||
|
<xsl:element name="rights">
|
||||||
|
<xsl:value-of select="." />
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
DataCite (17)
|
||||||
|
Description
|
||||||
|
-->
|
||||||
|
<xsl:template match="//dspace:field[@mdschema='dc' and @element='description'][not(@qualifier='provenance')]">
|
||||||
|
<xsl:element name="description">
|
||||||
|
<xsl:attribute name="descriptionType">
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="@qualifier='abstract'">Abstract</xsl:when>
|
||||||
|
<xsl:otherwise>Other</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:attribute>
|
||||||
|
<xsl:value-of select="." />
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
@@ -233,6 +233,25 @@ log.dir = ${dspace.dir}/log
|
|||||||
# an X-Forward header. If it finds it, it will use this for the user IP address
|
# an X-Forward header. If it finds it, it will use this for the user IP address
|
||||||
#useProxies = true
|
#useProxies = true
|
||||||
|
|
||||||
|
##### DOI registration agency credentials ######
|
||||||
|
# To mint DOIs you have to use a DOI registration agency like DataCite. Several
|
||||||
|
# DataCite members offers services as DOI registration agency, so f.e. EZID or
|
||||||
|
# TIB Hannover. To mint DOIs with DSpace you have to get an agreement with an
|
||||||
|
# DOI registration agency. You have to edit
|
||||||
|
# [dspace]/config/spring/api/identifier-service.xml and to configure the following
|
||||||
|
# properties.
|
||||||
|
|
||||||
|
# Credentials used to authenticate against the registration agency:
|
||||||
|
identifier.doi.user = username
|
||||||
|
identifier.doi.password = password
|
||||||
|
# DOI prefix used to mint DOIs. All DOIs minted by DSpace will use this prefix.
|
||||||
|
# The Prefix will be assinged by the registration agency.
|
||||||
|
identifier.doi.prefix = 10.5072
|
||||||
|
# If you want to, you can further separate your namespace. Should all the suffix
|
||||||
|
# of all DOIs minted by DSpace start with a special string to separate it from
|
||||||
|
# other services also minting DOIs under your prefix?
|
||||||
|
identifier.doi.namespaceseparator = dspace/
|
||||||
|
|
||||||
##### Search settings #####
|
##### Search settings #####
|
||||||
|
|
||||||
# Where to put search index files
|
# Where to put search index files
|
||||||
@@ -477,6 +496,15 @@ crosswalk.dissemination.marc.schemaLocation = \
|
|||||||
http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd
|
http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd
|
||||||
crosswalk.dissemination.marc.preferList = true
|
crosswalk.dissemination.marc.preferList = true
|
||||||
|
|
||||||
|
##
|
||||||
|
## Configure XSLT-driven submission crosswalk for DataCite
|
||||||
|
##
|
||||||
|
crosswalk.dissemination.DataCite.stylesheet = crosswalks/DIM2DataCite.xsl
|
||||||
|
crosswalk.dissemination.DataCite.schemaLocation = \
|
||||||
|
http://datacite.org/schema/kernel-2.2 \
|
||||||
|
http://schema.datacite.org/meta/kernel-2.2/metadata.xsd
|
||||||
|
crosswalk.dissemination.DataCite.preferList = false
|
||||||
|
|
||||||
# Crosswalk Plugin Configuration:
|
# Crosswalk Plugin Configuration:
|
||||||
# The purpose of Crosswalks is to translate an external metadata format to/from
|
# The purpose of Crosswalks is to translate an external metadata format to/from
|
||||||
# the DSpace Internal Metadata format (DIM) or the DSpace Database.
|
# the DSpace Internal Metadata format (DIM) or the DSpace Database.
|
||||||
@@ -648,9 +676,15 @@ event.dispatcher.default.class = org.dspace.event.BasicDispatcher
|
|||||||
# as the SOLR implementation rely on the discovery consumer
|
# as the SOLR implementation rely on the discovery consumer
|
||||||
#
|
#
|
||||||
# event.dispatcher.default.consumers = versioning, browse, discovery, eperson, harvester
|
# event.dispatcher.default.consumers = versioning, browse, discovery, eperson, harvester
|
||||||
|
#
|
||||||
|
# uncomment event.consumer.doi.class and event.consumer.doi.filters below and add doi here
|
||||||
|
# if you want to send metadata updates to your doi registration agency.
|
||||||
|
|
||||||
event.dispatcher.default.consumers = versioning, discovery, eperson, harvester
|
event.dispatcher.default.consumers = versioning, discovery, eperson, harvester
|
||||||
|
|
||||||
|
|
||||||
|
# event.dispatcher.default.consumers = versioning, discovery, eperson, harvester, doi
|
||||||
|
|
||||||
# The noindex dispatcher will not create search or browse indexes (useful for batch item imports)
|
# The noindex dispatcher will not create search or browse indexes (useful for batch item imports)
|
||||||
event.dispatcher.noindex.class = org.dspace.event.BasicDispatcher
|
event.dispatcher.noindex.class = org.dspace.event.BasicDispatcher
|
||||||
event.dispatcher.noindex.consumers = eperson
|
event.dispatcher.noindex.consumers = eperson
|
||||||
@@ -675,6 +709,10 @@ event.consumer.eperson.filters = EPerson+Create
|
|||||||
event.consumer.harvester.class = org.dspace.harvest.HarvestConsumer
|
event.consumer.harvester.class = org.dspace.harvest.HarvestConsumer
|
||||||
event.consumer.harvester.filters = Item+Delete
|
event.consumer.harvester.filters = Item+Delete
|
||||||
|
|
||||||
|
# consumer to update metadata of DOIs
|
||||||
|
#event.consumer.doi.class = org.dspace.identifier.doi.DOIConsumer
|
||||||
|
#event.consumer.doi.filters = Item+Modify_Metadata
|
||||||
|
|
||||||
# test consumer for debugging and monitoring
|
# test consumer for debugging and monitoring
|
||||||
#event.consumer.test.class = org.dspace.event.TestConsumer
|
#event.consumer.test.class = org.dspace.event.TestConsumer
|
||||||
#event.consumer.test.filters = All+All
|
#event.consumer.test.filters = All+All
|
||||||
|
18
dspace/config/emails/doi_maintenance_error
Normal file
18
dspace/config/emails/doi_maintenance_error
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# E-mail sent to designated address when a metadata update, registration
|
||||||
|
# or reserveration of a doi fails
|
||||||
|
#
|
||||||
|
# Parameters: {0} action (updating metadata of, registering or reserving)
|
||||||
|
# {1} Date & Time
|
||||||
|
# {2} resource type text
|
||||||
|
# {3} resource id
|
||||||
|
# {4} doi
|
||||||
|
# {5} reason
|
||||||
|
#
|
||||||
|
# See org.dspace.core.Email for information on the format of this file.
|
||||||
|
#
|
||||||
|
Subject: DSpace: Error {0} DOI {3}
|
||||||
|
|
||||||
|
Date: {1}
|
||||||
|
|
||||||
|
{0} DOI {4} for {2} with ID {3} failed:
|
||||||
|
{5}
|
@@ -199,6 +199,14 @@
|
|||||||
</step>
|
</step>
|
||||||
</command>
|
</command>
|
||||||
|
|
||||||
|
<command>
|
||||||
|
<name>doi-organiser</name>
|
||||||
|
<description>Run the DOI organiser</description>
|
||||||
|
<step>
|
||||||
|
<class>org.dspace.identifier.doi.DOIOrganiser</class>
|
||||||
|
</step>
|
||||||
|
</command>
|
||||||
|
|
||||||
<command>
|
<command>
|
||||||
<name>packager</name>
|
<name>packager</name>
|
||||||
<description>Execute a packager</description>
|
<description>Execute a packager</description>
|
||||||
|
@@ -21,11 +21,48 @@
|
|||||||
autowire="byType"
|
autowire="byType"
|
||||||
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"-->
|
<!--<bean id="org.dspace.identifier.HandleIdentifierProvider" class="org.dspace.identifier.VersionedHandleIdentifierProvider"-->
|
||||||
<!--scope="singleton">-->
|
<!--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.
|
||||||
|
To mint DOIs you need a registration agency. The DOIIdentifierProvider
|
||||||
|
maintains the doi database table and handling of DSpaceObject. It uses
|
||||||
|
a DOIConnector that handle all API calls to your DOI registration
|
||||||
|
agency. Please configure a DOIConnector as well!-->
|
||||||
|
|
||||||
|
<!-- To mint DOIs with DSpace get an agreement with a DOI registration
|
||||||
|
agency, take a look into dspace.cfg, and remove this comment
|
||||||
|
<bean id="org.dspace.identifier.DOIIdentifierProvider"
|
||||||
|
class="org.dspace.identifier.DOIIdentifierProvider"
|
||||||
|
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
|
||||||
|
agency for the DOIIdentifierProvider. If your registration agency
|
||||||
|
tells you to use DataCites API directly you can use the
|
||||||
|
DataCiteConnector. If your registration agency is not part of DataCite
|
||||||
|
or provides their own API you have to implement a DOIConnector.
|
||||||
|
EZID f.e. is part of DataCite but provides their own APIs. The following
|
||||||
|
DataCiteConnector won't work if EZID is your registration agency.
|
||||||
|
-->
|
||||||
|
<!-- Remove this comment to use DataCite API directly as DOIConnector.
|
||||||
|
<bean id="org.dspace.identifier.doi.DOIConnector"
|
||||||
|
class="org.dspace.identifier.doi.DataCiteConnector"
|
||||||
|
scope="singleton">
|
||||||
|
<property name='DATACITE_SCHEME' value='https'/>
|
||||||
|
<property name='DATACITE_HOST' value='test.datacite.org'/>
|
||||||
|
<property name='DATACITE_DOI_PATH' value='/mds/doi/' />
|
||||||
|
<property name='DATACITE_METADATA_PATH' value='/mds/metadata/' />
|
||||||
|
<property name='disseminationCrosswalkName' value="DataCite" />
|
||||||
|
</bean>
|
||||||
|
-->
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
@@ -64,6 +64,7 @@ DROP TABLE TasklistItem;
|
|||||||
DROP TABLE WorkflowItem;
|
DROP TABLE WorkflowItem;
|
||||||
DROP TABLE WorkspaceItem;
|
DROP TABLE WorkspaceItem;
|
||||||
DROP TABLE Handle;
|
DROP TABLE Handle;
|
||||||
|
DROP TABLE Doi;
|
||||||
DROP TABLE EPersonGroup2EPerson;
|
DROP TABLE EPersonGroup2EPerson;
|
||||||
DROP TABLE ResourcePolicy;
|
DROP TABLE ResourcePolicy;
|
||||||
DROP TABLE Collection2Item;
|
DROP TABLE Collection2Item;
|
||||||
@@ -114,6 +115,7 @@ DROP SEQUENCE collection2item_seq;
|
|||||||
DROP SEQUENCE resourcepolicy_seq;
|
DROP SEQUENCE resourcepolicy_seq;
|
||||||
DROP SEQUENCE epersongroup2eperson_seq;
|
DROP SEQUENCE epersongroup2eperson_seq;
|
||||||
DROP SEQUENCE handle_seq;
|
DROP SEQUENCE handle_seq;
|
||||||
|
DROP SEQUENCE doi_seq;
|
||||||
DROP SEQUENCE workspaceitem_seq;
|
DROP SEQUENCE workspaceitem_seq;
|
||||||
DROP SEQUENCE workflowitem_seq;
|
DROP SEQUENCE workflowitem_seq;
|
||||||
DROP SEQUENCE tasklistitem_seq;
|
DROP SEQUENCE tasklistitem_seq;
|
||||||
|
@@ -102,6 +102,7 @@ CREATE SEQUENCE collection2item_seq;
|
|||||||
CREATE SEQUENCE resourcepolicy_seq;
|
CREATE SEQUENCE resourcepolicy_seq;
|
||||||
CREATE SEQUENCE epersongroup2eperson_seq;
|
CREATE SEQUENCE epersongroup2eperson_seq;
|
||||||
CREATE SEQUENCE handle_seq;
|
CREATE SEQUENCE handle_seq;
|
||||||
|
CREATE SEQUENCE doi_seq;
|
||||||
CREATE SEQUENCE workspaceitem_seq;
|
CREATE SEQUENCE workspaceitem_seq;
|
||||||
CREATE SEQUENCE workflowitem_seq;
|
CREATE SEQUENCE workflowitem_seq;
|
||||||
CREATE SEQUENCE tasklistitem_seq;
|
CREATE SEQUENCE tasklistitem_seq;
|
||||||
@@ -492,6 +493,23 @@ CREATE INDEX handle_handle_idx ON Handle(handle);
|
|||||||
-- index by resource id and resource type id
|
-- index by resource id and resource type id
|
||||||
CREATE INDEX handle_resource_id_and_type_idx ON handle(resource_id, resource_type_id);
|
CREATE INDEX handle_resource_id_and_type_idx ON handle(resource_id, resource_type_id);
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- Doi table
|
||||||
|
-------------------------------------------------------
|
||||||
|
CREATE TABLE Doi
|
||||||
|
(
|
||||||
|
doi_id INTEGER PRIMARY KEY,
|
||||||
|
doi VARCHAR(256),
|
||||||
|
resource_type_id INTEGER,
|
||||||
|
resource_id INTEGER,
|
||||||
|
status INTEGER
|
||||||
|
);
|
||||||
|
|
||||||
|
-- index by handle, commonly looked up
|
||||||
|
CREATE INDEX doi_doi_idx ON Doi(doi);
|
||||||
|
-- index by resource id and resource type id
|
||||||
|
CREATE INDEX doi_resource_id_and_type_idx ON Doi(resource_id, resource_type_id);
|
||||||
|
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
-- WorkspaceItem table
|
-- WorkspaceItem table
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
@@ -55,6 +55,7 @@ CREATE SEQUENCE collection2item_seq;
|
|||||||
CREATE SEQUENCE resourcepolicy_seq;
|
CREATE SEQUENCE resourcepolicy_seq;
|
||||||
CREATE SEQUENCE epersongroup2eperson_seq;
|
CREATE SEQUENCE epersongroup2eperson_seq;
|
||||||
CREATE SEQUENCE handle_seq;
|
CREATE SEQUENCE handle_seq;
|
||||||
|
CREATE SEQUENCE doi_seq;
|
||||||
CREATE SEQUENCE workspaceitem_seq;
|
CREATE SEQUENCE workspaceitem_seq;
|
||||||
CREATE SEQUENCE workflowitem_seq;
|
CREATE SEQUENCE workflowitem_seq;
|
||||||
CREATE SEQUENCE tasklistitem_seq;
|
CREATE SEQUENCE tasklistitem_seq;
|
||||||
@@ -444,6 +445,21 @@ CREATE TABLE Handle
|
|||||||
-- index by resource id and resource type id
|
-- index by resource id and resource type id
|
||||||
CREATE INDEX handle_resource_id_type_idx ON handle(resource_id, resource_type_id);
|
CREATE INDEX handle_resource_id_type_idx ON handle(resource_id, resource_type_id);
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- Doi table
|
||||||
|
-------------------------------------------------------
|
||||||
|
CREATE TABLE Doi
|
||||||
|
(
|
||||||
|
doi_id INTEGER PRIMARY KEY,
|
||||||
|
doi VARCHAR2(256) UNIQUE,
|
||||||
|
resource_type_id INTEGER,
|
||||||
|
resource_id INTEGER,
|
||||||
|
status INTEGER
|
||||||
|
);
|
||||||
|
|
||||||
|
-- index by resource id and resource type id
|
||||||
|
CREATE INDEX doi_resource_id_type_idx ON doi(resource_id, resource_type_id);
|
||||||
|
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
-- WorkspaceItem table
|
-- WorkspaceItem table
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
@@ -21,6 +21,23 @@
|
|||||||
-- DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST.
|
-- DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST.
|
||||||
--
|
--
|
||||||
|
|
||||||
|
-------------------------------------------
|
||||||
|
-- Add support for DOIs (table and seq.) --
|
||||||
|
-------------------------------------------
|
||||||
|
CREATE SEQUENCE doi_seq;
|
||||||
|
|
||||||
|
CREATE TABLE Doi
|
||||||
|
(
|
||||||
|
doi_id INTEGER PRIMARY KEY,
|
||||||
|
doi VARCHAR2(256) UNIQUE,
|
||||||
|
resource_type_id INTEGER,
|
||||||
|
resource_id INTEGER,
|
||||||
|
status INTEGER
|
||||||
|
);
|
||||||
|
|
||||||
|
-- index by resource id and resource type id
|
||||||
|
CREATE INDEX doi_resource_id_type_idx ON doi(resource_id, resource_type_id);
|
||||||
|
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
-- Table of running web applications for 'dspace version' --
|
-- Table of running web applications for 'dspace version' --
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
@@ -93,6 +93,7 @@ CREATE SEQUENCE collection2item_seq;
|
|||||||
CREATE SEQUENCE resourcepolicy_seq;
|
CREATE SEQUENCE resourcepolicy_seq;
|
||||||
CREATE SEQUENCE epersongroup2eperson_seq;
|
CREATE SEQUENCE epersongroup2eperson_seq;
|
||||||
CREATE SEQUENCE handle_seq;
|
CREATE SEQUENCE handle_seq;
|
||||||
|
CREATE SEQUENCE doi_seq;
|
||||||
CREATE SEQUENCE workspaceitem_seq;
|
CREATE SEQUENCE workspaceitem_seq;
|
||||||
CREATE SEQUENCE workflowitem_seq;
|
CREATE SEQUENCE workflowitem_seq;
|
||||||
CREATE SEQUENCE tasklistitem_seq;
|
CREATE SEQUENCE tasklistitem_seq;
|
||||||
@@ -485,6 +486,23 @@ CREATE INDEX handle_handle_idx ON Handle(handle);
|
|||||||
-- index by resource id and resource type id
|
-- index by resource id and resource type id
|
||||||
CREATE INDEX handle_resource_id_and_type_idx ON handle(resource_id, resource_type_id);
|
CREATE INDEX handle_resource_id_and_type_idx ON handle(resource_id, resource_type_id);
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- Doi table
|
||||||
|
-------------------------------------------------------
|
||||||
|
CREATE TABLE Doi
|
||||||
|
(
|
||||||
|
doi_id INTEGER PRIMARY KEY,
|
||||||
|
doi VARCHAR(256) UNIQUE,
|
||||||
|
resource_type_id INTEGER,
|
||||||
|
resource_id INTEGER,
|
||||||
|
status INTEGER
|
||||||
|
);
|
||||||
|
|
||||||
|
-- index by handle, commonly looked up
|
||||||
|
CREATE INDEX doi_doi_idx ON Doi(doi);
|
||||||
|
-- index by resource id and resource type id
|
||||||
|
CREATE INDEX doi_resource_id_and_type_idx ON Doi(resource_id, resource_type_id);
|
||||||
|
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
-- WorkspaceItem table
|
-- WorkspaceItem table
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
@@ -21,6 +21,26 @@
|
|||||||
-- DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST.
|
-- DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST.
|
||||||
--
|
--
|
||||||
|
|
||||||
|
-------------------------------------------
|
||||||
|
-- Add support for DOIs (table and seq.) --
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
CREATE SEQUENCE doi_seq;
|
||||||
|
|
||||||
|
CREATE TABLE Doi
|
||||||
|
(
|
||||||
|
doi_id INTEGER PRIMARY KEY,
|
||||||
|
doi VARCHAR(256) UNIQUE,
|
||||||
|
resource_type_id INTEGER,
|
||||||
|
resource_id INTEGER,
|
||||||
|
status INTEGER
|
||||||
|
);
|
||||||
|
|
||||||
|
-- index by handle, commonly looked up
|
||||||
|
CREATE INDEX doi_doi_idx ON Doi(doi);
|
||||||
|
-- index by resource id and resource type id
|
||||||
|
CREATE INDEX doi_resource_id_and_type_idx ON Doi(resource_id, resource_type_id);
|
||||||
|
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
-- New columns and longer hash for salted password hashing DS-861 --
|
-- New columns and longer hash for salted password hashing DS-861 --
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
Reference in New Issue
Block a user