This is an automated email from the ASF dual-hosted git repository.
fmariani 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 66cf13f220b0 Consider WrappedFile.getFIleLength() in all components
working with Files/Streams
66cf13f220b0 is described below
commit 66cf13f220b02acf98db2984c1175b43a2c4b3d2
Author: Croway <[email protected]>
AuthorDate: Thu Jan 29 11:36:23 2026 +0100
Consider WrappedFile.getFIleLength() in all components working with
Files/Streams
---
.../camel/component/aws2/s3/AWS2S3Producer.java | 4 ++
.../azure/storage/blob/BlobStreamAndLength.java | 9 ++--
.../storage/datalake/FileStreamAndLength.java | 11 +++--
.../google/storage/GoogleCloudStorageProducer.java | 14 +++++-
.../component/huaweicloud/obs/OBSProducer.java | 6 +++
.../src/main/docs/ibm-cos-component.adoc | 54 ++++++++++++++++++++++
.../camel/component/ibm/cos/IBMCOSProducer.java | 11 +++++
.../camel/component/minio/MinioProducer.java | 19 ++++++--
8 files changed, 116 insertions(+), 12 deletions(-)
diff --git
a/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Producer.java
b/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Producer.java
index 2603723906de..b0e14787cbac 100644
---
a/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Producer.java
+++
b/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Producer.java
@@ -174,6 +174,10 @@ public class AWS2S3Producer extends DefaultProducer {
// Need to check if the message body is WrappedFile
if (obj instanceof WrappedFile<?> wf) {
+ // Get file length from WrappedFile before unwrapping (works for
remote files like SFTP)
+ if (contentLength <= 0) {
+ contentLength = wf.getFileLength();
+ }
obj = wf.getFile();
}
if (obj instanceof File f) {
diff --git
a/components/camel-azure/camel-azure-storage-blob/src/main/java/org/apache/camel/component/azure/storage/blob/BlobStreamAndLength.java
b/components/camel-azure/camel-azure-storage-blob/src/main/java/org/apache/camel/component/azure/storage/blob/BlobStreamAndLength.java
index 34bd2e3d6885..d2908a453a04 100644
---
a/components/camel-azure/camel-azure-storage-blob/src/main/java/org/apache/camel/component/azure/storage/blob/BlobStreamAndLength.java
+++
b/components/camel-azure/camel-azure-storage-blob/src/main/java/org/apache/camel/component/azure/storage/blob/BlobStreamAndLength.java
@@ -43,9 +43,12 @@ public final class BlobStreamAndLength {
Long blobSize =
exchange.getIn().getHeader(BlobConstants.BLOB_UPLOAD_SIZE, () -> null,
Long.class);
exchange.getIn().removeHeader(BlobConstants.BLOB_UPLOAD_SIZE); //
remove to avoid issues for further uploads
- if (body instanceof WrappedFile) {
- // unwrap file
- body = ((WrappedFile) body).getFile();
+ if (body instanceof WrappedFile wf) {
+ // Get file length from WrappedFile before unwrapping (works for
remote files like SFTP)
+ if (blobSize == null) {
+ blobSize = wf.getFileLength();
+ }
+ body = wf.getFile();
}
if (body instanceof InputStream) {
diff --git
a/components/camel-azure/camel-azure-storage-datalake/src/main/java/org/apache/camel/component/azure/storage/datalake/FileStreamAndLength.java
b/components/camel-azure/camel-azure-storage-datalake/src/main/java/org/apache/camel/component/azure/storage/datalake/FileStreamAndLength.java
index 44abf44520ce..ce6c210db692 100644
---
a/components/camel-azure/camel-azure-storage-datalake/src/main/java/org/apache/camel/component/azure/storage/datalake/FileStreamAndLength.java
+++
b/components/camel-azure/camel-azure-storage-datalake/src/main/java/org/apache/camel/component/azure/storage/datalake/FileStreamAndLength.java
@@ -38,16 +38,21 @@ public final class FileStreamAndLength {
@SuppressWarnings("rawtypes")
public static FileStreamAndLength
createFileStreamAndLengthFromExchangeBody(final Exchange exchange) throws
IOException {
Object body = exchange.getIn().getBody();
+ long fileLength = -1;
- if (body instanceof WrappedFile) {
- body = ((WrappedFile) body).getFile();
+ if (body instanceof WrappedFile wf) {
+ // Get file length from WrappedFile before unwrapping (works for
remote files like SFTP)
+ fileLength = wf.getFileLength();
+ body = wf.getFile();
}
if (body instanceof InputStream) {
if (!((InputStream) body).markSupported()) {
throw new IllegalArgumentException("Inputstream does not
support mark rest operations");
}
- return new FileStreamAndLength((InputStream) body,
DataLakeUtils.getInputStreamLength((InputStream) body));
+ // Use cached file length if available, otherwise calculate from
stream
+ long length = fileLength > 0 ? fileLength :
DataLakeUtils.getInputStreamLength((InputStream) body);
+ return new FileStreamAndLength((InputStream) body, length);
}
if (body instanceof File) {
diff --git
a/components/camel-google/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageProducer.java
b/components/camel-google/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageProducer.java
index 83e98449baf4..723b87050a53 100644
---
a/components/camel-google/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageProducer.java
+++
b/components/camel-google/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageProducer.java
@@ -98,17 +98,27 @@ public class GoogleCloudStorageProducer extends
DefaultProducer {
InputStream is;
Object obj = exchange.getIn().getMandatoryBody();
+ long fileLength = -1;
// Need to check if the message body is WrappedFile
- if (obj instanceof WrappedFile) {
- obj = ((WrappedFile<?>) obj).getFile();
+ if (obj instanceof WrappedFile<?> wf) {
+ // Get file length from WrappedFile before unwrapping (works for
remote files like SFTP)
+ fileLength = wf.getFileLength();
+ obj = wf.getFile();
}
if (obj instanceof File) {
File filePayload = (File) obj;
is = new FileInputStream(filePayload);
+ if (fileLength <= 0) {
+ fileLength = filePayload.length();
+ }
} else {
is = exchange.getIn().getMandatoryBody(InputStream.class);
}
+ // Set content length from WrappedFile if available and not already set
+ if (fileLength > 0 && !objectMetadata.containsKey("Content-Length")) {
+ objectMetadata.put("Content-Length", String.valueOf(fileLength));
+ }
// Handle Content-Length if not already set
is = setContentLength(objectMetadata, is);
diff --git
a/components/camel-huawei/camel-huaweicloud-obs/src/main/java/org/apache/camel/component/huaweicloud/obs/OBSProducer.java
b/components/camel-huawei/camel-huaweicloud-obs/src/main/java/org/apache/camel/component/huaweicloud/obs/OBSProducer.java
index 0843703231b6..c4e678da8618 100644
---
a/components/camel-huawei/camel-huaweicloud-obs/src/main/java/org/apache/camel/component/huaweicloud/obs/OBSProducer.java
+++
b/components/camel-huawei/camel-huaweicloud-obs/src/main/java/org/apache/camel/component/huaweicloud/obs/OBSProducer.java
@@ -40,6 +40,7 @@ import com.obs.services.model.ObsBucket;
import com.obs.services.model.ObsObject;
import com.obs.services.model.PutObjectResult;
import org.apache.camel.Exchange;
+import org.apache.camel.WrappedFile;
import org.apache.camel.component.huaweicloud.obs.constants.OBSConstants;
import org.apache.camel.component.huaweicloud.obs.constants.OBSOperations;
import org.apache.camel.component.huaweicloud.obs.constants.OBSProperties;
@@ -112,6 +113,11 @@ public class OBSProducer extends DefaultProducer {
Object body = exchange.getMessage().getBody();
+ // Handle WrappedFile (e.g., from SFTP, FTP) by extracting the
underlying file/stream
+ if (body instanceof WrappedFile<?> wf) {
+ body = wf.getFile();
+ }
+
// if body doesn't contain File, then user must pass object name.
Bucket name is mandatory in all case
if ((ObjectHelper.isEmpty(clientConfigurations.getBucketName()) ||
ObjectHelper.isEmpty(clientConfigurations.getObjectName())) &&
!(body instanceof File)) {
diff --git
a/components/camel-ibm/camel-ibm-cos/src/main/docs/ibm-cos-component.adoc
b/components/camel-ibm/camel-ibm-cos/src/main/docs/ibm-cos-component.adoc
index c9c0e64f8640..b2f24b340019 100644
--- a/components/camel-ibm/camel-ibm-cos/src/main/docs/ibm-cos-component.adoc
+++ b/components/camel-ibm/camel-ibm-cos/src/main/docs/ibm-cos-component.adoc
@@ -373,6 +373,60 @@
from("ibm-cos://mycamelbucket?cosClient=#cosClient&prefix=inbox/&deleteAfterRead
This route will only consume objects whose keys start with "inbox/".
+== Running Integration Tests
+
+Integration tests require valid IBM Cloud credentials. Follow these steps to
set up and run the tests.
+
+=== Creating Service Credentials
+
+1. Log in to the https://cloud.ibm.com[IBM Cloud Console]
+2. Navigate to your Cloud Object Storage instance (or create one if you don't
have one)
+3. Go to **Service credentials** in the left menu
+4. Click **New credential**
+5. Give it a name (e.g., `camel-cos-test`)
+6. **Important**: Set the role to **Manager** (required for bucket creation
operations)
+7. Click **Add**
+8. Expand the newly created credential to view the JSON
+
+=== Mapping Credentials to Test Properties
+
+From the service credential JSON, extract the following values:
+
+[cols="1,2,3"]
+|===
+|System Property |JSON Field |Example
+
+|`camel.ibm.cos.apiKey`
+|`apikey`
+|`Hh1u4wjecZ_jUhJScOt0sN...`
+
+|`camel.ibm.cos.serviceInstanceId`
+|`resource_instance_id`
+|`crn:v1:bluemix:public:cloud-object-storage:global:a/...`
+
+|`camel.ibm.cos.endpointUrl`
+|Not in credentials - choose based on region
+|`https://s3.us-south.cloud-object-storage.appdomain.cloud`
+|===
+
+NOTE: The `endpoints` field in the credentials JSON is a control API URL, not
the actual COS endpoint. You must choose a regional endpoint from the
https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-endpoints[IBM
COS Endpoints documentation].
+
+=== Running the Tests
+
+[source,bash]
+----
+mvn verify -pl components/camel-ibm/camel-ibm-cos \
+ -Dcamel.ibm.cos.apiKey=YOUR_API_KEY \
+ -Dcamel.ibm.cos.serviceInstanceId='YOUR_SERVICE_INSTANCE_ID' \
+
-Dcamel.ibm.cos.endpointUrl=https://s3.us-south.cloud-object-storage.appdomain.cloud
+----
+
+TIP: Use single quotes around the `serviceInstanceId` value to prevent shell
interpretation of special characters in the CRN.
+
+=== Troubleshooting
+
+* **403 Forbidden**: Ensure your service credential has the **Manager** role.
Writer role is not sufficient for bucket creation.
+
== Dependencies
Maven users will need to add the following dependency to their `pom.xml`.
diff --git
a/components/camel-ibm/camel-ibm-cos/src/main/java/org/apache/camel/component/ibm/cos/IBMCOSProducer.java
b/components/camel-ibm/camel-ibm-cos/src/main/java/org/apache/camel/component/ibm/cos/IBMCOSProducer.java
index 57d8e2460fdb..e8bed18528fa 100644
---
a/components/camel-ibm/camel-ibm-cos/src/main/java/org/apache/camel/component/ibm/cos/IBMCOSProducer.java
+++
b/components/camel-ibm/camel-ibm-cos/src/main/java/org/apache/camel/component/ibm/cos/IBMCOSProducer.java
@@ -35,6 +35,7 @@ import
com.ibm.cloud.objectstorage.services.s3.model.PutObjectResult;
import com.ibm.cloud.objectstorage.services.s3.model.S3Object;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
+import org.apache.camel.WrappedFile;
import org.apache.camel.support.DefaultProducer;
import org.apache.camel.util.ObjectHelper;
import org.slf4j.Logger;
@@ -122,12 +123,22 @@ public class IBMCOSProducer extends DefaultProducer {
metadata.setContentType(contentType);
}
+ // Check for WrappedFile to get file length (works for remote files
like SFTP)
+ Object body = exchange.getIn().getMandatoryBody();
+ long wrappedFileLength = -1;
+ if (body instanceof WrappedFile<?> wf) {
+ wrappedFileLength = wf.getFileLength();
+ }
+
InputStream inputStream =
exchange.getIn().getMandatoryBody(InputStream.class);
// Calculate content length if not provided to avoid SDK warnings
Long contentLength =
exchange.getIn().getHeader(IBMCOSConstants.CONTENT_LENGTH, Long.class);
if (contentLength != null) {
metadata.setContentLength(contentLength);
+ } else if (wrappedFileLength > 0) {
+ // Use file length from WrappedFile (avoids reading stream into
memory)
+ metadata.setContentLength(wrappedFileLength);
} else if (inputStream.markSupported()) {
// For ByteArrayInputStream and similar streams that support
mark/reset
inputStream.mark(Integer.MAX_VALUE);
diff --git
a/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioProducer.java
b/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioProducer.java
index a77928f9dab6..f5cfba2c68ba 100644
---
a/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioProducer.java
+++
b/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioProducer.java
@@ -142,18 +142,29 @@ public class MinioProducer extends DefaultProducer {
// the content-length may already be known
long contentLength =
Long.parseLong(objectMetadata.getOrDefault(Exchange.CONTENT_LENGTH, "-1"));
- Object object = exchange.getIn().getMandatoryBody();
+ // Use getBody() first to check for WrappedFile before any type
conversion
+ Object object = exchange.getIn().getBody();
InputStream inputStream = null;
File filePayload = null;
try {
// Need to check if the message body is WrappedFile
- if (object instanceof WrappedFile) {
- object = ((WrappedFile<?>) object).getFile();
+ if (object instanceof WrappedFile<?> wf) {
+ // Get file length from WrappedFile before unwrapping
(works for remote files like SFTP)
+ contentLength = wf.getFileLength();
+ object = wf.getFile();
+ }
+ if (object == null) {
+ throw new IllegalArgumentException("Message body is null");
}
if (object instanceof File) {
filePayload = (File) object;
inputStream = new FileInputStream(filePayload);
- contentLength = filePayload.length();
+ if (contentLength <= 0) {
+ contentLength = filePayload.length();
+ }
+ } else if (object instanceof InputStream) {
+ // Use the InputStream directly (e.g., from
WrappedFile.getFile())
+ inputStream = (InputStream) object;
} else {
inputStream =
exchange.getMessage().getMandatoryBody(InputStream.class);
if (contentLength <= 0) {