mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-18 07:23:08 +00:00
Fixes from testing
Conflicts: dspace-api/src/main/java/org/dspace/identifier/DataCiteIdentifierProvider.java dspace-api/src/test/java/org/dspace/identifier/DataCiteIdentifierProviderTest.java
This commit is contained in:

committed by
Pascal-Nicolas Becker

parent
98ee2d7e43
commit
e41eb134ed
@@ -16,4 +16,5 @@ package org.dspace.identifier;
|
|||||||
public class DOI
|
public class DOI
|
||||||
implements Identifier
|
implements Identifier
|
||||||
{
|
{
|
||||||
|
public static final String SCHEME = "doi:";
|
||||||
}
|
}
|
||||||
|
@@ -11,10 +11,11 @@ package org.dspace.identifier;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.logging.Level;
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.content.DCValue;
|
import org.dspace.content.DCValue;
|
||||||
import org.dspace.content.DSpaceObject;
|
import org.dspace.content.DSpaceObject;
|
||||||
@@ -60,15 +61,17 @@ public class DataCiteIdentifierProvider
|
|||||||
private static final Logger log = LoggerFactory.getLogger(DataCiteIdentifierProvider.class);
|
private static final Logger log = LoggerFactory.getLogger(DataCiteIdentifierProvider.class);
|
||||||
|
|
||||||
// Configuration property names
|
// Configuration property names
|
||||||
private static final String CFG_SHOULDER = "identifier.doi.ezid.shoulder";
|
static final String CFG_SHOULDER = "identifier.doi.ezid.shoulder";
|
||||||
private static final String CFG_USER = "identifier.doi.ezid.user";
|
static final String CFG_USER = "identifier.doi.ezid.user";
|
||||||
private static final String CFG_PASSWORD = "identifier.doi.ezid.password";
|
static final String CFG_PASSWORD = "identifier.doi.ezid.password";
|
||||||
|
|
||||||
// Metadata field name elements
|
// Metadata field name elements
|
||||||
// XXX move these to MetadataSchema or some such
|
// XXX move these to MetadataSchema or some such
|
||||||
public static final String MD_SCHEMA_DSPACE = "dspace";
|
public static final String MD_SCHEMA = "dc";
|
||||||
public static final String DSPACE_DOI_ELEMENT = "identifier";
|
public static final String DOI_ELEMENT = "identifier";
|
||||||
public static final String DSPACE_DOI_QUALIFIER = "doi";
|
public static final String DOI_QUALIFIER = null;
|
||||||
|
|
||||||
|
private static final String DOI_SCHEME = "doi:";
|
||||||
|
|
||||||
/** Map DataCite metadata into local metadata. */
|
/** Map DataCite metadata into local metadata. */
|
||||||
private static Map<String, String> crosswalk = new HashMap<String, String>();
|
private static Map<String, String> crosswalk = new HashMap<String, String>();
|
||||||
@@ -85,7 +88,10 @@ public class DataCiteIdentifierProvider
|
|||||||
@Override
|
@Override
|
||||||
public boolean supports(String identifier)
|
public boolean supports(String identifier)
|
||||||
{
|
{
|
||||||
return identifier.startsWith("doi:"); // XXX more thorough test?
|
if (null == identifier)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return identifier.startsWith(DOI_SCHEME); // XXX more thorough test?
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -94,22 +100,20 @@ public class DataCiteIdentifierProvider
|
|||||||
{
|
{
|
||||||
log.debug("register {}", dso);
|
log.debug("register {}", dso);
|
||||||
|
|
||||||
Item item;
|
if (!(dso instanceof Item))
|
||||||
|
|
||||||
if (dso instanceof Item)
|
|
||||||
item = (Item)dso;
|
|
||||||
else
|
|
||||||
throw new IdentifierException("Unsupported object type " + dso.getTypeText());
|
throw new IdentifierException("Unsupported object type " + dso.getTypeText());
|
||||||
|
|
||||||
String id;
|
Item item = (Item)dso;
|
||||||
DCValue[] previous = item.getMetadata(MD_SCHEMA_DSPACE, DSPACE_DOI_ELEMENT, DSPACE_DOI_QUALIFIER, null);
|
DCValue[] identifiers = item.getMetadata(MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null);
|
||||||
if ((previous.length > 0) && (null != previous[0].value))
|
for (DCValue identifier : identifiers)
|
||||||
return previous[0].value;
|
if ((null != identifier.value) && (identifier.value.startsWith(DOI_SCHEME)))
|
||||||
|
return identifier.value;
|
||||||
|
|
||||||
id = mint(context, item);
|
String id = mint(context, item);
|
||||||
item.addMetadata(MD_SCHEMA_DSPACE, DSPACE_DOI_ELEMENT, DSPACE_DOI_QUALIFIER, null, id);
|
item.addMetadata(MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null, id);
|
||||||
try {
|
try {
|
||||||
item.update();
|
item.update();
|
||||||
|
context.commit();
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
throw new IdentifierException("New identifier not stored", ex);
|
throw new IdentifierException("New identifier not stored", ex);
|
||||||
} catch (AuthorizeException ex) {
|
} catch (AuthorizeException ex) {
|
||||||
@@ -132,30 +136,29 @@ public class DataCiteIdentifierProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
EZIDResponse response;
|
EZIDResponse response;
|
||||||
String doi = "unknown"; // In case we can't even build a name
|
|
||||||
try {
|
try {
|
||||||
doi = getShoulder() + identifier;
|
EZIDRequest request = requestFactory.getInstance(loadAuthority(),
|
||||||
EZIDRequest request = requestFactory.getInstance(doi,
|
loadUser(), loadPassword());
|
||||||
getUser(), getPassword());
|
response = request.create(identifier, crosswalkMetadata(object));
|
||||||
response = request.create(crosswalkMetadata(object));
|
|
||||||
} catch (IdentifierException e) {
|
} catch (IdentifierException e) {
|
||||||
log.error("doi:{} not registered: {}", doi, e.getMessage());
|
log.error("Identifier '{}' not registered: {}", identifier, e.getMessage());
|
||||||
return;
|
return;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("doi:{} not registered: {}", doi, e.getMessage());
|
log.error("Identifier '{}' not registered: {}", identifier, e.getMessage());
|
||||||
return;
|
return;
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
log.error("doi:{} not registered: {}", doi, e.getMessage());
|
log.error("Identifier '{}' not registered: {}", identifier, e.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.isSuccess())
|
if (response.isSuccess())
|
||||||
{
|
{
|
||||||
Item item = (Item)object;
|
Item item = (Item)object;
|
||||||
item.addMetadata(MD_SCHEMA_DSPACE, DSPACE_DOI_ELEMENT,
|
|
||||||
DSPACE_DOI_QUALIFIER, null, identifier);
|
|
||||||
try {
|
try {
|
||||||
|
item.addMetadata(MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null,
|
||||||
|
idToDOI(identifier));
|
||||||
item.update();
|
item.update();
|
||||||
|
context.commit();
|
||||||
log.info("registered {}", identifier);
|
log.info("registered {}", identifier);
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
// TODO throw new IdentifierException("New identifier not stored", ex);
|
// TODO throw new IdentifierException("New identifier not stored", ex);
|
||||||
@@ -163,12 +166,14 @@ public class DataCiteIdentifierProvider
|
|||||||
} catch (AuthorizeException ex) {
|
} catch (AuthorizeException ex) {
|
||||||
// TODO throw new IdentifierException("New identifier not stored", ex);
|
// TODO throw new IdentifierException("New identifier not stored", ex);
|
||||||
log.error("New identifier not stored", ex);
|
log.error("New identifier not stored", ex);
|
||||||
|
} catch (IdentifierException ex) {
|
||||||
|
log.error("New identifier not stored", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log.error("doi:{} not registered -- EZID returned: {}", doi,
|
log.error("Identifier '{}' not registered -- EZID returned: {}",
|
||||||
response.getEZIDStatusValue());
|
identifier, response.getEZIDStatusValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,29 +184,27 @@ public class DataCiteIdentifierProvider
|
|||||||
log.debug("reserve {}", identifier);
|
log.debug("reserve {}", identifier);
|
||||||
|
|
||||||
EZIDResponse response;
|
EZIDResponse response;
|
||||||
String doi = "unknown"; // In case we can't even build a name
|
|
||||||
try {
|
try {
|
||||||
doi = getShoulder() + identifier;
|
EZIDRequest request = requestFactory.getInstance(loadAuthority(),
|
||||||
EZIDRequest request = requestFactory.getInstance(doi,
|
loadUser(), loadPassword());
|
||||||
getUser(), getPassword());
|
|
||||||
Map<String, String> metadata = crosswalkMetadata(dso);
|
Map<String, String> metadata = crosswalkMetadata(dso);
|
||||||
metadata.put("_status", "reserved");
|
metadata.put("_status", "reserved");
|
||||||
response = request.create(metadata);
|
response = request.create(identifier, metadata);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("doi:{} not registered: {}", doi, e.getMessage());
|
log.error("Identifier '{}' not registered: {}", identifier, e.getMessage());
|
||||||
return;
|
return;
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
log.error("doi:{} not registered: {}", doi, e.getMessage());
|
log.error("Identifier '{}' not registered: {}", identifier, e.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.isSuccess())
|
if (response.isSuccess())
|
||||||
{
|
{
|
||||||
Item item = (Item)dso;
|
Item item = (Item)dso;
|
||||||
item.addMetadata(MD_SCHEMA_DSPACE, DSPACE_DOI_ELEMENT,
|
item.addMetadata(MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null, idToDOI(identifier));
|
||||||
DSPACE_DOI_QUALIFIER, null, identifier);
|
|
||||||
try {
|
try {
|
||||||
item.update();
|
item.update();
|
||||||
|
context.commit();
|
||||||
log.info("reserved {}", identifier);
|
log.info("reserved {}", identifier);
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
throw new IdentifierException("New identifier not stored", ex);
|
throw new IdentifierException("New identifier not stored", ex);
|
||||||
@@ -211,8 +214,8 @@ public class DataCiteIdentifierProvider
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log.error("doi:{} not registered -- EZID returned: {}", doi,
|
log.error("Identifier '{}' not registered -- EZID returned: {}",
|
||||||
response.getEZIDStatusValue());
|
identifier, response.getEZIDStatusValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +228,7 @@ public class DataCiteIdentifierProvider
|
|||||||
// Compose the request
|
// Compose the request
|
||||||
EZIDRequest request;
|
EZIDRequest request;
|
||||||
try {
|
try {
|
||||||
request = requestFactory.getInstance(getShoulder(), getUser(), getPassword());
|
request = requestFactory.getInstance(loadAuthority(), loadUser(), loadPassword());
|
||||||
} catch (URISyntaxException ex) {
|
} catch (URISyntaxException ex) {
|
||||||
log.error(ex.getMessage());
|
log.error(ex.getMessage());
|
||||||
throw new IdentifierException("DOI request not sent: " + ex.getMessage());
|
throw new IdentifierException("DOI request not sent: " + ex.getMessage());
|
||||||
@@ -236,8 +239,10 @@ public class DataCiteIdentifierProvider
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
response = request.mint(crosswalkMetadata(dso));
|
response = request.mint(crosswalkMetadata(dso));
|
||||||
} catch (IOException ex)
|
} catch (IOException ex) {
|
||||||
{
|
log.error("Failed to send EZID request: {}", ex.getMessage());
|
||||||
|
throw new IdentifierException("DOI request not sent: " + ex.getMessage());
|
||||||
|
} catch (URISyntaxException ex) {
|
||||||
log.error("Failed to send EZID request: {}", ex.getMessage());
|
log.error("Failed to send EZID request: {}", ex.getMessage());
|
||||||
throw new IdentifierException("DOI request not sent: " + ex.getMessage());
|
throw new IdentifierException("DOI request not sent: " + ex.getMessage());
|
||||||
}
|
}
|
||||||
@@ -275,27 +280,33 @@ public class DataCiteIdentifierProvider
|
|||||||
{
|
{
|
||||||
log.debug("resolve {}", identifier);
|
log.debug("resolve {}", identifier);
|
||||||
|
|
||||||
try
|
ItemIterator found;
|
||||||
{
|
try {
|
||||||
ItemIterator found = Item.findByMetadataField(context, MD_SCHEMA_DSPACE, DSPACE_DOI_ELEMENT, DSPACE_DOI_QUALIFIER,
|
found = Item.findByMetadataField(context,
|
||||||
identifier);
|
MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER,
|
||||||
|
idToDOI(identifier));
|
||||||
|
} catch (IdentifierException ex) {
|
||||||
|
log.error(ex.getMessage());
|
||||||
|
throw new IdentifierNotResolvableException(ex);
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
log.error(ex.getMessage());
|
||||||
|
throw new IdentifierNotResolvableException(ex);
|
||||||
|
} catch (AuthorizeException ex) {
|
||||||
|
log.error(ex.getMessage());
|
||||||
|
throw new IdentifierNotResolvableException(ex);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
log.error(ex.getMessage());
|
||||||
|
throw new IdentifierNotResolvableException(ex);
|
||||||
|
}
|
||||||
|
try {
|
||||||
if (!found.hasNext())
|
if (!found.hasNext())
|
||||||
throw new IdentifierNotFoundException("No Item bound to DOI " + identifier);
|
throw new IdentifierNotFoundException("No object bound to " + identifier);
|
||||||
Item found1 = found.next();
|
Item found1 = found.next();
|
||||||
if (found.hasNext())
|
if (found.hasNext())
|
||||||
log.error("DOI {} multiply bound!", identifier);
|
log.error("More than one object bound to {}!", identifier);
|
||||||
log.debug("Resolved to {}", found1);
|
log.debug("Resolved to {}", found1);
|
||||||
return found1;
|
return found1;
|
||||||
} catch (SQLException ex)
|
} catch (SQLException ex) {
|
||||||
{
|
|
||||||
log.error(ex.getMessage());
|
|
||||||
throw new IdentifierNotResolvableException(ex);
|
|
||||||
} catch (AuthorizeException ex)
|
|
||||||
{
|
|
||||||
log.error(ex.getMessage());
|
|
||||||
throw new IdentifierNotResolvableException(ex);
|
|
||||||
} catch (IOException ex)
|
|
||||||
{
|
|
||||||
log.error(ex.getMessage());
|
log.error(ex.getMessage());
|
||||||
throw new IdentifierNotResolvableException(ex);
|
throw new IdentifierNotResolvableException(ex);
|
||||||
}
|
}
|
||||||
@@ -307,16 +318,21 @@ public class DataCiteIdentifierProvider
|
|||||||
{
|
{
|
||||||
log.debug("lookup {}", object);
|
log.debug("lookup {}", object);
|
||||||
|
|
||||||
Item item;
|
|
||||||
if (!(object instanceof Item))
|
if (!(object instanceof Item))
|
||||||
throw new IllegalArgumentException("Unsupported type " + object.getTypeText());
|
throw new IllegalArgumentException("Unsupported type " + object.getTypeText());
|
||||||
|
|
||||||
item = (Item)object;
|
Item item = (Item)object;
|
||||||
DCValue[] metadata = item.getMetadata(MD_SCHEMA_DSPACE, DSPACE_DOI_ELEMENT, DSPACE_DOI_QUALIFIER, null);
|
DCValue found = null;
|
||||||
if (metadata.length > 0)
|
for (DCValue candidate : item.getMetadata(MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null))
|
||||||
|
if (candidate.value.startsWith(DOI_SCHEME))
|
||||||
|
{
|
||||||
|
found = candidate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (null != found)
|
||||||
{
|
{
|
||||||
log.debug("Found {}", metadata[0].value);
|
log.debug("Found {}", found.value);
|
||||||
return metadata[0].value;
|
return found.value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new IdentifierNotFoundException(object.getTypeText() + " "
|
throw new IdentifierNotFoundException(object.getTypeText() + " "
|
||||||
@@ -332,34 +348,62 @@ public class DataCiteIdentifierProvider
|
|||||||
if (!(dso instanceof Item))
|
if (!(dso instanceof Item))
|
||||||
throw new IllegalArgumentException("Unsupported type " + dso.getTypeText());
|
throw new IllegalArgumentException("Unsupported type " + dso.getTypeText());
|
||||||
|
|
||||||
String username = configurationService.getProperty(CFG_USER);
|
|
||||||
String password = configurationService.getProperty(CFG_PASSWORD);
|
|
||||||
if (null == username || null == password)
|
|
||||||
throw new IdentifierException("Unconfigured: define " + CFG_USER
|
|
||||||
+ " and " + CFG_PASSWORD);
|
|
||||||
|
|
||||||
Item item = (Item)dso;
|
Item item = (Item)dso;
|
||||||
|
|
||||||
// delete from EZID
|
// delete from EZID
|
||||||
for (DCValue id : item.getMetadata(MD_SCHEMA_DSPACE, DSPACE_DOI_ELEMENT,
|
DCValue[] metadata = item.getMetadata(MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null);
|
||||||
DSPACE_DOI_QUALIFIER, null))
|
List<String> remainder = new ArrayList<String>();
|
||||||
|
int skipped = 0;
|
||||||
|
for (DCValue id : metadata)
|
||||||
{
|
{
|
||||||
|
if (!id.value.startsWith(DOI_SCHEME))
|
||||||
|
{
|
||||||
|
remainder.add(id.value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
EZIDResponse response;
|
EZIDResponse response;
|
||||||
try {
|
try {
|
||||||
EZIDRequest request = requestFactory.getInstance(id.value, username, password);
|
EZIDRequest request = requestFactory.getInstance(loadAuthority(),
|
||||||
response = request.delete();
|
loadUser(), loadPassword());
|
||||||
|
response = request.delete(DOIToId(id.value));
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
throw new IdentifierException("Bad URI in metadata value", e);
|
log.error("Bad URI in metadata value: {}", e.getMessage());
|
||||||
|
remainder.add(id.value);
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IdentifierException("Failed request to EZID", e);
|
log.error("Failed request to EZID: {}", e.getMessage());
|
||||||
|
remainder.add(id.value);
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (!response.isSuccess())
|
if (!response.isSuccess())
|
||||||
throw new IdentifierException("Unable to delete " + id.value
|
{
|
||||||
+ "from DataCite: " + response.getEZIDStatusValue());
|
log.error("Unable to delete {} from DataCite: {}", id.value,
|
||||||
|
response.getEZIDStatusValue());
|
||||||
|
remainder.add(id.value);
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
log.info("Deleted {}", id.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete from item
|
// delete from item
|
||||||
item.clearMetadata(MD_SCHEMA_DSPACE, DSPACE_DOI_ELEMENT, DSPACE_DOI_QUALIFIER, null);
|
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) {
|
||||||
|
log.error("Failed to re-add identifiers: {}", e.getMessage());
|
||||||
|
} catch (AuthorizeException e) {
|
||||||
|
log.error("Failed to re-add identifiers: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skipped > 0)
|
||||||
|
throw new IdentifierException(skipped + " identifiers could not be deleted.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -368,14 +412,98 @@ public class DataCiteIdentifierProvider
|
|||||||
{
|
{
|
||||||
log.debug("delete {} from {}", identifier, dso);
|
log.debug("delete {} from {}", identifier, dso);
|
||||||
|
|
||||||
throw new UnsupportedOperationException("Not supported yet."); // TODO implement delete(specific)
|
if (!(dso instanceof Item))
|
||||||
// TODO find metadata value == identifier
|
throw new IllegalArgumentException("Unsupported type " + dso.getTypeText());
|
||||||
// TODO delete from EZID
|
|
||||||
|
|
||||||
// TODO delete from item NOTE!!! can't delete single MD values!
|
Item item = (Item)dso;
|
||||||
|
|
||||||
|
DCValue[] metadata = item.getMetadata(MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null);
|
||||||
|
List<String> remainder = new ArrayList<String>();
|
||||||
|
int skipped = 0;
|
||||||
|
for (DCValue id : metadata)
|
||||||
|
{
|
||||||
|
if (!id.value.equals(idToDOI(identifier)))
|
||||||
|
{
|
||||||
|
remainder.add(id.value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
EZIDResponse response;
|
||||||
|
try {
|
||||||
|
EZIDRequest request = requestFactory.getInstance(loadAuthority(),
|
||||||
|
loadUser(), loadPassword());
|
||||||
|
response = request.delete(DOIToId(id.value));
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
log.error("Bad URI in metadata value {}: {}", id.value, e.getMessage());
|
||||||
|
remainder.add(id.value);
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Failed request to EZID: {}", e.getMessage());
|
||||||
|
remainder.add(id.value);
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.isSuccess())
|
||||||
|
{
|
||||||
|
log.error("Unable to delete {} from DataCite: {}", id.value,
|
||||||
|
response.getEZIDStatusValue());
|
||||||
|
remainder.add(id.value);
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
log.info("Deleted {}", id.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete from item
|
||||||
|
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) {
|
||||||
|
log.error("Failed to re-add identifiers: {}", e.getMessage());
|
||||||
|
} catch (AuthorizeException e) {
|
||||||
|
log.error("Failed to re-add identifiers: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skipped > 0)
|
||||||
|
throw new IdentifierException(identifier + " could not be deleted.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getUser()
|
/**
|
||||||
|
* Format a naked identifier as a DOI with our configured authority prefix.
|
||||||
|
*
|
||||||
|
* @throws IdentifierException if authority prefix is not configured.
|
||||||
|
*/
|
||||||
|
String idToDOI(String id)
|
||||||
|
throws IdentifierException
|
||||||
|
{
|
||||||
|
return "doi:" + loadAuthority() + id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove scheme and our configured authority prefix from a doi: URI string.
|
||||||
|
* @return naked local identifier.
|
||||||
|
* @throws IdentifierException if authority prefix is not configured.
|
||||||
|
*/
|
||||||
|
String DOIToId(String DOI)
|
||||||
|
throws IdentifierException
|
||||||
|
{
|
||||||
|
String prefix = "doi:" + loadAuthority();
|
||||||
|
if (DOI.startsWith(prefix))
|
||||||
|
return DOI.substring(prefix.length());
|
||||||
|
else
|
||||||
|
return DOI;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get configured value of EZID username.
|
||||||
|
* @throws IdentifierException
|
||||||
|
*/
|
||||||
|
private String loadUser()
|
||||||
throws IdentifierException
|
throws IdentifierException
|
||||||
{
|
{
|
||||||
String user = configurationService.getProperty(CFG_USER);
|
String user = configurationService.getProperty(CFG_USER);
|
||||||
@@ -385,7 +513,11 @@ public class DataCiteIdentifierProvider
|
|||||||
throw new IdentifierException("Unconfigured: define " + CFG_USER);
|
throw new IdentifierException("Unconfigured: define " + CFG_USER);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPassword()
|
/**
|
||||||
|
* Get configured value of EZID password.
|
||||||
|
* @throws IdentifierException
|
||||||
|
*/
|
||||||
|
private String loadPassword()
|
||||||
throws IdentifierException
|
throws IdentifierException
|
||||||
{
|
{
|
||||||
String password = configurationService.getProperty(CFG_PASSWORD);
|
String password = configurationService.getProperty(CFG_PASSWORD);
|
||||||
@@ -395,7 +527,11 @@ public class DataCiteIdentifierProvider
|
|||||||
throw new IdentifierException("Unconfigured: define " + CFG_PASSWORD);
|
throw new IdentifierException("Unconfigured: define " + CFG_PASSWORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getShoulder()
|
/**
|
||||||
|
* Get configured value of EZID "shoulder".
|
||||||
|
* @throws IdentifierException
|
||||||
|
*/
|
||||||
|
private String loadAuthority()
|
||||||
throws IdentifierException
|
throws IdentifierException
|
||||||
{
|
{
|
||||||
String shoulder = configurationService.getProperty(CFG_SHOULDER);
|
String shoulder = configurationService.getProperty(CFG_SHOULDER);
|
||||||
@@ -423,21 +559,18 @@ public class DataCiteIdentifierProvider
|
|||||||
for (DCValue value : values)
|
for (DCValue value : values)
|
||||||
mapped.put(datum.getKey(), value.value);
|
mapped.put(datum.getKey(), value.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO find a way to get a current direct URL to the object and set _target
|
||||||
|
// mapped.put("_target", url);
|
||||||
|
|
||||||
return mapped;
|
return mapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param aCrosswalk the crosswalk to set
|
|
||||||
*/
|
|
||||||
@Required
|
@Required
|
||||||
public void setCrosswalk(Map<String, String> aCrosswalk)
|
public void setCrosswalk(Map<String, String> aCrosswalk)
|
||||||
{
|
{
|
||||||
crosswalk = aCrosswalk;
|
crosswalk = aCrosswalk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param aRequestFactory the requestFactory to set
|
|
||||||
*/
|
|
||||||
@Required
|
@Required
|
||||||
public static void setRequestFactory(EZIDRequestFactory aRequestFactory)
|
public static void setRequestFactory(EZIDRequestFactory aRequestFactory)
|
||||||
{
|
{
|
||||||
|
@@ -11,7 +11,6 @@ import java.io.IOException;
|
|||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@@ -25,6 +24,7 @@ import org.apache.http.client.methods.HttpPut;
|
|||||||
import org.apache.http.entity.StringEntity;
|
import org.apache.http.entity.StringEntity;
|
||||||
import org.apache.http.impl.client.AbstractHttpClient;
|
import org.apache.http.impl.client.AbstractHttpClient;
|
||||||
import org.apache.http.impl.client.DefaultHttpClient;
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
|
import org.dspace.identifier.DOI;
|
||||||
import org.dspace.identifier.IdentifierException;
|
import org.dspace.identifier.IdentifierException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -38,42 +38,63 @@ public class EZIDRequest
|
|||||||
{
|
{
|
||||||
private static final Logger log = LoggerFactory.getLogger(EZIDRequest.class);
|
private static final Logger log = LoggerFactory.getLogger(EZIDRequest.class);
|
||||||
|
|
||||||
private URI url;
|
private static final String ID_PATH = "/ezid/id/" + DOI.SCHEME;
|
||||||
|
|
||||||
private AbstractHttpClient client;
|
private static final String SHOULDER_PATH = "/ezid/shoulder/" + DOI.SCHEME;
|
||||||
|
|
||||||
|
private static final String UTF_8 = "UTF-8";
|
||||||
|
|
||||||
|
private static final String MD_KEY_STATUS = "_status";
|
||||||
|
|
||||||
|
private final AbstractHttpClient client;
|
||||||
|
|
||||||
|
private final String scheme;
|
||||||
|
|
||||||
|
private final String host;
|
||||||
|
|
||||||
|
private final String authority;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare a context for requests concerning a specific identifier or
|
* Prepare a context for requests concerning a specific identifier or
|
||||||
* authority prefix.
|
* authority prefix.
|
||||||
*
|
*
|
||||||
* @param url EZID API service point (and object) for this request.
|
* @param scheme
|
||||||
|
* @param host
|
||||||
|
* @param authority DOI authority prefix.
|
||||||
* @param username an EZID user identity.
|
* @param username an EZID user identity.
|
||||||
* @param password user's password, or null for none.
|
* @param password user's password, or {@code null} for none.
|
||||||
|
* @throws URISyntaxException if host or authority is bad.
|
||||||
*/
|
*/
|
||||||
EZIDRequest(URI url, String username, String password)
|
EZIDRequest(String scheme, String host, String authority, String username, String password)
|
||||||
throws URISyntaxException
|
throws URISyntaxException
|
||||||
{
|
{
|
||||||
this.url = url;
|
this.scheme = scheme;
|
||||||
|
this.host = host;
|
||||||
|
this.authority = authority;
|
||||||
client = new DefaultHttpClient();
|
client = new DefaultHttpClient();
|
||||||
if (null != username)
|
if (null != username)
|
||||||
|
{
|
||||||
|
URI uri = new URI(scheme, host, null, null);
|
||||||
client.getCredentialsProvider().setCredentials(
|
client.getCredentialsProvider().setCredentials(
|
||||||
new AuthScope(url.getHost(), url.getPort()),
|
new AuthScope(uri.getHost(), uri.getPort()),
|
||||||
new UsernamePasswordCredentials(username, password));
|
new UsernamePasswordCredentials(username, password));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch an identifier's metadata.
|
* Fetch the metadata bound to an identifier.
|
||||||
*
|
*
|
||||||
* @return
|
|
||||||
* @throws IdentifierException if the response is error or body malformed.
|
* @throws IdentifierException if the response is error or body malformed.
|
||||||
* @throws IOException if the HTTP request fails.
|
* @throws IOException if the HTTP request fails.
|
||||||
|
* @throws URISyntaxException
|
||||||
*/
|
*/
|
||||||
public EZIDResponse lookup()
|
public EZIDResponse lookup(String name)
|
||||||
throws IdentifierException, IOException
|
throws IdentifierException, IOException, URISyntaxException
|
||||||
{
|
{
|
||||||
// GET path
|
// GET path
|
||||||
HttpGet request;
|
HttpGet request;
|
||||||
request = new HttpGet(url);
|
URI uri = new URI(scheme, host, ID_PATH + authority + name, null);
|
||||||
|
request = new HttpGet(uri);
|
||||||
HttpResponse response = client.execute(request);
|
HttpResponse response = client.execute(request);
|
||||||
return new EZIDResponse(response);
|
return new EZIDResponse(response);
|
||||||
}
|
}
|
||||||
@@ -86,16 +107,17 @@ public class EZIDRequest
|
|||||||
* @param metadata ANVL-encoded key/value pairs.
|
* @param metadata ANVL-encoded key/value pairs.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public EZIDResponse create(Map<String, String> metadata)
|
public EZIDResponse create(String name, Map<String, String> metadata)
|
||||||
throws IOException, IdentifierException
|
throws IOException, IdentifierException, URISyntaxException
|
||||||
{
|
{
|
||||||
// PUT path [+metadata]
|
// PUT path [+metadata]
|
||||||
HttpPut request;
|
HttpPut request;
|
||||||
request = new HttpPut(url);
|
URI uri = new URI(scheme, host, ID_PATH + authority + name, null);
|
||||||
|
request = new HttpPut(uri);
|
||||||
if (null != metadata)
|
if (null != metadata)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
request.setEntity(new StringEntity(formatMetadata(metadata), "UTF-8"));
|
request.setEntity(new StringEntity(formatMetadata(metadata), UTF_8));
|
||||||
} catch (UnsupportedEncodingException ex) { /* SNH */ }
|
} catch (UnsupportedEncodingException ex) { /* SNH */ }
|
||||||
}
|
}
|
||||||
HttpResponse response = client.execute(request);
|
HttpResponse response = client.execute(request);
|
||||||
@@ -110,30 +132,30 @@ public class EZIDRequest
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public EZIDResponse mint(Map<String, String> metadata)
|
public EZIDResponse mint(Map<String, String> metadata)
|
||||||
throws IOException, IdentifierException
|
throws IOException, IdentifierException, URISyntaxException
|
||||||
{
|
{
|
||||||
// POST path [+metadata]
|
// POST path [+metadata]
|
||||||
HttpPost request;
|
HttpPost request;
|
||||||
request = new HttpPost(url);
|
URI uri = new URI(scheme, host, SHOULDER_PATH + authority, null);
|
||||||
|
request = new HttpPost(uri);
|
||||||
if (null != metadata)
|
if (null != metadata)
|
||||||
{
|
{
|
||||||
request.setEntity(new StringEntity(formatMetadata(metadata), "UTF-8"));
|
request.setEntity(new StringEntity(formatMetadata(metadata), UTF_8));
|
||||||
}
|
}
|
||||||
HttpResponse response = client.execute(request);
|
HttpResponse response = client.execute(request);
|
||||||
EZIDResponse myResponse = new EZIDResponse(response);
|
EZIDResponse myResponse = new EZIDResponse(response);
|
||||||
// TODO add the identifier to the path for subsequent operations?
|
|
||||||
return myResponse;
|
return myResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alter the identifier's metadata.
|
* Alter the metadata bound to an identifier.
|
||||||
*
|
*
|
||||||
* @param metadata fields to be altered. Leave a field's value empty to
|
* @param metadata fields to be altered. Leave the value of a field's empty
|
||||||
* delete the field.
|
* to delete the field.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public EZIDResponse modify(Map<String, String> metadata)
|
public EZIDResponse modify(String name, Map<String, String> metadata)
|
||||||
throws IOException, IdentifierException
|
throws IOException, IdentifierException, URISyntaxException
|
||||||
{
|
{
|
||||||
if (null == metadata)
|
if (null == metadata)
|
||||||
{
|
{
|
||||||
@@ -141,8 +163,9 @@ public class EZIDRequest
|
|||||||
}
|
}
|
||||||
// POST path +metadata
|
// POST path +metadata
|
||||||
HttpPost request;
|
HttpPost request;
|
||||||
request = new HttpPost(url);
|
URI uri = new URI(scheme, host, ID_PATH + authority + name, null);
|
||||||
request.setEntity(new StringEntity(formatMetadata(metadata), "UTF-8"));
|
request = new HttpPost(uri);
|
||||||
|
request.setEntity(new StringEntity(formatMetadata(metadata), UTF_8));
|
||||||
HttpResponse response = client.execute(request);
|
HttpResponse response = client.execute(request);
|
||||||
return new EZIDResponse(response);
|
return new EZIDResponse(response);
|
||||||
}
|
}
|
||||||
@@ -150,12 +173,13 @@ public class EZIDRequest
|
|||||||
/**
|
/**
|
||||||
* Destroy a reserved identifier. Fails if ID was ever public.
|
* Destroy a reserved identifier. Fails if ID was ever public.
|
||||||
*/
|
*/
|
||||||
public EZIDResponse delete()
|
public EZIDResponse delete(String name)
|
||||||
throws IOException, IdentifierException
|
throws IOException, IdentifierException, URISyntaxException
|
||||||
{
|
{
|
||||||
// DELETE path
|
// DELETE path
|
||||||
HttpDelete request;
|
HttpDelete request;
|
||||||
request = new HttpDelete(url);
|
URI uri = new URI(scheme, host, ID_PATH + authority + name, null);
|
||||||
|
request = new HttpDelete(uri);
|
||||||
HttpResponse response = client.execute(request);
|
HttpResponse response = client.execute(request);
|
||||||
return new EZIDResponse(response);
|
return new EZIDResponse(response);
|
||||||
}
|
}
|
||||||
@@ -163,12 +187,12 @@ public class EZIDRequest
|
|||||||
/**
|
/**
|
||||||
* Remove a public identifier from view.
|
* Remove a public identifier from view.
|
||||||
*/
|
*/
|
||||||
public EZIDResponse withdraw()
|
public EZIDResponse withdraw(String name)
|
||||||
throws IOException, IdentifierException
|
throws IOException, IdentifierException, URISyntaxException
|
||||||
{
|
{
|
||||||
Map<String, String> metadata = new HashMap<String, String>();
|
Map<String, String> metadata = new HashMap<String, String>();
|
||||||
metadata.put("_status", "unavailable");
|
metadata.put(MD_KEY_STATUS, "unavailable");
|
||||||
return modify(metadata);
|
return modify(name, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -176,38 +200,39 @@ public class EZIDRequest
|
|||||||
*
|
*
|
||||||
* @param reason annotation for the item's unavailability.
|
* @param reason annotation for the item's unavailability.
|
||||||
*/
|
*/
|
||||||
public EZIDResponse withdraw(String reason)
|
public EZIDResponse withdraw(String name, String reason)
|
||||||
throws IOException, IdentifierException
|
throws IOException, IdentifierException, URISyntaxException
|
||||||
{
|
{
|
||||||
String reasonEncoded = null;
|
|
||||||
try {
|
|
||||||
reasonEncoded = URLEncoder.encode(reason, "UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) { /* XXX SNH */ }
|
|
||||||
Map<String, String> metadata = new HashMap<String, String>();
|
Map<String, String> metadata = new HashMap<String, String>();
|
||||||
metadata.put("_status", "unavailable | " + reasonEncoded);
|
metadata.put(MD_KEY_STATUS, "unavailable | " + escape(reason));
|
||||||
return modify(metadata);
|
return modify(name, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create ANVL-formatted name/value pairs from a Map.
|
* Create ANVL-formatted name/value pairs from a Map.
|
||||||
*/
|
*/
|
||||||
private String formatMetadata(Map<String, String> raw)
|
private static String formatMetadata(Map<String, String> raw)
|
||||||
{
|
{
|
||||||
StringBuilder formatted = new StringBuilder();
|
StringBuilder formatted = new StringBuilder();
|
||||||
for (Entry<String, String> entry : raw.entrySet())
|
for (Entry<String, String> entry : raw.entrySet())
|
||||||
formatted.append(entry.getKey())
|
{
|
||||||
|
formatted.append(escape(entry.getKey()))
|
||||||
.append(": ")
|
.append(": ")
|
||||||
.append(entry.getValue())
|
.append(escape(entry.getValue()))
|
||||||
.append('\n');
|
.append('\n');
|
||||||
|
|
||||||
// Body should be percent-encoded
|
|
||||||
String body = null;
|
|
||||||
try {
|
|
||||||
body = URLEncoder.encode(formatted.toString(), "UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException ex) { // XXX SNH
|
|
||||||
log.error(ex.getMessage());
|
|
||||||
} finally {
|
|
||||||
return body;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return formatted.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Percent-encode a few EZID-specific characters.
|
||||||
|
*/
|
||||||
|
private static String escape(String s)
|
||||||
|
{
|
||||||
|
return s.replace("%", "%25")
|
||||||
|
.replace("\n", "%0A")
|
||||||
|
.replace("\r", "%0D")
|
||||||
|
.replace(":", "%3A");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,6 @@
|
|||||||
package org.dspace.identifier.ezid;
|
package org.dspace.identifier.ezid;
|
||||||
|
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import org.apache.http.client.utils.URIBuilder;
|
|
||||||
import org.springframework.beans.factory.annotation.Required;
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,42 +31,19 @@ public class EZIDRequestFactory
|
|||||||
{
|
{
|
||||||
private static String EZID_SCHEME;
|
private static String EZID_SCHEME;
|
||||||
private static String EZID_HOST;
|
private static String EZID_HOST;
|
||||||
private static String EZID_PATH;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure an EZID request.
|
* Configure an EZID request.
|
||||||
*
|
*
|
||||||
* @param requestPath specific request (DOI, shoulder).
|
* @param authority our DOI authority number.
|
||||||
* @param username
|
* @param username EZID user name.
|
||||||
* @param password
|
* @param password {@code username}'s password.
|
||||||
* @throws URISyntaxException
|
* @throws URISyntaxException
|
||||||
*/
|
*/
|
||||||
public EZIDRequest getInstance(String requestPath, String username, String password)
|
public EZIDRequest getInstance(String authority, String username, String password)
|
||||||
throws URISyntaxException
|
throws URISyntaxException
|
||||||
{
|
{
|
||||||
URIBuilder uri = new URIBuilder();
|
return new EZIDRequest(EZID_SCHEME, EZID_HOST, authority, username, password);
|
||||||
|
|
||||||
uri.setScheme(EZID_SCHEME);
|
|
||||||
|
|
||||||
uri.setHost(EZID_HOST);
|
|
||||||
|
|
||||||
String head, tail;
|
|
||||||
if (EZID_PATH.endsWith("/"))
|
|
||||||
head = EZID_PATH.substring(0, EZID_PATH.length() - 1);
|
|
||||||
else
|
|
||||||
head = EZID_PATH;
|
|
||||||
if (requestPath.startsWith("/"))
|
|
||||||
tail = requestPath.substring( 0, requestPath.length() - 1);
|
|
||||||
else
|
|
||||||
tail = requestPath;
|
|
||||||
|
|
||||||
StringBuilder path = new StringBuilder();
|
|
||||||
path.append(head);
|
|
||||||
path.append('/');
|
|
||||||
path.append(tail);
|
|
||||||
uri.setPath(path.toString());
|
|
||||||
|
|
||||||
return new EZIDRequest(uri.build(), username, password);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,13 +63,4 @@ public class EZIDRequestFactory
|
|||||||
{
|
{
|
||||||
EZID_HOST = aEZID_HOST;
|
EZID_HOST = aEZID_HOST;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param aEZID_PATH the EZID path to set
|
|
||||||
*/
|
|
||||||
@Required
|
|
||||||
public static void setEZID_PATH(String aEZID_PATH)
|
|
||||||
{
|
|
||||||
EZID_PATH = aEZID_PATH;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -29,6 +29,8 @@ public class EZIDResponse
|
|||||||
{
|
{
|
||||||
private static final Logger log = LoggerFactory.getLogger(EZIDResponse.class);
|
private static final Logger log = LoggerFactory.getLogger(EZIDResponse.class);
|
||||||
|
|
||||||
|
private static final String UTF_8 = "UTF-8";
|
||||||
|
|
||||||
private final String status;
|
private final String status;
|
||||||
|
|
||||||
private final String statusValue;
|
private final String statusValue;
|
||||||
@@ -48,7 +50,7 @@ public class EZIDResponse
|
|||||||
String body;
|
String body;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
body = EntityUtils.toString(responseBody, "UTF-8");
|
body = EntityUtils.toString(responseBody, UTF_8);
|
||||||
} catch (IOException ex)
|
} catch (IOException ex)
|
||||||
{
|
{
|
||||||
log.error(ex.getMessage());
|
log.error(ex.getMessage());
|
||||||
@@ -83,10 +85,10 @@ public class EZIDResponse
|
|||||||
parts = lines[i].split(":", 2);
|
parts = lines[i].split(":", 2);
|
||||||
String key = null, value = null;
|
String key = null, value = null;
|
||||||
try {
|
try {
|
||||||
key = URLDecoder.decode(parts[0], "UTF-8").trim();
|
key = URLDecoder.decode(parts[0], UTF_8).trim();
|
||||||
if (parts.length > 1)
|
if (parts.length > 1)
|
||||||
{
|
{
|
||||||
value = URLDecoder.decode(parts[1], "UTF-8").trim();
|
value = URLDecoder.decode(parts[1], UTF_8).trim();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -120,7 +122,7 @@ public class EZIDResponse
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Value associated with the EZID status (identifier, error text, etc.)
|
* Value associated with the EZID status (identifier, error text, etc.).
|
||||||
*/
|
*/
|
||||||
public String getEZIDStatusValue()
|
public String getEZIDStatusValue()
|
||||||
{
|
{
|
||||||
|
@@ -22,12 +22,11 @@
|
|||||||
<bean class='org.dspace.identifier.ezid.EZIDRequestFactory'>
|
<bean class='org.dspace.identifier.ezid.EZIDRequestFactory'>
|
||||||
<property name='EZID_SCHEME' value='https'/>
|
<property name='EZID_SCHEME' value='https'/>
|
||||||
<property name='EZID_HOST' value='n2t.net'/>
|
<property name='EZID_HOST' value='n2t.net'/>
|
||||||
<property name='EZID_PATH' value='/ezid/shoulder/'/>
|
|
||||||
</bean>
|
</bean>
|
||||||
</property>
|
</property>
|
||||||
<property name='crosswalk'>
|
<property name='crosswalk'>
|
||||||
<map>
|
<map>
|
||||||
<entry key='datacite.creator' value='dc.creator.author'/>
|
<entry key='datacite.creator' value='dc.contributor.author'/>
|
||||||
<entry key='datacite.title' value='dc.title'/>
|
<entry key='datacite.title' value='dc.title'/>
|
||||||
<entry key='datacite.publisher' value='dc.publisher'/>
|
<entry key='datacite.publisher' value='dc.publisher'/>
|
||||||
<entry key='datacite.publicationyear' value='dc.date.published'/>
|
<entry key='datacite.publicationyear' value='dc.date.published'/>
|
||||||
|
@@ -8,16 +8,17 @@
|
|||||||
|
|
||||||
package org.dspace.identifier;
|
package org.dspace.identifier;
|
||||||
|
|
||||||
import java.util.List;
|
import java.io.IOException;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.UUID;
|
||||||
import org.dspace.AbstractUnitTest;
|
import org.dspace.AbstractUnitTest;
|
||||||
import org.dspace.content.Collection;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.content.Community;
|
import org.dspace.content.*;
|
||||||
import org.dspace.content.DSpaceObject;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.content.WorkspaceItem;
|
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.kernel.ServiceManager;
|
import org.dspace.kernel.ServiceManager;
|
||||||
import org.dspace.services.ConfigurationService;
|
import org.dspace.services.ConfigurationService;
|
||||||
|
import org.dspace.workflow.WorkflowItem;
|
||||||
|
import org.dspace.workflow.WorkflowManager;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
@@ -28,29 +29,85 @@ import static org.junit.Assert.*;
|
|||||||
public class DataCiteIdentifierProviderTest
|
public class DataCiteIdentifierProviderTest
|
||||||
extends AbstractUnitTest
|
extends AbstractUnitTest
|
||||||
{
|
{
|
||||||
private static final String TEST_SHOULDER = "doi:10.5072/FK2";
|
/** Name of the reserved EZID test authority */
|
||||||
|
private static final String TEST_SHOULDER = "10.5072/FK2";
|
||||||
|
|
||||||
private static ServiceManager sm = null;
|
private static ServiceManager sm = null;
|
||||||
|
|
||||||
private static ConfigurationService config = null;
|
private static ConfigurationService config = null;
|
||||||
|
|
||||||
private static Item item = null;
|
private static Community community;
|
||||||
|
|
||||||
|
private static Collection collection;
|
||||||
|
|
||||||
|
/** The most recently created test Item's ID */
|
||||||
|
private static int itemID;
|
||||||
|
|
||||||
public DataCiteIdentifierProviderTest()
|
public DataCiteIdentifierProviderTest()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
item.update();
|
||||||
|
itemID = item.getID();
|
||||||
|
|
||||||
|
ctx.commit();
|
||||||
|
ctx.restoreAuthSystemState();
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUpClass()
|
public static void setUpClass()
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
// Create an object to work with
|
|
||||||
Context ctx = new Context();
|
Context ctx = new Context();
|
||||||
ctx.turnOffAuthorisationSystem();
|
ctx.turnOffAuthorisationSystem();
|
||||||
Community community = Community.create(null, ctx);
|
|
||||||
Collection collection = community.createCollection();
|
ctx.setCurrentUser(eperson);
|
||||||
WorkspaceItem wsItem = WorkspaceItem.create(ctx, collection, false);
|
|
||||||
item = wsItem.getItem();
|
// 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();
|
ctx.complete();
|
||||||
|
|
||||||
// Find the usual kernel services
|
// Find the usual kernel services
|
||||||
@@ -58,26 +115,35 @@ public class DataCiteIdentifierProviderTest
|
|||||||
|
|
||||||
config = kernelImpl.getConfigurationService();
|
config = kernelImpl.getConfigurationService();
|
||||||
|
|
||||||
// Configure the service under test
|
// Configure the service under test.
|
||||||
config.setProperty("identifier.doi.ezid.shoulder", TEST_SHOULDER);
|
config.setProperty(DataCiteIdentifierProvider.CFG_SHOULDER, TEST_SHOULDER);
|
||||||
config.setProperty("identifier.doi.ezid.user", "apitest");
|
config.setProperty(DataCiteIdentifierProvider.CFG_USER, "apitest");
|
||||||
config.setProperty("identifier.doi.ezid.password", "apitest");
|
config.setProperty(DataCiteIdentifierProvider.CFG_PASSWORD, "apitest");
|
||||||
|
|
||||||
|
// Don't try to send mail.
|
||||||
|
config.setProperty("mail.server.disabled", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void tearDownClass()
|
public static void tearDownClass()
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
|
System.out.print("Tearing down\n\n");
|
||||||
|
Context ctx = new Context();
|
||||||
|
dumpMetadata(Item.find(ctx, itemID));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp()
|
public void setUp()
|
||||||
{
|
{
|
||||||
|
context.setCurrentUser(eperson);
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown()
|
public void tearDown()
|
||||||
{
|
{
|
||||||
|
context.restoreAuthSystemState();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -103,7 +169,7 @@ public class DataCiteIdentifierProviderTest
|
|||||||
System.out.println("supports");
|
System.out.println("supports");
|
||||||
DataCiteIdentifierProvider instance = new DataCiteIdentifierProvider();
|
DataCiteIdentifierProvider instance = new DataCiteIdentifierProvider();
|
||||||
|
|
||||||
String identifier = TEST_SHOULDER;
|
String identifier = "doi:" + TEST_SHOULDER;
|
||||||
boolean result = instance.supports(identifier);
|
boolean result = instance.supports(identifier);
|
||||||
assertTrue(identifier + " should be supported", result);
|
assertTrue(identifier + " should be supported", result);
|
||||||
}
|
}
|
||||||
@@ -115,16 +181,16 @@ public class DataCiteIdentifierProviderTest
|
|||||||
public void testRegister_Context_DSpaceObject()
|
public void testRegister_Context_DSpaceObject()
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
System.out.println("register");
|
System.out.println("register 2");
|
||||||
|
|
||||||
List<DataCiteIdentifierProvider> instance
|
List<DataCiteIdentifierProvider> instance
|
||||||
= (List<DataCiteIdentifierProvider>)
|
= (List<DataCiteIdentifierProvider>)
|
||||||
sm.getServicesByType(DataCiteIdentifierProvider.class);
|
sm.getServicesByType(DataCiteIdentifierProvider.class);
|
||||||
|
|
||||||
DSpaceObject dso = item;
|
DSpaceObject dso = newItem(context);
|
||||||
|
|
||||||
String result = instance.get(0).register(context, dso);
|
String result = instance.register(context, dso);
|
||||||
assertTrue("Didn't get a DOI back", result.startsWith("doi:10.5072/"));
|
assertTrue("Didn't get a DOI back", result.startsWith("doi:" + TEST_SHOULDER));
|
||||||
System.out.println(" got identifier: " + result);
|
System.out.println(" got identifier: " + result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,18 +199,17 @@ public class DataCiteIdentifierProviderTest
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testRegister_3args()
|
public void testRegister_3args()
|
||||||
|
throws SQLException, AuthorizeException, IOException
|
||||||
{
|
{
|
||||||
System.out.println("register");
|
System.out.println("register 3");
|
||||||
// TODO review the generated test code and remove the default call to fail.
|
|
||||||
fail("The test case is a prototype.");
|
|
||||||
|
|
||||||
List<DataCiteIdentifierProvider> instances
|
List<DataCiteIdentifierProvider> instances
|
||||||
= (List<DataCiteIdentifierProvider>)
|
= (List<DataCiteIdentifierProvider>)
|
||||||
sm.getServicesByType(DataCiteIdentifierProvider.class);
|
sm.getServicesByType(DataCiteIdentifierProvider.class);
|
||||||
|
|
||||||
DSpaceObject object = item;
|
DSpaceObject object = newItem(context);
|
||||||
|
|
||||||
String identifier = TEST_SHOULDER + "blarg"; // TODO a unique value
|
String identifier = UUID.randomUUID().toString();
|
||||||
|
|
||||||
instances.get(0).register(context, object, identifier);
|
instances.get(0).register(context, object, identifier);
|
||||||
}
|
}
|
||||||
@@ -157,13 +222,11 @@ public class DataCiteIdentifierProviderTest
|
|||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
System.out.println("reserve");
|
System.out.println("reserve");
|
||||||
// TODO review the generated test code and remove the default call to fail.
|
|
||||||
fail("The test case is a prototype.");
|
|
||||||
|
|
||||||
DataCiteIdentifierProvider instance = new DataCiteIdentifierProvider();
|
DataCiteIdentifierProvider instance = new DataCiteIdentifierProvider();
|
||||||
|
|
||||||
DSpaceObject dso = item;
|
DSpaceObject dso = newItem(context);
|
||||||
String identifier = "";
|
String identifier = UUID.randomUUID().toString();
|
||||||
instance.reserve(context, dso, identifier);
|
instance.reserve(context, dso, identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,8 +243,7 @@ public class DataCiteIdentifierProviderTest
|
|||||||
|
|
||||||
DataCiteIdentifierProvider instance = new DataCiteIdentifierProvider();
|
DataCiteIdentifierProvider instance = new DataCiteIdentifierProvider();
|
||||||
|
|
||||||
DSpaceObject dso = item;
|
DSpaceObject dso = newItem(context);
|
||||||
String expResult = "";
|
|
||||||
String result = instance.mint(context, dso);
|
String result = instance.mint(context, dso);
|
||||||
assertEquals(expResult, result);
|
assertEquals(expResult, result);
|
||||||
}
|
}
|
||||||
@@ -194,18 +256,18 @@ public class DataCiteIdentifierProviderTest
|
|||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
System.out.println("resolve");
|
System.out.println("resolve");
|
||||||
// TODO review the generated test code and remove the default call to fail.
|
|
||||||
fail("The test case is a prototype.");
|
|
||||||
|
|
||||||
DataCiteIdentifierProvider instance = new DataCiteIdentifierProvider();
|
DataCiteIdentifierProvider instance = new DataCiteIdentifierProvider();
|
||||||
|
|
||||||
String identifier = "";
|
String identifier = UUID.randomUUID().toString();
|
||||||
|
DSpaceObject expResult = newItem(context);
|
||||||
|
instance.register(context, expResult, identifier);
|
||||||
|
|
||||||
String[] attributes = null;
|
String[] attributes = null;
|
||||||
DSpaceObject expResult = null;
|
|
||||||
DSpaceObject result = instance.resolve(context, identifier, attributes);
|
DSpaceObject result = instance.resolve(context, identifier, attributes);
|
||||||
assertEquals(expResult, result);
|
assertEquals(expResult, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test of lookup method, of class DataCiteIdentifierProvider.
|
* Test of lookup method, of class DataCiteIdentifierProvider.
|
||||||
*/
|
*/
|
||||||
@@ -219,8 +281,10 @@ public class DataCiteIdentifierProviderTest
|
|||||||
|
|
||||||
DataCiteIdentifierProvider instance = new DataCiteIdentifierProvider();
|
DataCiteIdentifierProvider instance = new DataCiteIdentifierProvider();
|
||||||
|
|
||||||
DSpaceObject object = item;
|
String identifier = UUID.randomUUID().toString();
|
||||||
String expResult = "";
|
DSpaceObject object = newItem(context);
|
||||||
|
instance.register(context, object, identifier);
|
||||||
|
|
||||||
String result = instance.lookup(context, object);
|
String result = instance.lookup(context, object);
|
||||||
assertEquals(expResult, result);
|
assertEquals(expResult, result);
|
||||||
}
|
}
|
||||||
@@ -232,31 +296,66 @@ public class DataCiteIdentifierProviderTest
|
|||||||
public void testDelete_Context_DSpaceObject()
|
public void testDelete_Context_DSpaceObject()
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
System.out.println("delete");
|
System.out.println("delete 2");
|
||||||
// TODO review the generated test code and remove the default call to fail.
|
|
||||||
fail("The test case is a prototype.");
|
|
||||||
|
|
||||||
DataCiteIdentifierProvider instance = new DataCiteIdentifierProvider();
|
DataCiteIdentifierProvider instance = new DataCiteIdentifierProvider();
|
||||||
|
|
||||||
DSpaceObject dso = item;
|
DSpaceObject dso = newItem(context);
|
||||||
instance.delete(context, dso);
|
|
||||||
|
// Ensure that it has multiple DOIs (ooo, bad boy!)
|
||||||
|
String id1 = UUID.randomUUID().toString();
|
||||||
|
String id2 = UUID.randomUUID().toString();
|
||||||
|
instance.reserve(context, dso, id1);
|
||||||
|
instance.reserve(context, dso, id2);
|
||||||
|
|
||||||
|
// Test deletion
|
||||||
|
try {
|
||||||
|
instance.delete(context, dso);
|
||||||
|
} catch (IdentifierException e) {
|
||||||
|
// Creation of the Item registers a "public" identifier, which can't be deleted.
|
||||||
|
assertEquals("Unexpected exception", "1 identifiers could not be deleted.", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if those identifiers were really deleted.
|
||||||
|
ItemIterator found;
|
||||||
|
found = Item.findByMetadataField(context,
|
||||||
|
DataCiteIdentifierProvider.MD_SCHEMA,
|
||||||
|
DataCiteIdentifierProvider.DOI_ELEMENT,
|
||||||
|
DataCiteIdentifierProvider.DOI_QUALIFIER, id1);
|
||||||
|
assertFalse("A test identifier is still present", found.hasNext());
|
||||||
|
|
||||||
|
found = Item.findByMetadataField(context,
|
||||||
|
DataCiteIdentifierProvider.MD_SCHEMA,
|
||||||
|
DataCiteIdentifierProvider.DOI_ELEMENT,
|
||||||
|
DataCiteIdentifierProvider.DOI_QUALIFIER, id2);
|
||||||
|
assertFalse("A test identifier is still present", found.hasNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test of delete method, of class DataCiteIdentifierProvider.
|
* Test of delete method, of class DataCiteIdentifierProvider.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test()
|
||||||
public void testDelete_3args()
|
public void testDelete_3args()
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
System.out.println("delete");
|
System.out.println("delete 3");
|
||||||
// TODO review the generated test code and remove the default call to fail.
|
|
||||||
fail("The test case is a prototype.");
|
|
||||||
|
|
||||||
DataCiteIdentifierProvider instance = new DataCiteIdentifierProvider();
|
DataCiteIdentifierProvider instance = new DataCiteIdentifierProvider();
|
||||||
|
|
||||||
DSpaceObject dso = item;
|
DSpaceObject dso = newItem(context);
|
||||||
String identifier = "";
|
String identifier = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
// Set a known identifier on the object
|
||||||
|
instance.reserve(context, dso, identifier);
|
||||||
|
|
||||||
|
// Test deletion
|
||||||
instance.delete(context, dso, identifier);
|
instance.delete(context, dso, identifier);
|
||||||
|
|
||||||
|
// See if it is gone
|
||||||
|
ItemIterator found = Item.findByMetadataField(context,
|
||||||
|
DataCiteIdentifierProvider.MD_SCHEMA,
|
||||||
|
DataCiteIdentifierProvider.DOI_ELEMENT,
|
||||||
|
DataCiteIdentifierProvider.DOI_QUALIFIER, identifier);
|
||||||
|
assertFalse("Test identifier is still present", found.hasNext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user