mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 10:04:21 +00:00
[CST-18015] Added base OpenAlex Publication integration.
[CST-18015] Added base OpenAlex Publication integration.
This commit is contained in:
@@ -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.importer.external.metadatamapping.contributor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author adamo.fapohunda at 4science.com
|
||||||
|
**/
|
||||||
|
public abstract class AbstractJsonPathMetadataProcessor implements JsonPathMetadataProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<String> processMetadata(String json) {
|
||||||
|
Collection<String> values = new ArrayList<>();
|
||||||
|
JsonNode jsonNode = convertStringJsonToJsonNode(json);
|
||||||
|
JsonNode node = jsonNode.at(getPath());
|
||||||
|
if (node.isArray()) {
|
||||||
|
for (JsonNode value : node) {
|
||||||
|
String nodeValue = getStringValue(value);
|
||||||
|
if (StringUtils.isNotBlank(nodeValue)) {
|
||||||
|
values.add(nodeValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!node.isNull() && StringUtils.isNotBlank(node.toString())) {
|
||||||
|
String nodeValue = getStringValue(node);
|
||||||
|
if (StringUtils.isNotBlank(nodeValue)) {
|
||||||
|
values.add(nodeValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String getStringValue(JsonNode node);
|
||||||
|
|
||||||
|
protected abstract Logger getLogger();
|
||||||
|
|
||||||
|
protected abstract String getPath();
|
||||||
|
|
||||||
|
private JsonNode convertStringJsonToJsonNode(String json) {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
JsonNode body = null;
|
||||||
|
try {
|
||||||
|
body = mapper.readTree(json);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
getLogger().error("Unable to process json response.", e);
|
||||||
|
}
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* 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.importer.external.metadatamapping.contributor;
|
||||||
|
|
||||||
|
import java.util.SortedMap;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author adamo.fapohunda at 4science.com
|
||||||
|
**/
|
||||||
|
public class InvertedIndexProcessor extends AbstractJsonPathMetadataProcessor {
|
||||||
|
|
||||||
|
private static final Logger log = LogManager.getLogger(InvertedIndexProcessor.class);
|
||||||
|
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getStringValue(JsonNode node) {
|
||||||
|
if (node == null || node.isEmpty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
SortedMap<Integer, String> positionMap = new TreeMap<>();
|
||||||
|
node.at(path).fields().forEachRemaining(entry -> entry.getValue()
|
||||||
|
.forEach(position ->
|
||||||
|
positionMap
|
||||||
|
.put(position.asInt(), entry.getKey())));
|
||||||
|
|
||||||
|
return String.join(" ", positionMap.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Logger getLogger() {
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPath() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath(String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
}
|
@@ -18,6 +18,6 @@ import java.util.Collection;
|
|||||||
*/
|
*/
|
||||||
public interface JsonPathMetadataProcessor {
|
public interface JsonPathMetadataProcessor {
|
||||||
|
|
||||||
public Collection<String> processMetadata(String json);
|
Collection<String> processMetadata(String json);
|
||||||
|
|
||||||
}
|
}
|
@@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* 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.importer.external.openalex.metadatamapping;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.dspace.importer.external.metadatamapping.contributor.AbstractJsonPathMetadataProcessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author adamo.fapohunda at 4science.com
|
||||||
|
**/
|
||||||
|
public class OpenAlexDateMetadataProcessor extends AbstractJsonPathMetadataProcessor {
|
||||||
|
|
||||||
|
private static final Logger log = LogManager.getLogger(OpenAlexDateMetadataProcessor.class);
|
||||||
|
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getStringValue(JsonNode node) {
|
||||||
|
|
||||||
|
if (node == null || !node.isTextual()) {
|
||||||
|
throw new IllegalArgumentException("Input must be a non-null JsonNode containing a text value");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String dateStr = node.asText();
|
||||||
|
LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ISO_DATE);
|
||||||
|
return date.toString();
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
throw new IllegalArgumentException("Invalid ISO 8601 date format: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Logger getLogger() {
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath(String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* 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.importer.external.openalex.metadatamapping;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.dspace.importer.external.metadatamapping.contributor.AbstractJsonPathMetadataProcessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author adamo.fapohunda at 4science.com
|
||||||
|
**/
|
||||||
|
public class OpenAlexIdMetadataProcessor extends AbstractJsonPathMetadataProcessor {
|
||||||
|
|
||||||
|
private static final Logger log = LogManager.getLogger(OpenAlexIdMetadataProcessor.class);
|
||||||
|
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
private String toBeReplaced;
|
||||||
|
|
||||||
|
private String replacement;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getStringValue(JsonNode node) {
|
||||||
|
if (node == null || !node.isTextual()) {
|
||||||
|
throw new IllegalArgumentException("Input must be a non-null JsonNode containing a text value");
|
||||||
|
}
|
||||||
|
String idStr = node.asText();
|
||||||
|
if (toBeReplaced == null || toBeReplaced.isEmpty() || replacement == null) {
|
||||||
|
return idStr;
|
||||||
|
}
|
||||||
|
return idStr.replaceAll(toBeReplaced, replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Logger getLogger() {
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath(String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToBeReplaced(String toBeReplaced) {
|
||||||
|
this.toBeReplaced = toBeReplaced;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReplacement(String replacement) {
|
||||||
|
this.replacement = replacement;
|
||||||
|
}
|
||||||
|
}
|
@@ -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.importer.external.openalex.metadatamapping;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.dspace.importer.external.metadatamapping.AbstractMetadataFieldMapping;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author adamo.fapohunda at 4science.com
|
||||||
|
**/
|
||||||
|
public class OpenAlexPublicationFieldMapping extends AbstractMetadataFieldMapping {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Resource(name = "openalexPublicationsMetadataFieldMap")
|
||||||
|
public void setMetadataFieldMap(Map metadataFieldMap) {
|
||||||
|
super.setMetadataFieldMap(metadataFieldMap);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* 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.importer.external.openalex.service;
|
||||||
|
|
||||||
|
import org.dspace.importer.external.service.components.QuerySource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author adamo.fapohunda at 4science.com
|
||||||
|
**/
|
||||||
|
public interface OpenAlexImportMetadataSourceService extends QuerySource {
|
||||||
|
}
|
@@ -0,0 +1,287 @@
|
|||||||
|
/**
|
||||||
|
* 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.importer.external.openalex.service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import jakarta.el.MethodNotFoundException;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.dspace.content.Item;
|
||||||
|
import org.dspace.importer.external.datamodel.ImportRecord;
|
||||||
|
import org.dspace.importer.external.datamodel.Query;
|
||||||
|
import org.dspace.importer.external.exception.MetadataSourceException;
|
||||||
|
import org.dspace.importer.external.liveimportclient.service.LiveImportClient;
|
||||||
|
import org.dspace.importer.external.liveimportclient.service.LiveImportClientImpl;
|
||||||
|
import org.dspace.importer.external.service.AbstractImportMetadataSourceService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author adamo.fapohunda at 4science.com
|
||||||
|
**/
|
||||||
|
public class OpenAlexImportMetadataSourceServiceImpl extends AbstractImportMetadataSourceService<String>
|
||||||
|
implements OpenAlexImportMetadataSourceService {
|
||||||
|
|
||||||
|
private final static Logger log = LogManager.getLogger();
|
||||||
|
private final int timeout = 1000;
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private LiveImportClient liveImportClient;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getImportSource() {
|
||||||
|
return "openalex";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImportRecord getRecord(String id) throws MetadataSourceException {
|
||||||
|
if (id == null) {
|
||||||
|
throw new MetadataSourceException("ID cannot be null");
|
||||||
|
}
|
||||||
|
List<ImportRecord> records = retry(new SearchByIdCallable(id));
|
||||||
|
return CollectionUtils.isEmpty(records) ? null : records.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRecordsCount(String query) throws MetadataSourceException {
|
||||||
|
if (query == null) {
|
||||||
|
throw new MetadataSourceException("Query cannot be null");
|
||||||
|
}
|
||||||
|
return retry(new CountByQueryCallable(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRecordsCount(Query query) throws MetadataSourceException {
|
||||||
|
if (query == null) {
|
||||||
|
throw new MetadataSourceException("Query cannot be null");
|
||||||
|
}
|
||||||
|
return retry(new CountByQueryCallable(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ImportRecord> getRecords(String query, int start, int count) throws MetadataSourceException {
|
||||||
|
if (query == null) {
|
||||||
|
throw new MetadataSourceException("Query cannot be null");
|
||||||
|
}
|
||||||
|
return retry(new SearchByQueryCallable(query, start, count));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ImportRecord> getRecords(Query query) throws MetadataSourceException {
|
||||||
|
throw new MethodNotFoundException("This method is not implemented for OpenAlex");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImportRecord getRecord(Query query) throws MetadataSourceException {
|
||||||
|
if (query == null) {
|
||||||
|
throw new MetadataSourceException("Query cannot be null");
|
||||||
|
}
|
||||||
|
List<ImportRecord> records = retry(new SearchByIdCallable(query));
|
||||||
|
return CollectionUtils.isEmpty(records) ? null : records.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ImportRecord> findMatchingRecords(Query query) throws MetadataSourceException {
|
||||||
|
throw new MethodNotFoundException("This method is not implemented for OpenAlex");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException {
|
||||||
|
throw new MethodNotFoundException("This method is not implemented for OpenAlex");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() throws Exception {
|
||||||
|
if (liveImportClient == null) {
|
||||||
|
throw new IllegalStateException("LiveImportClient not properly initialized");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(url)) {
|
||||||
|
throw new IllegalStateException("URL not properly configured");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer count(String query) throws MetadataSourceException {
|
||||||
|
if (query == null) {
|
||||||
|
throw new MetadataSourceException("Query cannot be null");
|
||||||
|
}
|
||||||
|
Map<String, Map<String, String>> params = new HashMap<>();
|
||||||
|
Map<String, String> uriParams = new HashMap<>();
|
||||||
|
params.put(LiveImportClientImpl.URI_PARAMETERS, uriParams);
|
||||||
|
try {
|
||||||
|
uriParams.put("search", query);
|
||||||
|
String resp = liveImportClient.executeHttpGetRequest(timeout, this.url, params);
|
||||||
|
if (StringUtils.isEmpty(resp)) {
|
||||||
|
log.error("Got an empty response from LiveImportClient for query: {}", query);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
JsonNode jsonNode = convertStringJsonToJsonNode(resp);
|
||||||
|
if (jsonNode != null && jsonNode.hasNonNull("meta")
|
||||||
|
&& jsonNode.at("/meta/count").isNumber()) {
|
||||||
|
return jsonNode.at("/meta/count").asInt();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error executing count query", e);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ImportRecord> searchById(String id) {
|
||||||
|
List<ImportRecord> results = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
String resp = liveImportClient.executeHttpGetRequest(timeout, this.url + "/" + id, new HashMap<>());
|
||||||
|
if (StringUtils.isEmpty(resp)) {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
JsonNode jsonNode = convertStringJsonToJsonNode(resp);
|
||||||
|
if (jsonNode != null) {
|
||||||
|
ImportRecord record = transformSourceRecords(jsonNode.toString());
|
||||||
|
if (record != null) {
|
||||||
|
results.add(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error searching by ID: {}", id, e);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ImportRecord> search(String query, Integer page, Integer pageSize) {
|
||||||
|
List<ImportRecord> results = new ArrayList<>();
|
||||||
|
Map<String, Map<String, String>> params = new HashMap<>();
|
||||||
|
Map<String, String> uriParams = new HashMap<>();
|
||||||
|
params.put(LiveImportClientImpl.URI_PARAMETERS, uriParams);
|
||||||
|
|
||||||
|
try {
|
||||||
|
uriParams.put("search", query);
|
||||||
|
if (page != null) {
|
||||||
|
uriParams.put("page", String.valueOf(page + 1));
|
||||||
|
}
|
||||||
|
if (pageSize != null) {
|
||||||
|
uriParams.put("per_page", String.valueOf(pageSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
String resp = liveImportClient.executeHttpGetRequest(timeout, this.url, params);
|
||||||
|
if (StringUtils.isEmpty(resp)) {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonNode jsonNode = convertStringJsonToJsonNode(resp);
|
||||||
|
if (jsonNode != null) {
|
||||||
|
JsonNode docs = jsonNode.at("/results");
|
||||||
|
if (docs != null && docs.isArray()) {
|
||||||
|
for (JsonNode node : docs) {
|
||||||
|
if (node != null) {
|
||||||
|
ImportRecord record = transformSourceRecords(node.toString());
|
||||||
|
if (record != null) {
|
||||||
|
results.add(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error executing search query", e);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private JsonNode convertStringJsonToJsonNode(String json) {
|
||||||
|
if (StringUtils.isEmpty(json)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return new ObjectMapper().readTree(json);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
log.error("Unable to process JSON response", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = StringUtils.trimToNull(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SearchByQueryCallable implements Callable<List<ImportRecord>> {
|
||||||
|
private final Query query;
|
||||||
|
|
||||||
|
private SearchByQueryCallable(String queryString, int start, int count) {
|
||||||
|
query = new Query();
|
||||||
|
query.addParameter("query", queryString);
|
||||||
|
query.addParameter("page", start / count);
|
||||||
|
query.addParameter("count", count);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ImportRecord> call() throws Exception {
|
||||||
|
String queryString = query.getParameterAsClass("query", String.class);
|
||||||
|
if (queryString == null) {
|
||||||
|
throw new MetadataSourceException("Query cannot be null");
|
||||||
|
}
|
||||||
|
return search(queryString,
|
||||||
|
query.getParameterAsClass("page", Integer.class),
|
||||||
|
query.getParameterAsClass("count", Integer.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SearchByIdCallable implements Callable<List<ImportRecord>> {
|
||||||
|
private final Query query;
|
||||||
|
|
||||||
|
private SearchByIdCallable(String id) {
|
||||||
|
this.query = new Query();
|
||||||
|
query.addParameter("id", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SearchByIdCallable(Query query) {
|
||||||
|
this.query = query;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ImportRecord> call() throws Exception {
|
||||||
|
String id = query.getParameterAsClass("id", String.class);
|
||||||
|
if (id == null) {
|
||||||
|
throw new MetadataSourceException("Id cannot be null");
|
||||||
|
}
|
||||||
|
return searchById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CountByQueryCallable implements Callable<Integer> {
|
||||||
|
private final Query query;
|
||||||
|
|
||||||
|
private CountByQueryCallable(String queryString) {
|
||||||
|
query = new Query();
|
||||||
|
query.addParameter("query", queryString);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CountByQueryCallable(Query query) {
|
||||||
|
this.query = query;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer call() throws Exception {
|
||||||
|
String queryString = query.getParameterAsClass("query", String.class);
|
||||||
|
if (queryString == null) {
|
||||||
|
throw new MetadataSourceException("Query cannot be null");
|
||||||
|
}
|
||||||
|
return count(queryString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -160,7 +160,7 @@
|
|||||||
<bean id="openairePublicationMetadataFieldMapping"
|
<bean id="openairePublicationMetadataFieldMapping"
|
||||||
class="org.dspace.importer.external.openaire.metadatamapping.OpenAIREPublicationFieldMapping">
|
class="org.dspace.importer.external.openaire.metadatamapping.OpenAIREPublicationFieldMapping">
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="CrossRefImportService" class="org.dspace.importer.external.crossref.CrossRefImportMetadataSourceServiceImpl" scope="singleton">
|
<bean id="CrossRefImportService" class="org.dspace.importer.external.crossref.CrossRefImportMetadataSourceServiceImpl" scope="singleton">
|
||||||
<property name="metadataFieldMapping" ref="CrossRefMetadataFieldMapping"/>
|
<property name="metadataFieldMapping" ref="CrossRefMetadataFieldMapping"/>
|
||||||
<property name="url" value="${crossref.url}"/>
|
<property name="url" value="${crossref.url}"/>
|
||||||
@@ -188,7 +188,7 @@
|
|||||||
<property name="viewMode" value="${scopus.search-api.viewMode}"/>
|
<property name="viewMode" value="${scopus.search-api.viewMode}"/>
|
||||||
</bean>
|
</bean>
|
||||||
<bean id="scopusMetadataFieldMapping" class="org.dspace.importer.external.scopus.service.ScopusFieldMapping"/>
|
<bean id="scopusMetadataFieldMapping" class="org.dspace.importer.external.scopus.service.ScopusFieldMapping"/>
|
||||||
|
|
||||||
<bean id="rorImportService" class="org.dspace.importer.external.ror.service.RorImportMetadataSourceServiceImpl">
|
<bean id="rorImportService" class="org.dspace.importer.external.ror.service.RorImportMetadataSourceServiceImpl">
|
||||||
<property name="metadataFieldMapping" ref="rorMetadataFieldMapping"/>
|
<property name="metadataFieldMapping" ref="rorMetadataFieldMapping"/>
|
||||||
<property name="url" value="${ror.orgunit-import.api-url}"/>
|
<property name="url" value="${ror.orgunit-import.api-url}"/>
|
||||||
@@ -244,4 +244,13 @@
|
|||||||
<constructor-arg value="dc.identifier.other"/>
|
<constructor-arg value="dc.identifier.other"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openalexImportServiceByTitle" class="org.dspace.importer.external.openalex.service.OpenAlexImportMetadataSourceServiceImpl">
|
||||||
|
<property name="metadataFieldMapping" ref="openalexPublicationMetadataFieldMapping"/>
|
||||||
|
<property name="url" value="${openalex.url.works}"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openalexPublicationMetadataFieldMapping"
|
||||||
|
class="org.dspace.importer.external.openalex.metadatamapping.OpenAlexPublicationFieldMapping">
|
||||||
|
</bean>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
@@ -1,4 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
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/
|
||||||
|
|
||||||
|
-->
|
||||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
|
||||||
default-lazy-init="true">
|
default-lazy-init="true">
|
||||||
@@ -282,4 +291,17 @@
|
|||||||
</list>
|
</list>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openalexLiveImportDataProviderByTitle" class="org.dspace.external.provider.impl.LiveImportDataProvider">
|
||||||
|
<property name="metadataSource" ref="openalexImportServiceByTitle"/>
|
||||||
|
<property name="sourceIdentifier" value="openalex"/>
|
||||||
|
<property name="recordIdMetadata" value="dc.identifier.other"/>
|
||||||
|
<property name="supportedEntityTypes">
|
||||||
|
<list>
|
||||||
|
<value>Publication</value>
|
||||||
|
<value>none</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
138
dspace/config/spring/api/openalex-integration.xml
Normal file
138
dspace/config/spring/api/openalex-integration.xml
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
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/
|
||||||
|
|
||||||
|
-->
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:context="http://www.springframework.org/schema/context"
|
||||||
|
xmlns:util="http://www.springframework.org/schema/util"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||||
|
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||||
|
http://www.springframework.org/schema/context
|
||||||
|
http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
|
||||||
|
default-autowire-candidates="*Service,*DAO,javax.sql.DataSource">
|
||||||
|
|
||||||
|
<context:annotation-config/>
|
||||||
|
<!-- allows us to use spring annotations in beans -->
|
||||||
|
|
||||||
|
<util:map id="openalexPublicationsMetadataFieldMap" key-type="org.dspace.importer.external.metadatamapping.MetadataFieldConfig"
|
||||||
|
value-type="org.dspace.importer.external.metadatamapping.contributor.MetadataContributor">
|
||||||
|
<description>Defines which metadatum is mapped on which metadatum. Note that while the key must be unique it
|
||||||
|
only matters here for postprocessing of the value. The mapped MetadatumContributor has full control over
|
||||||
|
what metadatafield is generated.
|
||||||
|
</description>
|
||||||
|
<entry key-ref="openalex.title" value-ref="openalexTitleContrib"/>
|
||||||
|
<entry key-ref="openalex.abstract" value-ref="openalexAbstractContrib"/>
|
||||||
|
<entry key-ref="openalex.publication.date" value-ref="openalexDateContrib"/>
|
||||||
|
<entry key-ref="openalex.doi" value-ref="openalexDoiContrib"/>
|
||||||
|
<entry key-ref="openalex.pmid" value-ref="openalexPmidContrib"/>
|
||||||
|
<entry key-ref="openalex.openalexId" value-ref="openalexIdContrib"/>
|
||||||
|
<!-- <entry key-ref="openalex.mag" value-ref="openalexMagContrib"/>-->
|
||||||
|
<entry key-ref="openalex.author" value-ref="openalexAuthorContrib"/>
|
||||||
|
<entry key-ref="openalex.language" value-ref="openalexLanguageContrib"/>
|
||||||
|
</util:map>
|
||||||
|
|
||||||
|
<bean id="openalexTitleContrib" class="org.dspace.importer.external.metadatamapping.contributor.SimpleJsonPathMetadataContributor">
|
||||||
|
<property name="field" ref="openalex.title"/>
|
||||||
|
<property name="query" value="/title"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="openalex.title" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.title"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openalexAbstractContrib" class="org.dspace.importer.external.metadatamapping.contributor.SimpleJsonPathMetadataContributor">
|
||||||
|
<property name="field" ref="openalex.abstract"/>
|
||||||
|
<property name="metadataProcessor" ref="invertedIndexMetadataProcessor"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="openalex.abstract" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.description.abstract"/>
|
||||||
|
</bean>
|
||||||
|
<bean name="invertedIndexMetadataProcessor" class="org.dspace.importer.external.metadatamapping.contributor.InvertedIndexProcessor">
|
||||||
|
<property name="path" value="/abstract_inverted_index"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openalexDateContrib" class="org.dspace.importer.external.metadatamapping.contributor.SimpleJsonPathMetadataContributor">
|
||||||
|
<property name="field" ref="openalex.publication.date"/>
|
||||||
|
<property name="metadataProcessor" ref="openalexDateMetadataProcessor"/>
|
||||||
|
</bean>
|
||||||
|
<bean name="openalexDateMetadataProcessor" class="org.dspace.importer.external.openalex.metadatamapping.OpenAlexDateMetadataProcessor">
|
||||||
|
<property name="path" value="/publication_date"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="openalex.publication.date" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.date.issued"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openalexDoiContrib" class="org.dspace.importer.external.metadatamapping.contributor.SimpleJsonPathMetadataContributor">
|
||||||
|
<property name="field" ref="openalex.doi"/>
|
||||||
|
<property name="metadataProcessor" ref="openalexDoiMetadataProcessor"/>
|
||||||
|
</bean>
|
||||||
|
<bean name="openalexDoiMetadataProcessor" class="org.dspace.importer.external.openalex.metadatamapping.OpenAlexIdMetadataProcessor">
|
||||||
|
<property name="path" value="/ids/doi"/>
|
||||||
|
<property name="toBeReplaced" value="https://doi.org/"/>
|
||||||
|
<property name="replacement" value=""/>
|
||||||
|
</bean>
|
||||||
|
<bean id="openalex.doi" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.identifier.doi"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openalexPmidContrib" class="org.dspace.importer.external.metadatamapping.contributor.SimpleJsonPathMetadataContributor">
|
||||||
|
<property name="field" ref="openalex.pmid"/>
|
||||||
|
<property name="metadataProcessor" ref="openalexPmidMetadataProcessor"/>
|
||||||
|
</bean>
|
||||||
|
<bean name="openalexPmidMetadataProcessor" class="org.dspace.importer.external.openalex.metadatamapping.OpenAlexIdMetadataProcessor">
|
||||||
|
<property name="path" value="/ids/pmid"/>
|
||||||
|
<property name="toBeReplaced" value="https://pubmed.ncbi.nlm.nih.gov/"/>
|
||||||
|
<property name="replacement" value=""/>
|
||||||
|
</bean>
|
||||||
|
<bean id="openalex.pmid" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.identifier.pmid"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openalexIdContrib" class="org.dspace.importer.external.metadatamapping.contributor.SimpleJsonPathMetadataContributor">
|
||||||
|
<property name="field" ref="openalex.openalexId"/>
|
||||||
|
<property name="metadataProcessor" ref="openalexOpenAlexIdMetadataProcessor"/>
|
||||||
|
</bean>
|
||||||
|
<bean name="openalexOpenAlexIdMetadataProcessor" class="org.dspace.importer.external.openalex.metadatamapping.OpenAlexIdMetadataProcessor">
|
||||||
|
<property name="path" value="/ids/openalex"/>
|
||||||
|
<property name="toBeReplaced" value="https://openalex.org/"/>
|
||||||
|
<property name="replacement" value=""/>
|
||||||
|
</bean>
|
||||||
|
<bean id="openalex.openalexId" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.identifier.other"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openalexMagContrib" class="org.dspace.importer.external.metadatamapping.contributor.SimpleJsonPathMetadataContributor">
|
||||||
|
<property name="field" ref="openalex.mag"/>
|
||||||
|
<property name="query" value="/ids/mag"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="openalex.mag" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.identifier.mag"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openalexAuthorContrib" class="org.dspace.importer.external.metadatamapping.contributor.SimpleJsonPathMetadataContributor">
|
||||||
|
<property name="field" ref="openalex.author"/>
|
||||||
|
<property name="metadataProcessor" ref="openalexAuthorProcessor"/>
|
||||||
|
</bean>
|
||||||
|
<bean name="openalexAuthorProcessor" class="org.dspace.importer.external.metadatamapping.contributor.ArrayElementAttributeProcessor">
|
||||||
|
<property name="pathToArray" value="/authorships"/>
|
||||||
|
<property name="elementAttribute" value="/raw_author_name"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="openalex.author" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.contributor.author"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="openalexLanguageContrib" class="org.dspace.importer.external.metadatamapping.contributor.SimpleJsonPathMetadataContributor">
|
||||||
|
<property name="field" ref="openalex.language"/>
|
||||||
|
<property name="query" value="/language"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="openalex.language" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
|
||||||
|
<constructor-arg value="dc.language.iso"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
</beans>
|
Reference in New Issue
Block a user