You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2021/12/03 09:22:23 UTC

[camel] branch main updated: CAMEL-17266: camel-google-storage - Download to file support.

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 da5cadb  CAMEL-17266: camel-google-storage - Download to file support.
da5cadb is described below

commit da5cadb5516bf11b96e240ec4935affe65737dea
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Dec 3 10:21:42 2021 +0100

    CAMEL-17266: camel-google-storage - Download to file support.
---
 .../GoogleCloudStorageComponentConfigurer.java     |  6 +++
 .../GoogleCloudStorageEndpointConfigurer.java      |  6 +++
 .../GoogleCloudStorageEndpointUriFactory.java      |  3 +-
 .../component/google/storage/google-storage.json   |  2 +
 .../storage/GoogleCloudStorageConfiguration.java   | 22 +++++++++
 .../google/storage/GoogleCloudStorageConsumer.java | 55 ++++++++++++++++++----
 ...calTest.java => ConsumerDownloadLocalTest.java} | 15 ++++--
 .../google/storage/unit/ConsumerLocalTest.java     |  1 -
 .../dsl/GoogleStorageComponentBuilderFactory.java  | 23 +++++++++
 .../GoogleCloudStorageEndpointBuilderFactory.java  | 22 +++++++++
 10 files changed, 142 insertions(+), 13 deletions(-)

diff --git a/components/camel-google/camel-google-storage/src/generated/java/org/apache/camel/component/google/storage/GoogleCloudStorageComponentConfigurer.java b/components/camel-google/camel-google-storage/src/generated/java/org/apache/camel/component/google/storage/GoogleCloudStorageComponentConfigurer.java
index 7eb4300..6ddc88f 100644
--- a/components/camel-google/camel-google-storage/src/generated/java/org/apache/camel/component/google/storage/GoogleCloudStorageComponentConfigurer.java
+++ b/components/camel-google/camel-google-storage/src/generated/java/org/apache/camel/component/google/storage/GoogleCloudStorageComponentConfigurer.java
@@ -39,6 +39,8 @@ public class GoogleCloudStorageComponentConfigurer extends PropertyConfigurerSup
         case "deleteAfterRead": getOrCreateConfiguration(target).setDeleteAfterRead(property(camelContext, boolean.class, value)); return true;
         case "destinationbucket":
         case "destinationBucket": getOrCreateConfiguration(target).setDestinationBucket(property(camelContext, java.lang.String.class, value)); return true;
+        case "downloadfilename":
+        case "downloadFileName": getOrCreateConfiguration(target).setDownloadFileName(property(camelContext, java.lang.String.class, value)); return true;
         case "includebody":
         case "includeBody": getOrCreateConfiguration(target).setIncludeBody(property(camelContext, boolean.class, value)); return true;
         case "includefolders":
@@ -81,6 +83,8 @@ public class GoogleCloudStorageComponentConfigurer extends PropertyConfigurerSup
         case "deleteAfterRead": return boolean.class;
         case "destinationbucket":
         case "destinationBucket": return java.lang.String.class;
+        case "downloadfilename":
+        case "downloadFileName": return java.lang.String.class;
         case "includebody":
         case "includeBody": return boolean.class;
         case "includefolders":
@@ -119,6 +123,8 @@ public class GoogleCloudStorageComponentConfigurer extends PropertyConfigurerSup
         case "deleteAfterRead": return getOrCreateConfiguration(target).isDeleteAfterRead();
         case "destinationbucket":
         case "destinationBucket": return getOrCreateConfiguration(target).getDestinationBucket();
+        case "downloadfilename":
+        case "downloadFileName": return getOrCreateConfiguration(target).getDownloadFileName();
         case "includebody":
         case "includeBody": return getOrCreateConfiguration(target).isIncludeBody();
         case "includefolders":
diff --git a/components/camel-google/camel-google-storage/src/generated/java/org/apache/camel/component/google/storage/GoogleCloudStorageEndpointConfigurer.java b/components/camel-google/camel-google-storage/src/generated/java/org/apache/camel/component/google/storage/GoogleCloudStorageEndpointConfigurer.java
index 7fe7f5d..00d8366 100644
--- a/components/camel-google/camel-google-storage/src/generated/java/org/apache/camel/component/google/storage/GoogleCloudStorageEndpointConfigurer.java
+++ b/components/camel-google/camel-google-storage/src/generated/java/org/apache/camel/component/google/storage/GoogleCloudStorageEndpointConfigurer.java
@@ -36,6 +36,8 @@ public class GoogleCloudStorageEndpointConfigurer extends PropertyConfigurerSupp
         case "deleteAfterRead": target.getConfiguration().setDeleteAfterRead(property(camelContext, boolean.class, value)); return true;
         case "destinationbucket":
         case "destinationBucket": target.getConfiguration().setDestinationBucket(property(camelContext, java.lang.String.class, value)); return true;
+        case "downloadfilename":
+        case "downloadFileName": target.getConfiguration().setDownloadFileName(property(camelContext, java.lang.String.class, value)); return true;
         case "exceptionhandler":
         case "exceptionHandler": target.setExceptionHandler(property(camelContext, org.apache.camel.spi.ExceptionHandler.class, value)); return true;
         case "exchangepattern":
@@ -108,6 +110,8 @@ public class GoogleCloudStorageEndpointConfigurer extends PropertyConfigurerSupp
         case "deleteAfterRead": return boolean.class;
         case "destinationbucket":
         case "destinationBucket": return java.lang.String.class;
+        case "downloadfilename":
+        case "downloadFileName": return java.lang.String.class;
         case "exceptionhandler":
         case "exceptionHandler": return org.apache.camel.spi.ExceptionHandler.class;
         case "exchangepattern":
@@ -176,6 +180,8 @@ public class GoogleCloudStorageEndpointConfigurer extends PropertyConfigurerSupp
         case "deleteAfterRead": return target.getConfiguration().isDeleteAfterRead();
         case "destinationbucket":
         case "destinationBucket": return target.getConfiguration().getDestinationBucket();
+        case "downloadfilename":
+        case "downloadFileName": return target.getConfiguration().getDownloadFileName();
         case "exceptionhandler":
         case "exceptionHandler": return target.getExceptionHandler();
         case "exchangepattern":
diff --git a/components/camel-google/camel-google-storage/src/generated/java/org/apache/camel/component/google/storage/GoogleCloudStorageEndpointUriFactory.java b/components/camel-google/camel-google-storage/src/generated/java/org/apache/camel/component/google/storage/GoogleCloudStorageEndpointUriFactory.java
index 31332e9..a7cebe6 100644
--- a/components/camel-google/camel-google-storage/src/generated/java/org/apache/camel/component/google/storage/GoogleCloudStorageEndpointUriFactory.java
+++ b/components/camel-google/camel-google-storage/src/generated/java/org/apache/camel/component/google/storage/GoogleCloudStorageEndpointUriFactory.java
@@ -20,7 +20,7 @@ public class GoogleCloudStorageEndpointUriFactory extends org.apache.camel.suppo
     private static final Set<String> PROPERTY_NAMES;
     private static final Set<String> SECRET_PROPERTY_NAMES;
     static {
-        Set<String> props = new HashSet<>(33);
+        Set<String> props = new HashSet<>(34);
         props.add("backoffMultiplier");
         props.add("bucketName");
         props.add("destinationBucket");
@@ -37,6 +37,7 @@ public class GoogleCloudStorageEndpointUriFactory extends org.apache.camel.suppo
         props.add("repeatCount");
         props.add("timeUnit");
         props.add("serviceAccountKey");
+        props.add("downloadFileName");
         props.add("autoCreateBucket");
         props.add("moveAfterRead");
         props.add("sendEmptyMessageWhenIdle");
diff --git a/components/camel-google/camel-google-storage/src/generated/resources/org/apache/camel/component/google/storage/google-storage.json b/components/camel-google/camel-google-storage/src/generated/resources/org/apache/camel/component/google/storage/google-storage.json
index 7ea0144..d5fedf1 100644
--- a/components/camel-google/camel-google-storage/src/generated/resources/org/apache/camel/component/google/storage/google-storage.json
+++ b/components/camel-google/camel-google-storage/src/generated/resources/org/apache/camel/component/google/storage/google-storage.json
@@ -31,6 +31,7 @@
     "bridgeErrorHandler": { "kind": "property", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a me [...]
     "deleteAfterRead": { "kind": "property", "displayName": "Delete After Read", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.google.storage.GoogleCloudStorageConfiguration", "configurationField": "configuration", "description": "Delete objects from the bucket after they have been retrieved. The delete  [...]
     "destinationBucket": { "kind": "property", "displayName": "Destination Bucket", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.google.storage.GoogleCloudStorageConfiguration", "configurationField": "configuration", "description": "Define the destination bucket where an object must be moved when moveAfterRead is set [...]
+    "downloadFileName": { "kind": "property", "displayName": "Download File Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.google.storage.GoogleCloudStorageConfiguration", "configurationField": "configuration", "description": "The folder or filename to use when downloading the blob. By default, this specifies th [...]
     "includeBody": { "kind": "property", "displayName": "Include Body", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.google.storage.GoogleCloudStorageConfiguration", "configurationField": "configuration", "description": "If it is true, the Object exchange will be consumed and put into the body. If false [...]
     "includeFolders": { "kind": "property", "displayName": "Include Folders", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.google.storage.GoogleCloudStorageConfiguration", "configurationField": "configuration", "description": "If it is true, the folders\/directories will be consumed. If it is false, the [...]
     "moveAfterRead": { "kind": "property", "displayName": "Move After Read", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.google.storage.GoogleCloudStorageConfiguration", "configurationField": "configuration", "description": "Move objects from the origin bucket to a different bucket after they have bee [...]
@@ -49,6 +50,7 @@
     "bridgeErrorHandler": { "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a m [...]
     "deleteAfterRead": { "kind": "parameter", "displayName": "Delete After Read", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.google.storage.GoogleCloudStorageConfiguration", "configurationField": "configuration", "description": "Delete objects from the bucket after they have been retrieved. The delete [...]
     "destinationBucket": { "kind": "parameter", "displayName": "Destination Bucket", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.google.storage.GoogleCloudStorageConfiguration", "configurationField": "configuration", "description": "Define the destination bucket where an object must be moved when moveAfterRead is se [...]
+    "downloadFileName": { "kind": "parameter", "displayName": "Download File Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.google.storage.GoogleCloudStorageConfiguration", "configurationField": "configuration", "description": "The folder or filename to use when downloading the blob. By default, this specifies t [...]
     "includeBody": { "kind": "parameter", "displayName": "Include Body", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.google.storage.GoogleCloudStorageConfiguration", "configurationField": "configuration", "description": "If it is true, the Object exchange will be consumed and put into the body. If fals [...]
     "includeFolders": { "kind": "parameter", "displayName": "Include Folders", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.google.storage.GoogleCloudStorageConfiguration", "configurationField": "configuration", "description": "If it is true, the folders\/directories will be consumed. If it is false, th [...]
     "moveAfterRead": { "kind": "parameter", "displayName": "Move After Read", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.google.storage.GoogleCloudStorageConfiguration", "configurationField": "configuration", "description": "Move objects from the origin bucket to a different bucket after they have be [...]
diff --git a/components/camel-google/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageConfiguration.java b/components/camel-google/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageConfiguration.java
index 651e004..cfbf2bf 100644
--- a/components/camel-google/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageConfiguration.java
+++ b/components/camel-google/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageConfiguration.java
@@ -69,6 +69,9 @@ public class GoogleCloudStorageConfiguration implements Cloneable {
     @UriParam(label = "consumer", defaultValue = "true")
     private boolean includeFolders = true;
 
+    @UriParam(label = "consumer")
+    private String downloadFileName;
+
     @UriParam
     @Metadata(autowired = true)
     private Storage storageClient;
@@ -205,6 +208,24 @@ public class GoogleCloudStorageConfiguration implements Cloneable {
         return includeFolders;
     }
 
+    public String getDownloadFileName() {
+        return downloadFileName;
+    }
+
+    /**
+     * The folder or filename to use when downloading the blob. By default, this specifies the folder name, and the name
+     * of the file is the blob name. For example, setting this to mydownload will be the same as setting
+     * mydownload/${file:name}.
+     *
+     * You can use dynamic expressions for fine-grained control. For example, you can specify
+     * ${date:now:yyyyMMdd}/${file:name} to store the blob in sub folders based on today's day.
+     *
+     * Only ${file:name} and ${file:name.noext} is supported as dynamic tokens for the blob name.
+     */
+    public void setDownloadFileName(String downloadFileName) {
+        this.downloadFileName = downloadFileName;
+    }
+
     public boolean isDeleteAfterRead() {
         return deleteAfterRead;
     }
@@ -238,4 +259,5 @@ public class GoogleCloudStorageConfiguration implements Cloneable {
             throw new RuntimeCamelException(e);
         }
     }
+
 }
diff --git a/components/camel-google/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageConsumer.java b/components/camel-google/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageConsumer.java
index 8891ecc..39a9b9f 100644
--- a/components/camel-google/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageConsumer.java
+++ b/components/camel-google/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageConsumer.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.google.storage;
 
+import java.io.File;
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
@@ -27,13 +28,16 @@ import com.google.cloud.storage.Bucket;
 import com.google.cloud.storage.CopyWriter;
 import com.google.cloud.storage.Storage;
 import com.google.cloud.storage.Storage.CopyRequest;
+import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
 import org.apache.camel.ExchangePropertyKey;
+import org.apache.camel.Expression;
 import org.apache.camel.ExtendedExchange;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.spi.Language;
 import org.apache.camel.spi.Synchronization;
 import org.apache.camel.support.EmptyAsyncCallback;
 import org.apache.camel.support.ScheduledBatchPollingConsumer;
@@ -47,8 +51,11 @@ public class GoogleCloudStorageConsumer extends ScheduledBatchPollingConsumer {
 
     private static final Logger LOG = LoggerFactory.getLogger(GoogleCloudStorageConsumer.class);
 
+    private final Language language;
+
     public GoogleCloudStorageConsumer(GoogleCloudStorageEndpoint endpoint, Processor processor) {
         super(endpoint, processor);
+        this.language = getEndpoint().getCamelContext().resolveLanguage("file");
     }
 
     @Override
@@ -270,16 +277,29 @@ public class GoogleCloudStorageConsumer extends ScheduledBatchPollingConsumer {
         Message message = exchange.getIn();
 
         if (getConfiguration().isIncludeBody()) {
-            try {
-                // if stream caching is enabled then use that so we can stream accordingly
-                // for example to overflow to disk for big streams
-                OutputStreamBuilder osb = OutputStreamBuilder.withExchange(exchange);
-                blob.downloadTo(osb);
-                message.setBody(osb.build());
-            } catch (Exception e) {
-                throw new RuntimeCamelException(e);
+            // download as file
+            if (getConfiguration().getDownloadFileName() != null) {
+                // create a dummy exchange as Exchange is needed for expression evaluation
+                String result = evaluateFileExpression(exchange, getConfiguration().getDownloadFileName(), blob.getName());
+                if (result != null) {
+                    File file = new File(result);
+                    blob.downloadTo(file.toPath());
+                    message.setBody(file);
+                }
+            } else {
+                // store blob data in the message body
+                try {
+                    // if stream caching is enabled then use that so we can stream accordingly
+                    // for example to overflow to disk for big streams
+                    OutputStreamBuilder osb = OutputStreamBuilder.withExchange(exchange);
+                    blob.downloadTo(osb);
+                    message.setBody(osb.build());
+                } catch (Exception e) {
+                    throw new RuntimeCamelException(e);
+                }
             }
         } else {
+            // store raw blob
             message.setBody(blob);
         }
 
@@ -309,4 +329,23 @@ public class GoogleCloudStorageConsumer extends ScheduledBatchPollingConsumer {
         return exchange;
     }
 
+    protected String evaluateFileExpression(Exchange exchange, String downloadFileName, String blogName) {
+        CamelContext camelContext = exchange.getContext();
+        // use blob as file name
+        exchange.getMessage().setHeader(Exchange.FILE_NAME, blogName);
+
+        String eval = downloadFileName;
+        if (!downloadFileName.contains("$")) {
+            eval = downloadFileName + "/${file:name}";
+        }
+        Expression exp = language.createExpression(eval);
+        exp.init(camelContext);
+
+        String result = exp.evaluate(exchange, String.class);
+        if (exchange.getException() != null) {
+            throw RuntimeCamelException.wrapRuntimeCamelException(exchange.getException());
+        }
+        return result;
+    }
+
 }
diff --git a/components/camel-google/camel-google-storage/src/test/java/org/apache/camel/component/google/storage/unit/ConsumerLocalTest.java b/components/camel-google/camel-google-storage/src/test/java/org/apache/camel/component/google/storage/unit/ConsumerDownloadLocalTest.java
similarity index 85%
copy from components/camel-google/camel-google-storage/src/test/java/org/apache/camel/component/google/storage/unit/ConsumerLocalTest.java
copy to components/camel-google/camel-google-storage/src/test/java/org/apache/camel/component/google/storage/unit/ConsumerDownloadLocalTest.java
index 419bbe1..d3343ea 100644
--- a/components/camel-google/camel-google-storage/src/test/java/org/apache/camel/component/google/storage/unit/ConsumerLocalTest.java
+++ b/components/camel-google/camel-google-storage/src/test/java/org/apache/camel/component/google/storage/unit/ConsumerDownloadLocalTest.java
@@ -16,14 +16,17 @@
  */
 package org.apache.camel.component.google.storage.unit;
 
+import java.io.File;
+
 import org.apache.camel.EndpointInject;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.google.storage.GoogleCloudStorageConstants;
 import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
-public class ConsumerLocalTest extends GoogleCloudStorageBaseTest {
+public class ConsumerDownloadLocalTest extends GoogleCloudStorageBaseTest {
 
     @EndpointInject
     private ProducerTemplate template;
@@ -52,7 +55,8 @@ public class ConsumerLocalTest extends GoogleCloudStorageBaseTest {
                      + "&destinationBucket=camelDestinationBucket"
                      + "&autoCreateBucket=true"
                      + "&deleteAfterRead=true"
-                     + "&includeBody=true")
+                     + "&includeBody=true"
+                     + "&downloadFileName=target")
                              .startupOrder(2)
                              //.log("consuming: ${header.CamelGoogleCloudStorageBucketName}/${header.CamelGoogleCloudStorageObjectName}, body=${body}")
                              .to("mock:consumedObjects");
@@ -79,9 +83,14 @@ public class ConsumerLocalTest extends GoogleCloudStorageBaseTest {
             });
         }
 
-        Thread.sleep(5000);
         assertMockEndpointsSatisfied();
 
+        context.stop();
+
+        // there should be downloaded files
+        Assertions.assertTrue(new File("target/file_0.txt").exists());
+        Assertions.assertTrue(new File("target/file_1.txt").exists());
+        Assertions.assertTrue(new File("target/file_2.txt").exists());
     }
 
 }
diff --git a/components/camel-google/camel-google-storage/src/test/java/org/apache/camel/component/google/storage/unit/ConsumerLocalTest.java b/components/camel-google/camel-google-storage/src/test/java/org/apache/camel/component/google/storage/unit/ConsumerLocalTest.java
index 419bbe1..43ee7e7 100644
--- a/components/camel-google/camel-google-storage/src/test/java/org/apache/camel/component/google/storage/unit/ConsumerLocalTest.java
+++ b/components/camel-google/camel-google-storage/src/test/java/org/apache/camel/component/google/storage/unit/ConsumerLocalTest.java
@@ -79,7 +79,6 @@ public class ConsumerLocalTest extends GoogleCloudStorageBaseTest {
             });
         }
 
-        Thread.sleep(5000);
         assertMockEndpointsSatisfied();
 
     }
diff --git a/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/GoogleStorageComponentBuilderFactory.java b/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/GoogleStorageComponentBuilderFactory.java
index 4ac1b7f..5f0f41f 100644
--- a/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/GoogleStorageComponentBuilderFactory.java
+++ b/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/GoogleStorageComponentBuilderFactory.java
@@ -209,6 +209,28 @@ public interface GoogleStorageComponentBuilderFactory {
             return this;
         }
         /**
+         * The folder or filename to use when downloading the blob. By default,
+         * this specifies the folder name, and the name of the file is the blob
+         * name. For example, setting this to mydownload will be the same as
+         * setting mydownload/${file:name}. You can use dynamic expressions for
+         * fine-grained control. For example, you can specify
+         * ${date:now:yyyyMMdd}/${file:name} to store the blob in sub folders
+         * based on today's day. Only ${file:name} and ${file:name.noext} is
+         * supported as dynamic tokens for the blob name.
+         * 
+         * The option is a: &lt;code&gt;java.lang.String&lt;/code&gt; type.
+         * 
+         * Group: consumer
+         * 
+         * @param downloadFileName the value to set
+         * @return the dsl builder
+         */
+        default GoogleStorageComponentBuilder downloadFileName(
+                java.lang.String downloadFileName) {
+            doSetProperty("downloadFileName", downloadFileName);
+            return this;
+        }
+        /**
          * If it is true, the Object exchange will be consumed and put into the
          * body. If false the Object stream will be put raw into the body and
          * the headers will be set with the object metadata.
@@ -372,6 +394,7 @@ public interface GoogleStorageComponentBuilderFactory {
             case "bridgeErrorHandler": ((GoogleCloudStorageComponent) component).setBridgeErrorHandler((boolean) value); return true;
             case "deleteAfterRead": getOrCreateConfiguration((GoogleCloudStorageComponent) component).setDeleteAfterRead((boolean) value); return true;
             case "destinationBucket": getOrCreateConfiguration((GoogleCloudStorageComponent) component).setDestinationBucket((java.lang.String) value); return true;
+            case "downloadFileName": getOrCreateConfiguration((GoogleCloudStorageComponent) component).setDownloadFileName((java.lang.String) value); return true;
             case "includeBody": getOrCreateConfiguration((GoogleCloudStorageComponent) component).setIncludeBody((boolean) value); return true;
             case "includeFolders": getOrCreateConfiguration((GoogleCloudStorageComponent) component).setIncludeFolders((boolean) value); return true;
             case "moveAfterRead": getOrCreateConfiguration((GoogleCloudStorageComponent) component).setMoveAfterRead((boolean) value); return true;
diff --git a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GoogleCloudStorageEndpointBuilderFactory.java b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GoogleCloudStorageEndpointBuilderFactory.java
index 3005376..829d81d 100644
--- a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GoogleCloudStorageEndpointBuilderFactory.java
+++ b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GoogleCloudStorageEndpointBuilderFactory.java
@@ -281,6 +281,28 @@ public interface GoogleCloudStorageEndpointBuilderFactory {
             return this;
         }
         /**
+         * The folder or filename to use when downloading the blob. By default,
+         * this specifies the folder name, and the name of the file is the blob
+         * name. For example, setting this to mydownload will be the same as
+         * setting mydownload/${file:name}. You can use dynamic expressions for
+         * fine-grained control. For example, you can specify
+         * ${date:now:yyyyMMdd}/${file:name} to store the blob in sub folders
+         * based on today's day. Only ${file:name} and ${file:name.noext} is
+         * supported as dynamic tokens for the blob name.
+         * 
+         * The option is a: &lt;code&gt;java.lang.String&lt;/code&gt; type.
+         * 
+         * Group: consumer
+         * 
+         * @param downloadFileName the value to set
+         * @return the dsl builder
+         */
+        default GoogleCloudStorageEndpointConsumerBuilder downloadFileName(
+                String downloadFileName) {
+            doSetProperty("downloadFileName", downloadFileName);
+            return this;
+        }
+        /**
          * If it is true, the Object exchange will be consumed and put into the
          * body. If false the Object stream will be put raw into the body and
          * the headers will be set with the object metadata.