mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +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>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gr.ekt</groupId>
|
||||
<artifactId>biblio-transformation-engine</artifactId>
|
||||
|
@@ -84,6 +84,48 @@ public class HandleManager
|
||||
|
||||
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>.
|
||||
|
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;;
|
||||
|
||||
/**
|
||||
* 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;;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
@@ -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
|
||||
#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 #####
|
||||
|
||||
# Where to put search index files
|
||||
@@ -477,6 +496,15 @@ crosswalk.dissemination.marc.schemaLocation = \
|
||||
http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd
|
||||
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:
|
||||
# The purpose of Crosswalks is to translate an external metadata format to/from
|
||||
# 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
|
||||
#
|
||||
# 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, doi
|
||||
|
||||
# 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.consumers = eperson
|
||||
@@ -675,6 +709,10 @@ event.consumer.eperson.filters = EPerson+Create
|
||||
event.consumer.harvester.class = org.dspace.harvest.HarvestConsumer
|
||||
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
|
||||
#event.consumer.test.class = org.dspace.event.TestConsumer
|
||||
#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>
|
||||
</command>
|
||||
|
||||
<command>
|
||||
<name>doi-organiser</name>
|
||||
<description>Run the DOI organiser</description>
|
||||
<step>
|
||||
<class>org.dspace.identifier.doi.DOIOrganiser</class>
|
||||
</step>
|
||||
</command>
|
||||
|
||||
<command>
|
||||
<name>packager</name>
|
||||
<description>Execute a packager</description>
|
||||
|
@@ -21,11 +21,48 @@
|
||||
autowire="byType"
|
||||
scope="singleton"/>
|
||||
|
||||
|
||||
<!-- provider for using the versioned handle identifier instead of the default one. -->
|
||||
<!--<bean id="org.dspace.identifier.HandleIdentifierProvider" class="org.dspace.identifier.VersionedHandleIdentifierProvider"-->
|
||||
<!--scope="singleton">-->
|
||||
<!--<property name="configurationService" ref="org.dspace.services.ConfigurationService"/>-->
|
||||
<!--</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>
|
||||
|
@@ -64,6 +64,7 @@ DROP TABLE TasklistItem;
|
||||
DROP TABLE WorkflowItem;
|
||||
DROP TABLE WorkspaceItem;
|
||||
DROP TABLE Handle;
|
||||
DROP TABLE Doi;
|
||||
DROP TABLE EPersonGroup2EPerson;
|
||||
DROP TABLE ResourcePolicy;
|
||||
DROP TABLE Collection2Item;
|
||||
@@ -114,6 +115,7 @@ DROP SEQUENCE collection2item_seq;
|
||||
DROP SEQUENCE resourcepolicy_seq;
|
||||
DROP SEQUENCE epersongroup2eperson_seq;
|
||||
DROP SEQUENCE handle_seq;
|
||||
DROP SEQUENCE doi_seq;
|
||||
DROP SEQUENCE workspaceitem_seq;
|
||||
DROP SEQUENCE workflowitem_seq;
|
||||
DROP SEQUENCE tasklistitem_seq;
|
||||
|
@@ -102,6 +102,7 @@ CREATE SEQUENCE collection2item_seq;
|
||||
CREATE SEQUENCE resourcepolicy_seq;
|
||||
CREATE SEQUENCE epersongroup2eperson_seq;
|
||||
CREATE SEQUENCE handle_seq;
|
||||
CREATE SEQUENCE doi_seq;
|
||||
CREATE SEQUENCE workspaceitem_seq;
|
||||
CREATE SEQUENCE workflowitem_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
|
||||
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
|
||||
-------------------------------------------------------
|
||||
|
@@ -55,6 +55,7 @@ CREATE SEQUENCE collection2item_seq;
|
||||
CREATE SEQUENCE resourcepolicy_seq;
|
||||
CREATE SEQUENCE epersongroup2eperson_seq;
|
||||
CREATE SEQUENCE handle_seq;
|
||||
CREATE SEQUENCE doi_seq;
|
||||
CREATE SEQUENCE workspaceitem_seq;
|
||||
CREATE SEQUENCE workflowitem_seq;
|
||||
CREATE SEQUENCE tasklistitem_seq;
|
||||
@@ -444,6 +445,21 @@ CREATE TABLE Handle
|
||||
-- index by resource id and 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
|
||||
-------------------------------------------------------
|
||||
|
@@ -21,6 +21,23 @@
|
||||
-- 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' --
|
||||
-------------------------------------------
|
||||
|
@@ -93,6 +93,7 @@ CREATE SEQUENCE collection2item_seq;
|
||||
CREATE SEQUENCE resourcepolicy_seq;
|
||||
CREATE SEQUENCE epersongroup2eperson_seq;
|
||||
CREATE SEQUENCE handle_seq;
|
||||
CREATE SEQUENCE doi_seq;
|
||||
CREATE SEQUENCE workspaceitem_seq;
|
||||
CREATE SEQUENCE workflowitem_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
|
||||
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
|
||||
-------------------------------------------------------
|
||||
|
@@ -21,6 +21,26 @@
|
||||
-- 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 --
|
||||
-------------------------------------------
|
||||
|
Reference in New Issue
Block a user