gnodet-bot commented on code in PR #29618:
URL: https://github.com/apache/camel/pull/29618#discussion_r4536183574


##########
components/camel-kafka/src/test/java/org/apache/camel/component/kafka/consumer/errorhandler/KafkaErrorStrategiesTest.java:
##########
@@ -0,0 +1,113 @@
+/*
+ * 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.kafka.consumer.errorhandler;
+
+import org.apache.camel.component.kafka.KafkaComponent;
+import org.apache.camel.component.kafka.KafkaConfiguration;
+import org.apache.camel.component.kafka.KafkaEndpoint;
+import org.apache.camel.component.kafka.KafkaFetchRecords;
+import org.apache.camel.component.kafka.PollExceptionStrategy;
+import org.apache.camel.component.kafka.PollExceptionStrategyFactory;
+import org.apache.camel.component.kafka.PollOnError;
+import org.apache.kafka.clients.consumer.Consumer;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class KafkaErrorStrategiesTest {
+
+    private final Consumer<byte[], byte[]> consumer = mock(Consumer.class);
+
+    private KafkaEndpoint endpointWith(KafkaComponent component, PollOnError 
pollOnError) {
+        KafkaConfiguration configuration = mock(KafkaConfiguration.class);
+        when(configuration.getPollOnError()).thenReturn(pollOnError);
+
+        KafkaEndpoint endpoint = mock(KafkaEndpoint.class);
+        when(endpoint.getComponent()).thenReturn(component);
+        when(endpoint.getConfiguration()).thenReturn(configuration);
+        return endpoint;
+    }
+
+    @Test
+    void defaultsToTheBuiltInStrategyForThePollOnErrorConfiguration() {
+        KafkaComponent component = mock(KafkaComponent.class);
+        when(component.getPollExceptionStrategyFactory()).thenReturn(null);
+        when(component.getPollExceptionStrategy()).thenReturn(null);
+        KafkaEndpoint endpoint = endpointWith(component, 
PollOnError.RECONNECT);
+
+        PollExceptionStrategy strategy = KafkaErrorStrategies.strategies(
+                mock(KafkaFetchRecords.class), endpoint, consumer);
+
+        assertInstanceOf(ReconnectErrorStrategy.class, strategy);
+    }
+
+    @Test
+    void honoursTheLegacyComponentStrategyWhenNoFactoryIsSet() {
+        PollExceptionStrategy legacy = mock(PollExceptionStrategy.class);
+        KafkaComponent component = mock(KafkaComponent.class);
+        when(component.getPollExceptionStrategyFactory()).thenReturn(null);
+        when(component.getPollExceptionStrategy()).thenReturn(legacy);
+        KafkaEndpoint endpoint = endpointWith(component, 
PollOnError.RECONNECT);
+
+        PollExceptionStrategy strategy = KafkaErrorStrategies.strategies(
+                mock(KafkaFetchRecords.class), endpoint, consumer);
+
+        assertSame(legacy, strategy);
+    }
+
+    @Test
+    void factoryTakesPrecedenceOverTheLegacyComponentStrategy() {
+        PollExceptionStrategy legacy = mock(PollExceptionStrategy.class);
+        PollExceptionStrategy fromFactory = mock(PollExceptionStrategy.class);
+        PollExceptionStrategyFactory factory = 
mock(PollExceptionStrategyFactory.class);
+        when(factory.create(org.mockito.ArgumentMatchers.any(), 
org.mockito.ArgumentMatchers.any(),
+                org.mockito.ArgumentMatchers.any())).thenReturn(fromFactory);
+
+        KafkaComponent component = mock(KafkaComponent.class);

Review Comment:
   πŸ’‘ **Style nit:** `org.mockito.ArgumentMatchers.any()` is used as a 
fully-qualified name here while the other Mockito utilities (`mock`, `when`) 
are statically imported. Consider adding a static import for `any` to keep the 
style consistent:
   
   ```suggestion
           when(factory.create(any(), any(),
                   any())).thenReturn(fromFactory);
   ```



##########
components/camel-kafka/src/main/java/org/apache/camel/component/kafka/consumer/errorhandler/KafkaErrorStrategies.java:
##########
@@ -35,26 +34,19 @@ public static PollExceptionStrategy strategies(
             KafkaFetchRecords recordFetcher, KafkaEndpoint endpoint, 
Consumer<?, ?> consumer) {
         ObjectHelper.notNull(consumer, "consumer");
 
+        // a factory is created per fetch thread and receives the owning fetch 
records task, so it supports the
+        // fetcher-bound built-in strategies and works correctly with multiple 
consumer threads
+        PollExceptionStrategyFactory factory = 
endpoint.getComponent().getPollExceptionStrategyFactory();
+        if (factory != null) {
+            return factory.create(recordFetcher, endpoint, consumer);
+        }
+
+        // a single strategy instance shared across all fetch threads; kept 
for backwards compatibility
         PollExceptionStrategy strategy = 
endpoint.getComponent().getPollExceptionStrategy();
         if (strategy != null) {
             return strategy;
         }
 
-        PollOnError onError = endpoint.getConfiguration().getPollOnError();
-
-        switch (onError) {
-            case RETRY:
-                return new RetryErrorStrategy();
-            case RECONNECT:
-                return new ReconnectErrorStrategy(recordFetcher);
-            case ERROR_HANDLER:
-                return new BridgeErrorStrategy(recordFetcher, consumer);
-            case DISCARD:
-                return new DiscardErrorStrategy(consumer);
-            case STOP:
-                return new StopErrorStrategy(recordFetcher);
-            default:
-                throw new RuntimeCamelException("The provided pollOnError 
strategy is invalid");
-        }
+        return new DefaultPollExceptionStrategyFactory().create(recordFetcher, 
endpoint, consumer);
     }

Review Comment:
   πŸ’‘ **Minor:** The fallback path allocates a new 
`DefaultPollExceptionStrategyFactory` on every call to `strategies()`. Since 
`DefaultPollExceptionStrategyFactory` is stateless, consider promoting it to a 
constant to avoid a small but unnecessary per-call allocation:
   
   ```suggestion
           return DEFAULT_FACTORY.create(recordFetcher, endpoint, consumer);
   ```
   
   …with `private static final DefaultPollExceptionStrategyFactory 
DEFAULT_FACTORY = new DefaultPollExceptionStrategyFactory();` declared at the 
top of the class. (Alternatively, the method could also move into the factory 
itself.)



##########
components/camel-kafka/src/main/java/org/apache/camel/component/kafka/PollExceptionStrategyFactory.java:
##########
@@ -0,0 +1,41 @@
+/*
+ * 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.kafka;
+
+import org.apache.kafka.clients.consumer.Consumer;
+
+/**
+ * Factory to create a {@link PollExceptionStrategy} for each Kafka consumer 
fetch thread.
+ * <p/>

Review Comment:
   πŸ’‘ **Style nit:** `<p/>` is not valid HTML4/5 β€” use `<p>` (self-closing void 
elements are not valid in HTML) or simply drop it, as Javadoc tools handle bare 
paragraph breaks fine.
   
   ```suggestion
    * <p>
   ```



##########
components/camel-kafka/src/main/java/org/apache/camel/component/kafka/consumer/errorhandler/DefaultPollExceptionStrategyFactory.java:
##########
@@ -0,0 +1,68 @@
+/*
+ * 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.kafka.consumer.errorhandler;
+
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.kafka.KafkaEndpoint;
+import org.apache.camel.component.kafka.KafkaFetchRecords;
+import org.apache.camel.component.kafka.PollExceptionStrategy;
+import org.apache.camel.component.kafka.PollExceptionStrategyFactory;
+import org.apache.camel.component.kafka.PollOnError;
+import org.apache.kafka.clients.consumer.Consumer;
+
+/**
+ * Default {@link PollExceptionStrategyFactory} that creates the built-in 
strategy selected by the endpoint's
+ * {@link PollOnError} configuration.
+ * <p/>

Review Comment:
   πŸ’‘ **Style nit:** `<p/>` is not valid HTML4/5 β€” use `<p>` or drop it.
   
   ```suggestion
    * <p>
   ```



##########
components/camel-kafka/src/main/java/org/apache/camel/component/kafka/PollExceptionStrategyFactory.java:
##########
@@ -0,0 +1,41 @@
+/*
+ * 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.kafka;
+
+import org.apache.kafka.clients.consumer.Consumer;
+
+/**
+ * Factory to create a {@link PollExceptionStrategy} for each Kafka consumer 
fetch thread.
+ * <p/>
+ * Unlike setting a single {@link PollExceptionStrategy} on the component, 
which shares one instance across all consumer
+ * threads, this factory is invoked once per fetch thread and receives the 
owning fetch records task. This allows a
+ * custom strategy to be bound to its fetch records task, which is required by 
the built-in reconnect, stop, and bridge
+ * strategies to drive the consumer (for example to request a reconnect). It 
therefore also works correctly when a
+ * single endpoint uses multiple consumer threads (the <tt>consumersCount</tt> 
option).
+ */
+public interface PollExceptionStrategyFactory {
+

Review Comment:
   πŸ’‘ **Style nit:** `PollExceptionStrategyFactory` is a single-abstract-method 
interface β€” adding `@FunctionalInterface` documents the intent, enables lambda 
usage, and causes a compile error if a second abstract method is accidentally 
added:
   
   ```suggestion
   @FunctionalInterface
   public interface PollExceptionStrategyFactory {
   ```



##########
components/camel-kafka/src/main/java/org/apache/camel/component/kafka/PollExceptionStrategyFactory.java:
##########
@@ -0,0 +1,41 @@
+/*
+ * 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.kafka;
+
+import org.apache.kafka.clients.consumer.Consumer;
+
+/**
+ * Factory to create a {@link PollExceptionStrategy} for each Kafka consumer 
fetch thread.
+ * <p/>
+ * Unlike setting a single {@link PollExceptionStrategy} on the component, 
which shares one instance across all consumer
+ * threads, this factory is invoked once per fetch thread and receives the 
owning fetch records task. This allows a
+ * custom strategy to be bound to its fetch records task, which is required by 
the built-in reconnect, stop, and bridge
+ * strategies to drive the consumer (for example to request a reconnect). It 
therefore also works correctly when a
+ * single endpoint uses multiple consumer threads (the <tt>consumersCount</tt> 
option).
+ */

Review Comment:
   πŸ’‘ **Style nit:** `<tt>` is deprecated in HTML5 β€” use `{@code 
consumersCount}` instead:
   
   ```suggestion
    * single endpoint uses multiple consumer threads (the {@code 
consumersCount} option).
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to