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

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 59fb5b7673dd CAMEL-26518: camel-alibaba-oss - the consumer sets its 
client before it starts polling (#29191)
59fb5b7673dd is described below

commit 59fb5b7673ddb751d70241ff9efc2a6b3955588b
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Nov 5 07:16:36 2026 +0100

    CAMEL-26518: camel-alibaba-oss - the consumer sets its client before it 
starts polling (#29191)
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../camel/component/alibaba/oss/OSSConsumer.java   |   9 +-
 .../alibaba/oss/OSSConsumerFirstPollTest.java      | 161 +++++++++++++++++++++
 2 files changed, 166 insertions(+), 4 deletions(-)

diff --git 
a/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSConsumer.java
 
b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSConsumer.java
index bd8eab5ec3a6..00d64f5dd277 100644
--- 
a/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSConsumer.java
+++ 
b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSConsumer.java
@@ -65,13 +65,14 @@ public class OSSConsumer extends 
ScheduledBatchPollingConsumer {
 
     @Override
     protected void doStart() throws Exception {
-        super.doStart();
-
-        this.ossClient = this.endpoint.initClient();
-
         if (ObjectHelper.isEmpty(endpoint.getBucketName())) {
             throw new IllegalArgumentException("Bucket name is mandatory to 
consume objects");
         }
+
+        // the client must be set before super.doStart() starts the scheduler, 
which may poll right away
+        this.ossClient = this.endpoint.initClient();
+
+        super.doStart();
     }
 
     @Override
diff --git 
a/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/OSSConsumerFirstPollTest.java
 
b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/OSSConsumerFirstPollTest.java
new file mode 100644
index 000000000000..61a29b68948a
--- /dev/null
+++ 
b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/OSSConsumerFirstPollTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.alibaba.oss;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import com.aliyun.sdk.service.oss2.OSSClient;
+import com.aliyun.sdk.service.oss2.models.GetObjectRequest;
+import com.aliyun.sdk.service.oss2.models.GetObjectResult;
+import com.aliyun.sdk.service.oss2.models.ListObjectsV2Request;
+import com.aliyun.sdk.service.oss2.models.ListObjectsV2Result;
+import com.aliyun.sdk.service.oss2.models.ObjectSummary;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Consumer;
+import org.apache.camel.Endpoint;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spi.PollingConsumerPollStrategy;
+import org.apache.camel.spi.ScheduledPollConsumerScheduler;
+import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * The scheduler may run the first poll as soon as the consumer starts it 
(initialDelay=0), so the consumer must have
+ * its client before it starts the scheduler. The scheduler of this test runs 
the first poll right away, in the thread
+ * that starts the consumer.
+ */
+class OSSConsumerFirstPollTest extends CamelTestSupport {
+
+    private final List<Exception> failedPolls = new CopyOnWriteArrayList<>();
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+        context.getRegistry().bind("ossClient", ossClient());
+        context.getRegistry().bind("pollOnStart", new PollOnStartScheduler());
+        context.getRegistry().bind("recordFailedPolls", new 
PollingConsumerPollStrategy() {
+            @Override
+            public boolean begin(Consumer consumer, Endpoint endpoint) {
+                return true;
+            }
+
+            @Override
+            public void commit(Consumer consumer, Endpoint endpoint, int 
polledMessages) {
+                // noop
+            }
+
+            @Override
+            public boolean rollback(Consumer consumer, Endpoint endpoint, int 
retryCounter, Exception e) {
+                failedPolls.add(e);
+                return false;
+            }
+        });
+        return context;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                
from("alibaba-oss:bucket?ossClient=#ossClient&scheduler=#pollOnStart&pollStrategy=#recordFailedPolls")
+                        .convertBodyTo(String.class)
+                        .to("mock:result");
+            }
+        };
+    }
+
+    @Test
+    void firstPollRunsWithTheClient() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceived("a.txt");
+
+        mock.assertIsSatisfied();
+        assertThat(failedPolls).as("the first poll does not fail").isEmpty();
+    }
+
+    private static OSSClient ossClient() {
+        OSSClient client = Mockito.mock(OSSClient.class);
+        ObjectSummary summary = Mockito.mock(ObjectSummary.class);
+        Mockito.when(summary.key()).thenReturn("a.txt");
+        ListObjectsV2Result listing = Mockito.mock(ListObjectsV2Result.class);
+        Mockito.when(listing.contents()).thenReturn(List.of(summary));
+        
Mockito.when(client.listObjectsV2(Mockito.any(ListObjectsV2Request.class))).thenReturn(listing);
+        
Mockito.when(client.getObject(Mockito.any(GetObjectRequest.class))).thenAnswer(i
 -> {
+            GetObjectResult result = Mockito.mock(GetObjectResult.class);
+            Mockito.when(result.body()).thenReturn(new 
ByteArrayInputStream("a.txt".getBytes(StandardCharsets.UTF_8)));
+            return result;
+        });
+        return client;
+    }
+
+    /**
+     * Runs the task once when the scheduler is started.
+     */
+    private static final class PollOnStartScheduler extends ServiceSupport 
implements ScheduledPollConsumerScheduler {
+
+        private CamelContext camelContext;
+        private Runnable task;
+        private boolean started;
+
+        @Override
+        public void onInit(Consumer consumer) {
+            // noop
+        }
+
+        @Override
+        public void scheduleTask(Runnable task) {
+            this.task = task;
+        }
+
+        @Override
+        public void unscheduleTask() {
+            task = null;
+        }
+
+        @Override
+        public void startScheduler() {
+            if (!started && task != null) {
+                started = true;
+                task.run();
+            }
+        }
+
+        @Override
+        public boolean isSchedulerStarted() {
+            return started;
+        }
+
+        @Override
+        public void setCamelContext(CamelContext camelContext) {
+            this.camelContext = camelContext;
+        }
+
+        @Override
+        public CamelContext getCamelContext() {
+            return camelContext;
+        }
+    }
+}

Reply via email to