[CST-5269] configured sherpa service in submission

This commit is contained in:
Mykhaylo
2022-04-21 22:24:46 +02:00
parent a9edca7f55
commit a1d619979e
17 changed files with 284 additions and 22 deletions

View File

@@ -31,6 +31,7 @@ import org.dspace.app.sherpa.v2.SHERPAResponse;
import org.dspace.app.sherpa.v2.SHERPAUtils;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
/**
* SHERPAService is responsible for making the HTTP call to the SHERPA v2 API
@@ -91,6 +92,7 @@ public class SHERPAService {
* @param query ISSN string to pass in an "issn equals" API query
* @return SHERPAResponse containing an error or journal policies
*/
@Cacheable(key = "#query", cacheNames = "sherpa.searchByJournalISSN")
public SHERPAResponse searchByJournalISSN(String query) {
return performRequest("publication", "issn", "equals", query, 0, 1);
}

View File

@@ -0,0 +1,38 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.sherpa.cache;
import java.util.Objects;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* Exposes the Spring application's Sherpa cache evict service to the submission sherpaPolicyStep.
*
* @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.com)
*/
@Component
public class SherpaCacheEvictBeanLocator implements ApplicationContextAware {
private static ApplicationContext context;
private static final String SHERPA_CACHE_EVICT_SERVICE = "sherpaCacheEvictService";
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static SherpaCacheEvictService getSherpaCacheEvictService() {
return Objects.nonNull(context) ? (SherpaCacheEvictService) context.getBean(SHERPA_CACHE_EVICT_SERVICE) : null;
}
}

View File

@@ -0,0 +1,38 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.sherpa.cache;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Component;
/**
* Removes items from the sherpaSearchByJournalISSN cache.
*
* @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.com)
*/
@Component
public class SherpaCacheEvictService {
// The cache that is managed by this service.
static final String CACHE_NAME = "sherpa.searchByJournalISSN";
@Autowired
private CacheManager cacheManager;
public void evictSingleCacheValue(String cacheKey) {
Objects.requireNonNull(cacheManager.getCache(CACHE_NAME)).evict(cacheKey);
}
public void evictAllCacheValues() {
Objects.requireNonNull(cacheManager.getCache(CACHE_NAME)).clear();
}
}

View File

@@ -9,7 +9,6 @@ package org.dspace.app.sherpa.submit;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -63,19 +62,19 @@ public class SHERPASubmitService {
* issnItemExtractor(s) in the SHERPA spring configuration.
* The ISSNs are not validated with a regular expression or other rules - any values
* extracted will be included in API queries.
* Return the first not empty response from Sherpa
* @see "dspace-dspace-addon-sherpa-configuration-services.xml"
* @param context DSpace context
* @param item DSpace item containing ISSNs to be checked
* @return SHERPA v2 API response (policy data)
*/
public List<SHERPAResponse> searchRelatedJournals(Context context, Item item) {
public SHERPAResponse searchRelatedJournals(Context context, Item item) {
Set<String> issns = getISSNs(context, item);
if (issns == null || issns.size() == 0) {
return null;
} else {
// SHERPA v2 API no longer supports "OR'd" ISSN search, perform individual searches instead
Iterator<String> issnIterator = issns.iterator();
List<SHERPAResponse> responses = new LinkedList<>();
while (issnIterator.hasNext()) {
String issn = issnIterator.next();
SHERPAResponse response = sherpaService.searchByJournalISSN(issn);
@@ -83,14 +82,12 @@ public class SHERPASubmitService {
// Continue with loop
log.warn("Failed to look up SHERPA ROMeO result for ISSN: " + issn
+ ": " + response.getMessage());
} else if (!response.getJournals().isEmpty()) {
// return this response, if it is not empty
return response;
}
// Store this response, even if it has an error (useful for UI reporting)
responses.add(response);
}
if (responses.isEmpty()) {
responses.add(new SHERPAResponse("SHERPA ROMeO lookup failed"));
}
return responses;
return new SHERPAResponse("SHERPA ROMeO lookup failed");
}
}

View File

@@ -12,10 +12,12 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.JSONArray;
@@ -52,6 +54,9 @@ public class SHERPAResponse {
// SHERPA URI (the human page version of this API response)
private String uri;
@JsonIgnore
private Date retrievalTime = new Date();
// Format enum - currently only JSON is supported
public enum SHERPAFormat {
JSON, XML
@@ -542,4 +547,8 @@ public class SHERPAResponse {
public SHERPASystemMetadata getMetadata() {
return metadata;
}
public Date getRetrievalTime() {
return retrievalTime;
}
}

View File

@@ -131,6 +131,12 @@
<processing-class>org.dspace.app.rest.submit.step.DescribeStep</processing-class>
<type>submission-form</type>
</step-definition>
<step-definition id="sherpaPolicies" mandatory="true">
<heading>submit.progressbar.sherpapolicy</heading>
<processing-class>org.dspace.app.rest.submit.step.SherpaPolicyStep</processing-class>
<type>sherpaPolicy</type>
</step-definition>
</step-definitions>
<!-- The submission-definitions map lays out the detailed definition of -->
@@ -166,6 +172,7 @@
<!-- <step id="upload-with-embargo"/> -->
<!-- <step id="extractionstep"/> -->
<step id="defaultAC"/>
<step id="sherpaPolicies"/>
<!--Step will be to Sign off on the License -->
<step id="license"/>

View File

@@ -11,7 +11,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.sql.SQLException;
import java.util.List;
import org.dspace.AbstractUnitTest;
import org.dspace.app.sherpa.v2.SHERPAResponse;
@@ -109,20 +108,18 @@ public class SHERPASubmitServiceTest extends AbstractUnitTest {
// Get responses from SHERPA submit service, which should inspect item ISSNs and perform search
// on the mock SHERPA service
List<SHERPAResponse> responses = sherpaSubmitService.searchRelatedJournals(context, testItem);
SHERPAResponse response = sherpaSubmitService.searchRelatedJournals(context, testItem);
// Make sure response is not null or empty
assertTrue("Response list should not be null or empty",
responses != null && !responses.isEmpty());
assertTrue("Response should not be null", response != null);
// For each response (there should be only one based on test data) perform the standard set
// of thorough parsing tests
for (SHERPAResponse response : responses) {
// Assert response is not error, or fail with message
assertFalse("Response was flagged as 'isError'", response.isError());
// Skip remainder of parsing tests - these are already done in SHERPAServiceTEst
}
// Assert response is not error, or fail with message
assertFalse("Response was flagged as 'isError'", response.isError());
// Skip remainder of parsing tests - these are already done in SHERPAServiceTEst
}
}

View File

@@ -177,14 +177,18 @@ public class WorkspaceItemBuilder extends AbstractBuilder<WorkspaceItem, Workspa
return addMetadataValue(MetadataSchemaEnum.DC.getName(), "subject", null, subject);
}
public WorkspaceItemBuilder withAbstract(final String subject) {
return addMetadataValue(MetadataSchemaEnum.DC.getName(),"description", "abstract", subject);
public WorkspaceItemBuilder withIssn(String issn) {
return addMetadataValue(MetadataSchemaEnum.DC.getName(), "identifier", "issn", issn);
}
public WorkspaceItemBuilder withEntityType(final String entityType) {
return addMetadataValue("dspace", "entity", "type", entityType);
}
public WorkspaceItemBuilder withAbstract(final String subject) {
return addMetadataValue(MetadataSchemaEnum.DC.getName(),"description", "abstract", subject);
}
public WorkspaceItemBuilder grantLicense() {
Item item = workspaceItem.getItem();
String license;

View File

@@ -0,0 +1,42 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.model.step;
import java.util.Date;
import org.dspace.app.sherpa.v2.SHERPAResponse;
/**
* @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.com)
*/
public class SherpaPolicy implements SectionData {
private static final long serialVersionUID = 2440249335255683173L;
private Date retrievalTime;
private SHERPAResponse sherpaResponse;
public Date getRetrievalTime() {
return retrievalTime;
}
public void setRetrievalTime(Date retrievalTime) {
this.retrievalTime = retrievalTime;
}
public SHERPAResponse getSherpaResponse() {
return sherpaResponse;
}
public void setSherpaResponse(SHERPAResponse sherpaResponse) {
this.sherpaResponse = sherpaResponse;
this.retrievalTime = sherpaResponse.getRetrievalTime();
}
}

View File

@@ -7,6 +7,7 @@
*/
package org.dspace.app.rest.submit;
import org.dspace.app.sherpa.submit.SHERPASubmitService;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.factory.ContentServiceFactory;
@@ -35,5 +36,7 @@ public abstract class AbstractProcessingStep implements DataProcessingStep {
protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService();
protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
protected SHERPASubmitService sherpaSubmitService = DSpaceServicesFactory.getInstance().getServiceManager()
.getServiceByName("org.dspace.app.sherpa.submit.SHERPASubmitService", SHERPASubmitService.class);
}

View File

@@ -38,6 +38,7 @@ public interface DataProcessingStep extends RestProcessingStep {
public static final String CCLICENSE_STEP_OPERATION_ENTRY = "cclicense/uri";
public static final String ACCESS_CONDITION_STEP_OPERATION_ENTRY = "discoverable";
public static final String ACCESS_CONDITION_POLICY_STEP_OPERATION_ENTRY = "accessConditions";
public static final String SHERPA_RETRIEVAL_TIME = "retrievalTime";
public static final String UPLOAD_STEP_METADATA_PATH = "metadata";

View File

@@ -0,0 +1,51 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.submit.step;
import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.model.patch.Operation;
import org.dspace.app.rest.model.step.SherpaPolicy;
import org.dspace.app.rest.submit.AbstractProcessingStep;
import org.dspace.app.rest.submit.SubmissionService;
import org.dspace.app.sherpa.cache.SherpaCacheEvictBeanLocator;
import org.dspace.app.sherpa.cache.SherpaCacheEvictService;
import org.dspace.app.sherpa.v2.SHERPAResponse;
import org.dspace.app.util.SubmissionStepConfig;
import org.dspace.content.InProgressSubmission;
import org.dspace.core.Context;
import org.dspace.web.ContextUtil;
/**
* @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.com)
*/
public class SherpaPolicyStep extends AbstractProcessingStep {
@Override
@SuppressWarnings("unchecked")
public SherpaPolicy getData(SubmissionService submissionService, InProgressSubmission obj,
SubmissionStepConfig config) throws Exception {
SherpaPolicy result = new SherpaPolicy();
Context context = ContextUtil.obtainCurrentRequestContext();
SHERPAResponse response = sherpaSubmitService.searchRelatedJournals(context, obj.getItem());
result.setSherpaResponse(response);
return result;
}
@Override
public void doPatchProcessing(Context context, HttpServletRequest currentRequest, InProgressSubmission source,
Operation op, SubmissionStepConfig stepConf) throws Exception {
String path = op.getPath();
SherpaCacheEvictService sherpaCacheEvictService = SherpaCacheEvictBeanLocator.getSherpaCacheEvictService();
if (path.contains(SHERPA_RETRIEVAL_TIME)) {
// uuid or issn?
sherpaCacheEvictService.evictSingleCacheValue(source.getItem().getID().toString());
}
}
}

View File

@@ -23,7 +23,7 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@ComponentScan( {"org.dspace.app.rest.converter", "org.dspace.app.rest.repository", "org.dspace.app.rest.utils",
"org.dspace.app.configuration", "org.dspace.iiif", "org.dspace.app.iiif"})
"org.dspace.app.configuration", "org.dspace.iiif", "org.dspace.app.iiif", "org.dspace.app.sherpa.cache"})
public class ApplicationConfig {
// Allowed CORS origins ("Access-Control-Allow-Origin" header)
// Can be overridden in DSpace configuration

View File

@@ -47,6 +47,24 @@
<offheap unit="MB">4</offheap>
</resources>
</cache-template>
<cache-template name="sherpa-default">
<listeners>
<listener>
<class>org.dspace.app.rest.cache.CanvasCacheLogger</class>
<event-firing-mode>ASYNCHRONOUS</event-firing-mode>
<event-ordering-mode>UNORDERED</event-ordering-mode>
<events-to-fire-on>CREATED</events-to-fire-on>
<events-to-fire-on>EXPIRED</events-to-fire-on>
<events-to-fire-on>REMOVED</events-to-fire-on>
<events-to-fire-on>EVICTED</events-to-fire-on>
</listener>
</listeners>
<resources>
<heap>3000</heap>
<offheap unit="MB">4</offheap>
</resources>
</cache-template>
<cache alias="manifests" uses-template="iiif-default"/>
<cache alias="canvasdimensions" uses-template="iiif-canvas"/>
<cache alias="sherpa.searchByJournalISSN" uses-template="sherpa-default"/>
</config>

View File

@@ -94,4 +94,11 @@ public class SubmissionAccessOptionRestRepositoryIT extends AbstractControllerIn
.andExpect(status().isNotFound());
}
@Test
public void test() throws Exception {
String tokenAdmin = getAuthToken(admin.getEmail(), password);
getClient(tokenAdmin).perform(get("/api/config/submissionforms/sherpaPolicyStep"))
.andExpect(status().isOk());
}
}

View File

@@ -371,7 +371,9 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1)
.withTitle("Workspace Item 1")
.withIssueDate("2017-10-17")
.withAuthor("Smith, Donald").withAuthor("Doe, John")
.withAuthor("Smith, Donald")
.withIssn("222731-0582")
.withAuthor("Doe, John")
.withSubject("ExtraEntry")
.build();
@@ -7262,4 +7264,43 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
.andExpect(jsonPath("$.page.totalElements", is(1)));
}
@Test
public void test99() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity)
.withName("Collection 1")
.build();
WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1)
.withTitle("Workspace Item 1")
.withIssueDate("2017-10-17")
.withAuthor("Smith, Donald")
.withIssn("222731-0582")
.withAuthor("Doe, John")
.withSubject("ExtraEntry")
.build();
context.restoreAuthSystemState();
String token = getAuthToken(eperson.getEmail(), password);
getClient(token).perform(get("/api/submission/workspaceitems/" + witem.getID()))
.andExpect(status().isOk());
// create a list of values to use in add operation
List<Operation> operations = new ArrayList<>();
operations.add(new RemoveOperation("/sections/sherpaPolicies/retrievalTime"));
String patchBody = getPatchContent(operations);
getClient(token).perform(patch("/api/submission/workspaceitems/" + witem.getID())
.content(patchBody)
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
.andExpect(status().isOk());
getClient(token).perform(get("/api/submission/workspaceitems/" + witem.getID()))
.andExpect(status().isOk());
}
}

View File

@@ -203,6 +203,12 @@
<processing-class>org.dspace.submit.step.SampleStep</processing-class>
<type>sample</type>
</step-definition>
<step-definition id="sherpaPolicies" mandatory="true">
<heading>submit.progressbar.sherpapolicy</heading>
<processing-class>org.dspace.app.rest.submit.step.SherpaPolicyStep</processing-class>
<type>sherpaPolicy</type>
</step-definition>
</step-definitions>
<!-- The submission-definitions map lays out the detailed definition of -->
@@ -237,6 +243,7 @@
<!--Step will be to Upload the item -->
<step id="upload"/>
<step id="sherpaPolicies"/>
<!-- <step id="extractionstep"/> -->
<!-- Uncomment this step to allow the user to select a Creative Commons License -->