Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for deposit to the DSpace REST API #135

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ protected List<DepositFileResource> resolveCustodialResources(List<DepositFile>
} else if (Objects.nonNull(dfr.getDepositFile().getPassFileId())) {
String passFileId = dfr.getDepositFile().getPassFileId();
LOG.trace("Returning PassFileResource for Pass File {}", passFileId);
delegateResource = new PassFileResource(passClient, passFileId);
delegateResource = new PassFileResource(passClient, passFileId, dfr.getDepositFile().getName());
} else if (location.startsWith(HTTP_PREFIX) || location.startsWith(HTTPS_PREFIX) ||
location.startsWith(JAR_PREFIX)) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ public class PassFileResource extends AbstractResource {

private final PassClient passClient;
private final String passFileId;
private final String filename;

public PassFileResource(PassClient passClient, String passFileId) {
public PassFileResource(PassClient passClient, String passFileId, String filename) {
this.passClient = passClient;
this.passFileId = passFileId;
this.filename = filename;
}

@Override
Expand All @@ -54,4 +56,9 @@ public String getContentAsString(Charset charset) throws IOException {
public String getDescription() {
return "PassFileResource File ID: " + passFileId;
}

@Override
public String getFilename() {
return filename;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@

import java.net.URI;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -73,8 +73,8 @@ public class DepositSubmissionMapper {
private static final String AUTHORS_KEY = "authors";
private static final String AUTHOR_KEY = "author";
private static final String PUB_TYPE_KEY = "pubType";
private static final String EMBARGO_END_DATE_PATTERN = "yyyy-MM-dd";
private static final String NLMTA_KEY = "journal-NLMTA-ID";
private static final String DEFAULT_DATE_TIME_ZONE = "America/New_York";

/**
* Creates a DepositSubmission by walking the tree of PassEntity objects, starting with the Submission entity,
Expand Down Expand Up @@ -267,7 +267,7 @@ private void processCommonMetadata(DepositMetadata metadata, JsonObject submissi
.ifPresent(pName -> metadata.getJournalMetadata().setPublisherName(pName));

getStringProperty(submissionData, PUBLICATION_DATE_KEY)
.ifPresent(pName -> metadata.getJournalMetadata().setPublicationDate(pName));
.ifPresent(date -> metadata.getJournalMetadata().setPublicationDate(parseDate(date)));

getArrayProperty(submissionData, ISSNS).ifPresent(issns -> {
issns.forEach(issnObjAsStr -> {
Expand All @@ -290,19 +290,29 @@ private void processCommonMetadata(DepositMetadata metadata, JsonObject submissi

getStringProperty(submissionData, EMBARGO_END_DATE_KEY).ifPresent(endDate -> {
try {
// TODO - Resolve inconsistent date/date-time formats in metadata and deposit data model
// TODO - Fix assumption of local timezone
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(EMBARGO_END_DATE_PATTERN);
LocalDateTime localEndDate = LocalDate.parse(endDate, formatter).atStartOfDay();
ZonedDateTime zonedEndDate = localEndDate.atZone(ZoneId.of("America/New_York"));
metadata.getArticleMetadata().setEmbargoLiftDate(zonedEndDate);
} catch (Exception e) {
metadata.getArticleMetadata().setEmbargoLiftDate(parseDate(endDate));
} catch (DateTimeParseException e) {
throw new DepositServiceRuntimeException(
String.format("Data file contained an invalid Date: '%s'.", endDate), e);
String.format("Data file contained an invalid Date: '%s'.", endDate), e);
}
});
}

// Parse an ISO 8601 date with or without a time zone
public ZonedDateTime parseDate(String date) {
try {
return ZonedDateTime.parse(date, DateTimeFormatter.ISO_DATE);
} catch (DateTimeParseException e) {
try {
return LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE).atStartOfDay()
.atZone(ZoneId.of(DEFAULT_DATE_TIME_ZONE));
} catch (DateTimeParseException e2) {
throw new DepositServiceRuntimeException(
String.format("Metadata contained an invalid Date: '%s'.", date), e2);
}
}
}

private void processCrossrefMetadata(DepositMetadata metadata, JsonObject submissionData) {
getStringProperty(submissionData, DOI_KEY).ifPresent(doi -> {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2024 Johns Hopkins University
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eclipse.pass.deposit.config.repository;

import static org.eclipse.pass.deposit.transport.Transport.TRANSPORT_PROTOCOL;

import java.util.Map;

import org.eclipse.pass.deposit.transport.Transport;

/**
* @author Russ Poetker ([email protected])
*/
public class DSpaceBinding extends ProtocolBinding {
static final String PROTO = "DSpace";

public DSpaceBinding() {
this.setProtocol(PROTO);
}

@Override
public Map<String, String> asPropertiesMap() {
return Map.of(TRANSPORT_PROTOCOL, Transport.PROTOCOL.DSpace.name());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
@JsonSubTypes.Type(value = SftpBinding.class, name = SftpBinding.PROTO),
@JsonSubTypes.Type(value = SwordV2Binding.class, name = SwordV2Binding.PROTO),
@JsonSubTypes.Type(value = FilesystemBinding.class, name = FilesystemBinding.PROTO),
@JsonSubTypes.Type(value = InvenioRdmBinding.class, name = InvenioRdmBinding.PROTO)
@JsonSubTypes.Type(value = InvenioRdmBinding.class, name = InvenioRdmBinding.PROTO),
@JsonSubTypes.Type(value = DSpaceBinding.class, name = DSpaceBinding.PROTO)
})
public abstract class ProtocolBinding {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2024 Johns Hopkins University
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eclipse.pass.deposit.provider.dspace;

import static org.eclipse.pass.deposit.assembler.AssemblerSupport.buildMetadata;

import java.util.List;
import java.util.Map;

import org.eclipse.pass.deposit.assembler.AbstractAssembler;
import org.eclipse.pass.deposit.assembler.DepositFileResource;
import org.eclipse.pass.deposit.assembler.MetadataBuilder;
import org.eclipse.pass.deposit.assembler.MetadataBuilderFactory;
import org.eclipse.pass.deposit.assembler.PackageStream;
import org.eclipse.pass.deposit.assembler.ResourceBuilderFactory;
import org.eclipse.pass.deposit.assembler.SimplePackageStream;
import org.eclipse.pass.deposit.model.DepositSubmission;
import org.eclipse.pass.support.client.PassClient;
import org.springframework.stereotype.Component;

@Component
public class DSpaceAssembler extends AbstractAssembler {
public DSpaceAssembler(MetadataBuilderFactory mbf,
ResourceBuilderFactory rbf,
PassClient passClient) {
super(mbf, rbf, passClient);
}

@Override
protected PackageStream createPackageStream(DepositSubmission depositSubmission,
List<DepositFileResource> custodialResources,
MetadataBuilder mb, ResourceBuilderFactory rbf,
Map<String, Object> options) {
buildMetadata(mb, options);
return new SimplePackageStream(depositSubmission, custodialResources, mb);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Copyright 2024 Johns Hopkins University
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eclipse.pass.deposit.provider.dspace;

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
import org.eclipse.pass.deposit.model.DepositMetadata;
import org.eclipse.pass.deposit.model.DepositMetadata.Article;
import org.eclipse.pass.deposit.model.DepositMetadata.Journal;
import org.eclipse.pass.deposit.model.DepositMetadata.Manuscript;
import org.eclipse.pass.deposit.model.DepositMetadata.Person;
import org.eclipse.pass.deposit.model.DepositSubmission;
import org.eclipse.pass.deposit.provider.util.CitationUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
* DSpace metadata fields set:
* <ul>
* <li>dc.title for the Manuscript
* <li>dc.publisher for the publisher name
* <li>dc.identifier.citation for the Manuscript
* <li>dc.identifier.doi for the DOI
* <li>dc.contributor for each non-submitter associated with the Manuscript
* <li>dc.description.abstract for the Manuscript
* <li>dc.date.issued for the publication date
* <li>DSPACE_FIELD_EMBARGO_LIFT Date that the embargo is lifted
* <li>DSPACE_FIELD_EMBARGO_TERMS Date that the embargo is lifted
* </ul>
*/
@Component
public class DSpaceMetadataMapper {
// Section of workspace item form to add metadata
private static final String SECTION = "traditionalpageone";

private final String dspaceFieldEmbargoLift;
private final String dspaceFieldEmbargoTerms;

public DSpaceMetadataMapper(@Value("${dspace.field.embargo.lift}") String dspaceFieldEmbargoLift,
@Value("${dspace.field.embargo.terms}") String dspaceFieldEmbargoTerms) {
this.dspaceFieldEmbargoLift = dspaceFieldEmbargoLift;
this.dspaceFieldEmbargoTerms = dspaceFieldEmbargoTerms;
}

public String patchWorkspaceItem(DepositSubmission submission) {
DepositMetadata depositMd = submission.getMetadata();
Journal journalMd = depositMd.getJournalMetadata();
Article articleMd = depositMd.getArticleMetadata();
Manuscript manuscriptMd = depositMd.getManuscriptMetadata();

JSONArray metadata = new JSONArray();

// Required by DSpace
metadata.add(add_array(SECTION, "dc.title", manuscriptMd.getTitle()));

if (journalMd != null && journalMd.getPublisherName() != null) {
metadata.add(add_array(SECTION, "dc.publisher", journalMd.getPublisherName()));
}

if (articleMd.getDoi() != null) {
metadata.add(add_array(SECTION, "dc.identifier.doi", articleMd.getDoi().toString()));
}

if (manuscriptMd.getMsAbstract() != null) {
metadata.add(add_array(SECTION, "dc.description.abstract", manuscriptMd.getMsAbstract()));
}

String citation = CitationUtil.createCitation(submission);

if (!citation.isEmpty()) {
metadata.add(add_array(SECTION, "dc.identifier.citation", citation));
}

// Required by DSpace as ISO 8601 local date
metadata.add(add_array(SECTION, "dc.date.issued", journalMd.getPublicationDate().
format(DateTimeFormatter.ISO_LOCAL_DATE)));

// Add non-submitters as authors
String[] authors = depositMd.getPersons().stream().filter(
p -> p.getType() != DepositMetadata.PERSON_TYPE.submitter).
map(Person::getName).toArray(String[]::new);

metadata.add(add_array(SECTION, "dc.contributor.author", authors));

ZonedDateTime embargoLiftDate = articleMd.getEmbargoLiftDate();

if (embargoLiftDate != null) {
String liftDate = embargoLiftDate.format(DateTimeFormatter.ISO_LOCAL_DATE);

metadata.add(add_array(SECTION, dspaceFieldEmbargoLift, liftDate));
metadata.add(add_array(SECTION, dspaceFieldEmbargoTerms, liftDate));
}

// Required by DSpace
metadata.add(add("license", "granted", "true"));

return metadata.toString();
}

private JSONObject add(String section, String key, String value) {
JSONObject op = new JSONObject();

op.put("op", "add");
op.put("path", "/sections/" + section + "/" + key);
op.put("value", value);

return op;
}

private JSONObject add_array(String section, String key, String... values) {
JSONObject op = new JSONObject();

op.put("op", "add");
op.put("path", "/sections/" + section + "/" + key);

JSONArray op_value = new JSONArray();
for (String value : values) {
op_value.add(array_value(value));
}

op.put("value", op_value);

return op;
}

private JSONObject array_value(String value) {
JSONObject obj = new JSONObject();
obj.put("value", value);
return obj;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.eclipse.pass.deposit.provider.inveniordm;

import java.time.format.DateTimeFormatter;
import java.util.Objects;

import net.minidev.json.JSONArray;
Expand Down Expand Up @@ -49,8 +50,9 @@ public JSONObject toInvenioMetadata(DepositSubmission depositSubmission) {
invenioMetadata.put("creators", creators);
String title = depositSubmission.getSubmissionMeta().get("title").getAsString();
invenioMetadata.put("title", title);
String publicationDate = depositMetadata.getJournalMetadata().getPublicationDate();
invenioMetadata.put("publication_date", publicationDate);

invenioMetadata.put("publication_date", depositMetadata.getJournalMetadata().
getPublicationDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
JSONObject resourceType = new JSONObject();
resourceType.put("id", "publication-article");
invenioMetadata.put("resource_type", resourceType);
Expand Down
Loading
Loading