Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crossref as a DOI provider (experimental) #10806

Merged
merged 12 commits into from
Sep 17, 2024
3 changes: 3 additions & 0 deletions doc/release-notes/8581-add-crossref-pid-provider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Added CrossRef DOI Pid Provider

See Installation Configuration document for JVM Settings to enable CrossRef as a Pid Provider
35 changes: 35 additions & 0 deletions doc/sphinx-guides/source/installation/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,41 @@ for `Fabrica <https://doi.datacite.org/>`_ and their APIs. You need to provide
the same credentials (``username``, ``password``) to Dataverse software to mint and manage DOIs for you.
As noted above, you should use one of the more secure options for setting the password.

CrossRef-specific Settings
^^^^^^^^^^^^^^^^^^^^^^^^^^

dataverse.pid.*.crossref.url
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
dataverse.pid.*.crossref.rest-api-url
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
dataverse.pid.*.crossref.username
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
dataverse.pid.*.crossref.password
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
dataverse.pid.*.crossref.depositor
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
dataverse.pid.*.crossref.depositor-email
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

CrossRef is an experimental provider.
PID Providers of type ``crossref`` require six additional parameters that define how the provider connects to CrossRef.
CrossRef has two APIs that are used in Dataverse:

The base URL of the `CrossRef <https://api.crossref.org>`_,
used to mint and manage DOIs. Current valid values for ``dataverse.pid.*.crossref.url`` are "https://doi.crossref.org" and ``dataverse.pid.*.crossref.rest-api-url`` are "https://api.crossref.org" (production).
``dataverse.pid.*.crossref.username=crusername``
``dataverse.pid.*.crossref.password=secret``
``dataverse.pid.*.crossref.depositor=xyz``
``dataverse.pid.*.crossref.depositor-email=xyz@example.com``

CrossRef uses `HTTP Basic authentication <https://en.wikipedia.org/wiki/Basic_access_authentication>`_
XML files can be POSTed to CrossRef where they are added to the submission queue to await processing
`Post URL <https://doi.crossref.org/>`_
REST API allows the search and reuse our members' metadata.
`Rest API <https://api.crossref.org/>`_ and their APIs.
You need to provide the same credentials (``username``, ``password``) to Dataverse software to mint and manage DOIs for you.
As noted above, you should use one of the more secure options for setting the password.
Depositor and Depositor Email are used for the generation and distribution of Depositor reports.

.. _dataverse.pid.*.ezid:

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package edu.harvard.iq.dataverse.pidproviders.doi.crossref;

import edu.harvard.iq.dataverse.DvObject;
import edu.harvard.iq.dataverse.GlobalId;
import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public class CrossRefDOIProvider extends AbstractDOIProvider {
private static final Logger logger = Logger.getLogger(CrossRefDOIProvider.class.getCanonicalName());

public static final String TYPE = "crossref";

CrossRefDOIRegisterService crossRefDOIRegisterService;

public CrossRefDOIProvider(String id, String label, String providerAuthority, String providerShoulder, String identifierGenerationStyle, String datafilePidFormat, String managedList, String excludedList,
String url, String apiUrl, String username, String password, String depositor, String depositorEmail) {
super(id, label, providerAuthority, providerShoulder, identifierGenerationStyle, datafilePidFormat,
managedList, excludedList);

crossRefDOIRegisterService = new CrossRefDOIRegisterService(url, apiUrl, username, password, depositor, depositorEmail);
}

@Override
public boolean alreadyRegistered(GlobalId pid, boolean noProviderDefault) throws Exception {
logger.info("CrossRef alreadyRegistered");
if (pid == null || pid.asString().isEmpty()) {
logger.fine("No identifier sent.");
return false;
}
boolean alreadyExists;
String identifier = pid.asString();
try {
alreadyExists = crossRefDOIRegisterService.testDOIExists(identifier);
} catch (Exception e) {
logger.log(Level.WARNING, "alreadyExists failed");
return false;
}
return alreadyExists;
}

@Override
public boolean registerWhenPublished() {
return true;
}

@Override
public List<String> getProviderInformation() {
return List.of("CrossRef", "https://status.crossref.org/");
}

@Override
public String createIdentifier(DvObject dvObject) throws Throwable {
logger.info("CrossRef createIdentifier");
if (dvObject.getIdentifier() == null || dvObject.getIdentifier().isEmpty()) {
dvObject = generatePid(dvObject);
}
String identifier = getIdentifier(dvObject);
try {
String retString = crossRefDOIRegisterService.reserveIdentifier(identifier, dvObject);
logger.log(Level.FINE, "CrossRef create DOI identifier retString : " + retString);
return retString;
} catch (Exception e) {
logger.log(Level.WARNING, "CrossRef Identifier not created: create failed", e);
throw e;
}
}

@Override
public Map<String, String> getIdentifierMetadata(DvObject dvObject) {
logger.info("CrossRef getIdentifierMetadata");
String identifier = getIdentifier(dvObject);
Map<String, String> metadata = new HashMap<>();
try {
metadata = crossRefDOIRegisterService.getMetadata(identifier);
} catch (Exception e) {
logger.log(Level.WARNING, "getIdentifierMetadata failed", e);
}
return metadata;
}

@Override
public String modifyIdentifierTargetURL(DvObject dvObject) throws Exception {
logger.info("CrossRef modifyIdentifier");
String identifier = getIdentifier(dvObject);
try {
crossRefDOIRegisterService.modifyIdentifier(identifier, dvObject);
} catch (Exception e) {
logger.log(Level.WARNING, "modifyMetadata failed", e);
throw e;
}
return identifier;
}

@Override
public void deleteIdentifier(DvObject dvo) throws Exception {
logger.info("CrossRef deleteIdentifier");
}

@Override
public boolean publicizeIdentifier(DvObject dvObject) {
logger.info("CrossRef updateIdentifierStatus");
if (dvObject.getIdentifier() == null || dvObject.getIdentifier().isEmpty()) {
dvObject = generatePid(dvObject);
}
String identifier = getIdentifier(dvObject);

try {
crossRefDOIRegisterService.reserveIdentifier(identifier, dvObject);
return true;
} catch (Exception e) {
logger.log(Level.WARNING, "modifyMetadata failed: " + e.getMessage(), e);
return false;
}
}

@Override
public String getProviderType() {
return TYPE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package edu.harvard.iq.dataverse.pidproviders.doi.crossref;

import com.google.auto.service.AutoService;
import edu.harvard.iq.dataverse.pidproviders.PidProvider;
import edu.harvard.iq.dataverse.pidproviders.PidProviderFactory;
import edu.harvard.iq.dataverse.settings.JvmSettings;
import edu.harvard.iq.dataverse.util.SystemConfig;

@AutoService(PidProviderFactory.class)
public class CrossRefDOIProviderFactory implements PidProviderFactory {

@Override
public PidProvider createPidProvider(String providerId) {
String providerType = JvmSettings.PID_PROVIDER_TYPE.lookup(providerId);
if (!providerType.equals(CrossRefDOIProvider.TYPE)) {
// Being asked to create a non-CrossRef provider
return null;
}
String providerLabel = JvmSettings.PID_PROVIDER_LABEL.lookup(providerId);
String providerAuthority = JvmSettings.PID_PROVIDER_AUTHORITY.lookup(providerId);
String providerShoulder = JvmSettings.PID_PROVIDER_SHOULDER.lookupOptional(providerId).orElse("");
String identifierGenerationStyle = JvmSettings.PID_PROVIDER_IDENTIFIER_GENERATION_STYLE
.lookupOptional(providerId).orElse("randomString");
String datafilePidFormat = JvmSettings.PID_PROVIDER_DATAFILE_PID_FORMAT.lookupOptional(providerId)
.orElse(SystemConfig.DataFilePIDFormat.DEPENDENT.toString());
String managedList = JvmSettings.PID_PROVIDER_MANAGED_LIST.lookupOptional(providerId).orElse("");
String excludedList = JvmSettings.PID_PROVIDER_EXCLUDED_LIST.lookupOptional(providerId).orElse("");

String baseUrl = JvmSettings.CROSSREF_URL.lookup(providerId);
String apiUrl = JvmSettings.CROSSREF_REST_API_URL.lookup(providerId);
String username = JvmSettings.CROSSREF_USERNAME.lookup(providerId);
String password = JvmSettings.CROSSREF_PASSWORD.lookup(providerId);
String depositor = JvmSettings.CROSSREF_DEPOSITOR.lookup(providerId);
String depositorEmail = JvmSettings.CROSSREF_DEPOSITOR_EMAIL.lookup(providerId);

return new CrossRefDOIProvider(providerId, providerLabel, providerAuthority, providerShoulder, identifierGenerationStyle,
datafilePidFormat, managedList, excludedList, baseUrl, apiUrl, username, password, depositor, depositorEmail);
}

public String getType() {
return CrossRefDOIProvider.TYPE;
}
}
Loading
Loading