You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2026/03/02 10:13:27 UTC

(camel) branch task-17 created (now 83dd20f462a6)

This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a change to branch task-17
in repository https://gitbox.apache.org/repos/asf/camel.git


      at 83dd20f462a6 CAMEL-23106 - camel-docling - Remove temp file in DoclingProducer.getInputPath()

This branch includes the following new commits:

     new 83dd20f462a6 CAMEL-23106 - camel-docling - Remove temp file in DoclingProducer.getInputPath()

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(camel) 01/01: CAMEL-23106 - camel-docling - Remove temp file in DoclingProducer.getInputPath()

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a commit to branch task-17
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 83dd20f462a64de1807c1bfc9cf0b73723d2bf37
Author: Andrea Cosentino <an...@gmail.com>
AuthorDate: Sun Mar 1 14:20:31 2026 +0100

    CAMEL-23106 - camel-docling - Remove temp file in DoclingProducer.getInputPath()
    
    Signed-off-by: Andrea Cosentino <an...@gmail.com>
---
 .../camel/component/docling/DoclingProducer.java   |  17 ++++
 .../docling/DoclingTempFileCleanupTest.java        | 105 +++++++++++++++++++++
 2 files changed, 122 insertions(+)

diff --git a/components/camel-ai/camel-docling/src/main/java/org/apache/camel/component/docling/DoclingProducer.java b/components/camel-ai/camel-docling/src/main/java/org/apache/camel/component/docling/DoclingProducer.java
index e066933887bb..a1a04f6f70e9 100644
--- a/components/camel-ai/camel-docling/src/main/java/org/apache/camel/component/docling/DoclingProducer.java
+++ b/components/camel-ai/camel-docling/src/main/java/org/apache/camel/component/docling/DoclingProducer.java
@@ -72,6 +72,7 @@ import org.apache.camel.InvalidPayloadException;
 import org.apache.camel.WrappedFile;
 import org.apache.camel.support.DefaultProducer;
 import org.apache.camel.support.OAuthHelper;
+import org.apache.camel.support.SynchronizationAdapter;
 import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -1506,6 +1507,7 @@ public class DoclingProducer extends DefaultProducer {
                 // Treat as content to be written to a temp file
                 Path tempFile = Files.createTempFile("docling-", ".tmp");
                 Files.write(tempFile, content.getBytes());
+                registerTempFileCleanup(exchange, tempFile);
                 validateFileSize(tempFile.toString());
                 return tempFile.toString();
             }
@@ -1515,6 +1517,7 @@ public class DoclingProducer extends DefaultProducer {
             }
             Path tempFile = Files.createTempFile("docling-", ".tmp");
             Files.write(tempFile, content);
+            registerTempFileCleanup(exchange, tempFile);
             return tempFile.toString();
         } else if (body instanceof File file) {
             validateFileSize(file.getAbsolutePath());
@@ -1524,6 +1527,20 @@ public class DoclingProducer extends DefaultProducer {
         throw new InvalidPayloadException(exchange, String.class);
     }
 
+    private void registerTempFileCleanup(Exchange exchange, Path tempFile) {
+        exchange.getExchangeExtension().addOnCompletion(new SynchronizationAdapter() {
+            @Override
+            public void onDone(Exchange exchange) {
+                try {
+                    Files.deleteIfExists(tempFile);
+                    LOG.debug("Cleaned up temp file: {}", tempFile);
+                } catch (IOException e) {
+                    LOG.warn("Failed to clean up temp file: {}", tempFile, e);
+                }
+            }
+        });
+    }
+
     private void validateFileSize(String filePath) throws IOException {
         Path path = Paths.get(filePath);
         if (Files.exists(path)) {
diff --git a/components/camel-ai/camel-docling/src/test/java/org/apache/camel/component/docling/DoclingTempFileCleanupTest.java b/components/camel-ai/camel-docling/src/test/java/org/apache/camel/component/docling/DoclingTempFileCleanupTest.java
new file mode 100644
index 000000000000..69c0178e19ff
--- /dev/null
+++ b/components/camel-ai/camel-docling/src/test/java/org/apache/camel/component/docling/DoclingTempFileCleanupTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.camel.component.docling;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Verifies that temporary files created in {@code DoclingProducer.getInputPath()} are cleaned up after exchange
+ * processing completes.
+ *
+ * <p>
+ * Before the fix, temp files created for String content and byte[] bodies accumulated on disk indefinitely. After the
+ * fix, an {@code addOnCompletion} callback deletes them when the exchange finishes.
+ */
+class DoclingTempFileCleanupTest extends CamelTestSupport {
+
+    @Test
+    void tempFileFromStringContentIsCleanedUp() throws Exception {
+        // Snapshot temp files before
+        List<Path> before = listDoclingTempFiles();
+
+        // Send string content (not a path, not a URL) — this triggers temp file creation.
+        // The docling CLI will fail (not installed), but the temp file cleanup
+        // runs on exchange completion regardless of success or failure.
+        try {
+            template.requestBody("direct:convert", "This is raw text content to convert");
+        } catch (CamelExecutionException e) {
+            // Expected — docling binary not available in test env
+        }
+
+        // After exchange completes, temp files should have been cleaned up
+        List<Path> after = listDoclingTempFiles();
+        List<Path> leaked = new ArrayList<>(after);
+        leaked.removeAll(before);
+
+        assertTrue(leaked.isEmpty(),
+                "Temp files leaked after exchange completion: " + leaked);
+    }
+
+    @Test
+    void tempFileFromByteArrayIsCleanedUp() throws Exception {
+        List<Path> before = listDoclingTempFiles();
+
+        try {
+            template.requestBody("direct:convert", "Binary content for conversion".getBytes());
+        } catch (CamelExecutionException e) {
+            // Expected — docling binary not available in test env
+        }
+
+        List<Path> after = listDoclingTempFiles();
+        List<Path> leaked = new ArrayList<>(after);
+        leaked.removeAll(before);
+
+        assertTrue(leaked.isEmpty(),
+                "Temp files leaked after exchange completion: " + leaked);
+    }
+
+    private List<Path> listDoclingTempFiles() throws IOException {
+        List<Path> result = new ArrayList<>();
+        Path tmpDir = Path.of(System.getProperty("java.io.tmpdir"));
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(tmpDir, "docling-*.tmp")) {
+            for (Path entry : stream) {
+                result.add(entry);
+            }
+        }
+        return result;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:convert")
+                        .to("docling:convert?operation=CONVERT_TO_MARKDOWN");
+            }
+        };
+    }
+}