package jnpf.fileStorage.dms; import jnpf.exception.DataException; import jnpf.service.DmsApprovalPageTagService; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.docx4j.XmlUtils; import org.docx4j.model.structure.SectionWrapper; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.openpackaging.parts.WordprocessingML.HeaderPart; import org.docx4j.relationships.Relationship; import org.docx4j.wml.Hdr; import org.docx4j.wml.HdrFtrRef; import org.docx4j.wml.HeaderReference; import org.docx4j.wml.ObjectFactory; import org.docx4j.wml.SectPr; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.math.BigInteger; import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; public class DmsApprovalPageMergeServiceTest { private static final ObjectFactory WML = new ObjectFactory(); private final DmsApprovalPageTagService tags = new DmsApprovalPageTagService(); private final DmsApprovalPageMergeService service = new DmsApprovalPageMergeService(tags); @BeforeClass public static void useHeadlessRendering() { System.setProperty("java.awt.headless", "true"); } @Test public void rendersPdfPagesBeforeTheOriginalDocxContent() throws Exception { MultipartFile result = service.prepend(docx("main.docx", "ORIGINAL CONTENT"), pdf("approval.pdf")); WordprocessingMLPackage merged = WordprocessingMLPackage.load(result.getInputStream()); String xml = XmlUtils.marshaltoString( merged.getMainDocumentPart().getJaxbElement(), true, true); assertTrue(xml.indexOf("w:drawing") >= 0); assertTrue(xml.indexOf("w:drawing") < xml.indexOf("ORIGINAL CONTENT")); assertTrue(xml.contains("w:type=\"page\"")); assertTrue(service.hasApprovalPage(result)); assertEquals("main.docx", result.getOriginalFilename()); } @Test public void embedsDocxApprovalPageAheadOfTheOriginalDocument() throws Exception { MultipartFile result = service.prepend( docx("main.docx", "ORIGINAL CONTENT"), docx("approval.docx", "APPROVAL CONTENT")); WordprocessingMLPackage merged = WordprocessingMLPackage.load(result.getInputStream()); String xml = XmlUtils.marshaltoString( merged.getMainDocumentPart().getJaxbElement(), true, true); assertTrue(xml.indexOf("APPROVAL CONTENT") < xml.indexOf("ORIGINAL CONTENT")); assertFalse(xml.contains("w:altChunk")); assertTrue(xml.contains("w:val=\"nextPage\"")); assertTrue(service.hasApprovalPage(result)); } @Test public void preservesApprovalPageMarginsAndHeaderAsAnIndependentFirstSection() throws Exception { MultipartFile result = service.prepend( docxWithLayout("main.docx", "ORIGINAL CONTENT", 1800, null), docxWithLayout("approval.docx", "APPROVAL CONTENT", 1080, "APPROVAL HEADER")); WordprocessingMLPackage merged = WordprocessingMLPackage.load(result.getInputStream()); List sections = merged.getDocumentModel().getSections(); assertEquals(2, sections.size()); assertEquals(BigInteger.valueOf(1080), sections.get(0).getSectPr().getPgMar().getLeft()); assertEquals(BigInteger.valueOf(1800), sections.get(1).getSectPr().getPgMar().getLeft()); HeaderPart approvalHeader = sections.get(0).getHeaderFooterPolicy().getDefaultHeader(); HeaderPart mainHeader = sections.get(1).getHeaderFooterPolicy().getDefaultHeader(); assertTrue(XmlUtils.marshaltoString(approvalHeader.getJaxbElement(), true, true) .contains("APPROVAL HEADER")); assertFalse(XmlUtils.marshaltoString(mainHeader.getJaxbElement(), true, true) .contains("APPROVAL HEADER")); String mainXml = XmlUtils.marshaltoString( merged.getMainDocumentPart().getJaxbElement(), true, true); assertFalse(mainXml.contains("APPROVAL HEADER")); } @Test public void tagsUploadedDocxApprovalPageWithoutAddingVisibleText() throws Exception { MultipartFile tagged = tags.tagApprovalPage(docx("approval.docx", "APPROVAL CONTENT")); WordprocessingMLPackage word = WordprocessingMLPackage.load(tagged.getInputStream()); String xml = XmlUtils.marshaltoString(word.getMainDocumentPart().getJaxbElement(), true, true); assertTrue(tags.hasApprovalPage(tagged)); assertTrue(xml.contains(DmsApprovalPageTagService.TAG_VALUE)); assertFalse(xml.contains(" service.prepend( docx("main.docx", "ORIGINAL"), new MockMultipartFile("file", "approval.png", "image/png", new byte[]{1}))); assertThrows(DataException.class, () -> service.prepend( new MockMultipartFile("file", "legacy.doc", "application/msword", new byte[]{1}), pdf("approval.pdf"))); } private MockMultipartFile docx(String name, String text) throws Exception { WordprocessingMLPackage document = WordprocessingMLPackage.createPackage(); document.getMainDocumentPart().addParagraphOfText(text); ByteArrayOutputStream output = new ByteArrayOutputStream(); document.save(output); return new MockMultipartFile("file", name, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", output.toByteArray()); } private MockMultipartFile docxWithLayout(String name, String text, long horizontalMargin, String headerText) throws Exception { WordprocessingMLPackage document = WordprocessingMLPackage.createPackage(); document.getMainDocumentPart().addParagraphOfText(text); SectPr section = document.getMainDocumentPart().getJaxbElement().getBody().getSectPr(); section.getPgMar().setLeft(BigInteger.valueOf(horizontalMargin)); section.getPgMar().setRight(BigInteger.valueOf(horizontalMargin)); if (headerText != null) { HeaderPart headerPart = new HeaderPart(); Hdr header = WML.createHdr(); header.getContent().add(document.getMainDocumentPart().createParagraphOfText(headerText)); headerPart.setJaxbElement(header); Relationship relationship = document.getMainDocumentPart().addTargetPart(headerPart); HeaderReference reference = WML.createHeaderReference(); reference.setType(HdrFtrRef.DEFAULT); reference.setId(relationship.getId()); section.getEGHdrFtrReferences().add(reference); } ByteArrayOutputStream output = new ByteArrayOutputStream(); document.save(output); return new MockMultipartFile("file", name, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", output.toByteArray()); } private MockMultipartFile pdf(String name) throws Exception { ByteArrayOutputStream output = new ByteArrayOutputStream(); try (PDDocument document = new PDDocument()) { document.addPage(new PDPage()); document.save(output); } return new MockMultipartFile("file", name, "application/pdf", output.toByteArray()); } private int occurrences(String source, String value) { int count = 0; for (int index = 0; (index = source.indexOf(value, index)) >= 0; index += value.length()) count++; return count; } }