Timeout and Abort in the Java Engine
This article explains how to use timeout and abort for report cancellation in the embedded Java Engine.
Overview
The Java Engine supports two cooperative cancellation controls on a per-report instance:
setTimeout(seconds): stop a report after a configured runtime limit.abort(): stop a specific in-progress report from another thread.
Both controls are instance-scoped. If you run many reports concurrently, calling timeout or abort on one ProcessReport instance does not stop other reports.
Timeout Behavior
Use setTimeout(seconds) on the report instance.
0means no timeout.- Values are per report instance.
- Timeout throws
net.windward.xmlreport.TimeoutExceptionwith modeTIMEOUT.
Precedence and Call Order
Timeout is now honored regardless of call order relative to processSetup().
Order of precedence:
setTimeout(seconds)report.timeoutproperty
If both are set, setTimeout(seconds) wins.
Abort Behavior
Use abort() to cancel a running report from another thread.
abort()sets cancellation state and returns immediately.- The report thread exits at the next checkpoint.
- Abort throws
net.windward.xmlreport.TimeoutExceptionwith modeABORT.
Bounded Observation
Timeout and abort are checked throughout long-running phases, including:
- Data processing loops (DNV/XSNV)
- Chart processing paths
- Layout loops
- DOCX/XLSX/PPTX parsing loops
- Office output build and PDF output paths
The design is cooperative, so cancellation occurs at checkpoints rather than by force-killing threads.
Java Usage Example
import net.windward.xmlreport.*;
import net.windward.datasource.DataSourceProvider;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;
public class JavaTimeoutAbortExample {
public static void main(String[] args) throws Exception {
ProcessReport.init();
try (FileInputStream template = new FileInputStream("template.docx");
FileOutputStream output = new FileOutputStream("report.pdf")) {
ProcessPdf report = new ProcessPdf(template, output);
// Timeout API has highest precedence over report.timeout property.
report.setTimeout(30);
report.processSetup();
Map<String, DataSourceProvider> providers = new HashMap<>();
// providers.put("", yourDatasource);
// Optional: abort from another thread.
Thread abortThread = new Thread(() -> {
try {
Thread.sleep(5000);
report.abort();
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
});
abortThread.setDaemon(true);
abortThread.start();
try {
report.processData(providers);
report.processComplete();
} catch (TimeoutException ex) {
if (ex.getMode() == TimeoutException.TIMEOUT) {
System.out.println("Report timed out");
} else if (ex.getMode() == TimeoutException.ABORT) {
System.out.println("Report aborted");
}
throw ex;
}
}
}
}
Logging and Diagnostics
The engine logs both timeout and abort observations.
Abort logs include request origin and observation details (requesting thread, observing thread, timestamps). Timeout logs include observer thread, configured timeout, deadline, and overrun timing.
Best Practices
- Prefer
abort()andsetTimeout()over force-killing threads. - Keep one report per task and do not share a
ProcessReportinstance across unrelated jobs. - Catch
TimeoutExceptionand branch on mode (TIMEOUTvsABORT). - Ensure application cleanup runs in
finallyblocks for streams and external resources.