Skip to main content

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.

  • 0 means no timeout.
  • Values are per report instance.
  • Timeout throws net.windward.xmlreport.TimeoutException with mode TIMEOUT.

Precedence and Call Order

Timeout is now honored regardless of call order relative to processSetup().

Order of precedence:

  1. setTimeout(seconds)
  2. report.timeout property

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.TimeoutException with mode ABORT.

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() and setTimeout() over force-killing threads.
  • Keep one report per task and do not share a ProcessReport instance across unrelated jobs.
  • Catch TimeoutException and branch on mode (TIMEOUT vs ABORT).
  • Ensure application cleanup runs in finally blocks for streams and external resources.