mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-17 06:53:09 +00:00
Add initial code
This commit is contained in:

committed by
Pascal-Nicolas Becker

parent
4ebe7217d9
commit
e5d53f8f43
12
dspace-api/src/main/java/org/dspace/identifier/DOI.java
Normal file
12
dspace-api/src/main/java/org/dspace/identifier/DOI.java
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
package org.dspace.identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOI identifiers.
|
||||||
|
*
|
||||||
|
* @author mwood
|
||||||
|
*/
|
||||||
|
public class DOI
|
||||||
|
implements Identifier
|
||||||
|
{
|
||||||
|
}
|
@@ -0,0 +1,297 @@
|
|||||||
|
/**
|
||||||
|
* 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.net.HttpURLConnection;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import org.apache.commons.httpclient.StatusLine;
|
||||||
|
import org.apache.http.HttpEntity;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.ParseException;
|
||||||
|
import org.apache.http.auth.AuthScope;
|
||||||
|
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||||
|
import org.apache.http.client.ClientProtocolException;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.client.utils.URIBuilder;
|
||||||
|
import org.apache.http.entity.ContentType;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.impl.client.AbstractHttpClient;
|
||||||
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
import org.dspace.content.DCValue;
|
||||||
|
import org.dspace.content.DSpaceObject;
|
||||||
|
import org.dspace.content.Item;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide service for DOIs through DataCite.
|
||||||
|
*
|
||||||
|
* @author mwood
|
||||||
|
*/
|
||||||
|
public class DataCiteIdentifierProvider
|
||||||
|
extends IdentifierProvider
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(DataCiteIdentifierProvider.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(Class<? extends Identifier> identifier)
|
||||||
|
{
|
||||||
|
return DOI.class.isAssignableFrom(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(String identifier)
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String register(Context context, DSpaceObject item)
|
||||||
|
throws IdentifierException
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String mint(Context context, DSpaceObject dso)
|
||||||
|
throws IdentifierException
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DSpaceObject resolve(Context context, String identifier,
|
||||||
|
String... attributes)
|
||||||
|
throws IdentifierNotFoundException, IdentifierNotResolvableException
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String lookup(Context context, DSpaceObject object)
|
||||||
|
throws IdentifierNotFoundException, IdentifierNotResolvableException
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(Context context, DSpaceObject dso)
|
||||||
|
throws IdentifierException
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(Context context, DSpaceObject dso, String identifier)
|
||||||
|
throws IdentifierException
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reserve(Context context, DSpaceObject dso, String identifier)
|
||||||
|
throws IdentifierException
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void register(Context context, DSpaceObject object, String identifier)
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String EZID_SCHEME; // = "https";
|
||||||
|
private static String EZID_HOST; // = "n2t.net";
|
||||||
|
private static String EZID_PATH; // = "/ezid/shoulder/";
|
||||||
|
|
||||||
|
/** Map DataCite metadata into local metadata */
|
||||||
|
private static Map<String, String> crosswalk = new HashMap<String, String>();
|
||||||
|
/* default mapping */
|
||||||
|
/*
|
||||||
|
static
|
||||||
|
{
|
||||||
|
crosswalk.put("datacite.creator", "dc.creator.author");
|
||||||
|
crosswalk.put("datacite.title", "dc.title");
|
||||||
|
crosswalk.put("datacite.publisher", "dc.publisher");
|
||||||
|
crosswalk.put("datacite.publicationyear", "dc.date.published");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param aEZID_SCHEME the EZID URL scheme to set
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
@Required
|
||||||
|
public static void setEZID_SCHEME(String aEZID_SCHEME)
|
||||||
|
{
|
||||||
|
EZID_SCHEME = aEZID_SCHEME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param aEZID_HOST the EZID host to set
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
@Required
|
||||||
|
public static void setEZID_HOST(String aEZID_HOST)
|
||||||
|
{
|
||||||
|
EZID_HOST = aEZID_HOST;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param aEZID_PATH the EZID path to set
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
@Required
|
||||||
|
public static void setEZID_PATH(String aEZID_PATH)
|
||||||
|
{
|
||||||
|
EZID_PATH = aEZID_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param aCrosswalk the crosswalk to set
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
public static void setCrosswalk(Map<String, String> aCrosswalk)
|
||||||
|
{
|
||||||
|
crosswalk = aCrosswalk;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Pattern DOIpattern = Pattern.compile("doi:[\\S]+");
|
||||||
|
private static final Pattern ARKpattern = Pattern.compile("ark:[\\S]+");
|
||||||
|
private static final ContentType CONTENT_UTF8_TEXT = ContentType.create("text/plain", "UTF-8");
|
||||||
|
|
||||||
|
private String doi = null;
|
||||||
|
private String ark = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit some object details and request identifiers for the object.
|
||||||
|
*
|
||||||
|
* @param postBody the details, formatted for EZID.
|
||||||
|
*/
|
||||||
|
public void request(String postBody)
|
||||||
|
throws IdentifierException
|
||||||
|
{
|
||||||
|
// Address the service
|
||||||
|
URIBuilder mintURL = new URIBuilder();
|
||||||
|
mintURL.setScheme(EZID_SCHEME)
|
||||||
|
.setHost(EZID_HOST)
|
||||||
|
.setPath(EZID_PATH + configurationService.getProperty("identifier.doi.ezid.shoulder"));
|
||||||
|
|
||||||
|
// Compose the request
|
||||||
|
HttpPost request;
|
||||||
|
try {
|
||||||
|
request = new HttpPost(mintURL.build());
|
||||||
|
} catch (URISyntaxException ex) {
|
||||||
|
log.error(ex.getMessage());
|
||||||
|
throw new IdentifierException("DOI request not sent: " + ex.getMessage());
|
||||||
|
}
|
||||||
|
request.setEntity(new StringEntity(postBody, CONTENT_UTF8_TEXT));
|
||||||
|
|
||||||
|
AbstractHttpClient mint = new DefaultHttpClient();
|
||||||
|
mint.getCredentialsProvider().setCredentials(
|
||||||
|
new AuthScope(mintURL.getHost(), mintURL.getPort()),
|
||||||
|
new UsernamePasswordCredentials(
|
||||||
|
configurationService.getProperty("identifier.doi.ezid.user"),
|
||||||
|
configurationService.getProperty("identifier.doi.ezid.password")));
|
||||||
|
|
||||||
|
// Send the request
|
||||||
|
HttpResponse response;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
response = mint.execute(request);
|
||||||
|
} catch (IOException ex)
|
||||||
|
{
|
||||||
|
log.error("Failed to send EZID request: {}", ex.getMessage());
|
||||||
|
throw new IdentifierException("DOI request not sent: " + ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Good response?
|
||||||
|
StatusLine status = (StatusLine) response.getStatusLine();
|
||||||
|
if (HttpURLConnection.HTTP_CREATED != status.getStatusCode())
|
||||||
|
{
|
||||||
|
log.error("EZID responded: {} {}", status.getStatusCode(),
|
||||||
|
status.getReasonPhrase());
|
||||||
|
throw new IdentifierException("DOI not created: " + status.getReasonPhrase());
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpEntity responseBody = response.getEntity();
|
||||||
|
|
||||||
|
// Collect the content of the response
|
||||||
|
String content;
|
||||||
|
try {
|
||||||
|
content = EntityUtils.toString(responseBody, "UTF-8");
|
||||||
|
} catch (IOException ex) {
|
||||||
|
log.error(ex.getMessage());
|
||||||
|
throw new IdentifierException("EZID response not understood: " + ex.getMessage());
|
||||||
|
} catch (ParseException ex) {
|
||||||
|
log.error(ex.getMessage());
|
||||||
|
throw new IdentifierException("EZID response not understood: " + ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the identifiers from the content blob
|
||||||
|
|
||||||
|
Matcher matcher;
|
||||||
|
|
||||||
|
// DOI
|
||||||
|
matcher = DOIpattern.matcher(content);
|
||||||
|
if (matcher.find())
|
||||||
|
doi = matcher.group();
|
||||||
|
|
||||||
|
// ARK
|
||||||
|
matcher = ARKpattern.matcher(content);
|
||||||
|
if (matcher.find())
|
||||||
|
ark = matcher.group();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDoi() { return doi; }
|
||||||
|
|
||||||
|
public String getArk() { return ark; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assemble the identifier request document, one field per line.
|
||||||
|
*
|
||||||
|
* @param dso the object we want to identify.
|
||||||
|
*/
|
||||||
|
static public String generatePostBody(DSpaceObject dso)
|
||||||
|
{
|
||||||
|
if ((null == dso) || !(dso instanceof Item))
|
||||||
|
throw new IllegalArgumentException("Must be an Item");
|
||||||
|
Item item = (Item) dso; // TODO generalize to DSO when all DSOs have metadata.
|
||||||
|
|
||||||
|
StringBuilder bupher = new StringBuilder();
|
||||||
|
|
||||||
|
for (Map.Entry<String, String> datum : crosswalk.entrySet())
|
||||||
|
{
|
||||||
|
DCValue[] values = item.getMetadata(datum.getValue());
|
||||||
|
if (null != values)
|
||||||
|
{
|
||||||
|
for (DCValue value : values)
|
||||||
|
{
|
||||||
|
bupher.append(datum.getKey())
|
||||||
|
.append(": ")
|
||||||
|
.append(value.value)
|
||||||
|
.append('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bupher.toString();
|
||||||
|
}
|
||||||
|
}
|
@@ -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;
|
Reference in New Issue
Block a user