mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
Merge pull request #2560 from atmire/feature-external-sources
Feature: external sources
This commit is contained in:
@@ -15,6 +15,9 @@ import java.util.List;
|
||||
* @author Andrea Bollini
|
||||
*/
|
||||
public class SHERPAPublisher {
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String alias;
|
||||
@@ -49,7 +52,7 @@ public class SHERPAPublisher {
|
||||
|
||||
private String dateupdated;
|
||||
|
||||
public SHERPAPublisher(String name, String alias, String homeurl,
|
||||
public SHERPAPublisher(String id, String name, String alias, String homeurl,
|
||||
String prearchiving, List<String> prerestriction,
|
||||
String postarchiving, List<String> postrestriction,
|
||||
String pubarchiving, List<String> pubrestriction,
|
||||
@@ -57,6 +60,8 @@ public class SHERPAPublisher {
|
||||
String paidaccessname, String paidaccessnotes,
|
||||
List<String[]> copyright, String romeocolour, String datedded,
|
||||
String dateupdated) {
|
||||
this.id = id;
|
||||
|
||||
this.name = name;
|
||||
|
||||
this.alias = alias;
|
||||
@@ -160,4 +165,11 @@ public class SHERPAPublisher {
|
||||
return dateupdated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the id
|
||||
* @return the id value of this SHERPAPublisher
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@ import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.util.XMLUtils;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -24,7 +25,9 @@ import org.w3c.dom.Element;
|
||||
* @author Andrea Bollini
|
||||
*/
|
||||
public class SHERPAResponse {
|
||||
private boolean error;
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SHERPAResponse.class);
|
||||
|
||||
private int numHits;
|
||||
|
||||
private String message;
|
||||
|
||||
@@ -57,12 +60,13 @@ public class SHERPAResponse {
|
||||
Element publishersElement = XMLUtils.getSingleElement(xmlRoot,
|
||||
"publishers");
|
||||
|
||||
message = XMLUtils.getElementValue(headersElement, "message");
|
||||
|
||||
if (StringUtils.isNotBlank(message)) {
|
||||
error = true;
|
||||
return;
|
||||
String numhitsString = XMLUtils.getElementValue(headersElement, "numhits");
|
||||
if (StringUtils.isNotBlank(numhitsString)) {
|
||||
numHits = Integer.parseInt(numhitsString);
|
||||
} else {
|
||||
numHits = 0;
|
||||
}
|
||||
message = XMLUtils.getElementValue(headersElement, "message");
|
||||
|
||||
license = XMLUtils.getElementValue(headersElement, "license");
|
||||
licenseURL = XMLUtils.getElementValue(headersElement, "licenseurl");
|
||||
@@ -112,9 +116,8 @@ public class SHERPAResponse {
|
||||
|
||||
Element copyrightlinksElement = XMLUtils.getSingleElement(
|
||||
publisherElement, "copyrightlinks");
|
||||
|
||||
publishers
|
||||
.add(new SHERPAPublisher(XMLUtils.getElementValue(
|
||||
.add(new SHERPAPublisher(publisherElement.getAttribute("id"), XMLUtils.getElementValue(
|
||||
publisherElement, "name"),
|
||||
XMLUtils.getElementValue(publisherElement,
|
||||
"alias"), XMLUtils.getElementValue(
|
||||
@@ -162,17 +165,12 @@ public class SHERPAResponse {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
error = true;
|
||||
log.error("Error parsing SHERPA API Response", e);
|
||||
}
|
||||
}
|
||||
|
||||
public SHERPAResponse(String message) {
|
||||
this.message = message;
|
||||
this.error = true;
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
@@ -198,4 +196,8 @@ public class SHERPAResponse {
|
||||
public List<SHERPAPublisher> getPublishers() {
|
||||
return publishers;
|
||||
}
|
||||
|
||||
public int getNumHits() {
|
||||
return numHits;
|
||||
}
|
||||
}
|
||||
|
@@ -52,11 +52,11 @@ public class InitializeEntities {
|
||||
private RelationshipService relationshipService;
|
||||
private EntityTypeService entityTypeService;
|
||||
|
||||
|
||||
private InitializeEntities() {
|
||||
relationshipTypeService = ContentServiceFactory.getInstance().getRelationshipTypeService();
|
||||
relationshipService = ContentServiceFactory.getInstance().getRelationshipService();
|
||||
entityTypeService = ContentServiceFactory.getInstance().getEntityTypeService();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -35,6 +35,7 @@ public abstract class AuthorityServiceFactory {
|
||||
|
||||
public abstract AuthorityService getAuthorityService();
|
||||
|
||||
|
||||
public abstract List<AuthorityIndexerInterface> getAuthorityIndexers();
|
||||
|
||||
public static AuthorityServiceFactory getInstance() {
|
||||
|
@@ -1,191 +0,0 @@
|
||||
/**
|
||||
* 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.authority.orcid;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.authority.AuthorityValue;
|
||||
import org.dspace.authority.SolrAuthorityInterface;
|
||||
import org.dspace.authority.orcid.xml.XMLtoBio;
|
||||
import org.dspace.authority.rest.RESTConnector;
|
||||
import org.json.JSONObject;
|
||||
import org.orcid.jaxb.model.record_v2.Person;
|
||||
|
||||
/**
|
||||
* @author Jonas Van Goolen (jonas at atmire dot com)
|
||||
* This class contains all methods for retrieving "Person" objects calling the ORCID (version 2) endpoints.
|
||||
* Additionally, this can also create AuthorityValues based on these returned Person objects
|
||||
*/
|
||||
public class Orcidv2 implements SolrAuthorityInterface {
|
||||
|
||||
private static Logger log = LogManager.getLogger(Orcidv2.class);
|
||||
|
||||
public RESTConnector restConnector;
|
||||
private String OAUTHUrl;
|
||||
private String clientId;
|
||||
|
||||
private String clientSecret;
|
||||
|
||||
private String accessToken;
|
||||
|
||||
/**
|
||||
* Initialize the accessToken that is required for all subsequent calls to ORCID.
|
||||
*
|
||||
* @throws java.io.IOException passed through from HTTPclient.
|
||||
*/
|
||||
public void init() throws IOException {
|
||||
if (StringUtils.isNotBlank(accessToken) && StringUtils.isNotBlank(clientSecret)) {
|
||||
String authenticationParameters = "?client_id=" + clientId +
|
||||
"&client_secret=" + clientSecret +
|
||||
"&scope=/read-public&grant_type=client_credentials";
|
||||
HttpPost httpPost = new HttpPost(OAUTHUrl + authenticationParameters);
|
||||
httpPost.addHeader("Accept", "application/json");
|
||||
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
|
||||
HttpClient httpClient = HttpClientBuilder.create().build();
|
||||
HttpResponse getResponse = httpClient.execute(httpPost);
|
||||
|
||||
InputStream is = getResponse.getEntity().getContent();
|
||||
BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
|
||||
|
||||
JSONObject responseObject = null;
|
||||
String inputStr;
|
||||
while ((inputStr = streamReader.readLine()) != null && responseObject == null) {
|
||||
if (inputStr.startsWith("{") && inputStr.endsWith("}") && inputStr.contains("access_token")) {
|
||||
try {
|
||||
responseObject = new JSONObject(inputStr);
|
||||
} catch (Exception e) {
|
||||
//Not as valid as I'd hoped, move along
|
||||
responseObject = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (responseObject != null && responseObject.has("access_token")) {
|
||||
accessToken = (String) responseObject.get("access_token");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an instance of the Orcidv2 class based on the provided parameters.
|
||||
* This constructor is called through the spring bean initialization
|
||||
*/
|
||||
private Orcidv2(String url, String OAUTHUrl, String clientId, String clientSecret) {
|
||||
this.restConnector = new RESTConnector(url);
|
||||
this.OAUTHUrl = OAUTHUrl;
|
||||
this.clientId = clientId;
|
||||
this.clientSecret = clientSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an instance of the Orcidv2 class based on the provided parameters.
|
||||
* This constructor is called through the spring bean initialization
|
||||
*/
|
||||
private Orcidv2(String url) {
|
||||
this.restConnector = new RESTConnector(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an instance of the AuthorityValue with the given information.
|
||||
* @param text search string
|
||||
* @return List<AuthorityValue>
|
||||
*/
|
||||
@Override
|
||||
public List<AuthorityValue> queryAuthorities(String text, int max) {
|
||||
List<Person> bios = queryBio(text, max);
|
||||
List<AuthorityValue> result = new ArrayList<>();
|
||||
for (Person person : bios) {
|
||||
AuthorityValue orcidAuthorityValue = Orcidv2AuthorityValue.create(person);
|
||||
if (orcidAuthorityValue != null) {
|
||||
result.add(orcidAuthorityValue);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an AuthorityValue from a Person retrieved using the given orcid identifier.
|
||||
* @param id orcid identifier
|
||||
* @return AuthorityValue
|
||||
*/
|
||||
public AuthorityValue queryAuthorityID(String id) {
|
||||
Person person = getBio(id);
|
||||
AuthorityValue valueFromPerson = Orcidv2AuthorityValue.create(person);
|
||||
return valueFromPerson;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a Person object based on a given orcid identifier
|
||||
* @param id orcid identifier
|
||||
* @return Person
|
||||
*/
|
||||
public Person getBio(String id) {
|
||||
log.debug("getBio called with ID=" + id);
|
||||
if (!isValid(id)) {
|
||||
return null;
|
||||
}
|
||||
InputStream bioDocument = restConnector.get(id + ((id.endsWith("/person")) ? "" : "/person"), accessToken);
|
||||
XMLtoBio converter = new XMLtoBio();
|
||||
Person person = converter.convertSinglePerson(bioDocument);
|
||||
return person;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a list of Person objects.
|
||||
* @param text search string
|
||||
* @param start offset to use
|
||||
* @param rows how many rows to return
|
||||
* @return List<Person>
|
||||
*/
|
||||
public List<Person> queryBio(String text, int start, int rows) {
|
||||
if (rows > 100) {
|
||||
throw new IllegalArgumentException("The maximum number of results to retrieve cannot exceed 100.");
|
||||
}
|
||||
|
||||
String searchPath = "search?q=" + URLEncoder.encode(text) + "&start=" + start + "&rows=" + rows;
|
||||
log.debug("queryBio searchPath=" + searchPath + " accessToken=" + accessToken);
|
||||
InputStream bioDocument = restConnector.get(searchPath, accessToken);
|
||||
XMLtoBio converter = new XMLtoBio();
|
||||
List<Person> bios = converter.convert(bioDocument);
|
||||
return bios;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of Person objects.
|
||||
* @param text search string
|
||||
* @param max how many rows to return
|
||||
* @return List<Person>
|
||||
*/
|
||||
public List<Person> queryBio(String text, int max) {
|
||||
return queryBio(text, 0, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the provided text has the correct ORCID syntax.
|
||||
* Since only searching on ORCID id is allowed, this way, we filter out any queries that would return a
|
||||
* blank result anyway
|
||||
*/
|
||||
private boolean isValid(String text) {
|
||||
return StringUtils.isNotBlank(text) && text.matches(Orcidv2AuthorityValue.ORCID_ID_SYNTAX);
|
||||
}
|
||||
}
|
@@ -1,342 +0,0 @@
|
||||
/**
|
||||
* 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.authority.orcid;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.solr.common.SolrDocument;
|
||||
import org.apache.solr.common.SolrInputDocument;
|
||||
import org.dspace.authority.AuthorityValue;
|
||||
import org.dspace.authority.AuthorityValueServiceImpl;
|
||||
import org.dspace.authority.PersonAuthorityValue;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.orcid.jaxb.model.common_v2.ExternalId;
|
||||
import org.orcid.jaxb.model.record_v2.ExternalIdentifiers;
|
||||
import org.orcid.jaxb.model.record_v2.KeywordType;
|
||||
import org.orcid.jaxb.model.record_v2.NameType;
|
||||
import org.orcid.jaxb.model.record_v2.Person;
|
||||
import org.orcid.jaxb.model.record_v2.ResearcherUrlType;
|
||||
|
||||
/**
|
||||
* @author Jonas Van Goolen (jonas at atmire dot com)
|
||||
*/
|
||||
public class Orcidv2AuthorityValue extends PersonAuthorityValue {
|
||||
|
||||
/*
|
||||
* The ORCID identifier
|
||||
*/
|
||||
private String orcid_id;
|
||||
|
||||
/*
|
||||
* Map containing key-value pairs filled in by "setValues(Person person)".
|
||||
* This represents all dynamic information of the object.
|
||||
*/
|
||||
private Map<String, List<String>> otherMetadata = new HashMap<String, List<String>>();
|
||||
|
||||
/**
|
||||
* The syntax that the ORCID id needs to conform to
|
||||
*/
|
||||
public static final String ORCID_ID_SYNTAX = "\\d{4}-\\d{4}-\\d{4}-(\\d{3}X|\\d{4})";
|
||||
|
||||
|
||||
/**
|
||||
* Creates an instance of Orcidv2AuthorityValue with only uninitialized fields.
|
||||
* This is meant to be filled in with values from an existing record.
|
||||
* To create a brand new Orcidv2AuthorityValue, use create()
|
||||
*/
|
||||
public Orcidv2AuthorityValue() {
|
||||
}
|
||||
|
||||
public Orcidv2AuthorityValue(SolrDocument document) {
|
||||
super(document);
|
||||
}
|
||||
|
||||
|
||||
public String getOrcid_id() {
|
||||
return orcid_id;
|
||||
}
|
||||
|
||||
public void setOrcid_id(String orcid_id) {
|
||||
this.orcid_id = orcid_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty authority.
|
||||
* @return OrcidAuthorityValue
|
||||
*/
|
||||
public static Orcidv2AuthorityValue create() {
|
||||
Orcidv2AuthorityValue orcidAuthorityValue = new Orcidv2AuthorityValue();
|
||||
orcidAuthorityValue.setId(UUID.randomUUID().toString());
|
||||
orcidAuthorityValue.updateLastModifiedDate();
|
||||
orcidAuthorityValue.setCreationDate(new Date());
|
||||
return orcidAuthorityValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an authority based on a given orcid bio
|
||||
* @return OrcidAuthorityValue
|
||||
*/
|
||||
public static Orcidv2AuthorityValue create(Person person) {
|
||||
if (person == null) {
|
||||
return null;
|
||||
}
|
||||
Orcidv2AuthorityValue authority = Orcidv2AuthorityValue.create();
|
||||
|
||||
authority.setValues(person);
|
||||
|
||||
return authority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this instance based on a Person object
|
||||
* @param person Person
|
||||
*/
|
||||
protected void setValues(Person person) {
|
||||
NameType name = person.getName();
|
||||
|
||||
if (!StringUtils.equals(name.getPath(), this.getOrcid_id())) {
|
||||
this.setOrcid_id(name.getPath());
|
||||
}
|
||||
|
||||
if (!StringUtils.equals(name.getFamilyName().getValue(), this.getLastName())) {
|
||||
this.setLastName(name.getFamilyName().getValue());
|
||||
}
|
||||
|
||||
if (!StringUtils.equals(name.getGivenNames().getValue(), this.getFirstName())) {
|
||||
this.setFirstName(name.getGivenNames().getValue());
|
||||
}
|
||||
|
||||
if (name.getCreditName() != null && StringUtils.isNotBlank(name.getCreditName().getValue())) {
|
||||
if (!this.getNameVariants().contains(name.getCreditName().getValue())) {
|
||||
this.addNameVariant(name.getCreditName().getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (person.getKeywords() != null) {
|
||||
for (KeywordType keyword : person.getKeywords().getKeyword()) {
|
||||
if (this.isNewMetadata("keyword", keyword.getContent())) {
|
||||
this.addOtherMetadata("keyword", keyword.getContent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExternalIdentifiers externalIdentifiers = person.getExternalIdentifiers();
|
||||
if (externalIdentifiers != null) {
|
||||
for (ExternalId externalIdentifier : externalIdentifiers.getExternalIdentifier()) {
|
||||
if (this.isNewMetadata("external_identifier", externalIdentifier.getExternalIdValue())) {
|
||||
this.addOtherMetadata("external_identifier", externalIdentifier.getExternalIdValue());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (person.getResearcherUrls() != null) {
|
||||
for (ResearcherUrlType researcherUrl : person.getResearcherUrls().getResearcherUrl()) {
|
||||
if (this.isNewMetadata("researcher_url", researcherUrl.getUrl().getValue())) {
|
||||
this.addOtherMetadata("researcher_url", researcherUrl.getUrl().getValue());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (person.getBiography() != null) {
|
||||
if (this.isNewMetadata("biography", person.getBiography().getContent())) {
|
||||
this.addOtherMetadata("biography", person.getBiography().getContent());
|
||||
}
|
||||
}
|
||||
|
||||
this.setValue(this.getName());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an instance of the AuthorityValue with the given information.
|
||||
* @param info string info
|
||||
* @return AuthorityValue
|
||||
*/
|
||||
@Override
|
||||
public AuthorityValue newInstance(String info) {
|
||||
AuthorityValue authorityValue = null;
|
||||
if (StringUtils.isNotBlank(info)) {
|
||||
Orcidv2 orcid = new DSpace().getServiceManager().getServiceByName("AuthoritySource", Orcidv2.class);
|
||||
authorityValue = orcid.queryAuthorityID(info);
|
||||
} else {
|
||||
authorityValue = this.create();
|
||||
}
|
||||
return authorityValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(String value) {
|
||||
super.setValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the provided label / data pair is already present in the "otherMetadata" or not
|
||||
* */
|
||||
public boolean isNewMetadata(String label, String data) {
|
||||
List<String> strings = getOtherMetadata().get(label);
|
||||
boolean update;
|
||||
if (strings == null) {
|
||||
update = StringUtils.isNotBlank(data);
|
||||
} else {
|
||||
update = !strings.contains(data);
|
||||
}
|
||||
return update;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional metadata to the otherMetadata map*/
|
||||
public void addOtherMetadata(String label, String data) {
|
||||
List<String> strings = otherMetadata.get(label);
|
||||
if (strings == null) {
|
||||
strings = new ArrayList<>();
|
||||
}
|
||||
strings.add(data);
|
||||
otherMetadata.put(label, strings);
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getOtherMetadata() {
|
||||
return otherMetadata;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a solr record from this instance
|
||||
* @return SolrInputDocument
|
||||
*/
|
||||
@Override
|
||||
public SolrInputDocument getSolrInputDocument() {
|
||||
SolrInputDocument doc = super.getSolrInputDocument();
|
||||
if (StringUtils.isNotBlank(getOrcid_id())) {
|
||||
doc.addField("orcid_id", getOrcid_id());
|
||||
}
|
||||
|
||||
for (String t : otherMetadata.keySet()) {
|
||||
List<String> data = otherMetadata.get(t);
|
||||
for (String data_entry : data) {
|
||||
doc.addField("label_" + t, data_entry);
|
||||
}
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Information that can be used the choice ui
|
||||
* @return map
|
||||
*/
|
||||
@Override
|
||||
public Map<String, String> choiceSelectMap() {
|
||||
|
||||
Map<String, String> map = super.choiceSelectMap();
|
||||
|
||||
String orcid_id = getOrcid_id();
|
||||
if (StringUtils.isNotBlank(orcid_id)) {
|
||||
map.put("orcid", orcid_id);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthorityType() {
|
||||
return "orcid";
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a string that will allow this AuthorityType to be recognized and provides information to create a new
|
||||
* instance to be created using public Orcidv2AuthorityValue newInstance(String info).
|
||||
* @return see {@link org.dspace.authority.service.AuthorityValueService#GENERATE AuthorityValueService.GENERATE}
|
||||
*/
|
||||
@Override
|
||||
public String generateString() {
|
||||
String generateString = AuthorityValueServiceImpl.GENERATE + getAuthorityType() +
|
||||
AuthorityValueServiceImpl.SPLIT;
|
||||
if (StringUtils.isNotBlank(getOrcid_id())) {
|
||||
generateString += getOrcid_id();
|
||||
}
|
||||
return generateString;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Orcidv2AuthorityValue that = (Orcidv2AuthorityValue) o;
|
||||
|
||||
if (orcid_id != null ? !orcid_id.equals(that.orcid_id) : that.orcid_id != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return orcid_id != null ? orcid_id.hashCode() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The regular equals() only checks if both AuthorityValues describe the same authority.
|
||||
* This method checks if the AuthorityValues have different information
|
||||
* E.g. it is used to decide when lastModified should be updated.
|
||||
* @param o object
|
||||
* @return true or false
|
||||
*/
|
||||
@Override
|
||||
public boolean hasTheSameInformationAs(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (!super.hasTheSameInformationAs(o)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Orcidv2AuthorityValue that = (Orcidv2AuthorityValue) o;
|
||||
|
||||
if (orcid_id != null ? !orcid_id.equals(that.orcid_id) : that.orcid_id != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String key : otherMetadata.keySet()) {
|
||||
if (otherMetadata.get(key) != null) {
|
||||
List<String> metadata = otherMetadata.get(key);
|
||||
List<String> otherMetadata = that.otherMetadata.get(key);
|
||||
if (otherMetadata == null) {
|
||||
return false;
|
||||
} else {
|
||||
HashSet<String> metadataSet = new HashSet<String>(metadata);
|
||||
HashSet<String> otherMetadataSet = new HashSet<String>(otherMetadata);
|
||||
if (!metadataSet.equals(otherMetadataSet)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (that.otherMetadata.get(key) != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -8,6 +8,7 @@
|
||||
package org.dspace.authority.rest;
|
||||
|
||||
import org.dspace.authority.SolrAuthorityInterface;
|
||||
import org.dspace.external.OrcidRestConnector;
|
||||
|
||||
/**
|
||||
* @author Antoine Snyers (antoine at atmire.com)
|
||||
@@ -17,9 +18,9 @@ import org.dspace.authority.SolrAuthorityInterface;
|
||||
*/
|
||||
public abstract class RestSource implements SolrAuthorityInterface {
|
||||
|
||||
protected RESTConnector restConnector;
|
||||
protected OrcidRestConnector restConnector;
|
||||
|
||||
public RestSource(String url) {
|
||||
this.restConnector = new RESTConnector(url);
|
||||
this.restConnector = new OrcidRestConnector(url);
|
||||
}
|
||||
}
|
||||
|
@@ -1,59 +0,0 @@
|
||||
/**
|
||||
* 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.content.authority;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.dspace.content.Collection;
|
||||
|
||||
/**
|
||||
* Sample Journal-name authority based on SHERPA/RoMEO
|
||||
*
|
||||
* WARNING: This is a very crude and incomplete implementation, done mainly
|
||||
* as a proof-of-concept. Any site that actually wants to use it will
|
||||
* probably have to refine it (and give patches back to dspace.org).
|
||||
*
|
||||
* @author Larry Stone
|
||||
* @version $Revision $
|
||||
* @see SHERPARoMEOProtocol
|
||||
*/
|
||||
public class SHERPARoMEOJournalTitle extends SHERPARoMEOProtocol {
|
||||
private static final String RESULT = "journal";
|
||||
private static final String LABEL = "jtitle";
|
||||
private static final String AUTHORITY = "issn";
|
||||
|
||||
public SHERPARoMEOJournalTitle() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choices getMatches(String text, Collection collection, int start, int limit, String locale) {
|
||||
// punt if there is no query text
|
||||
if (text == null || text.trim().length() == 0) {
|
||||
return new Choices(true);
|
||||
}
|
||||
|
||||
// query args to add to SHERPA/RoMEO request URL
|
||||
List<BasicNameValuePair> args = new ArrayList<BasicNameValuePair>();
|
||||
args.add(new BasicNameValuePair("jtitle", text));
|
||||
args.add(new BasicNameValuePair("qtype", "contains")); // OR: starts, exact
|
||||
|
||||
Choices result = query(RESULT, LABEL, AUTHORITY, args, start, limit);
|
||||
if (result == null) {
|
||||
result = new Choices(true);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale) {
|
||||
return getMatches(text, collection, start, limit, locale);
|
||||
}
|
||||
}
|
@@ -1,228 +0,0 @@
|
||||
/**
|
||||
* 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.content.authority;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.core.ConfigurationManager;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
/**
|
||||
* Choice Authority based on SHERPA/RoMEO - for Publishers and Journals
|
||||
* See the subclasses SHERPARoMEOPublisher and SHERPARoMEOJournalTitle
|
||||
* for actual choice plugin implementations. This is a superclass
|
||||
* containing all the common protocol logic.
|
||||
*
|
||||
* Reads these DSpace Config properties:
|
||||
*
|
||||
* # contact URL for server
|
||||
* sherpa.romeo.url = http://www.sherpa.ac.uk/romeoapi11.php
|
||||
*
|
||||
* WARNING: This is a very crude and incomplete implementation, done mainly
|
||||
* as a proof-of-concept. Any site that actually wants to use it will
|
||||
* probably have to refine it (and give patches back to dspace.org).
|
||||
*
|
||||
* @author Larry Stone
|
||||
* @version $Revision $
|
||||
* @see SHERPARoMEOPublisher
|
||||
* @see SHERPARoMEOJournalTitle
|
||||
*/
|
||||
public abstract class SHERPARoMEOProtocol implements ChoiceAuthority {
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SHERPARoMEOProtocol.class);
|
||||
|
||||
// contact URL from configuration
|
||||
private static String url = null;
|
||||
|
||||
public SHERPARoMEOProtocol() {
|
||||
if (url == null) {
|
||||
url = ConfigurationManager.getProperty("sherpa.romeo.url");
|
||||
|
||||
// sanity check
|
||||
if (url == null) {
|
||||
throw new IllegalStateException("Missing DSpace configuration keys for SHERPA/RoMEO Query");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this implements the specific RoMEO API args and XML tag naming
|
||||
public abstract Choices getMatches(String text, Collection collection, int start, int limit, String locale);
|
||||
|
||||
@Override
|
||||
public Choices getBestMatch(String field, String text, Collection collection, String locale) {
|
||||
return getMatches(field, text, collection, 0, 2, locale);
|
||||
}
|
||||
|
||||
// XXX FIXME just punt, returning value, never got around to
|
||||
// implementing a reverse query.
|
||||
@Override
|
||||
public String getLabel(String field, String key, String locale) {
|
||||
return key;
|
||||
}
|
||||
|
||||
// NOTE - ignore limit and start for now
|
||||
protected Choices query(String result, String label, String authority,
|
||||
List<BasicNameValuePair> args, int start, int limit) {
|
||||
HttpClient hc = new DefaultHttpClient();
|
||||
String srUrl = url + "?" + URLEncodedUtils.format(args, "UTF8");
|
||||
HttpGet get = new HttpGet(srUrl);
|
||||
|
||||
log.debug("Trying SHERPA/RoMEO Query, URL=" + srUrl);
|
||||
|
||||
try {
|
||||
HttpResponse response = hc.execute(get);
|
||||
if (response.getStatusLine().getStatusCode() == 200) {
|
||||
SAXParserFactory spf = SAXParserFactory.newInstance();
|
||||
SAXParser sp = spf.newSAXParser();
|
||||
XMLReader xr = sp.getXMLReader();
|
||||
SRHandler handler = new SRHandler(result, label, authority);
|
||||
|
||||
// XXX FIXME: should turn off validation here explicitly, but
|
||||
// it seems to be off by default.
|
||||
xr.setFeature("http://xml.org/sax/features/namespaces", true);
|
||||
xr.setContentHandler(handler);
|
||||
xr.setErrorHandler(handler);
|
||||
xr.parse(new InputSource(response.getEntity().getContent()));
|
||||
int confidence;
|
||||
if (handler.total == 0) {
|
||||
confidence = Choices.CF_NOTFOUND;
|
||||
} else if (handler.total == 1) {
|
||||
confidence = Choices.CF_UNCERTAIN;
|
||||
} else {
|
||||
confidence = Choices.CF_AMBIGUOUS;
|
||||
}
|
||||
return new Choices(handler.result, start, handler.total, confidence, false);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("SHERPA/RoMEO query failed: ", e);
|
||||
return null;
|
||||
} catch (ParserConfigurationException e) {
|
||||
log.warn("Failed parsing SHERPA/RoMEO result: ", e);
|
||||
return null;
|
||||
} catch (SAXException e) {
|
||||
log.warn("Failed parsing SHERPA/RoMEO result: ", e);
|
||||
return null;
|
||||
} finally {
|
||||
get.releaseConnection();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// SAX handler to grab SHERPA/RoMEO (and eventually other details) from result
|
||||
private static class SRHandler
|
||||
extends DefaultHandler {
|
||||
private Choice result[] = null;
|
||||
int rindex = 0; // result index
|
||||
int total = 0;
|
||||
|
||||
// name of element containing a result, e.g. <journal>
|
||||
private String resultElement = null;
|
||||
|
||||
// name of element containing the label e.g. <name>
|
||||
private String labelElement = null;
|
||||
|
||||
// name of element containing the authority value e.g. <issn>
|
||||
private String authorityElement = null;
|
||||
|
||||
protected String textValue = null;
|
||||
|
||||
public SRHandler(String result, String label, String authority) {
|
||||
super();
|
||||
resultElement = result;
|
||||
labelElement = label;
|
||||
authorityElement = authority;
|
||||
}
|
||||
|
||||
// NOTE: text value MAY be presented in multiple calls, even if
|
||||
// it all one word, so be ready to splice it together.
|
||||
// BEWARE: subclass's startElement method should call super()
|
||||
// to null out 'value'. (Don't you miss the method combination
|
||||
// options of a real object system like CLOS?)
|
||||
@Override
|
||||
public void characters(char[] ch, int start, int length)
|
||||
throws SAXException {
|
||||
String newValue = new String(ch, start, length);
|
||||
if (newValue.length() > 0) {
|
||||
if (textValue == null) {
|
||||
textValue = newValue;
|
||||
} else {
|
||||
textValue += newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if this was the FIRST "numhits" element, it's size of results:
|
||||
@Override
|
||||
public void endElement(String namespaceURI, String localName,
|
||||
String qName)
|
||||
throws SAXException {
|
||||
if (localName.equals("numhits")) {
|
||||
String stotal = textValue.trim();
|
||||
if (stotal.length() > 0) {
|
||||
total = Integer.parseInt(stotal);
|
||||
result = new Choice[total];
|
||||
if (total > 0) {
|
||||
result[0] = new Choice();
|
||||
log.debug("Got " + total + " records in results.");
|
||||
}
|
||||
}
|
||||
} else if (localName.equals(resultElement)) {
|
||||
// after start of result element, get next hit ready
|
||||
if (++rindex < result.length) {
|
||||
result[rindex] = new Choice();
|
||||
}
|
||||
} else if (localName.equals(labelElement) && textValue != null) {
|
||||
// plug in label value
|
||||
result[rindex].value = textValue.trim();
|
||||
result[rindex].label = result[rindex].value;
|
||||
} else if (authorityElement != null && localName.equals(authorityElement) && textValue != null) {
|
||||
// plug in authority value
|
||||
result[rindex].authority = textValue.trim();
|
||||
} else if (localName.equals("message") && textValue != null) {
|
||||
// error message
|
||||
log.warn("SHERPA/RoMEO response error message: " + textValue.trim());
|
||||
}
|
||||
}
|
||||
|
||||
// subclass overriding this MUST call it with super()
|
||||
@Override
|
||||
public void startElement(String namespaceURI, String localName,
|
||||
String qName, Attributes atts)
|
||||
throws SAXException {
|
||||
textValue = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(SAXParseException exception)
|
||||
throws SAXException {
|
||||
throw new SAXException(exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatalError(SAXParseException exception)
|
||||
throws SAXException {
|
||||
throw new SAXException(exception);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* 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.content.authority;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.dspace.content.Collection;
|
||||
|
||||
/**
|
||||
* Sample Publisher name authority based on SHERPA/RoMEO
|
||||
*
|
||||
*
|
||||
* WARNING: This is a very crude and incomplete implementation, done mainly
|
||||
* as a proof-of-concept. Any site that actually wants to use it will
|
||||
* probably have to refine it (and give patches back to dspace.org).
|
||||
*
|
||||
* @author Larry Stone
|
||||
* @version $Revision $
|
||||
* @see SHERPARoMEOProtocol
|
||||
*/
|
||||
public class SHERPARoMEOPublisher extends SHERPARoMEOProtocol {
|
||||
protected static final String RESULT = "publisher";
|
||||
protected static final String LABEL = "name";
|
||||
// note: the publisher records have nothing we can use as authority code.
|
||||
protected static final String AUTHORITY = null;
|
||||
|
||||
public SHERPARoMEOPublisher() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choices getMatches(String text, Collection collection, int start, int limit, String locale) {
|
||||
// punt if there is no query text
|
||||
if (text == null || text.trim().length() == 0) {
|
||||
return new Choices(true);
|
||||
}
|
||||
|
||||
// query args to add to SHERPA/RoMEO request URL
|
||||
List<BasicNameValuePair> args = new ArrayList<BasicNameValuePair>();
|
||||
args.add(new BasicNameValuePair("pub", text));
|
||||
args.add(new BasicNameValuePair("qtype", "all")); // OR: starts, exact
|
||||
|
||||
Choices result = query(RESULT, LABEL, AUTHORITY, args, start, limit);
|
||||
if (result == null) {
|
||||
result = new Choices(true);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale) {
|
||||
return getMatches(text, collection, start, limit, locale);
|
||||
}
|
||||
}
|
@@ -22,6 +22,7 @@ import org.dspace.content.Community;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.Site;
|
||||
import org.dspace.content.dto.MetadataValueDTO;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.packager.DSpaceAIPIngester;
|
||||
import org.dspace.content.packager.METSManifest;
|
||||
@@ -195,7 +196,7 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros
|
||||
public Element disseminateElement(Context context, DSpaceObject dso)
|
||||
throws CrosswalkException, IOException, SQLException,
|
||||
AuthorizeException {
|
||||
List<MockMetadataValue> dc = new ArrayList<>();
|
||||
List<MetadataValueDTO> dc = new ArrayList<>();
|
||||
if (dso.getType() == Constants.ITEM) {
|
||||
Item item = (Item) dso;
|
||||
EPerson is = item.getSubmitter();
|
||||
@@ -282,8 +283,8 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros
|
||||
return XSLTDisseminationCrosswalk.createDIM(dso, dc);
|
||||
}
|
||||
|
||||
private static MockMetadataValue makeDC(String element, String qualifier, String value) {
|
||||
MockMetadataValue dcv = new MockMetadataValue();
|
||||
private static MetadataValueDTO makeDC(String element, String qualifier, String value) {
|
||||
MetadataValueDTO dcv = new MetadataValueDTO();
|
||||
dcv.setSchema("dc");
|
||||
dcv.setLanguage(null);
|
||||
dcv.setElement(element);
|
||||
|
@@ -29,6 +29,7 @@ import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.Site;
|
||||
import org.dspace.content.dto.MetadataValueDTO;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.CommunityService;
|
||||
@@ -327,7 +328,7 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
|
||||
|
||||
private List<Element> disseminateListInternal(DSpaceObject dso, boolean addSchema)
|
||||
throws CrosswalkException, IOException, SQLException, AuthorizeException {
|
||||
List<MockMetadataValue> dcvs = null;
|
||||
List<MetadataValueDTO> dcvs = null;
|
||||
if (dso.getType() == Constants.ITEM) {
|
||||
dcvs = item2Metadata((Item) dso);
|
||||
} else if (dso.getType() == Constants.COLLECTION) {
|
||||
@@ -344,7 +345,7 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
|
||||
|
||||
List<Element> result = new ArrayList<Element>(dcvs.size());
|
||||
|
||||
for (MockMetadataValue dcv : dcvs) {
|
||||
for (MetadataValueDTO dcv : dcvs) {
|
||||
String qdc = dcv.getSchema() + "." + dcv.getElement();
|
||||
if (dcv.getQualifier() != null) {
|
||||
qdc += "." + dcv.getQualifier();
|
||||
@@ -418,8 +419,8 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
|
||||
* @param site The site to derive metadata from
|
||||
* @return list of metadata
|
||||
*/
|
||||
protected List<MockMetadataValue> site2Metadata(Site site) {
|
||||
List<MockMetadataValue> metadata = new ArrayList<>();
|
||||
protected List<MetadataValueDTO> site2Metadata(Site site) {
|
||||
List<MetadataValueDTO> metadata = new ArrayList<>();
|
||||
|
||||
String identifier_uri = handleService.getCanonicalPrefix()
|
||||
+ site.getHandle();
|
||||
@@ -449,8 +450,8 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
|
||||
* @param community The community to derive metadata from
|
||||
* @return list of metadata
|
||||
*/
|
||||
protected List<MockMetadataValue> community2Metadata(Community community) {
|
||||
List<MockMetadataValue> metadata = new ArrayList<>();
|
||||
protected List<MetadataValueDTO> community2Metadata(Community community) {
|
||||
List<MetadataValueDTO> metadata = new ArrayList<>();
|
||||
|
||||
String description = communityService.getMetadata(community, "introductory_text");
|
||||
String description_abstract = communityService.getMetadata(community, "short_description");
|
||||
@@ -492,8 +493,8 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
|
||||
* @param collection The collection to derive metadata from
|
||||
* @return list of metadata
|
||||
*/
|
||||
protected List<MockMetadataValue> collection2Metadata(Collection collection) {
|
||||
List<MockMetadataValue> metadata = new ArrayList<>();
|
||||
protected List<MetadataValueDTO> collection2Metadata(Collection collection) {
|
||||
List<MetadataValueDTO> metadata = new ArrayList<>();
|
||||
|
||||
String description = collectionService.getMetadata(collection, "introductory_text");
|
||||
String description_abstract = collectionService.getMetadata(collection, "short_description");
|
||||
@@ -546,19 +547,19 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
|
||||
* @param item The item to derive metadata from
|
||||
* @return list of metadata
|
||||
*/
|
||||
protected List<MockMetadataValue> item2Metadata(Item item) {
|
||||
protected List<MetadataValueDTO> item2Metadata(Item item) {
|
||||
List<MetadataValue> dcvs = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY,
|
||||
Item.ANY);
|
||||
List<MockMetadataValue> result = new ArrayList<>();
|
||||
List<MetadataValueDTO> result = new ArrayList<>();
|
||||
for (MetadataValue metadataValue : dcvs) {
|
||||
result.add(new MockMetadataValue(metadataValue));
|
||||
result.add(new MetadataValueDTO(metadataValue));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected MockMetadataValue createDCValue(String element, String qualifier, String value) {
|
||||
MockMetadataValue dcv = new MockMetadataValue();
|
||||
protected MetadataValueDTO createDCValue(String element, String qualifier, String value) {
|
||||
MetadataValueDTO dcv = new MetadataValueDTO();
|
||||
dcv.setSchema("dc");
|
||||
dcv.setElement(element);
|
||||
dcv.setQualifier(qualifier);
|
||||
|
@@ -1,101 +0,0 @@
|
||||
/**
|
||||
* 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.content.crosswalk;
|
||||
|
||||
import org.dspace.content.MetadataField;
|
||||
import org.dspace.content.MetadataSchema;
|
||||
import org.dspace.content.MetadataValue;
|
||||
|
||||
/**
|
||||
* Metadata Value is bound to a database, the dissemination crosswalk require mock metadata just need for desimanation
|
||||
* This class provides a wrapper for this.
|
||||
* This class should only be used for the dissemniation metadata values that aren't to be written to the database
|
||||
*
|
||||
* @author kevinvandevelde at atmire.com
|
||||
*/
|
||||
public class MockMetadataValue {
|
||||
|
||||
private String schema;
|
||||
private String element;
|
||||
private String qualifier;
|
||||
private String language;
|
||||
private String value;
|
||||
private String authority;
|
||||
private int confidence;
|
||||
|
||||
public MockMetadataValue(MetadataValue metadataValue) {
|
||||
MetadataField metadataField = metadataValue.getMetadataField();
|
||||
MetadataSchema metadataSchema = metadataField.getMetadataSchema();
|
||||
schema = metadataSchema.getName();
|
||||
element = metadataField.getElement();
|
||||
qualifier = metadataField.getQualifier();
|
||||
language = metadataValue.getLanguage();
|
||||
value = metadataValue.getValue();
|
||||
authority = metadataValue.getAuthority();
|
||||
confidence = metadataValue.getConfidence();
|
||||
}
|
||||
|
||||
public MockMetadataValue() {
|
||||
}
|
||||
|
||||
public String getSchema() {
|
||||
return schema;
|
||||
}
|
||||
|
||||
public String getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
public String getQualifier() {
|
||||
return qualifier;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setSchema(String schema) {
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
public void setElement(String element) {
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
public void setQualifier(String qualifier) {
|
||||
this.qualifier = qualifier;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
public void setLanguage(String language) {
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
public String getAuthority() {
|
||||
return authority;
|
||||
}
|
||||
|
||||
public void setAuthority(String authority) {
|
||||
this.authority = authority;
|
||||
}
|
||||
|
||||
public int getConfidence() {
|
||||
return confidence;
|
||||
}
|
||||
|
||||
public void setConfidence(int confidence) {
|
||||
this.confidence = confidence;
|
||||
}
|
||||
}
|
@@ -31,6 +31,7 @@ import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.Site;
|
||||
import org.dspace.content.authority.Choices;
|
||||
import org.dspace.content.dto.MetadataValueDTO;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.CommunityService;
|
||||
@@ -307,13 +308,13 @@ public class XSLTDisseminationCrosswalk
|
||||
* @param dcvs list of metadata
|
||||
* @return element
|
||||
*/
|
||||
public static Element createDIM(DSpaceObject dso, List<MockMetadataValue> dcvs) {
|
||||
public static Element createDIM(DSpaceObject dso, List<MetadataValueDTO> dcvs) {
|
||||
Element dim = new Element("dim", DIM_NS);
|
||||
String type = Constants.typeText[dso.getType()];
|
||||
dim.setAttribute("dspaceType", type);
|
||||
|
||||
for (int i = 0; i < dcvs.size(); i++) {
|
||||
MockMetadataValue dcv = dcvs.get(i);
|
||||
MetadataValueDTO dcv = dcvs.get(i);
|
||||
Element field =
|
||||
createField(dcv.getSchema(), dcv.getElement(), dcv.getQualifier(),
|
||||
dcv.getLanguage(), dcv.getValue(), dcv.getAuthority(), dcv.getConfidence());
|
||||
@@ -390,12 +391,12 @@ public class XSLTDisseminationCrosswalk
|
||||
}
|
||||
}
|
||||
|
||||
protected static List<MockMetadataValue> item2Metadata(Item item) {
|
||||
protected static List<MetadataValueDTO> item2Metadata(Item item) {
|
||||
List<MetadataValue> dcvs = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY,
|
||||
Item.ANY);
|
||||
List<MockMetadataValue> result = new ArrayList<>();
|
||||
List<MetadataValueDTO> result = new ArrayList<>();
|
||||
for (MetadataValue metadataValue : dcvs) {
|
||||
result.add(new MockMetadataValue(metadataValue));
|
||||
result.add(new MetadataValueDTO(metadataValue));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* 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.content.dto;
|
||||
|
||||
import org.dspace.content.MetadataField;
|
||||
import org.dspace.content.MetadataSchema;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.authority.Choices;
|
||||
|
||||
/**
|
||||
* This class acts as Data transfer object in which we can store data like in a regular MetadataValue object, but this
|
||||
* one isn't saved in the DB. This can freely be used to represent Metadata without it being saved in the database,
|
||||
* this will typically be used when transferring data
|
||||
*
|
||||
* @author kevinvandevelde at atmire.com
|
||||
*/
|
||||
public class MetadataValueDTO {
|
||||
|
||||
private String schema;
|
||||
private String element;
|
||||
private String qualifier;
|
||||
private String language;
|
||||
private String value;
|
||||
private String authority;
|
||||
private int confidence = Choices.CF_UNSET;
|
||||
|
||||
public MetadataValueDTO(MetadataValue metadataValue) {
|
||||
MetadataField metadataField = metadataValue.getMetadataField();
|
||||
MetadataSchema metadataSchema = metadataField.getMetadataSchema();
|
||||
schema = metadataSchema.getName();
|
||||
element = metadataField.getElement();
|
||||
qualifier = metadataField.getQualifier();
|
||||
language = metadataValue.getLanguage();
|
||||
value = metadataValue.getValue();
|
||||
authority = metadataValue.getAuthority();
|
||||
confidence = metadataValue.getConfidence();
|
||||
}
|
||||
|
||||
public MetadataValueDTO() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for the MetadataValueDTO class
|
||||
* @param schema The schema to be assigned to this MetadataValueDTO object
|
||||
* @param element The element to be assigned to this MetadataValueDTO object
|
||||
* @param qualifier The qualifier to be assigned to this MetadataValueDTO object
|
||||
* @param language The language to be assigend to this MetadataValueDTO object
|
||||
* @param value The value to be assigned to this MetadataValueDTO object
|
||||
* @param authority The authority to be assigned to this MetadataValueDTO object
|
||||
* @param confidence The confidence to be assigned to this MetadataValueDTO object
|
||||
*/
|
||||
public MetadataValueDTO(String schema, String element, String qualifier, String language, String value,
|
||||
String authority, int confidence) {
|
||||
this.schema = schema;
|
||||
this.element = element;
|
||||
this.qualifier = qualifier;
|
||||
this.language = language;
|
||||
this.value = value;
|
||||
this.authority = authority;
|
||||
this.confidence = confidence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for the MetadataValueDTO class
|
||||
* @param schema The schema to be assigned to this MetadataValueDTO object
|
||||
* @param element The element to be assigned to this MetadataValueDTO object
|
||||
* @param qualifier The qualifier to be assigned to this MetadataValueDTO object
|
||||
* @param language The language to be assigend to this MetadataValueDTO object
|
||||
* @param value The value to be assigned to this MetadataValueDTO object
|
||||
*/
|
||||
public MetadataValueDTO(String schema, String element, String qualifier, String language, String value) {
|
||||
this.schema = schema;
|
||||
this.element = element;
|
||||
this.qualifier = qualifier;
|
||||
this.language = language;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getSchema() {
|
||||
return schema;
|
||||
}
|
||||
|
||||
public String getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
public String getQualifier() {
|
||||
return qualifier;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setSchema(String schema) {
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
public void setElement(String element) {
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
public void setQualifier(String qualifier) {
|
||||
this.qualifier = qualifier;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
public void setLanguage(String language) {
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
public String getAuthority() {
|
||||
return authority;
|
||||
}
|
||||
|
||||
public void setAuthority(String authority) {
|
||||
this.authority = authority;
|
||||
}
|
||||
|
||||
public int getConfidence() {
|
||||
return confidence;
|
||||
}
|
||||
|
||||
public void setConfidence(int confidence) {
|
||||
this.confidence = confidence;
|
||||
}
|
||||
}
|
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.authority.rest;
|
||||
package org.dspace.external;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Scanner;
|
||||
@@ -23,16 +23,16 @@ import org.apache.logging.log4j.Logger;
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
*/
|
||||
public class RESTConnector {
|
||||
public class OrcidRestConnector {
|
||||
|
||||
/**
|
||||
* log4j logger
|
||||
*/
|
||||
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(RESTConnector.class);
|
||||
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(OrcidRestConnector.class);
|
||||
|
||||
private String url;
|
||||
|
||||
public RESTConnector(String url) {
|
||||
public OrcidRestConnector(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
34
dspace-api/src/main/java/org/dspace/external/factory/ExternalServiceFactory.java
vendored
Normal file
34
dspace-api/src/main/java/org/dspace/external/factory/ExternalServiceFactory.java
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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.external.factory;
|
||||
|
||||
import org.dspace.external.service.ExternalDataService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
|
||||
/**
|
||||
* Abstract factory to get services for the External package. Use ExternalServiceFactory.getInstance() to retrieve
|
||||
* an implementation
|
||||
*/
|
||||
public abstract class ExternalServiceFactory {
|
||||
|
||||
/**
|
||||
* Calling this method will provide an ExternalDataService bean
|
||||
* @return An implementation of the ExternalDataService
|
||||
*/
|
||||
public abstract ExternalDataService getExternalDataService();
|
||||
|
||||
|
||||
/**
|
||||
* This method will provide you with an implementation of this class to work with
|
||||
* @return An implementation of this class to work with
|
||||
*/
|
||||
public static ExternalServiceFactory getInstance() {
|
||||
return DSpaceServicesFactory.getInstance().getServiceManager()
|
||||
.getServiceByName("externalServiceFactory", ExternalServiceFactory.class);
|
||||
}
|
||||
}
|
26
dspace-api/src/main/java/org/dspace/external/factory/ExternalServiceFactoryImpl.java
vendored
Normal file
26
dspace-api/src/main/java/org/dspace/external/factory/ExternalServiceFactoryImpl.java
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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.external.factory;
|
||||
|
||||
import org.dspace.external.service.ExternalDataService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Abstract factory to get services for the External package. Use ExternalServiceFactory.getInstance() to retrieve
|
||||
* an implementation
|
||||
*/
|
||||
public class ExternalServiceFactoryImpl extends ExternalServiceFactory {
|
||||
|
||||
@Autowired(required = true)
|
||||
private ExternalDataService externalDataService;
|
||||
|
||||
@Override
|
||||
public ExternalDataService getExternalDataService() {
|
||||
return externalDataService;
|
||||
}
|
||||
}
|
146
dspace-api/src/main/java/org/dspace/external/model/ExternalDataObject.java
vendored
Normal file
146
dspace-api/src/main/java/org/dspace/external/model/ExternalDataObject.java
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* 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.external.model;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.content.dto.MetadataValueDTO;
|
||||
|
||||
/**
|
||||
* The representation model object for external data
|
||||
*/
|
||||
public class ExternalDataObject {
|
||||
|
||||
/**
|
||||
* This field determines the ID for the ExternalDataObject
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* This field determines the value for the ExternalDataObject
|
||||
*/
|
||||
private String value;
|
||||
/**
|
||||
* This field determines where the ExternalData came from
|
||||
*/
|
||||
private String source;
|
||||
/**
|
||||
* The list of Metadata values. These our MetadataValueDTO because they won't exist in the DB
|
||||
*/
|
||||
private List<MetadataValueDTO> metadata = new LinkedList<>();
|
||||
/**
|
||||
* The display value of the ExternalDataObject
|
||||
*/
|
||||
private String displayValue;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public ExternalDataObject() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for the ExternalDataObject with as parameter the source of where it came from
|
||||
* @param source The source where the ExternalDataObject came from
|
||||
*/
|
||||
public ExternalDataObject(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the source
|
||||
* @return The source
|
||||
*/
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the source
|
||||
* @param source The source to be set
|
||||
*/
|
||||
public void setSource(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the Metadata
|
||||
* @return The metadata
|
||||
*/
|
||||
public List<MetadataValueDTO> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the Metadata
|
||||
* @param metadata The metadata to be set
|
||||
*/
|
||||
public void setMetadata(List<MetadataValueDTO> metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will add a Metadata value to the list of metadata values
|
||||
* @param metadataValueDTO The metadatavalue to be added
|
||||
*/
|
||||
public void addMetadata(MetadataValueDTO metadataValueDTO) {
|
||||
if (metadata == null) {
|
||||
metadata = new LinkedList<>();
|
||||
}
|
||||
metadata.add(metadataValueDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the display value
|
||||
* @return The display value
|
||||
*/
|
||||
public String getDisplayValue() {
|
||||
return displayValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the display value
|
||||
* @param displayValue The display value to be set
|
||||
*/
|
||||
public void setDisplayValue(String displayValue) {
|
||||
this.displayValue = displayValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the ID
|
||||
* @return The id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the ID
|
||||
* @param id The id to be set
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the value
|
||||
* @return the value value of this ExternalDataObject
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the value
|
||||
* @param value The value to be set on this ExternalDataObject
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
60
dspace-api/src/main/java/org/dspace/external/provider/ExternalDataProvider.java
vendored
Normal file
60
dspace-api/src/main/java/org/dspace/external/provider/ExternalDataProvider.java
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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.external.provider;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.dspace.external.model.ExternalDataObject;
|
||||
|
||||
/**
|
||||
* This interface should be implemented by all providers that will deal with external data
|
||||
*/
|
||||
public interface ExternalDataProvider {
|
||||
|
||||
/**
|
||||
* This method will return the SourceIdentifier for the ExternalDataProvider that implements the interface
|
||||
* @return The source identifier as a String
|
||||
*/
|
||||
public String getSourceIdentifier();
|
||||
|
||||
/**
|
||||
* This method will take a String id as a parameter and it'll call the ExternalDataProvider's endpoint or data
|
||||
* source to retrieve and build the ExternalDataObject
|
||||
* @param id The id on which will be searched
|
||||
* @return An Optional object of ExternalDataObject. This is to indicate that this object may be null.
|
||||
* This ExternalDataObject will return all the data returned by the ExternalDataProvider
|
||||
*/
|
||||
Optional<ExternalDataObject> getExternalDataObject(String id);
|
||||
|
||||
/**
|
||||
* This method will query the ExternalDataProvider's endpoint or data source to retrieve and build a list of
|
||||
* ExternalDataObjects through a search with the given parameters
|
||||
* @param query The query for the search
|
||||
* @param start The start of the search
|
||||
* @param limit The max amount of records to be returned by the search
|
||||
* @return A list of ExternalDataObjects that were retrieved and built by this search
|
||||
*/
|
||||
List<ExternalDataObject> searchExternalDataObjects(String query, int start, int limit);
|
||||
|
||||
/**
|
||||
* This method will return a boolean indicating whether this ExternalDataProvider can deal with the given source
|
||||
* or not
|
||||
* @param source The source on which the check needs to be done
|
||||
* @return A boolean indicating whether this ExternalDataProvider can deal with this source or not
|
||||
*/
|
||||
public boolean supports(String source);
|
||||
|
||||
/**
|
||||
* Returns the total amount of results that this source can return for the given query
|
||||
* @param query The query to be search on and give the total amount of results
|
||||
* @return The total amount of results that the source can return for the given query
|
||||
*/
|
||||
public int getNumberOfResults(String query);
|
||||
|
||||
}
|
@@ -5,27 +5,32 @@
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.content.authority;
|
||||
package org.dspace.external.provider.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.DCPersonName;
|
||||
import org.dspace.core.ConfigurationManager;
|
||||
import org.dspace.content.dto.MetadataValueDTO;
|
||||
import org.dspace.external.model.ExternalDataObject;
|
||||
import org.dspace.external.provider.ExternalDataProvider;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
@@ -51,16 +56,14 @@ import org.xml.sax.helpers.DefaultHandler;
|
||||
*
|
||||
* lcname.url = http://alcme.oclc.org/srw/search/lcnaf
|
||||
*
|
||||
* TODO: make # of results to ask for (and return) configurable.
|
||||
*
|
||||
* @author Larry Stone
|
||||
* @version $Revision $
|
||||
*/
|
||||
public class LCNameAuthority implements ChoiceAuthority {
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(LCNameAuthority.class);
|
||||
public class LCNameDataProvider implements ExternalDataProvider {
|
||||
private static final Logger log = LogManager.getLogger(LCNameDataProvider.class);
|
||||
|
||||
// get these from configuration
|
||||
protected static String url = null;
|
||||
private String url;
|
||||
private String sourceIdentifier;
|
||||
|
||||
// NS URI for SRU respones
|
||||
protected static final String NS_SRU = "http://www.loc.gov/zing/srw/";
|
||||
@@ -68,53 +71,53 @@ public class LCNameAuthority implements ChoiceAuthority {
|
||||
// NS URI for MARC/XML
|
||||
protected static final String NS_MX = "http://www.loc.gov/MARC21/slim";
|
||||
|
||||
// constructor does static init too..
|
||||
public LCNameAuthority() {
|
||||
if (url == null) {
|
||||
url = ConfigurationManager.getProperty("lcname.url");
|
||||
|
||||
// sanity check
|
||||
if (url == null) {
|
||||
throw new IllegalStateException("Missing DSpace configuration keys for LCName Query");
|
||||
}
|
||||
}
|
||||
public String getSourceIdentifier() {
|
||||
return sourceIdentifier;
|
||||
}
|
||||
|
||||
// punt! this is a poor implementation..
|
||||
@Override
|
||||
public Choices getBestMatch(String field, String text, Collection collection, String locale) {
|
||||
return getMatches(field, text, collection, 0, 2, locale);
|
||||
public Optional<ExternalDataObject> getExternalDataObject(String id) {
|
||||
|
||||
StringBuilder query = new StringBuilder();
|
||||
query.append("local.LCCN = \"").append(id).append("\"");
|
||||
List<ExternalDataObject> list = doLookup(0, 10, query);
|
||||
if (list.size() > 0) {
|
||||
return Optional.of(list.get(0));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Match a proposed value against name authority records
|
||||
* Value is assumed to be in "Lastname, Firstname" format.
|
||||
* Generic getter for the url
|
||||
* @return the url value of this LCNameDataProvider
|
||||
*/
|
||||
@Override
|
||||
public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale) {
|
||||
Choices result = queryPerson(text, start, limit);
|
||||
if (result == null) {
|
||||
result = new Choices(true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// punt; supposed to get the canonical display form of a metadata authority key
|
||||
// XXX FIXME implement this with a query on the authority key, cache results
|
||||
@Override
|
||||
public String getLabel(String field, String key, String locale) {
|
||||
return key;
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Guts of the implementation, returns a complete Choices result, or
|
||||
* null for a failure.
|
||||
* Generic setter for the url
|
||||
* @param url The url to be set on this LCNameDataProvider
|
||||
*/
|
||||
private Choices queryPerson(String text, int start, int limit) {
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the sourceIdentifier
|
||||
* @param sourceIdentifier The sourceIdentifier to be set on this LCNameDataProvider
|
||||
*/
|
||||
public void setSourceIdentifier(String sourceIdentifier) {
|
||||
this.sourceIdentifier = sourceIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ExternalDataObject> searchExternalDataObjects(String text, int start, int limit) {
|
||||
// punt if there is no query text
|
||||
if (text == null || text.trim().length() == 0) {
|
||||
return new Choices(true);
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
// 1. build CQL query
|
||||
@@ -123,12 +126,51 @@ public class LCNameAuthority implements ChoiceAuthority {
|
||||
query.append("local.FirstName = \"").append(pn.getFirstNames()).
|
||||
append("\" and local.FamilyName = \"").append(pn.getLastName()).
|
||||
append("\"");
|
||||
return doLookup(start, limit, query);
|
||||
|
||||
}
|
||||
|
||||
private List<ExternalDataObject> doLookup(int start, int limit, StringBuilder query) {
|
||||
// XXX arbitrary default limit - should be configurable?
|
||||
if (limit == 0) {
|
||||
limit = 50;
|
||||
}
|
||||
|
||||
HttpGet get = constructHttpGet(query, start, limit);
|
||||
// 2. web request
|
||||
try {
|
||||
HttpClient hc = new DefaultHttpClient();
|
||||
HttpResponse response = hc.execute(get);
|
||||
if (response.getStatusLine().getStatusCode() == 200) {
|
||||
SRUHandler handler = parseResponseToSRUHandler(response);
|
||||
|
||||
// this probably just means more results available..
|
||||
if (handler.hits != handler.result.size()) {
|
||||
log.warn("Discrepency in results, result.length=" + handler.result.size() +
|
||||
", yet expected results=" + handler.hits);
|
||||
}
|
||||
return handler.result;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("SRU query failed: ", e);
|
||||
return Collections.EMPTY_LIST;
|
||||
} catch (ParserConfigurationException e) {
|
||||
log.warn("Failed parsing SRU result: ", e);
|
||||
return Collections.EMPTY_LIST;
|
||||
} catch (SAXException e) {
|
||||
log.warn("Failed parsing SRU result: ", e);
|
||||
return Collections.EMPTY_LIST;
|
||||
} finally {
|
||||
get.releaseConnection();
|
||||
}
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
public boolean supports(String source) {
|
||||
return StringUtils.equalsIgnoreCase(sourceIdentifier, source);
|
||||
}
|
||||
|
||||
private HttpGet constructHttpGet(StringBuilder query, int start, int limit) {
|
||||
URI sruUri;
|
||||
try {
|
||||
URIBuilder builder = new URIBuilder(url);
|
||||
@@ -141,66 +183,65 @@ public class LCNameAuthority implements ChoiceAuthority {
|
||||
sruUri = builder.build();
|
||||
} catch (URISyntaxException e) {
|
||||
log.error("SRU query failed: ", e);
|
||||
return new Choices(true);
|
||||
return null;
|
||||
}
|
||||
HttpGet get = new HttpGet(sruUri);
|
||||
|
||||
log.debug("Trying SRU query, URL=" + sruUri);
|
||||
return get;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfResults(String query) {
|
||||
// punt if there is no query text
|
||||
if (query == null || query.trim().length() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 1. build CQL query
|
||||
DCPersonName pn = new DCPersonName(query);
|
||||
StringBuilder queryStringBuilder = new StringBuilder();
|
||||
queryStringBuilder.append("local.FirstName = \"").append(pn.getFirstNames()).
|
||||
append("\" and local.FamilyName = \"").append(pn.getLastName()).
|
||||
append("\"");
|
||||
|
||||
HttpGet get = constructHttpGet(queryStringBuilder, 0, 1);
|
||||
|
||||
// 2. web request
|
||||
try {
|
||||
HttpClient hc = new DefaultHttpClient();
|
||||
HttpResponse response = hc.execute(get);
|
||||
if (response.getStatusLine().getStatusCode() == 200) {
|
||||
SAXParserFactory spf = SAXParserFactory.newInstance();
|
||||
SAXParser sp = spf.newSAXParser();
|
||||
XMLReader xr = sp.getXMLReader();
|
||||
SRUHandler handler = new SRUHandler();
|
||||
|
||||
// XXX FIXME: should turn off validation here explicitly, but
|
||||
// it seems to be off by default.
|
||||
xr.setFeature("http://xml.org/sax/features/namespaces", true);
|
||||
xr.setContentHandler(handler);
|
||||
xr.setErrorHandler(handler);
|
||||
HttpEntity responseBody = response.getEntity();
|
||||
xr.parse(new InputSource(responseBody.getContent()));
|
||||
|
||||
// this probably just means more results available..
|
||||
if (handler.hits != handler.result.size()) {
|
||||
log.warn("Discrepency in results, result.length=" + handler.result.size() +
|
||||
", yet expected results=" + handler.hits);
|
||||
}
|
||||
boolean more = handler.hits > (start + handler.result.size());
|
||||
|
||||
// XXX add non-auth option; perhaps the UI should do this?
|
||||
// XXX it's really a policy matter if they allow unauth result.
|
||||
// XXX good, stop it.
|
||||
// handler.result.add(new Choice("", text, "Non-Authority: \""+text+"\""));
|
||||
|
||||
int confidence;
|
||||
if (handler.hits == 0) {
|
||||
confidence = Choices.CF_NOTFOUND;
|
||||
} else if (handler.hits == 1) {
|
||||
confidence = Choices.CF_UNCERTAIN;
|
||||
} else {
|
||||
confidence = Choices.CF_AMBIGUOUS;
|
||||
}
|
||||
return new Choices(handler.result.toArray(new Choice[handler.result.size()]),
|
||||
start, handler.hits, confidence, more);
|
||||
SRUHandler handler = parseResponseToSRUHandler(response);
|
||||
return handler.hits;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("SRU query failed: ", e);
|
||||
return new Choices(true);
|
||||
} catch (ParserConfigurationException e) {
|
||||
} catch (IOException | ParserConfigurationException | SAXException e) {
|
||||
log.warn("Failed parsing SRU result: ", e);
|
||||
return new Choices(true);
|
||||
} catch (SAXException e) {
|
||||
log.warn("Failed parsing SRU result: ", e);
|
||||
return new Choices(true);
|
||||
return 0;
|
||||
} finally {
|
||||
get.releaseConnection();
|
||||
}
|
||||
return new Choices(true);
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
private SRUHandler parseResponseToSRUHandler(HttpResponse response)
|
||||
throws ParserConfigurationException, SAXException, IOException {
|
||||
SAXParserFactory spf = SAXParserFactory.newInstance();
|
||||
SAXParser sp = spf.newSAXParser();
|
||||
XMLReader xr = sp.getXMLReader();
|
||||
SRUHandler handler = new SRUHandler(sourceIdentifier);
|
||||
|
||||
// XXX FIXME: should turn off validation here explicitly, but
|
||||
// it seems to be off by default.
|
||||
xr.setFeature("http://xml.org/sax/features/namespaces", true);
|
||||
xr.setContentHandler(handler);
|
||||
xr.setErrorHandler(handler);
|
||||
HttpEntity responseBody = response.getEntity();
|
||||
xr.parse(new InputSource(responseBody.getContent()));
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,14 +253,21 @@ public class LCNameAuthority implements ChoiceAuthority {
|
||||
*/
|
||||
private static class SRUHandler
|
||||
extends DefaultHandler {
|
||||
private List<Choice> result = new ArrayList<Choice>();
|
||||
private String sourceIdentifier;
|
||||
private List<ExternalDataObject> result = new ArrayList<ExternalDataObject>();
|
||||
private int hits = -1;
|
||||
private String textValue = null;
|
||||
private String name = null;
|
||||
private String birthDate = null;
|
||||
private String lccn = null;
|
||||
private String lastTag = null;
|
||||
private String lastCode = null;
|
||||
|
||||
public SRUHandler(String sourceIdentifier) {
|
||||
super();
|
||||
this.sourceIdentifier = sourceIdentifier;
|
||||
}
|
||||
|
||||
// NOTE: text value MAY be presented in multiple calls, even if
|
||||
// it all one word, so be ready to splice it together.
|
||||
// BEWARE: subclass's startElement method should call super()
|
||||
@@ -259,14 +307,33 @@ public class LCNameAuthority implements ChoiceAuthority {
|
||||
name = name.substring(0, name.length() - 1);
|
||||
}
|
||||
|
||||
// XXX DEBUG
|
||||
// log.debug("Got result, name="+name+", lccn="+lccn);
|
||||
result.add(new Choice(lccn, name, name));
|
||||
ExternalDataObject externalDataObject = new ExternalDataObject(sourceIdentifier);
|
||||
externalDataObject.setDisplayValue(name);
|
||||
externalDataObject.setValue(name);
|
||||
externalDataObject.setId(lccn);
|
||||
String[] names = name.split(", ");
|
||||
String familyName = names[0];
|
||||
String givenName = names.length > 1 ? names[1] : null;
|
||||
if (StringUtils.isNotBlank(familyName)) {
|
||||
externalDataObject
|
||||
.addMetadata(new MetadataValueDTO("person", "familyName", null, null, familyName));
|
||||
}
|
||||
if (StringUtils.isNotBlank(givenName)) {
|
||||
externalDataObject
|
||||
.addMetadata(new MetadataValueDTO("person", "givenName", null, null, givenName));
|
||||
}
|
||||
if (StringUtils.isNotBlank(birthDate)) {
|
||||
externalDataObject
|
||||
.addMetadata(new MetadataValueDTO("person", "date", "birth", null, birthDate));
|
||||
}
|
||||
externalDataObject.addMetadata(new MetadataValueDTO("person", "identifier", "lccn", null, lccn));
|
||||
result.add(externalDataObject);
|
||||
} else {
|
||||
log.warn("Got anomalous result, at least one of these null: lccn=" + lccn + ", name=" + name);
|
||||
}
|
||||
name = null;
|
||||
lccn = null;
|
||||
birthDate = null;
|
||||
} else if (localName.equals("subfield") && namespaceURI.equals(NS_MX)) {
|
||||
if (lastTag != null && lastCode != null) {
|
||||
if (lastTag.equals("010") && lastCode.equals("a")) {
|
||||
@@ -276,9 +343,8 @@ public class LCNameAuthority implements ChoiceAuthority {
|
||||
// 100.a is the personal name
|
||||
name = textValue;
|
||||
}
|
||||
|
||||
if (lastTag.equals("100") && lastCode.equals("d") && (name != null)) {
|
||||
name = name + " " + textValue;
|
||||
if (lastTag.equals("100") && lastCode.equals("d")) {
|
||||
birthDate = textValue;
|
||||
}
|
||||
}
|
||||
}
|
280
dspace-api/src/main/java/org/dspace/external/provider/impl/OrcidV2AuthorDataProvider.java
vendored
Normal file
280
dspace-api/src/main/java/org/dspace/external/provider/impl/OrcidV2AuthorDataProvider.java
vendored
Normal file
@@ -0,0 +1,280 @@
|
||||
/**
|
||||
* 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.external.provider.impl;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.dto.MetadataValueDTO;
|
||||
import org.dspace.external.OrcidRestConnector;
|
||||
import org.dspace.external.model.ExternalDataObject;
|
||||
import org.dspace.external.provider.ExternalDataProvider;
|
||||
import org.dspace.external.provider.orcid.xml.XMLtoBio;
|
||||
import org.json.JSONObject;
|
||||
import org.orcid.jaxb.model.common_v2.OrcidId;
|
||||
import org.orcid.jaxb.model.record_v2.Person;
|
||||
import org.orcid.jaxb.model.search_v2.Result;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
/**
|
||||
* This class is the implementation of the ExternalDataProvider interface that will deal with the OrcidV2 External
|
||||
* Data lookup
|
||||
*/
|
||||
public class OrcidV2AuthorDataProvider implements ExternalDataProvider {
|
||||
|
||||
private static Logger log = LogManager.getLogger(OrcidV2AuthorDataProvider.class);
|
||||
|
||||
private OrcidRestConnector orcidRestConnector;
|
||||
private String OAUTHUrl;
|
||||
private String clientId;
|
||||
|
||||
private String clientSecret;
|
||||
|
||||
private String accessToken;
|
||||
|
||||
private String sourceIdentifier;
|
||||
private String orcidUrl;
|
||||
|
||||
public static final String ORCID_ID_SYNTAX = "\\d{4}-\\d{4}-\\d{4}-(\\d{3}X|\\d{4})";
|
||||
|
||||
@Override
|
||||
public String getSourceIdentifier() {
|
||||
return sourceIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the accessToken that is required for all subsequent calls to ORCID.
|
||||
*
|
||||
* @throws java.io.IOException passed through from HTTPclient.
|
||||
*/
|
||||
public void init() throws IOException {
|
||||
if (StringUtils.isNotBlank(accessToken) && StringUtils.isNotBlank(clientSecret)) {
|
||||
String authenticationParameters = "?client_id=" + clientId +
|
||||
"&client_secret=" + clientSecret +
|
||||
"&scope=/read-public&grant_type=client_credentials";
|
||||
HttpPost httpPost = new HttpPost(OAUTHUrl + authenticationParameters);
|
||||
httpPost.addHeader("Accept", "application/json");
|
||||
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
|
||||
HttpClient httpClient = HttpClientBuilder.create().build();
|
||||
HttpResponse getResponse = httpClient.execute(httpPost);
|
||||
|
||||
JSONObject responseObject = null;
|
||||
try (InputStream is = getResponse.getEntity().getContent();
|
||||
BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
|
||||
String inputStr;
|
||||
while ((inputStr = streamReader.readLine()) != null && responseObject == null) {
|
||||
if (inputStr.startsWith("{") && inputStr.endsWith("}") && inputStr.contains("access_token")) {
|
||||
try {
|
||||
responseObject = new JSONObject(inputStr);
|
||||
} catch (Exception e) {
|
||||
//Not as valid as I'd hoped, move along
|
||||
responseObject = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (responseObject != null && responseObject.has("access_token")) {
|
||||
accessToken = (String) responseObject.get("access_token");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an instance of the Orcidv2 class based on the provided parameters.
|
||||
* This constructor is called through the spring bean initialization
|
||||
*/
|
||||
private OrcidV2AuthorDataProvider(String url) {
|
||||
this.orcidRestConnector = new OrcidRestConnector(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ExternalDataObject> getExternalDataObject(String id) {
|
||||
Person person = getBio(id);
|
||||
ExternalDataObject externalDataObject = convertToExternalDataObject(person);
|
||||
return Optional.of(externalDataObject);
|
||||
}
|
||||
|
||||
protected ExternalDataObject convertToExternalDataObject(Person person) {
|
||||
ExternalDataObject externalDataObject = new ExternalDataObject(sourceIdentifier);
|
||||
String lastName = "";
|
||||
String firstName = "";
|
||||
if (person.getName().getFamilyName() != null) {
|
||||
lastName = person.getName().getFamilyName().getValue();
|
||||
externalDataObject.addMetadata(new MetadataValueDTO("person", "familyName", null, null,
|
||||
lastName));
|
||||
}
|
||||
if (person.getName().getGivenNames() != null) {
|
||||
firstName = person.getName().getGivenNames().getValue();
|
||||
externalDataObject.addMetadata(new MetadataValueDTO("person", "givenName", null, null,
|
||||
firstName));
|
||||
|
||||
}
|
||||
externalDataObject.setId(person.getName().getPath());
|
||||
externalDataObject
|
||||
.addMetadata(new MetadataValueDTO("dc", "identifier", "orcid", null, person.getName().getPath()));
|
||||
externalDataObject
|
||||
.addMetadata(new MetadataValueDTO("dc", "identifier", "uri", null, orcidUrl + person.getName().getPath()));
|
||||
if (!StringUtils.isBlank(lastName) && !StringUtils.isBlank(firstName)) {
|
||||
externalDataObject.setDisplayValue(lastName + ", " + firstName);
|
||||
externalDataObject.setValue(lastName + ", " + firstName);
|
||||
} else if (StringUtils.isBlank(firstName)) {
|
||||
externalDataObject.setDisplayValue(lastName);
|
||||
externalDataObject.setValue(lastName);
|
||||
} else if (StringUtils.isBlank(lastName)) {
|
||||
externalDataObject.setDisplayValue(firstName);
|
||||
externalDataObject.setValue(firstName);
|
||||
}
|
||||
return externalDataObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a Person object based on a given orcid identifier
|
||||
* @param id orcid identifier
|
||||
* @return Person
|
||||
*/
|
||||
public Person getBio(String id) {
|
||||
log.debug("getBio called with ID=" + id);
|
||||
if (!isValid(id)) {
|
||||
return null;
|
||||
}
|
||||
InputStream bioDocument = orcidRestConnector.get(id + ((id.endsWith("/person")) ? "" : "/person"), accessToken);
|
||||
XMLtoBio converter = new XMLtoBio();
|
||||
Person person = converter.convertSinglePerson(bioDocument);
|
||||
try {
|
||||
bioDocument.close();
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return person;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the provided text has the correct ORCID syntax.
|
||||
* Since only searching on ORCID id is allowed, this way, we filter out any queries that would return a
|
||||
* blank result anyway
|
||||
*/
|
||||
private boolean isValid(String text) {
|
||||
return StringUtils.isNotBlank(text) && text.matches(ORCID_ID_SYNTAX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ExternalDataObject> searchExternalDataObjects(String query, int start, int limit) {
|
||||
if (limit > 100) {
|
||||
throw new IllegalArgumentException("The maximum number of results to retrieve cannot exceed 100.");
|
||||
}
|
||||
|
||||
String searchPath = "search?q=" + URLEncoder.encode(query) + "&start=" + start + "&rows=" + limit;
|
||||
log.debug("queryBio searchPath=" + searchPath + " accessToken=" + accessToken);
|
||||
InputStream bioDocument = orcidRestConnector.get(searchPath, accessToken);
|
||||
XMLtoBio converter = new XMLtoBio();
|
||||
List<Result> results = converter.convert(bioDocument);
|
||||
List<Person> bios = new LinkedList<>();
|
||||
for (Result result : results) {
|
||||
OrcidId orcidIdentifier = result.getOrcidIdentifier();
|
||||
if (orcidIdentifier != null) {
|
||||
log.debug("Found OrcidId=" + orcidIdentifier.toString());
|
||||
String orcid = orcidIdentifier.getUriPath();
|
||||
Person bio = getBio(orcid);
|
||||
if (bio != null) {
|
||||
bios.add(bio);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
bioDocument.close();
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
if (bios == null) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
return bios.stream().map(bio -> convertToExternalDataObject(bio)).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(String source) {
|
||||
return StringUtils.equalsIgnoreCase(sourceIdentifier, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfResults(String query) {
|
||||
String searchPath = "search?q=" + URLEncoder.encode(query) + "&start=" + 0 + "&rows=" + 0;
|
||||
log.debug("queryBio searchPath=" + searchPath + " accessToken=" + accessToken);
|
||||
InputStream bioDocument = orcidRestConnector.get(searchPath, accessToken);
|
||||
XMLtoBio converter = new XMLtoBio();
|
||||
return converter.getNumberOfResultsFromXml(bioDocument);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generic setter for the sourceIdentifier
|
||||
* @param sourceIdentifier The sourceIdentifier to be set on this OrcidV2AuthorDataProvider
|
||||
*/
|
||||
@Required
|
||||
public void setSourceIdentifier(String sourceIdentifier) {
|
||||
this.sourceIdentifier = sourceIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the orcidUrl
|
||||
* @return the orcidUrl value of this OrcidV2AuthorDataProvider
|
||||
*/
|
||||
public String getOrcidUrl() {
|
||||
return orcidUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the orcidUrl
|
||||
* @param orcidUrl The orcidUrl to be set on this OrcidV2AuthorDataProvider
|
||||
*/
|
||||
@Required
|
||||
public void setOrcidUrl(String orcidUrl) {
|
||||
this.orcidUrl = orcidUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the OAUTHUrl
|
||||
* @param OAUTHUrl The OAUTHUrl to be set on this OrcidV2AuthorDataProvider
|
||||
*/
|
||||
public void setOAUTHUrl(String OAUTHUrl) {
|
||||
this.OAUTHUrl = OAUTHUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the clientId
|
||||
* @param clientId The clientId to be set on this OrcidV2AuthorDataProvider
|
||||
*/
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the clientSecret
|
||||
* @param clientSecret The clientSecret to be set on this OrcidV2AuthorDataProvider
|
||||
*/
|
||||
public void setClientSecret(String clientSecret) {
|
||||
this.clientSecret = clientSecret;
|
||||
}
|
||||
}
|
236
dspace-api/src/main/java/org/dspace/external/provider/impl/SherpaJournalDataProvider.java
vendored
Normal file
236
dspace-api/src/main/java/org/dspace/external/provider/impl/SherpaJournalDataProvider.java
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
* 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.external.provider.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.sherpa.SHERPAJournal;
|
||||
import org.dspace.app.sherpa.SHERPAResponse;
|
||||
import org.dspace.content.dto.MetadataValueDTO;
|
||||
import org.dspace.external.model.ExternalDataObject;
|
||||
import org.dspace.external.provider.ExternalDataProvider;
|
||||
|
||||
/**
|
||||
* This class is the implementation of the ExternalDataProvider interface that will deal with SherpaJournal External
|
||||
* data lookups
|
||||
*/
|
||||
public class SherpaJournalDataProvider implements ExternalDataProvider {
|
||||
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SherpaJournalDataProvider.class);
|
||||
|
||||
private String url;
|
||||
private String sourceIdentifier;
|
||||
private String apiKey;
|
||||
|
||||
private CloseableHttpClient client = null;
|
||||
|
||||
@Override
|
||||
public String getSourceIdentifier() {
|
||||
return sourceIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the client that we need to call the endpoint
|
||||
* @throws IOException If something goes wrong
|
||||
*/
|
||||
public void init() throws IOException {
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
// httpclient 4.3+ doesn't appear to have any sensible defaults any more. Setting conservative defaults as
|
||||
// not to hammer the SHERPA service too much.
|
||||
client = builder
|
||||
.disableAutomaticRetries()
|
||||
.setMaxConnTotal(5)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ExternalDataObject> getExternalDataObject(String id) {
|
||||
|
||||
HttpGet method = null;
|
||||
SHERPAResponse sherpaResponse = null;
|
||||
int timeout = 5000;
|
||||
URIBuilder uriBuilder = null;
|
||||
try {
|
||||
uriBuilder = new URIBuilder(url);
|
||||
uriBuilder.addParameter("jtitle", id);
|
||||
if (StringUtils.isNotBlank(apiKey)) {
|
||||
uriBuilder.addParameter("ak", apiKey);
|
||||
}
|
||||
|
||||
method = new HttpGet(uriBuilder.build());
|
||||
method.setConfig(RequestConfig.custom()
|
||||
.setConnectionRequestTimeout(timeout)
|
||||
.setConnectTimeout(timeout)
|
||||
.setSocketTimeout(timeout)
|
||||
.build());
|
||||
// Execute the method.
|
||||
|
||||
HttpResponse response = client.execute(method);
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
|
||||
if (statusCode != HttpStatus.SC_OK) {
|
||||
sherpaResponse = new SHERPAResponse("SHERPA/RoMEO return not OK status: "
|
||||
+ statusCode);
|
||||
}
|
||||
|
||||
HttpEntity responseBody = response.getEntity();
|
||||
|
||||
if (null != responseBody) {
|
||||
sherpaResponse = new SHERPAResponse(responseBody.getContent());
|
||||
} else {
|
||||
sherpaResponse = new SHERPAResponse("SHERPA/RoMEO returned no response");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("SHERPA/RoMEO query failed: ", e);
|
||||
}
|
||||
|
||||
if (sherpaResponse == null) {
|
||||
sherpaResponse = new SHERPAResponse(
|
||||
"Error processing the SHERPA/RoMEO answer");
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(sherpaResponse.getJournals())) {
|
||||
SHERPAJournal sherpaJournal = sherpaResponse.getJournals().get(0);
|
||||
|
||||
ExternalDataObject externalDataObject = constructExternalDataObjectFromSherpaJournal(sherpaJournal);
|
||||
return Optional.of(externalDataObject);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ExternalDataObject constructExternalDataObjectFromSherpaJournal(SHERPAJournal sherpaJournal) {
|
||||
ExternalDataObject externalDataObject = new ExternalDataObject();
|
||||
externalDataObject.setSource(sourceIdentifier);
|
||||
externalDataObject.setId(sherpaJournal.getTitle());
|
||||
externalDataObject
|
||||
.addMetadata(new MetadataValueDTO("dc", "title", null, null, sherpaJournal.getTitle()));
|
||||
externalDataObject
|
||||
.addMetadata(new MetadataValueDTO("dc", "identifier", "issn", null, sherpaJournal.getIssn()));
|
||||
externalDataObject.setValue(sherpaJournal.getTitle());
|
||||
externalDataObject.setDisplayValue(sherpaJournal.getTitle());
|
||||
return externalDataObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ExternalDataObject> searchExternalDataObjects(String query, int start, int limit) {
|
||||
// query args to add to SHERPA/RoMEO request URL
|
||||
HttpGet get = constructHttpGet(query);
|
||||
try {
|
||||
HttpClient hc = new DefaultHttpClient();
|
||||
HttpResponse response = hc.execute(get);
|
||||
if (response.getStatusLine().getStatusCode() == 200) {
|
||||
|
||||
SHERPAResponse sherpaResponse = new SHERPAResponse(response.getEntity().getContent());
|
||||
List<ExternalDataObject> list = sherpaResponse.getJournals().stream().map(
|
||||
sherpaJournal -> constructExternalDataObjectFromSherpaJournal(sherpaJournal)).collect(
|
||||
Collectors.toList());
|
||||
// This is because Sherpa returns everything by default so we can't specifiy a start and limit
|
||||
// in the query itself
|
||||
return list.subList(start, Math.min(start + limit, list.size()));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("SHERPA/RoMEO query failed: ", e);
|
||||
return null;
|
||||
} finally {
|
||||
get.releaseConnection();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private HttpGet constructHttpGet(String query) {
|
||||
List<BasicNameValuePair> args = new ArrayList<BasicNameValuePair>();
|
||||
args.add(new BasicNameValuePair("jtitle", query));
|
||||
args.add(new BasicNameValuePair("qtype", "contains"));
|
||||
args.add(new BasicNameValuePair("ak", apiKey));
|
||||
String srUrl = url + "?" + URLEncodedUtils.format(args, "UTF8");
|
||||
return new HttpGet(srUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(String source) {
|
||||
return StringUtils.equalsIgnoreCase(sourceIdentifier, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfResults(String query) {
|
||||
HttpGet get = constructHttpGet(query);
|
||||
try {
|
||||
HttpClient hc = new DefaultHttpClient();
|
||||
HttpResponse response = hc.execute(get);
|
||||
if (response.getStatusLine().getStatusCode() == 200) {
|
||||
|
||||
SHERPAResponse sherpaResponse = new SHERPAResponse(response.getEntity().getContent());
|
||||
return sherpaResponse.getNumHits();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("SHERPA/RoMEO query failed: ", e);
|
||||
return 0;
|
||||
} finally {
|
||||
get.releaseConnection();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the sourceIdentifier
|
||||
* @param sourceIdentifier The sourceIdentifier to be set on this SherpaJournalDataProvider
|
||||
*/
|
||||
public void setSourceIdentifier(String sourceIdentifier) {
|
||||
this.sourceIdentifier = sourceIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the url
|
||||
* @return the url value of this SherpaJournalDataProvider
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the url
|
||||
* @param url The url to be set on this SherpaJournalDataProvider
|
||||
*/
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the apiKey
|
||||
* @return the apiKey value of this SherpaJournalDataProvider
|
||||
*/
|
||||
public String getApiKey() {
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the apiKey
|
||||
* @param apiKey The apiKey to be set on this SherpaJournalDataProvider
|
||||
*/
|
||||
public void setApiKey(String apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
}
|
||||
}
|
194
dspace-api/src/main/java/org/dspace/external/provider/impl/SherpaPublisherDataProvider.java
vendored
Normal file
194
dspace-api/src/main/java/org/dspace/external/provider/impl/SherpaPublisherDataProvider.java
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* 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.external.provider.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.sherpa.SHERPAPublisher;
|
||||
import org.dspace.app.sherpa.SHERPAResponse;
|
||||
import org.dspace.content.dto.MetadataValueDTO;
|
||||
import org.dspace.external.model.ExternalDataObject;
|
||||
import org.dspace.external.provider.ExternalDataProvider;
|
||||
|
||||
/**
|
||||
* This class is the implementation of the ExternalDataProvider interface that will deal with SherpaPublisher External
|
||||
* data lookups
|
||||
*/
|
||||
public class SherpaPublisherDataProvider implements ExternalDataProvider {
|
||||
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SherpaPublisherDataProvider.class);
|
||||
|
||||
private String sourceIdentifier;
|
||||
private String url;
|
||||
private String apiKey;
|
||||
|
||||
@Override
|
||||
public String getSourceIdentifier() {
|
||||
return sourceIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ExternalDataObject> getExternalDataObject(String id) {
|
||||
List<BasicNameValuePair> args = new ArrayList<BasicNameValuePair>();
|
||||
args.add(new BasicNameValuePair("id", id));
|
||||
args.add(new BasicNameValuePair("ak", apiKey));
|
||||
HttpClient hc = new DefaultHttpClient();
|
||||
String srUrl = url + "?" + URLEncodedUtils.format(args, "UTF8");
|
||||
HttpGet get = new HttpGet(srUrl);
|
||||
try {
|
||||
HttpResponse response = hc.execute(get);
|
||||
if (response.getStatusLine().getStatusCode() == 200) {
|
||||
SHERPAResponse sherpaResponse = new SHERPAResponse(response.getEntity().getContent());
|
||||
List<SHERPAPublisher> list = sherpaResponse.getPublishers();
|
||||
if (CollectionUtils.isNotEmpty(list)) {
|
||||
return Optional.of(constructExternalDataObjectFromSherpaPublisher(list.get(0)));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("SHERPA/RoMEO query failed: ", e);
|
||||
return null;
|
||||
} finally {
|
||||
get.releaseConnection();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ExternalDataObject> searchExternalDataObjects(String query, int start, int limit) {
|
||||
HttpGet get = constructHttpGet(query);
|
||||
try {
|
||||
HttpClient hc = new DefaultHttpClient();
|
||||
HttpResponse response = hc.execute(get);
|
||||
if (response.getStatusLine().getStatusCode() == 200) {
|
||||
SHERPAResponse sherpaResponse = new SHERPAResponse(response.getEntity().getContent());
|
||||
List<ExternalDataObject> list = sherpaResponse.getPublishers().stream().map(
|
||||
sherpaPublisher -> constructExternalDataObjectFromSherpaPublisher(sherpaPublisher)).collect(
|
||||
Collectors.toList());
|
||||
|
||||
// This is because Sherpa returns everything by default so we can't specifiy a start and limit
|
||||
// in the query itself
|
||||
return list.subList(start, Math.min(start + limit, list.size()));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("SHERPA/RoMEO query failed: ", e);
|
||||
return null;
|
||||
} finally {
|
||||
get.releaseConnection();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private HttpGet constructHttpGet(String query) {
|
||||
List<BasicNameValuePair> args = new ArrayList<BasicNameValuePair>();
|
||||
args.add(new BasicNameValuePair("pub", query));
|
||||
args.add(new BasicNameValuePair("qtype", "all"));
|
||||
args.add(new BasicNameValuePair("ak", apiKey));
|
||||
String srUrl = url + "?" + URLEncodedUtils.format(args, "UTF8");
|
||||
return new HttpGet(srUrl);
|
||||
}
|
||||
|
||||
private ExternalDataObject constructExternalDataObjectFromSherpaPublisher(SHERPAPublisher sherpaPublisher) {
|
||||
ExternalDataObject externalDataObject = new ExternalDataObject();
|
||||
externalDataObject.setSource(sourceIdentifier);
|
||||
|
||||
//Text value == name
|
||||
externalDataObject.addMetadata(new MetadataValueDTO("dc", "title", null, null, sherpaPublisher.getName()));
|
||||
externalDataObject.setDisplayValue(sherpaPublisher.getName());
|
||||
externalDataObject.setValue(sherpaPublisher.getName());
|
||||
if (StringUtils.isNotBlank(sherpaPublisher.getId())) {
|
||||
externalDataObject.setId(sherpaPublisher.getId());
|
||||
externalDataObject
|
||||
.addMetadata(
|
||||
new MetadataValueDTO("dc", "identifier", "sherpaPublisher", null, sherpaPublisher.getId()));
|
||||
}
|
||||
|
||||
//Text value == homeurl
|
||||
externalDataObject
|
||||
.addMetadata(new MetadataValueDTO("dc", "identifier", "other", null, sherpaPublisher.getHomeurl()));
|
||||
|
||||
return externalDataObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(String source) {
|
||||
return StringUtils.equalsIgnoreCase(sourceIdentifier, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfResults(String query) {
|
||||
HttpGet get = constructHttpGet(query);
|
||||
try {
|
||||
HttpClient hc = new DefaultHttpClient();
|
||||
HttpResponse response = hc.execute(get);
|
||||
if (response.getStatusLine().getStatusCode() == 200) {
|
||||
|
||||
SHERPAResponse sherpaResponse = new SHERPAResponse(response.getEntity().getContent());
|
||||
return sherpaResponse.getNumHits();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("SHERPA/RoMEO query failed: ", e);
|
||||
return 0;
|
||||
} finally {
|
||||
get.releaseConnection();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the sourceIdentifier
|
||||
* @param sourceIdentifier The sourceIdentifier to be set on this SherpaPublisherDataProvider
|
||||
*/
|
||||
public void setSourceIdentifier(String sourceIdentifier) {
|
||||
this.sourceIdentifier = sourceIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the url
|
||||
* @return the url value of this SherpaPublisherDataProvider
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the url
|
||||
* @param url The url to be set on this SherpaPublisherDataProvider
|
||||
*/
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the apiKey
|
||||
* @return the apiKey value of this SherpaPublisherDataProvider
|
||||
*/
|
||||
public String getApiKey() {
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the apiKey
|
||||
* @param apiKey The apiKey to be set on this SherpaPublisherDataProvider
|
||||
*/
|
||||
public void setApiKey(String apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
}
|
||||
}
|
@@ -5,11 +5,10 @@
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.authority.orcid.xml;
|
||||
package org.dspace.external.provider.orcid.xml;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Unmarshaller;
|
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.authority.orcid.xml;
|
||||
package org.dspace.external.provider.orcid.xml;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URISyntaxException;
|
||||
@@ -13,9 +13,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.authority.orcid.Orcidv2;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.orcid.jaxb.model.common_v2.OrcidId;
|
||||
import org.orcid.jaxb.model.record_v2.Person;
|
||||
import org.orcid.jaxb.model.search_v2.Result;
|
||||
import org.orcid.jaxb.model.search_v2.Search;
|
||||
@@ -27,7 +24,7 @@ import org.xml.sax.SAXException;
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
*/
|
||||
public class XMLtoBio extends Converter {
|
||||
public class XMLtoBio extends Converter<List<Result>> {
|
||||
|
||||
/**
|
||||
* log4j logger
|
||||
@@ -35,29 +32,26 @@ public class XMLtoBio extends Converter {
|
||||
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(XMLtoBio.class);
|
||||
|
||||
@Override
|
||||
public List<Person> convert(InputStream xml) {
|
||||
List<Person> bios = new ArrayList<>();
|
||||
public List<Result> convert(InputStream xml) {
|
||||
List<Result> bios = new ArrayList<>();
|
||||
try {
|
||||
Orcidv2 connector = new DSpace().getServiceManager().getServiceByName("AuthoritySource", Orcidv2.class);
|
||||
|
||||
Search search = (Search) unmarshall(xml, Search.class);
|
||||
for (Result result : search.getResult()) {
|
||||
OrcidId orcidIdentifier = result.getOrcidIdentifier();
|
||||
if (orcidIdentifier != null) {
|
||||
log.debug("Found OrcidId=" + orcidIdentifier.toString());
|
||||
String orcid = orcidIdentifier.getUriPath();
|
||||
Person bio = connector.getBio(orcid);
|
||||
if (bio != null) {
|
||||
bios.add(bio);
|
||||
}
|
||||
}
|
||||
}
|
||||
bios = search.getResult();
|
||||
} catch (SAXException | URISyntaxException e) {
|
||||
log.error(e);
|
||||
}
|
||||
return bios;
|
||||
}
|
||||
|
||||
public int getNumberOfResultsFromXml(InputStream xml) {
|
||||
try {
|
||||
Search search = (Search) unmarshall(xml, Search.class);
|
||||
return search.getNumFound().intValue();
|
||||
} catch (SAXException | URISyntaxException e) {
|
||||
log.error(e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
public Person convertSinglePerson(InputStream xml) {
|
||||
Person person = null;
|
||||
try {
|
62
dspace-api/src/main/java/org/dspace/external/service/ExternalDataService.java
vendored
Normal file
62
dspace-api/src/main/java/org/dspace/external/service/ExternalDataService.java
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* 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.external.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.dspace.external.model.ExternalDataObject;
|
||||
import org.dspace.external.provider.ExternalDataProvider;
|
||||
|
||||
/**
|
||||
* This is an interface that will deal with all Service level calls for External Data
|
||||
*/
|
||||
public interface ExternalDataService {
|
||||
|
||||
/**
|
||||
* This method will return a list of ExternalDataProvider objects defined by all ExternalDataProvider spring beans
|
||||
* @return A list of all ExternalDataProvider objects
|
||||
*/
|
||||
public List<ExternalDataProvider> getExternalDataProviders();
|
||||
|
||||
/**
|
||||
* This method will return a single ExternalDataProvider which will support the given sourceIdentifier param
|
||||
* @param sourceIdentifier The source identifier that the ExternalDataProvider that will be returned by this
|
||||
* method has to support
|
||||
* @return The ExternalDataProvider that supports the given source identifier
|
||||
*/
|
||||
public ExternalDataProvider getExternalDataProvider(String sourceIdentifier);
|
||||
|
||||
/**
|
||||
* This method will return an Optional instance of ExternalDataObject for the given source and identifier
|
||||
* It will try to retrieve one through an ExternalDataProvider as defined by the source with the given identifier
|
||||
* @param source The source in which the lookup will be done
|
||||
* @param identifier The identifier which will be looked up
|
||||
* @return An Optional instance of ExternalDataObject
|
||||
*/
|
||||
public Optional<ExternalDataObject> getExternalDataObject(String source, String identifier);
|
||||
|
||||
/**
|
||||
* This method will return a list of ExternalDataObjects as defined through the source in which they will be
|
||||
* searched for, the given query start and limit parameters
|
||||
* @param source The source that defines which ExternalDataProvider is to be used
|
||||
* @param query The query for which the search will be done
|
||||
* @param start The start of the search
|
||||
* @param limit The maximum amount of records to be returned by the search
|
||||
* @return A list of ExternalDataObjects that obey the rules in the parameters
|
||||
*/
|
||||
public List<ExternalDataObject> searchExternalDataObjects(String source, String query, int start, int limit);
|
||||
|
||||
/**
|
||||
* This method wil return the total amount of results that will be found for the given query in the given source
|
||||
* @param source The source in which the query will happen to return the number of results
|
||||
* @param query The query to be ran in this source to retrieve the total amount of results
|
||||
* @return The total amount of results that can be returned for this query in the given source
|
||||
*/
|
||||
public int getNumberOfResults(String source, String query);
|
||||
}
|
68
dspace-api/src/main/java/org/dspace/external/service/impl/ExternalDataServiceImpl.java
vendored
Normal file
68
dspace-api/src/main/java/org/dspace/external/service/impl/ExternalDataServiceImpl.java
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* 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.external.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.dspace.external.model.ExternalDataObject;
|
||||
import org.dspace.external.provider.ExternalDataProvider;
|
||||
import org.dspace.external.service.ExternalDataService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ExternalDataService}
|
||||
*/
|
||||
public class ExternalDataServiceImpl implements ExternalDataService {
|
||||
|
||||
@Autowired
|
||||
private List<ExternalDataProvider> externalDataProviders;
|
||||
|
||||
@Override
|
||||
public Optional<ExternalDataObject> getExternalDataObject(String source, String id) {
|
||||
ExternalDataProvider provider = getExternalDataProvider(source);
|
||||
if (provider == null) {
|
||||
throw new IllegalArgumentException("Provider for: " + source + " couldn't be found");
|
||||
}
|
||||
return provider.getExternalDataObject(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ExternalDataObject> searchExternalDataObjects(String source, String query, int start, int limit) {
|
||||
ExternalDataProvider provider = getExternalDataProvider(source);
|
||||
if (provider == null) {
|
||||
throw new IllegalArgumentException("Provider for: " + source + " couldn't be found");
|
||||
}
|
||||
return provider.searchExternalDataObjects(query, start, limit);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ExternalDataProvider> getExternalDataProviders() {
|
||||
return externalDataProviders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalDataProvider getExternalDataProvider(String sourceIdentifier) {
|
||||
for (ExternalDataProvider externalDataProvider : externalDataProviders) {
|
||||
if (externalDataProvider.supports(sourceIdentifier)) {
|
||||
return externalDataProvider;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfResults(String source, String query) {
|
||||
ExternalDataProvider provider = getExternalDataProvider(source);
|
||||
if (provider == null) {
|
||||
throw new IllegalArgumentException("Provider for: " + source + " couldn't be found");
|
||||
}
|
||||
return provider.getNumberOfResults(query);
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
|
||||
default-lazy-init="true">
|
||||
|
||||
<bean class="org.dspace.external.service.impl.ExternalDataServiceImpl"/>
|
||||
|
||||
<bean class="org.dspace.external.provider.impl.MockDataProvider" init-method="init">
|
||||
<property name="sourceIdentifier" value="mock"/>
|
||||
|
||||
</bean>
|
||||
</beans>
|
||||
|
93
dspace-api/src/test/java/org/dspace/external/provider/impl/MockDataProvider.java
vendored
Normal file
93
dspace-api/src/test/java/org/dspace/external/provider/impl/MockDataProvider.java
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* 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.external.provider.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.content.dto.MetadataValueDTO;
|
||||
import org.dspace.external.model.ExternalDataObject;
|
||||
import org.dspace.external.provider.ExternalDataProvider;
|
||||
|
||||
public class MockDataProvider implements ExternalDataProvider {
|
||||
|
||||
private Map<String, ExternalDataObject> mockLookupMap;
|
||||
private String sourceIdentifier;
|
||||
|
||||
/**
|
||||
* Generic getter for the sourceIdentifier
|
||||
* @return the sourceIdentifier value of this MockDataProvider
|
||||
*/
|
||||
public String getSourceIdentifier() {
|
||||
return sourceIdentifier;
|
||||
}
|
||||
|
||||
public Optional<ExternalDataObject> getExternalDataObject(String id) {
|
||||
ExternalDataObject externalDataObject = mockLookupMap.get(id);
|
||||
if (externalDataObject == null) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
return Optional.of(externalDataObject);
|
||||
}
|
||||
}
|
||||
|
||||
public List<ExternalDataObject> searchExternalDataObjects(String query, int start, int limit) {
|
||||
List<ExternalDataObject> listToReturn = new LinkedList<>();
|
||||
for (Map.Entry<String, ExternalDataObject> entry : mockLookupMap.entrySet()) {
|
||||
if (StringUtils.containsIgnoreCase(entry.getKey(), query)) {
|
||||
listToReturn.add(entry.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
return listToReturn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(String source) {
|
||||
return StringUtils.equalsIgnoreCase(sourceIdentifier, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfResults(String query) {
|
||||
return searchExternalDataObjects(query, 0, 100).size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the sourceIdentifier
|
||||
* @param sourceIdentifier The sourceIdentifier to be set on this MockDataProvider
|
||||
*/
|
||||
public void setSourceIdentifier(String sourceIdentifier) {
|
||||
this.sourceIdentifier = sourceIdentifier;
|
||||
}
|
||||
|
||||
public void init() throws IOException {
|
||||
mockLookupMap = new HashMap<>();
|
||||
List<String> externalDataObjectsToMake = new LinkedList<>();
|
||||
externalDataObjectsToMake.add("one");
|
||||
externalDataObjectsToMake.add("two");
|
||||
externalDataObjectsToMake.add("three");
|
||||
externalDataObjectsToMake.add("onetwo");
|
||||
|
||||
for (String id : externalDataObjectsToMake) {
|
||||
ExternalDataObject externalDataObject = new ExternalDataObject("mock");
|
||||
externalDataObject.setId(id);
|
||||
externalDataObject.setValue(id);
|
||||
externalDataObject.setDisplayValue(id);
|
||||
List<MetadataValueDTO> list = new LinkedList<>();
|
||||
list.add(new MetadataValueDTO("dc", "contributor", "author", null, "Donald, Smith"));
|
||||
externalDataObject.setMetadata(list);
|
||||
|
||||
mockLookupMap.put(id, externalDataObject);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* 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.app.rest;
|
||||
|
||||
import org.dspace.app.rest.link.HalLinkService;
|
||||
import org.dspace.app.rest.model.ExternalSourceEntryRest;
|
||||
import org.dspace.app.rest.model.hateoas.ExternalSourceEntryResource;
|
||||
import org.dspace.app.rest.repository.ExternalSourceRestRepository;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.web.PagedResourcesAssembler;
|
||||
import org.springframework.hateoas.PagedResources;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* This RestController takes care of the retrieval of External data from various endpoints and providers depending
|
||||
* on the calls it receives
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/integration/externalsources/{externalSourceName}")
|
||||
public class ExternalSourcesRestController {
|
||||
|
||||
@Autowired
|
||||
private ExternalSourceRestRepository externalSourceRestRepository;
|
||||
|
||||
@Autowired
|
||||
protected Utils utils;
|
||||
|
||||
@Autowired
|
||||
HalLinkService linkService;
|
||||
|
||||
/**
|
||||
* This method will retrieve all the ExternalSourceEntries for the ExternalSource for the given externalSourceName
|
||||
* param
|
||||
*
|
||||
* curl -X GET http://<dspace.restUrl>/api/integration/externalsources/orcidV2/entries
|
||||
*
|
||||
* @param externalSourceName The externalSourceName that defines which ExternalDataProvider is used
|
||||
* @param query The query used in the lookup
|
||||
* @param parent The parent used in the lookup
|
||||
* @param pageable The pagination object
|
||||
* @param assembler The assembler object
|
||||
* @return A paginated list of ExternalSourceEntryResource objects that comply with the params
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/entries")
|
||||
public PagedResources<ExternalSourceEntryResource> getExternalSourceEntries(
|
||||
@PathVariable("externalSourceName") String externalSourceName,
|
||||
@RequestParam(name = "query") String query,
|
||||
@RequestParam(name = "parent", required = false) String parent,
|
||||
Pageable pageable, PagedResourcesAssembler assembler) {
|
||||
|
||||
Page<ExternalSourceEntryRest> externalSourceEntryRestPage = externalSourceRestRepository
|
||||
.getExternalSourceEntries(externalSourceName, query, parent, pageable);
|
||||
Page<ExternalSourceEntryResource> externalSourceEntryResources = externalSourceEntryRestPage
|
||||
.map(externalSourceEntryRest -> new ExternalSourceEntryResource(externalSourceEntryRest));
|
||||
externalSourceEntryResources.forEach(linkService::addLinks);
|
||||
PagedResources<ExternalSourceEntryResource> result = assembler.toResource(externalSourceEntryResources);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will retrieve one ExternalSourceEntryResource based on the ExternalSource for the given
|
||||
* externalSourceName and with the given entryId
|
||||
*
|
||||
* curl -X GET http://<dspace.restUrl>/api/integration/externalsources/orcidV2/entries/0000-0000-0000-0000
|
||||
*
|
||||
* @param externalSourceName The externalSourceName that defines which ExternalDataProvider is used
|
||||
* @param entryId The entryId used for the lookup
|
||||
* @return An ExternalSourceEntryResource that complies with the above params
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/entryValues/{entryId}")
|
||||
public ExternalSourceEntryResource getExternalSourceEntryValue(@PathVariable("externalSourceName") String
|
||||
externalSourceName,
|
||||
@PathVariable("entryId") String entryId) {
|
||||
|
||||
ExternalSourceEntryRest externalSourceEntryRest = externalSourceRestRepository
|
||||
.getExternalSourceEntryValue(externalSourceName, entryId);
|
||||
ExternalSourceEntryResource externalSourceEntryResource = new ExternalSourceEntryResource(
|
||||
externalSourceEntryRest);
|
||||
linkService.addLinks(externalSourceEntryResource);
|
||||
|
||||
return externalSourceEntryResource;
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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.app.rest.converter;
|
||||
|
||||
import org.dspace.app.rest.model.ExternalSourceEntryRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.external.model.ExternalDataObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This converter deals with the conversion between ExternalDataObjects and ExternalSourceEntryRest objects
|
||||
*/
|
||||
@Component
|
||||
public class ExternalSourceEntryRestConverter implements DSpaceConverter<ExternalDataObject, ExternalSourceEntryRest> {
|
||||
|
||||
@Autowired
|
||||
private MetadataValueDTOListConverter metadataConverter;
|
||||
|
||||
public ExternalSourceEntryRest convert(ExternalDataObject modelObject, Projection projection) {
|
||||
ExternalSourceEntryRest externalSourceEntryRest = new ExternalSourceEntryRest();
|
||||
externalSourceEntryRest.setId(modelObject.getId());
|
||||
externalSourceEntryRest.setExternalSource(modelObject.getSource());
|
||||
externalSourceEntryRest.setDisplay(modelObject.getDisplayValue());
|
||||
externalSourceEntryRest.setValue(modelObject.getValue());
|
||||
externalSourceEntryRest.setExternalSource(modelObject.getSource());
|
||||
externalSourceEntryRest.setMetadata(metadataConverter.convert(modelObject.getMetadata()));
|
||||
return externalSourceEntryRest;
|
||||
}
|
||||
|
||||
public Class<ExternalDataObject> getModelClass() {
|
||||
return ExternalDataObject.class;
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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.app.rest.converter;
|
||||
|
||||
import org.dspace.app.rest.model.ExternalSourceRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.external.provider.ExternalDataProvider;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This converter deals with the conversion between ExternalDataProvider objects and ExternalSourceRest objects
|
||||
*/
|
||||
@Component
|
||||
public class ExternalSourceRestConverter implements DSpaceConverter<ExternalDataProvider, ExternalSourceRest> {
|
||||
|
||||
public ExternalSourceRest convert(ExternalDataProvider modelObject, Projection projection) {
|
||||
ExternalSourceRest externalSourceRest = new ExternalSourceRest();
|
||||
externalSourceRest.setId(modelObject.getSourceIdentifier());
|
||||
externalSourceRest.setName(modelObject.getSourceIdentifier());
|
||||
externalSourceRest.setHierarchical(false);
|
||||
return externalSourceRest;
|
||||
}
|
||||
|
||||
public Class<ExternalDataProvider> getModelClass() {
|
||||
return ExternalDataProvider.class;
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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.app.rest.converter;
|
||||
|
||||
import org.dspace.app.rest.model.MetadataValueRest;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.dto.MetadataValueDTO;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Converter to translate between domain {@link MetadataValue}s and {@link MetadataValueRest} representations.
|
||||
*/
|
||||
@Component
|
||||
public class MetadataValueDTOConverter implements Converter<MetadataValueDTO, MetadataValueRest> {
|
||||
|
||||
/**
|
||||
* Gets a rest representation of the given domain metadata value.
|
||||
*
|
||||
* @param metadataValue the domain value.
|
||||
* @return the rest representation.
|
||||
*/
|
||||
@Override
|
||||
public MetadataValueRest convert(MetadataValueDTO metadataValue) {
|
||||
MetadataValueRest metadataValueRest = new MetadataValueRest();
|
||||
metadataValueRest.setValue(metadataValue.getValue());
|
||||
metadataValueRest.setLanguage(metadataValue.getLanguage());
|
||||
metadataValueRest.setAuthority(metadataValue.getAuthority());
|
||||
metadataValueRest.setConfidence(metadataValue.getConfidence());
|
||||
return metadataValueRest;
|
||||
}
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* 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.app.rest.converter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.rest.model.MetadataRest;
|
||||
import org.dspace.app.rest.model.MetadataValueRest;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.dto.MetadataValueDTO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Converter to translate between lists of domain {@link MetadataValue}s and {@link MetadataRest} representations.
|
||||
*/
|
||||
@Component
|
||||
public class MetadataValueDTOListConverter implements Converter<List<MetadataValueDTO>, MetadataRest> {
|
||||
|
||||
@Autowired
|
||||
private MetadataValueDTOConverter valueConverter;
|
||||
|
||||
/**
|
||||
* Gets a rest representation of the given list of domain metadata values.
|
||||
*
|
||||
* @param metadataValueList the domain values.
|
||||
* @return the rest representation.
|
||||
*/
|
||||
@Override
|
||||
public MetadataRest convert(List<MetadataValueDTO> metadataValueList) {
|
||||
// Convert each value to a DTO while retaining place order in a map of key -> SortedSet
|
||||
Map<String, List<MetadataValueRest>> mapOfLists = new HashMap<>();
|
||||
for (MetadataValueDTO metadataValue : metadataValueList) {
|
||||
String key = metadataValue.getSchema() + "." + metadataValue.getElement();
|
||||
if (StringUtils.isNotBlank(metadataValue.getQualifier())) {
|
||||
key += "." + metadataValue.getQualifier();
|
||||
}
|
||||
List<MetadataValueRest> list = mapOfLists.get(key);
|
||||
if (list == null) {
|
||||
list = new LinkedList();
|
||||
mapOfLists.put(key, list);
|
||||
}
|
||||
list.add(valueConverter.convert(metadataValue));
|
||||
}
|
||||
|
||||
MetadataRest metadataRest = new MetadataRest();
|
||||
|
||||
// Populate MetadataRest's map of key -> List while respecting SortedSet's order
|
||||
Map<String, List<MetadataValueRest>> metadataRestMap = metadataRest.getMap();
|
||||
for (Map.Entry<String, List<MetadataValueRest>> entry : mapOfLists.entrySet()) {
|
||||
metadataRestMap.put(entry.getKey(), entry.getValue().stream().collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
return metadataRest;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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.app.rest.link.externalsources;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.dspace.app.rest.ExternalSourcesRestController;
|
||||
import org.dspace.app.rest.link.HalLinkFactory;
|
||||
import org.dspace.app.rest.model.hateoas.ExternalSourceEntryResource;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This HalLinkFactory adds links to the ExternalSourceEntryResource object
|
||||
*/
|
||||
@Component
|
||||
public class ExternalSourceEntryHalLinkFactory
|
||||
extends HalLinkFactory<ExternalSourceEntryResource, ExternalSourcesRestController> {
|
||||
|
||||
@Override
|
||||
protected void addLinks(ExternalSourceEntryResource halResource, Pageable pageable, LinkedList<Link> list)
|
||||
throws Exception {
|
||||
|
||||
list.add(buildLink(Link.REL_SELF,
|
||||
getMethodOn().getExternalSourceEntryValue(halResource.getContent().getExternalSource(),
|
||||
halResource.getContent().getId())));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<ExternalSourcesRestController> getControllerClass() {
|
||||
return ExternalSourcesRestController.class;
|
||||
}
|
||||
|
||||
protected Class<ExternalSourceEntryResource> getResourceClass() {
|
||||
return ExternalSourceEntryResource.class;
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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.app.rest.link.externalsources;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.dspace.app.rest.ExternalSourcesRestController;
|
||||
import org.dspace.app.rest.link.HalLinkFactory;
|
||||
import org.dspace.app.rest.model.hateoas.ExternalSourceResource;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This HalLinkFactory adds links to the ExternalSourceResource object
|
||||
*/
|
||||
@Component
|
||||
public class ExternalSourceHalLinkFactory extends
|
||||
HalLinkFactory<ExternalSourceResource, ExternalSourcesRestController> {
|
||||
|
||||
@Override
|
||||
protected void addLinks(ExternalSourceResource halResource, Pageable pageable, LinkedList<Link> list)
|
||||
throws Exception {
|
||||
|
||||
list.add(buildLink("entries", getMethodOn()
|
||||
.getExternalSourceEntries(halResource.getContent().getName(), "", null, null, null)));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<ExternalSourcesRestController> getControllerClass() {
|
||||
return ExternalSourcesRestController.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<ExternalSourceResource> getResourceClass() {
|
||||
return ExternalSourceResource.class;
|
||||
}
|
||||
}
|
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* 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.app.rest.model;
|
||||
|
||||
import org.dspace.app.rest.ExternalSourcesRestController;
|
||||
|
||||
/**
|
||||
* This class serves as a REST representation for an entry of external data
|
||||
*/
|
||||
public class ExternalSourceEntryRest extends BaseObjectRest<String> {
|
||||
|
||||
public static final String NAME = "externalSourceEntry";
|
||||
public static final String PLURAL_NAME = "externalSourceEntries";
|
||||
public static final String CATEGORY = RestAddressableModel.INTEGRATION;
|
||||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return CATEGORY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getController() {
|
||||
return ExternalSourcesRestController.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
private String id;
|
||||
private String display;
|
||||
private String value;
|
||||
private String externalSource;
|
||||
private MetadataRest metadata = new MetadataRest();
|
||||
|
||||
/**
|
||||
* Generic getter for the id
|
||||
* @return the id value of this ExternalSourceEntryRest
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the id
|
||||
* @param id The id to be set on this ExternalSourceEntryRest
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the display
|
||||
* @return the display value of this ExternalSourceEntryRest
|
||||
*/
|
||||
public String getDisplay() {
|
||||
return display;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the display
|
||||
* @param display The display to be set on this ExternalSourceEntryRest
|
||||
*/
|
||||
public void setDisplay(String display) {
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the value
|
||||
* @return the value value of this ExternalSourceEntryRest
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the value
|
||||
* @param value The value to be set on this ExternalSourceEntryRest
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the externalSource
|
||||
* @return the externalSource value of this ExternalSourceEntryRest
|
||||
*/
|
||||
public String getExternalSource() {
|
||||
return externalSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the externalSource
|
||||
* @param externalSource The externalSource to be set on this ExternalSourceEntryRest
|
||||
*/
|
||||
public void setExternalSource(String externalSource) {
|
||||
this.externalSource = externalSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the metadata
|
||||
* @return the metadata value of this ExternalSourceEntryRest
|
||||
*/
|
||||
public MetadataRest getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the metadata
|
||||
* @param metadata The metadata to be set on this ExternalSourceEntryRest
|
||||
*/
|
||||
public void setMetadata(MetadataRest metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
}
|
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* 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.app.rest.model;
|
||||
|
||||
import org.dspace.app.rest.RestResourceController;
|
||||
|
||||
/**
|
||||
* This class serves as a REST representation for an External Source
|
||||
*/
|
||||
public class ExternalSourceRest extends BaseObjectRest<String> {
|
||||
|
||||
public static final String NAME = "externalsource";
|
||||
public static final String PLURAL_NAME = "externalsources";
|
||||
public static final String CATEGORY = RestAddressableModel.INTEGRATION;
|
||||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return CATEGORY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getController() {
|
||||
return RestResourceController.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private boolean hierarchical;
|
||||
|
||||
/**
|
||||
* Generic getter for the id
|
||||
* @return the id value of this ExternalSourceRest
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the id
|
||||
* @param id The id to be set on this ExternalSourceRest
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the name
|
||||
* @return the name value of this ExternalSourceRest
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the name
|
||||
* @param name The name to be set on this ExternalSourceRest
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the hierarchical
|
||||
* @return the hierarchical value of this ExternalSourceRest
|
||||
*/
|
||||
public boolean isHierarchical() {
|
||||
return hierarchical;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the hierarchical
|
||||
* @param hierarchical The hierarchical to be set on this ExternalSourceRest
|
||||
*/
|
||||
public void setHierarchical(boolean hierarchical) {
|
||||
this.hierarchical = hierarchical;
|
||||
}
|
||||
}
|
@@ -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/
|
||||
*/
|
||||
package org.dspace.app.rest.model.hateoas;
|
||||
|
||||
import org.dspace.app.rest.model.ExternalSourceEntryRest;
|
||||
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
|
||||
|
||||
/**
|
||||
* This class serves as the HAL Resource for an ExternalSourceEntryRest object
|
||||
*/
|
||||
@RelNameDSpaceResource(ExternalSourceEntryRest.NAME)
|
||||
public class ExternalSourceEntryResource extends HALResource<ExternalSourceEntryRest> {
|
||||
public ExternalSourceEntryResource(ExternalSourceEntryRest content) {
|
||||
super(content);
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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.app.rest.model.hateoas;
|
||||
|
||||
import org.dspace.app.rest.model.ExternalSourceRest;
|
||||
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
|
||||
/**
|
||||
* This class serves as the HAL Resource for the ExternalSourceRest object
|
||||
*/
|
||||
@RelNameDSpaceResource(ExternalSourceRest.NAME)
|
||||
public class ExternalSourceResource extends DSpaceResource<ExternalSourceRest> {
|
||||
public ExternalSourceResource(ExternalSourceRest externalSourceRest, Utils utils) {
|
||||
super(externalSourceRest, utils);
|
||||
}
|
||||
}
|
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* 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.app.rest.repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.dspace.app.rest.converter.ConverterService;
|
||||
import org.dspace.app.rest.model.ExternalSourceEntryRest;
|
||||
import org.dspace.app.rest.model.ExternalSourceRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.external.model.ExternalDataObject;
|
||||
import org.dspace.external.provider.ExternalDataProvider;
|
||||
import org.dspace.external.service.ExternalDataService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This is the Repository that is responsible for the functionality and implementations coming from
|
||||
* {@link org.dspace.app.rest.ExternalSourcesRestController}
|
||||
*/
|
||||
@Component(ExternalSourceRest.CATEGORY + "." + ExternalSourceRest.NAME)
|
||||
public class ExternalSourceRestRepository extends DSpaceRestRepository<ExternalSourceRest, String> {
|
||||
|
||||
@Autowired
|
||||
private ExternalDataService externalDataService;
|
||||
|
||||
@Autowired
|
||||
ConverterService converter;
|
||||
|
||||
/**
|
||||
* This method will retrieve one ExternalSourceEntryResource based on the ExternalSource for the given
|
||||
* externalSourceName and with the given entryId
|
||||
* @param externalSourceName The externalSourceName that defines which ExternalDataProvider is used
|
||||
* @param entryId The entryId used for the lookup
|
||||
* @return An ExternalSourceEntryRest object that complies with the above params
|
||||
*/
|
||||
public ExternalSourceEntryRest getExternalSourceEntryValue(String externalSourceName, String entryId) {
|
||||
if (externalDataService.getExternalDataProvider(externalSourceName) == null) {
|
||||
throw new ResourceNotFoundException("The externalSource for: " + externalSourceName + " couldn't be found");
|
||||
}
|
||||
Optional<ExternalDataObject> externalDataObject = externalDataService.getExternalDataObject(externalSourceName,
|
||||
entryId);
|
||||
ExternalDataObject dataObject = externalDataObject.orElseThrow(() -> new ResourceNotFoundException(
|
||||
"Couldn't find an ExternalSource for source: " + externalSourceName + " and ID: " + entryId));
|
||||
return converter.toRest(dataObject, Projection.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will retrieve all the ExternalSourceEntries for the ExternalSource for the given externalSourceName
|
||||
* param
|
||||
* @param externalSourceName The externalSourceName that defines which ExternalDataProvider is used
|
||||
* @param query The query used in the lookup
|
||||
* @param parent The parent used in the lookup
|
||||
* @param pageable The pagination object
|
||||
* @return A paginated list of ExternalSourceEntryResource objects that comply with the params
|
||||
*/
|
||||
public Page<ExternalSourceEntryRest> getExternalSourceEntries(String externalSourceName, String query,
|
||||
String parent, Pageable pageable) {
|
||||
if (externalDataService.getExternalDataProvider(externalSourceName) == null) {
|
||||
throw new ResourceNotFoundException("The externalSource for: " + externalSourceName + " couldn't be found");
|
||||
}
|
||||
List<ExternalDataObject> externalDataObjects = externalDataService
|
||||
.searchExternalDataObjects(externalSourceName, query, pageable.getOffset(), pageable.getPageSize());
|
||||
int numberOfResults = externalDataService.getNumberOfResults(externalSourceName, query);
|
||||
return converter.toRestPage(externalDataObjects, pageable, numberOfResults,
|
||||
utils.obtainProjection(true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalSourceRest findOne(Context context, String externalSourceName) {
|
||||
ExternalDataProvider externalDataProvider = externalDataService.getExternalDataProvider(externalSourceName);
|
||||
if (externalDataProvider == null) {
|
||||
throw new ResourceNotFoundException("ExternalDataProvider for: " +
|
||||
externalSourceName + " couldn't be found");
|
||||
}
|
||||
return converter.toRest(externalDataProvider, Projection.DEFAULT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<ExternalSourceRest> findAll(Context context, Pageable pageable) {
|
||||
List<ExternalDataProvider> externalSources = externalDataService.getExternalDataProviders();
|
||||
return converter.toRestPage(externalSources, pageable, externalSources.size(),
|
||||
utils.obtainProjection(true));
|
||||
}
|
||||
|
||||
public Class<ExternalSourceRest> getDomainClass() {
|
||||
return ExternalSourceRest.class;
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
|
||||
default-lazy-init="true">
|
||||
|
||||
<bean class="org.dspace.external.service.impl.ExternalDataServiceImpl"/>
|
||||
|
||||
<bean class="org.dspace.external.provider.impl.MockDataProvider" init-method="init">
|
||||
<property name="sourceIdentifier" value="mock"/>
|
||||
|
||||
</bean>
|
||||
</beans>
|
||||
|
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* 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.app.rest;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.dspace.app.rest.matcher.ExternalSourceEntryMatcher;
|
||||
import org.dspace.app.rest.matcher.ExternalSourceMatcher;
|
||||
import org.dspace.app.rest.matcher.PageMatcher;
|
||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ExternalSourcesRestControllerIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void findAllExternalSources() throws Exception {
|
||||
getClient().perform(get("/api/integration/externalsources"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.externalsources", Matchers.hasItem(
|
||||
ExternalSourceMatcher.matchExternalSource("mock", "mock", false)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneExternalSourcesExistingSources() throws Exception {
|
||||
getClient().perform(get("/api/integration/externalsources/mock"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", Matchers.is(
|
||||
ExternalSourceMatcher.matchExternalSource("mock", "mock", false)
|
||||
)));
|
||||
}
|
||||
@Test
|
||||
public void findOneExternalSourcesNotExistingSources() throws Exception {
|
||||
getClient().perform(get("/api/integration/externalsources/mock2"))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneExternalSourceEntryValue() throws Exception {
|
||||
getClient().perform(get("/api/integration/externalsources/mock/entryValues/one"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", Matchers.is(
|
||||
ExternalSourceEntryMatcher.matchExternalSourceEntry("one", "one", "one", "mock")
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneExternalSourceEntryValueInvalidEntryId() throws Exception {
|
||||
getClient().perform(get("/api/integration/externalsources/mock/entryValues/entryIdInvalid"))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneExternalSourceEntryValueInvalidSource() throws Exception {
|
||||
getClient().perform(get("/api/integration/externalsources/mocktwo/entryValues/one"))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneExternalSourceEntriesInvalidSource() throws Exception {
|
||||
getClient().perform(get("/api/integration/externalsources/mocktwo/entries")
|
||||
.param("query", "test"))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneExternalSourceEntriesApplicableQuery() throws Exception {
|
||||
getClient().perform(get("/api/integration/externalsources/mock/entries")
|
||||
.param("query", "one"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.externalSourceEntries", Matchers.containsInAnyOrder(
|
||||
ExternalSourceEntryMatcher.matchExternalSourceEntry("one", "one", "one", "mock"),
|
||||
ExternalSourceEntryMatcher.matchExternalSourceEntry("onetwo", "onetwo", "onetwo", "mock")
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneExternalSourceEntriesApplicableQueryPagination() throws Exception {
|
||||
getClient().perform(get("/api/integration/externalsources/mock/entries")
|
||||
.param("query", "one").param("size", "1"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.externalSourceEntries", Matchers.hasItem(
|
||||
ExternalSourceEntryMatcher.matchExternalSourceEntry("onetwo", "onetwo", "onetwo", "mock")
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", PageMatcher.pageEntryWithTotalPagesAndElements(0, 1, 2, 2)));
|
||||
|
||||
getClient().perform(get("/api/integration/externalsources/mock/entries")
|
||||
.param("query", "one").param("size", "1").param("page", "1"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.externalSourceEntries", Matchers.hasItem(
|
||||
ExternalSourceEntryMatcher.matchExternalSourceEntry("one", "one", "one", "mock")
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", PageMatcher.pageEntryWithTotalPagesAndElements(1, 1, 2, 2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneExternalSourceEntriesNoReturnQuery() throws Exception {
|
||||
getClient().perform(get("/api/integration/externalsources/mock/entries")
|
||||
.param("query", "randomqueryfornoresults"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded").doesNotExist());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneExternalSourceEntriesNoQuery() throws Exception {
|
||||
getClient().perform(get("/api/integration/externalsources/mock/entries"))
|
||||
.andExpect(status().isUnprocessableEntity());
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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.app.rest.matcher;
|
||||
|
||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
public class ExternalSourceEntryMatcher {
|
||||
|
||||
private ExternalSourceEntryMatcher() { }
|
||||
|
||||
public static Matcher<? super Object> matchExternalSourceEntry(String id, String displayValue,
|
||||
String value, String source) {
|
||||
return allOf(
|
||||
hasJsonPath("$.id", is(id)),
|
||||
hasJsonPath("$.display", is(displayValue)),
|
||||
hasJsonPath("$.value", is(value)),
|
||||
hasJsonPath("$.externalSource", is(source))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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.app.rest.matcher;
|
||||
|
||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
public class ExternalSourceMatcher {
|
||||
|
||||
private ExternalSourceMatcher() {
|
||||
}
|
||||
|
||||
public static Matcher<? super Object> matchExternalSource(String id, String name, boolean hierarchical) {
|
||||
return allOf(
|
||||
hasJsonPath("$.id", is(id)),
|
||||
hasJsonPath("$.name", is(name)),
|
||||
hasJsonPath("$.hierarchical", is(hierarchical))
|
||||
);
|
||||
}
|
||||
}
|
93
dspace-server-webapp/src/test/java/org/dspace/external/provider/impl/MockDataProvider.java
vendored
Normal file
93
dspace-server-webapp/src/test/java/org/dspace/external/provider/impl/MockDataProvider.java
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* 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.external.provider.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.content.dto.MetadataValueDTO;
|
||||
import org.dspace.external.model.ExternalDataObject;
|
||||
import org.dspace.external.provider.ExternalDataProvider;
|
||||
|
||||
public class MockDataProvider implements ExternalDataProvider {
|
||||
|
||||
private Map<String, ExternalDataObject> mockLookupMap;
|
||||
private String sourceIdentifier;
|
||||
|
||||
/**
|
||||
* Generic getter for the sourceIdentifier
|
||||
* @return the sourceIdentifier value of this MockDataProvider
|
||||
*/
|
||||
public String getSourceIdentifier() {
|
||||
return sourceIdentifier;
|
||||
}
|
||||
|
||||
public Optional<ExternalDataObject> getExternalDataObject(String id) {
|
||||
ExternalDataObject externalDataObject = mockLookupMap.get(id);
|
||||
if (externalDataObject == null) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
return Optional.of(externalDataObject);
|
||||
}
|
||||
}
|
||||
|
||||
public List<ExternalDataObject> searchExternalDataObjects(String query, int start, int limit) {
|
||||
List<ExternalDataObject> listToReturn = new LinkedList<>();
|
||||
for (Map.Entry<String, ExternalDataObject> entry : mockLookupMap.entrySet()) {
|
||||
if (StringUtils.containsIgnoreCase(entry.getKey(), query)) {
|
||||
listToReturn.add(entry.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
return listToReturn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(String source) {
|
||||
return StringUtils.equalsIgnoreCase(sourceIdentifier, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfResults(String query) {
|
||||
return searchExternalDataObjects(query, 0, 100).size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the sourceIdentifier
|
||||
* @param sourceIdentifier The sourceIdentifier to be set on this MockDataProvider
|
||||
*/
|
||||
public void setSourceIdentifier(String sourceIdentifier) {
|
||||
this.sourceIdentifier = sourceIdentifier;
|
||||
}
|
||||
|
||||
public void init() throws IOException {
|
||||
mockLookupMap = new HashMap<>();
|
||||
List<String> externalDataObjectsToMake = new LinkedList<>();
|
||||
externalDataObjectsToMake.add("one");
|
||||
externalDataObjectsToMake.add("two");
|
||||
externalDataObjectsToMake.add("three");
|
||||
externalDataObjectsToMake.add("onetwo");
|
||||
|
||||
for (String id : externalDataObjectsToMake) {
|
||||
ExternalDataObject externalDataObject = new ExternalDataObject("mock");
|
||||
externalDataObject.setId(id);
|
||||
externalDataObject.setValue(id);
|
||||
externalDataObject.setDisplayValue(id);
|
||||
List<MetadataValueDTO> list = new LinkedList<>();
|
||||
list.add(new MetadataValueDTO("dc", "contributor", "author", null, "Donald, Smith"));
|
||||
externalDataObject.setMetadata(list);
|
||||
|
||||
mockLookupMap.put(id, externalDataObject);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1449,20 +1449,13 @@ sitemap.engineurls = http://www.google.com/webmasters/sitemaps/ping?sitemap=
|
||||
# the SHERPA/RoMEO endpoint
|
||||
sherpa.romeo.url = http://www.sherpa.ac.uk/romeo/api29.php
|
||||
|
||||
# to disable the sherpa/romeo integration
|
||||
# uncomment the follow line
|
||||
# webui.submission.sherparomeo-policy-enabled = false
|
||||
|
||||
# please register for a free api access key to get many benefits
|
||||
# http://www.sherpa.ac.uk/news/romeoapikeys.htm
|
||||
# sherpa.romeo.apikey = YOUR-API-KEY
|
||||
sherpa.romeo.apikey =
|
||||
|
||||
##### Authority Control Settings #####
|
||||
#plugin.named.org.dspace.content.authority.ChoiceAuthority = \
|
||||
# org.dspace.content.authority.SampleAuthority = Sample, \
|
||||
# org.dspace.content.authority.LCNameAuthority = LCNameAuthority, \
|
||||
# org.dspace.content.authority.SHERPARoMEOPublisher = SRPublisher, \
|
||||
# org.dspace.content.authority.SHERPARoMEOJournalTitle = SRJournalTitle, \
|
||||
# org.dspace.content.authority.SolrAuthority = SolrAuthorAuthority
|
||||
|
||||
#Uncomment to enable ORCID authority control
|
||||
@@ -1472,6 +1465,7 @@ sherpa.romeo.url = http://www.sherpa.ac.uk/romeo/api29.php
|
||||
# URL of ORCID API
|
||||
# Defaults to using the Public API (pub.orcid.org)
|
||||
orcid.api.url = https://pub.orcid.org/v2.1
|
||||
orcid.url = https://orcid.org/
|
||||
|
||||
## The DCInputAuthority plugin is automatically configured with every
|
||||
## value-pairs element in input-forms.xml, namely:
|
||||
@@ -1493,7 +1487,7 @@ plugin.selfnamed.org.dspace.content.authority.ChoiceAuthority = \
|
||||
org.dspace.content.authority.DSpaceControlledVocabulary
|
||||
|
||||
## configure LC Names plugin
|
||||
#lcname.url = http://alcme.oclc.org/srw/search/lcnaf
|
||||
lcname.url = http://alcme.oclc.org/srw/search/lcnaf
|
||||
|
||||
##
|
||||
## This sets the default lowest confidence level at which a metadata value is included
|
||||
@@ -1518,10 +1512,6 @@ authority.minconfidence = ambiguous
|
||||
#
|
||||
#authority.author.indexer.field.1=dc.contributor.author
|
||||
|
||||
## demo: use LC plugin for author
|
||||
#choices.plugin.dc.contributor.author = LCNameAuthority
|
||||
#choices.presentation.dc.contributor.author = lookup
|
||||
#authority.controlled.dc.contributor.author = true
|
||||
##
|
||||
## This sets the lowest confidence level at which a metadata value is included
|
||||
## in an authority-controlled browse (and search) index. It is a symbolic
|
||||
@@ -1535,15 +1525,6 @@ authority.minconfidence = ambiguous
|
||||
#vocabulary.plugin.srsc.hierarchy.suggest = true
|
||||
#vocabulary.plugin.srsc.delimiter = "::"
|
||||
|
||||
## Demo: publisher name lookup through SHERPA/RoMEO:
|
||||
#choices.plugin.dc.publisher = SRPublisher
|
||||
#choices.presentation.dc.publisher = suggest
|
||||
|
||||
## demo: journal title lookup, with ISSN as authority
|
||||
#choices.plugin.dc.title.alternative = SRJournalTitle
|
||||
#choices.presentation.dc.title.alternative = suggest
|
||||
#authority.controlled.dc.title.alternative = true
|
||||
|
||||
# Change number of choices shown in the select in Choices lookup popup
|
||||
#xmlui.lookup.select.size = 12
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
<bean id="authenticateServiceFactory" class="org.dspace.authenticate.factory.AuthenticateServiceFactoryImpl"/>
|
||||
|
||||
<bean id="authorityServiceFactory" class="org.dspace.authority.factory.AuthorityServiceFactoryImpl"/>
|
||||
<bean id="externalServiceFactory" class="org.dspace.external.factory.ExternalServiceFactoryImpl"/>
|
||||
<bean id="contentAuthorityServiceFactory" class="org.dspace.content.authority.factory.ContentAuthorityServiceFactoryImpl"/>
|
||||
|
||||
<bean id="authorizeServiceFactory" class="org.dspace.authorize.factory.AuthorizeServiceFactoryImpl"/>
|
||||
|
34
dspace/config/spring/api/external-services.xml
Normal file
34
dspace/config/spring/api/external-services.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
|
||||
default-lazy-init="true">
|
||||
|
||||
<bean class="org.dspace.external.service.impl.ExternalDataServiceImpl"/>
|
||||
|
||||
<bean class="org.dspace.external.provider.impl.SherpaJournalDataProvider" init-method="init">
|
||||
<property name="sourceIdentifier" value="sherpaJournal"/>
|
||||
<property name="url" value="${sherpa.romeo.url}"/>
|
||||
<!-- please register for a free api access key to get many benefits -->
|
||||
<property name="apiKey" value="${sherpa.romeo.apikey}"/>
|
||||
|
||||
</bean>
|
||||
<bean class="org.dspace.external.provider.impl.SherpaPublisherDataProvider">
|
||||
<property name="sourceIdentifier" value="sherpaPublisher"/>
|
||||
<property name="url" value="${sherpa.romeo.url}"/>
|
||||
<!-- please register for a free api access key to get many benefits -->
|
||||
<property name="apiKey" value="${sherpa.romeo.apikey}"/>
|
||||
|
||||
</bean>
|
||||
<bean class="org.dspace.external.provider.impl.OrcidV2AuthorDataProvider" init-method="init">
|
||||
<constructor-arg value="${orcid.api.url}"/>
|
||||
<property name="sourceIdentifier" value="orcidV2"/>
|
||||
<property name="orcidUrl" value="${orcid.url}" />
|
||||
</bean>
|
||||
|
||||
<bean class="org.dspace.external.provider.impl.LCNameDataProvider">
|
||||
<property name="url" value="${lcname.url}"/>
|
||||
<property name="sourceIdentifier" value="lcname"/>
|
||||
</bean>
|
||||
</beans>
|
||||
|
@@ -18,7 +18,6 @@
|
||||
<bean name="AuthorityTypes" class="org.dspace.authority.AuthorityTypes">
|
||||
<property name="types">
|
||||
<list>
|
||||
<bean class="org.dspace.authority.orcid.Orcidv2AuthorityValue"/>
|
||||
<bean class="org.dspace.authority.PersonAuthorityValue"/>
|
||||
</list>
|
||||
</property>
|
||||
@@ -31,10 +30,4 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<alias name="OrcidSource" alias="AuthoritySource"/>
|
||||
<bean name="OrcidSource" class="org.dspace.authority.orcid.Orcidv2" init-method="init">
|
||||
<constructor-arg value="${orcid.api.url}"/>
|
||||
</bean>
|
||||
|
||||
|
||||
</beans>
|
||||
|
Reference in New Issue
Block a user