From bf5cb19196ffec5f30fb895a14bd51e21ded64c6 Mon Sep 17 00:00:00 2001 From: Ma-Tador Date: Fri, 25 Oct 2024 10:18:08 +0200 Subject: [PATCH] SwordV2 - Add Item DOI Filter --- .../content/MetadataValueServiceImpl.java | 6 ++ .../dspace/content/dao/MetadataValueDAO.java | 3 + .../dao/impl/MetadataValueDAOImpl.java | 47 +++++++++++++ .../content/service/MetadataValueService.java | 4 ++ .../CollectionDepositManagerDSpace.java | 8 ++- .../dspace/sword2/WorkflowManagerDefault.java | 69 ++++++++++++++----- 6 files changed, 117 insertions(+), 20 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataValueServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/MetadataValueServiceImpl.java index 0c34c04f3..be3c59788 100755 --- a/dspace-api/src/main/java/org/dspace/content/MetadataValueServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/MetadataValueServiceImpl.java @@ -130,4 +130,10 @@ public class MetadataValueServiceImpl implements MetadataValueService { public int countTotal(Context context) throws SQLException { return metadataValueDAO.countRows(context); } + + @Override + public Long countDoiMatches(Context context, Item item) throws SQLException { + return metadataValueDAO.countDoiMatches(context, item); + } + } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/MetadataValueDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/MetadataValueDAO.java index 6a09cfdd8..ca13950d6 100755 --- a/dspace-api/src/main/java/org/dspace/content/dao/MetadataValueDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/MetadataValueDAO.java @@ -10,6 +10,7 @@ package org.dspace.content.dao; import java.sql.SQLException; import java.util.Iterator; import java.util.List; +import org.dspace.content.Item; import org.dspace.content.MetadataField; import org.dspace.content.MetadataValue; @@ -41,4 +42,6 @@ public interface MetadataValueDAO extends GenericDAO { int countRows(Context context) throws SQLException; + Long countDoiMatches(Context context, Item item) throws SQLException; + } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataValueDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataValueDAOImpl.java index f37ced9ab..7b00e8b3b 100755 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataValueDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataValueDAOImpl.java @@ -15,6 +15,8 @@ import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Join; import javax.persistence.criteria.Root; +import org.apache.commons.lang3.StringUtils; +import org.dspace.content.Item; import org.dspace.content.MetadataField; import org.dspace.content.MetadataField_; @@ -95,5 +97,50 @@ public class MetadataValueDAOImpl extends AbstractHibernateDAO im public int countRows(Context context) throws SQLException { return count(createQuery(context, "SELECT count(*) FROM MetadataValue")); } + + + @Override + public Long countDoiMatches(Context context, Item item) throws SQLException { + + String queryString = "SELECT COUNT(m) FROM MetadataValue m " + + "WHERE m.metadataField.element = 'identifier' " + + "AND m.metadataField.qualifier = 'doi' " + + "AND m.dSpaceObject.id != :itemId " + // Exclude the current item + "AND ( " + + " SELECT mv.value FROM MetadataValue mv " + + " WHERE mv.dSpaceObject.id = :itemId " + + " AND mv.metadataField.element = 'identifier' " + + " AND mv.metadataField.qualifier = 'doi' " + + ") IS NOT NULL " + + "AND ( " + + " m.value = ( " + + " SELECT mv.value FROM MetadataValue mv " + + " WHERE mv.dSpaceObject.id = :itemId " + + " AND mv.metadataField.element = 'identifier' " + + " AND mv.metadataField.qualifier = 'doi' " + + " ) " + // Exact DOI match + " OR m.value = concat('doi.org/', ( " + + " SELECT mv.value FROM MetadataValue mv " + + " WHERE mv.dSpaceObject.id = :itemId " + + " AND mv.metadataField.element = 'identifier' " + + " AND mv.metadataField.qualifier = 'doi' " + + " )) " + // Match with 'doi.org/' prefix + " OR m.value = concat('https://doi.org/', ( " + + " SELECT mv.value FROM MetadataValue mv " + + " WHERE mv.dSpaceObject.id = :itemId " + + " AND mv.metadataField.element = 'identifier' " + + " AND mv.metadataField.qualifier = 'doi' " + + " )) " + // Match with 'https://doi.org/' prefix + ")"; + + // Create and execute the query + Query query = createQuery(context, queryString); + + // Set the item ID as a parameter + query.setParameter("itemId", item.getID()); + + // Return the count of matching DOIs, or 0 if no DOI exists + return (Long) query.getSingleResult(); + } } diff --git a/dspace-api/src/main/java/org/dspace/content/service/MetadataValueService.java b/dspace-api/src/main/java/org/dspace/content/service/MetadataValueService.java index 1cf26e37f..9b796043b 100755 --- a/dspace-api/src/main/java/org/dspace/content/service/MetadataValueService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/MetadataValueService.java @@ -14,6 +14,7 @@ import java.util.List; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; import org.dspace.content.MetadataField; import org.dspace.content.MetadataValue; import org.dspace.core.Context; @@ -112,4 +113,7 @@ public interface MetadataValueService { throws SQLException; int countTotal(Context context) throws SQLException; + + // finds how many items have .identifier.doi matching given item's doi value + public Long countDoiMatches(Context context, Item item) throws SQLException; } diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionDepositManagerDSpace.java b/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionDepositManagerDSpace.java index 7f77c00f0..2442204cb 100755 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionDepositManagerDSpace.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/CollectionDepositManagerDSpace.java @@ -147,14 +147,16 @@ public class CollectionDepositManagerDSpace extends DSpaceSwordAPI " ms"); this.addVerboseDescription(receipt, this.verboseDescription); - // if something hasn't killed it already (allowed), then complete the transaction - sc.commit(); + // if duplicate DOI found, don't commit + if(!result.getTreatment().contains("Item skipped as the current item's DOI matches another item's DOI.")) { + sc.commit(); + } return receipt; } catch (DSpaceSwordException e) { log.error("caught exception:", e); throw new SwordServerException( - "There was a problem depositing the item", e); + e.getMessage(), e); } finally { // this is a read operation only, so there's never any need to commit the context if (sc != null) { diff --git a/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerDefault.java b/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerDefault.java index ea5a52091..47b5afd24 100755 --- a/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerDefault.java +++ b/dspace-swordv2/src/main/java/org/dspace/sword2/WorkflowManagerDefault.java @@ -7,13 +7,23 @@ */ package org.dspace.sword2; +import java.io.IOException; import java.sql.SQLException; import java.util.List; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.apache.commons.lang3.StringUtils; +import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; import org.dspace.content.Bundle; import org.dspace.content.Collection; import org.dspace.content.Item; +import org.dspace.content.MetadataValue; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.MetadataValueService; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.services.ConfigurationService; @@ -28,6 +38,13 @@ import org.swordapp.server.UriRegistry; * performed on items which are in the deposit phase. */ public class WorkflowManagerDefault implements WorkflowManager { + + private final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); + + private final MetadataValueService metadataValueService = ContentServiceFactory.getInstance().getMetadataValueService(); + + private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(WorkflowManagerDefault.class); + private final ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); @@ -281,19 +298,13 @@ public class WorkflowManagerDefault implements WorkflowManager { // or find out if the item is in the archive boolean inarch = item.isArchived() || item.isWithdrawn(); - // in progress inws inwf inarch action description - // 0 0 0 1 NOTHING the deposit finished, and the item is in the - // archive; - // 0 0 1 0 NOTHING the deposit finished, and the item is in the - // workflow. Carry on as normal - // 0 1 0 0 START WF the deposit is finished, and the item is in the - // workflow, so we start it - // 1 0 0 1 NOTHING the deposit is not finished, and the item is in - // the archive; - // 1 0 1 0 STOP WF the deposit is not finished, and it is in the - // workflow. Pull it out into the workspace - // 1 1 0 0 NOTHING the deposit is not finished, and is in the - // workspace; leave it there +// in progress inws inwf inarch action description +// 0 0 0 1 NOTHING the deposit finished, and the item is in the archive; +// 0 0 1 0 NOTHING the deposit finished, and the item is in the workflow. Carry on as normal +// 0 1 0 0 START WF the deposit is finished, and the item is in the workflow, so we start it (if no DOI duplicate is found) +// 1 0 0 1 NOTHING the deposit is not finished, and the item is in the archive; +// 1 0 1 0 STOP WF the deposit is not finished, and it's in the workflow. Pull it out into the workspace +// 1 1 0 0 NOTHING the deposit is not finished, and is in the workspace; leave it there if (!deposit.isInProgress() && inarch) { verboseDescription @@ -302,11 +313,35 @@ public class WorkflowManagerDefault implements WorkflowManager { } if (!deposit.isInProgress() && inws) { - verboseDescription - .append("The deposit is finished: moving it from the workspace to the workflow"); - wft.startWorkflow(context, item); + try { + Long nrMatches = this.metadataValueService.countDoiMatches(context, item); + String doi = ""; + //Item i = itemService.find(context, UUID.fromString("b3694e20-4b31-4a79-9159-ab9dad105f63")); + //itemService.delete(context, i); + var mvs = item.getMetadata(); + for(MetadataValue mv : mvs) { + if(mv.getMetadataField().getQualifier() != null && mv.getMetadataField().getQualifier().equals("doi")) { + doi = mv.getValue(); + break; + } + } + + //if items that matches are found for the given doi, then dont save item and send CREATED to Sword to allow import of next items + if(nrMatches > 0) { + log.info("Sword Import: item ( " + item.getID() + ") skipped as the current item's DOI ( " + doi + " ) matches another item's DOI. Nr matches found: " + nrMatches ); + result.setTreatment("Item skipped as the current item's DOI matches another item's DOI."); + verboseDescription.append("The deposit is finished: skipping item because another item has the same DOI."); + this.itemService.delete(context, item); + } else { + log.info("Sword Import: item ( " + item.getID() + ") imported as its DOI is unique. Nr matches found: " + nrMatches ); + verboseDescription.append("The deposit is finished: moving it from the workspace to the workflow"); + wft.startWorkflow(context, item); + } + } catch (AuthorizeException | IOException | SQLException ex) { + Logger.getLogger(WorkflowManagerDefault.class.getName()).log(Level.SEVERE, null, ex); + } } - + if (deposit.isInProgress() && inarch) { verboseDescription .append("The deposit is not finished, and the item is already in the archive"); -- 2.25.1