diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml index d2419f9f74aed..52b9cdbee2bd2 100644 --- a/bom/camel-bom/pom.xml +++ b/bom/camel-bom/pom.xml @@ -66,6 +66,21 @@ camel-ai-tool 4.23.0-SNAPSHOT + + org.apache.camel + camel-alibaba-common + 4.23.0-SNAPSHOT + + + org.apache.camel + camel-alibaba-mns + 4.23.0-SNAPSHOT + + + org.apache.camel + camel-alibaba-oss + 4.23.0-SNAPSHOT + org.apache.camel camel-amqp diff --git a/catalog/camel-allcomponents/pom.xml b/catalog/camel-allcomponents/pom.xml index fab4a83b9ab1f..4ae87f8003f74 100644 --- a/catalog/camel-allcomponents/pom.xml +++ b/catalog/camel-allcomponents/pom.xml @@ -72,6 +72,21 @@ camel-ai-tool ${project.version} + + org.apache.camel + camel-alibaba-common + ${project.version} + + + org.apache.camel + camel-alibaba-mns + ${project.version} + + + org.apache.camel + camel-alibaba-oss + ${project.version} + org.apache.camel camel-amqp diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties index e8a80790f9c4c..f0cd17702e552 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties @@ -2,6 +2,8 @@ a2a activemq activemq6 ai-tool +alibaba-mns +alibaba-oss amqp arangodb as2 diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/alibaba-mns.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/alibaba-mns.json new file mode 100644 index 0000000000000..76e09dff19bb1 --- /dev/null +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/alibaba-mns.json @@ -0,0 +1,79 @@ +{ + "component": { + "kind": "component", + "name": "alibaba-mns", + "title": "Alibaba Message Service (MNS)", + "description": "Send and receive messages to\/from Alibaba Cloud Message Service (MNS).", + "deprecated": false, + "firstVersion": "4.23.0", + "label": "cloud,messaging", + "javaType": "org.apache.camel.component.alibaba.mns.MNSComponent", + "supportLevel": "Preview", + "groupId": "org.apache.camel", + "artifactId": "camel-alibaba-mns", + "version": "4.23.0-SNAPSHOT", + "scheme": "alibaba-mns", + "extendsScheme": "", + "syntax": "alibaba-mns:queueName", + "async": false, + "api": false, + "consumerOnly": false, + "producerOnly": false, + "lenientProperties": false, + "browsable": false, + "remote": true + }, + "componentProperties": { + "bridgeErrorHandler": { "index": 0, "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 (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "lazyStartProducer": { "index": 1, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "autowiredEnabled": { "index": 2, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." }, + "healthCheckConsumerEnabled": { "index": 3, "kind": "property", "displayName": "Health Check Consumer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all consumer based health checks from this component" }, + "healthCheckProducerEnabled": { "index": 4, "kind": "property", "displayName": "Health Check Producer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all producer based health checks from this component. Notice: Camel has by default disabled all producer based health-checks. You can turn on producer checks globally by setting camel.health.producersEnabled=true." } + }, + "headers": { + "CamelAlibabaMnsMessageId": { "index": 0, "kind": "header", "displayName": "", "group": "common", "label": "common", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The MNS message id", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#MESSAGE_ID" }, + "CamelAlibabaMnsReceiptHandle": { "index": 1, "kind": "header", "displayName": "", "group": "common", "label": "common", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The MNS receipt handle", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#RECEIPT_HANDLE" }, + "CamelAlibabaMnsMessageBodyMd5": { "index": 2, "kind": "header", "displayName": "", "group": "common", "label": "common", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The MD5 digest of the message body", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#MESSAGE_BODY_MD5" }, + "CamelAlibabaMnsDelaySeconds": { "index": 3, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Delay in seconds before the message becomes visible", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#DELAY_SECONDS" }, + "CamelAlibabaMnsPriority": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Message priority", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#PRIORITY" }, + "CamelAlibabaMnsMessageTag": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Message tag for topic publish operations", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#MESSAGE_TAG" }, + "CamelAlibabaMnsDequeueCount": { "index": 6, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Number of times the message has been dequeued", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#DEQUEUE_COUNT" }, + "CamelAlibabaMnsEnqueueTime": { "index": 7, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "java.util.Date", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Time when the message was enqueued", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#ENQUEUE_TIME" }, + "CamelAlibabaMnsNextVisibleTime": { "index": 8, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "java.util.Date", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Next time the message becomes visible", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#NEXT_VISIBLE_TIME" }, + "CamelAlibabaMnsFirstDequeueTime": { "index": 9, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "java.util.Date", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Time when the message was first dequeued", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#FIRST_DEQUEUE_TIME" } + }, + "properties": { + "queueName": { "index": 0, "kind": "path", "displayName": "Queue Name", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Queue name, or topic name when using the topic URI syntax" }, + "accountEndpoint": { "index": 1, "kind": "parameter", "displayName": "Account Endpoint", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "MNS account endpoint, for example https:\/\/123456.mns.cn-hangzhou.aliyuncs.com" }, + "operation": { "index": 2, "kind": "parameter", "displayName": "Operation", "group": "common", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "sendMessage", "receiveMessage", "deleteMessage", "publishMessage" ], "deprecated": false, "autowired": false, "secret": false, "description": "Operation to perform" }, + "region": { "index": 3, "kind": "parameter", "displayName": "Region", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Alibaba Cloud region" }, + "topicName": { "index": 4, "kind": "parameter", "displayName": "Topic Name", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Topic name for publishMessage operations" }, + "waitSeconds": { "index": 5, "kind": "parameter", "displayName": "Wait Seconds", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 0, "description": "Long polling wait time in seconds when receiving messages" }, + "deleteAfterRead": { "index": 6, "kind": "parameter", "displayName": "Delete After Read", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Delete message from the queue after it has been processed" }, + "maxMessagesPerPoll": { "index": 7, "kind": "parameter", "displayName": "Max Messages Per Poll", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1, "description": "Maximum number of messages to receive per poll" }, + "sendEmptyMessageWhenIdle": { "index": 8, "kind": "parameter", "displayName": "Send Empty Message When Idle", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If the polling consumer did not poll any files, you can enable this option to send an empty message (no body) instead." }, + "bridgeErrorHandler": { "index": 9, "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "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 (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "exceptionHandler": { "index": 10, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "exchangePattern": { "index": 11, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "enum", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, + "pollStrategy": { "index": 12, "kind": "parameter", "displayName": "Poll Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "A pluggable org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your custom implementation to control error handling usually occurred during the poll operation before an Exchange have been created and being routed in Camel." }, + "lazyStartProducer": { "index": 13, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "mnsClient": { "index": 14, "kind": "parameter", "displayName": "MNS Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "com.aliyun.mns.client.MNSClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "description": "Autowire an existing MNSClient instance" }, + "backoffErrorThreshold": { "index": 15, "kind": "parameter", "displayName": "Backoff Error Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in." }, + "backoffIdleThreshold": { "index": 16, "kind": "parameter", "displayName": "Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent idle polls that should happen before the backoffMultipler should kick-in." }, + "backoffMultiplier": { "index": 17, "kind": "parameter", "displayName": "Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "To let the scheduled polling consumer backoff if there has been a number of subsequent idles\/errors in a row. The multiplier is then the number of polls that will be skipped before the next actual attempt is happening again. When this option is in use then backoffIdleThreshold and\/or backoffErrorThreshold must also be configured." }, + "delay": { "index": 18, "kind": "parameter", "displayName": "Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 500, "description": "Milliseconds before the next poll." }, + "greedy": { "index": 19, "kind": "parameter", "displayName": "Greedy", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If greedy is enabled, then the ScheduledPollConsumer will run immediately again, if the previous run polled 1 or more messages." }, + "initialDelay": { "index": 20, "kind": "parameter", "displayName": "Initial Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1000, "description": "Milliseconds before the first poll starts." }, + "repeatCount": { "index": 21, "kind": "parameter", "displayName": "Repeat Count", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 0, "description": "Specifies a maximum limit of number of fires. So if you set it to 1, the scheduler will only fire once. If you set it to 5, it will only fire five times. A value of zero or negative means fire forever." }, + "runLoggingLevel": { "index": 22, "kind": "parameter", "displayName": "Run Logging Level", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "enum", "javaType": "org.apache.camel.LoggingLevel", "enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "TRACE", "description": "The consumer logs a start\/complete log line when it polls. This option allows you to configure the logging level for that." }, + "scheduledExecutorService": { "index": 23, "kind": "parameter", "displayName": "Scheduled Executor Service", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.util.concurrent.ScheduledExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "Allows for configuring a custom\/shared thread pool to use for the consumer. By default each consumer has its own single threaded thread pool." }, + "scheduler": { "index": 24, "kind": "parameter", "displayName": "Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.lang.Object", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "description": "To use a cron scheduler from either camel-spring or camel-quartz component. Use value spring or quartz for built in scheduler" }, + "schedulerProperties": { "index": 25, "kind": "parameter", "displayName": "Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.util.Map", "prefix": "scheduler.", "multiValue": true, "deprecated": false, "autowired": false, "secret": false, "description": "To configure additional properties when using a custom scheduler or any of the Quartz, Spring based scheduler. This is a multi-value option with prefix: scheduler." }, + "startScheduler": { "index": 26, "kind": "parameter", "displayName": "Start Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether the scheduler should be auto started." }, + "timeUnit": { "index": 27, "kind": "parameter", "displayName": "Time Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [ "NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS", "DAYS" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and delay options." }, + "useFixedDelay": { "index": 28, "kind": "parameter", "displayName": "Use Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in JDK for details." }, + "accessKey": { "index": 29, "kind": "parameter", "displayName": "Access Key", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "description": "Access key for the cloud user" }, + "secretKey": { "index": 30, "kind": "parameter", "displayName": "Secret Key", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "description": "Secret key for the cloud user" }, + "serviceKeys": { "index": 31, "kind": "parameter", "displayName": "Service Keys", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.component.alibaba.common.models.ServiceKeys", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "description": "Configuration object for cloud service authentication" } + } +} diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/alibaba-oss.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/alibaba-oss.json new file mode 100644 index 0000000000000..2a48300a4ba0d --- /dev/null +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/alibaba-oss.json @@ -0,0 +1,79 @@ +{ + "component": { + "kind": "component", + "name": "alibaba-oss", + "title": "Alibaba Object Storage Service (OSS)", + "description": "Alibaba Cloud Object Storage Service (OSS) component", + "deprecated": false, + "firstVersion": "4.23.0", + "label": "cloud", + "javaType": "org.apache.camel.component.alibaba.oss.OSSComponent", + "supportLevel": "Preview", + "groupId": "org.apache.camel", + "artifactId": "camel-alibaba-oss", + "version": "4.23.0-SNAPSHOT", + "scheme": "alibaba-oss", + "extendsScheme": "", + "syntax": "alibaba-oss:bucketName", + "async": false, + "api": false, + "consumerOnly": false, + "producerOnly": false, + "lenientProperties": false, + "browsable": false, + "remote": true + }, + "componentProperties": { + "bridgeErrorHandler": { "index": 0, "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 (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "lazyStartProducer": { "index": 1, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "autowiredEnabled": { "index": 2, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." }, + "healthCheckConsumerEnabled": { "index": 3, "kind": "property", "displayName": "Health Check Consumer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all consumer based health checks from this component" }, + "healthCheckProducerEnabled": { "index": 4, "kind": "property", "displayName": "Health Check Producer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all producer based health checks from this component. Notice: Camel has by default disabled all producer based health-checks. You can turn on producer checks globally by setting camel.health.producersEnabled=true." } + }, + "headers": { + "CamelAlibabaOssBucketName": { "index": 0, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Name of the bucket where object is contained", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#BUCKET_NAME" }, + "CamelAlibabaOssObjectKey": { "index": 1, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The key that the object is stored under", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#OBJECT_KEY" }, + "CamelAlibabaOssLastModified": { "index": 2, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The date and time that the object was last modified", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#LAST_MODIFIED" }, + "CamelAlibabaOssETag": { "index": 3, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The 128-bit MD5 digest of the object content", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#ETAG" }, + "CamelAlibabaOssContentMD5": { "index": 4, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The 128-bit Base64-encoded digest of the object", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#CONTENT_MD5" }, + "CamelAlibabaOssObjectType": { "index": 5, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Shows whether the object is a file or a folder", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#OBJECT_TYPE" }, + "CamelAlibabaOssContentLength": { "index": 6, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The size of the object body in bytes", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#CONTENT_LENGTH" }, + "CamelAlibabaOssContentType": { "index": 7, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The type of content stored in the object", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#CONTENT_TYPE" }, + "CamelFileName": { "index": 8, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Name of the object with which the operation is to be performed", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#FILE_NAME" } + }, + "properties": { + "bucketName": { "index": 0, "kind": "path", "displayName": "Bucket Name", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of bucket to perform operation on" }, + "endpoint": { "index": 1, "kind": "parameter", "displayName": "Endpoint url", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "OSS endpoint URL. Carries higher precedence than region based client initialization" }, + "objectName": { "index": 2, "kind": "parameter", "displayName": "Object Name", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of object to perform operation with" }, + "region": { "index": 3, "kind": "parameter", "displayName": "Service region", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "OSS service region" }, + "deleteAfterRead": { "index": 4, "kind": "parameter", "displayName": "Delete after read", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Determines if objects should be deleted after they have been retrieved" }, + "maxMessagesPerPoll": { "index": 5, "kind": "parameter", "displayName": "Maximum messages per poll", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "description": "The maximum number of messages to poll at each polling" }, + "prefix": { "index": 6, "kind": "parameter", "displayName": "Prefix", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The object name prefix used for filtering objects to be listed" }, + "sendEmptyMessageWhenIdle": { "index": 7, "kind": "parameter", "displayName": "Send Empty Message When Idle", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If the polling consumer did not poll any files, you can enable this option to send an empty message (no body) instead." }, + "bridgeErrorHandler": { "index": 8, "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "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 (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "exceptionHandler": { "index": 9, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "exchangePattern": { "index": 10, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "enum", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, + "pollStrategy": { "index": 11, "kind": "parameter", "displayName": "Poll Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "A pluggable org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your custom implementation to control error handling usually occurred during the poll operation before an Exchange have been created and being routed in Camel." }, + "maxKeys": { "index": 12, "kind": "parameter", "displayName": "Max Keys", "group": "producer", "label": "consumer,producer", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "description": "The maximum number of keys returned when listing objects" }, + "operation": { "index": 13, "kind": "parameter", "displayName": "Operation", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "listBuckets", "listObjects", "putObject", "getObject", "deleteObject", "copyObject", "headObject" ], "deprecated": false, "autowired": false, "secret": false, "description": "Operation to be performed" }, + "lazyStartProducer": { "index": 14, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "ossClient": { "index": 15, "kind": "parameter", "displayName": "OSS Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "com.aliyun.sdk.service.oss2.OSSClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "description": "An autowired OSS client" }, + "backoffErrorThreshold": { "index": 16, "kind": "parameter", "displayName": "Backoff Error Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in." }, + "backoffIdleThreshold": { "index": 17, "kind": "parameter", "displayName": "Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent idle polls that should happen before the backoffMultipler should kick-in." }, + "backoffMultiplier": { "index": 18, "kind": "parameter", "displayName": "Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "To let the scheduled polling consumer backoff if there has been a number of subsequent idles\/errors in a row. The multiplier is then the number of polls that will be skipped before the next actual attempt is happening again. When this option is in use then backoffIdleThreshold and\/or backoffErrorThreshold must also be configured." }, + "delay": { "index": 19, "kind": "parameter", "displayName": "Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 500, "description": "Milliseconds before the next poll." }, + "greedy": { "index": 20, "kind": "parameter", "displayName": "Greedy", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If greedy is enabled, then the ScheduledPollConsumer will run immediately again, if the previous run polled 1 or more messages." }, + "initialDelay": { "index": 21, "kind": "parameter", "displayName": "Initial Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1000, "description": "Milliseconds before the first poll starts." }, + "repeatCount": { "index": 22, "kind": "parameter", "displayName": "Repeat Count", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 0, "description": "Specifies a maximum limit of number of fires. So if you set it to 1, the scheduler will only fire once. If you set it to 5, it will only fire five times. A value of zero or negative means fire forever." }, + "runLoggingLevel": { "index": 23, "kind": "parameter", "displayName": "Run Logging Level", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "enum", "javaType": "org.apache.camel.LoggingLevel", "enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "TRACE", "description": "The consumer logs a start\/complete log line when it polls. This option allows you to configure the logging level for that." }, + "scheduledExecutorService": { "index": 24, "kind": "parameter", "displayName": "Scheduled Executor Service", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.util.concurrent.ScheduledExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "Allows for configuring a custom\/shared thread pool to use for the consumer. By default each consumer has its own single threaded thread pool." }, + "scheduler": { "index": 25, "kind": "parameter", "displayName": "Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.lang.Object", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "description": "To use a cron scheduler from either camel-spring or camel-quartz component. Use value spring or quartz for built in scheduler" }, + "schedulerProperties": { "index": 26, "kind": "parameter", "displayName": "Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.util.Map", "prefix": "scheduler.", "multiValue": true, "deprecated": false, "autowired": false, "secret": false, "description": "To configure additional properties when using a custom scheduler or any of the Quartz, Spring based scheduler. This is a multi-value option with prefix: scheduler." }, + "startScheduler": { "index": 27, "kind": "parameter", "displayName": "Start Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether the scheduler should be auto started." }, + "timeUnit": { "index": 28, "kind": "parameter", "displayName": "Time Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [ "NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS", "DAYS" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and delay options." }, + "useFixedDelay": { "index": 29, "kind": "parameter", "displayName": "Use Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in JDK for details." }, + "accessKey": { "index": 30, "kind": "parameter", "displayName": "API access key (AK)", "group": "security", "label": "security", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": true, "security": "secret", "description": "Access key for the cloud user" }, + "secretKey": { "index": 31, "kind": "parameter", "displayName": "API secret key (SK)", "group": "security", "label": "security", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": true, "security": "secret", "description": "Secret key for the cloud user" }, + "serviceKeys": { "index": 32, "kind": "parameter", "displayName": "Service Configuration", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.component.alibaba.common.models.ServiceKeys", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "description": "Configuration object for cloud service authentication" } + } +} diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs.properties index 03163011cb014..f1afa700fe0ea 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs.properties +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs.properties @@ -7,6 +7,8 @@ activemq6-component aggregate-eip ai-patterns ai-tool-component +alibaba-mns-component +alibaba-oss-component amqp-component arangodb-component as2-component diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/alibaba-mns-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/alibaba-mns-component.adoc new file mode 100644 index 0000000000000..86820b7e56ffd --- /dev/null +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/alibaba-mns-component.adoc @@ -0,0 +1,128 @@ += Alibaba Message Service (MNS) Component +:doctitle: Alibaba Message Service (MNS) +:shortname: alibaba-mns +:artifactid: camel-alibaba-mns +:description: Send and receive messages to/from Alibaba Cloud Message Service (MNS). +:since: 4.23 +:supportlevel: Preview +:tabs-sync-option: +:component-header: Both producer and consumer are supported +//Manually maintained attributes +:group: Alibaba Cloud + +*Since Camel {since}* + +*{component-header}* + +The Alibaba Cloud Message Service (MNS) component allows you to integrate with +https://www.alibabacloud.com/product/mns[Alibaba Cloud MNS] for queue and topic messaging. + +NOTE: Alibaba Cloud recommends RocketMQ for new messaging workloads. MNS remains supported, +but evaluate https://www.alibabacloud.com/product/rocketmq[RocketMQ] or the Camel RocketMQ +component for greenfield projects. + +Maven users will need to add the following dependency to their `pom.xml` +for this component: + +[source,xml] +---- + + org.apache.camel + camel-alibaba-mns + x.x.x + + +---- + +== URI format + +Queue endpoints: + +[source] +---- +alibaba-mns:queueName[?options] +---- + +Topic endpoints: + +[source] +---- +alibaba-mns:topic:topicName[?options] +---- + +// component options: START +include::partial$component-configure-options.adoc[] +include::partial$component-endpoint-options.adoc[] +include::partial$component-endpoint-headers.adoc[] +// component options: END + +== Usage + +=== Operations + +The component supports the following operations: + +* `sendMessage` - send a message to a queue (producer) +* `receiveMessage` - receive messages from a queue (consumer) +* `deleteMessage` - delete a message from a queue using its receipt handle (producer) +* `publishMessage` - publish a message to a topic (producer) + +=== Queue producer example + +[source,java] +---- +from("direct:start") + .setBody(constant("Hello MNS")) + .to("alibaba-mns:myQueue?operation=sendMessage®ion=cn-hangzhou&accountEndpoint=https://123456.mns.cn-hangzhou.aliyuncs.com&accessKey=RAW(accessKey)&secretKey=RAW(secretKey)"); +---- + +=== Topic producer example + +[source,java] +---- +from("direct:start") + .setBody(constant("Hello Topic")) + .to("alibaba-mns:topic:myTopic?operation=publishMessage®ion=cn-hangzhou&accountEndpoint=https://123456.mns.cn-hangzhou.aliyuncs.com&accessKey=RAW(accessKey)&secretKey=RAW(secretKey)"); +---- + +=== Queue consumer example + +[source,java] +---- +from("alibaba-mns:myQueue?region=cn-hangzhou&accountEndpoint=https://123456.mns.cn-hangzhou.aliyuncs.com&accessKey=RAW(accessKey)&secretKey=RAW(secretKey)&deleteAfterRead=true") + .to("bean:processMessage"); +---- + +=== Exchange properties evaluated by the producer + +[width="100%",cols="10%,10%,80%",options="header",] +|======================================================================= +|Property |Type |Description + +|`CamelAlibabaMnsOperation` |`String` |Operation to perform + +|`CamelAlibabaMnsQueueName` |`String` |Queue name override + +|`CamelAlibabaMnsTopicName` |`String` |Topic name for publish operations + +|`CamelAlibabaMnsReceiptHandle` |`String` |Receipt handle for delete operations + +|======================================================================= + +=== Exchange properties set by the producer + +[width="100%",cols="10%,10%,80%",options="header",] +|======================================================================= +|Property |Type |Description + +|`CamelAlibabaMnsMessageId` |`String` |Message id returned by MNS + +|`CamelAlibabaMnsRequestId` |`String` |Request id returned by MNS + +|`CamelAlibabaMnsMessageBodyMd5` |`String` |MD5 digest of the message body + +|======================================================================= + +== Examples + +For more examples, see the unit tests in the `camel-alibaba-mns` module. diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/alibaba-oss-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/alibaba-oss-component.adoc new file mode 100644 index 0000000000000..5c48d5b101acb --- /dev/null +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/alibaba-oss-component.adoc @@ -0,0 +1,105 @@ += Alibaba Object Storage Service (OSS) Component +:doctitle: Alibaba Object Storage Service (OSS) +:shortname: alibaba-oss +:artifactid: camel-alibaba-oss +:description: Alibaba Cloud Object Storage Service (OSS) component +:since: 4.23 +:supportlevel: Preview +:tabs-sync-option: +:component-header: Both producer and consumer are supported +//Manually maintained attributes +:group: Alibaba Cloud + +*Since Camel {since}* + +*{component-header}* + +The Alibaba Cloud Object Storage Service (OSS) component allows you to integrate with https://www.alibabacloud.com/product/object-storage-service[Alibaba Cloud OSS]. + +Maven users will need to add the following dependency to their `pom.xml` for this component: + +[source,xml] +---- + + org.apache.camel + camel-alibaba-oss + x.x.x + + +---- + +== URI Format + +---- +alibaba-oss:bucketName[?options] +---- + +The `operation` query parameter selects the OSS operation to perform (for example `putObject`, `getObject`, `listObjects`). + +// component options: START +include::partial$component-configure-options.adoc[] +include::partial$component-endpoint-options.adoc[] +include::partial$component-endpoint-headers.adoc[] +// component options: END + +== Usage + +=== Message headers evaluated by the OSS producer + +[width="100%",cols="10%,10%,80%",options="header",] +|======================================================================= +|Header |Type |Description + +|`CamelAlibabaOssOperation` |`String` | Name of operation to invoke + +|`CamelAlibabaOssBucketName` |`String` | Bucket name to invoke operation on (overrides the URI path bucket name) + +|`CamelAlibabaOssObjectName` |`String` | Name of the object to be used in operation + +|`CamelAlibabaOssSourceBucketName` |`String` | Source bucket name for copy operations + +|`CamelAlibabaOssSourceObjectName` |`String` | Source object name for copy operations + +|`CamelAlibabaOssPrefix` |`String` | Prefix filter when listing objects + +|`CamelAlibabaOssMaxKeys` |`Integer` | Maximum number of keys returned when listing objects + +|======================================================================= + +If any of the above headers are set, they will override their corresponding query parameter or URI path value. + +=== List of Supported OSS Operations + +- listBuckets +- listObjects - `bucketName` parameter is *required* +- putObject - `bucketName` and `objectName` parameters are *required* (unless uploading a `File`) +- getObject - `bucketName` and `objectName` parameters are *required* +- deleteObject - `bucketName` and `objectName` parameters are *required* +- copyObject - source and destination bucket/object names are *required* +- headObject - `bucketName` and `objectName` parameters are *required* + +=== Consumer + +The consumer polls objects from a bucket using `listObjectsV2`, downloads each object body, and optionally deletes objects after they have been processed when `deleteAfterRead` is enabled. + +== Examples + +=== Put an object + +[source,java] +---- +from("direct:start") + .setBody(constant("Hello OSS")) + .setHeader("CamelAlibabaOssObjectName", constant("hello.txt")) + .to("alibaba-oss:my-bucket?operation=putObject®ion=cn-hangzhou&accessKey=xxx&secretKey=yyy"); +---- + +Producer operations return structured response metadata in the message body (`Map` or `List` depending on the operation). + +=== Consume objects from a bucket + +[source,java] +---- +from("alibaba-oss:my-bucket?region=cn-hangzhou&accessKey=xxx&secretKey=yyy&deleteAfterRead=true") + .to("log:output"); +---- diff --git a/components/camel-alibaba/camel-alibaba-common/pom.xml b/components/camel-alibaba/camel-alibaba-common/pom.xml new file mode 100644 index 0000000000000..62023cae0f174 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-common/pom.xml @@ -0,0 +1,46 @@ + + + + + 4.0.0 + + + org.apache.camel + camel-alibaba-parent + 4.23.0-SNAPSHOT + + + + 4.23.0 + + + camel-alibaba-common + jar + Camel :: Alibaba Cloud :: Common + Common utilities for Camel Alibaba Cloud components + + + + org.apache.camel + camel-support + + + + diff --git a/components/camel-alibaba/camel-alibaba-common/src/generated/resources/META-INF/services/org/apache/camel/other.properties b/components/camel-alibaba/camel-alibaba-common/src/generated/resources/META-INF/services/org/apache/camel/other.properties new file mode 100644 index 0000000000000..aec20ac9d5f94 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-common/src/generated/resources/META-INF/services/org/apache/camel/other.properties @@ -0,0 +1,7 @@ +# Generated by camel build tools - do NOT edit this file! +name=alibaba-common +groupId=org.apache.camel +artifactId=camel-alibaba-common +version=4.23.0-SNAPSHOT +projectName=Camel :: Alibaba Cloud :: Common +projectDescription=Common utilities for Camel Alibaba Cloud components diff --git a/components/camel-alibaba/camel-alibaba-common/src/generated/resources/alibaba-common.json b/components/camel-alibaba/camel-alibaba-common/src/generated/resources/alibaba-common.json new file mode 100644 index 0000000000000..b0e29d769095f --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-common/src/generated/resources/alibaba-common.json @@ -0,0 +1,14 @@ +{ + "other": { + "kind": "other", + "name": "alibaba-common", + "title": "Alibaba Common", + "description": "Common utilities for Camel Alibaba Cloud components", + "deprecated": false, + "firstVersion": "4.23.0", + "supportLevel": "Preview", + "groupId": "org.apache.camel", + "artifactId": "camel-alibaba-common", + "version": "4.23.0-SNAPSHOT" + } +} diff --git a/components/camel-alibaba/camel-alibaba-common/src/main/java/org/apache/camel/component/alibaba/common/models/ServiceKeys.java b/components/camel-alibaba/camel-alibaba-common/src/main/java/org/apache/camel/component/alibaba/common/models/ServiceKeys.java new file mode 100644 index 0000000000000..033e89b4f4141 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-common/src/main/java/org/apache/camel/component/alibaba/common/models/ServiceKeys.java @@ -0,0 +1,47 @@ +/* + * 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.common.models; + +public class ServiceKeys { + + private String accessKey; + private String secretKey; + + public ServiceKeys() { + } + + public ServiceKeys(String accessKey, String secretKey) { + this.accessKey = accessKey; + this.secretKey = secretKey; + } + + public String getAccessKey() { + return accessKey; + } + + public void setAccessKey(String accessKey) { + this.accessKey = accessKey; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/pom.xml b/components/camel-alibaba/camel-alibaba-mns/pom.xml new file mode 100644 index 0000000000000..c5c1ab046901f --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/pom.xml @@ -0,0 +1,77 @@ + + + + + 4.0.0 + + + org.apache.camel + camel-alibaba-parent + 4.23.0-SNAPSHOT + + + + 4.23.0 + + + camel-alibaba-mns + jar + Camel :: Alibaba Cloud :: Message Service (MNS) + Camel Alibaba Cloud Message Service (MNS) component + + + + org.apache.camel + camel-support + + + + org.apache.camel + camel-alibaba-common + ${project.version} + + + + com.aliyun.mns + aliyun-sdk-mns + ${aliyun-sdk-mns-version} + + + + org.apache.camel + camel-test-junit6 + test + + + + org.assertj + assertj-core + test + + + + org.mockito + mockito-core + ${mockito-version} + test + + + + diff --git a/components/camel-alibaba/camel-alibaba-mns/src/generated/java/org/apache/camel/component/alibaba/mns/MNSComponentConfigurer.java b/components/camel-alibaba/camel-alibaba-mns/src/generated/java/org/apache/camel/component/alibaba/mns/MNSComponentConfigurer.java new file mode 100644 index 0000000000000..05eb92427cc00 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/generated/java/org/apache/camel/component/alibaba/mns/MNSComponentConfigurer.java @@ -0,0 +1,75 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.alibaba.mns; + +import javax.annotation.processing.Generated; +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.ExtendedPropertyConfigurerGetter; +import org.apache.camel.spi.PropertyConfigurerGetter; +import org.apache.camel.spi.ConfigurerStrategy; +import org.apache.camel.spi.GeneratedPropertyConfigurer; +import org.apache.camel.util.CaseInsensitiveMap; +import org.apache.camel.support.component.PropertyConfigurerSupport; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.EndpointSchemaGeneratorMojo") +@SuppressWarnings("unchecked") +public class MNSComponentConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter { + + @Override + public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) { + MNSComponent target = (MNSComponent) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "autowiredenabled": + case "autowiredEnabled": target.setAutowiredEnabled(property(camelContext, boolean.class, value)); return true; + case "bridgeerrorhandler": + case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true; + case "healthcheckconsumerenabled": + case "healthCheckConsumerEnabled": target.setHealthCheckConsumerEnabled(property(camelContext, boolean.class, value)); return true; + case "healthcheckproducerenabled": + case "healthCheckProducerEnabled": target.setHealthCheckProducerEnabled(property(camelContext, boolean.class, value)); return true; + case "lazystartproducer": + case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; + default: return false; + } + } + + @Override + public Class getOptionType(String name, boolean ignoreCase) { + switch (ignoreCase ? name.toLowerCase() : name) { + case "autowiredenabled": + case "autowiredEnabled": return boolean.class; + case "bridgeerrorhandler": + case "bridgeErrorHandler": return boolean.class; + case "healthcheckconsumerenabled": + case "healthCheckConsumerEnabled": return boolean.class; + case "healthcheckproducerenabled": + case "healthCheckProducerEnabled": return boolean.class; + case "lazystartproducer": + case "lazyStartProducer": return boolean.class; + default: return null; + } + } + + @Override + public Object getOptionValue(Object obj, String name, boolean ignoreCase) { + MNSComponent target = (MNSComponent) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "autowiredenabled": + case "autowiredEnabled": return target.isAutowiredEnabled(); + case "bridgeerrorhandler": + case "bridgeErrorHandler": return target.isBridgeErrorHandler(); + case "healthcheckconsumerenabled": + case "healthCheckConsumerEnabled": return target.isHealthCheckConsumerEnabled(); + case "healthcheckproducerenabled": + case "healthCheckProducerEnabled": return target.isHealthCheckProducerEnabled(); + case "lazystartproducer": + case "lazyStartProducer": return target.isLazyStartProducer(); + default: return null; + } + } +} + diff --git a/components/camel-alibaba/camel-alibaba-mns/src/generated/java/org/apache/camel/component/alibaba/mns/MNSEndpointConfigurer.java b/components/camel-alibaba/camel-alibaba-mns/src/generated/java/org/apache/camel/component/alibaba/mns/MNSEndpointConfigurer.java new file mode 100644 index 0000000000000..6866443c6bdd0 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/generated/java/org/apache/camel/component/alibaba/mns/MNSEndpointConfigurer.java @@ -0,0 +1,230 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.alibaba.mns; + +import javax.annotation.processing.Generated; +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.ExtendedPropertyConfigurerGetter; +import org.apache.camel.spi.PropertyConfigurerGetter; +import org.apache.camel.spi.ConfigurerStrategy; +import org.apache.camel.spi.GeneratedPropertyConfigurer; +import org.apache.camel.util.CaseInsensitiveMap; +import org.apache.camel.support.component.PropertyConfigurerSupport; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.EndpointSchemaGeneratorMojo") +@SuppressWarnings("unchecked") +public class MNSEndpointConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter { + + @Override + public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) { + MNSEndpoint target = (MNSEndpoint) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "accesskey": + case "accessKey": target.setAccessKey(property(camelContext, java.lang.String.class, value)); return true; + case "accountendpoint": + case "accountEndpoint": target.setAccountEndpoint(property(camelContext, java.lang.String.class, value)); return true; + case "backofferrorthreshold": + case "backoffErrorThreshold": target.setBackoffErrorThreshold(property(camelContext, int.class, value)); return true; + case "backoffidlethreshold": + case "backoffIdleThreshold": target.setBackoffIdleThreshold(property(camelContext, int.class, value)); return true; + case "backoffmultiplier": + case "backoffMultiplier": target.setBackoffMultiplier(property(camelContext, int.class, value)); return true; + case "bridgeerrorhandler": + case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true; + case "delay": target.setDelay(property(camelContext, long.class, value)); return true; + case "deleteafterread": + case "deleteAfterRead": target.setDeleteAfterRead(property(camelContext, boolean.class, value)); return true; + case "exceptionhandler": + case "exceptionHandler": target.setExceptionHandler(property(camelContext, org.apache.camel.spi.ExceptionHandler.class, value)); return true; + case "exchangepattern": + case "exchangePattern": target.setExchangePattern(property(camelContext, org.apache.camel.ExchangePattern.class, value)); return true; + case "greedy": target.setGreedy(property(camelContext, boolean.class, value)); return true; + case "initialdelay": + case "initialDelay": target.setInitialDelay(property(camelContext, long.class, value)); return true; + case "lazystartproducer": + case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; + case "maxmessagesperpoll": + case "maxMessagesPerPoll": target.setMaxMessagesPerPoll(property(camelContext, int.class, value)); return true; + case "mnsclient": + case "mnsClient": target.setMnsClient(property(camelContext, com.aliyun.mns.client.MNSClient.class, value)); return true; + case "operation": target.setOperation(property(camelContext, java.lang.String.class, value)); return true; + case "pollstrategy": + case "pollStrategy": target.setPollStrategy(property(camelContext, org.apache.camel.spi.PollingConsumerPollStrategy.class, value)); return true; + case "region": target.setRegion(property(camelContext, java.lang.String.class, value)); return true; + case "repeatcount": + case "repeatCount": target.setRepeatCount(property(camelContext, long.class, value)); return true; + case "runlogginglevel": + case "runLoggingLevel": target.setRunLoggingLevel(property(camelContext, org.apache.camel.LoggingLevel.class, value)); return true; + case "scheduledexecutorservice": + case "scheduledExecutorService": target.setScheduledExecutorService(property(camelContext, java.util.concurrent.ScheduledExecutorService.class, value)); return true; + case "scheduler": target.setScheduler(property(camelContext, java.lang.Object.class, value)); return true; + case "schedulerproperties": + case "schedulerProperties": target.setSchedulerProperties(property(camelContext, java.util.Map.class, value)); return true; + case "secretkey": + case "secretKey": target.setSecretKey(property(camelContext, java.lang.String.class, value)); return true; + case "sendemptymessagewhenidle": + case "sendEmptyMessageWhenIdle": target.setSendEmptyMessageWhenIdle(property(camelContext, boolean.class, value)); return true; + case "servicekeys": + case "serviceKeys": target.setServiceKeys(property(camelContext, org.apache.camel.component.alibaba.common.models.ServiceKeys.class, value)); return true; + case "startscheduler": + case "startScheduler": target.setStartScheduler(property(camelContext, boolean.class, value)); return true; + case "timeunit": + case "timeUnit": target.setTimeUnit(property(camelContext, java.util.concurrent.TimeUnit.class, value)); return true; + case "topicname": + case "topicName": target.setTopicName(property(camelContext, java.lang.String.class, value)); return true; + case "usefixeddelay": + case "useFixedDelay": target.setUseFixedDelay(property(camelContext, boolean.class, value)); return true; + case "waitseconds": + case "waitSeconds": target.setWaitSeconds(property(camelContext, int.class, value)); return true; + default: return false; + } + } + + @Override + public String[] getAutowiredNames() { + return new String[]{"mnsClient"}; + } + + @Override + public Class getOptionType(String name, boolean ignoreCase) { + switch (ignoreCase ? name.toLowerCase() : name) { + case "accesskey": + case "accessKey": return java.lang.String.class; + case "accountendpoint": + case "accountEndpoint": return java.lang.String.class; + case "backofferrorthreshold": + case "backoffErrorThreshold": return int.class; + case "backoffidlethreshold": + case "backoffIdleThreshold": return int.class; + case "backoffmultiplier": + case "backoffMultiplier": return int.class; + case "bridgeerrorhandler": + case "bridgeErrorHandler": return boolean.class; + case "delay": return long.class; + case "deleteafterread": + case "deleteAfterRead": return boolean.class; + case "exceptionhandler": + case "exceptionHandler": return org.apache.camel.spi.ExceptionHandler.class; + case "exchangepattern": + case "exchangePattern": return org.apache.camel.ExchangePattern.class; + case "greedy": return boolean.class; + case "initialdelay": + case "initialDelay": return long.class; + case "lazystartproducer": + case "lazyStartProducer": return boolean.class; + case "maxmessagesperpoll": + case "maxMessagesPerPoll": return int.class; + case "mnsclient": + case "mnsClient": return com.aliyun.mns.client.MNSClient.class; + case "operation": return java.lang.String.class; + case "pollstrategy": + case "pollStrategy": return org.apache.camel.spi.PollingConsumerPollStrategy.class; + case "region": return java.lang.String.class; + case "repeatcount": + case "repeatCount": return long.class; + case "runlogginglevel": + case "runLoggingLevel": return org.apache.camel.LoggingLevel.class; + case "scheduledexecutorservice": + case "scheduledExecutorService": return java.util.concurrent.ScheduledExecutorService.class; + case "scheduler": return java.lang.Object.class; + case "schedulerproperties": + case "schedulerProperties": return java.util.Map.class; + case "secretkey": + case "secretKey": return java.lang.String.class; + case "sendemptymessagewhenidle": + case "sendEmptyMessageWhenIdle": return boolean.class; + case "servicekeys": + case "serviceKeys": return org.apache.camel.component.alibaba.common.models.ServiceKeys.class; + case "startscheduler": + case "startScheduler": return boolean.class; + case "timeunit": + case "timeUnit": return java.util.concurrent.TimeUnit.class; + case "topicname": + case "topicName": return java.lang.String.class; + case "usefixeddelay": + case "useFixedDelay": return boolean.class; + case "waitseconds": + case "waitSeconds": return int.class; + default: return null; + } + } + + @Override + public Object getOptionValue(Object obj, String name, boolean ignoreCase) { + MNSEndpoint target = (MNSEndpoint) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "accesskey": + case "accessKey": return target.getAccessKey(); + case "accountendpoint": + case "accountEndpoint": return target.getAccountEndpoint(); + case "backofferrorthreshold": + case "backoffErrorThreshold": return target.getBackoffErrorThreshold(); + case "backoffidlethreshold": + case "backoffIdleThreshold": return target.getBackoffIdleThreshold(); + case "backoffmultiplier": + case "backoffMultiplier": return target.getBackoffMultiplier(); + case "bridgeerrorhandler": + case "bridgeErrorHandler": return target.isBridgeErrorHandler(); + case "delay": return target.getDelay(); + case "deleteafterread": + case "deleteAfterRead": return target.isDeleteAfterRead(); + case "exceptionhandler": + case "exceptionHandler": return target.getExceptionHandler(); + case "exchangepattern": + case "exchangePattern": return target.getExchangePattern(); + case "greedy": return target.isGreedy(); + case "initialdelay": + case "initialDelay": return target.getInitialDelay(); + case "lazystartproducer": + case "lazyStartProducer": return target.isLazyStartProducer(); + case "maxmessagesperpoll": + case "maxMessagesPerPoll": return target.getMaxMessagesPerPoll(); + case "mnsclient": + case "mnsClient": return target.getMnsClient(); + case "operation": return target.getOperation(); + case "pollstrategy": + case "pollStrategy": return target.getPollStrategy(); + case "region": return target.getRegion(); + case "repeatcount": + case "repeatCount": return target.getRepeatCount(); + case "runlogginglevel": + case "runLoggingLevel": return target.getRunLoggingLevel(); + case "scheduledexecutorservice": + case "scheduledExecutorService": return target.getScheduledExecutorService(); + case "scheduler": return target.getScheduler(); + case "schedulerproperties": + case "schedulerProperties": return target.getSchedulerProperties(); + case "secretkey": + case "secretKey": return target.getSecretKey(); + case "sendemptymessagewhenidle": + case "sendEmptyMessageWhenIdle": return target.isSendEmptyMessageWhenIdle(); + case "servicekeys": + case "serviceKeys": return target.getServiceKeys(); + case "startscheduler": + case "startScheduler": return target.isStartScheduler(); + case "timeunit": + case "timeUnit": return target.getTimeUnit(); + case "topicname": + case "topicName": return target.getTopicName(); + case "usefixeddelay": + case "useFixedDelay": return target.isUseFixedDelay(); + case "waitseconds": + case "waitSeconds": return target.getWaitSeconds(); + default: return null; + } + } + + @Override + public Object getCollectionValueType(Object target, String name, boolean ignoreCase) { + switch (ignoreCase ? name.toLowerCase() : name) { + case "schedulerproperties": + case "schedulerProperties": return java.lang.Object.class; + default: return null; + } + } +} + diff --git a/components/camel-alibaba/camel-alibaba-mns/src/generated/java/org/apache/camel/component/alibaba/mns/MNSEndpointUriFactory.java b/components/camel-alibaba/camel-alibaba-mns/src/generated/java/org/apache/camel/component/alibaba/mns/MNSEndpointUriFactory.java new file mode 100644 index 0000000000000..be7fced35e33b --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/generated/java/org/apache/camel/component/alibaba/mns/MNSEndpointUriFactory.java @@ -0,0 +1,114 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.alibaba.mns; + +import javax.annotation.processing.Generated; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.camel.spi.EndpointUriFactory; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.GenerateEndpointUriFactoryMojo") +public class MNSEndpointUriFactory extends org.apache.camel.support.component.EndpointUriFactorySupport implements EndpointUriFactory { + + private static final String BASE = ":queueName"; + + private static final Set PROPERTY_NAMES; + private static final Set SECRET_PROPERTY_NAMES; + private static final Set ENDPOINT_IDENTITY_PROPERTY_NAMES; + private static final Map MULTI_VALUE_PREFIXES; + static { + Set props = new HashSet<>(32); + props.add("accessKey"); + props.add("accountEndpoint"); + props.add("backoffErrorThreshold"); + props.add("backoffIdleThreshold"); + props.add("backoffMultiplier"); + props.add("bridgeErrorHandler"); + props.add("delay"); + props.add("deleteAfterRead"); + props.add("exceptionHandler"); + props.add("exchangePattern"); + props.add("greedy"); + props.add("initialDelay"); + props.add("lazyStartProducer"); + props.add("maxMessagesPerPoll"); + props.add("mnsClient"); + props.add("operation"); + props.add("pollStrategy"); + props.add("queueName"); + props.add("region"); + props.add("repeatCount"); + props.add("runLoggingLevel"); + props.add("scheduledExecutorService"); + props.add("scheduler"); + props.add("schedulerProperties"); + props.add("secretKey"); + props.add("sendEmptyMessageWhenIdle"); + props.add("serviceKeys"); + props.add("startScheduler"); + props.add("timeUnit"); + props.add("topicName"); + props.add("useFixedDelay"); + props.add("waitSeconds"); + PROPERTY_NAMES = Collections.unmodifiableSet(props); + Set secretProps = new HashSet<>(3); + secretProps.add("accessKey"); + secretProps.add("secretKey"); + secretProps.add("serviceKeys"); + SECRET_PROPERTY_NAMES = Collections.unmodifiableSet(secretProps); + ENDPOINT_IDENTITY_PROPERTY_NAMES = Collections.emptySet(); + Map prefixes = new HashMap<>(1); + prefixes.put("schedulerProperties", "scheduler."); + MULTI_VALUE_PREFIXES = Collections.unmodifiableMap(prefixes); + } + + @Override + public boolean isEnabled(String scheme) { + return "alibaba-mns".equals(scheme); + } + + @Override + public String buildUri(String scheme, Map properties, boolean encode) throws URISyntaxException { + String syntax = scheme + BASE; + String uri = syntax; + + Map copy = new HashMap<>(properties); + + uri = buildPathParameter(syntax, uri, "queueName", null, true, copy); + uri = buildQueryParameters(uri, copy, encode); + return uri; + } + + @Override + public Set propertyNames() { + return PROPERTY_NAMES; + } + + @Override + public Set secretPropertyNames() { + return SECRET_PROPERTY_NAMES; + } + + @Override + public Set endpointIdentityPropertyNames() { + return ENDPOINT_IDENTITY_PROPERTY_NAMES; + } + + @Override + public Map multiValuePrefixes() { + return MULTI_VALUE_PREFIXES; + } + + @Override + public boolean isLenientProperties() { + return false; + } +} + diff --git a/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/org/apache/camel/component/alibaba/mns/alibaba-mns.json b/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/org/apache/camel/component/alibaba/mns/alibaba-mns.json new file mode 100644 index 0000000000000..76e09dff19bb1 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/org/apache/camel/component/alibaba/mns/alibaba-mns.json @@ -0,0 +1,79 @@ +{ + "component": { + "kind": "component", + "name": "alibaba-mns", + "title": "Alibaba Message Service (MNS)", + "description": "Send and receive messages to\/from Alibaba Cloud Message Service (MNS).", + "deprecated": false, + "firstVersion": "4.23.0", + "label": "cloud,messaging", + "javaType": "org.apache.camel.component.alibaba.mns.MNSComponent", + "supportLevel": "Preview", + "groupId": "org.apache.camel", + "artifactId": "camel-alibaba-mns", + "version": "4.23.0-SNAPSHOT", + "scheme": "alibaba-mns", + "extendsScheme": "", + "syntax": "alibaba-mns:queueName", + "async": false, + "api": false, + "consumerOnly": false, + "producerOnly": false, + "lenientProperties": false, + "browsable": false, + "remote": true + }, + "componentProperties": { + "bridgeErrorHandler": { "index": 0, "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 (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "lazyStartProducer": { "index": 1, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "autowiredEnabled": { "index": 2, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." }, + "healthCheckConsumerEnabled": { "index": 3, "kind": "property", "displayName": "Health Check Consumer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all consumer based health checks from this component" }, + "healthCheckProducerEnabled": { "index": 4, "kind": "property", "displayName": "Health Check Producer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all producer based health checks from this component. Notice: Camel has by default disabled all producer based health-checks. You can turn on producer checks globally by setting camel.health.producersEnabled=true." } + }, + "headers": { + "CamelAlibabaMnsMessageId": { "index": 0, "kind": "header", "displayName": "", "group": "common", "label": "common", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The MNS message id", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#MESSAGE_ID" }, + "CamelAlibabaMnsReceiptHandle": { "index": 1, "kind": "header", "displayName": "", "group": "common", "label": "common", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The MNS receipt handle", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#RECEIPT_HANDLE" }, + "CamelAlibabaMnsMessageBodyMd5": { "index": 2, "kind": "header", "displayName": "", "group": "common", "label": "common", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The MD5 digest of the message body", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#MESSAGE_BODY_MD5" }, + "CamelAlibabaMnsDelaySeconds": { "index": 3, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Delay in seconds before the message becomes visible", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#DELAY_SECONDS" }, + "CamelAlibabaMnsPriority": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Message priority", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#PRIORITY" }, + "CamelAlibabaMnsMessageTag": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Message tag for topic publish operations", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#MESSAGE_TAG" }, + "CamelAlibabaMnsDequeueCount": { "index": 6, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Number of times the message has been dequeued", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#DEQUEUE_COUNT" }, + "CamelAlibabaMnsEnqueueTime": { "index": 7, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "java.util.Date", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Time when the message was enqueued", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#ENQUEUE_TIME" }, + "CamelAlibabaMnsNextVisibleTime": { "index": 8, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "java.util.Date", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Next time the message becomes visible", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#NEXT_VISIBLE_TIME" }, + "CamelAlibabaMnsFirstDequeueTime": { "index": 9, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "java.util.Date", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Time when the message was first dequeued", "constantName": "org.apache.camel.component.alibaba.mns.constants.MNSHeaders#FIRST_DEQUEUE_TIME" } + }, + "properties": { + "queueName": { "index": 0, "kind": "path", "displayName": "Queue Name", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Queue name, or topic name when using the topic URI syntax" }, + "accountEndpoint": { "index": 1, "kind": "parameter", "displayName": "Account Endpoint", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "MNS account endpoint, for example https:\/\/123456.mns.cn-hangzhou.aliyuncs.com" }, + "operation": { "index": 2, "kind": "parameter", "displayName": "Operation", "group": "common", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "sendMessage", "receiveMessage", "deleteMessage", "publishMessage" ], "deprecated": false, "autowired": false, "secret": false, "description": "Operation to perform" }, + "region": { "index": 3, "kind": "parameter", "displayName": "Region", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Alibaba Cloud region" }, + "topicName": { "index": 4, "kind": "parameter", "displayName": "Topic Name", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Topic name for publishMessage operations" }, + "waitSeconds": { "index": 5, "kind": "parameter", "displayName": "Wait Seconds", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 0, "description": "Long polling wait time in seconds when receiving messages" }, + "deleteAfterRead": { "index": 6, "kind": "parameter", "displayName": "Delete After Read", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Delete message from the queue after it has been processed" }, + "maxMessagesPerPoll": { "index": 7, "kind": "parameter", "displayName": "Max Messages Per Poll", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1, "description": "Maximum number of messages to receive per poll" }, + "sendEmptyMessageWhenIdle": { "index": 8, "kind": "parameter", "displayName": "Send Empty Message When Idle", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If the polling consumer did not poll any files, you can enable this option to send an empty message (no body) instead." }, + "bridgeErrorHandler": { "index": 9, "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "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 (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "exceptionHandler": { "index": 10, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "exchangePattern": { "index": 11, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "enum", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, + "pollStrategy": { "index": 12, "kind": "parameter", "displayName": "Poll Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "A pluggable org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your custom implementation to control error handling usually occurred during the poll operation before an Exchange have been created and being routed in Camel." }, + "lazyStartProducer": { "index": 13, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "mnsClient": { "index": 14, "kind": "parameter", "displayName": "MNS Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "com.aliyun.mns.client.MNSClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "description": "Autowire an existing MNSClient instance" }, + "backoffErrorThreshold": { "index": 15, "kind": "parameter", "displayName": "Backoff Error Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in." }, + "backoffIdleThreshold": { "index": 16, "kind": "parameter", "displayName": "Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent idle polls that should happen before the backoffMultipler should kick-in." }, + "backoffMultiplier": { "index": 17, "kind": "parameter", "displayName": "Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "To let the scheduled polling consumer backoff if there has been a number of subsequent idles\/errors in a row. The multiplier is then the number of polls that will be skipped before the next actual attempt is happening again. When this option is in use then backoffIdleThreshold and\/or backoffErrorThreshold must also be configured." }, + "delay": { "index": 18, "kind": "parameter", "displayName": "Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 500, "description": "Milliseconds before the next poll." }, + "greedy": { "index": 19, "kind": "parameter", "displayName": "Greedy", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If greedy is enabled, then the ScheduledPollConsumer will run immediately again, if the previous run polled 1 or more messages." }, + "initialDelay": { "index": 20, "kind": "parameter", "displayName": "Initial Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1000, "description": "Milliseconds before the first poll starts." }, + "repeatCount": { "index": 21, "kind": "parameter", "displayName": "Repeat Count", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 0, "description": "Specifies a maximum limit of number of fires. So if you set it to 1, the scheduler will only fire once. If you set it to 5, it will only fire five times. A value of zero or negative means fire forever." }, + "runLoggingLevel": { "index": 22, "kind": "parameter", "displayName": "Run Logging Level", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "enum", "javaType": "org.apache.camel.LoggingLevel", "enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "TRACE", "description": "The consumer logs a start\/complete log line when it polls. This option allows you to configure the logging level for that." }, + "scheduledExecutorService": { "index": 23, "kind": "parameter", "displayName": "Scheduled Executor Service", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.util.concurrent.ScheduledExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "Allows for configuring a custom\/shared thread pool to use for the consumer. By default each consumer has its own single threaded thread pool." }, + "scheduler": { "index": 24, "kind": "parameter", "displayName": "Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.lang.Object", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "description": "To use a cron scheduler from either camel-spring or camel-quartz component. Use value spring or quartz for built in scheduler" }, + "schedulerProperties": { "index": 25, "kind": "parameter", "displayName": "Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.util.Map", "prefix": "scheduler.", "multiValue": true, "deprecated": false, "autowired": false, "secret": false, "description": "To configure additional properties when using a custom scheduler or any of the Quartz, Spring based scheduler. This is a multi-value option with prefix: scheduler." }, + "startScheduler": { "index": 26, "kind": "parameter", "displayName": "Start Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether the scheduler should be auto started." }, + "timeUnit": { "index": 27, "kind": "parameter", "displayName": "Time Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [ "NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS", "DAYS" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and delay options." }, + "useFixedDelay": { "index": 28, "kind": "parameter", "displayName": "Use Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in JDK for details." }, + "accessKey": { "index": 29, "kind": "parameter", "displayName": "Access Key", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "description": "Access key for the cloud user" }, + "secretKey": { "index": 30, "kind": "parameter", "displayName": "Secret Key", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "description": "Secret key for the cloud user" }, + "serviceKeys": { "index": 31, "kind": "parameter", "displayName": "Service Keys", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.component.alibaba.common.models.ServiceKeys", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "description": "Configuration object for cloud service authentication" } + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/services/org/apache/camel/component.properties b/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/services/org/apache/camel/component.properties new file mode 100644 index 0000000000000..6968f368335fe --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/services/org/apache/camel/component.properties @@ -0,0 +1,7 @@ +# Generated by camel build tools - do NOT edit this file! +components=alibaba-mns +groupId=org.apache.camel +artifactId=camel-alibaba-mns +version=4.23.0-SNAPSHOT +projectName=Camel :: Alibaba Cloud :: Message Service (MNS) +projectDescription=Camel Alibaba Cloud Message Service (MNS) component diff --git a/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/services/org/apache/camel/component/alibaba-mns b/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/services/org/apache/camel/component/alibaba-mns new file mode 100644 index 0000000000000..5d2962600c879 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/services/org/apache/camel/component/alibaba-mns @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.alibaba.mns.MNSComponent diff --git a/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/services/org/apache/camel/configurer/alibaba-mns-component b/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/services/org/apache/camel/configurer/alibaba-mns-component new file mode 100644 index 0000000000000..70678be551413 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/services/org/apache/camel/configurer/alibaba-mns-component @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.alibaba.mns.MNSComponentConfigurer diff --git a/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/services/org/apache/camel/configurer/alibaba-mns-endpoint b/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/services/org/apache/camel/configurer/alibaba-mns-endpoint new file mode 100644 index 0000000000000..de659ae4e297f --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/services/org/apache/camel/configurer/alibaba-mns-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.alibaba.mns.MNSEndpointConfigurer diff --git a/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/services/org/apache/camel/urifactory/alibaba-mns-endpoint b/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/services/org/apache/camel/urifactory/alibaba-mns-endpoint new file mode 100644 index 0000000000000..0c059ae71060c --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/generated/resources/META-INF/services/org/apache/camel/urifactory/alibaba-mns-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.alibaba.mns.MNSEndpointUriFactory diff --git a/components/camel-alibaba/camel-alibaba-mns/src/main/docs/alibaba-mns-component.adoc b/components/camel-alibaba/camel-alibaba-mns/src/main/docs/alibaba-mns-component.adoc new file mode 100644 index 0000000000000..86820b7e56ffd --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/main/docs/alibaba-mns-component.adoc @@ -0,0 +1,128 @@ += Alibaba Message Service (MNS) Component +:doctitle: Alibaba Message Service (MNS) +:shortname: alibaba-mns +:artifactid: camel-alibaba-mns +:description: Send and receive messages to/from Alibaba Cloud Message Service (MNS). +:since: 4.23 +:supportlevel: Preview +:tabs-sync-option: +:component-header: Both producer and consumer are supported +//Manually maintained attributes +:group: Alibaba Cloud + +*Since Camel {since}* + +*{component-header}* + +The Alibaba Cloud Message Service (MNS) component allows you to integrate with +https://www.alibabacloud.com/product/mns[Alibaba Cloud MNS] for queue and topic messaging. + +NOTE: Alibaba Cloud recommends RocketMQ for new messaging workloads. MNS remains supported, +but evaluate https://www.alibabacloud.com/product/rocketmq[RocketMQ] or the Camel RocketMQ +component for greenfield projects. + +Maven users will need to add the following dependency to their `pom.xml` +for this component: + +[source,xml] +---- + + org.apache.camel + camel-alibaba-mns + x.x.x + + +---- + +== URI format + +Queue endpoints: + +[source] +---- +alibaba-mns:queueName[?options] +---- + +Topic endpoints: + +[source] +---- +alibaba-mns:topic:topicName[?options] +---- + +// component options: START +include::partial$component-configure-options.adoc[] +include::partial$component-endpoint-options.adoc[] +include::partial$component-endpoint-headers.adoc[] +// component options: END + +== Usage + +=== Operations + +The component supports the following operations: + +* `sendMessage` - send a message to a queue (producer) +* `receiveMessage` - receive messages from a queue (consumer) +* `deleteMessage` - delete a message from a queue using its receipt handle (producer) +* `publishMessage` - publish a message to a topic (producer) + +=== Queue producer example + +[source,java] +---- +from("direct:start") + .setBody(constant("Hello MNS")) + .to("alibaba-mns:myQueue?operation=sendMessage®ion=cn-hangzhou&accountEndpoint=https://123456.mns.cn-hangzhou.aliyuncs.com&accessKey=RAW(accessKey)&secretKey=RAW(secretKey)"); +---- + +=== Topic producer example + +[source,java] +---- +from("direct:start") + .setBody(constant("Hello Topic")) + .to("alibaba-mns:topic:myTopic?operation=publishMessage®ion=cn-hangzhou&accountEndpoint=https://123456.mns.cn-hangzhou.aliyuncs.com&accessKey=RAW(accessKey)&secretKey=RAW(secretKey)"); +---- + +=== Queue consumer example + +[source,java] +---- +from("alibaba-mns:myQueue?region=cn-hangzhou&accountEndpoint=https://123456.mns.cn-hangzhou.aliyuncs.com&accessKey=RAW(accessKey)&secretKey=RAW(secretKey)&deleteAfterRead=true") + .to("bean:processMessage"); +---- + +=== Exchange properties evaluated by the producer + +[width="100%",cols="10%,10%,80%",options="header",] +|======================================================================= +|Property |Type |Description + +|`CamelAlibabaMnsOperation` |`String` |Operation to perform + +|`CamelAlibabaMnsQueueName` |`String` |Queue name override + +|`CamelAlibabaMnsTopicName` |`String` |Topic name for publish operations + +|`CamelAlibabaMnsReceiptHandle` |`String` |Receipt handle for delete operations + +|======================================================================= + +=== Exchange properties set by the producer + +[width="100%",cols="10%,10%,80%",options="header",] +|======================================================================= +|Property |Type |Description + +|`CamelAlibabaMnsMessageId` |`String` |Message id returned by MNS + +|`CamelAlibabaMnsRequestId` |`String` |Request id returned by MNS + +|`CamelAlibabaMnsMessageBodyMd5` |`String` |MD5 digest of the message body + +|======================================================================= + +== Examples + +For more examples, see the unit tests in the `camel-alibaba-mns` module. diff --git a/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/MNSComponent.java b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/MNSComponent.java new file mode 100644 index 0000000000000..6c6e5c439ada6 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/MNSComponent.java @@ -0,0 +1,35 @@ +/* + * 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.mns; + +import java.util.Map; + +import org.apache.camel.Endpoint; +import org.apache.camel.spi.annotations.Component; +import org.apache.camel.support.HealthCheckComponent; + +@Component("alibaba-mns") +public class MNSComponent extends HealthCheckComponent { + + @Override + protected Endpoint createEndpoint(String uri, String remaining, Map parameters) throws Exception { + MNSEndpoint endpoint = new MNSEndpoint(uri, this); + MNSUtils.configurePath(remaining, endpoint); + setProperties(endpoint, parameters); + return endpoint; + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/MNSConsumer.java b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/MNSConsumer.java new file mode 100644 index 0000000000000..d206920079636 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/MNSConsumer.java @@ -0,0 +1,179 @@ +/* + * 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.mns; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import com.aliyun.mns.client.CloudQueue; +import com.aliyun.mns.model.Message; +import org.apache.camel.AsyncCallback; +import org.apache.camel.Exchange; +import org.apache.camel.ExchangePropertyKey; +import org.apache.camel.Processor; +import org.apache.camel.component.alibaba.mns.constants.MNSHeaders; +import org.apache.camel.spi.Synchronization; +import org.apache.camel.support.ScheduledBatchPollingConsumer; +import org.apache.camel.util.CastUtils; +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MNSConsumer extends ScheduledBatchPollingConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(MNSConsumer.class); + + public MNSConsumer(MNSEndpoint endpoint, Processor processor) { + super(endpoint, processor); + } + + @Override + protected int poll() throws Exception { + shutdownRunningTask = null; + pendingExchanges = 0; + + MNSEndpoint endpoint = getEndpoint(); + endpoint.initClient(); + + CloudQueue queue = endpoint.getMnsClient().getQueueRef(endpoint.getQueueName()); + List messages = receiveMessages(queue, endpoint.getMaxMessagesPerPoll(), endpoint.getWaitSeconds()); + + forceConsumerAsReady(); + + if (messages.isEmpty()) { + return 0; + } + + Queue exchanges = createExchanges(messages); + return processBatch(CastUtils.cast(exchanges)); + } + + private List receiveMessages(CloudQueue queue, int maxMessagesPerPoll, int waitSeconds) throws Exception { + int maxMessages = Math.max(1, maxMessagesPerPoll); + List messages = new ArrayList<>(); + + if (maxMessages == 1) { + Message message = waitSeconds > 0 ? queue.popMessage(waitSeconds) : queue.popMessage(); + if (message != null) { + messages.add(message); + } + return messages; + } + + List batch = waitSeconds > 0 + ? queue.batchPopMessage(maxMessages, waitSeconds) + : queue.batchPopMessage(maxMessages); + if (batch != null) { + messages.addAll(batch); + } + return messages; + } + + protected Queue createExchanges(List messages) { + Queue answer = new LinkedList<>(); + for (Message message : messages) { + if (ObjectHelper.isNotEmpty(message)) { + answer.add(createExchange(message)); + } + } + return answer; + } + + private Exchange createExchange(Message message) { + Exchange exchange = createExchange(true); + org.apache.camel.Message camelMessage = exchange.getIn(); + camelMessage.setBody(message.getMessageBody()); + camelMessage.setHeader(MNSHeaders.MESSAGE_ID, message.getMessageId()); + camelMessage.setHeader(MNSHeaders.RECEIPT_HANDLE, message.getReceiptHandle()); + camelMessage.setHeader(MNSHeaders.MESSAGE_BODY_MD5, message.getMessageBodyMD5()); + camelMessage.setHeader(MNSHeaders.DEQUEUE_COUNT, message.getDequeueCount()); + camelMessage.setHeader(MNSHeaders.ENQUEUE_TIME, message.getEnqueueTime()); + camelMessage.setHeader(MNSHeaders.NEXT_VISIBLE_TIME, message.getNextVisibleTime()); + camelMessage.setHeader(MNSHeaders.FIRST_DEQUEUE_TIME, message.getFirstDequeueTime()); + camelMessage.setHeader(MNSHeaders.PRIORITY, message.getPriority()); + return exchange; + } + + @Override + public int processBatch(Queue exchanges) throws Exception { + int total = exchanges.size(); + + for (int index = 0; index < total && isBatchAllowed(); index++) { + final Exchange exchange = ObjectHelper.cast(Exchange.class, exchanges.poll()); + exchange.setProperty(ExchangePropertyKey.BATCH_INDEX, index); + exchange.setProperty(ExchangePropertyKey.BATCH_SIZE, total); + exchange.setProperty(ExchangePropertyKey.BATCH_COMPLETE, index == total - 1); + + pendingExchanges = total - index - 1; + + exchange.getExchangeExtension().addOnCompletion(new Synchronization() { + @Override + public void onComplete(Exchange exchange) { + processCommit(exchange); + } + + @Override + public void onFailure(Exchange exchange) { + processRollback(exchange); + } + + @Override + public String toString() { + return "MNSConsumerOnCompletion"; + } + }); + + AsyncCallback callback = defaultConsumerCallback(exchange, true); + getAsyncProcessor().process(exchange, callback); + } + + return total; + } + + protected void processCommit(Exchange exchange) { + if (!getEndpoint().isDeleteAfterRead()) { + return; + } + try { + String receiptHandle = exchange.getIn().getHeader(MNSHeaders.RECEIPT_HANDLE, String.class); + if (ObjectHelper.isEmpty(receiptHandle)) { + return; + } + CloudQueue queue = getEndpoint().getMnsClient().getQueueRef(getEndpoint().getQueueName()); + queue.deleteMessage(receiptHandle); + } catch (Exception e) { + getExceptionHandler().handleException("Error occurred during deleting MNS message. This exception is ignored.", + exchange, e); + } + } + + protected void processRollback(Exchange exchange) { + Exception cause = exchange.getException(); + if (ObjectHelper.isNotEmpty(cause)) { + getExceptionHandler().handleException( + "Error during processing MNS exchange. Will attempt to process the message on next poll.", exchange, + cause); + } + } + + @Override + public MNSEndpoint getEndpoint() { + return (MNSEndpoint) super.getEndpoint(); + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/MNSEndpoint.java b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/MNSEndpoint.java new file mode 100644 index 0000000000000..43b5b37554012 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/MNSEndpoint.java @@ -0,0 +1,263 @@ +/* + * 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.mns; + +import com.aliyun.mns.client.MNSClient; +import org.apache.camel.Category; +import org.apache.camel.Consumer; +import org.apache.camel.Processor; +import org.apache.camel.Producer; +import org.apache.camel.component.alibaba.common.models.ServiceKeys; +import org.apache.camel.component.alibaba.mns.constants.MNSHeaders; +import org.apache.camel.component.alibaba.mns.constants.MNSOperations; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.UriEndpoint; +import org.apache.camel.spi.UriParam; +import org.apache.camel.spi.UriPath; +import org.apache.camel.support.ScheduledPollEndpoint; + +/** + * Send and receive messages to/from Alibaba Cloud Message Service (MNS). + */ +@UriEndpoint(firstVersion = "4.23.0", scheme = "alibaba-mns", title = "Alibaba Message Service (MNS)", + syntax = "alibaba-mns:queueName", category = { Category.CLOUD, Category.MESSAGING }, + headersClass = MNSHeaders.class) +public class MNSEndpoint extends ScheduledPollEndpoint { + + @UriPath(description = "Queue name, or topic name when using the topic URI syntax", displayName = "Queue Name") + @Metadata(required = true) + private String queueName; + + @UriParam(description = "Operation to perform", displayName = "Operation", + enums = "sendMessage,receiveMessage,deleteMessage,publishMessage") + private String operation; + + @UriParam(description = "Alibaba Cloud region", displayName = "Region") + @Metadata(required = true) + private String region; + + @UriParam(description = "MNS account endpoint, for example https://123456.mns.cn-hangzhou.aliyuncs.com", + displayName = "Account Endpoint") + @Metadata(required = true) + private String accountEndpoint; + + @UriParam(description = "Access key for the cloud user", displayName = "Access Key", + secret = true, security = "secret", label = "security") + private String accessKey; + + @UriParam(description = "Secret key for the cloud user", displayName = "Secret Key", + secret = true, security = "secret", label = "security") + private String secretKey; + + @UriParam(description = "Configuration object for cloud service authentication", displayName = "Service Keys", + secret = true, security = "secret", label = "security") + private ServiceKeys serviceKeys; + + @UriParam(description = "Topic name for publishMessage operations", displayName = "Topic Name") + private String topicName; + + @UriParam(description = "Long polling wait time in seconds when receiving messages", displayName = "Wait Seconds", + defaultValue = "0") + private int waitSeconds; + + @UriParam(description = "Delete message from the queue after it has been processed", displayName = "Delete After Read", + defaultValue = "true", label = "consumer") + private boolean deleteAfterRead = true; + + @UriParam(description = "Maximum number of messages to receive per poll", displayName = "Max Messages Per Poll", + defaultValue = "1", label = "consumer") + private int maxMessagesPerPoll = 1; + + @UriParam(description = "Autowire an existing MNSClient instance", displayName = "MNS Client", label = "advanced") + @Metadata(autowired = true) + private MNSClient mnsClient; + + private boolean autowiredMnsClient; + + private boolean topicEndpoint; + + public MNSEndpoint() { + } + + public MNSEndpoint(String uri, MNSComponent component) { + super(uri, component); + } + + @Override + public Producer createProducer() throws Exception { + return new MNSProducer(this); + } + + @Override + public Consumer createConsumer(Processor processor) throws Exception { + if (topicEndpoint) { + throw new IllegalArgumentException("Topic endpoints do not support consumers"); + } + MNSConsumer consumer = new MNSConsumer(this, processor); + configureConsumer(consumer); + consumer.setMaxMessagesPerPoll(maxMessagesPerPoll); + return consumer; + } + + public void initClient() { + if (mnsClient != null) { + return; + } + mnsClient = MNSUtils.createClient(this); + } + + @Override + protected void doStop() throws Exception { + if (mnsClient != null && !autowiredMnsClient) { + mnsClient.close(); + mnsClient = null; + } + super.doStop(); + } + + public boolean isTopicEndpoint() { + return topicEndpoint; + } + + public void setTopicEndpoint(boolean topicEndpoint) { + this.topicEndpoint = topicEndpoint; + } + + public String getQueueName() { + return queueName; + } + + public void setQueueName(String queueName) { + this.queueName = queueName; + } + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getAccountEndpoint() { + return accountEndpoint; + } + + public void setAccountEndpoint(String accountEndpoint) { + this.accountEndpoint = accountEndpoint; + } + + public String getAccessKey() { + return accessKey; + } + + public void setAccessKey(String accessKey) { + this.accessKey = accessKey; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public ServiceKeys getServiceKeys() { + return serviceKeys; + } + + public void setServiceKeys(ServiceKeys serviceKeys) { + this.serviceKeys = serviceKeys; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public int getWaitSeconds() { + return waitSeconds; + } + + public void setWaitSeconds(int waitSeconds) { + this.waitSeconds = waitSeconds; + } + + public boolean isDeleteAfterRead() { + return deleteAfterRead; + } + + public void setDeleteAfterRead(boolean deleteAfterRead) { + this.deleteAfterRead = deleteAfterRead; + } + + public int getMaxMessagesPerPoll() { + return maxMessagesPerPoll; + } + + public void setMaxMessagesPerPoll(int maxMessagesPerPoll) { + this.maxMessagesPerPoll = maxMessagesPerPoll; + } + + public MNSClient getMnsClient() { + return mnsClient; + } + + public void setMnsClient(MNSClient mnsClient) { + this.mnsClient = mnsClient; + this.autowiredMnsClient = mnsClient != null; + } + + public String resolveOperation() { + if (operation != null) { + return operation; + } + if (topicEndpoint) { + return MNSOperations.PUBLISH_MESSAGE; + } + return MNSOperations.SEND_MESSAGE; + } + + public String resolveConsumerOperation() { + if (operation != null) { + return operation; + } + return MNSOperations.RECEIVE_MESSAGE; + } + + public String resolveTopicName() { + if (topicName != null) { + return topicName; + } + if (topicEndpoint) { + return queueName; + } + return null; + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/MNSProducer.java b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/MNSProducer.java new file mode 100644 index 0000000000000..cc7056427e46c --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/MNSProducer.java @@ -0,0 +1,126 @@ +/* + * 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.mns; + +import com.aliyun.mns.client.CloudQueue; +import com.aliyun.mns.client.CloudTopic; +import com.aliyun.mns.model.Base64TopicMessage; +import com.aliyun.mns.model.BaseMessage; +import com.aliyun.mns.model.Message; +import com.aliyun.mns.model.TopicMessage; +import org.apache.camel.Exchange; +import org.apache.camel.component.alibaba.mns.constants.MNSHeaders; +import org.apache.camel.component.alibaba.mns.constants.MNSOperations; +import org.apache.camel.component.alibaba.mns.constants.MNSProperties; +import org.apache.camel.component.alibaba.mns.models.ClientConfigurations; +import org.apache.camel.support.DefaultProducer; +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MNSProducer extends DefaultProducer { + + private static final Logger LOG = LoggerFactory.getLogger(MNSProducer.class); + + public MNSProducer(MNSEndpoint endpoint) { + super(endpoint); + } + + @Override + public void process(Exchange exchange) throws Exception { + MNSEndpoint endpoint = getEndpoint(); + endpoint.initClient(); + + ClientConfigurations configuration = MNSUtils.createClientConfigurations(endpoint, exchange); + String operation = configuration.getOperation(); + + switch (operation) { + case MNSOperations.SEND_MESSAGE -> sendMessage(endpoint, exchange, configuration); + case MNSOperations.DELETE_MESSAGE -> deleteMessage(endpoint, exchange, configuration); + case MNSOperations.PUBLISH_MESSAGE -> publishMessage(endpoint, exchange, configuration); + default -> throw new UnsupportedOperationException("Unsupported operation: " + operation); + } + } + + private void sendMessage(MNSEndpoint endpoint, Exchange exchange, ClientConfigurations configuration) throws Exception { + CloudQueue queue = endpoint.getMnsClient().getQueueRef(configuration.getQueueName()); + Message message = new Message(); + message.setMessageBody(MNSUtils.resolveMessageBody(exchange)); + + Integer delaySeconds = exchange.getIn().getHeader(MNSHeaders.DELAY_SECONDS, Integer.class); + if (delaySeconds != null) { + message.setDelaySeconds(delaySeconds); + } + + Integer priority = exchange.getIn().getHeader(MNSHeaders.PRIORITY, Integer.class); + if (priority != null) { + message.setPriority(priority); + } + + Message response = queue.putMessage(message); + setMessageResponseProperties(exchange, response); + } + + private void deleteMessage(MNSEndpoint endpoint, Exchange exchange, ClientConfigurations configuration) throws Exception { + String receiptHandle = MNSUtils.resolveReceiptHandle(exchange); + if (ObjectHelper.isEmpty(receiptHandle)) { + throw new IllegalArgumentException("Receipt handle is required for deleteMessage operation"); + } + + CloudQueue queue = endpoint.getMnsClient().getQueueRef(configuration.getQueueName()); + queue.deleteMessage(receiptHandle); + } + + private void publishMessage(MNSEndpoint endpoint, Exchange exchange, ClientConfigurations configuration) throws Exception { + String topic = configuration.getTopicName(); + if (ObjectHelper.isEmpty(topic)) { + throw new IllegalArgumentException("Topic name is required for publishMessage operation"); + } + + CloudTopic cloudTopic = endpoint.getMnsClient().getTopicRef(topic); + TopicMessage topicMessage = new Base64TopicMessage(); + topicMessage.setMessageBody(MNSUtils.resolveMessageBody(exchange)); + + String messageTag = exchange.getIn().getHeader(MNSHeaders.MESSAGE_TAG, String.class); + if (messageTag != null) { + topicMessage.setMessageTag(messageTag); + } + + TopicMessage response = cloudTopic.publishMessage(topicMessage); + setMessageResponseProperties(exchange, response); + } + + private void setMessageResponseProperties(Exchange exchange, BaseMessage response) { + if (response == null) { + return; + } + if (ObjectHelper.isNotEmpty(response.getMessageId())) { + exchange.setProperty(MNSHeaders.MESSAGE_ID, response.getMessageId()); + } + if (ObjectHelper.isNotEmpty(response.getRequestId())) { + exchange.setProperty(MNSProperties.REQUEST_ID, response.getRequestId()); + } + if (ObjectHelper.isNotEmpty(response.getMessageBodyMD5())) { + exchange.setProperty(MNSHeaders.MESSAGE_BODY_MD5, response.getMessageBodyMD5()); + } + } + + @Override + public MNSEndpoint getEndpoint() { + return (MNSEndpoint) super.getEndpoint(); + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/MNSUtils.java b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/MNSUtils.java new file mode 100644 index 0000000000000..1a428dcdb2752 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/MNSUtils.java @@ -0,0 +1,146 @@ +/* + * 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.mns; + +import com.aliyun.mns.client.MNSClient; +import com.aliyun.mns.client.MNSClientBuilder; +import org.apache.camel.Exchange; +import org.apache.camel.component.alibaba.common.models.ServiceKeys; +import org.apache.camel.component.alibaba.mns.constants.MNSHeaders; +import org.apache.camel.component.alibaba.mns.constants.MNSProperties; +import org.apache.camel.component.alibaba.mns.models.ClientConfigurations; +import org.apache.camel.util.ObjectHelper; + +public final class MNSUtils { + + private static final String TOPIC_PATH_PREFIX = "topic:"; + + private MNSUtils() { + } + + public static void configurePath(String remaining, MNSEndpoint endpoint) { + if (remaining != null && remaining.startsWith(TOPIC_PATH_PREFIX)) { + endpoint.setTopicEndpoint(true); + endpoint.setTopicName(remaining.substring(TOPIC_PATH_PREFIX.length())); + endpoint.setQueueName(remaining.substring(TOPIC_PATH_PREFIX.length())); + } else { + endpoint.setQueueName(remaining); + } + } + + public static MNSClient createClient(MNSEndpoint endpoint) { + String accessKey = resolveAccessKey(endpoint); + String secretKey = resolveSecretKey(endpoint); + + if (ObjectHelper.isEmpty(endpoint.getAccountEndpoint())) { + throw new IllegalArgumentException("accountEndpoint is required"); + } + if (ObjectHelper.isEmpty(endpoint.getRegion())) { + throw new IllegalArgumentException("region is required"); + } + + return MNSClientBuilder.create() + .accessKeyId(accessKey) + .accessKeySecret(secretKey) + .accountEndpoint(endpoint.getAccountEndpoint()) + .region(endpoint.getRegion()) + .build(); + } + + public static ClientConfigurations createClientConfigurations(MNSEndpoint endpoint, Exchange exchange) { + ClientConfigurations configuration = new ClientConfigurations(); + configuration.setOperation(resolveOperation(endpoint, exchange)); + configuration.setAccessKey(resolveAccessKey(endpoint)); + configuration.setSecretKey(resolveSecretKey(endpoint)); + configuration.setRegion(endpoint.getRegion()); + configuration.setAccountEndpoint(endpoint.getAccountEndpoint()); + configuration.setQueueName(resolveQueueName(endpoint, exchange)); + configuration.setTopicName(resolveTopicName(endpoint, exchange)); + return configuration; + } + + public static String resolveOperation(MNSEndpoint endpoint, Exchange exchange) { + String operation = exchange.getProperty(MNSProperties.OPERATION, String.class); + if (ObjectHelper.isEmpty(operation)) { + operation = exchange.getIn().getHeader(MNSProperties.OPERATION, String.class); + } + if (ObjectHelper.isEmpty(operation)) { + operation = endpoint.resolveOperation(); + } + return operation; + } + + public static String resolveQueueName(MNSEndpoint endpoint, Exchange exchange) { + String queueName = exchange.getProperty(MNSProperties.QUEUE_NAME, String.class); + if (ObjectHelper.isEmpty(queueName)) { + queueName = endpoint.getQueueName(); + } + return queueName; + } + + public static String resolveTopicName(MNSEndpoint endpoint, Exchange exchange) { + String topicName = exchange.getProperty(MNSProperties.TOPIC_NAME, String.class); + if (ObjectHelper.isEmpty(topicName)) { + topicName = exchange.getIn().getHeader(MNSProperties.TOPIC_NAME, String.class); + } + if (ObjectHelper.isEmpty(topicName)) { + topicName = endpoint.resolveTopicName(); + } + return topicName; + } + + public static String resolveReceiptHandle(Exchange exchange) { + String receiptHandle = exchange.getIn().getHeader(MNSHeaders.RECEIPT_HANDLE, String.class); + if (ObjectHelper.isEmpty(receiptHandle)) { + receiptHandle = exchange.getProperty(MNSHeaders.RECEIPT_HANDLE, String.class); + } + return receiptHandle; + } + + public static String resolveMessageBody(Exchange exchange) { + Object body = exchange.getMessage().getBody(); + if (body == null) { + throw new IllegalArgumentException("exchange body cannot be null / empty"); + } + if (body instanceof String stringBody) { + return stringBody; + } + return exchange.getMessage().getBody(String.class); + } + + private static String resolveAccessKey(MNSEndpoint endpoint) { + if (ObjectHelper.isNotEmpty(endpoint.getAccessKey())) { + return endpoint.getAccessKey(); + } + ServiceKeys serviceKeys = endpoint.getServiceKeys(); + if (serviceKeys != null && ObjectHelper.isNotEmpty(serviceKeys.getAccessKey())) { + return serviceKeys.getAccessKey(); + } + throw new IllegalArgumentException("authentication parameter 'access key (AK)' not found"); + } + + private static String resolveSecretKey(MNSEndpoint endpoint) { + if (ObjectHelper.isNotEmpty(endpoint.getSecretKey())) { + return endpoint.getSecretKey(); + } + ServiceKeys serviceKeys = endpoint.getServiceKeys(); + if (serviceKeys != null && ObjectHelper.isNotEmpty(serviceKeys.getSecretKey())) { + return serviceKeys.getSecretKey(); + } + throw new IllegalArgumentException("authentication parameter 'secret key (SK)' not found"); + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/constants/MNSHeaders.java b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/constants/MNSHeaders.java new file mode 100644 index 0000000000000..1e1ec9948c53d --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/constants/MNSHeaders.java @@ -0,0 +1,55 @@ +/* + * 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.mns.constants; + +import org.apache.camel.spi.Metadata; + +public final class MNSHeaders { + + @Metadata(label = "common", description = "The MNS message id", javaType = "String") + public static final String MESSAGE_ID = "CamelAlibabaMnsMessageId"; + + @Metadata(label = "common", description = "The MNS receipt handle", javaType = "String") + public static final String RECEIPT_HANDLE = "CamelAlibabaMnsReceiptHandle"; + + @Metadata(label = "common", description = "The MD5 digest of the message body", javaType = "String") + public static final String MESSAGE_BODY_MD5 = "CamelAlibabaMnsMessageBodyMd5"; + + @Metadata(label = "producer", description = "Delay in seconds before the message becomes visible", javaType = "Integer") + public static final String DELAY_SECONDS = "CamelAlibabaMnsDelaySeconds"; + + @Metadata(label = "producer", description = "Message priority", javaType = "Integer") + public static final String PRIORITY = "CamelAlibabaMnsPriority"; + + @Metadata(label = "producer", description = "Message tag for topic publish operations", javaType = "String") + public static final String MESSAGE_TAG = "CamelAlibabaMnsMessageTag"; + + @Metadata(label = "consumer", description = "Number of times the message has been dequeued", javaType = "Integer") + public static final String DEQUEUE_COUNT = "CamelAlibabaMnsDequeueCount"; + + @Metadata(label = "consumer", description = "Time when the message was enqueued", javaType = "java.util.Date") + public static final String ENQUEUE_TIME = "CamelAlibabaMnsEnqueueTime"; + + @Metadata(label = "consumer", description = "Next time the message becomes visible", javaType = "java.util.Date") + public static final String NEXT_VISIBLE_TIME = "CamelAlibabaMnsNextVisibleTime"; + + @Metadata(label = "consumer", description = "Time when the message was first dequeued", javaType = "java.util.Date") + public static final String FIRST_DEQUEUE_TIME = "CamelAlibabaMnsFirstDequeueTime"; + + private MNSHeaders() { + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/constants/MNSOperations.java b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/constants/MNSOperations.java new file mode 100644 index 0000000000000..6f3d0a0b53041 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/constants/MNSOperations.java @@ -0,0 +1,28 @@ +/* + * 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.mns.constants; + +public final class MNSOperations { + + public static final String SEND_MESSAGE = "sendMessage"; + public static final String RECEIVE_MESSAGE = "receiveMessage"; + public static final String DELETE_MESSAGE = "deleteMessage"; + public static final String PUBLISH_MESSAGE = "publishMessage"; + + private MNSOperations() { + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/constants/MNSProperties.java b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/constants/MNSProperties.java new file mode 100644 index 0000000000000..7337c68fedcf1 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/constants/MNSProperties.java @@ -0,0 +1,28 @@ +/* + * 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.mns.constants; + +public final class MNSProperties { + + public static final String OPERATION = "CamelAlibabaMnsOperation"; + public static final String QUEUE_NAME = "CamelAlibabaMnsQueueName"; + public static final String TOPIC_NAME = "CamelAlibabaMnsTopicName"; + public static final String REQUEST_ID = "CamelAlibabaMnsRequestId"; + + private MNSProperties() { + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/models/ClientConfigurations.java b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/models/ClientConfigurations.java new file mode 100644 index 0000000000000..850a52fedb081 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/main/java/org/apache/camel/component/alibaba/mns/models/ClientConfigurations.java @@ -0,0 +1,84 @@ +/* + * 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.mns.models; + +public class ClientConfigurations { + + private String operation; + private String accessKey; + private String secretKey; + private String region; + private String accountEndpoint; + private String queueName; + private String topicName; + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + public String getAccessKey() { + return accessKey; + } + + public void setAccessKey(String accessKey) { + this.accessKey = accessKey; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getAccountEndpoint() { + return accountEndpoint; + } + + public void setAccountEndpoint(String accountEndpoint) { + this.accountEndpoint = accountEndpoint; + } + + public String getQueueName() { + return queueName; + } + + public void setQueueName(String queueName) { + this.queueName = queueName; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/MNSEndpointTest.java b/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/MNSEndpointTest.java new file mode 100644 index 0000000000000..95dfa7712d097 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/MNSEndpointTest.java @@ -0,0 +1,58 @@ +/* + * 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.mns; + +import com.aliyun.mns.client.MNSClient; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +class MNSEndpointTest { + + @Test + void doStopSkipsCloseForAutowiredClient() throws Exception { + MNSEndpoint endpoint = new MNSEndpoint(); + MNSClient client = mock(MNSClient.class); + endpoint.setMnsClient(client); + + endpoint.doStop(); + + verify(client, never()).close(); + } + + @Test + void doStopClosesOwnedClient() throws Exception { + MNSEndpoint endpoint = new MNSEndpoint(); + MNSClient client = mock(MNSClient.class); + + var clientField = MNSEndpoint.class.getDeclaredField("mnsClient"); + clientField.setAccessible(true); + clientField.set(endpoint, client); + + var autowiredField = MNSEndpoint.class.getDeclaredField("autowiredMnsClient"); + autowiredField.setAccessible(true); + autowiredField.setBoolean(endpoint, false); + + endpoint.doStop(); + + verify(client).close(); + assertThat(endpoint.getMnsClient()).isNull(); + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/PublishMessageTest.java b/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/PublishMessageTest.java new file mode 100644 index 0000000000000..41de43587f029 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/PublishMessageTest.java @@ -0,0 +1,87 @@ +/* + * 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.mns; + +import com.aliyun.mns.client.CloudTopic; +import com.aliyun.mns.client.MNSClient; +import com.aliyun.mns.model.Base64TopicMessage; +import com.aliyun.mns.model.TopicMessage; +import org.apache.camel.BindToRegistry; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.alibaba.mns.constants.MNSHeaders; +import org.apache.camel.component.alibaba.mns.constants.MNSProperties; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class PublishMessageTest extends CamelTestSupport { + + private final TestConfiguration testConfiguration = new TestConfiguration(); + + @BindToRegistry("mnsClient") + MNSClient mnsClient = mock(MNSClient.class); + + CloudTopic cloudTopic = mock(CloudTopic.class); + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:publish") + .to("alibaba-mns:topic:" + testConfiguration.getProperty("topic") + + "?operation=publishMessage" + + "®ion=" + testConfiguration.getProperty("region") + + "&accountEndpoint=" + testConfiguration.getProperty("accountEndpoint") + + "&accessKey=" + testConfiguration.getProperty("accessKey") + + "&secretKey=" + testConfiguration.getProperty("secretKey") + + "&mnsClient=#mnsClient") + .to("mock:result"); + } + }; + } + + @Test + void testPublishMessage() throws Exception { + TopicMessage response = new Base64TopicMessage(); + response.setMessageId("topic-message-id"); + response.setRequestId("topic-request-id"); + + when(mnsClient.getTopicRef(testConfiguration.getProperty("topic"))).thenReturn(cloudTopic); + when(cloudTopic.publishMessage(any(TopicMessage.class))).thenReturn(response); + + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMinimumMessageCount(1); + + template.sendBody("direct:publish", "hello topic"); + + mock.assertIsSatisfied(); + + Exchange exchange = mock.getExchanges().get(0); + assertThat(exchange.getProperty(MNSHeaders.MESSAGE_ID)).isEqualTo("topic-message-id"); + assertThat(exchange.getProperty(MNSProperties.REQUEST_ID)).isEqualTo("topic-request-id"); + + verify(cloudTopic).publishMessage(any(TopicMessage.class)); + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/ReceiveMessageConsumerTest.java b/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/ReceiveMessageConsumerTest.java new file mode 100644 index 0000000000000..0a5f255bcf678 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/ReceiveMessageConsumerTest.java @@ -0,0 +1,90 @@ +/* + * 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.mns; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +import com.aliyun.mns.client.CloudQueue; +import com.aliyun.mns.client.MNSClient; +import com.aliyun.mns.model.Message; +import org.apache.camel.BindToRegistry; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.alibaba.mns.constants.MNSHeaders; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.awaitility.Awaitility.await; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class ReceiveMessageConsumerTest extends CamelTestSupport { + + private final TestConfiguration testConfiguration = new TestConfiguration(); + + @BindToRegistry("mnsClient") + MNSClient mnsClient = mock(MNSClient.class); + + CloudQueue cloudQueue = mock(CloudQueue.class); + + @Override + protected RouteBuilder createRouteBuilder() { + String accountEndpoint = URLEncoder.encode(testConfiguration.getProperty("accountEndpoint"), + StandardCharsets.UTF_8); + return new RouteBuilder() { + @Override + public void configure() { + from("alibaba-mns:" + testConfiguration.getProperty("queue") + + "?region=" + testConfiguration.getProperty("region") + + "&accountEndpoint=" + accountEndpoint + + "&accessKey=" + testConfiguration.getProperty("accessKey") + + "&secretKey=" + testConfiguration.getProperty("secretKey") + + "&deleteAfterRead=true" + + "&initialDelay=100" + + "&delay=200" + + "&useFixedDelay=true" + + "&mnsClient=#mnsClient") + .to("mock:result"); + } + }; + } + + @Test + void testReceiveMessageAndDeleteAfterRead() throws Exception { + Message message = new Message("received body"); + message.setMessageId("received-id"); + message.setReceiptHandle("receipt-handle-123"); + message.setMessageBodyMD5("received-md5"); + + when(mnsClient.getQueueRef(testConfiguration.getProperty("queue"))).thenReturn(cloudQueue); + when(cloudQueue.popMessage()).thenReturn(message).thenReturn(null); + + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMessageCount(1); + mock.expectedHeaderReceived(MNSHeaders.MESSAGE_ID, "received-id"); + mock.expectedHeaderReceived(MNSHeaders.RECEIPT_HANDLE, "receipt-handle-123"); + mock.expectedBodiesReceived("received body"); + + MockEndpoint.assertIsSatisfied(context, 20, TimeUnit.SECONDS); + + await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> verify(cloudQueue).deleteMessage(eq("receipt-handle-123"))); + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/SendMessageDefaultOperationTest.java b/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/SendMessageDefaultOperationTest.java new file mode 100644 index 0000000000000..cbcb7980efd21 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/SendMessageDefaultOperationTest.java @@ -0,0 +1,75 @@ +/* + * 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.mns; + +import com.aliyun.mns.client.CloudQueue; +import com.aliyun.mns.client.MNSClient; +import com.aliyun.mns.model.Message; +import org.apache.camel.BindToRegistry; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class SendMessageDefaultOperationTest extends CamelTestSupport { + + private final TestConfiguration testConfiguration = new TestConfiguration(); + + @BindToRegistry("mnsClient") + MNSClient mnsClient = mock(MNSClient.class); + + CloudQueue cloudQueue = mock(CloudQueue.class); + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:send") + .to("alibaba-mns:" + testConfiguration.getProperty("queue") + + "?region=" + testConfiguration.getProperty("region") + + "&accountEndpoint=" + testConfiguration.getProperty("accountEndpoint") + + "&accessKey=" + testConfiguration.getProperty("accessKey") + + "&secretKey=" + testConfiguration.getProperty("secretKey") + + "&mnsClient=#mnsClient") + .to("mock:result"); + } + }; + } + + @Test + void queueProducerDefaultsToSendMessage() throws Exception { + Message response = new Message("response"); + response.setMessageId("message-id-default"); + + when(mnsClient.getQueueRef(testConfiguration.getProperty("queue"))).thenReturn(cloudQueue); + when(cloudQueue.putMessage(any(Message.class))).thenReturn(response); + + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMinimumMessageCount(1); + + template.sendBody("direct:send", "hello mns"); + + mock.assertIsSatisfied(); + verify(cloudQueue).putMessage(any(Message.class)); + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/SendMessageTest.java b/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/SendMessageTest.java new file mode 100644 index 0000000000000..a8d5a7d9d08bc --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/SendMessageTest.java @@ -0,0 +1,88 @@ +/* + * 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.mns; + +import com.aliyun.mns.client.CloudQueue; +import com.aliyun.mns.client.MNSClient; +import com.aliyun.mns.model.Message; +import org.apache.camel.BindToRegistry; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.alibaba.mns.constants.MNSHeaders; +import org.apache.camel.component.alibaba.mns.constants.MNSProperties; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class SendMessageTest extends CamelTestSupport { + + private final TestConfiguration testConfiguration = new TestConfiguration(); + + @BindToRegistry("mnsClient") + MNSClient mnsClient = mock(MNSClient.class); + + CloudQueue cloudQueue = mock(CloudQueue.class); + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:send") + .to("alibaba-mns:" + testConfiguration.getProperty("queue") + + "?operation=sendMessage" + + "®ion=" + testConfiguration.getProperty("region") + + "&accountEndpoint=" + testConfiguration.getProperty("accountEndpoint") + + "&accessKey=" + testConfiguration.getProperty("accessKey") + + "&secretKey=" + testConfiguration.getProperty("secretKey") + + "&mnsClient=#mnsClient") + .to("mock:result"); + } + }; + } + + @Test + void testSendMessage() throws Exception { + Message response = new Message("response"); + response.setMessageId("message-id-123"); + response.setRequestId("request-id-456"); + response.setMessageBodyMD5("md5-value"); + + when(mnsClient.getQueueRef(testConfiguration.getProperty("queue"))).thenReturn(cloudQueue); + when(cloudQueue.putMessage(any(Message.class))).thenReturn(response); + + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMinimumMessageCount(1); + + template.sendBody("direct:send", "hello mns"); + + mock.assertIsSatisfied(); + + Exchange exchange = mock.getExchanges().get(0); + assertThat(exchange.getProperty(MNSHeaders.MESSAGE_ID)).isEqualTo("message-id-123"); + assertThat(exchange.getProperty(MNSProperties.REQUEST_ID)).isEqualTo("request-id-456"); + assertThat(exchange.getProperty(MNSHeaders.MESSAGE_BODY_MD5)).isEqualTo("md5-value"); + + verify(cloudQueue).putMessage(any(Message.class)); + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/TestConfiguration.java b/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/TestConfiguration.java new file mode 100644 index 0000000000000..c49da0d696171 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/TestConfiguration.java @@ -0,0 +1,57 @@ +/* + * 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.mns; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.apache.camel.test.junit6.TestSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class TestConfiguration { + + private static final Logger LOGGER = LoggerFactory.getLogger(TestConfiguration.class); + private static Map propertyMap; + + TestConfiguration() { + initPropertyMap(); + } + + void initPropertyMap() { + if (propertyMap == null) { + propertyMap = new HashMap<>(); + String propertyFileName = "testconfiguration.properties"; + try { + Properties properties = TestSupport.loadExternalProperties(getClass().getClassLoader(), propertyFileName); + for (String key : properties.stringPropertyNames()) { + propertyMap.put(key, properties.getProperty(key)); + } + } catch (Exception e) { + LOGGER.error("Cannot load property file {}, reason {}", propertyFileName, e.getMessage()); + } + } + } + + String getProperty(String key) { + if (propertyMap == null) { + initPropertyMap(); + } + return propertyMap.get(key); + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/constants/MNSOperationsTest.java b/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/constants/MNSOperationsTest.java new file mode 100644 index 0000000000000..04b05e564b943 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/test/java/org/apache/camel/component/alibaba/mns/constants/MNSOperationsTest.java @@ -0,0 +1,32 @@ +/* + * 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.mns.constants; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class MNSOperationsTest { + + @Test + void testOperationNames() { + assertThat(MNSOperations.SEND_MESSAGE).isEqualTo("sendMessage"); + assertThat(MNSOperations.RECEIVE_MESSAGE).isEqualTo("receiveMessage"); + assertThat(MNSOperations.DELETE_MESSAGE).isEqualTo("deleteMessage"); + assertThat(MNSOperations.PUBLISH_MESSAGE).isEqualTo("publishMessage"); + } +} diff --git a/components/camel-alibaba/camel-alibaba-mns/src/test/resources/log4j2.properties b/components/camel-alibaba/camel-alibaba-mns/src/test/resources/log4j2.properties new file mode 100644 index 0000000000000..c3df5b0a8b22a --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/test/resources/log4j2.properties @@ -0,0 +1,29 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +appender.file.type = File +appender.file.name = file +appender.file.fileName = target/camel-alibaba-mns-test.log +appender.file.layout.type = PatternLayout +appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n +appender.out.type = Console +appender.out.name = out +appender.out.layout.type = PatternLayout +appender.out.layout.pattern = [%30.30t] %-30.30c{1} %-5p %m%n + +rootLogger.level = INFO +rootLogger.appenderRef.file.ref = file diff --git a/components/camel-alibaba/camel-alibaba-mns/src/test/resources/testconfiguration.properties b/components/camel-alibaba/camel-alibaba-mns/src/test/resources/testconfiguration.properties new file mode 100644 index 0000000000000..15d8d8675c6d1 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-mns/src/test/resources/testconfiguration.properties @@ -0,0 +1,23 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +accessKey=dummy_access_key +secretKey=dummy_secret_key +region=cn-hangzhou +accountEndpoint=https://123456.mns.cn-hangzhou.aliyuncs.com +queue=test-queue +topic=test-topic diff --git a/components/camel-alibaba/camel-alibaba-oss/pom.xml b/components/camel-alibaba/camel-alibaba-oss/pom.xml new file mode 100644 index 0000000000000..430caa77ff573 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/pom.xml @@ -0,0 +1,75 @@ + + + + + 4.0.0 + + + org.apache.camel + camel-alibaba-parent + 4.23.0-SNAPSHOT + + + + 4.23.0 + + + camel-alibaba-oss + jar + Camel :: Alibaba Cloud :: OSS + Alibaba Cloud Object Storage Service (OSS) component + + + + + org.apache.camel + camel-support + + + + org.apache.camel + camel-alibaba-common + ${project.version} + + + + com.aliyun + alibabacloud-oss-v2 + ${alibabacloud-oss-version} + + + + org.apache.camel + camel-test-junit6 + test + + + org.mockito + mockito-core + ${mockito-version} + test + + + org.assertj + assertj-core + test + + + diff --git a/components/camel-alibaba/camel-alibaba-oss/src/generated/java/org/apache/camel/component/alibaba/oss/OSSComponentConfigurer.java b/components/camel-alibaba/camel-alibaba-oss/src/generated/java/org/apache/camel/component/alibaba/oss/OSSComponentConfigurer.java new file mode 100644 index 0000000000000..18c5c5d677a2a --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/generated/java/org/apache/camel/component/alibaba/oss/OSSComponentConfigurer.java @@ -0,0 +1,75 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.alibaba.oss; + +import javax.annotation.processing.Generated; +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.ExtendedPropertyConfigurerGetter; +import org.apache.camel.spi.PropertyConfigurerGetter; +import org.apache.camel.spi.ConfigurerStrategy; +import org.apache.camel.spi.GeneratedPropertyConfigurer; +import org.apache.camel.util.CaseInsensitiveMap; +import org.apache.camel.support.component.PropertyConfigurerSupport; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.EndpointSchemaGeneratorMojo") +@SuppressWarnings("unchecked") +public class OSSComponentConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter { + + @Override + public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) { + OSSComponent target = (OSSComponent) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "autowiredenabled": + case "autowiredEnabled": target.setAutowiredEnabled(property(camelContext, boolean.class, value)); return true; + case "bridgeerrorhandler": + case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true; + case "healthcheckconsumerenabled": + case "healthCheckConsumerEnabled": target.setHealthCheckConsumerEnabled(property(camelContext, boolean.class, value)); return true; + case "healthcheckproducerenabled": + case "healthCheckProducerEnabled": target.setHealthCheckProducerEnabled(property(camelContext, boolean.class, value)); return true; + case "lazystartproducer": + case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; + default: return false; + } + } + + @Override + public Class getOptionType(String name, boolean ignoreCase) { + switch (ignoreCase ? name.toLowerCase() : name) { + case "autowiredenabled": + case "autowiredEnabled": return boolean.class; + case "bridgeerrorhandler": + case "bridgeErrorHandler": return boolean.class; + case "healthcheckconsumerenabled": + case "healthCheckConsumerEnabled": return boolean.class; + case "healthcheckproducerenabled": + case "healthCheckProducerEnabled": return boolean.class; + case "lazystartproducer": + case "lazyStartProducer": return boolean.class; + default: return null; + } + } + + @Override + public Object getOptionValue(Object obj, String name, boolean ignoreCase) { + OSSComponent target = (OSSComponent) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "autowiredenabled": + case "autowiredEnabled": return target.isAutowiredEnabled(); + case "bridgeerrorhandler": + case "bridgeErrorHandler": return target.isBridgeErrorHandler(); + case "healthcheckconsumerenabled": + case "healthCheckConsumerEnabled": return target.isHealthCheckConsumerEnabled(); + case "healthcheckproducerenabled": + case "healthCheckProducerEnabled": return target.isHealthCheckProducerEnabled(); + case "lazystartproducer": + case "lazyStartProducer": return target.isLazyStartProducer(); + default: return null; + } + } +} + diff --git a/components/camel-alibaba/camel-alibaba-oss/src/generated/java/org/apache/camel/component/alibaba/oss/OSSEndpointConfigurer.java b/components/camel-alibaba/camel-alibaba-oss/src/generated/java/org/apache/camel/component/alibaba/oss/OSSEndpointConfigurer.java new file mode 100644 index 0000000000000..13274286f1519 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/generated/java/org/apache/camel/component/alibaba/oss/OSSEndpointConfigurer.java @@ -0,0 +1,230 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.alibaba.oss; + +import javax.annotation.processing.Generated; +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.ExtendedPropertyConfigurerGetter; +import org.apache.camel.spi.PropertyConfigurerGetter; +import org.apache.camel.spi.ConfigurerStrategy; +import org.apache.camel.spi.GeneratedPropertyConfigurer; +import org.apache.camel.util.CaseInsensitiveMap; +import org.apache.camel.support.component.PropertyConfigurerSupport; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.EndpointSchemaGeneratorMojo") +@SuppressWarnings("unchecked") +public class OSSEndpointConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter { + + @Override + public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) { + OSSEndpoint target = (OSSEndpoint) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "accesskey": + case "accessKey": target.setAccessKey(property(camelContext, java.lang.String.class, value)); return true; + case "backofferrorthreshold": + case "backoffErrorThreshold": target.setBackoffErrorThreshold(property(camelContext, int.class, value)); return true; + case "backoffidlethreshold": + case "backoffIdleThreshold": target.setBackoffIdleThreshold(property(camelContext, int.class, value)); return true; + case "backoffmultiplier": + case "backoffMultiplier": target.setBackoffMultiplier(property(camelContext, int.class, value)); return true; + case "bridgeerrorhandler": + case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true; + case "delay": target.setDelay(property(camelContext, long.class, value)); return true; + case "deleteafterread": + case "deleteAfterRead": target.setDeleteAfterRead(property(camelContext, boolean.class, value)); return true; + case "endpoint": target.setEndpoint(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": + case "exchangePattern": target.setExchangePattern(property(camelContext, org.apache.camel.ExchangePattern.class, value)); return true; + case "greedy": target.setGreedy(property(camelContext, boolean.class, value)); return true; + case "initialdelay": + case "initialDelay": target.setInitialDelay(property(camelContext, long.class, value)); return true; + case "lazystartproducer": + case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; + case "maxkeys": + case "maxKeys": target.setMaxKeys(property(camelContext, java.lang.Integer.class, value)); return true; + case "maxmessagesperpoll": + case "maxMessagesPerPoll": target.setMaxMessagesPerPoll(property(camelContext, int.class, value)); return true; + case "objectname": + case "objectName": target.setObjectName(property(camelContext, java.lang.String.class, value)); return true; + case "operation": target.setOperation(property(camelContext, java.lang.String.class, value)); return true; + case "ossclient": + case "ossClient": target.setOssClient(property(camelContext, com.aliyun.sdk.service.oss2.OSSClient.class, value)); return true; + case "pollstrategy": + case "pollStrategy": target.setPollStrategy(property(camelContext, org.apache.camel.spi.PollingConsumerPollStrategy.class, value)); return true; + case "prefix": target.setPrefix(property(camelContext, java.lang.String.class, value)); return true; + case "region": target.setRegion(property(camelContext, java.lang.String.class, value)); return true; + case "repeatcount": + case "repeatCount": target.setRepeatCount(property(camelContext, long.class, value)); return true; + case "runlogginglevel": + case "runLoggingLevel": target.setRunLoggingLevel(property(camelContext, org.apache.camel.LoggingLevel.class, value)); return true; + case "scheduledexecutorservice": + case "scheduledExecutorService": target.setScheduledExecutorService(property(camelContext, java.util.concurrent.ScheduledExecutorService.class, value)); return true; + case "scheduler": target.setScheduler(property(camelContext, java.lang.Object.class, value)); return true; + case "schedulerproperties": + case "schedulerProperties": target.setSchedulerProperties(property(camelContext, java.util.Map.class, value)); return true; + case "secretkey": + case "secretKey": target.setSecretKey(property(camelContext, java.lang.String.class, value)); return true; + case "sendemptymessagewhenidle": + case "sendEmptyMessageWhenIdle": target.setSendEmptyMessageWhenIdle(property(camelContext, boolean.class, value)); return true; + case "servicekeys": + case "serviceKeys": target.setServiceKeys(property(camelContext, org.apache.camel.component.alibaba.common.models.ServiceKeys.class, value)); return true; + case "startscheduler": + case "startScheduler": target.setStartScheduler(property(camelContext, boolean.class, value)); return true; + case "timeunit": + case "timeUnit": target.setTimeUnit(property(camelContext, java.util.concurrent.TimeUnit.class, value)); return true; + case "usefixeddelay": + case "useFixedDelay": target.setUseFixedDelay(property(camelContext, boolean.class, value)); return true; + default: return false; + } + } + + @Override + public String[] getAutowiredNames() { + return new String[]{"ossClient"}; + } + + @Override + public Class getOptionType(String name, boolean ignoreCase) { + switch (ignoreCase ? name.toLowerCase() : name) { + case "accesskey": + case "accessKey": return java.lang.String.class; + case "backofferrorthreshold": + case "backoffErrorThreshold": return int.class; + case "backoffidlethreshold": + case "backoffIdleThreshold": return int.class; + case "backoffmultiplier": + case "backoffMultiplier": return int.class; + case "bridgeerrorhandler": + case "bridgeErrorHandler": return boolean.class; + case "delay": return long.class; + case "deleteafterread": + case "deleteAfterRead": return boolean.class; + case "endpoint": return java.lang.String.class; + case "exceptionhandler": + case "exceptionHandler": return org.apache.camel.spi.ExceptionHandler.class; + case "exchangepattern": + case "exchangePattern": return org.apache.camel.ExchangePattern.class; + case "greedy": return boolean.class; + case "initialdelay": + case "initialDelay": return long.class; + case "lazystartproducer": + case "lazyStartProducer": return boolean.class; + case "maxkeys": + case "maxKeys": return java.lang.Integer.class; + case "maxmessagesperpoll": + case "maxMessagesPerPoll": return int.class; + case "objectname": + case "objectName": return java.lang.String.class; + case "operation": return java.lang.String.class; + case "ossclient": + case "ossClient": return com.aliyun.sdk.service.oss2.OSSClient.class; + case "pollstrategy": + case "pollStrategy": return org.apache.camel.spi.PollingConsumerPollStrategy.class; + case "prefix": return java.lang.String.class; + case "region": return java.lang.String.class; + case "repeatcount": + case "repeatCount": return long.class; + case "runlogginglevel": + case "runLoggingLevel": return org.apache.camel.LoggingLevel.class; + case "scheduledexecutorservice": + case "scheduledExecutorService": return java.util.concurrent.ScheduledExecutorService.class; + case "scheduler": return java.lang.Object.class; + case "schedulerproperties": + case "schedulerProperties": return java.util.Map.class; + case "secretkey": + case "secretKey": return java.lang.String.class; + case "sendemptymessagewhenidle": + case "sendEmptyMessageWhenIdle": return boolean.class; + case "servicekeys": + case "serviceKeys": return org.apache.camel.component.alibaba.common.models.ServiceKeys.class; + case "startscheduler": + case "startScheduler": return boolean.class; + case "timeunit": + case "timeUnit": return java.util.concurrent.TimeUnit.class; + case "usefixeddelay": + case "useFixedDelay": return boolean.class; + default: return null; + } + } + + @Override + public Object getOptionValue(Object obj, String name, boolean ignoreCase) { + OSSEndpoint target = (OSSEndpoint) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "accesskey": + case "accessKey": return target.getAccessKey(); + case "backofferrorthreshold": + case "backoffErrorThreshold": return target.getBackoffErrorThreshold(); + case "backoffidlethreshold": + case "backoffIdleThreshold": return target.getBackoffIdleThreshold(); + case "backoffmultiplier": + case "backoffMultiplier": return target.getBackoffMultiplier(); + case "bridgeerrorhandler": + case "bridgeErrorHandler": return target.isBridgeErrorHandler(); + case "delay": return target.getDelay(); + case "deleteafterread": + case "deleteAfterRead": return target.isDeleteAfterRead(); + case "endpoint": return target.getEndpoint(); + case "exceptionhandler": + case "exceptionHandler": return target.getExceptionHandler(); + case "exchangepattern": + case "exchangePattern": return target.getExchangePattern(); + case "greedy": return target.isGreedy(); + case "initialdelay": + case "initialDelay": return target.getInitialDelay(); + case "lazystartproducer": + case "lazyStartProducer": return target.isLazyStartProducer(); + case "maxkeys": + case "maxKeys": return target.getMaxKeys(); + case "maxmessagesperpoll": + case "maxMessagesPerPoll": return target.getMaxMessagesPerPoll(); + case "objectname": + case "objectName": return target.getObjectName(); + case "operation": return target.getOperation(); + case "ossclient": + case "ossClient": return target.getOssClient(); + case "pollstrategy": + case "pollStrategy": return target.getPollStrategy(); + case "prefix": return target.getPrefix(); + case "region": return target.getRegion(); + case "repeatcount": + case "repeatCount": return target.getRepeatCount(); + case "runlogginglevel": + case "runLoggingLevel": return target.getRunLoggingLevel(); + case "scheduledexecutorservice": + case "scheduledExecutorService": return target.getScheduledExecutorService(); + case "scheduler": return target.getScheduler(); + case "schedulerproperties": + case "schedulerProperties": return target.getSchedulerProperties(); + case "secretkey": + case "secretKey": return target.getSecretKey(); + case "sendemptymessagewhenidle": + case "sendEmptyMessageWhenIdle": return target.isSendEmptyMessageWhenIdle(); + case "servicekeys": + case "serviceKeys": return target.getServiceKeys(); + case "startscheduler": + case "startScheduler": return target.isStartScheduler(); + case "timeunit": + case "timeUnit": return target.getTimeUnit(); + case "usefixeddelay": + case "useFixedDelay": return target.isUseFixedDelay(); + default: return null; + } + } + + @Override + public Object getCollectionValueType(Object target, String name, boolean ignoreCase) { + switch (ignoreCase ? name.toLowerCase() : name) { + case "schedulerproperties": + case "schedulerProperties": return java.lang.Object.class; + default: return null; + } + } +} + diff --git a/components/camel-alibaba/camel-alibaba-oss/src/generated/java/org/apache/camel/component/alibaba/oss/OSSEndpointUriFactory.java b/components/camel-alibaba/camel-alibaba-oss/src/generated/java/org/apache/camel/component/alibaba/oss/OSSEndpointUriFactory.java new file mode 100644 index 0000000000000..d2b53b40c9b8e --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/generated/java/org/apache/camel/component/alibaba/oss/OSSEndpointUriFactory.java @@ -0,0 +1,115 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.alibaba.oss; + +import javax.annotation.processing.Generated; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.camel.spi.EndpointUriFactory; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.GenerateEndpointUriFactoryMojo") +public class OSSEndpointUriFactory extends org.apache.camel.support.component.EndpointUriFactorySupport implements EndpointUriFactory { + + private static final String BASE = ":bucketName"; + + private static final Set PROPERTY_NAMES; + private static final Set SECRET_PROPERTY_NAMES; + private static final Set ENDPOINT_IDENTITY_PROPERTY_NAMES; + private static final Map MULTI_VALUE_PREFIXES; + static { + Set props = new HashSet<>(33); + props.add("accessKey"); + props.add("backoffErrorThreshold"); + props.add("backoffIdleThreshold"); + props.add("backoffMultiplier"); + props.add("bridgeErrorHandler"); + props.add("bucketName"); + props.add("delay"); + props.add("deleteAfterRead"); + props.add("endpoint"); + props.add("exceptionHandler"); + props.add("exchangePattern"); + props.add("greedy"); + props.add("initialDelay"); + props.add("lazyStartProducer"); + props.add("maxKeys"); + props.add("maxMessagesPerPoll"); + props.add("objectName"); + props.add("operation"); + props.add("ossClient"); + props.add("pollStrategy"); + props.add("prefix"); + props.add("region"); + props.add("repeatCount"); + props.add("runLoggingLevel"); + props.add("scheduledExecutorService"); + props.add("scheduler"); + props.add("schedulerProperties"); + props.add("secretKey"); + props.add("sendEmptyMessageWhenIdle"); + props.add("serviceKeys"); + props.add("startScheduler"); + props.add("timeUnit"); + props.add("useFixedDelay"); + PROPERTY_NAMES = Collections.unmodifiableSet(props); + Set secretProps = new HashSet<>(3); + secretProps.add("accessKey"); + secretProps.add("secretKey"); + secretProps.add("serviceKeys"); + SECRET_PROPERTY_NAMES = Collections.unmodifiableSet(secretProps); + ENDPOINT_IDENTITY_PROPERTY_NAMES = Collections.emptySet(); + Map prefixes = new HashMap<>(1); + prefixes.put("schedulerProperties", "scheduler."); + MULTI_VALUE_PREFIXES = Collections.unmodifiableMap(prefixes); + } + + @Override + public boolean isEnabled(String scheme) { + return "alibaba-oss".equals(scheme); + } + + @Override + public String buildUri(String scheme, Map properties, boolean encode) throws URISyntaxException { + String syntax = scheme + BASE; + String uri = syntax; + + Map copy = new HashMap<>(properties); + + uri = buildPathParameter(syntax, uri, "bucketName", null, false, copy); + uri = buildQueryParameters(uri, copy, encode); + return uri; + } + + @Override + public Set propertyNames() { + return PROPERTY_NAMES; + } + + @Override + public Set secretPropertyNames() { + return SECRET_PROPERTY_NAMES; + } + + @Override + public Set endpointIdentityPropertyNames() { + return ENDPOINT_IDENTITY_PROPERTY_NAMES; + } + + @Override + public Map multiValuePrefixes() { + return MULTI_VALUE_PREFIXES; + } + + @Override + public boolean isLenientProperties() { + return false; + } +} + diff --git a/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/org/apache/camel/component/alibaba/oss/alibaba-oss.json b/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/org/apache/camel/component/alibaba/oss/alibaba-oss.json new file mode 100644 index 0000000000000..2a48300a4ba0d --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/org/apache/camel/component/alibaba/oss/alibaba-oss.json @@ -0,0 +1,79 @@ +{ + "component": { + "kind": "component", + "name": "alibaba-oss", + "title": "Alibaba Object Storage Service (OSS)", + "description": "Alibaba Cloud Object Storage Service (OSS) component", + "deprecated": false, + "firstVersion": "4.23.0", + "label": "cloud", + "javaType": "org.apache.camel.component.alibaba.oss.OSSComponent", + "supportLevel": "Preview", + "groupId": "org.apache.camel", + "artifactId": "camel-alibaba-oss", + "version": "4.23.0-SNAPSHOT", + "scheme": "alibaba-oss", + "extendsScheme": "", + "syntax": "alibaba-oss:bucketName", + "async": false, + "api": false, + "consumerOnly": false, + "producerOnly": false, + "lenientProperties": false, + "browsable": false, + "remote": true + }, + "componentProperties": { + "bridgeErrorHandler": { "index": 0, "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 (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "lazyStartProducer": { "index": 1, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "autowiredEnabled": { "index": 2, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." }, + "healthCheckConsumerEnabled": { "index": 3, "kind": "property", "displayName": "Health Check Consumer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all consumer based health checks from this component" }, + "healthCheckProducerEnabled": { "index": 4, "kind": "property", "displayName": "Health Check Producer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all producer based health checks from this component. Notice: Camel has by default disabled all producer based health-checks. You can turn on producer checks globally by setting camel.health.producersEnabled=true." } + }, + "headers": { + "CamelAlibabaOssBucketName": { "index": 0, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Name of the bucket where object is contained", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#BUCKET_NAME" }, + "CamelAlibabaOssObjectKey": { "index": 1, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The key that the object is stored under", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#OBJECT_KEY" }, + "CamelAlibabaOssLastModified": { "index": 2, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The date and time that the object was last modified", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#LAST_MODIFIED" }, + "CamelAlibabaOssETag": { "index": 3, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The 128-bit MD5 digest of the object content", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#ETAG" }, + "CamelAlibabaOssContentMD5": { "index": 4, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The 128-bit Base64-encoded digest of the object", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#CONTENT_MD5" }, + "CamelAlibabaOssObjectType": { "index": 5, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Shows whether the object is a file or a folder", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#OBJECT_TYPE" }, + "CamelAlibabaOssContentLength": { "index": 6, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The size of the object body in bytes", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#CONTENT_LENGTH" }, + "CamelAlibabaOssContentType": { "index": 7, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The type of content stored in the object", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#CONTENT_TYPE" }, + "CamelFileName": { "index": 8, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Name of the object with which the operation is to be performed", "constantName": "org.apache.camel.component.alibaba.oss.constants.OSSHeaders#FILE_NAME" } + }, + "properties": { + "bucketName": { "index": 0, "kind": "path", "displayName": "Bucket Name", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of bucket to perform operation on" }, + "endpoint": { "index": 1, "kind": "parameter", "displayName": "Endpoint url", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "OSS endpoint URL. Carries higher precedence than region based client initialization" }, + "objectName": { "index": 2, "kind": "parameter", "displayName": "Object Name", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of object to perform operation with" }, + "region": { "index": 3, "kind": "parameter", "displayName": "Service region", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "OSS service region" }, + "deleteAfterRead": { "index": 4, "kind": "parameter", "displayName": "Delete after read", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Determines if objects should be deleted after they have been retrieved" }, + "maxMessagesPerPoll": { "index": 5, "kind": "parameter", "displayName": "Maximum messages per poll", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "description": "The maximum number of messages to poll at each polling" }, + "prefix": { "index": 6, "kind": "parameter", "displayName": "Prefix", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The object name prefix used for filtering objects to be listed" }, + "sendEmptyMessageWhenIdle": { "index": 7, "kind": "parameter", "displayName": "Send Empty Message When Idle", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If the polling consumer did not poll any files, you can enable this option to send an empty message (no body) instead." }, + "bridgeErrorHandler": { "index": 8, "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "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 (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "exceptionHandler": { "index": 9, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "exchangePattern": { "index": 10, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "enum", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, + "pollStrategy": { "index": 11, "kind": "parameter", "displayName": "Poll Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "A pluggable org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your custom implementation to control error handling usually occurred during the poll operation before an Exchange have been created and being routed in Camel." }, + "maxKeys": { "index": 12, "kind": "parameter", "displayName": "Max Keys", "group": "producer", "label": "consumer,producer", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "description": "The maximum number of keys returned when listing objects" }, + "operation": { "index": 13, "kind": "parameter", "displayName": "Operation", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "listBuckets", "listObjects", "putObject", "getObject", "deleteObject", "copyObject", "headObject" ], "deprecated": false, "autowired": false, "secret": false, "description": "Operation to be performed" }, + "lazyStartProducer": { "index": 14, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "ossClient": { "index": 15, "kind": "parameter", "displayName": "OSS Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "com.aliyun.sdk.service.oss2.OSSClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "description": "An autowired OSS client" }, + "backoffErrorThreshold": { "index": 16, "kind": "parameter", "displayName": "Backoff Error Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in." }, + "backoffIdleThreshold": { "index": 17, "kind": "parameter", "displayName": "Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent idle polls that should happen before the backoffMultipler should kick-in." }, + "backoffMultiplier": { "index": 18, "kind": "parameter", "displayName": "Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "To let the scheduled polling consumer backoff if there has been a number of subsequent idles\/errors in a row. The multiplier is then the number of polls that will be skipped before the next actual attempt is happening again. When this option is in use then backoffIdleThreshold and\/or backoffErrorThreshold must also be configured." }, + "delay": { "index": 19, "kind": "parameter", "displayName": "Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 500, "description": "Milliseconds before the next poll." }, + "greedy": { "index": 20, "kind": "parameter", "displayName": "Greedy", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If greedy is enabled, then the ScheduledPollConsumer will run immediately again, if the previous run polled 1 or more messages." }, + "initialDelay": { "index": 21, "kind": "parameter", "displayName": "Initial Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1000, "description": "Milliseconds before the first poll starts." }, + "repeatCount": { "index": 22, "kind": "parameter", "displayName": "Repeat Count", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 0, "description": "Specifies a maximum limit of number of fires. So if you set it to 1, the scheduler will only fire once. If you set it to 5, it will only fire five times. A value of zero or negative means fire forever." }, + "runLoggingLevel": { "index": 23, "kind": "parameter", "displayName": "Run Logging Level", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "enum", "javaType": "org.apache.camel.LoggingLevel", "enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "TRACE", "description": "The consumer logs a start\/complete log line when it polls. This option allows you to configure the logging level for that." }, + "scheduledExecutorService": { "index": 24, "kind": "parameter", "displayName": "Scheduled Executor Service", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.util.concurrent.ScheduledExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "Allows for configuring a custom\/shared thread pool to use for the consumer. By default each consumer has its own single threaded thread pool." }, + "scheduler": { "index": 25, "kind": "parameter", "displayName": "Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.lang.Object", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "description": "To use a cron scheduler from either camel-spring or camel-quartz component. Use value spring or quartz for built in scheduler" }, + "schedulerProperties": { "index": 26, "kind": "parameter", "displayName": "Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.util.Map", "prefix": "scheduler.", "multiValue": true, "deprecated": false, "autowired": false, "secret": false, "description": "To configure additional properties when using a custom scheduler or any of the Quartz, Spring based scheduler. This is a multi-value option with prefix: scheduler." }, + "startScheduler": { "index": 27, "kind": "parameter", "displayName": "Start Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether the scheduler should be auto started." }, + "timeUnit": { "index": 28, "kind": "parameter", "displayName": "Time Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [ "NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS", "DAYS" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and delay options." }, + "useFixedDelay": { "index": 29, "kind": "parameter", "displayName": "Use Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in JDK for details." }, + "accessKey": { "index": 30, "kind": "parameter", "displayName": "API access key (AK)", "group": "security", "label": "security", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": true, "security": "secret", "description": "Access key for the cloud user" }, + "secretKey": { "index": 31, "kind": "parameter", "displayName": "API secret key (SK)", "group": "security", "label": "security", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": true, "security": "secret", "description": "Secret key for the cloud user" }, + "serviceKeys": { "index": 32, "kind": "parameter", "displayName": "Service Configuration", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.component.alibaba.common.models.ServiceKeys", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "description": "Configuration object for cloud service authentication" } + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/services/org/apache/camel/component.properties b/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/services/org/apache/camel/component.properties new file mode 100644 index 0000000000000..3f474d7aa8e7a --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/services/org/apache/camel/component.properties @@ -0,0 +1,7 @@ +# Generated by camel build tools - do NOT edit this file! +components=alibaba-oss +groupId=org.apache.camel +artifactId=camel-alibaba-oss +version=4.23.0-SNAPSHOT +projectName=Camel :: Alibaba Cloud :: OSS +projectDescription=Alibaba Cloud Object Storage Service (OSS) component diff --git a/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/services/org/apache/camel/component/alibaba-oss b/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/services/org/apache/camel/component/alibaba-oss new file mode 100644 index 0000000000000..c4852dd5342d3 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/services/org/apache/camel/component/alibaba-oss @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.alibaba.oss.OSSComponent diff --git a/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/services/org/apache/camel/configurer/alibaba-oss-component b/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/services/org/apache/camel/configurer/alibaba-oss-component new file mode 100644 index 0000000000000..c47dbb557bd1b --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/services/org/apache/camel/configurer/alibaba-oss-component @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.alibaba.oss.OSSComponentConfigurer diff --git a/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/services/org/apache/camel/configurer/alibaba-oss-endpoint b/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/services/org/apache/camel/configurer/alibaba-oss-endpoint new file mode 100644 index 0000000000000..272ce632c0c72 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/services/org/apache/camel/configurer/alibaba-oss-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.alibaba.oss.OSSEndpointConfigurer diff --git a/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/services/org/apache/camel/urifactory/alibaba-oss-endpoint b/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/services/org/apache/camel/urifactory/alibaba-oss-endpoint new file mode 100644 index 0000000000000..fbf5e498e1ec9 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/generated/resources/META-INF/services/org/apache/camel/urifactory/alibaba-oss-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.alibaba.oss.OSSEndpointUriFactory diff --git a/components/camel-alibaba/camel-alibaba-oss/src/main/docs/alibaba-oss-component.adoc b/components/camel-alibaba/camel-alibaba-oss/src/main/docs/alibaba-oss-component.adoc new file mode 100644 index 0000000000000..5c48d5b101acb --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/main/docs/alibaba-oss-component.adoc @@ -0,0 +1,105 @@ += Alibaba Object Storage Service (OSS) Component +:doctitle: Alibaba Object Storage Service (OSS) +:shortname: alibaba-oss +:artifactid: camel-alibaba-oss +:description: Alibaba Cloud Object Storage Service (OSS) component +:since: 4.23 +:supportlevel: Preview +:tabs-sync-option: +:component-header: Both producer and consumer are supported +//Manually maintained attributes +:group: Alibaba Cloud + +*Since Camel {since}* + +*{component-header}* + +The Alibaba Cloud Object Storage Service (OSS) component allows you to integrate with https://www.alibabacloud.com/product/object-storage-service[Alibaba Cloud OSS]. + +Maven users will need to add the following dependency to their `pom.xml` for this component: + +[source,xml] +---- + + org.apache.camel + camel-alibaba-oss + x.x.x + + +---- + +== URI Format + +---- +alibaba-oss:bucketName[?options] +---- + +The `operation` query parameter selects the OSS operation to perform (for example `putObject`, `getObject`, `listObjects`). + +// component options: START +include::partial$component-configure-options.adoc[] +include::partial$component-endpoint-options.adoc[] +include::partial$component-endpoint-headers.adoc[] +// component options: END + +== Usage + +=== Message headers evaluated by the OSS producer + +[width="100%",cols="10%,10%,80%",options="header",] +|======================================================================= +|Header |Type |Description + +|`CamelAlibabaOssOperation` |`String` | Name of operation to invoke + +|`CamelAlibabaOssBucketName` |`String` | Bucket name to invoke operation on (overrides the URI path bucket name) + +|`CamelAlibabaOssObjectName` |`String` | Name of the object to be used in operation + +|`CamelAlibabaOssSourceBucketName` |`String` | Source bucket name for copy operations + +|`CamelAlibabaOssSourceObjectName` |`String` | Source object name for copy operations + +|`CamelAlibabaOssPrefix` |`String` | Prefix filter when listing objects + +|`CamelAlibabaOssMaxKeys` |`Integer` | Maximum number of keys returned when listing objects + +|======================================================================= + +If any of the above headers are set, they will override their corresponding query parameter or URI path value. + +=== List of Supported OSS Operations + +- listBuckets +- listObjects - `bucketName` parameter is *required* +- putObject - `bucketName` and `objectName` parameters are *required* (unless uploading a `File`) +- getObject - `bucketName` and `objectName` parameters are *required* +- deleteObject - `bucketName` and `objectName` parameters are *required* +- copyObject - source and destination bucket/object names are *required* +- headObject - `bucketName` and `objectName` parameters are *required* + +=== Consumer + +The consumer polls objects from a bucket using `listObjectsV2`, downloads each object body, and optionally deletes objects after they have been processed when `deleteAfterRead` is enabled. + +== Examples + +=== Put an object + +[source,java] +---- +from("direct:start") + .setBody(constant("Hello OSS")) + .setHeader("CamelAlibabaOssObjectName", constant("hello.txt")) + .to("alibaba-oss:my-bucket?operation=putObject®ion=cn-hangzhou&accessKey=xxx&secretKey=yyy"); +---- + +Producer operations return structured response metadata in the message body (`Map` or `List` depending on the operation). + +=== Consume objects from a bucket + +[source,java] +---- +from("alibaba-oss:my-bucket?region=cn-hangzhou&accessKey=xxx&secretKey=yyy&deleteAfterRead=true") + .to("log:output"); +---- diff --git a/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSComponent.java b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSComponent.java new file mode 100644 index 0000000000000..b35b35ecd14b3 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSComponent.java @@ -0,0 +1,34 @@ +/* + * 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.util.Map; + +import org.apache.camel.Endpoint; +import org.apache.camel.spi.annotations.Component; +import org.apache.camel.support.HealthCheckComponent; + +@Component("alibaba-oss") +public class OSSComponent extends HealthCheckComponent { + + @Override + protected Endpoint createEndpoint(String uri, String remaining, Map parameters) throws Exception { + Endpoint endpoint = new OSSEndpoint(uri, remaining, this); + setProperties(endpoint, parameters); + return endpoint; + } +} 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 new file mode 100644 index 0000000000000..4c285604ead4c --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSConsumer.java @@ -0,0 +1,186 @@ +/* + * 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.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import com.aliyun.sdk.service.oss2.OSSClient; +import com.aliyun.sdk.service.oss2.models.DeleteObjectRequest; +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 com.aliyun.sdk.service.oss2.utils.IOUtils; +import org.apache.camel.AsyncCallback; +import org.apache.camel.Exchange; +import org.apache.camel.ExchangePropertyKey; +import org.apache.camel.Processor; +import org.apache.camel.component.alibaba.oss.constants.OSSHeaders; +import org.apache.camel.spi.Synchronization; +import org.apache.camel.support.ScheduledBatchPollingConsumer; +import org.apache.camel.util.CastUtils; +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OSSConsumer extends ScheduledBatchPollingConsumer { + private static final Logger LOG = LoggerFactory.getLogger(OSSConsumer.class); + + private final OSSEndpoint endpoint; + private OSSClient ossClient; + private String continuationToken; + + public OSSConsumer(OSSEndpoint endpoint, Processor processor) { + super(endpoint, processor); + this.endpoint = endpoint; + } + + @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"); + } + } + + @Override + protected int poll() throws Exception { + shutdownRunningTask = null; + pendingExchanges = 0; + + String bucketName = endpoint.getBucketName(); + ListObjectsV2Request.Builder requestBuilder = ListObjectsV2Request.newBuilder() + .bucket(bucketName); + + if (ObjectHelper.isNotEmpty(endpoint.getPrefix())) { + requestBuilder.prefix(endpoint.getPrefix()); + } + + int maxKeys = maxMessagesPerPoll > 0 ? maxMessagesPerPoll : 10; + requestBuilder.maxKeys((long) maxKeys); + + if (continuationToken != null) { + LOG.trace("Resuming from continuation token: {}", continuationToken); + requestBuilder.continuationToken(continuationToken); + } + + ListObjectsV2Result listing = ossClient.listObjectsV2(requestBuilder.build()); + + forceConsumerAsReady(); + + String nextToken = null; + if (Boolean.TRUE.equals(listing.isTruncated()) && listing.nextContinuationToken() != null) { + nextToken = listing.nextContinuationToken(); + } + + Queue exchanges = createExchanges(bucketName, listing.contents()); + int processed = processBatch(CastUtils.cast(exchanges)); + if (processed >= 0) { + continuationToken = nextToken; + } + return processed; + } + + @Override + public int processBatch(Queue exchanges) throws Exception { + int total = exchanges.size(); + + for (int index = 0; index < total && isBatchAllowed(); index++) { + final Exchange exchange = ObjectHelper.cast(Exchange.class, exchanges.poll()); + + exchange.setProperty(ExchangePropertyKey.BATCH_SIZE, total); + exchange.setProperty(ExchangePropertyKey.BATCH_INDEX, index); + exchange.setProperty(ExchangePropertyKey.BATCH_COMPLETE, index == total - 1); + + pendingExchanges = total - index - 1; + + exchange.getExchangeExtension().addOnCompletion(new Synchronization() { + @Override + public void onComplete(Exchange exchange) { + processComplete(exchange); + } + + @Override + public void onFailure(Exchange exchange) { + processFailure(exchange); + } + }); + + AsyncCallback callback = defaultConsumerCallback(exchange, true); + getAsyncProcessor().process(exchange, callback); + } + + return total; + } + + private Queue createExchanges(String bucketName, List summaries) throws Exception { + Queue answer = new LinkedList<>(); + if (summaries == null) { + return answer; + } + + for (ObjectSummary summary : summaries) { + if (summary.key() == null || summary.key().endsWith("/")) { + continue; + } + + GetObjectResult result = ossClient.getObject(GetObjectRequest.newBuilder() + .bucket(bucketName) + .key(summary.key()) + .build()); + + byte[] body; + try (var stream = result.body()) { + body = IOUtils.toByteArray(stream); + } + + Exchange exchange = createExchange(true); + exchange.setPattern(endpoint.getExchangePattern()); + OSSUtils.mapOssObject(exchange, bucketName, summary.key(), result, body); + answer.add(exchange); + } + return answer; + } + + private void processComplete(Exchange exchange) { + if (endpoint.isDeleteAfterRead()) { + String bucketName = exchange.getIn().getHeader(OSSHeaders.BUCKET_NAME, String.class); + String objectKey = exchange.getIn().getHeader(OSSHeaders.OBJECT_KEY, String.class); + if (ObjectHelper.isNotEmpty(bucketName) && ObjectHelper.isNotEmpty(objectKey)) { + ossClient.deleteObject(DeleteObjectRequest.newBuilder() + .bucket(bucketName) + .key(objectKey) + .build()); + } + } + } + + private void processFailure(Exchange exchange) { + Exception exception = exchange.getException(); + if (exception != null) { + LOG.warn("Exchange failed, so rolling back message status: {}", exchange, exception); + } else { + LOG.warn("Exchange failed, so rolling back message status: {}", exchange); + } + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSEndpoint.java b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSEndpoint.java new file mode 100644 index 0000000000000..a40a3d573eb14 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSEndpoint.java @@ -0,0 +1,240 @@ +/* + * 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 com.aliyun.sdk.service.oss2.OSSClient; +import org.apache.camel.Category; +import org.apache.camel.Consumer; +import org.apache.camel.Processor; +import org.apache.camel.Producer; +import org.apache.camel.component.alibaba.common.models.ServiceKeys; +import org.apache.camel.component.alibaba.oss.constants.OSSHeaders; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.UriEndpoint; +import org.apache.camel.spi.UriParam; +import org.apache.camel.spi.UriPath; +import org.apache.camel.support.ScheduledPollEndpoint; + +/** + * Alibaba Cloud Object Storage Service (OSS) component + */ +@UriEndpoint(firstVersion = "4.23.0", scheme = "alibaba-oss", title = "Alibaba Object Storage Service (OSS)", + syntax = "alibaba-oss:bucketName", + category = { Category.CLOUD }, headersClass = OSSHeaders.class) +public class OSSEndpoint extends ScheduledPollEndpoint { + + @UriPath(description = "Name of bucket to perform operation on", displayName = "Bucket Name") + private String bucketName; + + @UriParam(description = "Operation to be performed", displayName = "Operation", label = "producer", + enums = "listBuckets,listObjects,putObject,getObject,deleteObject,copyObject,headObject") + private String operation; + + @UriParam(description = "OSS service region", displayName = "Service region") + @Metadata(required = true) + private String region; + + @UriParam(description = "OSS endpoint URL. Carries higher precedence than region based client initialization", + displayName = "Endpoint url") + private String endpoint; + + @UriParam(description = "Configuration object for cloud service authentication", displayName = "Service Configuration", + secret = true, security = "secret", label = "security") + private ServiceKeys serviceKeys; + + @UriParam(description = "Access key for the cloud user", displayName = "API access key (AK)", + secret = true, security = "secret", label = "security") + @Metadata(required = true) + private String accessKey; + + @UriParam(description = "Secret key for the cloud user", displayName = "API secret key (SK)", + secret = true, security = "secret", label = "security") + @Metadata(required = true) + private String secretKey; + + @UriParam(description = "Name of object to perform operation with", displayName = "Object Name") + private String objectName; + + @UriParam(description = "The object name prefix used for filtering objects to be listed", displayName = "Prefix", + label = "consumer") + private String prefix; + + @UriParam(description = "The maximum number of keys returned when listing objects", displayName = "Max Keys", + label = "consumer,producer") + private Integer maxKeys; + + @UriParam(description = "Determines if objects should be deleted after they have been retrieved", + displayName = "Delete after read", defaultValue = "false", label = "consumer") + private boolean deleteAfterRead; + + @UriParam(description = "The maximum number of messages to poll at each polling", displayName = "Maximum messages per poll", + defaultValue = "10", label = "consumer") + private int maxMessagesPerPoll = 10; + + @UriParam(description = "An autowired OSS client", displayName = "OSS Client", label = "advanced") + @Metadata(autowired = true) + private OSSClient ossClient; + + private boolean autowiredOssClient; + + public OSSEndpoint() { + } + + public OSSEndpoint(String uri, String bucketName, OSSComponent component) { + super(uri, component); + this.bucketName = bucketName; + } + + @Override + public Producer createProducer() throws Exception { + return new OSSProducer(this); + } + + @Override + public Consumer createConsumer(Processor processor) throws Exception { + OSSConsumer consumer = new OSSConsumer(this, processor); + configureConsumer(consumer); + consumer.setMaxMessagesPerPoll(maxMessagesPerPoll); + return consumer; + } + + /** + * Initialize and return an OSS client + */ + public OSSClient initClient() { + if (ossClient != null) { + return ossClient; + } + + ossClient = OSSUtils.createClient(this); + return ossClient; + } + + @Override + protected void doStop() throws Exception { + if (ossClient != null && !autowiredOssClient) { + ossClient.close(); + ossClient = null; + } + super.doStop(); + } + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getEndpoint() { + return endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + public ServiceKeys getServiceKeys() { + return serviceKeys; + } + + public void setServiceKeys(ServiceKeys serviceKeys) { + this.serviceKeys = serviceKeys; + } + + public String getAccessKey() { + return accessKey; + } + + public void setAccessKey(String accessKey) { + this.accessKey = accessKey; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public String getBucketName() { + return bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } + + public String getObjectName() { + return objectName; + } + + public void setObjectName(String objectName) { + this.objectName = objectName; + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public Integer getMaxKeys() { + return maxKeys; + } + + public void setMaxKeys(Integer maxKeys) { + this.maxKeys = maxKeys; + } + + public boolean isDeleteAfterRead() { + return deleteAfterRead; + } + + public void setDeleteAfterRead(boolean deleteAfterRead) { + this.deleteAfterRead = deleteAfterRead; + } + + public int getMaxMessagesPerPoll() { + return maxMessagesPerPoll; + } + + public void setMaxMessagesPerPoll(int maxMessagesPerPoll) { + this.maxMessagesPerPoll = maxMessagesPerPoll; + } + + public OSSClient getOssClient() { + return ossClient; + } + + public void setOssClient(OSSClient ossClient) { + this.ossClient = ossClient; + this.autowiredOssClient = ossClient != null; + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSProducer.java b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSProducer.java new file mode 100644 index 0000000000000..07b02d0109804 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSProducer.java @@ -0,0 +1,313 @@ +/* + * 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.File; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.aliyun.sdk.service.oss2.OSSClient; +import com.aliyun.sdk.service.oss2.models.BucketSummary; +import com.aliyun.sdk.service.oss2.models.CopyObjectRequest; +import com.aliyun.sdk.service.oss2.models.CopyObjectResult; +import com.aliyun.sdk.service.oss2.models.DeleteObjectRequest; +import com.aliyun.sdk.service.oss2.models.DeleteObjectResult; +import com.aliyun.sdk.service.oss2.models.GetObjectRequest; +import com.aliyun.sdk.service.oss2.models.GetObjectResult; +import com.aliyun.sdk.service.oss2.models.HeadObjectRequest; +import com.aliyun.sdk.service.oss2.models.HeadObjectResult; +import com.aliyun.sdk.service.oss2.models.ListBucketsRequest; +import com.aliyun.sdk.service.oss2.models.ListBucketsResult; +import com.aliyun.sdk.service.oss2.models.ListObjectsRequest; +import com.aliyun.sdk.service.oss2.models.ListObjectsResult; +import com.aliyun.sdk.service.oss2.models.ObjectSummary; +import com.aliyun.sdk.service.oss2.models.PutObjectRequest; +import com.aliyun.sdk.service.oss2.models.PutObjectResult; +import com.aliyun.sdk.service.oss2.transport.BinaryData; +import org.apache.camel.Exchange; +import org.apache.camel.WrappedFile; +import org.apache.camel.component.alibaba.oss.constants.OSSOperations; +import org.apache.camel.component.alibaba.oss.models.ClientConfigurations; +import org.apache.camel.support.DefaultProducer; +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OSSProducer extends DefaultProducer { + private static final Logger LOG = LoggerFactory.getLogger(OSSProducer.class); + + private final OSSEndpoint endpoint; + private OSSClient ossClient; + + public OSSProducer(OSSEndpoint endpoint) { + super(endpoint); + this.endpoint = endpoint; + } + + @Override + public void process(Exchange exchange) throws Exception { + ClientConfigurations clientConfigurations = OSSUtils.createClientConfigurations(endpoint, exchange); + + if (ossClient == null) { + this.ossClient = endpoint.initClient(); + } + + switch (clientConfigurations.getOperation()) { + case OSSOperations.LIST_BUCKETS: + listBuckets(exchange); + break; + case OSSOperations.LIST_OBJECTS: + listObjects(exchange, clientConfigurations); + break; + case OSSOperations.PUT_OBJECT: + putObject(exchange, clientConfigurations); + break; + case OSSOperations.GET_OBJECT: + getObject(exchange, clientConfigurations); + break; + case OSSOperations.DELETE_OBJECT: + deleteObject(exchange, clientConfigurations); + break; + case OSSOperations.COPY_OBJECT: + copyObject(exchange, clientConfigurations); + break; + case OSSOperations.HEAD_OBJECT: + headObject(exchange, clientConfigurations); + break; + default: + throw new UnsupportedOperationException( + String.format("%s is not a supported operation", clientConfigurations.getOperation())); + } + } + + private void putObject(Exchange exchange, ClientConfigurations clientConfigurations) throws Exception { + Object body = exchange.getMessage().getBody(); + + if (ObjectHelper.isEmpty(clientConfigurations.getBucketName())) { + throw new IllegalArgumentException("Bucket name is mandatory to put objects into bucket"); + } + + if (body instanceof WrappedFile wf) { + body = wf.getFile(); + } + + if (ObjectHelper.isEmpty(clientConfigurations.getObjectName()) && !(body instanceof File)) { + throw new IllegalArgumentException("Object name is mandatory when body is not a file"); + } + + PutObjectRequest.Builder requestBuilder = PutObjectRequest.newBuilder() + .bucket(clientConfigurations.getBucketName()); + + if (body instanceof File file) { + String objectName = ObjectHelper.isEmpty(clientConfigurations.getObjectName()) + ? file.getName() + : clientConfigurations.getObjectName(); + requestBuilder.key(objectName); + PutObjectResult result = ossClient.putObjectFromFile(requestBuilder.build(), file); + exchange.getMessage() + .setBody(toPutObjectMap(result, clientConfigurations.getBucketName(), objectName)); + } else if (body instanceof String stringBody) { + requestBuilder.key(clientConfigurations.getObjectName()) + .body(BinaryData.fromString(stringBody)); + PutObjectResult result = ossClient.putObject(requestBuilder.build()); + exchange.getMessage().setBody(toPutObjectMap(result, clientConfigurations.getBucketName(), + clientConfigurations.getObjectName())); + } else if (body instanceof InputStream inputStream) { + requestBuilder.key(clientConfigurations.getObjectName()) + .body(BinaryData.fromStream(inputStream)); + PutObjectResult result = ossClient.putObject(requestBuilder.build()); + exchange.getMessage().setBody(toPutObjectMap(result, clientConfigurations.getBucketName(), + clientConfigurations.getObjectName())); + } else if (body instanceof byte[] bytes) { + requestBuilder.key(clientConfigurations.getObjectName()) + .body(BinaryData.fromBytes(bytes)); + PutObjectResult result = ossClient.putObject(requestBuilder.build()); + exchange.getMessage().setBody(toPutObjectMap(result, clientConfigurations.getBucketName(), + clientConfigurations.getObjectName())); + } else { + InputStream is = exchange.getMessage().getMandatoryBody(InputStream.class); + requestBuilder.key(clientConfigurations.getObjectName()) + .body(BinaryData.fromStream(is)); + PutObjectResult result = ossClient.putObject(requestBuilder.build()); + exchange.getMessage().setBody(toPutObjectMap(result, clientConfigurations.getBucketName(), + clientConfigurations.getObjectName())); + } + } + + private Map toPutObjectMap(PutObjectResult result, String bucketName, String objectName) { + Map map = new HashMap<>(); + map.put("bucketName", bucketName); + map.put("objectKey", objectName); + map.put("eTag", result.eTag()); + map.put("contentMd5", result.contentMd5()); + map.put("versionId", result.versionId()); + map.put("statusCode", result.statusCode()); + return map; + } + + private void getObject(Exchange exchange, ClientConfigurations clientConfigurations) throws Exception { + if (ObjectHelper.isEmpty(clientConfigurations.getBucketName()) + || ObjectHelper.isEmpty(clientConfigurations.getObjectName())) { + throw new IllegalArgumentException("Bucket and object names are mandatory to get objects"); + } + + LOG.debug("Downloading OSS object {} from bucket {}", clientConfigurations.getObjectName(), + clientConfigurations.getBucketName()); + + GetObjectResult result = ossClient.getObject(GetObjectRequest.newBuilder() + .bucket(clientConfigurations.getBucketName()) + .key(clientConfigurations.getObjectName()) + .build()); + + OSSUtils.mapOssObject(exchange, clientConfigurations.getBucketName(), clientConfigurations.getObjectName(), result); + } + + private void listBuckets(Exchange exchange) { + ListBucketsResult response = ossClient.listBuckets(ListBucketsRequest.newBuilder().build()); + List> buckets = new ArrayList<>(); + if (response.buckets() != null) { + for (BucketSummary bucket : response.buckets()) { + Map bucketMap = new HashMap<>(); + bucketMap.put("name", bucket.name()); + bucketMap.put("region", bucket.region()); + bucketMap.put("storageClass", bucket.storageClass()); + buckets.add(bucketMap); + } + } + exchange.getMessage().setBody(buckets); + } + + private void listObjects(Exchange exchange, ClientConfigurations clientConfigurations) { + if (ObjectHelper.isEmpty(clientConfigurations.getBucketName())) { + throw new IllegalArgumentException("Bucket name is mandatory to list objects"); + } + + ListObjectsRequest.Builder requestBuilder = ListObjectsRequest.newBuilder() + .bucket(clientConfigurations.getBucketName()); + + if (ObjectHelper.isNotEmpty(clientConfigurations.getPrefix())) { + requestBuilder.prefix(clientConfigurations.getPrefix()); + } + if (clientConfigurations.getMaxKeys() != null) { + requestBuilder.maxKeys(clientConfigurations.getMaxKeys().longValue()); + } + + List> objects = new ArrayList<>(); + ListObjectsResult result; + ListObjectsRequest request = requestBuilder.build(); + long maxKeysLimit = clientConfigurations.getMaxKeys() != null + ? clientConfigurations.getMaxKeys().longValue() + : Long.MAX_VALUE; + do { + result = ossClient.listObjects(request); + if (result.contents() != null) { + for (ObjectSummary summary : result.contents()) { + if (objects.size() >= maxKeysLimit) { + break; + } + Map objectMap = new HashMap<>(); + objectMap.put("bucketName", clientConfigurations.getBucketName()); + objectMap.put("objectKey", summary.key()); + objectMap.put("size", summary.size()); + objectMap.put("eTag", summary.eTag()); + objectMap.put("lastModified", summary.lastModified() != null ? summary.lastModified().toString() : null); + objects.add(objectMap); + } + } + if (objects.size() >= maxKeysLimit) { + break; + } + if (Boolean.TRUE.equals(result.isTruncated()) && result.nextMarker() != null) { + request = request.toBuilder().marker(result.nextMarker()).build(); + } else { + break; + } + } while (Boolean.TRUE.equals(result.isTruncated())); + + exchange.getMessage().setBody(objects); + } + + private void deleteObject(Exchange exchange, ClientConfigurations clientConfigurations) { + if (ObjectHelper.isEmpty(clientConfigurations.getBucketName()) + || ObjectHelper.isEmpty(clientConfigurations.getObjectName())) { + throw new IllegalArgumentException("Bucket and object names are mandatory to delete objects"); + } + + DeleteObjectResult result = ossClient.deleteObject(DeleteObjectRequest.newBuilder() + .bucket(clientConfigurations.getBucketName()) + .key(clientConfigurations.getObjectName()) + .build()); + + Map map = new HashMap<>(); + map.put("statusCode", result.statusCode()); + map.put("requestId", result.requestId()); + map.put("deleteMarker", result.deleteMarker()); + map.put("versionId", result.versionId()); + exchange.getMessage().setBody(map); + } + + private void copyObject(Exchange exchange, ClientConfigurations clientConfigurations) { + if (ObjectHelper.isEmpty(clientConfigurations.getSourceBucketName()) + || ObjectHelper.isEmpty(clientConfigurations.getSourceObjectName()) + || ObjectHelper.isEmpty(clientConfigurations.getBucketName()) + || ObjectHelper.isEmpty(clientConfigurations.getObjectName())) { + throw new IllegalArgumentException( + "Source bucket, source object, destination bucket and destination object names are mandatory to copy objects"); + } + + CopyObjectResult result = ossClient.copyObject(CopyObjectRequest.newBuilder() + .sourceBucket(clientConfigurations.getSourceBucketName()) + .sourceKey(clientConfigurations.getSourceObjectName()) + .bucket(clientConfigurations.getBucketName()) + .key(clientConfigurations.getObjectName()) + .build()); + + Map map = new HashMap<>(); + map.put("eTag", result.eTag()); + map.put("lastModified", result.lastModified()); + map.put("statusCode", result.statusCode()); + map.put("requestId", result.requestId()); + exchange.getMessage().setBody(map); + } + + private void headObject(Exchange exchange, ClientConfigurations clientConfigurations) { + if (ObjectHelper.isEmpty(clientConfigurations.getBucketName()) + || ObjectHelper.isEmpty(clientConfigurations.getObjectName())) { + throw new IllegalArgumentException("Bucket and object names are mandatory to head objects"); + } + + HeadObjectResult result = ossClient.headObject(HeadObjectRequest.newBuilder() + .bucket(clientConfigurations.getBucketName()) + .key(clientConfigurations.getObjectName()) + .build()); + + Map map = new HashMap<>(); + map.put("eTag", result.eTag()); + map.put("contentLength", result.contentLength()); + map.put("contentType", result.contentType()); + map.put("contentMd5", result.contentMd5()); + map.put("lastModified", result.lastModified()); + map.put("storageClass", result.storageClass()); + map.put("metadata", result.metadata()); + map.put("statusCode", result.statusCode()); + map.put("requestId", result.requestId()); + exchange.getMessage().setBody(map); + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSUtils.java b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSUtils.java new file mode 100644 index 0000000000000..d6986a5807839 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/OSSUtils.java @@ -0,0 +1,207 @@ +/* + * 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.IOException; +import java.io.InputStream; + +import com.aliyun.sdk.service.oss2.OSSClient; +import com.aliyun.sdk.service.oss2.OSSClientBuilder; +import com.aliyun.sdk.service.oss2.credentials.StaticCredentialsProvider; +import com.aliyun.sdk.service.oss2.models.GetObjectResult; +import com.aliyun.sdk.service.oss2.utils.IOUtils; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.RuntimeCamelException; +import org.apache.camel.component.alibaba.common.models.ServiceKeys; +import org.apache.camel.component.alibaba.oss.constants.OSSConstants; +import org.apache.camel.component.alibaba.oss.constants.OSSHeaders; +import org.apache.camel.component.alibaba.oss.constants.OSSProperties; +import org.apache.camel.component.alibaba.oss.models.ClientConfigurations; +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class OSSUtils { + private static final Logger LOG = LoggerFactory.getLogger(OSSUtils.class); + + private OSSUtils() { + } + + public static ClientConfigurations createClientConfigurations(OSSEndpoint endpoint, Exchange exchange) { + ClientConfigurations clientConfigurations = new ClientConfigurations(); + + String operation = resolveString(exchange, OSSProperties.OPERATION, endpoint.getOperation()); + if (ObjectHelper.isEmpty(operation)) { + LOG.error("No operation name given. Cannot proceed with OSS operations."); + throw new IllegalArgumentException("Operation name not found"); + } + clientConfigurations.setOperation(operation); + + String bucketName = resolveString(exchange, OSSProperties.BUCKET_NAME, endpoint.getBucketName()); + if (ObjectHelper.isNotEmpty(bucketName)) { + clientConfigurations.setBucketName(bucketName); + } + + String objectName = resolveString(exchange, OSSProperties.OBJECT_NAME, endpoint.getObjectName()); + if (ObjectHelper.isNotEmpty(objectName)) { + clientConfigurations.setObjectName(objectName); + } + + String sourceBucketName = resolveString(exchange, OSSProperties.SOURCE_BUCKET_NAME, null); + if (ObjectHelper.isNotEmpty(sourceBucketName)) { + clientConfigurations.setSourceBucketName(sourceBucketName); + } + + String sourceObjectName = resolveString(exchange, OSSProperties.SOURCE_OBJECT_NAME, null); + if (ObjectHelper.isNotEmpty(sourceObjectName)) { + clientConfigurations.setSourceObjectName(sourceObjectName); + } + + String prefix = resolveString(exchange, OSSProperties.PREFIX, endpoint.getPrefix()); + if (ObjectHelper.isNotEmpty(prefix)) { + clientConfigurations.setPrefix(prefix); + } + + Integer maxKeys = resolveInteger(exchange, OSSProperties.MAX_KEYS, endpoint.getMaxKeys()); + if (maxKeys != null) { + clientConfigurations.setMaxKeys(maxKeys); + } + + return clientConfigurations; + } + + private static String resolveString(Exchange exchange, String name, String endpointValue) { + String value = exchange.getIn().getHeader(name, String.class); + if (ObjectHelper.isEmpty(value)) { + value = exchange.getProperty(name, String.class); + } + if (ObjectHelper.isEmpty(value)) { + value = endpointValue; + } + return value; + } + + private static Integer resolveInteger(Exchange exchange, String name, Integer endpointValue) { + Integer value = exchange.getIn().getHeader(name, Integer.class); + if (value == null) { + value = exchange.getProperty(name, Integer.class); + } + if (value == null) { + value = endpointValue; + } + return value; + } + + /** + * Maps the OSS object along with all its metadata into the exchange + */ + public static void mapOssObject(Exchange exchange, String bucketName, String objectKey, GetObjectResult result) + throws IOException { + Message message = exchange.getIn(); + + try (InputStream stream = result.body()) { + message.setBody(IOUtils.toByteArray(stream)); + } + + message.setHeader(OSSHeaders.BUCKET_NAME, bucketName); + message.setHeader(OSSHeaders.OBJECT_KEY, objectKey); + message.setHeader(OSSHeaders.LAST_MODIFIED, result.lastModified()); + message.setHeader(OSSHeaders.CONTENT_LENGTH, result.contentLength()); + message.setHeader(OSSHeaders.CONTENT_TYPE, result.contentType()); + message.setHeader(OSSHeaders.ETAG, result.eTag()); + message.setHeader(OSSHeaders.CONTENT_MD5, result.contentMd5()); + message.setHeader(OSSHeaders.FILE_NAME, objectKey); + + if (objectKey != null && objectKey.endsWith("/")) { + message.setHeader(OSSHeaders.OBJECT_TYPE, OSSConstants.FOLDER); + } else { + message.setHeader(OSSHeaders.OBJECT_TYPE, OSSConstants.FILE); + } + } + + public static void mapOssObject( + Exchange exchange, String bucketName, String objectKey, GetObjectResult result, + byte[] body) { + Message message = exchange.getIn(); + message.setBody(body); + + message.setHeader(OSSHeaders.BUCKET_NAME, bucketName); + message.setHeader(OSSHeaders.OBJECT_KEY, objectKey); + message.setHeader(OSSHeaders.LAST_MODIFIED, result.lastModified()); + message.setHeader(OSSHeaders.CONTENT_LENGTH, result.contentLength()); + message.setHeader(OSSHeaders.CONTENT_TYPE, result.contentType()); + message.setHeader(OSSHeaders.ETAG, result.eTag()); + message.setHeader(OSSHeaders.CONTENT_MD5, result.contentMd5()); + message.setHeader(OSSHeaders.FILE_NAME, objectKey); + + if (objectKey != null && objectKey.endsWith("/")) { + message.setHeader(OSSHeaders.OBJECT_TYPE, OSSConstants.FOLDER); + } else { + message.setHeader(OSSHeaders.OBJECT_TYPE, OSSConstants.FILE); + } + } + + public static RuntimeCamelException wrapIOException(IOException e) { + return new RuntimeCamelException(e); + } + + public static OSSClient createClient(OSSEndpoint endpoint) { + String accessKey = resolveAccessKey(endpoint); + String secretKey = resolveSecretKey(endpoint); + String region = endpoint.getRegion(); + String endpointUrl = endpoint.getEndpoint(); + + if (ObjectHelper.isEmpty(region) && ObjectHelper.isEmpty(endpointUrl)) { + throw new IllegalArgumentException("Region/endpoint not found"); + } + + OSSClientBuilder clientBuilder = OSSClient.newBuilder() + .credentialsProvider(new StaticCredentialsProvider(accessKey, secretKey)); + + if (ObjectHelper.isNotEmpty(region)) { + clientBuilder.region(region); + } + if (ObjectHelper.isNotEmpty(endpointUrl)) { + clientBuilder.endpoint(endpointUrl); + } + + return clientBuilder.build(); + } + + private static String resolveAccessKey(OSSEndpoint endpoint) { + if (ObjectHelper.isNotEmpty(endpoint.getAccessKey())) { + return endpoint.getAccessKey(); + } + ServiceKeys serviceKeys = endpoint.getServiceKeys(); + if (serviceKeys != null && ObjectHelper.isNotEmpty(serviceKeys.getAccessKey())) { + return serviceKeys.getAccessKey(); + } + throw new IllegalArgumentException("Authentication parameter 'access key (AK)' not found"); + } + + private static String resolveSecretKey(OSSEndpoint endpoint) { + if (ObjectHelper.isNotEmpty(endpoint.getSecretKey())) { + return endpoint.getSecretKey(); + } + ServiceKeys serviceKeys = endpoint.getServiceKeys(); + if (serviceKeys != null && ObjectHelper.isNotEmpty(serviceKeys.getSecretKey())) { + return serviceKeys.getSecretKey(); + } + throw new IllegalArgumentException("Authentication parameter 'secret key (SK)' not found"); + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/constants/OSSConstants.java b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/constants/OSSConstants.java new file mode 100644 index 0000000000000..b9b52f7cc0231 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/constants/OSSConstants.java @@ -0,0 +1,28 @@ +/* + * 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.constants; + +/** + * Constants for OSS + */ +public final class OSSConstants { + public static final String FOLDER = "folder"; + public static final String FILE = "file"; + + private OSSConstants() { + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/constants/OSSHeaders.java b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/constants/OSSHeaders.java new file mode 100644 index 0000000000000..ff74e1ece27ce --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/constants/OSSHeaders.java @@ -0,0 +1,48 @@ +/* + * 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.constants; + +import org.apache.camel.Exchange; +import org.apache.camel.spi.Metadata; + +/** + * Constants for the exchange headers when consuming objects + */ +public final class OSSHeaders { + @Metadata(label = "consumer", description = "Name of the bucket where object is contained", javaType = "String") + public static final String BUCKET_NAME = "CamelAlibabaOssBucketName"; + @Metadata(label = "consumer", description = "The key that the object is stored under", javaType = "String") + public static final String OBJECT_KEY = "CamelAlibabaOssObjectKey"; + @Metadata(label = "consumer", description = "The date and time that the object was last modified", javaType = "String") + public static final String LAST_MODIFIED = "CamelAlibabaOssLastModified"; + @Metadata(label = "consumer", description = "The 128-bit MD5 digest of the object content", javaType = "String") + public static final String ETAG = "CamelAlibabaOssETag"; + @Metadata(label = "consumer", description = "The 128-bit Base64-encoded digest of the object", javaType = "String") + public static final String CONTENT_MD5 = "CamelAlibabaOssContentMD5"; + @Metadata(label = "consumer", description = "Shows whether the object is a `file` or a `folder`", javaType = "String") + public static final String OBJECT_TYPE = "CamelAlibabaOssObjectType"; + @Metadata(label = "consumer", description = "The size of the object body in bytes", javaType = "Long") + public static final String CONTENT_LENGTH = "CamelAlibabaOssContentLength"; + @Metadata(label = "consumer", description = "The type of content stored in the object", javaType = "String") + public static final String CONTENT_TYPE = "CamelAlibabaOssContentType"; + @Metadata(label = "consumer", description = "Name of the object with which the operation is to be performed", + javaType = "String") + public static final String FILE_NAME = Exchange.FILE_NAME; + + private OSSHeaders() { + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/constants/OSSOperations.java b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/constants/OSSOperations.java new file mode 100644 index 0000000000000..4f3d7d60f7428 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/constants/OSSOperations.java @@ -0,0 +1,33 @@ +/* + * 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.constants; + +/** + * Constants for all the supported OSS operations + */ +public final class OSSOperations { + public static final String LIST_BUCKETS = "listBuckets"; + public static final String LIST_OBJECTS = "listObjects"; + public static final String PUT_OBJECT = "putObject"; + public static final String GET_OBJECT = "getObject"; + public static final String DELETE_OBJECT = "deleteObject"; + public static final String COPY_OBJECT = "copyObject"; + public static final String HEAD_OBJECT = "headObject"; + + private OSSOperations() { + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/constants/OSSProperties.java b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/constants/OSSProperties.java new file mode 100644 index 0000000000000..3814d07cddfa9 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/constants/OSSProperties.java @@ -0,0 +1,33 @@ +/* + * 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.constants; + +/** + * Constants for properties set on the exchange object + */ +public final class OSSProperties { + public static final String OPERATION = "CamelAlibabaOssOperation"; + public static final String BUCKET_NAME = "CamelAlibabaOssBucketName"; + public static final String OBJECT_NAME = "CamelAlibabaOssObjectName"; + public static final String SOURCE_BUCKET_NAME = "CamelAlibabaOssSourceBucketName"; + public static final String SOURCE_OBJECT_NAME = "CamelAlibabaOssSourceObjectName"; + public static final String PREFIX = "CamelAlibabaOssPrefix"; + public static final String MAX_KEYS = "CamelAlibabaOssMaxKeys"; + + private OSSProperties() { + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/models/ClientConfigurations.java b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/models/ClientConfigurations.java new file mode 100644 index 0000000000000..b1af5c06e6363 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/main/java/org/apache/camel/component/alibaba/oss/models/ClientConfigurations.java @@ -0,0 +1,89 @@ +/* + * 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.models; + +/** + * Class to combine parameters which can be passed through exchange properties and endpoint parameters + */ +public class ClientConfigurations { + private String operation; + private String bucketName; + private String objectName; + private String sourceBucketName; + private String sourceObjectName; + private String prefix; + private Integer maxKeys; + + public ClientConfigurations() { + } + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + public String getBucketName() { + return bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } + + public String getObjectName() { + return objectName; + } + + public void setObjectName(String objectName) { + this.objectName = objectName; + } + + public String getSourceBucketName() { + return sourceBucketName; + } + + public void setSourceBucketName(String sourceBucketName) { + this.sourceBucketName = sourceBucketName; + } + + public String getSourceObjectName() { + return sourceObjectName; + } + + public void setSourceObjectName(String sourceObjectName) { + this.sourceObjectName = sourceObjectName; + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public Integer getMaxKeys() { + return maxKeys; + } + + public void setMaxKeys(Integer maxKeys) { + this.maxKeys = maxKeys; + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/DeleteObjectTest.java b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/DeleteObjectTest.java new file mode 100644 index 0000000000000..432a492c969a6 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/DeleteObjectTest.java @@ -0,0 +1,87 @@ +/* + * 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.util.Map; + +import com.aliyun.sdk.service.oss2.OSSClient; +import com.aliyun.sdk.service.oss2.models.DeleteObjectRequest; +import com.aliyun.sdk.service.oss2.models.DeleteObjectResult; +import org.apache.camel.BindToRegistry; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.alibaba.common.models.ServiceKeys; +import org.apache.camel.component.alibaba.oss.constants.OSSProperties; +import org.apache.camel.component.mock.MockEndpoint; +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; + +class DeleteObjectTest extends CamelTestSupport { + + TestConfiguration testConfiguration = new TestConfiguration(); + + @BindToRegistry("ossClient") + OSSClient mockClient = Mockito.mock(OSSClient.class); + + @BindToRegistry("serviceKeys") + ServiceKeys serviceKeys = new ServiceKeys( + testConfiguration.getProperty("accessKey"), + testConfiguration.getProperty("secretKey")); + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:delete_object") + .setHeader(OSSProperties.OBJECT_NAME, constant(testConfiguration.getProperty("objectName"))) + .to("alibaba-oss:" + testConfiguration.getProperty("bucketName") + "?operation=deleteObject" + + "&serviceKeys=#serviceKeys" + + "®ion=" + testConfiguration.getProperty("region") + + "&ossClient=#ossClient") + .to("mock:delete_object_result"); + } + }; + } + + @Test + void testDeleteObject() throws Exception { + DeleteObjectResult result = Mockito.mock(DeleteObjectResult.class); + Mockito.when(result.statusCode()).thenReturn(204); + Mockito.when(result.requestId()).thenReturn("request-id-123"); + Mockito.when(result.deleteMarker()).thenReturn(false); + Mockito.when(result.versionId()).thenReturn("version-1"); + + Mockito.when(mockClient.deleteObject(Mockito.any(DeleteObjectRequest.class))).thenReturn(result); + + MockEndpoint mock = getMockEndpoint("mock:delete_object_result"); + mock.expectedMinimumMessageCount(1); + template.sendBody("direct:delete_object", "sample_body"); + Exchange responseExchange = mock.getExchanges().get(0); + + mock.assertIsSatisfied(); + + @SuppressWarnings("unchecked") + Map body = responseExchange.getIn().getBody(Map.class); + assertThat(body) + .containsEntry("statusCode", 204) + .containsEntry("requestId", "request-id-123"); + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/GetObjectTest.java b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/GetObjectTest.java new file mode 100644 index 0000000000000..69766dd2f30f2 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/GetObjectTest.java @@ -0,0 +1,99 @@ +/* + * 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.io.InputStream; + +import com.aliyun.sdk.service.oss2.OSSClient; +import com.aliyun.sdk.service.oss2.models.GetObjectRequest; +import com.aliyun.sdk.service.oss2.models.GetObjectResult; +import org.apache.camel.BindToRegistry; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.alibaba.common.models.ServiceKeys; +import org.apache.camel.component.alibaba.oss.constants.OSSHeaders; +import org.apache.camel.component.alibaba.oss.constants.OSSProperties; +import org.apache.camel.component.mock.MockEndpoint; +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; + +class GetObjectTest extends CamelTestSupport { + + TestConfiguration testConfiguration = new TestConfiguration(); + + String bucketName = "test-bucket"; + String objectName = "test_file.txt"; + + @BindToRegistry("ossClient") + OSSClient mockClient = Mockito.mock(OSSClient.class); + + @BindToRegistry("serviceKeys") + ServiceKeys serviceKeys = new ServiceKeys( + testConfiguration.getProperty("accessKey"), + testConfiguration.getProperty("secretKey")); + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:get_object") + .setHeader(OSSProperties.OBJECT_NAME, constant(objectName)) + .to("alibaba-oss:" + bucketName + "?operation=getObject" + + "&serviceKeys=#serviceKeys" + + "®ion=" + testConfiguration.getProperty("region") + + "&ossClient=#ossClient") + .to("mock:get_object_result"); + } + }; + } + + @Test + void testGetObject() throws Exception { + GetObjectResult response = Mockito.mock(GetObjectResult.class); + InputStream stream = new ByteArrayInputStream("hello oss".getBytes()); + Mockito.when(response.body()).thenReturn(stream); + Mockito.when(response.contentLength()).thenReturn(9L); + Mockito.when(response.contentType()).thenReturn("text/plain"); + Mockito.when(response.eTag()).thenReturn("eb733a00c0c9d336e65691a37ab54293"); + Mockito.when(response.contentMd5()).thenReturn("63M6AMDJ0zbmVpGjerVCkw=="); + Mockito.when(response.lastModified()).thenReturn("2024-01-01T00:00:00Z"); + + Mockito.when(mockClient.getObject(Mockito.any(GetObjectRequest.class))).thenReturn(response); + + MockEndpoint mock = getMockEndpoint("mock:get_object_result"); + mock.expectedMinimumMessageCount(1); + template.sendBody("direct:get_object", "dummy"); + Exchange responseExchange = mock.getExchanges().get(0); + + mock.assertIsSatisfied(); + + assertThat(responseExchange.getIn().getHeader(OSSHeaders.CONTENT_LENGTH)).isEqualTo(9L); + assertThat(responseExchange.getIn().getHeader(OSSHeaders.CONTENT_TYPE)).isEqualTo("text/plain"); + assertThat(responseExchange.getIn().getHeader(OSSHeaders.ETAG)).isEqualTo("eb733a00c0c9d336e65691a37ab54293"); + assertThat(responseExchange.getIn().getHeader(OSSHeaders.CONTENT_MD5)).isEqualTo("63M6AMDJ0zbmVpGjerVCkw=="); + assertThat(responseExchange.getIn().getHeader(OSSHeaders.LAST_MODIFIED)).isEqualTo("2024-01-01T00:00:00Z"); + assertThat(responseExchange.getIn().getHeader(OSSHeaders.BUCKET_NAME)).isEqualTo(bucketName); + assertThat(responseExchange.getIn().getHeader(OSSHeaders.OBJECT_KEY)).isEqualTo(objectName); + assertThat(responseExchange.getIn().getHeader(Exchange.FILE_NAME)).isEqualTo(objectName); + assertThat(responseExchange.getIn().getBody(byte[].class)).isEqualTo("hello oss".getBytes()); + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/HeadObjectTest.java b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/HeadObjectTest.java new file mode 100644 index 0000000000000..2ffe8c42ea0c7 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/HeadObjectTest.java @@ -0,0 +1,94 @@ +/* + * 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.util.Map; + +import com.aliyun.sdk.service.oss2.OSSClient; +import com.aliyun.sdk.service.oss2.models.HeadObjectRequest; +import com.aliyun.sdk.service.oss2.models.HeadObjectResult; +import org.apache.camel.BindToRegistry; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.alibaba.common.models.ServiceKeys; +import org.apache.camel.component.alibaba.oss.constants.OSSProperties; +import org.apache.camel.component.mock.MockEndpoint; +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; + +class HeadObjectTest extends CamelTestSupport { + + TestConfiguration testConfiguration = new TestConfiguration(); + + @BindToRegistry("ossClient") + OSSClient mockClient = Mockito.mock(OSSClient.class); + + @BindToRegistry("serviceKeys") + ServiceKeys serviceKeys = new ServiceKeys( + testConfiguration.getProperty("accessKey"), + testConfiguration.getProperty("secretKey")); + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:head_object") + .setHeader(OSSProperties.OBJECT_NAME, constant(testConfiguration.getProperty("objectName"))) + .to("alibaba-oss:" + testConfiguration.getProperty("bucketName") + "?operation=headObject" + + "&serviceKeys=#serviceKeys" + + "®ion=" + testConfiguration.getProperty("region") + + "&ossClient=#ossClient") + .to("mock:head_object_result"); + } + }; + } + + @Test + void testHeadObject() throws Exception { + HeadObjectResult result = Mockito.mock(HeadObjectResult.class); + Mockito.when(result.eTag()).thenReturn("eb733a00c0c9d336e65691a37ab54293"); + Mockito.when(result.contentLength()).thenReturn(1024L); + Mockito.when(result.contentType()).thenReturn("text/plain"); + Mockito.when(result.contentMd5()).thenReturn("content-md5"); + Mockito.when(result.lastModified()).thenReturn("2024-01-01T00:00:00Z"); + Mockito.when(result.storageClass()).thenReturn("Standard"); + Mockito.when(result.metadata()).thenReturn(java.util.Map.of("custom", "value")); + Mockito.when(result.statusCode()).thenReturn(200); + Mockito.when(result.requestId()).thenReturn("request-id-456"); + + Mockito.when(mockClient.headObject(Mockito.any(HeadObjectRequest.class))).thenReturn(result); + + MockEndpoint mock = getMockEndpoint("mock:head_object_result"); + mock.expectedMinimumMessageCount(1); + template.sendBody("direct:head_object", "sample_body"); + Exchange responseExchange = mock.getExchanges().get(0); + + mock.assertIsSatisfied(); + + @SuppressWarnings("unchecked") + Map body = responseExchange.getIn().getBody(Map.class); + assertThat(body) + .containsEntry("eTag", "eb733a00c0c9d336e65691a37ab54293") + .containsEntry("contentLength", 1024L) + .containsEntry("contentType", "text/plain") + .containsEntry("storageClass", "Standard"); + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/ListObjectsTest.java b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/ListObjectsTest.java new file mode 100644 index 0000000000000..c258f337af1a9 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/ListObjectsTest.java @@ -0,0 +1,101 @@ +/* + * 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.time.Instant; +import java.util.List; +import java.util.Map; + +import com.aliyun.sdk.service.oss2.OSSClient; +import com.aliyun.sdk.service.oss2.models.ListObjectsRequest; +import com.aliyun.sdk.service.oss2.models.ListObjectsResult; +import com.aliyun.sdk.service.oss2.models.ObjectSummary; +import org.apache.camel.BindToRegistry; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.alibaba.common.models.ServiceKeys; +import org.apache.camel.component.mock.MockEndpoint; +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; + +class ListObjectsTest extends CamelTestSupport { + + TestConfiguration testConfiguration = new TestConfiguration(); + + @BindToRegistry("ossClient") + OSSClient mockClient = Mockito.mock(OSSClient.class); + + @BindToRegistry("serviceKeys") + ServiceKeys serviceKeys = new ServiceKeys( + testConfiguration.getProperty("accessKey"), + testConfiguration.getProperty("secretKey")); + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:list_objects") + .to("alibaba-oss:" + testConfiguration.getProperty("bucketName") + "?operation=listObjects" + + "&serviceKeys=#serviceKeys" + + "®ion=" + testConfiguration.getProperty("region") + + "&ossClient=#ossClient") + .to("mock:list_objects_result"); + } + }; + } + + @Test + void testListObjects() throws Exception { + ObjectSummary object1 = ObjectSummary.newBuilder() + .key("Object 1") + .size(100L) + .eTag("etag-1") + .lastModified(Instant.parse("2024-01-01T00:00:00Z")) + .build(); + ObjectSummary object2 = ObjectSummary.newBuilder() + .key("Object 2") + .size(200L) + .eTag("etag-2") + .lastModified(Instant.parse("2024-01-02T00:00:00Z")) + .build(); + + ListObjectsResult listing = Mockito.mock(ListObjectsResult.class); + Mockito.when(listing.contents()).thenReturn(List.of(object1, object2)); + Mockito.when(listing.isTruncated()).thenReturn(false); + + Mockito.when(mockClient.listObjects(Mockito.any(ListObjectsRequest.class))).thenReturn(listing); + + MockEndpoint mock = getMockEndpoint("mock:list_objects_result"); + mock.expectedMinimumMessageCount(1); + template.sendBody("direct:list_objects", "sample_body"); + Exchange responseExchange = mock.getExchanges().get(0); + + mock.assertIsSatisfied(); + + @SuppressWarnings("unchecked") + List> body = responseExchange.getIn().getBody(List.class); + assertThat(body).hasSize(2); + assertThat(body.get(0)) + .containsEntry("objectKey", "Object 1") + .containsEntry("bucketName", "dummy_bucket_name"); + assertThat(body.get(1)).containsEntry("objectKey", "Object 2"); + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/OSSEndpointTest.java b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/OSSEndpointTest.java new file mode 100644 index 0000000000000..252028abd92f3 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/OSSEndpointTest.java @@ -0,0 +1,71 @@ +/* + * 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 com.aliyun.sdk.service.oss2.OSSClient; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +class OSSEndpointTest { + + @Test + void initClientReturnsCachedInstance() { + OSSEndpoint endpoint = new OSSEndpoint(); + endpoint.setAccessKey("ak"); + endpoint.setSecretKey("sk"); + endpoint.setRegion("cn-hangzhou"); + + OSSClient first = endpoint.initClient(); + OSSClient second = endpoint.initClient(); + + assertThat(first).isSameAs(second); + } + + @Test + void doStopSkipsCloseForAutowiredClient() throws Exception { + OSSEndpoint endpoint = new OSSEndpoint(); + OSSClient client = mock(OSSClient.class); + endpoint.setOssClient(client); + + endpoint.doStop(); + + verify(client, never()).close(); + } + + @Test + void doStopClosesOwnedClient() throws Exception { + OSSEndpoint endpoint = new OSSEndpoint(); + OSSClient client = mock(OSSClient.class); + + var clientField = OSSEndpoint.class.getDeclaredField("ossClient"); + clientField.setAccessible(true); + clientField.set(endpoint, client); + + var autowiredField = OSSEndpoint.class.getDeclaredField("autowiredOssClient"); + autowiredField.setAccessible(true); + autowiredField.setBoolean(endpoint, false); + + endpoint.doStop(); + + verify(client).close(); + assertThat(endpoint.getOssClient()).isNull(); + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/OSSUtilsTest.java b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/OSSUtilsTest.java new file mode 100644 index 0000000000000..4459e87d7ec04 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/OSSUtilsTest.java @@ -0,0 +1,86 @@ +/* + * 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 com.aliyun.sdk.service.oss2.OSSClient; +import org.apache.camel.component.alibaba.common.models.ServiceKeys; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class OSSUtilsTest { + + @Test + void createClientWithRegion() throws Exception { + OSSEndpoint endpoint = new OSSEndpoint(); + endpoint.setAccessKey("ak"); + endpoint.setSecretKey("sk"); + endpoint.setRegion("cn-hangzhou"); + + try (OSSClient client = OSSUtils.createClient(endpoint)) { + assertThat(client).isNotNull(); + } + } + + @Test + void createClientWithEndpoint() throws Exception { + OSSEndpoint endpoint = new OSSEndpoint(); + endpoint.setAccessKey("ak"); + endpoint.setSecretKey("sk"); + endpoint.setEndpoint("https://oss-cn-hangzhou.aliyuncs.com"); + + try (OSSClient client = OSSUtils.createClient(endpoint)) { + assertThat(client).isNotNull(); + } + } + + @Test + void createClientMissingAccessKey() { + OSSEndpoint endpoint = new OSSEndpoint(); + endpoint.setSecretKey("sk"); + endpoint.setRegion("cn-hangzhou"); + + assertThatThrownBy(() -> OSSUtils.createClient(endpoint)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("access key"); + } + + @Test + void createClientMissingRegionAndEndpoint() { + OSSEndpoint endpoint = new OSSEndpoint(); + endpoint.setAccessKey("ak"); + endpoint.setSecretKey("sk"); + + assertThatThrownBy(() -> OSSUtils.createClient(endpoint)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Region/endpoint"); + } + + @Test + void createClientPrefersEndpointCredentialsOverEmptyServiceKeys() throws Exception { + OSSEndpoint endpoint = new OSSEndpoint(); + endpoint.setAccessKey("uri-ak"); + endpoint.setSecretKey("uri-sk"); + endpoint.setRegion("cn-hangzhou"); + endpoint.setServiceKeys(new ServiceKeys("", "")); + + try (OSSClient client = OSSUtils.createClient(endpoint)) { + assertThat(client).isNotNull(); + } + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/PutObjectTest.java b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/PutObjectTest.java new file mode 100644 index 0000000000000..cc13342b4ddcb --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/PutObjectTest.java @@ -0,0 +1,90 @@ +/* + * 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.util.Map; + +import com.aliyun.sdk.service.oss2.OSSClient; +import com.aliyun.sdk.service.oss2.models.PutObjectRequest; +import com.aliyun.sdk.service.oss2.models.PutObjectResult; +import org.apache.camel.BindToRegistry; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.alibaba.common.models.ServiceKeys; +import org.apache.camel.component.alibaba.oss.constants.OSSProperties; +import org.apache.camel.component.mock.MockEndpoint; +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; + +class PutObjectTest extends CamelTestSupport { + + TestConfiguration testConfiguration = new TestConfiguration(); + + @BindToRegistry("ossClient") + OSSClient mockClient = Mockito.mock(OSSClient.class); + + @BindToRegistry("serviceKeys") + ServiceKeys serviceKeys = new ServiceKeys( + testConfiguration.getProperty("accessKey"), + testConfiguration.getProperty("secretKey")); + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:put_object") + .setBody(constant("a test string")) + .setHeader(OSSProperties.OBJECT_NAME, constant("string_file.txt")) + .to("alibaba-oss:test-bucket?operation=putObject" + + "&serviceKeys=#serviceKeys" + + "®ion=" + testConfiguration.getProperty("region") + + "&ossClient=#ossClient") + .to("mock:put_object_result"); + } + }; + } + + @Test + void putObjectStringTest() throws Exception { + PutObjectResult putObjectResult = Mockito.mock(PutObjectResult.class); + Mockito.when(putObjectResult.eTag()).thenReturn("eb733a00c0c9d336e65691a37ab54293"); + Mockito.when(putObjectResult.contentMd5()).thenReturn("content-md5"); + Mockito.when(putObjectResult.versionId()).thenReturn("version-xxx"); + Mockito.when(putObjectResult.statusCode()).thenReturn(200); + + Mockito.when(mockClient.putObject(Mockito.any(PutObjectRequest.class))) + .thenReturn(putObjectResult); + + MockEndpoint mock = getMockEndpoint("mock:put_object_result"); + mock.expectedMinimumMessageCount(1); + template.sendBody("direct:put_object", "sample file content"); + Exchange responseExchange = mock.getExchanges().get(0); + + mock.assertIsSatisfied(); + + @SuppressWarnings("unchecked") + Map body = responseExchange.getIn().getBody(Map.class); + assertThat(body) + .containsEntry("bucketName", "test-bucket") + .containsEntry("objectKey", "string_file.txt") + .containsEntry("eTag", "eb733a00c0c9d336e65691a37ab54293"); + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/TestConfiguration.java b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/TestConfiguration.java new file mode 100644 index 0000000000000..3441d8e7cb49a --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/TestConfiguration.java @@ -0,0 +1,45 @@ +/* + * 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.util.HashMap; +import java.util.Map; + +public class TestConfiguration { + private static Map propertyMap; + + public TestConfiguration() { + initPropertyMap(); + } + + private void initPropertyMap() { + propertyMap = new HashMap<>(); + propertyMap.put("accessKey", "dummy_access_key"); + propertyMap.put("secretKey", "dummy_secret_key"); + propertyMap.put("region", "cn-hangzhou"); + propertyMap.put("endpoint", "https://oss-cn-hangzhou.aliyuncs.com"); + propertyMap.put("bucketName", "dummy_bucket_name"); + propertyMap.put("objectName", "dummy_object.txt"); + } + + public String getProperty(String key) { + if (propertyMap == null) { + initPropertyMap(); + } + return propertyMap.get(key); + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/constants/OSSOperationsTest.java b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/constants/OSSOperationsTest.java new file mode 100644 index 0000000000000..f1d43acf68034 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/test/java/org/apache/camel/component/alibaba/oss/constants/OSSOperationsTest.java @@ -0,0 +1,34 @@ +/* + * 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.constants; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class OSSOperationsTest { + @Test + void testOperations() { + assertThat(OSSOperations.LIST_BUCKETS).isEqualTo("listBuckets"); + assertThat(OSSOperations.LIST_OBJECTS).isEqualTo("listObjects"); + assertThat(OSSOperations.PUT_OBJECT).isEqualTo("putObject"); + assertThat(OSSOperations.GET_OBJECT).isEqualTo("getObject"); + assertThat(OSSOperations.DELETE_OBJECT).isEqualTo("deleteObject"); + assertThat(OSSOperations.COPY_OBJECT).isEqualTo("copyObject"); + assertThat(OSSOperations.HEAD_OBJECT).isEqualTo("headObject"); + } +} diff --git a/components/camel-alibaba/camel-alibaba-oss/src/test/resources/log4j2.properties b/components/camel-alibaba/camel-alibaba-oss/src/test/resources/log4j2.properties new file mode 100644 index 0000000000000..a4c7b3d181092 --- /dev/null +++ b/components/camel-alibaba/camel-alibaba-oss/src/test/resources/log4j2.properties @@ -0,0 +1,29 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- +rootLogger.level = INFO +rootLogger.appenderRef.stdout.ref = console + +appender.console.type = Console +appender.console.name = console +appender.console.layout.type = PatternLayout +appender.console.layout.pattern = %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n + +logger.camel.name = org.apache.camel +logger.camel.level = INFO + +logger.oss.name = org.apache.camel.component.alibaba.oss +logger.oss.level = DEBUG diff --git a/components/camel-alibaba/pom.xml b/components/camel-alibaba/pom.xml new file mode 100644 index 0000000000000..ff7f255a79d5d --- /dev/null +++ b/components/camel-alibaba/pom.xml @@ -0,0 +1,41 @@ + + + + + 4.0.0 + + + org.apache.camel + components + 4.23.0-SNAPSHOT + + + camel-alibaba-parent + pom + Camel :: Alibaba Cloud :: Parent + Camel Alibaba Cloud parent + + + camel-alibaba-common + camel-alibaba-oss + camel-alibaba-mns + + + diff --git a/components/pom.xml b/components/pom.xml index e5c3970408dcd..b976af089d74a 100644 --- a/components/pom.xml +++ b/components/pom.xml @@ -80,6 +80,7 @@ camel-activemq camel-activemq6 camel-ai + camel-alibaba camel-amqp camel-arangodb camel-as2 diff --git a/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties b/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties index e8a80790f9c4c..f0cd17702e552 100644 --- a/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties +++ b/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties @@ -2,6 +2,8 @@ a2a activemq activemq6 ai-tool +alibaba-mns +alibaba-oss amqp arangodb as2 diff --git a/coverage/pom.xml b/coverage/pom.xml index 091662322f987..cac05d60ffa8f 100644 --- a/coverage/pom.xml +++ b/coverage/pom.xml @@ -221,6 +221,21 @@ camel-activemq6 ${project.version} + + org.apache.camel + camel-alibaba-common + ${project.version} + + + org.apache.camel + camel-alibaba-mns + ${project.version} + + + org.apache.camel + camel-alibaba-oss + ${project.version} + org.apache.camel camel-amqp diff --git a/parent/pom.xml b/parent/pom.xml index da651323c6444..a9eb89f61577b 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -64,6 +64,8 @@ 3.14.1 3.2.1 0.3.0 + 0.4.1 + 2.0.0 3.5.1 2.0.5 2.0.0.AM27 @@ -723,6 +725,21 @@ camel-ai-tool ${project.version} + + org.apache.camel + camel-alibaba-common + ${project.version} + + + org.apache.camel + camel-alibaba-mns + ${project.version} + + + org.apache.camel + camel-alibaba-oss + ${project.version} + org.apache.camel camel-amqp diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java index 678ec0b56e157..d32d722c50009 100644 --- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java +++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java @@ -142,6 +142,9 @@ public static List getComponentPath(Path dir) { return Arrays.asList(dir.resolve("camel-vertx"), dir.resolve("camel-vertx-http"), dir.resolve("camel-vertx-websocket")); + case "camel-alibaba": + return Arrays.asList(dir.resolve("camel-alibaba-oss"), + dir.resolve("camel-alibaba-mns")); case "camel-huawei": return Arrays.asList(dir.resolve("camel-huaweicloud-frs"), dir.resolve("camel-huaweicloud-dms"),