diff --git a/dspace-api/src/main/java/org/dspace/content/enhancer/impl/NameEnhancer.java b/dspace-api/src/main/java/org/dspace/content/enhancer/impl/NameEnhancer.java new file mode 100644 index 000000000000..3678c661a06b --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/enhancer/impl/NameEnhancer.java @@ -0,0 +1,187 @@ +/** + * 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.content.enhancer.impl; + +import java.sql.SQLException; +import java.util.List; +import java.util.Objects; + +import org.apache.commons.lang.StringUtils; +import org.dspace.content.Item; +import org.dspace.content.MetadataField; +import org.dspace.content.MetadataValue; +import org.dspace.content.enhancer.AbstractItemEnhancer; +import org.dspace.content.enhancer.ItemEnhancer; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.MetadataFieldService; +import org.dspace.core.Context; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Implementation of {@link ItemEnhancer} that add metadata values on the given + * item from a list of other metadatavalues . + * The first value of the list that is not null matches and overwrites the existing value. + * Some default value can be specified if no fields were found + * + * @author Florian Gantner (florian.gantner@uni-bamberg.de) + * + */ +public class NameEnhancer extends AbstractItemEnhancer { + + private static final Logger LOGGER = LoggerFactory.getLogger(NameEnhancer.class); + + @Autowired + private ItemService itemService; + + @Autowired + private MetadataFieldService metadatafieldService; + + private String sourceEntityType; + + private String targetItemMetadataField; + + private List relatedItemMetadataFields; + private String defaultValue; + + @Override + public boolean canEnhance(Context context, Item item) { + return sourceEntityType == null || sourceEntityType.equals(itemService.getEntityType(item)); + } + + @Override + public boolean enhance(Context context, Item item, boolean deepMode) { + try { + if (Objects.isNull(relatedItemMetadataFields) || relatedItemMetadataFields.isEmpty() || + StringUtils.isBlank(targetItemMetadataField)) { + return false; + } + return checkNames(context, item, deepMode); + } catch (Exception e) { + LOGGER.error("An error occurs enhancing item with id {}: {}", item.getID(), e.getMessage(), e); + //Exception handling not supported by ItemEnhancerService. Thus, just log to continue other enhancers + //throw new SQLRuntimeException(e); + } + return false; + } + + /** + * Check the names/values from the specified metadatafield and compare the first value found + * with the target metadatafield. Updates the target metadatafield when the value is different + * or when deepMode is set. + * When the target metadatafield has not been set before, then set this value. + * @param context current Context + * @param item current item + * @param deepMode boolean + * @return boolean value if some change/update has happened + * @throws Exception when some error occurs + */ + private boolean checkNames(Context context, Item item, boolean deepMode) throws Exception { + // ignore languages of Metadata here. Assume main title is not repeated + // Could be more simplified + List currentnames = itemService.getMetadataByMetadataString(item, targetItemMetadataField); + + if (!currentnames.isEmpty()) { + // some name is assigned yet + for (MetadataValue currentname : currentnames) { + String val = currentname.getValue(); + for (String field : relatedItemMetadataFields) { + List fieldnames = + itemService.getMetadataByMetadataString(item, field); + if (fieldnames.isEmpty()) { + continue ; //No Values, try next loop + } + for (MetadataValue fieldname : fieldnames) { + if (StringUtils.isNotBlank(fieldname.getValue()) + && fieldname.getValue().contentEquals(val)) { + //Values are the same. No Update necessary + if (deepMode) { + // value is recalculated in deepMode + return updateTargetMetadata(context, item, fieldname.getValue(), true); + } + return false; + } else { + //values differ. We must update the value + return updateTargetMetadata(context, item, fieldname.getValue(), true); + } + } + } + } + if (StringUtils.isNotBlank(defaultValue) + && !currentnames.get(0).getValue().contentEquals(defaultValue)) { + // None of the names above matches. Set Default-Value, if it exists. Otherwise, do nothing + return updateTargetMetadata(context, item, defaultValue, true); + } + + } else { + // No Name assigned yet + // Check existing names + for (String field : relatedItemMetadataFields) { + List fieldnames = itemService.getMetadataByMetadataString(item, field); + if (fieldnames.isEmpty()) { + continue; //No Values, try next loop + } + for (MetadataValue fieldname : fieldnames) { + if (StringUtils.isNotBlank(fieldname.getValue())) { + //Got some value + return updateTargetMetadata(context, item, fieldname.getValue(), false); + } + } + } + // If no name exist, set defaultvalue + if (StringUtils.isNotBlank(defaultValue)) { + return updateTargetMetadata(context, item, defaultValue, false); + } + // otherwise do not assign any value + } + return false; + } + + /** + * Update/Set the target metadata with option to clear/delete previous metadatavalues + * @param context current Context + * @param item item to set metadatavalue + * @param value value to set + * @param clear clear/delete existing values byfore + * @return boolean value if the value has been updated successfully + * @throws SQLException when some error occurs + */ + private boolean updateTargetMetadata(Context context, Item item, String value, boolean clear) throws SQLException { + MetadataField targetmd = metadatafieldService.findByString(context, targetItemMetadataField, '.'); + if (targetmd != null) { + if (clear) { + itemService.clearMetadata(context, item, targetmd.getMetadataSchema().getName(), targetmd.getElement(), + targetmd.getQualifier(), Item.ANY); + } + itemService.addMetadata(context, item, targetmd, null, value); + return true; + } else { + LOGGER.error("No valid metadatavalue to enhance specified"); + } + return false; + } + + public void setSourceEntityType(String sourceEntityType) { + this.sourceEntityType = sourceEntityType; + } + + public void setTargetItemMetadataField(String targetItemMetadataField) { + this.targetItemMetadataField = targetItemMetadataField; + } + + public void setRelatedItemMetadataFields(List relatedItemMetadataFields) { + this.relatedItemMetadataFields = relatedItemMetadataFields; + } + + public void setDefaultValue(String defaultvalue) { + this.defaultValue = defaultvalue; + } + +} + diff --git a/dspace-api/src/test/java/org/dspace/content/enhancer/script/ItemEnhancerScriptIT.java b/dspace-api/src/test/java/org/dspace/content/enhancer/script/ItemEnhancerScriptIT.java index 33913368b0a1..b95242910f44 100644 --- a/dspace-api/src/test/java/org/dspace/content/enhancer/script/ItemEnhancerScriptIT.java +++ b/dspace-api/src/test/java/org/dspace/content/enhancer/script/ItemEnhancerScriptIT.java @@ -58,6 +58,7 @@ public class ItemEnhancerScriptIT extends AbstractIntegrationTestWithDatabase { private Collection collection; + private Collection persons; /** * This method will be run before the first test as per @BeforeClass. It will @@ -100,6 +101,12 @@ public void setup() { collection = CollectionBuilder.createCollection(context, parentCommunity) .withName("Collection") .build(); + + persons = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection") + .withEntityType("Person") + .build(); + context.restoreAuthSystemState(); } @@ -321,6 +328,70 @@ public void testItemEnhancementWithForce() throws Exception { } + @Test + public void testItemEnhancementNameWithoutForce() throws Exception { + + context.turnOffAuthorisationSystem(); + + Item firstPerson = ItemBuilder.createItem(context, persons) + .withMetadata("crisrp", "name", null, "Walter White") + .build(); + + Item secondPerson = ItemBuilder.createItem(context, persons) + .withMetadata("crisrp", "name", null, "Alois White") + .withMetadata("crisrp", "name", "translated", "Alois W. White") + .build(); + + Item thirdPerson = ItemBuilder.createItem(context, persons) + .withMetadata("crisrp", "name", "translated", "Walt Alternative") + .build(); + + context.commit(); + + + assertThat(getMetadataValues(firstPerson, "dc.title"), empty()); + assertThat(getMetadataValues(secondPerson, "dc.title"), empty()); + assertThat(getMetadataValues(thirdPerson, "dc.title"), empty()); + + TestDSpaceRunnableHandler runnableHandler = runScript(false); + + assertThat(runnableHandler.getErrorMessages(), empty()); + assertThat(runnableHandler.getInfoMessages(), hasItem("Enhancement completed with success")); + + firstPerson = reload(firstPerson); + secondPerson = reload(secondPerson); + thirdPerson = reload(thirdPerson); + + assertThat(getMetadataValues(firstPerson, "dc.title"), hasSize(1)); + assertThat(getMetadataValues(secondPerson, "dc.title"), hasSize(1)); + assertThat(getMetadataValues(thirdPerson, "dc.title"), hasSize(1)); + + assertThat(firstPerson.getMetadata(), hasItem(with("dc.title", "Walter White"))); + assertThat(secondPerson.getMetadata(), hasItem(with("dc.title", "Alois White"))); + assertThat(thirdPerson.getMetadata(), hasItem(with("dc.title", "Walt Alternative"))); + + context.turnOffAuthorisationSystem(); + + MetadataValue nameToRemove = getMetadataValues(secondPerson, "crisrp.name").get(0); + itemService.removeMetadataValues(context, secondPerson, List.of(nameToRemove)); + + replaceMetadata(thirdPerson, "crisrp", "name", "translated", "Walt D. Alternative"); + + context.restoreAuthSystemState(); + + runnableHandler = runScript(false); + assertThat(runnableHandler.getErrorMessages(), empty()); + assertThat(runnableHandler.getInfoMessages(), hasItem("Enhancement completed with success")); + + firstPerson = reload(firstPerson); + secondPerson = reload(secondPerson); + thirdPerson = reload(thirdPerson); + + assertThat(firstPerson.getMetadata(), hasItem(with("dc.title", "Walter White"))); + assertThat(secondPerson.getMetadata(), hasItem(with("dc.title", "Alois W. White"))); + assertThat(thirdPerson.getMetadata(), hasItem(with("dc.title", "Walt D. Alternative"))); + } + @Test public void testItemEnhancementMetadataPositions() throws Exception { diff --git a/dspace/config/spring/api/metadata-enhancers.xml b/dspace/config/spring/api/metadata-enhancers.xml index e36727959c25..d52c9669988b 100644 --- a/dspace/config/spring/api/metadata-enhancers.xml +++ b/dspace/config/spring/api/metadata-enhancers.xml @@ -57,6 +57,20 @@ - + + + + + + + + crisrp.name + crisrp.name.translated + crisrp.name.variants + + + + +