Skip to content

Commit

Permalink
Merge pull request DSpace#9722 from 4Science/task/dspace-7_x/CST-14901
Browse files Browse the repository at this point in the history
[Port dspace-7_x] Handles versioning for ORCID publications.
  • Loading branch information
tdonohue authored Jan 22, 2025
2 parents f94bbfc + 6c99c25 commit 8bcd398
Show file tree
Hide file tree
Showing 11 changed files with 377 additions and 59 deletions.
42 changes: 42 additions & 0 deletions dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@
import org.dspace.orcid.service.OrcidTokenService;
import org.dspace.profile.service.ResearcherProfileService;
import org.dspace.services.ConfigurationService;
import org.dspace.versioning.Version;
import org.dspace.versioning.VersionHistory;
import org.dspace.versioning.service.VersionHistoryService;
import org.dspace.versioning.service.VersioningService;
import org.dspace.workflow.WorkflowItemService;
import org.dspace.workflow.factory.WorkflowServiceFactory;
Expand Down Expand Up @@ -172,6 +175,9 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
@Autowired(required = true)
protected SubscribeService subscribeService;

@Autowired
private VersionHistoryService versionHistoryService;

protected ItemServiceImpl() {
super();
}
Expand Down Expand Up @@ -1922,4 +1928,40 @@ private void deleteOrcidQueueRecords(Context context, Item item) throws SQLExcep
}
}

@Override
public boolean isLatestVersion(Context context, Item item) throws SQLException {

VersionHistory history = versionHistoryService.findByItem(context, item);
if (history == null) {
// not all items have a version history
// if an item does not have a version history, it is by definition the latest
// version
return true;
}

// start with the very latest version of the given item (may still be in
// workspace)
Version latestVersion = versionHistoryService.getLatestVersion(context, history);

// find the latest version of the given item that is archived
while (latestVersion != null && !latestVersion.getItem().isArchived()) {
latestVersion = versionHistoryService.getPrevious(context, history, latestVersion);
}

// could not find an archived version of the given item
if (latestVersion == null) {
// this scenario should never happen, but let's err on the side of showing too
// many items vs. to little
// (see discovery.xml, a lot of discovery configs filter out all items that are
// not the latest version)
return true;
}

// sanity check
assert latestVersion.getItem().isArchived();

return item.equals(latestVersion.getItem());

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -983,4 +983,14 @@ public List<MetadataValue> getMetadata(Item item, String schema, String element,
*/
public EntityType getEntityType(Context context, Item item) throws SQLException;


/**
* Check whether the given item is the latest version. If the latest item cannot
* be determined, because either the version history or the latest version is
* not present, assume the item is latest.
* @param context the DSpace context.
* @param item the item that should be checked.
* @return true if the item is the latest version, false otherwise.
*/
public boolean isLatestVersion(Context context, Item item) throws SQLException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,6 @@
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.util.MultiFormatDateParser;
import org.dspace.util.SolrUtils;
import org.dspace.versioning.Version;
import org.dspace.versioning.VersionHistory;
import org.dspace.versioning.service.VersionHistoryService;
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService;
Expand Down Expand Up @@ -151,7 +149,7 @@ public SolrInputDocument buildDocument(Context context, IndexableItem indexableI
doc.addField("withdrawn", item.isWithdrawn());
doc.addField("discoverable", item.isDiscoverable());
doc.addField("lastModified", SolrUtils.getDateFormatter().format(item.getLastModified()));
doc.addField("latestVersion", isLatestVersion(context, item));
doc.addField("latestVersion", itemService.isLatestVersion(context, item));

EPerson submitter = item.getSubmitter();
if (submitter != null && !(DSpaceServicesFactory.getInstance().getConfigurationService().getBooleanProperty(
Expand All @@ -177,43 +175,6 @@ public SolrInputDocument buildDocument(Context context, IndexableItem indexableI
return doc;
}

/**
* Check whether the given item is the latest version.
* If the latest item cannot be determined, because either the version history or the latest version is not present,
* assume the item is latest.
* @param context the DSpace context.
* @param item the item that should be checked.
* @return true if the item is the latest version, false otherwise.
*/
protected boolean isLatestVersion(Context context, Item item) throws SQLException {
VersionHistory history = versionHistoryService.findByItem(context, item);
if (history == null) {
// not all items have a version history
// if an item does not have a version history, it is by definition the latest version
return true;
}

// start with the very latest version of the given item (may still be in workspace)
Version latestVersion = versionHistoryService.getLatestVersion(context, history);

// find the latest version of the given item that is archived
while (latestVersion != null && !latestVersion.getItem().isArchived()) {
latestVersion = versionHistoryService.getPrevious(context, history, latestVersion);
}

// could not find an archived version of the given item
if (latestVersion == null) {
// this scenario should never happen, but let's err on the side of showing too many items vs. to little
// (see discovery.xml, a lot of discovery configs filter out all items that are not the latest version)
return true;
}

// sanity check
assert latestVersion.getItem().isArchived();

return item.equals(latestVersion.getItem());
}

@Override
public SolrInputDocument buildNewDocument(Context context, IndexableItem indexableItem)
throws SQLException, IOException {
Expand Down Expand Up @@ -706,7 +667,7 @@ public List getIndexableObjects(Context context, Item item) throws SQLException
return List.copyOf(workflowItemIndexFactory.getIndexableObjects(context, xmlWorkflowItem));
}

if (!isLatestVersion(context, item)) {
if (!itemService.isLatestVersion(context, item)) {
// the given item is an older version of another item
return List.of(new IndexableItem(item));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand Down Expand Up @@ -56,7 +57,7 @@
* be synchronized (based on the preferences set by the user)</li>
* <li>are publications/fundings related to profile items linked to orcid (based
* on the preferences set by the user)</li>
*
*
* </ul>
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
Expand All @@ -82,7 +83,7 @@ public class OrcidQueueConsumer implements Consumer {

private RelationshipService relationshipService;

private List<UUID> alreadyConsumedItems = new ArrayList<>();
private final Set<UUID> itemsToConsume = new HashSet<>();

@Override
public void initialize() throws Exception {
Expand Down Expand Up @@ -117,17 +118,26 @@ public void consume(Context context, Event event) throws Exception {
return;
}

if (alreadyConsumedItems.contains(item.getID())) {
return;
}
itemsToConsume.add(item.getID());
}

@Override
public void end(Context context) throws Exception {

for (UUID itemId : itemsToConsume) {

Item item = itemService.find(context, itemId);

context.turnOffAuthorisationSystem();
try {
consumeItem(context, item);
} finally {
context.restoreAuthSystemState();
}

context.turnOffAuthorisationSystem();
try {
consumeItem(context, item);
} finally {
context.restoreAuthSystemState();
}

itemsToConsume.clear();
}

/**
Expand All @@ -146,7 +156,7 @@ private void consumeItem(Context context, Item item) throws SQLException {
consumeProfile(context, item);
}

alreadyConsumedItems.add(item.getID());
itemsToConsume.add(item.getID());

}

Expand All @@ -169,6 +179,10 @@ private void consumeEntity(Context context, Item entity) throws SQLException {
continue;
}

if (isNotLatestVersion(context, entity)) {
continue;
}

orcidQueueService.create(context, relatedItem, entity);

}
Expand Down Expand Up @@ -329,6 +343,14 @@ private boolean isNotProfileItem(Item profileItemItem) {
return !getProfileType().equals(itemService.getEntityTypeLabel(profileItemItem));
}

private boolean isNotLatestVersion(Context context, Item entity) {
try {
return !itemService.isLatestVersion(context, entity);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}

private String getMetadataValue(Item item, String metadataField) {
return itemService.getMetadataFirstValue(item, new MetadataFieldName(metadataField), Item.ANY);
}
Expand All @@ -345,11 +367,6 @@ private boolean isOrcidSynchronizationDisabled() {
return !configurationService.getBooleanProperty("orcid.synchronization-enabled", true);
}

@Override
public void end(Context context) throws Exception {
alreadyConsumedItems.clear();
}

@Override
public void finish(Context context) throws Exception {
// nothing to do
Expand Down
10 changes: 10 additions & 0 deletions dspace-api/src/main/java/org/dspace/orcid/dao/OrcidQueueDAO.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ public List<OrcidQueue> findByProfileItemAndEntity(Context context, Item profile
*/
public List<OrcidQueue> findByProfileItemOrEntity(Context context, Item item) throws SQLException;

/**
* Get the OrcidQueue records where the given item is the entity.
*
* @param context DSpace context object
* @param item the item to search for
* @return the found OrcidQueue entities
* @throws SQLException if database error
*/
public List<OrcidQueue> findByEntity(Context context, Item item) throws SQLException;

/**
* Find all the OrcidQueue records with the given entity and record type.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ public List<OrcidQueue> findByProfileItemOrEntity(Context context, Item item) th
return query.getResultList();
}

@Override
public List<OrcidQueue> findByEntity(Context context, Item item) throws SQLException {
Query query = createQuery(context, "FROM OrcidQueue WHERE entity.id = :itemId");
query.setParameter("itemId", item.getID());
return query.getResultList();
}

@Override
public List<OrcidQueue> findByEntityAndRecordType(Context context, Item entity, String type) throws SQLException {
Query query = createQuery(context, "FROM OrcidQueue WHERE entity = :entity AND recordType = :type");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,16 @@ public List<OrcidQueue> findByProfileItemAndEntity(Context context, Item profile
*/
public List<OrcidQueue> findByProfileItemOrEntity(Context context, Item item) throws SQLException;

/**
* Get the OrcidQueue records where the given item is the entity.
*
* @param context DSpace context object
* @param item the item to search for
* @return the found OrcidQueue records
* @throws SQLException if database error
*/
public List<OrcidQueue> findByEntity(Context context, Item item) throws SQLException;

/**
* Get all the OrcidQueue records with attempts less than the given attempts.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ public List<OrcidQueue> findByProfileItemOrEntity(Context context, Item item) th
return orcidQueueDAO.findByProfileItemOrEntity(context, item);
}

@Override
public List<OrcidQueue> findByEntity(Context context, Item item) throws SQLException {
return orcidQueueDAO.findByEntity(context, item);
}

@Override
public long countByProfileItemId(Context context, UUID profileItemId) throws SQLException {
return orcidQueueDAO.countByProfileItemId(context, profileItemId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
import org.dspace.discovery.IndexEventConsumer;
import org.dspace.event.Consumer;
import org.dspace.event.Event;
import org.dspace.orcid.OrcidHistory;
import org.dspace.orcid.OrcidQueue;
import org.dspace.orcid.factory.OrcidServiceFactory;
import org.dspace.orcid.service.OrcidHistoryService;
import org.dspace.orcid.service.OrcidQueueService;
import org.dspace.versioning.factory.VersionServiceFactory;
import org.dspace.versioning.service.VersionHistoryService;
import org.dspace.versioning.utils.RelationshipVersioningUtils;
Expand All @@ -58,6 +63,8 @@ public class VersioningConsumer implements Consumer {
private RelationshipTypeService relationshipTypeService;
private RelationshipService relationshipService;
private RelationshipVersioningUtils relationshipVersioningUtils;
private OrcidQueueService orcidQueueService;
private OrcidHistoryService orcidHistoryService;

@Override
public void initialize() throws Exception {
Expand All @@ -67,6 +74,8 @@ public void initialize() throws Exception {
relationshipTypeService = ContentServiceFactory.getInstance().getRelationshipTypeService();
relationshipService = ContentServiceFactory.getInstance().getRelationshipService();
relationshipVersioningUtils = VersionServiceFactory.getInstance().getRelationshipVersioningUtils();
this.orcidQueueService = OrcidServiceFactory.getInstance().getOrcidQueueService();
this.orcidHistoryService = OrcidServiceFactory.getInstance().getOrcidHistoryService();
}

@Override
Expand Down Expand Up @@ -132,7 +141,8 @@ public void consume(Context ctx, Event event) throws Exception {

// unarchive previous item
unarchiveItem(ctx, previousItem);

// handles versions for ORCID publications waiting to be shipped, or already published (history-queue).
handleOrcidSynchronization(ctx, previousItem, latestItem);
// update relationships
updateRelationships(ctx, latestItem, previousItem);
}
Expand All @@ -148,6 +158,29 @@ protected void unarchiveItem(Context ctx, Item item) {
));
}

private void handleOrcidSynchronization(Context ctx, Item previousItem, Item latestItem) {
try {
replaceOrcidHistoryEntities(ctx, previousItem, latestItem);
removeOrcidQueueEntries(ctx, previousItem);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}

private void removeOrcidQueueEntries(Context ctx, Item previousItem) throws SQLException {
List<OrcidQueue> queueEntries = orcidQueueService.findByEntity(ctx, previousItem);
for (OrcidQueue queueEntry : queueEntries) {
orcidQueueService.delete(ctx, queueEntry);
}
}

private void replaceOrcidHistoryEntities(Context ctx, Item previousItem, Item latestItem) throws SQLException {
List<OrcidHistory> entries = orcidHistoryService.findByEntity(ctx, previousItem);
for (OrcidHistory entry : entries) {
entry.setEntity(latestItem);
}
}

/**
* Update {@link Relationship#latestVersionStatus} of the relationships of both the old version and the new version
* of the item.
Expand Down
Loading

0 comments on commit 8bcd398

Please sign in to comment.