Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
of error reporting by ensuring that only meaningful references are included in the ServiceError object.
- REF275-1: Enforce JJWT to use Jackson 3
- RpcDelegate and RpcResult: refactoring
- PdfBuilder: extra space for single page PDF
- removed **`PostOffice`** parameter, replaced with **`SinglePageHeightCalculationListener.onHeightCalculationRetry()`** to let caller decide what to do when retry happened.
- Multiple **`SinglePageHeightCalculationListener`** can be added via **`PdfBuilder.addListener()`**
- Multiple **`SinglePageHeightCalculationListener`** can be removed via **`PdfBuilder.removeListener()`**
- A one time **`SinglePageHeightCalculationListener`** can be provided via **`htmlToPdf(...)`** to override added listeners
- max retry can be defined by caller via **`PdfBuilderConfig.setSinglePageHeightCalculationMaxIteration(int)`**, the default value is 3; it was previously hardcoded to 2.

## Version 2.7.4 (2026-10-24)

Expand Down
31 changes: 15 additions & 16 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@
<maven-scm.version>2.2.1</maven-scm.version>
<maven-source.version>3.4.0</maven-source.version>
<maven-javadoc.version>3.12.0</maven-javadoc.version>
<maven-deploy.version>3.1.4</maven-deploy.version>
<maven-deploy.version>3.2.0</maven-deploy.version>
<maven-gpg.version>3.2.8</maven-gpg.version>
<nexus-staging-maven-plugin.version>1.7.0</nexus-staging-maven-plugin.version>
<central-publishing.version>0.10.0</central-publishing.version>
<central-publishing.version>0.12.0</central-publishing.version>
</properties>
<build>
<plugins>
Expand Down Expand Up @@ -157,17 +157,15 @@
<properties>
<!-- common properties and dependencies -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- <maven.compiler.source>21</maven.compiler.source>-->
<!-- <maven.compiler.target>21</maven.compiler.target>-->
<maven.compiler.release>21</maven.compiler.release>
<maven-clean.version>3.5.0</maven-clean.version>
<maven-compiler.version>3.15.0</maven-compiler.version>
<maven-dependency.version>3.10.0</maven-dependency.version>
<maven-jar.version>3.5.0</maven-jar.version>
<maven-compiler.version>3.16.0</maven-compiler.version>
<maven-dependency.version>3.11.0</maven-dependency.version>
<maven-jar.version>3.5.1</maven-jar.version>
<maven-resources.version>3.5.0</maven-resources.version>
<maven-surefire.version>3.5.5</maven-surefire.version>
<maven-doc-version>3.12.0</maven-doc-version>
<maven-install.version>3.1.4</maven-install.version>
<maven-surefire.version>3.6.1</maven-surefire.version>
<maven-javadoc-version>3.12.0</maven-javadoc-version>
<maven-install.version>3.2.0</maven-install.version>
<!-- Commons -->
<commons-lang3.version>3.21.0</commons-lang3.version>
<commons-cli.version>1.11.0</commons-cli.version>
Expand All @@ -193,12 +191,12 @@
<guava.version>33.7.2-jre</guava.version>
<protobuf.version>4.36.2</protobuf.version>
<!-- Web JAX-RS -->
<swagger.core.version>2.2.55</swagger.core.version>
<swagger.core.version>3.0.0</swagger.core.version>
<!--<elastic-apm.version>1.36.0</elastic-apm.version>-->


<!-- MIME-Type -->
<tika.version>4.1.0</tika.version>
<tika.version>4.2.0</tika.version>
<!-- JAX-RS -->
<rs-api.version>4.0.0</rs-api.version>
<jakarta.annotation.version>3.0.0</jakarta.annotation.version>
Expand Down Expand Up @@ -876,9 +874,10 @@
<version>${maven-compiler.version}</version>
<configuration>
<showDeprecation>true</showDeprecation>
<!-- <compilerArgs>-->
<!-- <arg>-Xlint:unchecked</arg>-->
<!-- </compilerArgs>-->
<compilerArgs>
<arg>-parameters</arg> <!-- Preserve parameter names -->
<!-- <arg>-Xlint:unchecked</arg> -->
</compilerArgs>
</configuration>

</plugin>
Expand Down Expand Up @@ -922,7 +921,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven-doc-version}</version>
<version>${maven-javadoc-version}</version>
<configuration>
<additionalJOptions>
<additionalJOption>--allow-script-in-comments</additionalJOption>
Expand Down
122 changes: 89 additions & 33 deletions src/main/java/org/summerboot/jexpress/integration/pdf/PdfBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

import com.google.protobuf.ByteString;
import com.openhtmltopdf.util.XRLog;
import freemarker.template.Template;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand All @@ -28,9 +27,7 @@
import org.summerboot.jexpress.api.common.BootPoi;
import org.summerboot.jexpress.api.common.Err;
import org.summerboot.jexpress.api.common.SessionContext;
import org.summerboot.jexpress.api.mail.PostOffice;
import org.summerboot.jexpress.boot.BootConstants;
import org.summerboot.jexpress.integration.mail.config.SmtpClientConfig;
import org.summerboot.jexpress.util.format.PageCssUtil;

import java.io.File;
Expand All @@ -40,9 +37,7 @@
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.CRC32;

/**
Expand All @@ -65,22 +60,27 @@ public static PdfBuilder init(File templateDir, File fontDir, File fontCacheDir,
return pdfBuilder;
}

public final File dumpDir;

public boolean isDumpEnabled() {
return BootConstants.isDebugMode() && dumpDir.exists();
public static interface SinglePageHeightCalculationListener {
/**
*
* @param retry
* @param pageCount
* @param requesterTxId
* @param htmlContent
* @param agent
* @param extraSpace
* @param pageHeightMillimeters
*/
void onHeightCalculationRetry(int retry, int pageCount, String requesterTxId, String htmlContent, PdfBuilderConfig.Agent agent, int extraSpace, float pageHeightMillimeters);
}

private File htmlTemplateDir;

public final File dumpDir;
private final File htmlTemplateDir;
protected final PdfBoxAgent pdfBoxAgent;
protected final ItextAgent agentIText;
protected final List<SinglePageHeightCalculationListener> listeners = new ArrayList<>();
//private static final WriterProperties WRITER_PROPS = IText.buildDefaultAccessPermission(null, null, true, PdfVersion.PDF_1_7);

private final Map<String, Template> FreeMarkerTemplates = new HashMap<>();

protected PdfBoxAgent pdfBoxAgent;
protected ItextAgent agentIText;


/**
* Initializes the PDF builder with template and font directories.
*
Expand Down Expand Up @@ -113,21 +113,66 @@ protected PdfBuilder(File htmlTemplateDir, File fontDir, File fontCacheDir, File
this.dumpDir = dumpDir;
}

public byte[] html2PDF(String requesterTxId, String htmlContent, PdfBuilderConfig cfg, PostOffice po, SessionContext context) throws IOException {
return html2PDF(requesterTxId, htmlContent, false, cfg, po, context);
public File getDumpDir() {
return dumpDir;
}

public File getHtmlTemplateDir() {
return htmlTemplateDir;
}

public byte[] html2PDF(String requesterTxId, String htmlContent, boolean isSinglePage, PdfBuilderConfig cfg, PostOffice po, SessionContext context) throws IOException {
return html2PDF(requesterTxId, htmlContent, isSinglePage, 5, cfg, po, context);
public void addListener(SinglePageHeightCalculationListener listener) {
if (listener == null) {
return;
}
listeners.add(listener);
}

public byte[] html2PDF(String requesterTxId, String htmlContent, boolean isSinglePage, int extraSpace, PdfBuilderConfig cfg, PostOffice po, SessionContext context) throws IOException {
public boolean removeListener(SinglePageHeightCalculationListener listener) {
return listeners.remove(listener);
}

public boolean isDumpEnabled() {
return BootConstants.isDebugMode() && dumpDir.exists();
}

/**
* Build a multipage PDF
*
* @param requesterTxId
* @param htmlContent
* @param cfg
* @param context
* @return
* @throws IOException
*/
public byte[] htmlToPdf(String requesterTxId, String htmlContent, PdfBuilderConfig cfg, SessionContext context) throws IOException {
return htmlToPdf(requesterTxId, htmlContent, cfg, false, 0, null, context);
}

/**
* Build a single page PDF
*
* @param requesterTxId
* @param htmlContent
* @param cfg
* @param extraSpace
* @param onetimeListener
* @param context
* @return
* @throws IOException
*/
public byte[] htmlToPdf(String requesterTxId, String htmlContent, PdfBuilderConfig cfg, int extraSpace, SinglePageHeightCalculationListener onetimeListener, SessionContext context) throws IOException {
return htmlToPdf(requesterTxId, htmlContent, cfg, true, extraSpace, onetimeListener, context);
}

protected byte[] htmlToPdf(String requesterTxId, String htmlContent, PdfBuilderConfig cfg, boolean isSinglePage, int extraSpace, SinglePageHeightCalculationListener onetimeListener, SessionContext context) throws IOException {
context.poi(BootPoi.PDF_BEGIN);
PdfBuilderConfig.Agent agent = cfg.getAgent();
if (extraSpace < 1) {
extraSpace = 5;
}
final String sessionName = requesterTxId + "_" + agent + "_" + isSinglePage + "_" + extraSpace;
final String sessionName = requesterTxId + "[" + agent + "]" + (isSinglePage ? ("SP+" + extraSpace + "mm") : "MP");
byte[] pdf = null;
try {
if (isSinglePage) {
Expand All @@ -138,21 +183,33 @@ public byte[] html2PDF(String requesterTxId, String htmlContent, boolean isSingl
int pageCount = layoutInfo.getPageCount();
float pageHeightMillimeters = layoutInfo.getPageHeight() * pageCount / PdfBoxAgent.POINTS_PER_MM;
String htmlTemplate = htmlContent;
int retry = 0;
while (pageCount > 1 && retry < 2) {
int iterationCount = 0;
while (pageCount > 1 && iterationCount < cfg.getSinglePageHeightCalculationMaxIteration()) {
pageHeightMillimeters += extraSpace;//add extra space
htmlTemplate = PageCssUtil.setHeight(htmlContent, pageHeightMillimeters + "mm;");
layoutInfo = pdfBoxAgent.layoutThenGetInfo(htmlTemplate, htmlTemplateDir);
pageCount = layoutInfo.getPageCount();
retry++;
context.poi(BootPoi.PDF_HV);
iterationCount++;
context.poi(BootPoi.PDF_HV)
.memo("iterationCount=" + iterationCount + ",pages=" + pageCount + ", extraSpace=" + extraSpace + "mm, height=" + pageHeightMillimeters + "mm");
}
if (retry > 1) {
context.level(Level.WARN).memo("template height oversize retry = " + retry).error(new Err(0, null, null, null, sessionName + " template height oversize retry = " + retry));
//log.fatal("template height oversize (retry={}) for TxId={}", retry, sessionName);
if (po != null) {
po.sendAlertAsync(SmtpClientConfig.cfg.getEmailToDevelopment(), "HTML oversize @" + sessionName, "retry=" + retry, null, true);
if (iterationCount > 1) {
context.level(Level.WARN)
.memo("template height oversize iterationCount = " + iterationCount)
.error(new Err(0, null, null, null, sessionName + " template height oversize iterationCount = " + iterationCount));
if (onetimeListener == null) {
for (SinglePageHeightCalculationListener addedListener : listeners) {
if (addedListener == null) {
continue;
}
addedListener.onHeightCalculationRetry(iterationCount, pageCount, requesterTxId, htmlContent, agent, extraSpace, pageHeightMillimeters);
}
} else {
onetimeListener.onHeightCalculationRetry(iterationCount, pageCount, requesterTxId, htmlContent, agent, extraSpace, pageHeightMillimeters);
}
// if (po != null) {
// po.sendAlertAsync(SmtpClientConfig.cfg.getEmailToDevelopment(), "HTML oversize @" + sessionName, "iterationCount=" + iterationCount, null, true);
// }
}
htmlContent = htmlTemplate;
}
Expand Down Expand Up @@ -192,7 +249,6 @@ public byte[] html2PDF(String requesterTxId, String htmlContent, boolean isSingl
return pdf;
}


public List<byte[]> pdf2Images(String requesterTxId, byte[] pdf, String password, ImageType imageType, float imageDPI, String imageFormat, RenderDestination renderDestination, SessionContext context) throws IOException {
context.poi(BootPoi.PDF2IMG_BEGIN);
String sessionName = requesterTxId + "_" + imageType + "_" + renderDestination + "_" + imageDPI + "_" + imageFormat;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public static final PdfBuilderConfig buildUnprotectedConfig() {
private String userPwd = null;
private int encryptionKeyLength = ProtectionSpec.EncryptionKeyLength; // PDFBox
private int encryptionAlgorithm = ProtectionSpec.EncryptionAlgorithm; // iText
private int singlePageHeightCalculationMaxIteration = 3;

public PdfBuilderConfig() {
this(null);
Expand Down Expand Up @@ -168,4 +169,12 @@ public int getEncryptionAlgorithm() {
public void setEncryptionAlgorithm(int encryptionAlgorithm) {
this.encryptionAlgorithm = encryptionAlgorithm;
}

public int getSinglePageHeightCalculationMaxIteration() {
return singlePageHeightCalculationMaxIteration;
}

public void setSinglePageHeightCalculationMaxIteration(int singlePageHeightCalculationMaxIteration) {
this.singlePageHeightCalculationMaxIteration = singlePageHeightCalculationMaxIteration;
}
}
Loading