You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2021/11/10 09:19:09 UTC
[isis] branch master updated: ISIS-2890: split DocxService into
interface and implementation
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/master by this push:
new 71ed932 ISIS-2890: split DocxService into interface and implementation
71ed932 is described below
commit 71ed932a0a0b02e8dc030844722f1ce7ebc19d11
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Nov 10 10:19:01 2021 +0100
ISIS-2890: split DocxService into interface and implementation
- then properly register with Spring
---
.../isis/subdomains/docx/applib/DocxService.java | 396 ++-------------------
.../applib/IsisModuleSubdomainsDocxApplib.java | 6 +
.../DocxServiceDefault.java} | 162 +--------
.../isis/subdomains/docx/applib/util/Docx.java | 17 +-
.../isis/subdomains/docx/applib/util/Dump.java | 28 +-
.../isis/subdomains/docx/applib/util/Jdom2.java | 20 +-
.../isis/subdomains/docx/applib/util/Types.java | 2 +-
.../docx/applib/DocxService_merge_Test.java | 13 +-
8 files changed, 87 insertions(+), 557 deletions(-)
diff --git a/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/DocxService.java b/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/DocxService.java
index 3d1a25a..c747328 100644
--- a/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/DocxService.java
+++ b/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/DocxService.java
@@ -1,83 +1,47 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
package org.apache.isis.subdomains.docx.applib;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.ArrayList;
import java.util.List;
-import java.util.stream.Collectors;
-import org.apache.commons.compress.utils.Lists;
-import org.apache.commons.io.IOUtils;
-import org.docx4j.Docx4J;
-import org.docx4j.XmlUtils;
-import org.docx4j.com.google.common.base.Objects;
-import org.docx4j.convert.out.FOSettings;
-import org.docx4j.fonts.IdentityPlusMapper;
-import org.docx4j.fonts.Mapper;
-import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
-import org.docx4j.wml.Body;
-import org.docx4j.wml.P;
-import org.docx4j.wml.R;
-import org.docx4j.wml.SdtElement;
-import org.docx4j.wml.Tbl;
-import org.docx4j.wml.Tc;
-import org.docx4j.wml.Tr;
-import org.jdom2.Content;
-import org.jdom2.Element;
-import org.jdom2.input.DOMBuilder;
-import org.springframework.stereotype.Service;
-import org.w3c.dom.Document;
import org.apache.isis.subdomains.docx.applib.exceptions.LoadInputException;
import org.apache.isis.subdomains.docx.applib.exceptions.LoadTemplateException;
import org.apache.isis.subdomains.docx.applib.exceptions.MergeException;
-import org.apache.isis.subdomains.docx.applib.traverse.AllMatches;
-import org.apache.isis.subdomains.docx.applib.traverse.FirstMatch;
-import org.apache.isis.subdomains.docx.applib.util.Docx;
-import org.apache.isis.subdomains.docx.applib.util.Jdom2;
-import org.apache.isis.subdomains.docx.applib.util.Types;
import lombok.Builder;
import lombok.Getter;
-import lombok.val;
/**
- * Provides a mail-merge capability.
+ * Merges input HTML against a provided <i>docx</i> template, generating a <i>Word docx</i>.
*
* @since 2.x {@index}
*/
-@Service
-public class DocxService {
+public interface DocxService {
+
+ /**
+ * Load and return an in-memory representation of a docx.
+ *
+ * <p>
+ * This is public API because building the in-memory structure can be
+ * quite slow. Thus, clients can use this method to cache the in-memory
+ * structure, and pass it in the {@link MergeParams} (through the
+ * {@link MergeParams.Builder#docxTemplateAsWpMlPackage(WordprocessingMLPackage) builder method})
+ */
+ WordprocessingMLPackage loadPackage(InputStream docxTemplate) throws LoadTemplateException;
+
+ /**
+ * Merge the input arguments (as HTML) against the Docx template, writing out as a Word docx..
+ */
+ void merge(MergeParams mergeDefn) throws LoadInputException, LoadTemplateException, MergeException;
/**
* @since 2.x {@index}
*/
@Getter
@Builder(builderClassName = "Builder")
- public static class MergeParams {
+ static class MergeParams {
/**
* Defines the policy for matching input to placeholders.
@@ -153,127 +117,10 @@ public class DocxService {
}
/**
- * Load and return an in-memory representation of a docx.
- *
- * <p>
- * This is public API because building the in-memory structure can be
- * quite slow. Thus, clients can use this method to cache the in-memory
- * structure, and pass it in the {@link MergeParams} (through the
- * {@link MergeParams.Builder#docxTemplateAsWpMlPackage(WordprocessingMLPackage) builder method})
- */
- public WordprocessingMLPackage loadPackage(final InputStream docxTemplate) throws LoadTemplateException {
- final WordprocessingMLPackage docxPkg;
- try {
- docxPkg = WordprocessingMLPackage.load(docxTemplate);
- } catch (final Docx4JException ex) {
- throw new LoadTemplateException("Unable to load docx template from input stream", ex);
- }
- return docxPkg;
- }
-
- /**
- * Merge the input arguments (as HTML) against the Docx template, writing out as a Word docx..
- */
- public void merge(final MergeParams mergeDefn) throws LoadInputException, LoadTemplateException, MergeException {
-
- final org.jdom2.Document htmlJdomDoc;
- final Document inputAsHtmlDoc = mergeDefn.getInputAsHtmlDoc();
- final String inputAsHtml = mergeDefn.getInputAsHtml();
- if(inputAsHtmlDoc != null) {
- htmlJdomDoc = new DOMBuilder().build(inputAsHtmlDoc);
- } else if (inputAsHtml != null) {
- htmlJdomDoc = Jdom2.loadInput(inputAsHtml);
- } else {
- throw new IllegalArgumentException("Input HTML must be provided");
- }
-
- final DefensiveCopy defensiveCopy;
- final WordprocessingMLPackage docxPkg;
- final WordprocessingMLPackage docxTemplateAsWpMlPackage = mergeDefn.getDocxTemplateAsWpMlPackage();
- final InputStream docxTemplate = mergeDefn.getDocxTemplate();
- if(docxTemplateAsWpMlPackage != null) {
- docxPkg = docxTemplateAsWpMlPackage;
- defensiveCopy = DefensiveCopy.REQUIRED;
- } else if (docxTemplate != null) {
- docxPkg = loadPackage(docxTemplate);
- defensiveCopy = DefensiveCopy.NOT_REQUIRED;
- } else {
- throw new IllegalArgumentException("Docx template HTML must be provided");
- }
-
- val output = mergeDefn.getOutput();
- if(output == null) {
- throw new IllegalArgumentException("Output stream must be provided");
- }
- merge(htmlJdomDoc, docxPkg, output, mergeDefn.getMatchingPolicy(), defensiveCopy, mergeDefn.getOutputType());
- }
-
- private void merge(
- final org.jdom2.Document htmlDoc,
- final WordprocessingMLPackage docxTemplateInput,
- final OutputStream docxTarget,
- final MatchingPolicy matchingPolicy,
- final DefensiveCopy defensiveCopy,
- final OutputType outputType)
- throws MergeException {
-
- final WordprocessingMLPackage docxTemplate =
- defensiveCopy == DefensiveCopy.REQUIRED
- ? Docx.clone(docxTemplateInput)
- : docxTemplateInput;
-
- try {
- final Element bodyEl = Jdom2.htmlBodyFor(htmlDoc);
- final Body docXBody = Docx.docxBodyFor(docxTemplate);
-
- merge(bodyEl, docXBody, matchingPolicy);
-
- if (outputType == OutputType.PDF) {
-
-
- final FOSettings foSettings = Docx4J.createFOSettings();
- foSettings.setWmlPackage(docxTemplate);
-
- try {
- final Mapper fontMapper = new IdentityPlusMapper();
- docxTemplate.setFontMapper(fontMapper, true);
- } catch (final Exception e) {
- throw new MergeException("unable to set font mapper for PDF generation", e);
- }
-
- // according to the documentation/examples the XSL transformation
- // is slower but more feature complete than Docx4J.FLAG_EXPORT_PREFER_NONXSL
-
- final int flags = Docx4J.FLAG_EXPORT_PREFER_XSL;
-
- Docx4J.toFO(foSettings, docxTarget, flags);
-
- } else {
- final File tempTargetFile = createTempFile();
- FileInputStream tempTargetFis = null;
- try {
- docxTemplate.save(tempTargetFile);
- tempTargetFis = new FileInputStream(tempTargetFile);
- IOUtils.copy(tempTargetFis, docxTarget);
- } finally {
- IOUtils.closeQuietly(tempTargetFis);
- tempTargetFile.delete();
- }
- }
- } catch (final Docx4JException e) {
- throw new MergeException("unable to write to target file", e);
- } catch (final FileNotFoundException e) {
- throw new MergeException("unable to read back from target file", e);
- } catch (final IOException e) {
- throw new MergeException("unable to generate output stream from temporary file", e);
- }
- }
-
- /**
* Defines the strategy as to whether placeholders must exactly input data
* (or whether there can be unmatched placeholders, or conversely unused input data).
*/
- public enum MatchingPolicy {
+ enum MatchingPolicy {
STRICT(false, false),
ALLOW_UNMATCHED_INPUT(true, false),
ALLOW_UNMATCHED_PLACEHOLDERS(false, true),
@@ -302,15 +149,10 @@ public class DocxService {
}
}
- private enum DefensiveCopy {
- REQUIRED,
- NOT_REQUIRED
- }
-
/**
* The type of the file to generate
*/
- public enum OutputType {
+ enum OutputType {
DOCX,
/**
* Support for PDF should be considered experimental.
@@ -318,198 +160,4 @@ public class DocxService {
PDF
}
- private enum MergeType {
- PLAIN("p.plain"),
- RICH("p.rich"),
- DATE("p.date"),
- UL("ul") {
- @Override
- boolean merge(final Element htmlUl, final SdtElement sdtElement) {
- final List<Element> htmlLiList = htmlUl.getChildren("li"); // can be empty
-
- final List<P> docxPOrigList = AllMatches.<P>matching(sdtElement, Types.withType(P.class));
- if (docxPOrigList.isEmpty()) {
- return false;
- }
-
- final List<P> docxPNewList = new ArrayList<P>();
- for (final Element htmlLi : htmlLiList) {
- final List<Element> htmlPList = htmlLi.getChildren("p");
-
- for (int htmlPNum = 0; htmlPNum < htmlPList.size(); htmlPNum++) {
- final int numDocxPNum = docxPOrigList.size();
- final int docxPNum = numDocxPNum == 1 || htmlPNum == 0 ? 0 : 1;
- final P docxP = XmlUtils.deepCopy(docxPOrigList.get(docxPNum));
- docxPNewList.add(docxP);
- final R docxR = FirstMatch.<R>matching(docxP, Types.withType(R.class));
- final Element htmlP = htmlPList.get(htmlPNum);
- Docx.setText(docxR, Jdom2.textValueOf(htmlP));
- }
- }
-
- // remove original and replace with new
- final List<Object> content = sdtElement.getSdtContent().getContent();
- for (final P docxP : docxPOrigList) {
- content.remove(docxP);
- }
- for (final P docxP : docxPNewList) {
- content.add(docxP);
- }
- return true;
- }
- },
- TABLE("table") {
- @Override
- boolean merge(final Element htmlTable, final SdtElement sdtElement) {
-
- final List<Element> htmlTrOrigList = htmlTable.getChildren("tr"); // can be empty
-
- final List<Object> docxContents = sdtElement.getSdtContent().getContent();
- final Tbl docxTbl = FirstMatch.matching(docxContents, Types.withType(Tbl.class));
- if (docxTbl == null) {
- return false;
- }
- final List<Tr> docxTrList = AllMatches.matching(docxTbl, Types.withType(Tr.class));
- if (docxTrList.size() < 2) {
- // require a header row and one other
- return false;
- }
-
- final List<Tr> docxTrNewList = Lists.newArrayList();
- for (int htmlRowNum = 0; htmlRowNum < htmlTrOrigList.size(); htmlRowNum++) {
- final Element htmlTr = htmlTrOrigList.get(htmlRowNum);
-
- final int numDocxBodyTr = docxTrList.size() - 1;
- final int docxTrNum = (htmlRowNum % numDocxBodyTr) + 1;
- final Tr docxTr = XmlUtils.deepCopy(docxTrList.get(docxTrNum));
- docxTrNewList.add(docxTr);
- final List<Tc> docxTcList = AllMatches.matching(docxTr.getContent(), Types.withType(Tc.class));
- final List<Element> htmlTdList = htmlTr.getChildren("td");
- final List<String> htmlCellValues =
- htmlTdList.stream().map(x -> Jdom2.textValue().apply(x))
- .collect(Collectors.toList());
- for (int cellNum = 0; cellNum < docxTcList.size(); cellNum++) {
- final Tc docxTc = docxTcList.get(cellNum);
- final String value = cellNum < htmlCellValues.size() ? htmlCellValues.get(cellNum) : "";
- final P docxP = FirstMatch.matching(docxTc.getContent(), Types.withType(P.class));
- if (docxP == null) {
- return false;
- }
- final R docxR = FirstMatch.matching(docxP, Types.withType(R.class));
- if (docxR == null) {
- return false;
- }
- Docx.setText(docxR, value);
- }
- }
- docxReplaceRows(docxTbl, docxTrList, docxTrNewList);
- return true;
- }
-
- private void docxReplaceRows(final Tbl docxTbl, final List<Tr> docxTrList, final List<Tr> docxTrToAdd) {
- final List<Object> docxTblContent = docxTbl.getContent();
- boolean first = true;
- for (final Tr docxTr : docxTrList) {
- if (first) {
- // header, do NOT remove
- first = false;
- } else {
- docxTblContent.remove(docxTr);
- }
- }
- for (final Tr docxTr : docxTrToAdd) {
- docxTblContent.add(docxTr);
- }
- }
- };
-
- private final String type;
-
-
- private MergeType(final String type) {
- this.type = type;
- }
-
- public static MergeType lookup(final String name, final String clazz) {
- final String type = name + (clazz != null ? "." + clazz : "");
- for (final MergeType mt : values()) {
- if (Objects.equal(mt.type, type)) {
- return mt;
- }
- }
- return null;
- }
-
- boolean merge(final Element htmlElement, final SdtElement docxElement) {
- final String htmlTextValue = Jdom2.textValueOf(htmlElement);
- if (htmlTextValue == null) {
- return false;
- }
-
- final R docxR = FirstMatch.matching(docxElement, Types.withType(R.class));
- if (docxR == null) {
- return false;
- }
- return Docx.setText(docxR, htmlTextValue);
- }
- }
-
- private static void merge(final Element htmlBody, final Body docXBody, final MatchingPolicy matchingPolicy) throws MergeException {
- final List<String> matchedInputIds = Lists.newArrayList();
- final List<String> unmatchedInputIds = Lists.newArrayList();
-
- final List<Content> htmlBodyContents = htmlBody.getContent();
- for (final Content input : htmlBodyContents) {
- if (!(input instanceof Element)) {
- continue;
- }
- mergeInto((Element) input, docXBody, matchedInputIds, unmatchedInputIds);
- }
-
- final List<String> unmatchedPlaceHolders = unmatchedPlaceholders(docXBody, matchedInputIds);
-
- matchingPolicy.unmatchedInputs(unmatchedInputIds);
- matchingPolicy.unmatchedPlaceholders(unmatchedPlaceHolders);
- }
-
- private static void mergeInto(final Element input, final Body docXBody, final List<String> matchedInputs, final List<String> unmatchedInputs) throws MergeException {
-
- final String id = Jdom2.attrOf(input, "id");
- if (id == null) {
- throw new MergeException("Missing 'id' attribute for element within body of input HTML");
- }
-
- final MergeType mergeType = MergeType.lookup(input.getName(), Jdom2.attrOf(input, "class"));
- if (mergeType == null) {
- unmatchedInputs.add(id);
- return;
- }
-
- final SdtElement docxElement = FirstMatch.matching(docXBody, Docx.withTagVal(id));
- if (docxElement == null) {
- unmatchedInputs.add(id);
- return;
- }
-
- if (mergeType.merge(input, docxElement)) {
- matchedInputs.add(id);
- } else {
- unmatchedInputs.add(id);
- }
- }
-
- private static List<String> unmatchedPlaceholders(final Body docXBody, final List<String> matchedIds) {
- final List<SdtElement> taggedElements = AllMatches.matching(docXBody, Docx.withAnyTag());
- final List<String> unmatchedPlaceHolders = taggedElements.stream().map(x -> Docx.tagToValue().apply(x)).collect(Collectors.toList());
- unmatchedPlaceHolders.removeAll(matchedIds);
- return unmatchedPlaceHolders;
- }
-
- private static File createTempFile() throws MergeException {
- try {
- return File.createTempFile("docx", null);
- } catch (final IOException ex) {
- throw new MergeException("Unable to create temporary working file", ex);
- }
- }
-}
+}
\ No newline at end of file
diff --git a/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/IsisModuleSubdomainsDocxApplib.java b/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/IsisModuleSubdomainsDocxApplib.java
index ce54e75..d12d16d 100644
--- a/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/IsisModuleSubdomainsDocxApplib.java
+++ b/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/IsisModuleSubdomainsDocxApplib.java
@@ -19,8 +19,14 @@
package org.apache.isis.subdomains.docx.applib;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+import org.apache.isis.subdomains.docx.applib.services.DocxServiceDefault;
@Configuration
+@Import({
+ DocxServiceDefault.class
+})
public class IsisModuleSubdomainsDocxApplib {
}
diff --git a/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/DocxService.java b/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/services/DocxServiceDefault.java
similarity index 76%
copy from subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/DocxService.java
copy to subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/services/DocxServiceDefault.java
index 3d1a25a..dd3fda8 100644
--- a/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/DocxService.java
+++ b/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/services/DocxServiceDefault.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.isis.subdomains.docx.applib;
+package org.apache.isis.subdomains.docx.applib.services;
import java.io.File;
import java.io.FileInputStream;
@@ -28,6 +28,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
+import javax.annotation.Priority;
+import javax.inject.Named;
+
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.io.IOUtils;
import org.docx4j.Docx4J;
@@ -48,9 +51,12 @@ import org.docx4j.wml.Tr;
import org.jdom2.Content;
import org.jdom2.Element;
import org.jdom2.input.DOMBuilder;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
+import org.apache.isis.applib.annotation.PriorityPrecedence;
+import org.apache.isis.subdomains.docx.applib.DocxService;
import org.apache.isis.subdomains.docx.applib.exceptions.LoadInputException;
import org.apache.isis.subdomains.docx.applib.exceptions.LoadTemplateException;
import org.apache.isis.subdomains.docx.applib.exceptions.MergeException;
@@ -60,107 +66,15 @@ import org.apache.isis.subdomains.docx.applib.util.Docx;
import org.apache.isis.subdomains.docx.applib.util.Jdom2;
import org.apache.isis.subdomains.docx.applib.util.Types;
-import lombok.Builder;
-import lombok.Getter;
import lombok.val;
-/**
- * Provides a mail-merge capability.
- *
- * @since 2.x {@index}
- */
@Service
-public class DocxService {
-
- /**
- * @since 2.x {@index}
- */
- @Getter
- @Builder(builderClassName = "Builder")
- public static class MergeParams {
-
- /**
- * Defines the policy for matching input to placeholders.
- *
- * <p>
- * Does not need to be specified, will default to {@link MatchingPolicy#STRICT strict}
- * </p>
- */
- @lombok.Builder.Default private MatchingPolicy matchingPolicy = MatchingPolicy.STRICT;
-
- /**
- * Defines whether to output as Word docx or PDF.
- *
- * <p>
- * Does not need to be specified, will default to {@link OutputType#DOCX docx}.
- * </p>
- */
- @lombok.Builder.Default private OutputType outputType = OutputType.DOCX;
-
- /**
- * Holds the input arguments to be merged into the template.
- *
- * <p>
- * Either this or {@link #getInputAsHtmlDoc()} must be specified.
- * Preference is given to {@link #getInputAsHtmlDoc()}.
- * </p>
- *
- * @see #getInputAsHtmlDoc()
- */
- private String inputAsHtml;
-
- /**
- * Holds the input arguments to be merged into the template.
- *
- * <p>
- * Either this or {@link #getInputAsHtml()} must be specified, with
- * preference given to this.
- * </p>
- *
- * @see #getInputAsHtml()
- */
- private org.w3c.dom.Document inputAsHtmlDoc;
-
- /**
- * Refers to the template with place holders to be merged into.
- *
- * <p>
- * Either this or {@link #getDocxTemplateAsWpMlPackage()} myst be
- * specified, with preference given to {@link #getDocxTemplateAsWpMlPackage()}
- * </p>
- *
- * @see #getDocxTemplateAsWpMlPackage()
- */
- private InputStream docxTemplate;
-
- /**
- * Refers to the template with place holders to be merged into.
- *
- * <p>
- * Either this or {@link #getDocxTemplate()} myst be
- * specified, with preference given to this.
- * </p>
- *
- * @see #getDocxTemplate()
- */
- private WordprocessingMLPackage docxTemplateAsWpMlPackage;
-
- /**
- * The output stream to write to.
- */
- private OutputStream output;
-
- }
+@Named("isis.sub.docx.ClockService")
+@Priority(PriorityPrecedence.MIDPOINT)
+@Qualifier("Default")
+public class DocxServiceDefault implements DocxService {
- /**
- * Load and return an in-memory representation of a docx.
- *
- * <p>
- * This is public API because building the in-memory structure can be
- * quite slow. Thus, clients can use this method to cache the in-memory
- * structure, and pass it in the {@link MergeParams} (through the
- * {@link MergeParams.Builder#docxTemplateAsWpMlPackage(WordprocessingMLPackage) builder method})
- */
+ @Override
public WordprocessingMLPackage loadPackage(final InputStream docxTemplate) throws LoadTemplateException {
final WordprocessingMLPackage docxPkg;
try {
@@ -171,9 +85,7 @@ public class DocxService {
return docxPkg;
}
- /**
- * Merge the input arguments (as HTML) against the Docx template, writing out as a Word docx..
- */
+ @Override
public void merge(final MergeParams mergeDefn) throws LoadInputException, LoadTemplateException, MergeException {
final org.jdom2.Document htmlJdomDoc;
@@ -208,6 +120,8 @@ public class DocxService {
merge(htmlJdomDoc, docxPkg, output, mergeDefn.getMatchingPolicy(), defensiveCopy, mergeDefn.getOutputType());
}
+ // -- HELPER
+
private void merge(
final org.jdom2.Document htmlDoc,
final WordprocessingMLPackage docxTemplateInput,
@@ -232,7 +146,7 @@ public class DocxService {
final FOSettings foSettings = Docx4J.createFOSettings();
- foSettings.setWmlPackage(docxTemplate);
+ foSettings.setOpcPackage(docxTemplate);
try {
final Mapper fontMapper = new IdentityPlusMapper();
@@ -269,55 +183,11 @@ public class DocxService {
}
}
- /**
- * Defines the strategy as to whether placeholders must exactly input data
- * (or whether there can be unmatched placeholders, or conversely unused input data).
- */
- public enum MatchingPolicy {
- STRICT(false, false),
- ALLOW_UNMATCHED_INPUT(true, false),
- ALLOW_UNMATCHED_PLACEHOLDERS(false, true),
- /**
- * Combination of both {@link #ALLOW_UNMATCHED_INPUT} and {@link #ALLOW_UNMATCHED_PLACEHOLDERS}.
- */
- LAX(true, true);
- private final boolean allowUnmatchedInput;
- private final boolean allowUnmatchedPlaceholders;
-
- private MatchingPolicy(final boolean allowUnmatchedInput, final boolean allowUnmatchedPlaceholders) {
- this.allowUnmatchedInput = allowUnmatchedInput;
- this.allowUnmatchedPlaceholders = allowUnmatchedPlaceholders;
- }
-
- public void unmatchedInputs(final List<String> unmatched) throws MergeException {
- if (!allowUnmatchedInput && !unmatched.isEmpty()) {
- throw new MergeException("Input elements " + unmatched + " were not matched to placeholders");
- }
- }
-
- public void unmatchedPlaceholders(final List<String> unmatched) throws MergeException {
- if (!allowUnmatchedPlaceholders && !unmatched.isEmpty()) {
- throw new MergeException("Placeholders " + unmatched + " were not matched to input");
- }
- }
- }
-
private enum DefensiveCopy {
REQUIRED,
NOT_REQUIRED
}
- /**
- * The type of the file to generate
- */
- public enum OutputType {
- DOCX,
- /**
- * Support for PDF should be considered experimental.
- */
- PDF
- }
-
private enum MergeType {
PLAIN("p.plain"),
RICH("p.rich"),
diff --git a/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Docx.java b/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Docx.java
index e979c95..cd37671 100644
--- a/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Docx.java
+++ b/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Docx.java
@@ -44,11 +44,11 @@ import lombok.experimental.UtilityClass;
@UtilityClass
public class Docx {
- public static Function<SdtElement, String> tagToValue() {
+ public Function<SdtElement, String> tagToValue() {
return input -> input.getSdtPr().getTag().getVal();
}
- public static Predicate<Object> withAnyTag() {
+ public Predicate<Object> withAnyTag() {
return object -> {
if(!(object instanceof SdtElement)) {
return false;
@@ -59,7 +59,7 @@ public class Docx {
};
}
- public static Predicate<Object> withTagVal(final String tagVal) {
+ public Predicate<Object> withTagVal(final String tagVal) {
return object -> {
if(!(object instanceof SdtElement)) {
return false;
@@ -70,9 +70,8 @@ public class Docx {
};
}
- @SuppressWarnings({ "rawtypes", "restriction" })
- public
- static boolean setText(R run, String value) {
+ @SuppressWarnings({ "rawtypes" })
+ public boolean setText(final R run, final String value) {
List<Object> runContent = run.getContent();
if(runContent.isEmpty()) {
return false;
@@ -92,13 +91,13 @@ public class Docx {
return true;
}
- public static Body docxBodyFor(WordprocessingMLPackage docxPkg) {
+ public Body docxBodyFor(final WordprocessingMLPackage docxPkg) {
val docxMdp = docxPkg.getMainDocumentPart();
val docxDoc = docxMdp.getJaxbElement();
return docxDoc.getBody();
}
- public static WordprocessingMLPackage clone(WordprocessingMLPackage docxTemplate) throws MergeException {
+ public WordprocessingMLPackage clone(WordprocessingMLPackage docxTemplate) throws MergeException {
val foxc = new FlatOpcXmlCreator(docxTemplate);
val baos = new ByteArrayOutputStream();
try {
@@ -108,7 +107,7 @@ public class Docx {
docxTemplate = (WordprocessingMLPackage) foxi.get();
} catch (Docx4JException e) {
throw new MergeException("unable to defensive copy (problem exporting)", e);
- } catch (@SuppressWarnings("restriction") JAXBException e) {
+ } catch (JAXBException e) {
throw new MergeException("unable to defensive copy (problem importing)", e);
}
return docxTemplate;
diff --git a/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Dump.java b/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Dump.java
index 80ee728..83636e2 100644
--- a/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Dump.java
+++ b/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Dump.java
@@ -39,7 +39,7 @@ import org.docx4j.wml.Body;
public class Dump {
- public static void main(String[] args) throws Exception {
+ public static void main(final String[] args) throws Exception {
//String filename = "helloWorld.docx";
String filename = "TypicalDocument.docx";
@@ -60,11 +60,11 @@ public class Dump {
private Map<Part, Part> handled = new HashMap<Part, Part>();
- public Dump(File file) {
+ public Dump(final File file) {
this.file = file;
}
- public void partsList(PrintStream out) throws Exception {
+ public void partsList(final PrintStream out) throws Exception {
OpcPackage opcPackage = OpcPackage.load(file);
@@ -81,8 +81,8 @@ public class Dump {
// saver.save(System.getProperty("user.dir") + "/out.docx");
}
- @SuppressWarnings({ "restriction", "rawtypes" })
- private void appendInfo(Part p, StringBuilder sb, String indent) {
+ @SuppressWarnings({ "rawtypes" })
+ private void appendInfo(final Part p, final StringBuilder sb, final String indent) {
String relationshipType = "";
if (p.getSourceRelationships().size() > 0) {
@@ -101,7 +101,7 @@ public class Dump {
}
}
- private void traverseRelationships(OpcPackage opcPackage, RelationshipsPart rp, StringBuilder sb, String indent) {
+ private void traverseRelationships(final OpcPackage opcPackage, final RelationshipsPart rp, final StringBuilder sb, final String indent) {
// TODO: order by rel id
@@ -134,11 +134,11 @@ public class Dump {
}
}
- public void documentTraverse(PrintStream out) throws Docx4JException {
+ public void documentTraverse(final PrintStream out) throws Docx4JException {
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(file);
MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
- org.docx4j.wml.Document wmlDocumentEl = (org.docx4j.wml.Document) documentPart.getJaxbElement();
+ org.docx4j.wml.Document wmlDocumentEl = documentPart.getJaxbElement();
Body body = wmlDocumentEl.getBody();
new TraversalUtil(body,
@@ -147,7 +147,8 @@ public class Dump {
String indent = "";
- public List<Object> apply(Object o) {
+ @Override
+ public List<Object> apply(final Object o) {
String text = "";
if (o instanceof org.docx4j.wml.Text)
@@ -157,12 +158,14 @@ public class Dump {
return null;
}
- public boolean shouldTraverse(Object o) {
+ @Override
+ public boolean shouldTraverse(final Object o) {
return true;
}
// Depth first
- public void walkJAXBElements(Object parent) {
+ @Override
+ public void walkJAXBElements(final Object parent) {
indent += " ";
@@ -187,7 +190,8 @@ public class Dump {
indent = indent.substring(0, indent.length() - 4);
}
- public List<Object> getChildren(Object o) {
+ @Override
+ public List<Object> getChildren(final Object o) {
return TraversalUtil.getChildrenImpl(o);
}
}
diff --git a/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Jdom2.java b/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Jdom2.java
index aa6ee92..a1bf6a7 100644
--- a/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Jdom2.java
+++ b/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Jdom2.java
@@ -34,11 +34,12 @@ import org.jdom2.input.SAXBuilder;
import org.apache.isis.subdomains.docx.applib.exceptions.LoadInputException;
import org.apache.isis.subdomains.docx.applib.exceptions.MergeException;
-public final class Jdom2 {
+import lombok.experimental.UtilityClass;
- private Jdom2(){}
+@UtilityClass
+public final class Jdom2 {
- public static String textValueOf(Element htmlElement) {
+ public String textValueOf(final Element htmlElement) {
List<Content> htmlContent = htmlElement.getContent();
if(htmlContent.isEmpty()) {
return null;
@@ -52,19 +53,20 @@ public final class Jdom2 {
}
- private static String normalized(String value) {
+ private String normalized(final String value) {
String replaceAll = value.replaceAll("\\s+", " ");
return replaceAll;
}
- public static Function<Element, String> textValue() {
+ public Function<Element, String> textValue() {
return new Function<Element, String>(){
- public String apply(Element input) {
+ @Override
+ public String apply(final Element input) {
return textValueOf(input);
}};
}
- public static String attrOf(Element input, String attname) {
+ public String attrOf(final Element input, final String attname) {
Attribute attribute = input.getAttribute(attname);
if(attribute == null) {
return null;
@@ -72,7 +74,7 @@ public final class Jdom2 {
return attribute.getValue();
}
- public static Document loadInput(String html) throws LoadInputException {
+ public Document loadInput(final String html) throws LoadInputException {
try {
return new SAXBuilder().build(new StringReader(html));
} catch (JDOMException e) {
@@ -82,7 +84,7 @@ public final class Jdom2 {
}
}
- public static Element htmlBodyFor(Document htmlDoc) throws MergeException {
+ public Element htmlBodyFor(final Document htmlDoc) throws MergeException {
Element htmlEl = htmlDoc.getRootElement();
Element bodyEl = htmlEl.getChild("body");
if (bodyEl == null) {
diff --git a/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Types.java b/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Types.java
index 5447ee4..91ad2bc 100644
--- a/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Types.java
+++ b/subdomains/docx/applib/src/main/java/org/apache/isis/subdomains/docx/applib/util/Types.java
@@ -25,7 +25,7 @@ import lombok.experimental.UtilityClass;
@UtilityClass
public final class Types {
- public static Predicate<Object> withType(final Class<?> cls) {
+ public Predicate<Object> withType(final Class<?> cls) {
return object -> cls.isAssignableFrom(object.getClass());
}
diff --git a/subdomains/docx/applib/src/test/java/org/apache/isis/subdomains/docx/applib/DocxService_merge_Test.java b/subdomains/docx/applib/src/test/java/org/apache/isis/subdomains/docx/applib/DocxService_merge_Test.java
index 1777578..1f51a8e 100644
--- a/subdomains/docx/applib/src/test/java/org/apache/isis/subdomains/docx/applib/DocxService_merge_Test.java
+++ b/subdomains/docx/applib/src/test/java/org/apache/isis/subdomains/docx/applib/DocxService_merge_Test.java
@@ -33,6 +33,7 @@ import static org.assertj.core.api.Assumptions.assumeThat;
import org.apache.isis.subdomains.docx.applib.exceptions.LoadInputException;
import org.apache.isis.subdomains.docx.applib.exceptions.MergeException;
+import org.apache.isis.subdomains.docx.applib.services.DocxServiceDefault;
import lombok.val;
@@ -45,7 +46,7 @@ class DocxService_merge_Test {
@BeforeEach
public void setUp() throws Exception {
- docxService = new DocxService();
+ docxService = new DocxServiceDefault();
// given
docxTemplate = docxService.loadPackage(io.openInputStream("Template.docx"));
@@ -55,7 +56,7 @@ class DocxService_merge_Test {
@Nested
public class Strict {
- private DocxService.MatchingPolicy matchingPolicy = DocxService.MatchingPolicy.STRICT;
+ private DocxServiceDefault.MatchingPolicy matchingPolicy = DocxService.MatchingPolicy.STRICT;
@Test
public void exactMatch() throws Exception {
@@ -129,7 +130,7 @@ class DocxService_merge_Test {
@Nested
public class AllowUnmatchedInput {
- private DocxService.MatchingPolicy matchingPolicy = DocxService.MatchingPolicy.ALLOW_UNMATCHED_INPUT;
+ private DocxServiceDefault.MatchingPolicy matchingPolicy = DocxService.MatchingPolicy.ALLOW_UNMATCHED_INPUT;
@Test
public void exactMatch() throws Exception {
@@ -186,7 +187,7 @@ class DocxService_merge_Test {
@Nested
public class AllowUnmatchedPlaceholders {
- private DocxService.MatchingPolicy matchingPolicy = DocxService.MatchingPolicy.ALLOW_UNMATCHED_PLACEHOLDERS;
+ private DocxServiceDefault.MatchingPolicy matchingPolicy = DocxService.MatchingPolicy.ALLOW_UNMATCHED_PLACEHOLDERS;
@Test
public void exactMatch() throws Exception {
@@ -242,7 +243,7 @@ class DocxService_merge_Test {
@Nested
public class Lax {
- private DocxService.MatchingPolicy matchingPolicy = DocxService.MatchingPolicy.LAX;
+ private DocxServiceDefault.MatchingPolicy matchingPolicy = DocxService.MatchingPolicy.LAX;
@Test
public void exactMatch() throws Exception {
@@ -322,7 +323,7 @@ class DocxService_merge_Test {
@Nested
public class GeneratePdf {
- private DocxService.MatchingPolicy matchingPolicy = DocxService.MatchingPolicy.STRICT;
+ private DocxServiceDefault.MatchingPolicy matchingPolicy = DocxService.MatchingPolicy.STRICT;
@BeforeEach
public void setUp() throws Exception {