This is an automated email from the ASF dual-hosted git repository. acosentino 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 c2f4266dbd5 CAMEL-21251 - Camel-AWS2-S3: Support Conditional Reads on producer operations (#15691) c2f4266dbd5 is described below commit c2f4266dbd55bdc39c5e07219c11fb632738a3af Author: Andrea Cosentino <anco...@gmail.com> AuthorDate: Wed Sep 25 11:50:29 2024 +0200 CAMEL-21251 - Camel-AWS2-S3: Support Conditional Reads on producer operations (#15691) * CAMEL-21251 - Camel-AWS2-S3: Support Conditional Reads on producer operations - GetObject Signed-off-by: Andrea Cosentino <anco...@gmail.com> * CAMEL-21251 - Camel-AWS2-S3: Support Conditional Reads on producer operations - CopyObject Signed-off-by: Andrea Cosentino <anco...@gmail.com> --------- Signed-off-by: Andrea Cosentino <anco...@gmail.com> --- .../apache/camel/catalog/components/aws2-s3.json | 6 ++- .../apache/camel/component/aws2/s3/aws2-s3.json | 6 ++- .../camel/component/aws2/s3/AWS2S3Constants.java | 12 +++++ .../camel/component/aws2/s3/AWS2S3Producer.java | 39 ++++++++++++++++ .../endpoint/dsl/AWS2S3EndpointBuilderFactory.java | 53 ++++++++++++++++++++++ 5 files changed, 114 insertions(+), 2 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/aws2-s3.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/aws2-s3.json index df28d3a336d..d94c1646ba1 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/aws2-s3.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/aws2-s3.json @@ -117,7 +117,11 @@ "CamelAwsS3Metadata": { "index": 28, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Map<String, String>", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "A map of metadata to be stored or stored with the object in S3. More details about metadata https:\/\/docs.aws.amazon.com\/AmazonS3\/latest\/userguide\/UsingMetadata.htmlhere.", "constantName": "org.apache.camel.component.aws2.s3.A [...] "CamelMessageTimestamp": { "index": 29, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The timestamp of the message", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#MESSAGE_TIMESTAMP" }, "CamelAwsS3Prefix": { "index": 30, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The prefix which is used in the com.amazonaws.services.s3.model.ListObjectsRequest to only list objects we are interested in", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#PREFIX" }, - "CamelAwsS3Delimiter": { "index": 31, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The delimiter which is used in the com.amazonaws.services.s3.model.ListObjectsRequest to only list objects we are interested in", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#DELIMITER" } + "CamelAwsS3Delimiter": { "index": 31, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The delimiter which is used in the com.amazonaws.services.s3.model.ListObjectsRequest to only list objects we are interested in", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#DELIMITER" }, + "CamelAwsS3IfMatchCondition": { "index": 32, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Return\/copy the object only if its entity tag (ETag) is the same as the one specified in this header.", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#IF_MATCH_CONDITION" }, + "CamelAwsS3IfModifiedSinceCondition": { "index": 33, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Return\/copy the object only if it has been modified since the specified time; otherwise, return a 304 Not Modified error.", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#IF_MODIFIED_SINCE_CONDITION" }, + "CamelAwsS3IfNoneMatchCondition": { "index": 34, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Return\/copy the object only if its entity tag (ETag) is different from the one specified in this header.", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#IF_NONE_MATCH_CONDITION" }, + "CamelAwsS3IfUnmodifiedSinceCondition": { "index": 35, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Return\/copy the object only if it has not been modified since the specified time.", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#IF_UNMODIFIED_SINCE_CONDITION" } }, "properties": { "bucketNameOrArn": { "index": 0, "kind": "path", "displayName": "Bucket Name Or Arn", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Bucket name or ARN" }, diff --git a/components/camel-aws/camel-aws2-s3/src/generated/resources/META-INF/org/apache/camel/component/aws2/s3/aws2-s3.json b/components/camel-aws/camel-aws2-s3/src/generated/resources/META-INF/org/apache/camel/component/aws2/s3/aws2-s3.json index df28d3a336d..d94c1646ba1 100644 --- a/components/camel-aws/camel-aws2-s3/src/generated/resources/META-INF/org/apache/camel/component/aws2/s3/aws2-s3.json +++ b/components/camel-aws/camel-aws2-s3/src/generated/resources/META-INF/org/apache/camel/component/aws2/s3/aws2-s3.json @@ -117,7 +117,11 @@ "CamelAwsS3Metadata": { "index": 28, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Map<String, String>", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "A map of metadata to be stored or stored with the object in S3. More details about metadata https:\/\/docs.aws.amazon.com\/AmazonS3\/latest\/userguide\/UsingMetadata.htmlhere.", "constantName": "org.apache.camel.component.aws2.s3.A [...] "CamelMessageTimestamp": { "index": 29, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The timestamp of the message", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#MESSAGE_TIMESTAMP" }, "CamelAwsS3Prefix": { "index": 30, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The prefix which is used in the com.amazonaws.services.s3.model.ListObjectsRequest to only list objects we are interested in", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#PREFIX" }, - "CamelAwsS3Delimiter": { "index": 31, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The delimiter which is used in the com.amazonaws.services.s3.model.ListObjectsRequest to only list objects we are interested in", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#DELIMITER" } + "CamelAwsS3Delimiter": { "index": 31, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The delimiter which is used in the com.amazonaws.services.s3.model.ListObjectsRequest to only list objects we are interested in", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#DELIMITER" }, + "CamelAwsS3IfMatchCondition": { "index": 32, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Return\/copy the object only if its entity tag (ETag) is the same as the one specified in this header.", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#IF_MATCH_CONDITION" }, + "CamelAwsS3IfModifiedSinceCondition": { "index": 33, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Return\/copy the object only if it has been modified since the specified time; otherwise, return a 304 Not Modified error.", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#IF_MODIFIED_SINCE_CONDITION" }, + "CamelAwsS3IfNoneMatchCondition": { "index": 34, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Return\/copy the object only if its entity tag (ETag) is different from the one specified in this header.", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#IF_NONE_MATCH_CONDITION" }, + "CamelAwsS3IfUnmodifiedSinceCondition": { "index": 35, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Return\/copy the object only if it has not been modified since the specified time.", "constantName": "org.apache.camel.component.aws2.s3.AWS2S3Constants#IF_UNMODIFIED_SINCE_CONDITION" } }, "properties": { "bucketNameOrArn": { "index": 0, "kind": "path", "displayName": "Bucket Name Or Arn", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Bucket name or ARN" }, diff --git a/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Constants.java b/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Constants.java index 5248cff744d..c7a916e5bee 100644 --- a/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Constants.java +++ b/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Constants.java @@ -142,4 +142,16 @@ public interface AWS2S3Constants { @Metadata(description = "The delimiter which is used in the com.amazonaws.services.s3.model.ListObjectsRequest to only list objects we are interested in", javaType = "String") String DELIMITER = "CamelAwsS3Delimiter"; + @Metadata(description = "Return/copy the object only if its entity tag (ETag) is the same as the one specified in this header.", + javaType = "String") + String IF_MATCH_CONDITION = "CamelAwsS3IfMatchCondition"; + @Metadata(description = "Return/copy the object only if it has been modified since the specified time; otherwise, return a 304 Not Modified error.", + javaType = "String") + String IF_MODIFIED_SINCE_CONDITION = "CamelAwsS3IfModifiedSinceCondition"; + @Metadata(description = "Return/copy the object only if its entity tag (ETag) is different from the one specified in this header.", + javaType = "String") + String IF_NONE_MATCH_CONDITION = "CamelAwsS3IfNoneMatchCondition"; + @Metadata(description = "Return/copy the object only if it has not been modified since the specified time.", + javaType = "String") + String IF_UNMODIFIED_SINCE_CONDITION = "CamelAwsS3IfUnmodifiedSinceCondition"; } 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 3d1de35a387..368875fb0f3 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 @@ -23,6 +23,7 @@ import java.io.FileInputStream; import java.io.InputStream; import java.net.URI; import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -466,6 +467,25 @@ public class AWS2S3Producer extends DefaultProducer { copyObjectRequest.sseCustomerAlgorithm(getConfiguration().getCustomerAlgorithm()); } } + final String ifMatchCondition = exchange.getMessage().getHeader(AWS2S3Constants.IF_MATCH_CONDITION, String.class); + final Instant ifModifiedSinceCondition + = exchange.getMessage().getHeader(AWS2S3Constants.IF_MODIFIED_SINCE_CONDITION, Instant.class); + final String ifNoneMatchCondition + = exchange.getMessage().getHeader(AWS2S3Constants.IF_NONE_MATCH_CONDITION, String.class); + final Instant ifUnmodifiedSince + = exchange.getMessage().getHeader(AWS2S3Constants.IF_UNMODIFIED_SINCE_CONDITION, Instant.class); + if (ObjectHelper.isNotEmpty(ifMatchCondition)) { + copyObjectRequest.copySourceIfMatch(ifMatchCondition); + } + if (ObjectHelper.isNotEmpty(ifModifiedSinceCondition)) { + copyObjectRequest.copySourceIfModifiedSince(ifModifiedSinceCondition); + } + if (ObjectHelper.isNotEmpty(ifNoneMatchCondition)) { + copyObjectRequest.copySourceIfNoneMatch(ifNoneMatchCondition); + } + if (ObjectHelper.isNotEmpty(ifUnmodifiedSince)) { + copyObjectRequest.copySourceIfUnmodifiedSince(ifUnmodifiedSince); + } CopyObjectResponse copyObjectResult = s3Client.copyObject(copyObjectRequest.build()); @@ -541,7 +561,26 @@ public class AWS2S3Producer extends DefaultProducer { } else { final String bucketName = AWS2S3Utils.determineBucketName(exchange, getConfiguration()); final String keyName = AWS2S3Utils.determineKey(exchange, getConfiguration()); + final String ifMatchCondition = exchange.getMessage().getHeader(AWS2S3Constants.IF_MATCH_CONDITION, String.class); + final Instant ifModifiedSinceCondition + = exchange.getMessage().getHeader(AWS2S3Constants.IF_MODIFIED_SINCE_CONDITION, Instant.class); + final String ifNoneMatchCondition + = exchange.getMessage().getHeader(AWS2S3Constants.IF_NONE_MATCH_CONDITION, String.class); + final Instant ifUnmodifiedSince + = exchange.getMessage().getHeader(AWS2S3Constants.IF_UNMODIFIED_SINCE_CONDITION, Instant.class); GetObjectRequest.Builder req = GetObjectRequest.builder().bucket(bucketName).key(keyName); + if (ObjectHelper.isNotEmpty(ifMatchCondition)) { + req.ifMatch(ifMatchCondition); + } + if (ObjectHelper.isNotEmpty(ifModifiedSinceCondition)) { + req.ifModifiedSince(ifModifiedSinceCondition); + } + if (ObjectHelper.isNotEmpty(ifNoneMatchCondition)) { + req.ifNoneMatch(ifNoneMatchCondition); + } + if (ObjectHelper.isNotEmpty(ifUnmodifiedSince)) { + req.ifUnmodifiedSince(ifUnmodifiedSince); + } ResponseInputStream<GetObjectResponse> res = s3Client.getObject(req.build(), ResponseTransformer.toInputStream()); Message message = getMessageForResponse(exchange); diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/AWS2S3EndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/AWS2S3EndpointBuilderFactory.java index 5cb462a783d..4d21a4f9e58 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/AWS2S3EndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/AWS2S3EndpointBuilderFactory.java @@ -4017,6 +4017,59 @@ public interface AWS2S3EndpointBuilderFactory { public String awsS3Delimiter() { return "CamelAwsS3Delimiter"; } + /** + * Return/copy the object only if its entity tag (ETag) is the same as + * the one specified in this header. + * + * The option is a: {@code String} type. + * + * Group: common + * + * @return the name of the header {@code AwsS3IfMatchCondition}. + */ + public String awsS3IfMatchCondition() { + return "CamelAwsS3IfMatchCondition"; + } + /** + * Return/copy the object only if it has been modified since the + * specified time; otherwise, return a 304 Not Modified error. + * + * The option is a: {@code String} type. + * + * Group: common + * + * @return the name of the header {@code AwsS3IfModifiedSinceCondition}. + */ + public String awsS3IfModifiedSinceCondition() { + return "CamelAwsS3IfModifiedSinceCondition"; + } + /** + * Return/copy the object only if its entity tag (ETag) is different + * from the one specified in this header. + * + * The option is a: {@code String} type. + * + * Group: common + * + * @return the name of the header {@code AwsS3IfNoneMatchCondition}. + */ + public String awsS3IfNoneMatchCondition() { + return "CamelAwsS3IfNoneMatchCondition"; + } + /** + * Return/copy the object only if it has not been modified since the + * specified time. + * + * The option is a: {@code String} type. + * + * Group: common + * + * @return the name of the header {@code + * AwsS3IfUnmodifiedSinceCondition}. + */ + public String awsS3IfUnmodifiedSinceCondition() { + return "CamelAwsS3IfUnmodifiedSinceCondition"; + } } static AWS2S3EndpointBuilder endpointBuilder(String componentName, String path) { class AWS2S3EndpointBuilderImpl extends AbstractEndpointBuilder implements AWS2S3EndpointBuilder, AdvancedAWS2S3EndpointBuilder {