From 2403da23fd60c21d2e8db91d63b681d54964b2b7 Mon Sep 17 00:00:00 2001 From: msutya Date: Wed, 20 Mar 2024 17:27:30 +0100 Subject: [PATCH 1/5] QREPO-193 create StructuredTextExtractionFilter, add it to filter.plugins, add jackson-dataformat-xml dependency --- dspace-api/pom.xml | 6 ++ .../StructuredTextExtractionFilter.java | 74 +++++++++++++++++++ .../dspace/app/mediafilter/model/Page.java | 28 +++++++ .../dspace/app/mediafilter/model/Pages.java | 26 +++++++ dspace/config/dspace.cfg | 8 +- 5 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 dspace-api/src/main/java/org/dspace/app/mediafilter/StructuredTextExtractionFilter.java create mode 100644 dspace-api/src/main/java/org/dspace/app/mediafilter/model/Page.java create mode 100644 dspace-api/src/main/java/org/dspace/app/mediafilter/model/Pages.java diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 97ff29e5c583..93352ce541aa 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -623,6 +623,12 @@ tika-parsers-standard-package + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + 2.11.1 + + com.maxmind.geoip2 geoip2 diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/StructuredTextExtractionFilter.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/StructuredTextExtractionFilter.java new file mode 100644 index 000000000000..3c212a0b0ab2 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/StructuredTextExtractionFilter.java @@ -0,0 +1,74 @@ +package org.dspace.app.mediafilter; + +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import org.apache.commons.lang.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.pdfbox.multipdf.Splitter; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.text.PDFTextStripper; +import org.dspace.app.mediafilter.model.Page; +import org.dspace.app.mediafilter.model.Pages; +import org.dspace.content.Item; + +public class StructuredTextExtractionFilter extends MediaFilter { + + @Override + public String getFilteredName(String oldFileName) { + return oldFileName + ".xml"; + } + + @Override + public String getBundleName() { + return "STRUCTURED_TEXT"; + } + + @Override + public String getFormatString() { + return "XML"; + } + + @Override + public String getDescription() { + return "Extracted structured text"; + } + + @Override + public InputStream getDestinationStream(final Item item, final InputStream source, final boolean verbose) + throws Exception { + String extractedText; + + PDDocument document = PDDocument.load(source); + Splitter splitter = new Splitter(); + List splitPages = splitter.split(document); + + PDFTextStripper stripper = new PDFTextStripper(); + List pageTexts = new ArrayList<>(); + + for (int i = 0; i < splitPages.size(); i++) { + Page page = new Page(i + 1, stripper.getText(splitPages.get(i))); + pageTexts.add(page); + } + + Pages pages = new Pages(pageTexts); + + XmlMapper xmlMapper = new XmlMapper(); + xmlMapper.enable(SerializationFeature.INDENT_OUTPUT); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + xmlMapper.writeValue(byteArrayOutputStream, pages); + extractedText = byteArrayOutputStream.toString(); + + if (StringUtils.isNotEmpty(extractedText)) { + return new ByteArrayInputStream(extractedText.getBytes(StandardCharsets.UTF_8)); + } + + return null; + } +} diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/model/Page.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/model/Page.java new file mode 100644 index 000000000000..25e0e0036deb --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/model/Page.java @@ -0,0 +1,28 @@ +package org.dspace.app.mediafilter.model; + +public class Page { + + private int pageNumber; + private String text; + + public Page(int pageNumber, String text) { + this.pageNumber = pageNumber; + this.text = text; + } + + public int getPageNumber() { + return pageNumber; + } + + public void setPageNumber(final int pageNumber) { + this.pageNumber = pageNumber; + } + + public String getText() { + return text; + } + + public void setText(final String text) { + this.text = text; + } +} diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/model/Pages.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/model/Pages.java new file mode 100644 index 000000000000..c75c06f0ee19 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/model/Pages.java @@ -0,0 +1,26 @@ +package org.dspace.app.mediafilter.model; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.List; + +@JacksonXmlRootElement(localName = "pages") +public class Pages { + + @JacksonXmlProperty(localName = "page") + @JacksonXmlElementWrapper(useWrapping = false) + private List pageList; + + public Pages(final List pageList) { + this.pageList = pageList; + } + + public List getPageList() { + return pageList; + } + + public void setPageList(final List page) { + this.pageList = page; + } +} diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index d38ffd64339a..1b8a71a3bf18 100644 --- a/dspace/config/dspace.cfg +++ b/dspace/config/dspace.cfg @@ -27,14 +27,15 @@ csvexport.dir = ${dspace.dir}/exports # NOTE: This URL must be accessible to all DSpace users (should not use 'localhost' in Production) # and is usually "synced" with the "rest" section in the DSpace User Interface's config.*.yml. # It corresponds to the URL that you would type into your browser to access the REST API. -dspace.server.url = http://localhost:8080/server +# 192.168.1.7 +dspace.server.url = http://10.33.0.5:8080/server # Public URL of DSpace frontend (Angular UI). May require a port number if not using standard ports (80 or 443) # DO NOT end it with '/'. # This is used by the backend to provide links in emails, RSS feeds, Sitemaps, etc. # NOTE: this URL must be accessible to all DSpace users (should not use 'localhost' in Production). # It corresponds to the URL that you would type into your browser to access the User Interface. -dspace.ui.url = http://localhost:4000 +dspace.ui.url = http://10.33.0.5:4000 # Name of the site dspace.name = DSpace at My University @@ -445,6 +446,7 @@ useProxies = true #Names of the enabled MediaFilter or FormatFilter plugins filter.plugins = Text Extractor +#filter.plugins = Structured Text Extractor filter.plugins = JPEG Thumbnail filter.plugins = PDFBox JPEG Thumbnail @@ -465,6 +467,7 @@ filter.plugins = PDFBox JPEG Thumbnail #Assign 'human-understandable' names to each filter plugin.named.org.dspace.app.mediafilter.FormatFilter = org.dspace.app.mediafilter.TikaTextExtractionFilter = Text Extractor +#plugin.named.org.dspace.app.mediafilter.FormatFilter = org.dspace.app.mediafilter.StructuredTextExtractionFilter = Structured Text Extractor plugin.named.org.dspace.app.mediafilter.FormatFilter = org.dspace.app.mediafilter.JPEGFilter = JPEG Thumbnail plugin.named.org.dspace.app.mediafilter.FormatFilter = org.dspace.app.mediafilter.BrandedPreviewJPEGFilter = Branded Preview JPEG plugin.named.org.dspace.app.mediafilter.FormatFilter = org.dspace.app.mediafilter.PDFBoxThumbnail = PDFBox JPEG Thumbnail @@ -490,6 +493,7 @@ filter.org.dspace.app.mediafilter.TikaTextExtractionFilter.inputFormats = OpenDo filter.org.dspace.app.mediafilter.TikaTextExtractionFilter.inputFormats = OpenDocument Text filter.org.dspace.app.mediafilter.TikaTextExtractionFilter.inputFormats = RTF filter.org.dspace.app.mediafilter.TikaTextExtractionFilter.inputFormats = Text +#filter.org.dspace.app.mediafilter.StructuredTextExtractionFilter.inputFormats = Adobe PDF filter.org.dspace.app.mediafilter.JPEGFilter.inputFormats = BMP, GIF, JPEG, PNG filter.org.dspace.app.mediafilter.BrandedPreviewJPEGFilter.inputFormats = BMP, GIF, JPEG, PNG filter.org.dspace.app.mediafilter.ImageMagickImageThumbnailFilter.inputFormats = BMP, GIF, PNG, JPG, TIFF, JPEG, JPEG 2000 From beb19f044cd9cb0632f0858c19a91a84631b6a14 Mon Sep 17 00:00:00 2001 From: msutya Date: Sat, 23 Mar 2024 19:55:03 +0100 Subject: [PATCH 2/5] QREPO-193 create StructuredTextExtractionFilterTest, add test pdf, update dependencies, exclude dependencies that clash with others --- dspace-api/pom.xml | 12 ++- .../StructuredTextExtractionFilterTest.java | 87 ++++++++++++++++++ .../dspace/app/mediafilter/multipage_test.pdf | Bin 0 -> 40363 bytes 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 dspace-api/src/test/java/org/dspace/app/mediafilter/StructuredTextExtractionFilterTest.java create mode 100644 dspace-api/src/test/resources/org/dspace/app/mediafilter/multipage_test.pdf diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 93352ce541aa..64bb341cee98 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -626,7 +626,17 @@ com.fasterxml.jackson.dataformat jackson-dataformat-xml - 2.11.1 + 2.12.7 + + + com.fasterxml.woodstox + woodstox-core + + + jakarta.activation + jakarta.activation-api + + diff --git a/dspace-api/src/test/java/org/dspace/app/mediafilter/StructuredTextExtractionFilterTest.java b/dspace-api/src/test/java/org/dspace/app/mediafilter/StructuredTextExtractionFilterTest.java new file mode 100644 index 000000000000..81d30a00973f --- /dev/null +++ b/dspace-api/src/test/java/org/dspace/app/mediafilter/StructuredTextExtractionFilterTest.java @@ -0,0 +1,87 @@ +package org.dspace.app.mediafilter; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import org.dspace.content.Item; +import org.junit.Test; + +public class StructuredTextExtractionFilterTest { + + private static final String EXPECTED_RESULT_STRING = "\n" + + " \n" + + " 1\n" + + " A Text Extraction Test Document \n" + + "for \n" + + "DSpace \n" + + "This is a text. For the next sixty seconds this software will conduct a test of the DSpace text \n" + + "extraction facility. \n" + + "This is only a text. This is a paragraph that followed the first that lived in the document that \n" + + "Jack built. \n" + + "Lorem ipsum dolor sit amet. The quick brown fox jumped over the lazy dog. Yow! Are we \n" + + "having fun yet? \n" + + "This has been a test of the DSpace text extraction system. In the event of actual content you \n" + + "would care what is written here \n" + + "\n" + + " \n" + + " \n" + + " 2\n" + + " This is still a text. \n" + + "This is only a text, but on a separate page. This is a paragraph that followed the first that \n" + + "lived in the document that Jack built. \n" + + "Lorem ipsum dolor sit amet. The quick brown fox jumped over the lazy dog. \n" + + "This has been a test of the DSpace structured text extraction system. In the event of actual \n" + + "content you would care what is written here \n" + + "\n" + + " \n" + + "\n"; + + @Test + public void testGetFilteredName() { + StructuredTextExtractionFilter filter = new StructuredTextExtractionFilter(); + assertEquals("test.pdf.xml", filter.getFilteredName("test.pdf")); + } + + @Test + public void testGetBundleName() { + StructuredTextExtractionFilter filter = new StructuredTextExtractionFilter(); + assertEquals("STRUCTURED_TEXT", filter.getBundleName()); + } + + @Test + public void testGetFormatString() { + StructuredTextExtractionFilter filter = new StructuredTextExtractionFilter(); + assertEquals("XML", filter.getFormatString()); + } + + @Test + public void testGetDescription() { + StructuredTextExtractionFilter filter = new StructuredTextExtractionFilter(); + assertEquals("Extracted structured text", filter.getDescription()); + } + + @Test + public void testGetDestinationStream() throws Exception { + Item item = mock(Item.class); + InputStream source = mock(InputStream.class); + + when(source.read(any(byte[].class))).thenReturn(-1); + + StructuredTextExtractionFilter filter = new StructuredTextExtractionFilter(); + InputStream resultStream = filter.getDestinationStream(item, getMultiPagePDF(), true); + + assertNotNull(resultStream); + byte[] bytes = new byte[100]; + InputStream expectedInputStream = new ByteArrayInputStream(EXPECTED_RESULT_STRING.getBytes()); + assertEquals(expectedInputStream.read(bytes), resultStream.read(bytes)); + + resultStream.close(); + } + + private InputStream getMultiPagePDF() { + return getClass().getResourceAsStream("multipage_test.pdf"); + } +} diff --git a/dspace-api/src/test/resources/org/dspace/app/mediafilter/multipage_test.pdf b/dspace-api/src/test/resources/org/dspace/app/mediafilter/multipage_test.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ed6c6b369b9e8324d75c62fbd049425ca293b6e2 GIT binary patch literal 40363 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�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 Date: Thu, 11 Apr 2024 10:08:27 +0200 Subject: [PATCH 3/5] QREPO-193 refactor based on review, add licence, use property for version, rename classes, use xml file as expected result --- dspace-api/pom.xml | 3 +- .../StructuredPdfTextExtractionFilter.java | 154 ++++++++++++++++++ .../StructuredTextExtractionFilter.java | 74 --------- .../dspace/app/mediafilter/model/Page.java | 18 +- .../dspace/app/mediafilter/model/Pages.java | 10 +- ...StructuredPdfTextExtractionFilterTest.java | 60 +++++++ .../StructuredTextExtractionFilterTest.java | 87 ---------- .../mediafilter/multipage_expected_result.xml | 27 +++ 8 files changed, 259 insertions(+), 174 deletions(-) create mode 100644 dspace-api/src/main/java/org/dspace/app/mediafilter/StructuredPdfTextExtractionFilter.java delete mode 100644 dspace-api/src/main/java/org/dspace/app/mediafilter/StructuredTextExtractionFilter.java create mode 100644 dspace-api/src/test/java/org/dspace/app/mediafilter/StructuredPdfTextExtractionFilterTest.java delete mode 100644 dspace-api/src/test/java/org/dspace/app/mediafilter/StructuredTextExtractionFilterTest.java create mode 100644 dspace-api/src/test/resources/org/dspace/app/mediafilter/multipage_expected_result.xml diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 64bb341cee98..be55b29455c8 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -19,6 +19,7 @@ ${basedir}/.. + 2.12.7 ${basedir}/.. - 2.12.7 + 2.12.7