From 10b86d0b521fec13a172cf428d70fe2e09b2efde Mon Sep 17 00:00:00 2001 From: Eva Roddeck Date: Wed, 18 Sep 2024 12:55:13 +0200 Subject: [PATCH 01/16] first implementation --- .../merger/MCRCategoryMergeEventHandler.java | 63 +++++++ .../MCRCategoryMergeEventHandlerTest.java | 67 ++++++++ .../genre.xml | 157 ++++++++++++++++++ .../testMods.xml | 19 +++ 4 files changed, 306 insertions(+) create mode 100644 mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMergeEventHandler.java create mode 100644 mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/genre.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/testMods.xml diff --git a/mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMergeEventHandler.java b/mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMergeEventHandler.java new file mode 100644 index 0000000000..c8d88ad8ec --- /dev/null +++ b/mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMergeEventHandler.java @@ -0,0 +1,63 @@ +package org.mycore.mods.merger; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jdom2.Element; +import org.mycore.common.MCRConstants; +import org.mycore.common.events.MCREvent; +import org.mycore.common.events.MCREventHandlerBase; +import org.mycore.datamodel.metadata.MCRObject; +import org.mycore.mods.MCRMODSSorter; +import org.mycore.mods.MCRMODSWrapper; +import org.mycore.mods.classification.MCRClassMapper; + +import java.util.List; + +/** + * Checks for and removes redundant classifications in Mods-Documents. If a classification category and + * the classification's child category are both present in the document, the parent classification will + * be removed. The processed document will be finally be sorted using {@link MCRMODSSorter}. + */ +public class MCRCategoryMergeEventHandler extends MCREventHandlerBase { + + private static final Logger LOGGER = LogManager.getLogger(MCRCategoryMergeEventHandler.class); + + @Override + protected void handleObjectCreated(MCREvent evt, MCRObject obj) { + mergeCategories(obj); + } + + @Override + protected void handleObjectUpdated(MCREvent evt, MCRObject obj) { + mergeCategories(obj); + } + + @Override + protected void handleObjectRepaired(MCREvent evt, MCRObject obj) { + mergeCategories(obj); + } + + private void mergeCategories(MCRObject obj) { + MCRMODSWrapper mcrmodsWrapper = new MCRMODSWrapper(obj); + if (mcrmodsWrapper.getMODS() == null) { + return; + } + LOGGER.info("merge redundant classification categories for {}", obj.getId()); + + Element filledMods = mcrmodsWrapper.getMODS(); + Element emtpyMods = new Element("mods", MCRConstants.MODS_NAMESPACE); + + List supportedElements = filledMods.getChildren().stream() + .filter(element -> MCRClassMapper.getCategoryID(element) != null).toList(); + supportedElements.forEach(Element::detach); + + for (Element testedElement : supportedElements) { + emtpyMods.addContent(testedElement); + MCRMergeTool.merge(filledMods, emtpyMods); + + emtpyMods = new Element("mods", MCRConstants.MODS_NAMESPACE); + } + + MCRMODSSorter.sort(filledMods); + } +} diff --git a/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java b/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java new file mode 100644 index 0000000000..708852cd61 --- /dev/null +++ b/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java @@ -0,0 +1,67 @@ +package org.mycore.mods.merger; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jdom2.Document; +import org.jdom2.JDOMException; +import org.jdom2.input.SAXBuilder; +import org.junit.Test; +import org.mycore.common.MCRJPATestCase; +import org.mycore.common.MCRSessionMgr; +import org.mycore.common.MCRTransactionHelper; +import org.mycore.common.content.MCRJDOMContent; +import org.mycore.datamodel.classifications2.MCRCategory; +import org.mycore.datamodel.classifications2.MCRCategoryDAO; +import org.mycore.datamodel.classifications2.MCRCategoryDAOFactory; +import org.mycore.datamodel.classifications2.utils.MCRXMLTransformer; +import org.mycore.datamodel.metadata.MCRObject; +import org.mycore.mods.MCRMODSWrapper; + +import java.io.IOException; +import java.net.URISyntaxException; + +public class MCRCategoryMergeEventHandlerTest extends MCRJPATestCase { + + public static final String TEST_DIRECTORY = "MCRCategoryMergeEventHandlerTest/"; + + private static final Logger LOGGER = LogManager.getLogger(); + + public MCRCategoryDAO getDAO() { + return MCRCategoryDAOFactory.getInstance(); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + } + + /** + * Test has no assertions yet, only logs final mods. + * TODO: Current implementation changes order of genres, fix? + */ + @Test + public void testHandleObjectCreatedMultipleGenres() throws IOException, JDOMException, URISyntaxException { + + MCRSessionMgr.getCurrentSession(); + MCRTransactionHelper.isTransactionActive(); + ClassLoader classLoader = getClass().getClassLoader(); + SAXBuilder saxBuilder = new SAXBuilder(); + + MCRCategory category = MCRXMLTransformer + .getCategory(saxBuilder.build(classLoader.getResourceAsStream(TEST_DIRECTORY + "genre.xml"))); + getDAO().addCategory(null, category); + + Document document = saxBuilder.build(classLoader.getResourceAsStream(TEST_DIRECTORY + "testMods.xml")); + MCRObject mcro = new MCRObject(); + + MCRMODSWrapper mw = new MCRMODSWrapper(mcro); + mw.setMODS(document.getRootElement().detach()); + mw.setID("junit", 1); + + MCRCategoryMergeEventHandler mergeEventHandler = new MCRCategoryMergeEventHandler(); + mergeEventHandler.handleObjectCreated(null, mcro); + Document xml = mcro.createXML(); + + LOGGER.info(new MCRJDOMContent(xml).asString()); + } +} diff --git a/mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/genre.xml b/mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/genre.xml new file mode 100644 index 0000000000..1b1db0da7a --- /dev/null +++ b/mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/genre.xml @@ -0,0 +1,157 @@ + + + diff --git a/mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/testMods.xml b/mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/testMods.xml new file mode 100644 index 0000000000..b907e2fe3a --- /dev/null +++ b/mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/testMods.xml @@ -0,0 +1,19 @@ + + + + + + + + Test-Titel + + + 000 + + + + de + + cc_by-nc + text + From 08a24cd38ef55d4242097d6959353d74adfb4aaa Mon Sep 17 00:00:00 2001 From: Eva Roddeck Date: Tue, 24 Sep 2024 16:51:22 +0200 Subject: [PATCH 02/16] Alternative implementation that keeps Element order intact --- .../org/mycore/common/xml/MCRURIResolver.java | 3 +- .../merger/MCRCategoryMergeEventHandler.java | 17 +++++----- .../mycore/mods/merger/MCRCategoryMerger.java | 32 ++++++++++++++++++- .../MCRCategoryMergeEventHandlerTest.java | 19 +++++++++-- .../testMods.xml | 2 +- 5 files changed, 60 insertions(+), 13 deletions(-) diff --git a/mycore-base/src/main/java/org/mycore/common/xml/MCRURIResolver.java b/mycore-base/src/main/java/org/mycore/common/xml/MCRURIResolver.java index 6523dee9e2..ed0061cc46 100644 --- a/mycore-base/src/main/java/org/mycore/common/xml/MCRURIResolver.java +++ b/mycore-base/src/main/java/org/mycore/common/xml/MCRURIResolver.java @@ -32,6 +32,7 @@ import java.nio.file.Paths; import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -1026,7 +1027,7 @@ public Source resolve(String href, String base) { } } catch (Exception ex) { LOGGER.info("MCRNotNullResolver caught exception: {}", ex.getLocalizedMessage()); - LOGGER.debug(ex.getStackTrace()); + LOGGER.debug(Arrays.toString(ex.getStackTrace())); LOGGER.debug("MCRNotNullResolver returning empty xml"); return new JDOMSource(new Element("null")); } diff --git a/mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMergeEventHandler.java b/mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMergeEventHandler.java index c8d88ad8ec..6c2417a723 100644 --- a/mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMergeEventHandler.java +++ b/mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMergeEventHandler.java @@ -3,7 +3,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jdom2.Element; -import org.mycore.common.MCRConstants; import org.mycore.common.events.MCREvent; import org.mycore.common.events.MCREventHandlerBase; import org.mycore.datamodel.metadata.MCRObject; @@ -45,17 +44,19 @@ private void mergeCategories(MCRObject obj) { LOGGER.info("merge redundant classification categories for {}", obj.getId()); Element filledMods = mcrmodsWrapper.getMODS(); - Element emtpyMods = new Element("mods", MCRConstants.MODS_NAMESPACE); - List supportedElements = filledMods.getChildren().stream() .filter(element -> MCRClassMapper.getCategoryID(element) != null).toList(); - supportedElements.forEach(Element::detach); - for (Element testedElement : supportedElements) { - emtpyMods.addContent(testedElement); - MCRMergeTool.merge(filledMods, emtpyMods); + for (int i = 0; i < supportedElements.size(); i++) { + for (int j = i + 1; j < supportedElements.size(); j++) { - emtpyMods = new Element("mods", MCRConstants.MODS_NAMESPACE); + Element element1 = supportedElements.get(i); + Element element2 = supportedElements.get(j); + Element parentElement = MCRCategoryMerger.getElementWithParentCategory(element1, element2); + if (parentElement != null) { + parentElement.detach(); + } + } } MCRMODSSorter.sort(filledMods); diff --git a/mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMerger.java b/mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMerger.java index 7eba441538..f229b61c00 100644 --- a/mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMerger.java +++ b/mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMerger.java @@ -19,8 +19,11 @@ package org.mycore.mods.merger; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Optional; +import org.jdom2.Element; import org.mycore.common.config.MCRConfiguration2; import org.mycore.datamodel.classifications2.MCRCategory; import org.mycore.datamodel.classifications2.MCRCategoryDAO; @@ -88,12 +91,39 @@ static boolean oneIsDescendantOfTheOther(MCRCategoryID idThis, MCRCategoryID idO } private static List getAncestorsAndSelf(MCRCategoryID categoryID) { - List ancestorsAndSelf = new ArrayList<>(DAO.getParents(categoryID)); + List ancestorsAndSelf = new ArrayList<>(Optional.ofNullable(DAO.getParents(categoryID)).orElse( + Collections.emptyList())); ancestorsAndSelf.remove(DAO.getRootCategory(categoryID, 0)); ancestorsAndSelf.add(DAO.getCategory(categoryID, 0)); return ancestorsAndSelf; } + /** + * Compares two {@link Element Elements} that are assumed to be categories. + * If it is determined that one Element is a parent category of the other, return the parent, else return null. + * @param element1 first Element to compare + * @param element2 second Element to compare + * @return the parent Element or null + */ + public static Element getElementWithParentCategory(Element element1, Element element2) { + MCRCategoryID idThis = MCRClassMapper.getCategoryID(element1); + MCRCategoryID idOther = MCRClassMapper.getCategoryID(element2); + if (idThis == null || idOther == null) { + return null; + } + + final String p = CONFIG_PREFIX + idThis.getRootID(); + if (idThis.getRootID().equals(idOther.getRootID()) && !MCRConfiguration2.getBoolean(p).orElse(true)) { + return null; + } + + if (idThis.equals(idOther) || !oneIsDescendantOfTheOther(idThis, idOther)) { + return null; + } + + return getAncestorsAndSelf(idThis).containsAll(getAncestorsAndSelf(idOther)) ? element2 : element1; + } + @Override public void mergeFrom(MCRMerger other) { MCRCategoryMerger cmo = (MCRCategoryMerger) other; diff --git a/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java b/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java index 708852cd61..777a4e43df 100644 --- a/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java +++ b/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java @@ -2,10 +2,13 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jdom2.Attribute; import org.jdom2.Document; +import org.jdom2.Element; import org.jdom2.JDOMException; import org.jdom2.input.SAXBuilder; import org.junit.Test; +import org.mycore.common.MCRConstants; import org.mycore.common.MCRJPATestCase; import org.mycore.common.MCRSessionMgr; import org.mycore.common.MCRTransactionHelper; @@ -19,6 +22,9 @@ import java.io.IOException; import java.net.URISyntaxException; +import java.util.List; + +import static org.junit.Assert.assertEquals; public class MCRCategoryMergeEventHandlerTest extends MCRJPATestCase { @@ -36,8 +42,7 @@ public void setUp() throws Exception { } /** - * Test has no assertions yet, only logs final mods. - * TODO: Current implementation changes order of genres, fix? + * Tests if parent genres are succesfully removed from mods. */ @Test public void testHandleObjectCreatedMultipleGenres() throws IOException, JDOMException, URISyntaxException { @@ -63,5 +68,15 @@ public void testHandleObjectCreatedMultipleGenres() throws IOException, JDOMExce Document xml = mcro.createXML(); LOGGER.info(new MCRJDOMContent(xml).asString()); + + List genres = mw.getMODS().getChildren("genre", MCRConstants.MODS_NAMESPACE); + assertEquals(2, genres.size()); + String url = genres.get(0).getAttribute("valueURI").getValue(); + String genre = url.substring(url.indexOf('#') + 1); + assertEquals("book", genre); + + url = genres.get(1).getAttribute("valueURI").getValue(); + genre = url.substring(url.indexOf('#') + 1); + assertEquals("subchapter", genre); } } diff --git a/mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/testMods.xml b/mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/testMods.xml index b907e2fe3a..2be71a3e24 100644 --- a/mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/testMods.xml +++ b/mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/testMods.xml @@ -9,7 +9,7 @@ 000 - + de From b3d072acbbb8ccb7555ac03fa415ec3268d4312c Mon Sep 17 00:00:00 2001 From: Eva Roddeck Date: Wed, 25 Sep 2024 11:02:14 +0200 Subject: [PATCH 03/16] unused import --- .../org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java b/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java index 777a4e43df..eeb37f48bf 100644 --- a/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java +++ b/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java @@ -2,7 +2,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.jdom2.Attribute; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.JDOMException; From b4f0a3c4d35591f7ef78c36ccd7e053862e70404 Mon Sep 17 00:00:00 2001 From: Eva Roddeck Date: Wed, 9 Oct 2024 14:58:25 +0200 Subject: [PATCH 04/16] Config for new MCRCategoryMergeEventHandler --- .../src/main/resources/components/mods/config/mycore.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/mycore-mods/src/main/resources/components/mods/config/mycore.properties b/mycore-mods/src/main/resources/components/mods/config/mycore.properties index d5198c4937..87d6b53a4c 100644 --- a/mycore-mods/src/main/resources/components/mods/config/mycore.properties +++ b/mycore-mods/src/main/resources/components/mods/config/mycore.properties @@ -1,6 +1,7 @@ MCR.Metadata.Type.mods=true MCR.Metadata.ShareAgent.mods=org.mycore.mods.MCRMODSMetadataShareAgent MCR.EventHandler.MCRObject.040.Class=org.mycore.mods.MCRMODSLinksEventHandler +MCR.EventHandler.MCRObject.016a.Class=org.mycore.mods.merger.MCRCategoryMergeEventHandler MCR.MODS.NewObjectType=mods MCR.MODS.Types=mods From a27dbc0a8deb8e02c34d804342d9555bd5e0c4b3 Mon Sep 17 00:00:00 2001 From: Eva Roddeck Date: Tue, 22 Oct 2024 14:03:05 +0200 Subject: [PATCH 05/16] MCR-3198 keep EventHandler deactivated --- .../src/main/resources/components/mods/config/mycore.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mycore-mods/src/main/resources/components/mods/config/mycore.properties b/mycore-mods/src/main/resources/components/mods/config/mycore.properties index 87d6b53a4c..878506401d 100644 --- a/mycore-mods/src/main/resources/components/mods/config/mycore.properties +++ b/mycore-mods/src/main/resources/components/mods/config/mycore.properties @@ -1,7 +1,7 @@ MCR.Metadata.Type.mods=true MCR.Metadata.ShareAgent.mods=org.mycore.mods.MCRMODSMetadataShareAgent MCR.EventHandler.MCRObject.040.Class=org.mycore.mods.MCRMODSLinksEventHandler -MCR.EventHandler.MCRObject.016a.Class=org.mycore.mods.merger.MCRCategoryMergeEventHandler +# MCR.EventHandler.MCRObject.016a.Class=org.mycore.mods.merger.MCRCategoryMergeEventHandler MCR.MODS.NewObjectType=mods MCR.MODS.Types=mods From 237406bf759c047b96674f31baff764ff8ccc040 Mon Sep 17 00:00:00 2001 From: Eva Roddeck Date: Thu, 24 Oct 2024 12:59:46 +0200 Subject: [PATCH 06/16] corrected debug logging --- .../src/main/java/org/mycore/common/xml/MCRURIResolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mycore-base/src/main/java/org/mycore/common/xml/MCRURIResolver.java b/mycore-base/src/main/java/org/mycore/common/xml/MCRURIResolver.java index ed0061cc46..5a37fe0700 100644 --- a/mycore-base/src/main/java/org/mycore/common/xml/MCRURIResolver.java +++ b/mycore-base/src/main/java/org/mycore/common/xml/MCRURIResolver.java @@ -1027,7 +1027,7 @@ public Source resolve(String href, String base) { } } catch (Exception ex) { LOGGER.info("MCRNotNullResolver caught exception: {}", ex.getLocalizedMessage()); - LOGGER.debug(Arrays.toString(ex.getStackTrace())); + LOGGER.debug(ex); LOGGER.debug("MCRNotNullResolver returning empty xml"); return new JDOMSource(new Element("null")); } From a56ad50e67e4b4681146c0e5db9fb819d8f5f7c4 Mon Sep 17 00:00:00 2001 From: Eva Roddeck Date: Thu, 24 Oct 2024 13:21:42 +0200 Subject: [PATCH 07/16] MCR-3198 codestyle --- .../src/main/java/org/mycore/common/xml/MCRURIResolver.java | 1 - 1 file changed, 1 deletion(-) diff --git a/mycore-base/src/main/java/org/mycore/common/xml/MCRURIResolver.java b/mycore-base/src/main/java/org/mycore/common/xml/MCRURIResolver.java index 5a37fe0700..809f13e389 100644 --- a/mycore-base/src/main/java/org/mycore/common/xml/MCRURIResolver.java +++ b/mycore-base/src/main/java/org/mycore/common/xml/MCRURIResolver.java @@ -32,7 +32,6 @@ import java.nio.file.Paths; import java.time.Instant; import java.time.temporal.ChronoUnit; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; From 8a0af2f300ae4683b062c2a867d315c00dd6c377 Mon Sep 17 00:00:00 2001 From: Eva Roddeck Date: Fri, 29 Nov 2024 12:03:39 +0100 Subject: [PATCH 08/16] MCR-3198 fixed test case --- .../merger/MCRCategoryMergeEventHandlerTest.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java b/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java index eeb37f48bf..8c30aaad21 100644 --- a/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java +++ b/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java @@ -9,8 +9,6 @@ import org.junit.Test; import org.mycore.common.MCRConstants; import org.mycore.common.MCRJPATestCase; -import org.mycore.common.MCRSessionMgr; -import org.mycore.common.MCRTransactionHelper; import org.mycore.common.content.MCRJDOMContent; import org.mycore.datamodel.classifications2.MCRCategory; import org.mycore.datamodel.classifications2.MCRCategoryDAO; @@ -18,6 +16,7 @@ import org.mycore.datamodel.classifications2.utils.MCRXMLTransformer; import org.mycore.datamodel.metadata.MCRObject; import org.mycore.mods.MCRMODSWrapper; +import org.mycore.resource.MCRResourceHelper; import java.io.IOException; import java.net.URISyntaxException; @@ -41,21 +40,18 @@ public void setUp() throws Exception { } /** - * Tests if parent genres are succesfully removed from mods. + * Tests if parent genres are successfully removed from mods. */ @Test public void testHandleObjectCreatedMultipleGenres() throws IOException, JDOMException, URISyntaxException { - MCRSessionMgr.getCurrentSession(); - MCRTransactionHelper.isTransactionActive(); - ClassLoader classLoader = getClass().getClassLoader(); SAXBuilder saxBuilder = new SAXBuilder(); MCRCategory category = MCRXMLTransformer - .getCategory(saxBuilder.build(classLoader.getResourceAsStream(TEST_DIRECTORY + "genre.xml"))); + .getCategory(saxBuilder.build(MCRResourceHelper.getResourceAsStream(TEST_DIRECTORY + "genre.xml"))); getDAO().addCategory(null, category); - Document document = saxBuilder.build(classLoader.getResourceAsStream(TEST_DIRECTORY + "testMods.xml")); + Document document = saxBuilder.build(MCRResourceHelper.getResourceAsStream(TEST_DIRECTORY + "testMods.xml")); MCRObject mcro = new MCRObject(); MCRMODSWrapper mw = new MCRMODSWrapper(mcro); @@ -70,7 +66,7 @@ public void testHandleObjectCreatedMultipleGenres() throws IOException, JDOMExce List genres = mw.getMODS().getChildren("genre", MCRConstants.MODS_NAMESPACE); assertEquals(2, genres.size()); - String url = genres.get(0).getAttribute("valueURI").getValue(); + String url = genres.getFirst().getAttribute("valueURI").getValue(); String genre = url.substring(url.indexOf('#') + 1); assertEquals("book", genre); From bda8aede5e85ac35d9fc8cd2a907d248f86b2520 Mon Sep 17 00:00:00 2001 From: Eva Roddeck Date: Fri, 29 Nov 2024 16:39:51 +0100 Subject: [PATCH 09/16] MCR-3198 load all child-elements of mods recursively + added proposed test cases --- .../merger/MCRCategoryMergeEventHandler.java | 15 +- .../MCRCategoryMergeEventHandlerTest.java | 330 ++++++++++++++++-- .../genre.xml | 158 +-------- .../marcrelator.xml | 14 + .../mir_licenses.xml | 13 + .../modsAccessConditionsDifferingType.xml | 7 + .../modsAccessConditionsSameType.xml | 7 + .../modsClassificationDifferingAuthority.xml | 7 + ...ssificationSameAuthorityDifferingLabel.xml | 7 + ...dsClassificationSameAuthoritySameLabel.xml | 7 + .../modsGenresAscending.xml | 7 + .../modsGenresDescending.xml | 7 + .../modsGenresInRelatedItem.xml | 9 + .../modsLanguageTermsDifferingLanguage.xml | 15 + .../modsLanguageTermsInRelatedItem.xml | 11 + .../modsLanguageTermsSameLanguage.xml | 9 + .../modsRoleTermDifferingName.xml | 27 ++ .../modsRoleTermsSameNameDifferingRole.xml | 18 + .../modsRoleTermsSameNameSameRole.xml | 12 + .../modsTypesOfResource.xml | 7 + .../rfc5646.xml | 13 + .../MCRCategoryMergeEventHandlerTest/sdnb.xml | 14 + .../sdnb2.xml | 14 + .../sdnb3.xml | 14 + .../testMods.xml | 19 - .../typeOfResource.xml | 13 + 26 files changed, 570 insertions(+), 204 deletions(-) create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/marcrelator.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/mir_licenses.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/modsAccessConditionsDifferingType.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/modsAccessConditionsSameType.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/modsClassificationDifferingAuthority.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/modsClassificationSameAuthorityDifferingLabel.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/modsClassificationSameAuthoritySameLabel.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/modsGenresAscending.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/modsGenresDescending.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/modsGenresInRelatedItem.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/modsLanguageTermsDifferingLanguage.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/modsLanguageTermsInRelatedItem.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/modsLanguageTermsSameLanguage.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/modsRoleTermDifferingName.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/modsRoleTermsSameNameDifferingRole.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/modsRoleTermsSameNameSameRole.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/modsTypesOfResource.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/rfc5646.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/sdnb.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/sdnb2.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/sdnb3.xml delete mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/testMods.xml create mode 100644 mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/typeOfResource.xml diff --git a/mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMergeEventHandler.java b/mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMergeEventHandler.java index 6c2417a723..d80d13870b 100644 --- a/mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMergeEventHandler.java +++ b/mycore-mods/src/main/java/org/mycore/mods/merger/MCRCategoryMergeEventHandler.java @@ -11,6 +11,7 @@ import org.mycore.mods.classification.MCRClassMapper; import java.util.List; +import java.util.ArrayList; /** * Checks for and removes redundant classifications in Mods-Documents. If a classification category and @@ -36,6 +37,17 @@ protected void handleObjectRepaired(MCREvent evt, MCRObject obj) { mergeCategories(obj); } + public static List getAllDescendants(Element element) { + List descendants = new ArrayList<>(); + + for (Element child : element.getChildren()) { + descendants.add(child); + descendants.addAll(getAllDescendants(child)); + } + + return descendants; + } + private void mergeCategories(MCRObject obj) { MCRMODSWrapper mcrmodsWrapper = new MCRMODSWrapper(obj); if (mcrmodsWrapper.getMODS() == null) { @@ -44,7 +56,8 @@ private void mergeCategories(MCRObject obj) { LOGGER.info("merge redundant classification categories for {}", obj.getId()); Element filledMods = mcrmodsWrapper.getMODS(); - List supportedElements = filledMods.getChildren().stream() + List supportedElements = getAllDescendants(filledMods).stream() + //List supportedElements = filledMods.getChildren().stream() .filter(element -> MCRClassMapper.getCategoryID(element) != null).toList(); for (int i = 0; i < supportedElements.size(); i++) { diff --git a/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java b/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java index 8c30aaad21..b699634558 100644 --- a/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java +++ b/mycore-mods/src/test/java/org/mycore/mods/merger/MCRCategoryMergeEventHandlerTest.java @@ -1,5 +1,9 @@ package org.mycore.mods.merger; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mycore.common.MCRConstants.MODS_NAMESPACE; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jdom2.Document; @@ -7,10 +11,8 @@ import org.jdom2.JDOMException; import org.jdom2.input.SAXBuilder; import org.junit.Test; -import org.mycore.common.MCRConstants; import org.mycore.common.MCRJPATestCase; import org.mycore.common.content.MCRJDOMContent; -import org.mycore.datamodel.classifications2.MCRCategory; import org.mycore.datamodel.classifications2.MCRCategoryDAO; import org.mycore.datamodel.classifications2.MCRCategoryDAOFactory; import org.mycore.datamodel.classifications2.utils.MCRXMLTransformer; @@ -19,59 +21,321 @@ import org.mycore.resource.MCRResourceHelper; import java.io.IOException; -import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.assertEquals; - public class MCRCategoryMergeEventHandlerTest extends MCRJPATestCase { public static final String TEST_DIRECTORY = "MCRCategoryMergeEventHandlerTest/"; private static final Logger LOGGER = LogManager.getLogger(); - public MCRCategoryDAO getDAO() { - return MCRCategoryDAOFactory.getInstance(); - } - @Override public void setUp() throws Exception { super.setUp(); + + MCRCategoryDAO categoryDao = MCRCategoryDAOFactory.getInstance(); + categoryDao.addCategory(null, MCRXMLTransformer.getCategory(loadXml("genre.xml"))); + categoryDao.addCategory(null, MCRXMLTransformer.getCategory(loadXml("rfc5646.xml"))); + categoryDao.addCategory(null, MCRXMLTransformer.getCategory(loadXml("mir_licenses.xml"))); + categoryDao.addCategory(null, MCRXMLTransformer.getCategory(loadXml("typeOfResource.xml"))); + categoryDao.addCategory(null, MCRXMLTransformer.getCategory(loadXml("marcrelator.xml"))); + categoryDao.addCategory(null, MCRXMLTransformer.getCategory(loadXml("sdnb.xml"))); + categoryDao.addCategory(null, MCRXMLTransformer.getCategory(loadXml("sdnb2.xml"))); + categoryDao.addCategory(null, MCRXMLTransformer.getCategory(loadXml("sdnb3.xml"))); + + } + + private Element loadMods(String fileName) throws Exception { + + MCRObject object = new MCRObject(); + Document modsDocument = loadXml(fileName); + + MCRMODSWrapper modsWrapper = new MCRMODSWrapper(object); + modsWrapper.setMODS(modsDocument.getRootElement().detach()); + modsWrapper.setID("junit", 1); + + MCRCategoryMergeEventHandler mergeEventHandler = new MCRCategoryMergeEventHandler(); + mergeEventHandler.handleObjectCreated(null, object); + + LOGGER.info(new MCRJDOMContent(modsWrapper.getMODS()).asString()); + + return modsWrapper.getMODS(); + + } + + private static Document loadXml(String fileName) throws JDOMException, IOException { + return new SAXBuilder().build(MCRResourceHelper.getResourceAsStream(TEST_DIRECTORY + fileName)); } - /** - * Tests if parent genres are successfully removed from mods. - */ @Test - public void testHandleObjectCreatedMultipleGenres() throws IOException, JDOMException, URISyntaxException { + public void redundantGenresAreRemovedAscending() throws Exception { - SAXBuilder saxBuilder = new SAXBuilder(); + Element mods = loadMods("modsGenresAscending.xml"); - MCRCategory category = MCRXMLTransformer - .getCategory(saxBuilder.build(MCRResourceHelper.getResourceAsStream(TEST_DIRECTORY + "genre.xml"))); - getDAO().addCategory(null, category); + List genres = mods.getChildren("genre", MODS_NAMESPACE); + + assertEquals(2, genres.size()); + assertEquals("x-1-1", getCategoryIdFromValueUri(genres.get(0))); + assertEquals("y", getCategoryIdFromValueUri(genres.get(1))); - Document document = saxBuilder.build(MCRResourceHelper.getResourceAsStream(TEST_DIRECTORY + "testMods.xml")); - MCRObject mcro = new MCRObject(); + } - MCRMODSWrapper mw = new MCRMODSWrapper(mcro); - mw.setMODS(document.getRootElement().detach()); - mw.setID("junit", 1); + @Test + public void redundantGenresAreRemovedDescending() throws Exception { - MCRCategoryMergeEventHandler mergeEventHandler = new MCRCategoryMergeEventHandler(); - mergeEventHandler.handleObjectCreated(null, mcro); - Document xml = mcro.createXML(); + Element mods = loadMods("modsGenresDescending.xml"); - LOGGER.info(new MCRJDOMContent(xml).asString()); + List genres = mods.getChildren("genre", MODS_NAMESPACE); - List genres = mw.getMODS().getChildren("genre", MCRConstants.MODS_NAMESPACE); assertEquals(2, genres.size()); - String url = genres.getFirst().getAttribute("valueURI").getValue(); - String genre = url.substring(url.indexOf('#') + 1); - assertEquals("book", genre); + assertEquals("y", getCategoryIdFromValueUri(genres.get(0))); + assertEquals("x-1-1", getCategoryIdFromValueUri(genres.get(1))); + + } + + @Test + public void redundantGenresInRelatedItemAreKept() throws Exception { + + Element mods = loadMods("modsGenresInRelatedItem.xml"); + + Element relatedItem = mods.getChildren("relatedItem", MODS_NAMESPACE).getFirst(); + List genres = relatedItem.getChildren("genre", MODS_NAMESPACE); + + assertEquals(4, genres.size()); + assertEquals("x", getCategoryIdFromValueUri(genres.get(0))); + assertEquals("x-1", getCategoryIdFromValueUri(genres.get(1))); + assertEquals("x-1-1", getCategoryIdFromValueUri(genres.get(2))); + assertEquals("y", getCategoryIdFromValueUri(genres.get(3))); - url = genres.get(1).getAttribute("valueURI").getValue(); - genre = url.substring(url.indexOf('#') + 1); - assertEquals("subchapter", genre); } + + @Test + public void redundantLanguageTermsInSameLanguageAreRemoved() throws Exception { + + Element mods = loadMods("modsLanguageTermsSameLanguage.xml"); + + List languageTerms = new ArrayList<>(); + List languages = mods.getChildren("language", MODS_NAMESPACE); + for (Element language : languages) { + languageTerms.addAll(language.getChildren("languageTerm", MODS_NAMESPACE)); + } + + assertEquals(2, languageTerms.size()); + assertEquals("x-1-1", getCategoryIdFromTextValue(languageTerms.get(0))); + assertEquals("y", getCategoryIdFromTextValue(languageTerms.get(1))); + + } + + @Test + public void redundantLanguageTermsInDifferingLanguageAreRemoved() throws Exception { + + Element mods = loadMods("modsLanguageTermsDifferingLanguage.xml"); + + List languageTerms = new ArrayList<>(); + List languages = mods.getChildren("language", MODS_NAMESPACE); + for (Element element : languages) { + languageTerms.addAll(element.getChildren("languageTerm", MODS_NAMESPACE)); + } + + assertEquals(2, languageTerms.size()); + assertEquals("x-1-1", getCategoryIdFromTextValue(languageTerms.get(0))); + assertEquals("y", getCategoryIdFromTextValue(languageTerms.get(1))); + + for (Element language : languages) { + assertFalse(language.getChildren().isEmpty()); + } + + } + + @Test + public void redundantLanguageTermsInRelatedItemAreKept() throws Exception { + + Element mods = loadMods("modsLanguageTermsInRelatedItem.xml"); + Element relatedItem = mods.getChildren("relatedItem", MODS_NAMESPACE).getFirst(); + + List languageTerms = new ArrayList<>(); + List languages = relatedItem.getChildren("language", MODS_NAMESPACE); + for (Element element : languages) { + languageTerms.addAll(element.getChildren("languageTerm", MODS_NAMESPACE)); + } + + assertEquals(4, languageTerms.size()); + assertEquals("x", getCategoryIdFromTextValue(languageTerms.get(0))); + assertEquals("x-1", getCategoryIdFromTextValue(languageTerms.get(1))); + assertEquals("x-1-1", getCategoryIdFromTextValue(languageTerms.get(2))); + assertEquals("y", getCategoryIdFromTextValue(languageTerms.get(3))); + + } + + @Test + public void redundantAccessConditionsWithSameTypeAreRemoved() throws Exception { + + Element mods = loadMods("modsAccessConditionsSameType.xml"); + + List accessConditions = mods.getChildren("accessCondition", MODS_NAMESPACE); + + assertEquals(2, accessConditions.size()); + assertEquals("foo:x-1-1", getTypeFromAttributeAndCategoryIdFromTextValue(accessConditions.get(0))); + assertEquals("foo:y", getTypeFromAttributeAndCategoryIdFromTextValue(accessConditions.get(1))); + + } + + @Test + public void redundantAccessConditionsWithDifferingTypeAreKept() throws Exception { + + Element mods = loadMods("modsAccessConditionsDifferingType.xml"); + + List accessConditions = mods.getChildren("accessCondition", MODS_NAMESPACE); + + assertEquals(4, accessConditions.size()); + assertEquals("foo:x", getTypeFromAttributeAndCategoryIdFromTextValue(accessConditions.get(0))); + assertEquals("bar:x-1", getTypeFromAttributeAndCategoryIdFromTextValue(accessConditions.get(1))); + assertEquals("baz:x-1-1", getTypeFromAttributeAndCategoryIdFromTextValue(accessConditions.get(2))); + assertEquals("foo:y", getTypeFromAttributeAndCategoryIdFromTextValue(accessConditions.get(3))); + + } + + @Test + public void redundantTypesOfResourceAreRemoved() throws Exception { + + Element mods = loadMods("modsTypesOfResource.xml"); + + List typesOfResource = mods.getChildren("typeOfResource", MODS_NAMESPACE); + + assertEquals(2, typesOfResource.size()); + assertEquals("x-1-1", getCategoryIdFromTextValue(typesOfResource.get(0))); + assertEquals("y", getCategoryIdFromTextValue(typesOfResource.get(1))); + + } + + @Test + public void redundantRoleTermsInSameNameSameRoleAreRemoved() throws Exception { + + Element mods = loadMods("modsRoleTermsSameNameSameRole.xml"); + Element name = mods.getChildren("name", MODS_NAMESPACE).getFirst(); + + List roleTerms = new ArrayList<>(); + List roles = name.getChildren("role", MODS_NAMESPACE); + for (Element role : roles) { + roleTerms.addAll(role.getChildren("roleTerm", MODS_NAMESPACE)); + } + + assertEquals(2, roleTerms.size()); + assertEquals("foo:x-1-1", getDisplayFormFromAttributeAndCategoryIdFromTextValue(roleTerms.get(0))); + assertEquals("foo:y", getDisplayFormFromAttributeAndCategoryIdFromTextValue(roleTerms.get(1))); + + } + + @Test + public void redundantRoleTermsInSameNameDifferingRoleAreRemoved() throws Exception { + + Element mods = loadMods("modsRoleTermsSameNameDifferingRole.xml"); + Element name = mods.getChildren("name", MODS_NAMESPACE).getFirst(); + + List roleTerms = new ArrayList<>(); + List roles = name.getChildren("role", MODS_NAMESPACE); + for (Element role : roles) { + roleTerms.addAll(role.getChildren("roleTerm", MODS_NAMESPACE)); + } + + assertEquals(2, roleTerms.size()); + assertEquals("foo:x-1-1", getDisplayFormFromAttributeAndCategoryIdFromTextValue(roleTerms.get(0))); + assertEquals("foo:y", getDisplayFormFromAttributeAndCategoryIdFromTextValue(roleTerms.get(1))); + + for (Element role : roles) { + assertFalse(role.getChildren().isEmpty()); + } + + } + + @Test + public void redundantRoleTermsInDifferingNameAreKept() throws Exception { + + Element mods = loadMods("modsRoleTermDifferingName.xml"); + List names = mods.getChildren("name", MODS_NAMESPACE); + + List roleTerms = new ArrayList<>(); + for (Element name : names) { + List roles = name.getChildren("role", MODS_NAMESPACE); + for (Element role : roles) { + roleTerms.addAll(role.getChildren("roleTerm", MODS_NAMESPACE)); + } + } + + assertEquals(4, roleTerms.size()); + assertEquals("foo:x", getDisplayFormFromAttributeAndCategoryIdFromTextValue(roleTerms.get(0))); + assertEquals("bar:x-1", getDisplayFormFromAttributeAndCategoryIdFromTextValue(roleTerms.get(1))); + assertEquals("baz:x-1-1", getDisplayFormFromAttributeAndCategoryIdFromTextValue(roleTerms.get(2))); + assertEquals("foo:y", getDisplayFormFromAttributeAndCategoryIdFromTextValue(roleTerms.get(3))); + + } + + @Test + public void redundantClassificationsWithSameAuthorityAndLabelAreRemoved() throws Exception { + + Element mods = loadMods("modsClassificationSameAuthoritySameLabel.xml"); + + List classifications = mods.getChildren("classification", MODS_NAMESPACE); + + assertEquals(2, classifications.size()); + assertEquals("foo:x-1-1", getLabelFromAttributeAndCategoryIdFromTextValue(classifications.get(0))); + assertEquals("foo:y", getLabelFromAttributeAndCategoryIdFromTextValue(classifications.get(1))); + + } + + @Test + public void redundantClassificationsWithSameAuthorityAndDifferingLabelAreKept() throws Exception { + + Element mods = loadMods("modsClassificationSameAuthorityDifferingLabel.xml"); + + List classifications = mods.getChildren("classification", MODS_NAMESPACE); + + assertEquals(4, classifications.size()); + assertEquals("foo:x", getLabelFromAttributeAndCategoryIdFromTextValue(classifications.get(0))); + assertEquals("bar:x-1", getLabelFromAttributeAndCategoryIdFromTextValue(classifications.get(1))); + assertEquals("baz:x-1-1", getLabelFromAttributeAndCategoryIdFromTextValue(classifications.get(2))); + assertEquals("foo:y", getLabelFromAttributeAndCategoryIdFromTextValue(classifications.get(3))); + + } + + @Test + public void redundantClassificationsWithDifferingAuthorityAreKept() throws Exception { + + Element mods = loadMods("modsClassificationDifferingAuthority.xml"); + + List classifications = mods.getChildren("classification", MODS_NAMESPACE); + + assertEquals(4, classifications.size()); + assertEquals("foo:x", getLabelFromAttributeAndCategoryIdFromTextValue(classifications.get(0))); + assertEquals("foo:x-1", getLabelFromAttributeAndCategoryIdFromTextValue(classifications.get(1))); + assertEquals("foo:x-1-1", getLabelFromAttributeAndCategoryIdFromTextValue(classifications.get(2))); + assertEquals("foo:y", getLabelFromAttributeAndCategoryIdFromTextValue(classifications.get(3))); + + } + + + private String getCategoryIdFromValueUri(Element element) { + String uri = element.getAttribute("valueURI").getValue(); + return uri.substring(uri.indexOf('#') + 1); + } + + private String getCategoryIdFromTextValue(Element element) { + return element.getText().trim(); + } + + private String getTypeFromAttributeAndCategoryIdFromTextValue(Element element) { + return element.getAttributeValue("type") + ":" + element.getText().trim(); + } + + private String getDisplayFormFromAttributeAndCategoryIdFromTextValue(Element element) { + Element name = element.getParentElement().getParentElement(); + Element displayForm = name.getChildren("displayForm", MODS_NAMESPACE).getFirst(); + return displayForm.getText() + ":" + element.getText().trim(); + } + + private String getLabelFromAttributeAndCategoryIdFromTextValue(Element element) { + return element.getAttributeValue("displayLabel") + ":" + element.getText().trim(); + } + } diff --git a/mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/genre.xml b/mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/genre.xml index 1b1db0da7a..cc5a5aa506 100644 --- a/mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/genre.xml +++ b/mycore-mods/src/test/resources/MCRCategoryMergeEventHandlerTest/genre.xml @@ -1,157 +1,13 @@ - -