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

davsclaus pushed a commit to branch CAMEL-26513-printer-unsupported-flavor
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 6dffb13889f6bbaf446ea4dc85528bc16380df4d
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Nov 3 15:44:54 2026 +0100

    CAMEL-26513: camel-printer - a doc flavor the print service does not 
support fails the exchange
    
    PrinterProducer skipped the print job without an error when the print 
service
    did not support the doc flavor of the flavor and mimeType options, so the
    exchange completed as if the document was printed. It now throws a
    PrintException that names the doc flavor and the print service, as
    DocPrintJob.print does. Upgrade guide and component doc updated.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../apache/camel/catalog/docs/lpr-component.adoc   |   5 +
 .../camel-printer/src/main/docs/lpr-component.adoc |   5 +
 .../camel/component/printer/PrinterProducer.java   |  12 +-
 .../printer/PrinterProducerDocFlavorTest.java      | 142 +++++++++++++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    |   7 +
 5 files changed, 168 insertions(+), 3 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/lpr-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/lpr-component.adoc
index e814de09ca29..5143d1b8cfa2 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/lpr-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/lpr-component.adoc
@@ -63,6 +63,11 @@ Sending data to the printer is very straightforward and 
involves
 creating a producer endpoint that can be sent message exchanges on in
 route.
 
+The document is printed in the doc flavor of the `flavor` and `mimeType` 
options.
+When the print service does not support that doc flavor, the exchange fails 
with a
+`javax.print.PrintException` that names the doc flavor and the print service, 
and no
+print job is created. This also applies with `sendToPrinter=false`.
+
 == Examples
 
 Usage samples.
diff --git a/components/camel-printer/src/main/docs/lpr-component.adoc 
b/components/camel-printer/src/main/docs/lpr-component.adoc
index e814de09ca29..5143d1b8cfa2 100644
--- a/components/camel-printer/src/main/docs/lpr-component.adoc
+++ b/components/camel-printer/src/main/docs/lpr-component.adoc
@@ -63,6 +63,11 @@ Sending data to the printer is very straightforward and 
involves
 creating a producer endpoint that can be sent message exchanges on in
 route.
 
+The document is printed in the doc flavor of the `flavor` and `mimeType` 
options.
+When the print service does not support that doc flavor, the exchange fails 
with a
+`javax.print.PrintException` that names the doc flavor and the print service, 
and no
+print job is created. This also applies with `sendToPrinter=false`.
+
 == Examples
 
 Usage samples.
diff --git 
a/components/camel-printer/src/main/java/org/apache/camel/component/printer/PrinterProducer.java
 
b/components/camel-printer/src/main/java/org/apache/camel/component/printer/PrinterProducer.java
index f35ef3439f0d..ddf1f40aeb91 100644
--- 
a/components/camel-printer/src/main/java/org/apache/camel/component/printer/PrinterProducer.java
+++ 
b/components/camel-printer/src/main/java/org/apache/camel/component/printer/PrinterProducer.java
@@ -59,10 +59,16 @@ public class PrinterProducer extends DefaultProducer {
     }
 
     private void print(InputStream body, String jobName) throws PrintException 
{
-        if 
(printerOperations.getPrintService().isDocFlavorSupported(printerOperations.getFlavor()))
 {
-            PrintDocument printDoc = new PrintDocument(body, 
printerOperations.getFlavor());
-            printerOperations.print(printDoc, config.isSendToPrinter(), 
config.getMimeType(), jobName);
+        PrintService service = printerOperations.getPrintService();
+        DocFlavor flavor = printerOperations.getFlavor();
+        // fail, as DocPrintJob.print does, rather than skipping the job 
without an error
+        if (!service.isDocFlavorSupported(flavor)) {
+            throw new PrintException(
+                    "Print service " + service.getName() + " does not support 
the doc flavor " + flavor
+                                     + ". Set the flavor and mimeType options 
to a doc flavor this print service supports.");
         }
+        PrintDocument printDoc = new PrintDocument(body, flavor);
+        printerOperations.print(printDoc, config.isSendToPrinter(), 
config.getMimeType(), jobName);
     }
 
     private DocFlavor assignDocFlavor() {
diff --git 
a/components/camel-printer/src/test/java/org/apache/camel/component/printer/PrinterProducerDocFlavorTest.java
 
b/components/camel-printer/src/test/java/org/apache/camel/component/printer/PrinterProducerDocFlavorTest.java
new file mode 100644
index 000000000000..6957bd76c091
--- /dev/null
+++ 
b/components/camel-printer/src/test/java/org/apache/camel/component/printer/PrinterProducerDocFlavorTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.printer;
+
+import javax.print.Doc;
+import javax.print.DocFlavor;
+import javax.print.DocPrintJob;
+import javax.print.PrintException;
+import javax.print.PrintService;
+import javax.print.attribute.PrintRequestAttributeSet;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * The doc flavor check of the lpr producer, on a mocked PrintService (no 
print service lookup, so nothing reaches a
+ * real printer).
+ */
+public class PrinterProducerDocFlavorTest {
+
+    private CamelContext context;
+    private PrintService printService;
+    private DocPrintJob printJob;
+    private PrinterProducer producer;
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        context = new DefaultCamelContext();
+        context.start();
+
+        printService = mock(PrintService.class);
+        when(printService.getName()).thenReturn("MockedPrinter");
+        printJob = mock(DocPrintJob.class);
+        when(printService.createPrintJob()).thenReturn(printJob);
+    }
+
+    @AfterEach
+    public void tearDown() {
+        if (producer != null) {
+            producer.stop();
+        }
+        context.stop();
+    }
+
+    private void startProducer(String uri) {
+        PrinterEndpoint endpoint = context.getEndpoint(uri, 
PrinterEndpoint.class);
+        producer = new PrinterProducer(endpoint, endpoint.getConfig());
+        producer.setPrintService(printService);
+        producer.start();
+    }
+
+    private Exchange exchange(String body) {
+        Exchange exchange = new DefaultExchange(context);
+        exchange.getIn().setBody(body);
+        return exchange;
+    }
+
+    @Test
+    public void unsupportedFlavorFails() throws Exception {
+        
when(printService.isDocFlavorSupported(any(DocFlavor.class))).thenReturn(Boolean.FALSE);
+        
startProducer("lpr://localhost/MockedPrinter?flavor=DocFlavor.INPUT_STREAM&mimeType=PDF");
+
+        PrintException e = assertThrows(PrintException.class, () -> 
producer.process(exchange("Hello Printer")));
+
+        assertTrue(e.getMessage().contains("MockedPrinter"), e.getMessage());
+        
assertTrue(e.getMessage().contains(DocFlavor.INPUT_STREAM.PDF.toString()), 
e.getMessage());
+        verify(printService).isDocFlavorSupported(DocFlavor.INPUT_STREAM.PDF);
+        verify(printService, never()).createPrintJob();
+    }
+
+    @Test
+    public void unsupportedFlavorFailsWithoutSendToPrinter() throws Exception {
+        
when(printService.isDocFlavorSupported(any(DocFlavor.class))).thenReturn(Boolean.FALSE);
+        startProducer("lpr://localhost/MockedPrinter?sendToPrinter=false");
+
+        PrintException e = assertThrows(PrintException.class, () -> 
producer.process(exchange("Hello Printer")));
+
+        
assertTrue(e.getMessage().contains(DocFlavor.BYTE_ARRAY.AUTOSENSE.toString()), 
e.getMessage());
+        verify(printService, never()).createPrintJob();
+    }
+
+    @Test
+    public void unsupportedFlavorFailsTheRoute() throws Exception {
+        
when(printService.isDocFlavorSupported(any(DocFlavor.class))).thenReturn(Boolean.FALSE);
+        startProducer("lpr://localhost/MockedPrinter");
+
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start").process(producer).to("mock:printed");
+            }
+        });
+        MockEndpoint printed = context.getEndpoint("mock:printed", 
MockEndpoint.class);
+        printed.expectedMessageCount(0);
+
+        Exchange exchange = 
context.createProducerTemplate().send("direct:start", exchange("Hello 
Printer"));
+
+        assertEquals(PrintException.class, exchange.getException().getClass());
+        printed.assertIsSatisfied();
+        verify(printService, never()).createPrintJob();
+    }
+
+    @Test
+    public void supportedFlavorIsPrinted() throws Exception {
+        
when(printService.isDocFlavorSupported(DocFlavor.INPUT_STREAM.PDF)).thenReturn(Boolean.TRUE);
+        
startProducer("lpr://localhost/MockedPrinter?flavor=DocFlavor.INPUT_STREAM&mimeType=PDF");
+
+        producer.process(exchange("Hello Printer"));
+
+        verify(printJob).print(any(Doc.class), 
any(PrintRequestAttributeSet.class));
+    }
+}
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index 7c82ebd18930..3e445dad8b7a 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -1328,6 +1328,13 @@ The `lpr` producer submitted a print job with no data, 
without an error, for a m
 `InputStream`, such as a `Map`, a POJO or a number, and for a message without 
a body. It now fails the exchange with an
 `InvalidPayloadException`. Send the document as text, bytes, a stream or a 
file.
 
+=== camel-printer - a doc flavor the print service does not support fails the 
exchange
+
+The `lpr` producer skipped the print job, without an error, when the print 
service did not support the doc flavor of
+the `flavor` and `mimeType` options, and the exchange completed as if the 
document was printed. It now fails the
+exchange with a `javax.print.PrintException` that names the doc flavor and the 
print service, also with
+`sendToPrinter=false`. Set the `flavor` and `mimeType` options to a doc flavor 
that the printer supports.
+
 === camel-debezium - the row flattened by ExtractNewRecordState is the body
 
 With the Debezium `ExtractNewRecordState` single message transformation 
(`ExtractNewDocumentState` for MongoDB), the

Reply via email to