Merge pull request #8268 from 4Science/CST-5799

Porting of OrcidPublicationDataProvider
This commit is contained in:
Tim Donohue
2022-06-22 14:38:18 -05:00
committed by GitHub
20 changed files with 1868 additions and 2 deletions

View File

@@ -0,0 +1,547 @@
/**
* 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 static java.util.Collections.emptyList;
import static java.util.Comparator.comparing;
import static java.util.Comparator.reverseOrder;
import static java.util.Optional.ofNullable;
import static org.apache.commons.collections4.ListUtils.partition;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.orcid.jaxb.model.common.CitationType.FORMATTED_UNSPECIFIED;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.dspace.content.Item;
import org.dspace.content.MetadataFieldName;
import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.core.Context;
import org.dspace.external.model.ExternalDataObject;
import org.dspace.external.provider.AbstractExternalDataProvider;
import org.dspace.external.provider.ExternalDataProvider;
import org.dspace.importer.external.datamodel.ImportRecord;
import org.dspace.importer.external.metadatamapping.MetadatumDTO;
import org.dspace.importer.external.service.ImportService;
import org.dspace.orcid.OrcidToken;
import org.dspace.orcid.client.OrcidClient;
import org.dspace.orcid.client.OrcidConfiguration;
import org.dspace.orcid.model.OrcidTokenResponseDTO;
import org.dspace.orcid.model.OrcidWorkFieldMapping;
import org.dspace.orcid.service.OrcidSynchronizationService;
import org.dspace.orcid.service.OrcidTokenService;
import org.dspace.web.ContextUtil;
import org.orcid.jaxb.model.common.ContributorRole;
import org.orcid.jaxb.model.common.WorkType;
import org.orcid.jaxb.model.v3.release.common.Contributor;
import org.orcid.jaxb.model.v3.release.common.ContributorAttributes;
import org.orcid.jaxb.model.v3.release.common.PublicationDate;
import org.orcid.jaxb.model.v3.release.common.Subtitle;
import org.orcid.jaxb.model.v3.release.common.Title;
import org.orcid.jaxb.model.v3.release.record.Citation;
import org.orcid.jaxb.model.v3.release.record.ExternalIDs;
import org.orcid.jaxb.model.v3.release.record.SourceAware;
import org.orcid.jaxb.model.v3.release.record.Work;
import org.orcid.jaxb.model.v3.release.record.WorkBulk;
import org.orcid.jaxb.model.v3.release.record.WorkContributors;
import org.orcid.jaxb.model.v3.release.record.WorkTitle;
import org.orcid.jaxb.model.v3.release.record.summary.WorkGroup;
import org.orcid.jaxb.model.v3.release.record.summary.WorkSummary;
import org.orcid.jaxb.model.v3.release.record.summary.Works;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Implementation of {@link ExternalDataProvider} that search for all the works
* of the profile with the given orcid id that hava a source other than DSpace.
* The id of the external data objects returned by the methods of this class is
* the concatenation of the orcid id and the put code associated with the
* publication, separated by :: (example 0000-0000-0123-4567::123456)
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*
*/
public class OrcidPublicationDataProvider extends AbstractExternalDataProvider {
private final static Logger LOGGER = LoggerFactory.getLogger(OrcidPublicationDataProvider.class);
/**
* Examples of valid ORCID IDs:
* <ul>
* <li>0000-0002-1825-0097</li>
* <li>0000-0001-5109-3700</li>
* <li>0000-0002-1694-233X</li>
* </ul>
*/
private final static Pattern ORCID_ID_PATTERN = Pattern.compile("(\\d{4}-){3}\\d{3}(\\d|X)");
private final static int MAX_PUT_CODES_SIZE = 100;
@Autowired
private OrcidClient orcidClient;
@Autowired
private OrcidConfiguration orcidConfiguration;
@Autowired
private OrcidSynchronizationService orcidSynchronizationService;
@Autowired
private ImportService importService;
@Autowired
private OrcidTokenService orcidTokenService;
private OrcidWorkFieldMapping fieldMapping;
private String sourceIdentifier;
private String readPublicAccessToken;
@Override
public Optional<ExternalDataObject> getExternalDataObject(String id) {
if (isInvalidIdentifier(id)) {
throw new IllegalArgumentException("Invalid identifier '" + id + "', expected <orcid-id>::<put-code>");
}
String[] idSections = id.split("::");
String orcid = idSections[0];
String putCode = idSections[1];
validateOrcidId(orcid);
return getWork(orcid, putCode)
.filter(work -> hasDifferentSourceClientId(work))
.filter(work -> work.getPutCode() != null)
.map(work -> convertToExternalDataObject(orcid, work));
}
@Override
public List<ExternalDataObject> searchExternalDataObjects(String orcid, int start, int limit) {
validateOrcidId(orcid);
return findWorks(orcid, start, limit).stream()
.map(work -> convertToExternalDataObject(orcid, work))
.collect(Collectors.toList());
}
private boolean isInvalidIdentifier(String id) {
return StringUtils.isBlank(id) || id.split("::").length != 2;
}
private void validateOrcidId(String orcid) {
if (!ORCID_ID_PATTERN.matcher(orcid).matches()) {
throw new IllegalArgumentException("The given ORCID ID is not valid: " + orcid);
}
}
/**
* Returns all the works related to the given ORCID in the range from start and
* limit.
*
* @param orcid the ORCID ID of the author to search for works
* @param start the start index
* @param limit the limit index
* @return the list of the works
*/
private List<Work> findWorks(String orcid, int start, int limit) {
List<WorkSummary> workSummaries = findWorkSummaries(orcid, start, limit);
return findWorks(orcid, workSummaries);
}
/**
* Returns all the works summaries related to the given ORCID in the range from
* start and limit.
*
* @param orcid the ORCID ID of the author to search for works summaries
* @param start the start index
* @param limit the limit index
* @return the list of the works summaries
*/
private List<WorkSummary> findWorkSummaries(String orcid, int start, int limit) {
return getWorks(orcid).getWorkGroup().stream()
.filter(workGroup -> allWorkSummariesHaveDifferentSourceClientId(workGroup))
.map(workGroup -> getPreferredWorkSummary(workGroup))
.flatMap(Optional::stream)
.skip(start)
.limit(limit > 0 ? limit : Long.MAX_VALUE)
.collect(Collectors.toList());
}
/**
* Returns all the works related to the given ORCID ID and work summaries (a
* work has more details than a work summary).
*
* @param orcid the ORCID id of the author to search for works
* @param workSummaries the work summaries used to search the related works
* @return the list of the works
*/
private List<Work> findWorks(String orcid, List<WorkSummary> workSummaries) {
List<String> workPutCodes = getPutCodes(workSummaries);
if (CollectionUtils.isEmpty(workPutCodes)) {
return emptyList();
}
if (workPutCodes.size() == 1) {
return getWork(orcid, workPutCodes.get(0)).stream().collect(Collectors.toList());
}
return partition(workPutCodes, MAX_PUT_CODES_SIZE).stream()
.map(putCodes -> getWorkBulk(orcid, putCodes))
.flatMap(workBulk -> getWorks(workBulk).stream())
.collect(Collectors.toList());
}
/**
* Search a work by ORCID id and putcode, using API or PUBLIC urls based on
* whether the ORCID API keys are configured or not.
*
* @param orcid the ORCID ID
* @param putCode the work's identifier on ORCID
* @return the work, if any
*/
private Optional<Work> getWork(String orcid, String putCode) {
if (orcidConfiguration.isApiConfigured()) {
String accessToken = getAccessToken(orcid);
return orcidClient.getObject(accessToken, orcid, putCode, Work.class);
} else {
return orcidClient.getObject(orcid, putCode, Work.class);
}
}
/**
* Returns all the works related to the given ORCID.
*
* @param orcid the ORCID ID of the author to search for works
* @return the list of the works
*/
private Works getWorks(String orcid) {
if (orcidConfiguration.isApiConfigured()) {
String accessToken = getAccessToken(orcid);
return orcidClient.getWorks(accessToken, orcid);
} else {
return orcidClient.getWorks(orcid);
}
}
/**
* Returns all the works related to the given ORCID by the given putCodes.
*
* @param orcid the ORCID ID of the author to search for works
* @param putCodes the work's put codes to search
* @return the list of the works
*/
private WorkBulk getWorkBulk(String orcid, List<String> putCodes) {
if (orcidConfiguration.isApiConfigured()) {
String accessToken = getAccessToken(orcid);
return orcidClient.getWorkBulk(accessToken, orcid, putCodes);
} else {
return orcidClient.getWorkBulk(orcid, putCodes);
}
}
private String getAccessToken(String orcid) {
List<Item> items = orcidSynchronizationService.findProfilesByOrcid(new Context(), orcid);
return Optional.ofNullable(items.isEmpty() ? null : items.get(0))
.flatMap(item -> getAccessToken(item))
.orElseGet(() -> getReadPublicAccessToken());
}
private Optional<String> getAccessToken(Item item) {
return ofNullable(orcidTokenService.findByProfileItem(getContext(), item))
.map(OrcidToken::getAccessToken);
}
private String getReadPublicAccessToken() {
if (readPublicAccessToken != null) {
return readPublicAccessToken;
}
OrcidTokenResponseDTO accessTokenResponse = orcidClient.getReadPublicAccessToken();
readPublicAccessToken = accessTokenResponse.getAccessToken();
return readPublicAccessToken;
}
private List<Work> getWorks(WorkBulk workBulk) {
return workBulk.getBulk().stream()
.filter(bulkElement -> (bulkElement instanceof Work))
.map(bulkElement -> ((Work) bulkElement))
.collect(Collectors.toList());
}
private List<String> getPutCodes(List<WorkSummary> workSummaries) {
return workSummaries.stream()
.map(WorkSummary::getPutCode)
.map(String::valueOf)
.collect(Collectors.toList());
}
private Optional<WorkSummary> getPreferredWorkSummary(WorkGroup workGroup) {
return workGroup.getWorkSummary().stream()
.filter(work -> work.getPutCode() != null)
.filter(work -> NumberUtils.isCreatable(work.getDisplayIndex()))
.sorted(comparing(work -> Integer.valueOf(work.getDisplayIndex()), reverseOrder()))
.findFirst();
}
private ExternalDataObject convertToExternalDataObject(String orcid, Work work) {
ExternalDataObject externalDataObject = new ExternalDataObject(sourceIdentifier);
externalDataObject.setId(orcid + "::" + work.getPutCode().toString());
String title = getWorkTitle(work);
externalDataObject.setDisplayValue(title);
externalDataObject.setValue(title);
addMetadataValue(externalDataObject, fieldMapping.getTitleField(), () -> title);
addMetadataValue(externalDataObject, fieldMapping.getTypeField(), () -> getWorkType(work));
addMetadataValue(externalDataObject, fieldMapping.getPublicationDateField(), () -> getPublicationDate(work));
addMetadataValue(externalDataObject, fieldMapping.getJournalTitleField(), () -> getJournalTitle(work));
addMetadataValue(externalDataObject, fieldMapping.getSubTitleField(), () -> getSubTitleField(work));
addMetadataValue(externalDataObject, fieldMapping.getShortDescriptionField(), () -> getDescription(work));
addMetadataValue(externalDataObject, fieldMapping.getLanguageField(), () -> getLanguage(work));
for (String contributorField : fieldMapping.getContributorFields().keySet()) {
ContributorRole role = fieldMapping.getContributorFields().get(contributorField);
addMetadataValues(externalDataObject, contributorField, () -> getContributors(work, role));
}
for (String externalIdField : fieldMapping.getExternalIdentifierFields().keySet()) {
String type = fieldMapping.getExternalIdentifierFields().get(externalIdField);
addMetadataValues(externalDataObject, externalIdField, () -> getExternalIds(work, type));
}
try {
addMetadataValuesFromCitation(externalDataObject, work.getWorkCitation());
} catch (Exception e) {
LOGGER.error("An error occurs reading the following citation: " + work.getWorkCitation().getCitation(), e);
}
return externalDataObject;
}
private boolean allWorkSummariesHaveDifferentSourceClientId(WorkGroup workGroup) {
return workGroup.getWorkSummary().stream().allMatch(this::hasDifferentSourceClientId);
}
@SuppressWarnings("deprecation")
private boolean hasDifferentSourceClientId(SourceAware sourceAware) {
return Optional.ofNullable(sourceAware.getSource())
.map(source -> source.getSourceClientId())
.map(sourceClientId -> sourceClientId.getPath())
.map(clientId -> !StringUtils.equals(orcidConfiguration.getClientId(), clientId))
.orElse(true);
}
private void addMetadataValues(ExternalDataObject externalData, String metadata, Supplier<List<String>> values) {
if (StringUtils.isBlank(metadata)) {
return;
}
MetadataFieldName field = new MetadataFieldName(metadata);
for (String value : values.get()) {
externalData.addMetadata(new MetadataValueDTO(field.schema, field.element, field.qualifier, null, value));
}
}
private void addMetadataValue(ExternalDataObject externalData, String metadata, Supplier<String> valueSupplier) {
addMetadataValues(externalData, metadata, () -> {
String value = valueSupplier.get();
return isNotBlank(value) ? List.of(value) : emptyList();
});
}
private String getWorkTitle(Work work) {
WorkTitle workTitle = work.getWorkTitle();
if (workTitle == null) {
return null;
}
Title title = workTitle.getTitle();
return title != null ? title.getContent() : null;
}
private String getWorkType(Work work) {
WorkType workType = work.getWorkType();
return workType != null ? fieldMapping.convertType(workType.value()) : null;
}
private String getPublicationDate(Work work) {
PublicationDate publicationDate = work.getPublicationDate();
if (publicationDate == null) {
return null;
}
StringBuilder builder = new StringBuilder(publicationDate.getYear().getValue());
if (publicationDate.getMonth() != null) {
builder.append("-");
builder.append(publicationDate.getMonth().getValue());
}
if (publicationDate.getDay() != null) {
builder.append("-");
builder.append(publicationDate.getDay().getValue());
}
return builder.toString();
}
private String getJournalTitle(Work work) {
Title journalTitle = work.getJournalTitle();
return journalTitle != null ? journalTitle.getContent() : null;
}
private String getSubTitleField(Work work) {
WorkTitle workTitle = work.getWorkTitle();
if (workTitle == null) {
return null;
}
Subtitle subTitle = workTitle.getSubtitle();
return subTitle != null ? subTitle.getContent() : null;
}
private String getDescription(Work work) {
return work.getShortDescription();
}
private String getLanguage(Work work) {
return work.getLanguageCode() != null ? fieldMapping.convertLanguage(work.getLanguageCode()) : null;
}
private List<String> getContributors(Work work, ContributorRole role) {
WorkContributors workContributors = work.getWorkContributors();
if (workContributors == null) {
return emptyList();
}
return workContributors.getContributor().stream()
.filter(contributor -> hasRole(contributor, role))
.map(contributor -> getContributorName(contributor))
.flatMap(Optional::stream)
.collect(Collectors.toList());
}
private void addMetadataValuesFromCitation(ExternalDataObject externalDataObject, Citation citation)
throws Exception {
if (citation == null || citation.getWorkCitationType() == FORMATTED_UNSPECIFIED) {
return;
}
getImportRecord(citation).ifPresent(importRecord -> enrichExternalDataObject(externalDataObject, importRecord));
}
private Optional<ImportRecord> getImportRecord(Citation citation) throws Exception {
File citationFile = File.createTempFile("temp", "." + citation.getWorkCitationType().value());
try (FileOutputStream outputStream = new FileOutputStream(citationFile)) {
IOUtils.write(citation.getCitation(), new FileOutputStream(citationFile), Charset.defaultCharset());
return Optional.ofNullable(importService.getRecord(citationFile, citationFile.getName()));
} finally {
citationFile.delete();
}
}
private void enrichExternalDataObject(ExternalDataObject externalDataObject, ImportRecord importRecord) {
importRecord.getValueList().stream()
.filter(metadata -> doesNotContains(externalDataObject, metadata))
.forEach(metadata -> addMetadata(externalDataObject, metadata));
}
private void addMetadata(ExternalDataObject externalDataObject, MetadatumDTO metadata) {
externalDataObject.addMetadata(new MetadataValueDTO(metadata.getSchema(), metadata.getElement(),
metadata.getQualifier(), null, metadata.getValue()));
}
private boolean doesNotContains(ExternalDataObject externalDataObject, MetadatumDTO metadata) {
return externalDataObject.getMetadata().stream()
.filter(metadataValue -> StringUtils.equals(metadataValue.getSchema(), metadata.getSchema()))
.filter(metadataValue -> StringUtils.equals(metadataValue.getElement(), metadata.getElement()))
.filter(metadataValue -> StringUtils.equals(metadataValue.getQualifier(), metadata.getQualifier()))
.findAny().isEmpty();
}
private boolean hasRole(Contributor contributor, ContributorRole role) {
ContributorAttributes attributes = contributor.getContributorAttributes();
return attributes != null ? role.equals(attributes.getContributorRole()) : false;
}
private Optional<String> getContributorName(Contributor contributor) {
return Optional.ofNullable(contributor.getCreditName())
.map(creditName -> creditName.getContent());
}
private List<String> getExternalIds(Work work, String type) {
ExternalIDs externalIdentifiers = work.getExternalIdentifiers();
if (externalIdentifiers == null) {
return emptyList();
}
return externalIdentifiers.getExternalIdentifier().stream()
.filter(externalId -> type.equals(externalId.getType()))
.map(externalId -> externalId.getValue())
.collect(Collectors.toList());
}
private Context getContext() {
Context context = ContextUtil.obtainCurrentRequestContext();
return context != null ? context : new Context();
}
@Override
public boolean supports(String source) {
return StringUtils.equals(sourceIdentifier, source);
}
@Override
public int getNumberOfResults(String orcid) {
return findWorkSummaries(orcid, 0, -1).size();
}
public void setSourceIdentifier(String sourceIdentifier) {
this.sourceIdentifier = sourceIdentifier;
}
@Override
public String getSourceIdentifier() {
return sourceIdentifier;
}
public void setFieldMapping(OrcidWorkFieldMapping fieldMapping) {
this.fieldMapping = fieldMapping;
}
public void setReadPublicAccessToken(String readPublicAccessToken) {
this.readPublicAccessToken = readPublicAccessToken;
}
public OrcidClient getOrcidClient() {
return orcidClient;
}
public void setOrcidClient(OrcidClient orcidClient) {
this.orcidClient = orcidClient;
}
}

View File

@@ -7,9 +7,14 @@
*/
package org.dspace.orcid.client;
import java.util.List;
import java.util.Optional;
import org.dspace.orcid.exception.OrcidClientException;
import org.dspace.orcid.model.OrcidTokenResponseDTO;
import org.orcid.jaxb.model.v3.release.record.Person;
import org.orcid.jaxb.model.v3.release.record.WorkBulk;
import org.orcid.jaxb.model.v3.release.record.summary.Works;
/**
* Interface for classes that allow to contact ORCID.
@@ -19,6 +24,15 @@ import org.orcid.jaxb.model.v3.release.record.Person;
*/
public interface OrcidClient {
/**
* Retrieves an /read-public access token using a client-credentials OAuth flow,
* or 2-step OAuth.
*
* @return the ORCID token
* @throws OrcidClientException if some error occurs during the exchange
*/
OrcidTokenResponseDTO getReadPublicAccessToken();
/**
* Exchange the authorization code for an ORCID iD and 3-legged access token.
* The authorization code expires upon use.
@@ -39,6 +53,75 @@ public interface OrcidClient {
*/
Person getPerson(String accessToken, String orcid);
/**
* Retrieves all the works related to the given orcid.
*
* @param accessToken the access token
* @param orcid the orcid id related to the works
* @return the Works
* @throws OrcidClientException if some error occurs during the search
*/
Works getWorks(String accessToken, String orcid);
/**
* Retrieves all the works related to the given orcid.
*
* @param orcid the orcid id related to the works
* @return the Works
* @throws OrcidClientException if some error occurs during the search
*/
Works getWorks(String orcid);
/**
* Retrieves all the works with the given putCodes related to the given orcid
*
* @param accessToken the access token
* @param orcid the orcid id
* @param putCodes the putCodes of the works to retrieve
* @return the Works
* @throws OrcidClientException if some error occurs during the search
*/
WorkBulk getWorkBulk(String accessToken, String orcid, List<String> putCodes);
/**
* Retrieves all the works with the given putCodes related to the given orcid
*
* @param orcid the orcid id
* @param putCodes the putCodes of the works to retrieve
* @return the Works
* @throws OrcidClientException if some error occurs during the search
*/
WorkBulk getWorkBulk(String orcid, List<String> putCodes);
/**
* Retrieves an object from ORCID with the given putCode related to the given
* orcid.
*
* @param accessToken the access token
* @param orcid the orcid id
* @param putCode the object's put code
* @param clazz the object's class
* @return the Object, if any
* @throws OrcidClientException if some error occurs during the search
* @throws IllegalArgumentException if the given object class is not an valid
* ORCID object
*/
<T> Optional<T> getObject(String accessToken, String orcid, String putCode, Class<T> clazz);
/**
* Retrieves an object from ORCID with the given putCode related to the given
* orcid using the public API.
*
* @param orcid the orcid id
* @param putCode the object's put code
* @param clazz the object's class
* @return the Object, if any
* @throws OrcidClientException if some error occurs during the search
* @throws IllegalArgumentException if the given object class is not an valid
* ORCID object
*/
<T> Optional<T> getObject(String orcid, String putCode, Class<T> clazz);
/**
* Push the given object to ORCID.
*

View File

@@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
@@ -54,6 +55,8 @@ import org.orcid.jaxb.model.v3.release.record.Person;
import org.orcid.jaxb.model.v3.release.record.PersonExternalIdentifier;
import org.orcid.jaxb.model.v3.release.record.ResearcherUrl;
import org.orcid.jaxb.model.v3.release.record.Work;
import org.orcid.jaxb.model.v3.release.record.WorkBulk;
import org.orcid.jaxb.model.v3.release.record.summary.Works;
/**
* Implementation of {@link OrcidClient}.
@@ -114,6 +117,50 @@ public class OrcidClientImpl implements OrcidClient {
return executeAndUnmarshall(httpUriRequest, false, Person.class);
}
@Override
public Works getWorks(String accessToken, String orcid) {
HttpUriRequest httpUriRequest = buildGetUriRequest(accessToken, "/" + orcid + "/works");
Works works = executeAndUnmarshall(httpUriRequest, true, Works.class);
return works != null ? works : new Works();
}
@Override
public Works getWorks(String orcid) {
HttpUriRequest httpUriRequest = buildGetUriRequestToPublicEndpoint("/" + orcid + "/works");
Works works = executeAndUnmarshall(httpUriRequest, true, Works.class);
return works != null ? works : new Works();
}
@Override
public WorkBulk getWorkBulk(String accessToken, String orcid, List<String> putCodes) {
String putCode = String.join(",", putCodes);
HttpUriRequest httpUriRequest = buildGetUriRequest(accessToken, "/" + orcid + "/works/" + putCode);
WorkBulk workBulk = executeAndUnmarshall(httpUriRequest, true, WorkBulk.class);
return workBulk != null ? workBulk : new WorkBulk();
}
@Override
public WorkBulk getWorkBulk(String orcid, List<String> putCodes) {
String putCode = String.join(",", putCodes);
HttpUriRequest httpUriRequest = buildGetUriRequestToPublicEndpoint("/" + orcid + "/works/" + putCode);
WorkBulk workBulk = executeAndUnmarshall(httpUriRequest, true, WorkBulk.class);
return workBulk != null ? workBulk : new WorkBulk();
}
@Override
public <T> Optional<T> getObject(String accessToken, String orcid, String putCode, Class<T> clazz) {
String path = getOrcidPathFromOrcidObjectType(clazz);
HttpUriRequest httpUriRequest = buildGetUriRequest(accessToken, "/" + orcid + path + "/" + putCode);
return Optional.ofNullable(executeAndUnmarshall(httpUriRequest, true, clazz));
}
@Override
public <T> Optional<T> getObject(String orcid, String putCode, Class<T> clazz) {
String path = getOrcidPathFromOrcidObjectType(clazz);
HttpUriRequest httpUriRequest = buildGetUriRequestToPublicEndpoint("/" + orcid + path + "/" + putCode);
return Optional.ofNullable(executeAndUnmarshall(httpUriRequest, true, clazz));
}
@Override
public OrcidResponse push(String accessToken, String orcid, Object object) {
String path = getOrcidPathFromOrcidObjectType(object.getClass());
@@ -131,6 +178,27 @@ public class OrcidClientImpl implements OrcidClient {
return execute(buildDeleteUriRequest(accessToken, "/" + orcid + path + "/" + putCode), true);
}
@Override
public OrcidTokenResponseDTO getReadPublicAccessToken() {
return getClientCredentialsAccessToken("/read-public");
}
private OrcidTokenResponseDTO getClientCredentialsAccessToken(String scope) {
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("scope", scope));
params.add(new BasicNameValuePair("grant_type", "client_credentials"));
params.add(new BasicNameValuePair("client_id", orcidConfiguration.getClientId()));
params.add(new BasicNameValuePair("client_secret", orcidConfiguration.getClientSecret()));
HttpUriRequest httpUriRequest = RequestBuilder.post(orcidConfiguration.getTokenEndpointUrl())
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("Accept", "application/json")
.setEntity(new UrlEncodedFormEntity(params, Charset.defaultCharset()))
.build();
return executeAndParseJson(httpUriRequest, OrcidTokenResponseDTO.class);
}
private HttpUriRequest buildGetUriRequest(String accessToken, String relativePath) {
return get(orcidConfiguration.getApiUrl() + relativePath.trim())
.addHeader("Content-Type", "application/x-www-form-urlencoded")
@@ -138,6 +206,12 @@ public class OrcidClientImpl implements OrcidClient {
.build();
}
private HttpUriRequest buildGetUriRequestToPublicEndpoint(String relativePath) {
return get(orcidConfiguration.getPublicUrl() + relativePath.trim())
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.build();
}
private HttpUriRequest buildPostUriRequest(String accessToken, String relativePath, Object object) {
return post(orcidConfiguration.getApiUrl() + relativePath.trim())
.addHeader("Content-Type", "application/vnd.orcid+xml")

View File

@@ -107,4 +107,8 @@ public final class OrcidConfiguration {
this.publicUrl = publicUrl;
}
public boolean isApiConfigured() {
return !StringUtils.isAnyBlank(clientId, clientSecret);
}
}

View File

@@ -155,4 +155,13 @@ public interface OrcidSynchronizationService {
* @return the disconnection mode
*/
OrcidProfileDisconnectionMode getDisconnectionMode();
/**
* Returns all the profiles with the given orcid id.
*
* @param context the relevant DSpace Context.
* @param orcid the orcid id to search for
* @return the found profile items
*/
List<Item> findProfilesByOrcid(Context context, String orcid);
}

View File

@@ -30,6 +30,10 @@ import org.dspace.content.Item;
import org.dspace.content.MetadataValue;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.SearchService;
import org.dspace.discovery.SearchServiceException;
import org.dspace.discovery.indexobject.IndexableItem;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.service.EPersonService;
import org.dspace.orcid.OrcidToken;
@@ -62,6 +66,9 @@ public class OrcidSynchronizationServiceImpl implements OrcidSynchronizationServ
@Autowired
private EPersonService ePersonService;
@Autowired
private SearchService searchService;
@Autowired
private OrcidTokenService orcidTokenService;
@@ -306,4 +313,19 @@ public class OrcidSynchronizationServiceImpl implements OrcidSynchronizationServ
throw new RuntimeException(e);
}
}
@Override
public List<Item> findProfilesByOrcid(Context context, String orcid) {
DiscoverQuery discoverQuery = new DiscoverQuery();
discoverQuery.setDSpaceObjectFilter(IndexableItem.TYPE);
discoverQuery.addFilterQueries("search.entitytype:" + researcherProfileService.getProfileType());
discoverQuery.addFilterQueries("person.identifier.orcid:" + orcid);
try {
return searchService.search(context, discoverQuery).getIndexableObjects().stream()
.map(object -> ((IndexableItem) object).getIndexedObject())
.collect(Collectors.toList());
} catch (SearchServiceException ex) {
throw new RuntimeException(ex);
}
}
}

View File

@@ -58,6 +58,16 @@
<constructor-arg value="${orcid.api-url}"/>
</bean>
<bean id="orcidPublicationDataProvider" class="org.dspace.external.provider.impl.OrcidPublicationDataProvider">
<property name="sourceIdentifier" value="orcidWorks"/>
<property name="fieldMapping" ref="orcidPublicationDataProviderFieldMapping"/>
<property name="supportedEntityTypes">
<list>
<value>Publication</value>
</list>
</property>
</bean>
<bean id="pubmedLiveImportDataProvider" class="org.dspace.external.provider.impl.LiveImportDataProvider">
<property name="metadataSource" ref="pubmedImportService"/>
<property name="sourceIdentifier" value="pubmed"/>

View File

@@ -0,0 +1,434 @@
/**
* 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 static java.util.Optional.of;
import static org.dspace.app.matcher.LambdaMatcher.has;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import java.io.File;
import java.net.URL;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import org.apache.commons.codec.binary.StringUtils;
import org.dspace.AbstractIntegrationTestWithDatabase;
import org.dspace.builder.CollectionBuilder;
import org.dspace.builder.CommunityBuilder;
import org.dspace.builder.ItemBuilder;
import org.dspace.builder.OrcidTokenBuilder;
import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.content.MetadataFieldName;
import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.external.model.ExternalDataObject;
import org.dspace.orcid.client.OrcidClient;
import org.dspace.orcid.client.OrcidConfiguration;
import org.dspace.orcid.model.OrcidTokenResponseDTO;
import org.dspace.utils.DSpace;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.orcid.jaxb.model.v3.release.record.Work;
import org.orcid.jaxb.model.v3.release.record.WorkBulk;
import org.orcid.jaxb.model.v3.release.record.summary.Works;
/**
* Integration tests for {@link OrcidPublicationDataProvider}.
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*
*/
public class OrcidPublicationDataProviderIT extends AbstractIntegrationTestWithDatabase {
private static final String BASE_XML_DIR_PATH = "org/dspace/app/orcid-works/";
private static final String ACCESS_TOKEN = "32c83ccb-c6d5-4981-b6ea-6a34a36de8ab";
private static final String ORCID = "0000-1111-2222-3333";
private OrcidPublicationDataProvider dataProvider;
private OrcidConfiguration orcidConfiguration;
private OrcidClient orcidClient;
private OrcidClient orcidClientMock;
private String originalClientId;
private Collection persons;
@Before
public void setup() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
persons = CollectionBuilder.createCollection(context, parentCommunity)
.withEntityType("Person")
.withName("Profiles")
.build();
context.restoreAuthSystemState();
dataProvider = new DSpace().getServiceManager()
.getServiceByName("orcidPublicationDataProvider", OrcidPublicationDataProvider.class);
orcidConfiguration = new DSpace().getServiceManager()
.getServiceByName("org.dspace.orcid.client.OrcidConfiguration", OrcidConfiguration.class);
orcidClientMock = mock(OrcidClient.class);
orcidClient = dataProvider.getOrcidClient();
dataProvider.setReadPublicAccessToken(null);
dataProvider.setOrcidClient(orcidClientMock);
originalClientId = orcidConfiguration.getClientId();
orcidConfiguration.setClientId("DSPACE-CLIENT-ID");
orcidConfiguration.setClientSecret("DSPACE-CLIENT-SECRET");
when(orcidClientMock.getReadPublicAccessToken()).thenReturn(buildTokenResponse(ACCESS_TOKEN));
when(orcidClientMock.getWorks(any(), eq(ORCID))).thenReturn(unmarshall("works.xml", Works.class));
when(orcidClientMock.getWorks(eq(ORCID))).thenReturn(unmarshall("works.xml", Works.class));
when(orcidClientMock.getObject(any(), eq(ORCID), any(), eq(Work.class)))
.then((invocation) -> of(unmarshall("work-" + invocation.getArgument(2) + ".xml", Work.class)));
when(orcidClientMock.getObject(eq(ORCID), any(), eq(Work.class)))
.then((invocation) -> of(unmarshall("work-" + invocation.getArgument(1) + ".xml", Work.class)));
when(orcidClientMock.getWorkBulk(any(), eq(ORCID), any()))
.then((invocation) -> unmarshallWorkBulk(invocation.getArgument(2)));
when(orcidClientMock.getWorkBulk(eq(ORCID), any()))
.then((invocation) -> unmarshallWorkBulk(invocation.getArgument(1)));
}
@After
public void after() {
dataProvider.setOrcidClient(orcidClient);
orcidConfiguration.setClientId(originalClientId);
}
@Test
public void testSearchWithoutPagination() throws Exception {
List<ExternalDataObject> externalObjects = dataProvider.searchExternalDataObjects(ORCID, 0, -1);
assertThat(externalObjects, hasSize(3));
ExternalDataObject firstObject = externalObjects.get(0);
assertThat(firstObject.getDisplayValue(), is("The elements of style and the survey of ophthalmology."));
assertThat(firstObject.getValue(), is("The elements of style and the survey of ophthalmology."));
assertThat(firstObject.getId(), is(ORCID + "::277904"));
assertThat(firstObject.getSource(), is("orcidWorks"));
List<MetadataValueDTO> metadata = firstObject.getMetadata();
assertThat(metadata, hasSize(7));
assertThat(metadata, has(metadata("dc.date.issued", "2011")));
assertThat(metadata, has(metadata("dc.source", "Test Journal")));
assertThat(metadata, has(metadata("dc.language.iso", "it")));
assertThat(metadata, has(metadata("dc.type", "Other")));
assertThat(metadata, has(metadata("dc.identifier.doi", "10.11234.12")));
assertThat(metadata, has(metadata("dc.contributor.author", "Walter White")));
assertThat(metadata, has(metadata("dc.title", "The elements of style and the survey of ophthalmology.")));
ExternalDataObject secondObject = externalObjects.get(1);
assertThat(secondObject.getDisplayValue(), is("Another cautionary tale."));
assertThat(secondObject.getValue(), is("Another cautionary tale."));
assertThat(secondObject.getId(), is(ORCID + "::277902"));
assertThat(secondObject.getSource(), is("orcidWorks"));
metadata = secondObject.getMetadata();
assertThat(metadata, hasSize(8));
assertThat(metadata, has(metadata("dc.date.issued", "2011-05-01")));
assertThat(metadata, has(metadata("dc.description.abstract", "Short description")));
assertThat(metadata, has(metadata("dc.relation.ispartof", "Journal title")));
assertThat(metadata, has(metadata("dc.contributor.author", "Walter White")));
assertThat(metadata, has(metadata("dc.contributor.author", "John White")));
assertThat(metadata, has(metadata("dc.contributor.editor", "Jesse Pinkman")));
assertThat(metadata, has(metadata("dc.title", "Another cautionary tale.")));
assertThat(metadata, has(metadata("dc.type", "Article")));
ExternalDataObject thirdObject = externalObjects.get(2);
assertThat(thirdObject.getDisplayValue(), is("Branch artery occlusion in a young woman."));
assertThat(thirdObject.getValue(), is("Branch artery occlusion in a young woman."));
assertThat(thirdObject.getId(), is(ORCID + "::277871"));
assertThat(thirdObject.getSource(), is("orcidWorks"));
metadata = thirdObject.getMetadata();
assertThat(metadata, hasSize(3));
assertThat(metadata, has(metadata("dc.date.issued", "1985-07-01")));
assertThat(metadata, has(metadata("dc.title", "Branch artery occlusion in a young woman.")));
assertThat(metadata, has(metadata("dc.type", "Article")));
verify(orcidClientMock).getReadPublicAccessToken();
verify(orcidClientMock).getWorks(ACCESS_TOKEN, ORCID);
verify(orcidClientMock).getWorkBulk(ACCESS_TOKEN, ORCID, List.of("277904", "277902", "277871"));
verifyNoMoreInteractions(orcidClientMock);
}
@Test
public void testSearchWithInvalidOrcidId() {
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
() -> dataProvider.searchExternalDataObjects("0000-1111-2222", 0, -1));
assertThat(exception.getMessage(), is("The given ORCID ID is not valid: 0000-1111-2222"));
}
@Test
public void testSearchWithStoredAccessToken() throws Exception {
context.turnOffAuthorisationSystem();
String accessToken = "95cb5ed9-c208-4bbc-bc99-aa0bd76e4452";
Item profile = ItemBuilder.createItem(context, persons)
.withTitle("Profile")
.withOrcidIdentifier(ORCID)
.withDspaceObjectOwner(eperson.getEmail(), eperson.getID().toString())
.build();
OrcidTokenBuilder.create(context, eperson, accessToken)
.withProfileItem(profile)
.build();
context.restoreAuthSystemState();
List<ExternalDataObject> externalObjects = dataProvider.searchExternalDataObjects(ORCID, 0, -1);
assertThat(externalObjects, hasSize(3));
verify(orcidClientMock).getWorks(accessToken, ORCID);
verify(orcidClientMock).getWorkBulk(accessToken, ORCID, List.of("277904", "277902", "277871"));
verifyNoMoreInteractions(orcidClientMock);
}
@Test
public void testSearchWithProfileWithoutAccessToken() throws Exception {
context.turnOffAuthorisationSystem();
ItemBuilder.createItem(context, persons)
.withTitle("Profile")
.withOrcidIdentifier(ORCID)
.build();
context.restoreAuthSystemState();
List<ExternalDataObject> externalObjects = dataProvider.searchExternalDataObjects(ORCID, 0, -1);
assertThat(externalObjects, hasSize(3));
verify(orcidClientMock).getReadPublicAccessToken();
verify(orcidClientMock).getWorks(ACCESS_TOKEN, ORCID);
verify(orcidClientMock).getWorkBulk(ACCESS_TOKEN, ORCID, List.of("277904", "277902", "277871"));
verifyNoMoreInteractions(orcidClientMock);
}
@Test
public void testSearchWithoutResults() throws Exception {
String unknownOrcid = "1111-2222-3333-4444";
when(orcidClientMock.getWorks(ACCESS_TOKEN, unknownOrcid)).thenReturn(new Works());
List<ExternalDataObject> externalObjects = dataProvider.searchExternalDataObjects(unknownOrcid, 0, -1);
assertThat(externalObjects, empty());
verify(orcidClientMock).getReadPublicAccessToken();
verify(orcidClientMock).getWorks(ACCESS_TOKEN, unknownOrcid);
verifyNoMoreInteractions(orcidClientMock);
}
@Test
public void testClientCredentialsTokenCache() throws Exception {
List<ExternalDataObject> externalObjects = dataProvider.searchExternalDataObjects(ORCID, 0, -1);
assertThat(externalObjects, hasSize(3));
verify(orcidClientMock).getReadPublicAccessToken();
externalObjects = dataProvider.searchExternalDataObjects(ORCID, 0, -1);
assertThat(externalObjects, hasSize(3));
verify(orcidClientMock, times(1)).getReadPublicAccessToken();
dataProvider.setReadPublicAccessToken(null);
externalObjects = dataProvider.searchExternalDataObjects(ORCID, 0, -1);
assertThat(externalObjects, hasSize(3));
verify(orcidClientMock, times(2)).getReadPublicAccessToken();
}
@Test
public void testSearchPagination() throws Exception {
List<ExternalDataObject> externalObjects = dataProvider.searchExternalDataObjects(ORCID, 0, -1);
assertThat(externalObjects, hasSize(3));
assertThat(externalObjects, has((externalObject -> externalObject.getId().equals(ORCID + "::277904"))));
assertThat(externalObjects, has((externalObject -> externalObject.getId().equals(ORCID + "::277902"))));
assertThat(externalObjects, has((externalObject -> externalObject.getId().equals(ORCID + "::277871"))));
verify(orcidClientMock).getReadPublicAccessToken();
verify(orcidClientMock).getWorks(ACCESS_TOKEN, ORCID);
verify(orcidClientMock).getWorkBulk(ACCESS_TOKEN, ORCID, List.of("277904", "277902", "277871"));
externalObjects = dataProvider.searchExternalDataObjects(ORCID, 0, 5);
assertThat(externalObjects, hasSize(3));
assertThat(externalObjects, has((externalObject -> externalObject.getId().equals(ORCID + "::277904"))));
assertThat(externalObjects, has((externalObject -> externalObject.getId().equals(ORCID + "::277902"))));
assertThat(externalObjects, has((externalObject -> externalObject.getId().equals(ORCID + "::277871"))));
verify(orcidClientMock, times(2)).getWorks(ACCESS_TOKEN, ORCID);
verify(orcidClientMock, times(2)).getWorkBulk(ACCESS_TOKEN, ORCID, List.of("277904", "277902", "277871"));
externalObjects = dataProvider.searchExternalDataObjects(ORCID, 0, 2);
assertThat(externalObjects, hasSize(2));
assertThat(externalObjects, has((externalObject -> externalObject.getId().equals(ORCID + "::277904"))));
assertThat(externalObjects, has((externalObject -> externalObject.getId().equals(ORCID + "::277902"))));
verify(orcidClientMock, times(3)).getWorks(ACCESS_TOKEN, ORCID);
verify(orcidClientMock).getWorkBulk(ACCESS_TOKEN, ORCID, List.of("277904", "277902"));
externalObjects = dataProvider.searchExternalDataObjects(ORCID, 1, 1);
assertThat(externalObjects, hasSize(1));
assertThat(externalObjects, has((externalObject -> externalObject.getId().equals(ORCID + "::277902"))));
verify(orcidClientMock, times(4)).getWorks(ACCESS_TOKEN, ORCID);
verify(orcidClientMock).getObject(ACCESS_TOKEN, ORCID, "277902", Work.class);
externalObjects = dataProvider.searchExternalDataObjects(ORCID, 2, 1);
assertThat(externalObjects, hasSize(1));
assertThat(externalObjects, has((externalObject -> externalObject.getId().equals(ORCID + "::277871"))));
verify(orcidClientMock, times(5)).getWorks(ACCESS_TOKEN, ORCID);
verify(orcidClientMock).getObject(ACCESS_TOKEN, ORCID, "277871", Work.class);
verifyNoMoreInteractions(orcidClientMock);
}
@Test
public void testGetExternalDataObject() {
Optional<ExternalDataObject> optional = dataProvider.getExternalDataObject(ORCID + "::277902");
assertThat(optional.isPresent(), is(true));
ExternalDataObject externalDataObject = optional.get();
assertThat(externalDataObject.getDisplayValue(), is("Another cautionary tale."));
assertThat(externalDataObject.getValue(), is("Another cautionary tale."));
assertThat(externalDataObject.getId(), is(ORCID + "::277902"));
assertThat(externalDataObject.getSource(), is("orcidWorks"));
List<MetadataValueDTO> metadata = externalDataObject.getMetadata();
assertThat(metadata, hasSize(8));
assertThat(metadata, has(metadata("dc.date.issued", "2011-05-01")));
assertThat(metadata, has(metadata("dc.description.abstract", "Short description")));
assertThat(metadata, has(metadata("dc.relation.ispartof", "Journal title")));
assertThat(metadata, has(metadata("dc.contributor.author", "Walter White")));
assertThat(metadata, has(metadata("dc.contributor.author", "John White")));
assertThat(metadata, has(metadata("dc.contributor.editor", "Jesse Pinkman")));
assertThat(metadata, has(metadata("dc.title", "Another cautionary tale.")));
assertThat(metadata, has(metadata("dc.type", "Article")));
verify(orcidClientMock).getReadPublicAccessToken();
verify(orcidClientMock).getObject(ACCESS_TOKEN, ORCID, "277902", Work.class);
verifyNoMoreInteractions(orcidClientMock);
}
@Test
public void testGetExternalDataObjectWithInvalidOrcidId() {
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
() -> dataProvider.getExternalDataObject("invalid::277902"));
assertThat(exception.getMessage(), is("The given ORCID ID is not valid: invalid" ));
}
@Test
public void testGetExternalDataObjectWithInvalidId() {
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
() -> dataProvider.getExternalDataObject("id"));
assertThat(exception.getMessage(), is("Invalid identifier 'id', expected <orcid-id>::<put-code>"));
}
@Test
public void testSearchWithoutApiKeysConfigured() throws Exception {
context.turnOffAuthorisationSystem();
orcidConfiguration.setClientSecret(null);
ItemBuilder.createItem(context, persons)
.withTitle("Profile")
.withOrcidIdentifier(ORCID)
.build();
context.restoreAuthSystemState();
List<ExternalDataObject> externalObjects = dataProvider.searchExternalDataObjects(ORCID, 0, -1);
assertThat(externalObjects, hasSize(3));
verify(orcidClientMock).getWorks(ORCID);
verify(orcidClientMock).getWorkBulk(ORCID, List.of("277904", "277902", "277871"));
verifyNoMoreInteractions(orcidClientMock);
}
private Predicate<MetadataValueDTO> metadata(String metadataField, String value) {
MetadataFieldName metadataFieldName = new MetadataFieldName(metadataField);
return metadata(metadataFieldName.schema, metadataFieldName.element, metadataFieldName.qualifier, value);
}
private Predicate<MetadataValueDTO> metadata(String schema, String element, String qualifier, String value) {
return dto -> StringUtils.equals(schema, dto.getSchema())
&& StringUtils.equals(element, dto.getElement())
&& StringUtils.equals(qualifier, dto.getQualifier())
&& StringUtils.equals(value, dto.getValue());
}
private OrcidTokenResponseDTO buildTokenResponse(String accessToken) {
OrcidTokenResponseDTO response = new OrcidTokenResponseDTO();
response.setAccessToken(accessToken);
return response;
}
private WorkBulk unmarshallWorkBulk(List<String> putCodes) throws Exception {
return unmarshall("workBulk-" + String.join("-", putCodes) + ".xml", WorkBulk.class);
}
@SuppressWarnings("unchecked")
private <T> T unmarshall(String fileName, Class<T> clazz) throws Exception {
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
URL resource = getClass().getClassLoader().getResource(BASE_XML_DIR_PATH + fileName);
if (resource == null) {
throw new IllegalStateException("No resource found named " + BASE_XML_DIR_PATH + fileName);
}
return (T) unmarshaller.unmarshal(new File(resource.getFile()));
}
}

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<work:work put-code="277871" path="/0000-0001-9227-636X/work/277871" visibility="public" xmlns:internal="http://www.orcid.org/ns/internal" xmlns:education="http://www.orcid.org/ns/education" xmlns:distinction="http://www.orcid.org/ns/distinction" xmlns:deprecated="http://www.orcid.org/ns/deprecated" xmlns:other-name="http://www.orcid.org/ns/other-name" xmlns:membership="http://www.orcid.org/ns/membership" xmlns:error="http://www.orcid.org/ns/error" xmlns:common="http://www.orcid.org/ns/common" xmlns:record="http://www.orcid.org/ns/record" xmlns:personal-details="http://www.orcid.org/ns/personal-details" xmlns:keyword="http://www.orcid.org/ns/keyword" xmlns:email="http://www.orcid.org/ns/email" xmlns:external-identifier="http://www.orcid.org/ns/external-identifier" xmlns:funding="http://www.orcid.org/ns/funding" xmlns:preferences="http://www.orcid.org/ns/preferences" xmlns:address="http://www.orcid.org/ns/address" xmlns:invited-position="http://www.orcid.org/ns/invited-position" xmlns:work="http://www.orcid.org/ns/work" xmlns:history="http://www.orcid.org/ns/history" xmlns:employment="http://www.orcid.org/ns/employment" xmlns:qualification="http://www.orcid.org/ns/qualification" xmlns:service="http://www.orcid.org/ns/service" xmlns:person="http://www.orcid.org/ns/person" xmlns:activities="http://www.orcid.org/ns/activities" xmlns:researcher-url="http://www.orcid.org/ns/researcher-url" xmlns:peer-review="http://www.orcid.org/ns/peer-review" xmlns:bulk="http://www.orcid.org/ns/bulk" xmlns:research-resource="http://www.orcid.org/ns/research-resource">
<common:created-date>2014-01-22T19:11:57.151Z</common:created-date>
<common:last-modified-date>2015-06-19T19:14:25.924Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://sandbox.orcid.org/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-orcid>
<common:source-client-id>
<common:uri>https://sandbox.orcid.org/client/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-client-id>
<common:source-name>BU Profiles to ORCID Integration Site</common:source-name>
</common:source>
<work:title>
<common:title>Branch artery occlusion in a young woman.</common:title>
</work:title>
<work:citation>
<work:citation-type>formatted-unspecified</work:citation-type>
<work:citation-value>Gittinger JW, Miller NR, Keltner JL, Burde RM. Branch artery occlusion in a young woman. Surv Ophthalmol. 1985 Jul-Aug; 30(1):52-8.</work:citation-value>
</work:citation>
<work:type>journal-article</work:type>
<common:publication-date>
<common:year>1985</common:year>
<common:month>07</common:month>
<common:day>01</common:day>
</common:publication-date>
</work:work>

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<work:work put-code="277902" path="/0000-0001-9227-636X/work/277902" visibility="public" xmlns:internal="http://www.orcid.org/ns/internal" xmlns:education="http://www.orcid.org/ns/education" xmlns:distinction="http://www.orcid.org/ns/distinction" xmlns:deprecated="http://www.orcid.org/ns/deprecated" xmlns:other-name="http://www.orcid.org/ns/other-name" xmlns:membership="http://www.orcid.org/ns/membership" xmlns:error="http://www.orcid.org/ns/error" xmlns:common="http://www.orcid.org/ns/common" xmlns:record="http://www.orcid.org/ns/record" xmlns:personal-details="http://www.orcid.org/ns/personal-details" xmlns:keyword="http://www.orcid.org/ns/keyword" xmlns:email="http://www.orcid.org/ns/email" xmlns:external-identifier="http://www.orcid.org/ns/external-identifier" xmlns:funding="http://www.orcid.org/ns/funding" xmlns:preferences="http://www.orcid.org/ns/preferences" xmlns:address="http://www.orcid.org/ns/address" xmlns:invited-position="http://www.orcid.org/ns/invited-position" xmlns:work="http://www.orcid.org/ns/work" xmlns:history="http://www.orcid.org/ns/history" xmlns:employment="http://www.orcid.org/ns/employment" xmlns:qualification="http://www.orcid.org/ns/qualification" xmlns:service="http://www.orcid.org/ns/service" xmlns:person="http://www.orcid.org/ns/person" xmlns:activities="http://www.orcid.org/ns/activities" xmlns:researcher-url="http://www.orcid.org/ns/researcher-url" xmlns:peer-review="http://www.orcid.org/ns/peer-review" xmlns:bulk="http://www.orcid.org/ns/bulk" xmlns:research-resource="http://www.orcid.org/ns/research-resource">
<common:created-date>2014-01-22T19:11:57.159Z</common:created-date>
<common:last-modified-date>2015-06-19T19:14:26.327Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://sandbox.orcid.org/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-orcid>
<common:source-client-id>
<common:uri>https://sandbox.orcid.org/client/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-client-id>
<common:source-name>BU Profiles to ORCID Integration Site</common:source-name>
</common:source>
<work:title>
<common:title>Another cautionary tale.</common:title>
</work:title>
<work:journal-title>Journal title</work:journal-title>
<work:short-description>Short description</work:short-description>
<work:type>journal-article</work:type>
<common:publication-date>
<common:year>2011</common:year>
<common:month>05</common:month>
<common:day>01</common:day>
</common:publication-date>
<work:contributors>
<work:contributor>
<work:credit-name>Walter White</work:credit-name>
<work:contributor-email>walter@test.com</work:contributor-email>
<work:contributor-attributes>
<work:contributor-sequence>first</work:contributor-sequence>
<work:contributor-role>author</work:contributor-role>
</work:contributor-attributes>
</work:contributor>
<work:contributor>
<work:credit-name>John White</work:credit-name>
<work:contributor-email>john@test.com</work:contributor-email>
<work:contributor-attributes>
<work:contributor-sequence>additional</work:contributor-sequence>
<work:contributor-role>author</work:contributor-role>
</work:contributor-attributes>
</work:contributor>
<work:contributor>
<work:credit-name>Jesse Pinkman</work:credit-name>
<work:contributor-attributes>
<work:contributor-sequence>first</work:contributor-sequence>
<work:contributor-role>editor</work:contributor-role>
</work:contributor-attributes>
</work:contributor>
</work:contributors>
</work:work>

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<work:work put-code="277904" path="/0000-0001-9227-636X/work/277904" visibility="public" xmlns:internal="http://www.orcid.org/ns/internal" xmlns:education="http://www.orcid.org/ns/education" xmlns:distinction="http://www.orcid.org/ns/distinction" xmlns:deprecated="http://www.orcid.org/ns/deprecated" xmlns:other-name="http://www.orcid.org/ns/other-name" xmlns:membership="http://www.orcid.org/ns/membership" xmlns:error="http://www.orcid.org/ns/error" xmlns:common="http://www.orcid.org/ns/common" xmlns:record="http://www.orcid.org/ns/record" xmlns:personal-details="http://www.orcid.org/ns/personal-details" xmlns:keyword="http://www.orcid.org/ns/keyword" xmlns:email="http://www.orcid.org/ns/email" xmlns:external-identifier="http://www.orcid.org/ns/external-identifier" xmlns:funding="http://www.orcid.org/ns/funding" xmlns:preferences="http://www.orcid.org/ns/preferences" xmlns:address="http://www.orcid.org/ns/address" xmlns:invited-position="http://www.orcid.org/ns/invited-position" xmlns:work="http://www.orcid.org/ns/work" xmlns:history="http://www.orcid.org/ns/history" xmlns:employment="http://www.orcid.org/ns/employment" xmlns:qualification="http://www.orcid.org/ns/qualification" xmlns:service="http://www.orcid.org/ns/service" xmlns:person="http://www.orcid.org/ns/person" xmlns:activities="http://www.orcid.org/ns/activities" xmlns:researcher-url="http://www.orcid.org/ns/researcher-url" xmlns:peer-review="http://www.orcid.org/ns/peer-review" xmlns:bulk="http://www.orcid.org/ns/bulk" xmlns:research-resource="http://www.orcid.org/ns/research-resource">
<common:created-date>2014-01-22T19:11:57.160Z</common:created-date>
<common:last-modified-date>2015-06-19T19:14:26.350Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://sandbox.orcid.org/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-orcid>
<common:source-client-id>
<common:uri>https://sandbox.orcid.org/client/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-client-id>
<common:source-name>BU Profiles to ORCID Integration Site</common:source-name>
</common:source>
<work:title>
<common:title>The elements of style and the survey of ophthalmology.</common:title>
</work:title>
<work:citation>
<work:citation-type>bibtex</work:citation-type>
<work:citation-value>@article{Test,
doi = {10.11234.12},
year = 2011,
month = {nov},
publisher = {Elsevier {BV}},
volume = {110},
pages = {71--83},
author = {Walter White},
title = {Title from Bibtex: The elements of style and the survey of ophthalmology.},
journal = {Test Journal}
}
</work:citation-value>
</work:citation>
<work:type>invention</work:type>
<common:external-ids>
<common:external-id>
<common:external-id-type>agr</common:external-id-type>
<common:external-id-value>work:external-identifier-id</common:external-id-value>
<common:external-id-url>http://orcid.org</common:external-id-url>
<common:external-id-relationship>version-of</common:external-id-relationship>
</common:external-id>
<common:external-id>
<common:external-id-type>doi</common:external-id-type>
<common:external-id-value>10.11234.12</common:external-id-value>
<common:external-id-url>http://orcid.org</common:external-id-url>
<common:external-id-relationship>self</common:external-id-relationship>
</common:external-id>
</common:external-ids>
<work:contributors>
<work:contributor>
<work:credit-name>Walter White</work:credit-name>
<work:contributor-email>walter@test.com</work:contributor-email>
<work:contributor-attributes>
<work:contributor-sequence>first</work:contributor-sequence>
<work:contributor-role>author</work:contributor-role>
</work:contributor-attributes>
</work:contributor>
</work:contributors>
<common:language-code>it</common:language-code>
</work:work>

View File

@@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bulk:bulk xmlns:internal="http://www.orcid.org/ns/internal" xmlns:education="http://www.orcid.org/ns/education" xmlns:distinction="http://www.orcid.org/ns/distinction" xmlns:deprecated="http://www.orcid.org/ns/deprecated" xmlns:other-name="http://www.orcid.org/ns/other-name" xmlns:membership="http://www.orcid.org/ns/membership" xmlns:error="http://www.orcid.org/ns/error" xmlns:common="http://www.orcid.org/ns/common" xmlns:record="http://www.orcid.org/ns/record" xmlns:personal-details="http://www.orcid.org/ns/personal-details" xmlns:keyword="http://www.orcid.org/ns/keyword" xmlns:email="http://www.orcid.org/ns/email" xmlns:external-identifier="http://www.orcid.org/ns/external-identifier" xmlns:funding="http://www.orcid.org/ns/funding" xmlns:preferences="http://www.orcid.org/ns/preferences" xmlns:address="http://www.orcid.org/ns/address" xmlns:invited-position="http://www.orcid.org/ns/invited-position" xmlns:work="http://www.orcid.org/ns/work" xmlns:history="http://www.orcid.org/ns/history" xmlns:employment="http://www.orcid.org/ns/employment" xmlns:qualification="http://www.orcid.org/ns/qualification" xmlns:service="http://www.orcid.org/ns/service" xmlns:person="http://www.orcid.org/ns/person" xmlns:activities="http://www.orcid.org/ns/activities" xmlns:researcher-url="http://www.orcid.org/ns/researcher-url" xmlns:peer-review="http://www.orcid.org/ns/peer-review" xmlns:bulk="http://www.orcid.org/ns/bulk" xmlns:research-resource="http://www.orcid.org/ns/research-resource">
<work:work put-code="277904" path="/0000-0001-9227-636X/work/277904" visibility="public" xmlns:internal="http://www.orcid.org/ns/internal" xmlns:education="http://www.orcid.org/ns/education" xmlns:distinction="http://www.orcid.org/ns/distinction" xmlns:deprecated="http://www.orcid.org/ns/deprecated" xmlns:other-name="http://www.orcid.org/ns/other-name" xmlns:membership="http://www.orcid.org/ns/membership" xmlns:error="http://www.orcid.org/ns/error" xmlns:common="http://www.orcid.org/ns/common" xmlns:record="http://www.orcid.org/ns/record" xmlns:personal-details="http://www.orcid.org/ns/personal-details" xmlns:keyword="http://www.orcid.org/ns/keyword" xmlns:email="http://www.orcid.org/ns/email" xmlns:external-identifier="http://www.orcid.org/ns/external-identifier" xmlns:funding="http://www.orcid.org/ns/funding" xmlns:preferences="http://www.orcid.org/ns/preferences" xmlns:address="http://www.orcid.org/ns/address" xmlns:invited-position="http://www.orcid.org/ns/invited-position" xmlns:work="http://www.orcid.org/ns/work" xmlns:history="http://www.orcid.org/ns/history" xmlns:employment="http://www.orcid.org/ns/employment" xmlns:qualification="http://www.orcid.org/ns/qualification" xmlns:service="http://www.orcid.org/ns/service" xmlns:person="http://www.orcid.org/ns/person" xmlns:activities="http://www.orcid.org/ns/activities" xmlns:researcher-url="http://www.orcid.org/ns/researcher-url" xmlns:peer-review="http://www.orcid.org/ns/peer-review" xmlns:bulk="http://www.orcid.org/ns/bulk" xmlns:research-resource="http://www.orcid.org/ns/research-resource">
<common:created-date>2014-01-22T19:11:57.160Z</common:created-date>
<common:last-modified-date>2015-06-19T19:14:26.350Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://sandbox.orcid.org/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-orcid>
<common:source-client-id>
<common:uri>https://sandbox.orcid.org/client/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-client-id>
<common:source-name>BU Profiles to ORCID Integration Site</common:source-name>
</common:source>
<work:title>
<common:title>The elements of style and the survey of ophthalmology.</common:title>
</work:title>
<work:citation>
<work:citation-type>bibtex</work:citation-type>
<work:citation-value>@article{Test,
doi = {10.11234.12},
year = 2011,
month = {nov},
publisher = {Elsevier {BV}},
volume = {110},
pages = {71--83},
author = {Walter White},
title = {Title from Bibtex: The elements of style and the survey of ophthalmology.},
journal = {Test Journal}
}
</work:citation-value>
</work:citation>
<work:type>invention</work:type>
<common:external-ids>
<common:external-id>
<common:external-id-type>agr</common:external-id-type>
<common:external-id-value>work:external-identifier-id</common:external-id-value>
<common:external-id-url>http://orcid.org</common:external-id-url>
<common:external-id-relationship>version-of</common:external-id-relationship>
</common:external-id>
<common:external-id>
<common:external-id-type>doi</common:external-id-type>
<common:external-id-value>10.11234.12</common:external-id-value>
<common:external-id-url>http://orcid.org</common:external-id-url>
<common:external-id-relationship>self</common:external-id-relationship>
</common:external-id>
</common:external-ids>
<work:contributors>
<work:contributor>
<work:credit-name>Walter White</work:credit-name>
<work:contributor-email>walter@test.com</work:contributor-email>
<work:contributor-attributes>
<work:contributor-sequence>first</work:contributor-sequence>
<work:contributor-role>author</work:contributor-role>
</work:contributor-attributes>
</work:contributor>
</work:contributors>
<common:language-code>it</common:language-code>
</work:work>
<work:work put-code="277902" path="/0000-0001-9227-636X/work/277902" visibility="public" xmlns:internal="http://www.orcid.org/ns/internal" xmlns:education="http://www.orcid.org/ns/education" xmlns:distinction="http://www.orcid.org/ns/distinction" xmlns:deprecated="http://www.orcid.org/ns/deprecated" xmlns:other-name="http://www.orcid.org/ns/other-name" xmlns:membership="http://www.orcid.org/ns/membership" xmlns:error="http://www.orcid.org/ns/error" xmlns:common="http://www.orcid.org/ns/common" xmlns:record="http://www.orcid.org/ns/record" xmlns:personal-details="http://www.orcid.org/ns/personal-details" xmlns:keyword="http://www.orcid.org/ns/keyword" xmlns:email="http://www.orcid.org/ns/email" xmlns:external-identifier="http://www.orcid.org/ns/external-identifier" xmlns:funding="http://www.orcid.org/ns/funding" xmlns:preferences="http://www.orcid.org/ns/preferences" xmlns:address="http://www.orcid.org/ns/address" xmlns:invited-position="http://www.orcid.org/ns/invited-position" xmlns:work="http://www.orcid.org/ns/work" xmlns:history="http://www.orcid.org/ns/history" xmlns:employment="http://www.orcid.org/ns/employment" xmlns:qualification="http://www.orcid.org/ns/qualification" xmlns:service="http://www.orcid.org/ns/service" xmlns:person="http://www.orcid.org/ns/person" xmlns:activities="http://www.orcid.org/ns/activities" xmlns:researcher-url="http://www.orcid.org/ns/researcher-url" xmlns:peer-review="http://www.orcid.org/ns/peer-review" xmlns:bulk="http://www.orcid.org/ns/bulk" xmlns:research-resource="http://www.orcid.org/ns/research-resource">
<common:created-date>2014-01-22T19:11:57.159Z</common:created-date>
<common:last-modified-date>2015-06-19T19:14:26.327Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://sandbox.orcid.org/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-orcid>
<common:source-client-id>
<common:uri>https://sandbox.orcid.org/client/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-client-id>
<common:source-name>BU Profiles to ORCID Integration Site</common:source-name>
</common:source>
<work:title>
<common:title>Another cautionary tale.</common:title>
</work:title>
<work:journal-title>Journal title</work:journal-title>
<work:short-description>Short description</work:short-description>
<work:type>journal-article</work:type>
<common:publication-date>
<common:year>2011</common:year>
<common:month>05</common:month>
<common:day>01</common:day>
</common:publication-date>
<work:contributors>
<work:contributor>
<work:credit-name>Walter White</work:credit-name>
<work:contributor-email>walter@test.com</work:contributor-email>
<work:contributor-attributes>
<work:contributor-sequence>first</work:contributor-sequence>
<work:contributor-role>author</work:contributor-role>
</work:contributor-attributes>
</work:contributor>
<work:contributor>
<work:credit-name>John White</work:credit-name>
<work:contributor-email>john@test.com</work:contributor-email>
<work:contributor-attributes>
<work:contributor-sequence>additional</work:contributor-sequence>
<work:contributor-role>author</work:contributor-role>
</work:contributor-attributes>
</work:contributor>
<work:contributor>
<work:credit-name>Jesse Pinkman</work:credit-name>
<work:contributor-attributes>
<work:contributor-sequence>first</work:contributor-sequence>
<work:contributor-role>editor</work:contributor-role>
</work:contributor-attributes>
</work:contributor>
</work:contributors>
</work:work>
<work:work put-code="277871" path="/0000-0001-9227-636X/work/277871" visibility="public" xmlns:internal="http://www.orcid.org/ns/internal" xmlns:education="http://www.orcid.org/ns/education" xmlns:distinction="http://www.orcid.org/ns/distinction" xmlns:deprecated="http://www.orcid.org/ns/deprecated" xmlns:other-name="http://www.orcid.org/ns/other-name" xmlns:membership="http://www.orcid.org/ns/membership" xmlns:error="http://www.orcid.org/ns/error" xmlns:common="http://www.orcid.org/ns/common" xmlns:record="http://www.orcid.org/ns/record" xmlns:personal-details="http://www.orcid.org/ns/personal-details" xmlns:keyword="http://www.orcid.org/ns/keyword" xmlns:email="http://www.orcid.org/ns/email" xmlns:external-identifier="http://www.orcid.org/ns/external-identifier" xmlns:funding="http://www.orcid.org/ns/funding" xmlns:preferences="http://www.orcid.org/ns/preferences" xmlns:address="http://www.orcid.org/ns/address" xmlns:invited-position="http://www.orcid.org/ns/invited-position" xmlns:work="http://www.orcid.org/ns/work" xmlns:history="http://www.orcid.org/ns/history" xmlns:employment="http://www.orcid.org/ns/employment" xmlns:qualification="http://www.orcid.org/ns/qualification" xmlns:service="http://www.orcid.org/ns/service" xmlns:person="http://www.orcid.org/ns/person" xmlns:activities="http://www.orcid.org/ns/activities" xmlns:researcher-url="http://www.orcid.org/ns/researcher-url" xmlns:peer-review="http://www.orcid.org/ns/peer-review" xmlns:bulk="http://www.orcid.org/ns/bulk" xmlns:research-resource="http://www.orcid.org/ns/research-resource">
<common:created-date>2014-01-22T19:11:57.151Z</common:created-date>
<common:last-modified-date>2015-06-19T19:14:25.924Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://sandbox.orcid.org/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-orcid>
<common:source-client-id>
<common:uri>https://sandbox.orcid.org/client/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-client-id>
<common:source-name>BU Profiles to ORCID Integration Site</common:source-name>
</common:source>
<work:title>
<common:title>Branch artery occlusion in a young woman.</common:title>
</work:title>
<work:citation>
<work:citation-type>formatted-unspecified</work:citation-type>
<work:citation-value>Gittinger JW, Miller NR, Keltner JL, Burde RM. Branch artery occlusion in a young woman. Surv Ophthalmol. 1985 Jul-Aug; 30(1):52-8.</work:citation-value>
</work:citation>
<work:type>journal-article</work:type>
<common:publication-date>
<common:year>1985</common:year>
<common:month>07</common:month>
<common:day>01</common:day>
</common:publication-date>
</work:work>
</bulk:bulk>

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bulk:bulk xmlns:internal="http://www.orcid.org/ns/internal" xmlns:education="http://www.orcid.org/ns/education" xmlns:distinction="http://www.orcid.org/ns/distinction" xmlns:deprecated="http://www.orcid.org/ns/deprecated" xmlns:other-name="http://www.orcid.org/ns/other-name" xmlns:membership="http://www.orcid.org/ns/membership" xmlns:error="http://www.orcid.org/ns/error" xmlns:common="http://www.orcid.org/ns/common" xmlns:record="http://www.orcid.org/ns/record" xmlns:personal-details="http://www.orcid.org/ns/personal-details" xmlns:keyword="http://www.orcid.org/ns/keyword" xmlns:email="http://www.orcid.org/ns/email" xmlns:external-identifier="http://www.orcid.org/ns/external-identifier" xmlns:funding="http://www.orcid.org/ns/funding" xmlns:preferences="http://www.orcid.org/ns/preferences" xmlns:address="http://www.orcid.org/ns/address" xmlns:invited-position="http://www.orcid.org/ns/invited-position" xmlns:work="http://www.orcid.org/ns/work" xmlns:history="http://www.orcid.org/ns/history" xmlns:employment="http://www.orcid.org/ns/employment" xmlns:qualification="http://www.orcid.org/ns/qualification" xmlns:service="http://www.orcid.org/ns/service" xmlns:person="http://www.orcid.org/ns/person" xmlns:activities="http://www.orcid.org/ns/activities" xmlns:researcher-url="http://www.orcid.org/ns/researcher-url" xmlns:peer-review="http://www.orcid.org/ns/peer-review" xmlns:bulk="http://www.orcid.org/ns/bulk" xmlns:research-resource="http://www.orcid.org/ns/research-resource">
<work:work put-code="277904" path="/0000-0001-9227-636X/work/277904" visibility="public" xmlns:internal="http://www.orcid.org/ns/internal" xmlns:education="http://www.orcid.org/ns/education" xmlns:distinction="http://www.orcid.org/ns/distinction" xmlns:deprecated="http://www.orcid.org/ns/deprecated" xmlns:other-name="http://www.orcid.org/ns/other-name" xmlns:membership="http://www.orcid.org/ns/membership" xmlns:error="http://www.orcid.org/ns/error" xmlns:common="http://www.orcid.org/ns/common" xmlns:record="http://www.orcid.org/ns/record" xmlns:personal-details="http://www.orcid.org/ns/personal-details" xmlns:keyword="http://www.orcid.org/ns/keyword" xmlns:email="http://www.orcid.org/ns/email" xmlns:external-identifier="http://www.orcid.org/ns/external-identifier" xmlns:funding="http://www.orcid.org/ns/funding" xmlns:preferences="http://www.orcid.org/ns/preferences" xmlns:address="http://www.orcid.org/ns/address" xmlns:invited-position="http://www.orcid.org/ns/invited-position" xmlns:work="http://www.orcid.org/ns/work" xmlns:history="http://www.orcid.org/ns/history" xmlns:employment="http://www.orcid.org/ns/employment" xmlns:qualification="http://www.orcid.org/ns/qualification" xmlns:service="http://www.orcid.org/ns/service" xmlns:person="http://www.orcid.org/ns/person" xmlns:activities="http://www.orcid.org/ns/activities" xmlns:researcher-url="http://www.orcid.org/ns/researcher-url" xmlns:peer-review="http://www.orcid.org/ns/peer-review" xmlns:bulk="http://www.orcid.org/ns/bulk" xmlns:research-resource="http://www.orcid.org/ns/research-resource">
<common:created-date>2014-01-22T19:11:57.160Z</common:created-date>
<common:last-modified-date>2015-06-19T19:14:26.350Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://sandbox.orcid.org/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-orcid>
<common:source-client-id>
<common:uri>https://sandbox.orcid.org/client/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-client-id>
<common:source-name>BU Profiles to ORCID Integration Site</common:source-name>
</common:source>
<work:title>
<common:title>The elements of style and the survey of ophthalmology.</common:title>
</work:title>
<work:citation>
<work:citation-type>bibtex</work:citation-type>
<work:citation-value>@article{Test,
doi = {10.11234.12},
year = 2011,
month = {nov},
publisher = {Elsevier {BV}},
volume = {110},
pages = {71--83},
author = {Walter White},
title = {Title from Bibtex: The elements of style and the survey of ophthalmology.},
journal = {Test Journal}
}
</work:citation-value>
</work:citation>
<work:type>invention</work:type>
<common:external-ids>
<common:external-id>
<common:external-id-type>agr</common:external-id-type>
<common:external-id-value>work:external-identifier-id</common:external-id-value>
<common:external-id-url>http://orcid.org</common:external-id-url>
<common:external-id-relationship>version-of</common:external-id-relationship>
</common:external-id>
<common:external-id>
<common:external-id-type>doi</common:external-id-type>
<common:external-id-value>10.11234.12</common:external-id-value>
<common:external-id-url>http://orcid.org</common:external-id-url>
<common:external-id-relationship>self</common:external-id-relationship>
</common:external-id>
</common:external-ids>
<work:contributors>
<work:contributor>
<work:credit-name>Walter White</work:credit-name>
<work:contributor-email>walter@test.com</work:contributor-email>
<work:contributor-attributes>
<work:contributor-sequence>first</work:contributor-sequence>
<work:contributor-role>author</work:contributor-role>
</work:contributor-attributes>
</work:contributor>
</work:contributors>
<common:language-code>it</common:language-code>
</work:work>
<work:work put-code="277902" path="/0000-0001-9227-636X/work/277902" visibility="public" xmlns:internal="http://www.orcid.org/ns/internal" xmlns:education="http://www.orcid.org/ns/education" xmlns:distinction="http://www.orcid.org/ns/distinction" xmlns:deprecated="http://www.orcid.org/ns/deprecated" xmlns:other-name="http://www.orcid.org/ns/other-name" xmlns:membership="http://www.orcid.org/ns/membership" xmlns:error="http://www.orcid.org/ns/error" xmlns:common="http://www.orcid.org/ns/common" xmlns:record="http://www.orcid.org/ns/record" xmlns:personal-details="http://www.orcid.org/ns/personal-details" xmlns:keyword="http://www.orcid.org/ns/keyword" xmlns:email="http://www.orcid.org/ns/email" xmlns:external-identifier="http://www.orcid.org/ns/external-identifier" xmlns:funding="http://www.orcid.org/ns/funding" xmlns:preferences="http://www.orcid.org/ns/preferences" xmlns:address="http://www.orcid.org/ns/address" xmlns:invited-position="http://www.orcid.org/ns/invited-position" xmlns:work="http://www.orcid.org/ns/work" xmlns:history="http://www.orcid.org/ns/history" xmlns:employment="http://www.orcid.org/ns/employment" xmlns:qualification="http://www.orcid.org/ns/qualification" xmlns:service="http://www.orcid.org/ns/service" xmlns:person="http://www.orcid.org/ns/person" xmlns:activities="http://www.orcid.org/ns/activities" xmlns:researcher-url="http://www.orcid.org/ns/researcher-url" xmlns:peer-review="http://www.orcid.org/ns/peer-review" xmlns:bulk="http://www.orcid.org/ns/bulk" xmlns:research-resource="http://www.orcid.org/ns/research-resource">
<common:created-date>2014-01-22T19:11:57.159Z</common:created-date>
<common:last-modified-date>2015-06-19T19:14:26.327Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://sandbox.orcid.org/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-orcid>
<common:source-client-id>
<common:uri>https://sandbox.orcid.org/client/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-client-id>
<common:source-name>BU Profiles to ORCID Integration Site</common:source-name>
</common:source>
<work:title>
<common:title>Another cautionary tale.</common:title>
</work:title>
<work:journal-title>Journal title</work:journal-title>
<work:short-description>Short description</work:short-description>
<work:type>journal-article</work:type>
<common:publication-date>
<common:year>2011</common:year>
<common:month>05</common:month>
<common:day>01</common:day>
</common:publication-date>
<work:contributors>
<work:contributor>
<work:credit-name>Walter White</work:credit-name>
<work:contributor-email>walter@test.com</work:contributor-email>
<work:contributor-attributes>
<work:contributor-sequence>first</work:contributor-sequence>
<work:contributor-role>author</work:contributor-role>
</work:contributor-attributes>
</work:contributor>
<work:contributor>
<work:credit-name>John White</work:credit-name>
<work:contributor-email>john@test.com</work:contributor-email>
<work:contributor-attributes>
<work:contributor-sequence>additional</work:contributor-sequence>
<work:contributor-role>author</work:contributor-role>
</work:contributor-attributes>
</work:contributor>
<work:contributor>
<work:credit-name>Jesse Pinkman</work:credit-name>
<work:contributor-attributes>
<work:contributor-sequence>first</work:contributor-sequence>
<work:contributor-role>editor</work:contributor-role>
</work:contributor-attributes>
</work:contributor>
</work:contributors>
</work:work>
</bulk:bulk>

View File

@@ -0,0 +1,196 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<activities:works path="/0000-0001-9227-636X/works" xmlns:internal="http://www.orcid.org/ns/internal" xmlns:education="http://www.orcid.org/ns/education" xmlns:distinction="http://www.orcid.org/ns/distinction" xmlns:deprecated="http://www.orcid.org/ns/deprecated" xmlns:other-name="http://www.orcid.org/ns/other-name" xmlns:membership="http://www.orcid.org/ns/membership" xmlns:error="http://www.orcid.org/ns/error" xmlns:common="http://www.orcid.org/ns/common" xmlns:record="http://www.orcid.org/ns/record" xmlns:personal-details="http://www.orcid.org/ns/personal-details" xmlns:keyword="http://www.orcid.org/ns/keyword" xmlns:email="http://www.orcid.org/ns/email" xmlns:external-identifier="http://www.orcid.org/ns/external-identifier" xmlns:funding="http://www.orcid.org/ns/funding" xmlns:preferences="http://www.orcid.org/ns/preferences" xmlns:address="http://www.orcid.org/ns/address" xmlns:invited-position="http://www.orcid.org/ns/invited-position" xmlns:work="http://www.orcid.org/ns/work" xmlns:history="http://www.orcid.org/ns/history" xmlns:employment="http://www.orcid.org/ns/employment" xmlns:qualification="http://www.orcid.org/ns/qualification" xmlns:service="http://www.orcid.org/ns/service" xmlns:person="http://www.orcid.org/ns/person" xmlns:activities="http://www.orcid.org/ns/activities" xmlns:researcher-url="http://www.orcid.org/ns/researcher-url" xmlns:peer-review="http://www.orcid.org/ns/peer-review" xmlns:bulk="http://www.orcid.org/ns/bulk" xmlns:research-resource="http://www.orcid.org/ns/research-resource">
<common:last-modified-date>2015-06-19T19:14:26.350Z</common:last-modified-date>
<activities:group>
<common:last-modified-date>2015-06-19T19:14:26.350Z</common:last-modified-date>
<common:external-ids/>
<work:work-summary put-code="277904" path="/0000-0001-9227-636X/work/277904" visibility="public" display-index="0">
<common:created-date>2014-01-22T19:11:57.160Z</common:created-date>
<common:last-modified-date>2015-06-19T19:14:26.350Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://sandbox.orcid.org/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-orcid>
<common:source-client-id>
<common:uri>https://sandbox.orcid.org/client/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-client-id>
<common:source-name>BU Profiles to ORCID Integration Site</common:source-name>
</common:source>
<work:title>
<common:title>The elements of style and the survey of ophthalmology.</common:title>
</work:title>
<work:type>invention</work:type>
<common:publication-date>
<common:year>2012</common:year>
<common:month>11</common:month>
<common:day>01</common:day>
</common:publication-date>
</work:work-summary>
</activities:group>
<activities:group>
<common:last-modified-date>2015-06-19T19:14:26.339Z</common:last-modified-date>
<common:external-ids/>
<work:work-summary put-code="277903" path="/0000-0001-9227-636X/work/277903" visibility="public" display-index="0">
<common:created-date>2014-01-22T19:11:57.159Z</common:created-date>
<common:last-modified-date>2015-06-19T19:14:26.339Z</common:last-modified-date>
<common:source>
<common:source-client-id>
<common:uri>https://sandbox.orcid.org/client/DSPACE-CLIENT-ID</common:uri>
<common:path>DSPACE-CLIENT-ID</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-client-id>
<common:source-name>DSPACE-CRIS</common:source-name>
</common:source>
<work:title>
<common:title>Introduction.</common:title>
</work:title>
<work:type>journal-article</work:type>
<common:publication-date>
<common:year>2011</common:year>
<common:month>11</common:month>
<common:day>01</common:day>
</common:publication-date>
</work:work-summary>
</activities:group>
<activities:group>
<common:last-modified-date>2015-06-19T19:14:26.327Z</common:last-modified-date>
<common:external-ids/>
<work:work-summary put-code="277902" path="/0000-0001-9227-636X/work/277902" visibility="public" display-index="1">
<common:created-date>2014-01-22T19:11:57.159Z</common:created-date>
<common:last-modified-date>2015-06-19T19:14:26.327Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://sandbox.orcid.org/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-orcid>
<common:source-client-id>
<common:uri>https://sandbox.orcid.org/client/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-client-id>
<common:source-name>BU Profiles to ORCID Integration Site</common:source-name>
</common:source>
<work:title>
<common:title>Another cautionary tale.</common:title>
</work:title>
<work:type>journal-article</work:type>
<common:publication-date>
<common:year>2011</common:year>
<common:month>05</common:month>
<common:day>01</common:day>
</common:publication-date>
</work:work-summary>
<work:work-summary put-code="287902" path="/0000-0001-9227-636X/work/277902" visibility="public" display-index="0">
<common:created-date>2014-01-22T19:11:57.159Z</common:created-date>
<common:last-modified-date>2015-06-19T19:14:26.327Z</common:last-modified-date>
<common:source>
<common:source-client-id>
<common:uri>https://sandbox.orcid.org/client/4Science</common:uri>
<common:path>4Science</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-client-id>
<common:source-name>BU Profiles to ORCID Integration Site</common:source-name>
</common:source>
<work:title>
<common:title>Another cautionary tale (4Science).</common:title>
</work:title>
<work:type>journal-article</work:type>
<common:publication-date>
<common:year>2011</common:year>
<common:month>05</common:month>
<common:day>01</common:day>
</common:publication-date>
</work:work-summary>
</activities:group>
<activities:group>
<common:last-modified-date>2015-06-19T19:14:26.108Z</common:last-modified-date>
<common:external-ids/>
<work:work-summary put-code="277885" path="/0000-0001-9227-636X/work/277885" visibility="public" display-index="0">
<common:created-date>2014-01-22T19:11:57.155Z</common:created-date>
<common:last-modified-date>2015-06-19T19:14:26.108Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://sandbox.orcid.org/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-orcid>
<common:source-client-id>
<common:uri>https://sandbox.orcid.org/client/DSPACE-CLIENT-ID</common:uri>
<common:path>DSPACE-CLIENT-ID</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-client-id>
<common:source-name>DSPACE-CRIS</common:source-name>
</common:source>
<work:title>
<common:title>Functional hemianopsia: a historical perspective.</common:title>
</work:title>
<work:type>journal-article</work:type>
<common:publication-date>
<common:year>1988</common:year>
<common:month>05</common:month>
<common:day>01</common:day>
</common:publication-date>
</work:work-summary>
<work:work-summary put-code="277971" path="/0000-0001-9227-636X/work/277871" visibility="public" display-index="0">
<common:created-date>2014-01-22T19:11:57.151Z</common:created-date>
<common:last-modified-date>2015-06-19T19:14:25.924Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://sandbox.orcid.org/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-orcid>
<common:source-client-id>
<common:uri>https://sandbox.orcid.org/client/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-client-id>
<common:source-name>BU Profiles to ORCID Integration Site</common:source-name>
</common:source>
<work:title>
<common:title>Branch artery occlusion in a young man.</common:title>
</work:title>
<work:type>journal-article</work:type>
<common:publication-date>
<common:year>1985</common:year>
<common:month>07</common:month>
<common:day>01</common:day>
</common:publication-date>
</work:work-summary>
</activities:group>
<activities:group>
<common:last-modified-date>2015-06-19T19:14:26.108Z</common:last-modified-date>
<common:external-ids/>
<work:work-summary put-code="277871" path="/0000-0001-9227-636X/work/277871" visibility="public" display-index="0">
<common:created-date>2014-01-22T19:11:57.151Z</common:created-date>
<common:last-modified-date>2015-06-19T19:14:25.924Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://sandbox.orcid.org/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-orcid>
<common:source-client-id>
<common:uri>https://sandbox.orcid.org/client/0000-0002-4105-0763</common:uri>
<common:path>0000-0002-4105-0763</common:path>
<common:host>sandbox.orcid.org</common:host>
</common:source-client-id>
<common:source-name>BU Profiles to ORCID Integration Site</common:source-name>
</common:source>
<work:title>
<common:title>Branch artery occlusion in a young woman.</common:title>
</work:title>
<work:type>journal-article</work:type>
<common:publication-date>
<common:year>1985</common:year>
<common:month>07</common:month>
<common:day>01</common:day>
</common:publication-date>
</work:work-summary>
</activities:group>
</activities:works>

View File

@@ -53,7 +53,7 @@ public class ExternalSourcesRestControllerIT extends AbstractControllerIntegrati
ExternalSourceMatcher.matchExternalSource(
"openAIREFunding", "openAIREFunding", false)
)))
.andExpect(jsonPath("$.page.totalElements", Matchers.is(8)));
.andExpect(jsonPath("$.page.totalElements", Matchers.is(9)));
}
@Test

View File

@@ -0,0 +1 @@
# Mapping between languages supported by ORCID and the DSpace common iso languages

View File

@@ -0,0 +1,12 @@
# Mapping between work type supported by ORCID and the DSpace common publication's types
website = Other
data-set = Dataset
book = Book
book-chapter = Book chapter
conference-paper = Other
journal-article = Article
newspaper-article = Article
magazine-article = Article
patent = Other
report = Other
book-review = Other

View File

@@ -135,3 +135,30 @@ orcid.validation.organization.identifier-sources = LEI
## Configuration for max attempts during ORCID batch synchronization
orcid.bulk-synchronization.max-attempts = 5
#------------------------------------------------------------------#
#--------------------ORCID EXTERNAL DATA MAPPING-------------------#
#------------------------------------------------------------------#
### Work (Publication) external-data.mapping ###
orcid.external-data.mapping.publication.title = dc.title
orcid.external-data.mapping.publication.description = dc.description.abstract
orcid.external-data.mapping.publication.issued-date = dc.date.issued
orcid.external-data.mapping.publication.language = dc.language.iso
orcid.external-data.mapping.publication.language.converter = mapConverterOrcidToDSpaceLanguageCode
orcid.external-data.mapping.publication.is-part-of = dc.relation.ispartof
orcid.external-data.mapping.publication.type = dc.type
orcid.external-data.mapping.publication.type.converter = mapConverterOrcidToDSpacePublicationType
##orcid.external-data.mapping.publication.contributors syntax is <metadatafield>::<role>
orcid.external-data.mapping.publication.contributors = dc.contributor.author::author
orcid.external-data.mapping.publication.contributors = dc.contributor.editor::editor
##orcid.external-data.mapping.publication.external-ids syntax is <metadatafield>::<type> or $simple-handle::<type>
##The full list of available external identifiers is available here https://pub.orcid.org/v3.0/identifiers
orcid.external-data.mapping.publication.external-ids = dc.identifier.doi::doi
orcid.external-data.mapping.publication.external-ids = dc.identifier.scopus::eid
orcid.external-data.mapping.publication.external-ids = dc.identifier.pmid::pmid
orcid.external-data.mapping.publication.external-ids = dc.identifier.isi::wosuid
orcid.external-data.mapping.publication.external-ids = dc.identifier.issn::issn

View File

@@ -94,6 +94,16 @@
</property>
</bean>
<bean id="orcidPublicationDataProvider" class="org.dspace.external.provider.impl.OrcidPublicationDataProvider">
<property name="sourceIdentifier" value="orcidWorks"/>
<property name="fieldMapping" ref="orcidPublicationDataProviderFieldMapping"/>
<property name="supportedEntityTypes">
<list>
<value>Publication</value>
</list>
</property>
</bean>
<bean id="crossRefLiveImportDataProvider" class="org.dspace.external.provider.impl.LiveImportDataProvider">
<property name="metadataSource" ref="CrossRefImportService"/>
<property name="sourceIdentifier" value="crossref"/>

View File

@@ -147,10 +147,36 @@
<property name="defaultValue" value=""/>
</bean>
<bean id="orcidPublicationDataProviderFieldMapping" class="org.dspace.orcid.model.OrcidWorkFieldMapping" >
<property name="contributorFields" value="${orcid.external-data.mapping.publication.contributors}" />
<property name="externalIdentifierFields" value="${orcid.external-data.mapping.publication.external-ids}" />
<property name="publicationDateField" value="${orcid.external-data.mapping.publication.issued-date}" />
<property name="titleField" value="${orcid.external-data.mapping.publication.title}" />
<property name="journalTitleField" value="${orcid.external-data.mapping.publication.is-part-of}" />
<property name="shortDescriptionField" value="${orcid.external-data.mapping.publication.description}" />
<property name="languageField" value="${orcid.external-data.mapping.publication.language}" />
<property name="languageConverter" ref="${orcid.external-data.mapping.publication.language.converter}" />
<property name="typeField" value="${orcid.external-data.mapping.publication.type}" />
<property name="typeConverter" ref="${orcid.external-data.mapping.publication.type.converter}" />
</bean>
<bean name="mapConverterDSpaceToOrcidAmountCurrency" class="org.dspace.util.SimpleMapConverter" init-method="init">
<property name="converterNameFile" value="orcid/mapConverter-dspace-to-orcid-amount-currency.properties" />
<property name="configurationService" ref="org.dspace.services.ConfigurationService" />
<property name="defaultValue" value=""/>
</bean>
<bean name="mapConverterOrcidToDSpacePublicationType" class="org.dspace.util.SimpleMapConverter" init-method="init">
<property name="converterNameFile" value="orcid/mapConverter-orcid-to-dspace-publication-type.properties" />
<property name="configurationService" ref="org.dspace.services.ConfigurationService" />
<property name="defaultValue" value="Other"/>
</bean>
<bean name="mapConverterOrcidToDSpaceLanguageCode" class="org.dspace.util.SimpleMapConverter" init-method="init">
<property name="converterNameFile" value="orcid/mapConverter-orcid-to-dspace-language-code.properties" />
<property name="configurationService" ref="org.dspace.services.ConfigurationService" />
<property name="defaultValue" value=""/>
</bean>
</beans>