Skip to content
Open
Changes from 12 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
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,65 @@
public class DocumentProcessor {
private static final Logger LOGGER = Logger.getLogger(DocumentProcessor.class.getCanonicalName());

/**
* Releases PDF resources to prevent file locks and memory leaks.
* - Closes PDDocument to free OS file handles (required for file deletion)
* - Clears static containers to remove lingering references
* Should always be called in a finally block.
*/
private static void closePdfResources() throws Exception {
Exception closeFailure = null;
PDDocument document = StaticResources.getDocument();
if (document != null) {
try {
document.close();
} catch (Exception e) {
closeFailure = e;
}
}

try {
StaticLayoutContainers.closeContrastRatioConsumer();
} catch (Exception e) {
if (closeFailure != null) {
closeFailure.addSuppressed(e);
} else {
closeFailure = e;
}
}

// cleanup static containers
clearCleanupStep("StaticResources", StaticResources::clear);
clearCleanupStep("StaticContainers", () -> StaticContainers.updateContainers(null));
clearCleanupStep(
"GFStaticContainers",
org.verapdf.gf.model.impl.containers.StaticContainers::clearAllContainers
);
clearCleanupStep("StaticLayoutContainers", StaticLayoutContainers::clearContainers);
clearCleanupStep("StaticStorages", StaticStorages::clearAllContainers);
clearCleanupStep("StaticCoreContainers", StaticCoreContainers::clearAllContainers);
clearCleanupStep("StaticXmpCoreContainers", StaticXmpCoreContainers::clearAllContainers);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

if (closeFailure != null) {
throw closeFailure;
}
}

/**
* Executes a cleanup step safely without interrupting subsequent steps.
*
* Each cleanup action is isolated so that a failure in one step
* does not prevent the remaining cleanup operations from running.
* Errors are logged for debugging purposes.
*/
private static void clearCleanupStep(String name, Runnable cleanup) {
try {
cleanup.run();
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Error clearing " + name, e);
}
}

/**
* Processes a PDF file and generates the configured outputs.
*
Expand All @@ -89,15 +148,37 @@ public static void processFile(String inputPdfName, Config config) throws IOExce
* @throws IOException if unable to process the file
*/
public static ProcessingResult processFileWithResult(String inputPdfName, Config config) throws IOException {
// Phase 1: Extract
ExtractionResult extraction = extractContents(inputPdfName, config);

// Phase 2: Output (JSON/MD/HTML/PDF/Text)
long t0 = System.nanoTime();
generateOutputs(inputPdfName, extraction.getContents(), config);
long outputNs = System.nanoTime() - t0;

return new ProcessingResult(extraction.getHybridTimings(), extraction.getExtractionNs(), outputNs);
Throwable processingFailure = null;
try {
// Phase 1: Extract
ExtractionResult extraction = extractContents(inputPdfName, config);

// Phase 2: Output (JSON/MD/HTML/PDF/Text)
long t0 = System.nanoTime();
generateOutputs(inputPdfName, extraction.getContents(), config);
long outputNs = System.nanoTime() - t0;

return new ProcessingResult(extraction.getHybridTimings(), extraction.getExtractionNs(), outputNs);
} catch (IOException | RuntimeException | Error e) {
processingFailure = e;
throw e;
} finally {
// Ensures resources are always released, even if processing throws an exception
try {
closePdfResources();
} catch (Exception closeException) {
LOGGER.log(Level.WARNING, "Error during PDF resource cleanup", closeException);
if (processingFailure != null) {
processingFailure.addSuppressed(closeException);
} else {
if (closeException instanceof IOException) {
throw (IOException) closeException;
} else {
throw new IOException("Failed to close PDF resources", closeException);
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
}
}

/**
Expand Down
Loading